diff --git a/lib/Target/X86/X86ISelDAGToDAG.cpp b/lib/Target/X86/X86ISelDAGToDAG.cpp index c2a6a963e0b..ba0bf566a39 100644 --- a/lib/Target/X86/X86ISelDAGToDAG.cpp +++ b/lib/Target/X86/X86ISelDAGToDAG.cpp @@ -15,6 +15,8 @@ #include "X86.h" #include "X86Subtarget.h" #include "X86ISelLowering.h" +#include "llvm/GlobalValue.h" +#include "llvm/CodeGen/MachineConstantPool.h" #include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/SelectionDAGISel.h" #include "llvm/Target/TargetMachine.h" @@ -26,6 +28,32 @@ using namespace llvm; // Pattern Matcher Implementation //===----------------------------------------------------------------------===// +namespace { + /// X86ISelAddressMode - This corresponds to X86AddressMode, but uses + /// SDOperand's instead of register numbers for the leaves of the matched + /// tree. + struct X86ISelAddressMode { + enum { + RegBase, + FrameIndexBase, + } BaseType; + + struct { // This is really a union, discriminated by BaseType! + SDOperand Reg; + int FrameIndex; + } Base; + + unsigned Scale; + SDOperand IndexReg; + unsigned Disp; + GlobalValue *GV; + + X86ISelAddressMode() + : BaseType(RegBase), Scale(1), IndexReg(), Disp(), GV(0) { + } + }; +} + namespace { Statistic<> NumFPKill("x86-codegen", "Number of FP_REG_KILL instructions added"); @@ -66,6 +94,15 @@ namespace { private: SDOperand Select(SDOperand N); + void SelectAddress(SDOperand N, X86ISelAddressMode &AM); + bool MatchAddress(SDOperand N, X86ISelAddressMode &AM); + + /// getI8Imm - Return a target constant with the specified value, of type + /// i8. + inline SDOperand getI8Imm(unsigned Imm) { + return CurDAG->getTargetConstant(Imm, MVT::i8); + } + /// getI16Imm - Return a target constant with the specified value, of type /// i16. inline SDOperand getI16Imm(unsigned Imm) { @@ -93,6 +130,141 @@ void X86DAGToDAGISel::InstructionSelectBasicBlock(SelectionDAG &DAG) { ScheduleAndEmitDAG(DAG); } +/// SelectAddress - Pattern match the maximal addressing mode for this node. +void X86DAGToDAGISel::SelectAddress(SDOperand N, X86ISelAddressMode &AM) { + MatchAddress(N, AM); + + if (AM.BaseType == X86ISelAddressMode::RegBase && !AM.Base.Reg.Val) { + AM.Base.Reg = CurDAG->getRegister(0, MVT::i32); + } else { + AM.Base.Reg = Select(AM.Base.Reg); + } + if (!AM.IndexReg.Val) { + AM.IndexReg = CurDAG->getRegister(0, MVT::i32); + } else { + AM.IndexReg = Select(AM.IndexReg); + } +} + +/// FIXME: copied from X86ISelPattern.cpp +/// MatchAddress - Add the specified node to the specified addressing mode, +/// returning true if it cannot be done. This just pattern matches for the +/// addressing mode +bool X86DAGToDAGISel::MatchAddress(SDOperand N, X86ISelAddressMode &AM) { + switch (N.getOpcode()) { + default: break; + case ISD::FrameIndex: + if (AM.BaseType == X86ISelAddressMode::RegBase && AM.Base.Reg.Val == 0) { + AM.BaseType = X86ISelAddressMode::FrameIndexBase; + AM.Base.FrameIndex = cast(N)->getIndex(); + return false; + } + break; + case ISD::GlobalAddress: + if (AM.GV == 0) { + GlobalValue *GV = cast(N)->getGlobal(); + // For Darwin, external and weak symbols are indirect, so we want to load + // the value at address GV, not the value of GV itself. This means that + // the GlobalAddress must be in the base or index register of the address, + // not the GV offset field. + if (Subtarget->getIndirectExternAndWeakGlobals() && + (GV->hasWeakLinkage() || GV->isExternal())) { + break; + } else { + AM.GV = GV; + return false; + } + } + break; + case ISD::Constant: + AM.Disp += cast(N)->getValue(); + return false; + case ISD::SHL: + if (AM.IndexReg.Val == 0 && AM.Scale == 1) + if (ConstantSDNode *CN = dyn_cast(N.Val->getOperand(1))) { + unsigned Val = CN->getValue(); + if (Val == 1 || Val == 2 || Val == 3) { + AM.Scale = 1 << Val; + SDOperand ShVal = N.Val->getOperand(0); + + // Okay, we know that we have a scale by now. However, if the scaled + // value is an add of something and a constant, we can fold the + // constant into the disp field here. + if (ShVal.Val->getOpcode() == ISD::ADD && ShVal.hasOneUse() && + isa(ShVal.Val->getOperand(1))) { + AM.IndexReg = ShVal.Val->getOperand(0); + ConstantSDNode *AddVal = + cast(ShVal.Val->getOperand(1)); + AM.Disp += AddVal->getValue() << Val; + } else { + AM.IndexReg = ShVal; + } + return false; + } + } + break; + case ISD::MUL: + // X*[3,5,9] -> X+X*[2,4,8] + if (AM.IndexReg.Val == 0 && AM.BaseType == X86ISelAddressMode::RegBase && + AM.Base.Reg.Val == 0) + if (ConstantSDNode *CN = dyn_cast(N.Val->getOperand(1))) + if (CN->getValue() == 3 || CN->getValue() == 5 || CN->getValue() == 9) { + AM.Scale = unsigned(CN->getValue())-1; + + SDOperand MulVal = N.Val->getOperand(0); + SDOperand Reg; + + // Okay, we know that we have a scale by now. However, if the scaled + // value is an add of something and a constant, we can fold the + // constant into the disp field here. + if (MulVal.Val->getOpcode() == ISD::ADD && MulVal.hasOneUse() && + isa(MulVal.Val->getOperand(1))) { + Reg = MulVal.Val->getOperand(0); + ConstantSDNode *AddVal = + cast(MulVal.Val->getOperand(1)); + AM.Disp += AddVal->getValue() * CN->getValue(); + } else { + Reg = N.Val->getOperand(0); + } + + AM.IndexReg = AM.Base.Reg = Reg; + return false; + } + break; + + case ISD::ADD: { + X86ISelAddressMode Backup = AM; + if (!MatchAddress(N.Val->getOperand(0), AM) && + !MatchAddress(N.Val->getOperand(1), AM)) + return false; + AM = Backup; + if (!MatchAddress(N.Val->getOperand(1), AM) && + !MatchAddress(N.Val->getOperand(0), AM)) + return false; + AM = Backup; + break; + } + } + + // Is the base register already occupied? + if (AM.BaseType != X86ISelAddressMode::RegBase || AM.Base.Reg.Val) { + // If so, check to see if the scale index register is set. + if (AM.IndexReg.Val == 0) { + AM.IndexReg = N; + AM.Scale = 1; + return false; + } + + // Otherwise, we cannot select it. + return true; + } + + // Default, generate it as a register. + AM.BaseType = X86ISelAddressMode::RegBase; + AM.Base.Reg = N; + return false; +} + SDOperand X86DAGToDAGISel::Select(SDOperand Op) { SDNode *N = Op.Val; MVT::ValueType OpVT = Op.getValueType(); @@ -103,6 +275,21 @@ SDOperand X86DAGToDAGISel::Select(SDOperand Op) { switch (N->getOpcode()) { default: break; + case ISD::SHL: + if (ConstantSDNode *CN = dyn_cast(N->getOperand(1))) { + if (CN->getValue() == 1) { // X = SHL Y, 1 -> X = ADD Y, Y + switch (OpVT) { + default: assert(0 && "Cannot shift this type!"); + case MVT::i8: Opc = X86::ADD8rr; break; + case MVT::i16: Opc = X86::ADD16rr; break; + case MVT::i32: Opc = X86::ADD32rr; break; + } + SDOperand Tmp0 = Select(N->getOperand(0)); + CurDAG->SelectNodeTo(N, Opc, MVT::i32, Tmp0, Tmp0); + return SDOperand(N, 0); + } + } + case ISD::RET: { SDOperand Chain = Select(N->getOperand(0)); // Token chain. switch (N->getNumOperands()) { @@ -131,11 +318,47 @@ SDOperand X86DAGToDAGISel::Select(SDOperand Op) { if (X86Lowering.getBytesToPopOnReturn() == 0) CurDAG->SelectNodeTo(N, X86::RET, MVT::Other, Chain); else - CurDAG->SelectNodeTo(N, X86::RET, MVT::Other, Chain, - getI16Imm(X86Lowering.getBytesToPopOnReturn())); + CurDAG->SelectNodeTo(N, X86::RET, MVT::Other, + getI16Imm(X86Lowering.getBytesToPopOnReturn()), + Chain); return SDOperand(N, 0); } + + case ISD::LOAD: { + switch (N->getValueType(0)) { + default: assert(0 && "Cannot load this type!"); + case MVT::i1: + case MVT::i8: Opc = X86::MOV8rm; break; + case MVT::i16: Opc = X86::MOV16rm; break; + case MVT::i32: Opc = X86::MOV32rm; break; + case MVT::f32: Opc = X86::MOVSSrm; break; + case MVT::f64: Opc = X86::FLD64m; ContainsFPCode = true; break; + } + + if (ConstantPoolSDNode *CP = dyn_cast(N->getOperand(1))){ + unsigned CPIdx = BB->getParent()->getConstantPool()-> + getConstantPoolIndex(CP->get()); + // ??? + assert(0 && "Can't handle load from constant pool!"); + } else { + SDOperand Chain = Select(N->getOperand(0)); // Token chain. + X86ISelAddressMode AM; + SelectAddress(N->getOperand(1), AM); + SDOperand Scale = getI8Imm (AM.Scale); + SDOperand Disp = AM.GV ? CurDAG->getTargetGlobalAddress(AM.GV, MVT::i32) + : getI32Imm(AM.Disp); + if (AM.BaseType == X86ISelAddressMode::RegBase) { + CurDAG->SelectNodeTo(N, Opc, N->getValueType(0), MVT::Other, + AM.Base.Reg, Scale, AM.IndexReg, Disp, Chain); + } else { + SDOperand Base = CurDAG->getFrameIndex(AM.Base.FrameIndex, MVT::i32); + CurDAG->SelectNodeTo(N, Opc, N->getValueType(0), MVT::Other, + Base, Scale, AM.IndexReg, Disp, Chain); + } + } + return SDOperand(N, Op.ResNo); + } } return SelectCode(Op);