X-Git-Url: http://demsky.eecs.uci.edu/git/?a=blobdiff_plain;f=lib%2FTarget%2FARM%2FARMISelDAGToDAG.cpp;h=933651d8b15cc1035a88cbf75b15a99d917ea90c;hb=13ab020ea08826f1b87db6ec3da63889a12e3d9d;hp=beb0d6775ad639d810500adb76e6cc47882fc4fd;hpb=614057b843e5b27963095c42042a232e85527f02;p=oota-llvm.git diff --git a/lib/Target/ARM/ARMISelDAGToDAG.cpp b/lib/Target/ARM/ARMISelDAGToDAG.cpp index beb0d6775ad..933651d8b15 100644 --- a/lib/Target/ARM/ARMISelDAGToDAG.cpp +++ b/lib/Target/ARM/ARMISelDAGToDAG.cpp @@ -12,11 +12,13 @@ //===----------------------------------------------------------------------===// #include "ARM.h" +#include "ARMISelLowering.h" #include "ARMTargetMachine.h" +#include "ARMAddressingModes.h" #include "llvm/CallingConv.h" +#include "llvm/Constants.h" #include "llvm/DerivedTypes.h" #include "llvm/Function.h" -#include "llvm/Constants.h" #include "llvm/Intrinsics.h" #include "llvm/CodeGen/MachineFrameInfo.h" #include "llvm/CodeGen/MachineFunction.h" @@ -25,718 +27,833 @@ #include "llvm/CodeGen/SelectionDAGISel.h" #include "llvm/CodeGen/SSARegMap.h" #include "llvm/Target/TargetLowering.h" +#include "llvm/Target/TargetOptions.h" #include "llvm/Support/Debug.h" -#include -#include using namespace llvm; +//===--------------------------------------------------------------------===// +/// ARMDAGToDAGISel - ARM specific code to select ARM machine +/// instructions for SelectionDAG operations. +/// namespace { - class ARMTargetLowering : public TargetLowering { - int VarArgsFrameIndex; // FrameIndex for start of varargs area. - public: - ARMTargetLowering(TargetMachine &TM); - virtual SDOperand LowerOperation(SDOperand Op, SelectionDAG &DAG); - virtual const char *getTargetNodeName(unsigned Opcode) const; - }; - -} - -ARMTargetLowering::ARMTargetLowering(TargetMachine &TM) - : TargetLowering(TM) { - addRegisterClass(MVT::i32, ARM::IntRegsRegisterClass); - addRegisterClass(MVT::f32, ARM::FPRegsRegisterClass); - addRegisterClass(MVT::f64, ARM::DFPRegsRegisterClass); - - setOperationAction(ISD::SINT_TO_FP, MVT::i32, Custom); - - setOperationAction(ISD::RET, MVT::Other, Custom); - setOperationAction(ISD::GlobalAddress, MVT::i32, Custom); - setOperationAction(ISD::ConstantPool, MVT::i32, Custom); - - setOperationAction(ISD::SETCC, MVT::i32, Expand); - setOperationAction(ISD::SELECT_CC, MVT::i32, Custom); - setOperationAction(ISD::BR_CC, MVT::i32, Custom); +class ARMDAGToDAGISel : public SelectionDAGISel { + ARMTargetLowering Lowering; - setOperationAction(ISD::VASTART, MVT::Other, Custom); - setOperationAction(ISD::VAEND, MVT::Other, Expand); + /// Subtarget - Keep a pointer to the ARMSubtarget around so that we can + /// make the right decision when generating code for different targets. + const ARMSubtarget *Subtarget; - setOperationAction(ISD::ConstantFP, MVT::f64, Expand); - setOperationAction(ISD::ConstantFP, MVT::f32, Expand); +public: + ARMDAGToDAGISel(ARMTargetMachine &TM) + : SelectionDAGISel(Lowering), Lowering(TM), + Subtarget(&TM.getSubtarget()) { + } - setSchedulingPreference(SchedulingForRegPressure); - computeRegisterProperties(); + virtual const char *getPassName() const { + return "ARM Instruction Selection"; + } + + SDNode *Select(SDOperand Op); + virtual void InstructionSelectBasicBlock(SelectionDAG &DAG); + bool SelectAddrMode2(SDOperand Op, SDOperand N, SDOperand &Base, + SDOperand &Offset, SDOperand &Opc); + bool SelectAddrMode2Offset(SDOperand Op, SDOperand N, + SDOperand &Offset, SDOperand &Opc); + bool SelectAddrMode3(SDOperand Op, SDOperand N, SDOperand &Base, + SDOperand &Offset, SDOperand &Opc); + bool SelectAddrMode3Offset(SDOperand Op, SDOperand N, + SDOperand &Offset, SDOperand &Opc); + bool SelectAddrMode5(SDOperand Op, SDOperand N, SDOperand &Base, + SDOperand &Offset); + + bool SelectAddrModePC(SDOperand Op, SDOperand N, SDOperand &Offset, + SDOperand &Label); + + bool SelectThumbAddrModeRR(SDOperand Op, SDOperand N, SDOperand &Base, + SDOperand &Offset); + bool SelectThumbAddrModeRI5(SDOperand Op, SDOperand N, unsigned Scale, + SDOperand &Base, SDOperand &OffImm, + SDOperand &Offset); + bool SelectThumbAddrModeS1(SDOperand Op, SDOperand N, SDOperand &Base, + SDOperand &OffImm, SDOperand &Offset); + bool SelectThumbAddrModeS2(SDOperand Op, SDOperand N, SDOperand &Base, + SDOperand &OffImm, SDOperand &Offset); + bool SelectThumbAddrModeS4(SDOperand Op, SDOperand N, SDOperand &Base, + SDOperand &OffImm, SDOperand &Offset); + bool SelectThumbAddrModeSP(SDOperand Op, SDOperand N, SDOperand &Base, + SDOperand &OffImm); + + bool SelectShifterOperandReg(SDOperand Op, SDOperand N, SDOperand &A, + SDOperand &B, SDOperand &C); + + // Include the pieces autogenerated from the target description. +#include "ARMGenDAGISel.inc" +}; } -namespace llvm { - namespace ARMISD { - enum NodeType { - // Start the numbering where the builting ops and target ops leave off. - FIRST_NUMBER = ISD::BUILTIN_OP_END+ARM::INSTRUCTION_LIST_END, - /// CALL - A direct function call. - CALL, - - /// Return with a flag operand. - RET_FLAG, - - CMP, - - SELECT, - - BR, - - FSITOS, - - FSITOD, +void ARMDAGToDAGISel::InstructionSelectBasicBlock(SelectionDAG &DAG) { + DEBUG(BB->dump()); - FMRRD, + DAG.setRoot(SelectRoot(DAG.getRoot())); + DAG.RemoveDeadNodes(); - FMDRR - }; - } + ScheduleAndEmitDAG(DAG); } -/// DAGCCToARMCC - Convert a DAG integer condition code to an ARM CC -static ARMCC::CondCodes DAGCCToARMCC(ISD::CondCode CC) { - switch (CC) { - default: - std::cerr << "CC = " << CC << "\n"; - assert(0 && "Unknown condition code!"); - case ISD::SETUGT: return ARMCC::HI; - case ISD::SETULE: return ARMCC::LS; - case ISD::SETLE: return ARMCC::LE; - case ISD::SETLT: return ARMCC::LT; - case ISD::SETGT: return ARMCC::GT; - case ISD::SETNE: return ARMCC::NE; - case ISD::SETEQ: return ARMCC::EQ; - case ISD::SETGE: return ARMCC::GE; - case ISD::SETUGE: return ARMCC::CS; - case ISD::SETULT: return ARMCC::CC; +bool ARMDAGToDAGISel::SelectAddrMode2(SDOperand Op, SDOperand N, + SDOperand &Base, SDOperand &Offset, + SDOperand &Opc) { + if (N.getOpcode() == ISD::MUL) { + if (ConstantSDNode *RHS = dyn_cast(N.getOperand(1))) { + // X * [3,5,9] -> X + X * [2,4,8] etc. + int RHSC = (int)RHS->getValue(); + if (RHSC & 1) { + RHSC = RHSC & ~1; + ARM_AM::AddrOpc AddSub = ARM_AM::add; + if (RHSC < 0) { + AddSub = ARM_AM::sub; + RHSC = - RHSC; + } + if (isPowerOf2_32(RHSC)) { + unsigned ShAmt = Log2_32(RHSC); + Base = Offset = N.getOperand(0); + Opc = CurDAG->getTargetConstant(ARM_AM::getAM2Opc(AddSub, ShAmt, + ARM_AM::lsl), + MVT::i32); + return true; + } + } + } } -} -const char *ARMTargetLowering::getTargetNodeName(unsigned Opcode) const { - switch (Opcode) { - default: return 0; - case ARMISD::CALL: return "ARMISD::CALL"; - case ARMISD::RET_FLAG: return "ARMISD::RET_FLAG"; - case ARMISD::SELECT: return "ARMISD::SELECT"; - case ARMISD::CMP: return "ARMISD::CMP"; - case ARMISD::BR: return "ARMISD::BR"; - case ARMISD::FSITOS: return "ARMISD::FSITOS"; - case ARMISD::FSITOD: return "ARMISD::FSITOD"; - case ARMISD::FMRRD: return "ARMISD::FMRRD"; - case ARMISD::FMDRR: return "ARMISD::FMDRR"; + if (N.getOpcode() != ISD::ADD && N.getOpcode() != ISD::SUB) { + Base = N; + if (N.getOpcode() == ISD::FrameIndex) { + int FI = cast(N)->getIndex(); + Base = CurDAG->getTargetFrameIndex(FI, TLI.getPointerTy()); + } else if (N.getOpcode() == ARMISD::Wrapper) { + Base = N.getOperand(0); + } + Offset = CurDAG->getRegister(0, MVT::i32); + Opc = CurDAG->getTargetConstant(ARM_AM::getAM2Opc(ARM_AM::add, 0, + ARM_AM::no_shift), + MVT::i32); + return true; } -} - -class ArgumentLayout { - std::vector is_reg; - std::vector pos; - std::vector types; -public: - ArgumentLayout(const std::vector &Types) { - types = Types; - - unsigned RegNum = 0; - unsigned StackOffset = 0; - for(std::vector::const_iterator I = Types.begin(); - I != Types.end(); - ++I) { - MVT::ValueType VT = *I; - assert(VT == MVT::i32 || VT == MVT::f32 || VT == MVT::f64); - unsigned size = MVT::getSizeInBits(VT)/32; - - RegNum = ((RegNum + size - 1) / size) * size; - if (RegNum < 4) { - pos.push_back(RegNum); - is_reg.push_back(true); - RegNum += size; + + // Match simple R +/- imm12 operands. + if (N.getOpcode() == ISD::ADD) + if (ConstantSDNode *RHS = dyn_cast(N.getOperand(1))) { + int RHSC = (int)RHS->getValue(); + if ((RHSC >= 0 && RHSC < 0x1000) || + (RHSC < 0 && RHSC > -0x1000)) { // 12 bits. + Base = N.getOperand(0); + if (Base.getOpcode() == ISD::FrameIndex) { + int FI = cast(Base)->getIndex(); + Base = CurDAG->getTargetFrameIndex(FI, TLI.getPointerTy()); + } + Offset = CurDAG->getRegister(0, MVT::i32); + + ARM_AM::AddrOpc AddSub = ARM_AM::add; + if (RHSC < 0) { + AddSub = ARM_AM::sub; + RHSC = - RHSC; + } + Opc = CurDAG->getTargetConstant(ARM_AM::getAM2Opc(AddSub, RHSC, + ARM_AM::no_shift), + MVT::i32); + return true; + } + } + + // Otherwise this is R +/- [possibly shifted] R + ARM_AM::AddrOpc AddSub = N.getOpcode() == ISD::ADD ? ARM_AM::add:ARM_AM::sub; + ARM_AM::ShiftOpc ShOpcVal = ARM_AM::getShiftOpcForNode(N.getOperand(1)); + unsigned ShAmt = 0; + + Base = N.getOperand(0); + Offset = N.getOperand(1); + + if (ShOpcVal != ARM_AM::no_shift) { + // Check to see if the RHS of the shift is a constant, if not, we can't fold + // it. + if (ConstantSDNode *Sh = + dyn_cast(N.getOperand(1).getOperand(1))) { + ShAmt = Sh->getValue(); + Offset = N.getOperand(1).getOperand(0); + } else { + ShOpcVal = ARM_AM::no_shift; + } + } + + // Try matching (R shl C) + (R). + if (N.getOpcode() == ISD::ADD && ShOpcVal == ARM_AM::no_shift) { + ShOpcVal = ARM_AM::getShiftOpcForNode(N.getOperand(0)); + if (ShOpcVal != ARM_AM::no_shift) { + // Check to see if the RHS of the shift is a constant, if not, we can't + // fold it. + if (ConstantSDNode *Sh = + dyn_cast(N.getOperand(0).getOperand(1))) { + ShAmt = Sh->getValue(); + Offset = N.getOperand(0).getOperand(0); + Base = N.getOperand(1); } else { - unsigned bytes = size * 32/8; - StackOffset = ((StackOffset + bytes - 1) / bytes) * bytes; - pos.push_back(StackOffset); - is_reg.push_back(false); - StackOffset += bytes; + ShOpcVal = ARM_AM::no_shift; } } } - unsigned getRegisterNum(unsigned argNum) { - assert(isRegister(argNum)); - return pos[argNum]; - } - unsigned getOffset(unsigned argNum) { - assert(isOffset(argNum)); - return pos[argNum]; - } - unsigned isRegister(unsigned argNum) { - assert(argNum < is_reg.size()); - return is_reg[argNum]; - } - unsigned isOffset(unsigned argNum) { - return !isRegister(argNum); - } - MVT::ValueType getType(unsigned argNum) { - assert(argNum < types.size()); - return types[argNum]; - } - unsigned getStackSize(void) { - int last = is_reg.size() - 1; - if (last < 0) - return 0; - if (isRegister(last)) - return 0; - return getOffset(last) + MVT::getSizeInBits(getType(last))/8; - } - int lastRegArg(void) { - int size = is_reg.size(); - int last = 0; - while(last < size && isRegister(last)) - last++; - last--; - return last; - } - int lastRegNum(void) { - int l = lastRegArg(); - if (l < 0) - return -1; - unsigned r = getRegisterNum(l); - MVT::ValueType t = getType(l); - assert(t == MVT::i32 || t == MVT::f32 || t == MVT::f64); - if (t == MVT::f64) - return r + 1; - return r; + + Opc = CurDAG->getTargetConstant(ARM_AM::getAM2Opc(AddSub, ShAmt, ShOpcVal), + MVT::i32); + return true; +} + +bool ARMDAGToDAGISel::SelectAddrMode2Offset(SDOperand Op, SDOperand N, + SDOperand &Offset, SDOperand &Opc) { + unsigned Opcode = Op.getOpcode(); + ISD::MemIndexedMode AM = (Opcode == ISD::LOAD) + ? cast(Op)->getAddressingMode() + : cast(Op)->getAddressingMode(); + ARM_AM::AddrOpc AddSub = (AM == ISD::PRE_INC || AM == ISD::POST_INC) + ? ARM_AM::add : ARM_AM::sub; + if (ConstantSDNode *C = dyn_cast(N)) { + int Val = (int)C->getValue(); + if (Val >= 0 && Val < 0x1000) { // 12 bits. + Offset = CurDAG->getRegister(0, MVT::i32); + Opc = CurDAG->getTargetConstant(ARM_AM::getAM2Opc(AddSub, Val, + ARM_AM::no_shift), + MVT::i32); + return true; + } } -}; -// This transforms a ISD::CALL node into a -// callseq_star <- ARMISD:CALL <- callseq_end -// chain -static SDOperand LowerCALL(SDOperand Op, SelectionDAG &DAG) { - SDOperand Chain = Op.getOperand(0); - unsigned CallConv = cast(Op.getOperand(1))->getValue(); - assert(CallConv == CallingConv::C && "unknown calling convention"); - bool isVarArg = cast(Op.getOperand(2))->getValue() != 0; - bool isTailCall = cast(Op.getOperand(3))->getValue() != 0; - assert(isTailCall == false && "tail call not supported"); - SDOperand Callee = Op.getOperand(4); - unsigned NumOps = (Op.getNumOperands() - 5) / 2; - SDOperand StackPtr = DAG.getRegister(ARM::R13, MVT::i32); - static const unsigned regs[] = { - ARM::R0, ARM::R1, ARM::R2, ARM::R3 - }; - - std::vector Types; - for (unsigned i = 0; i < NumOps; ++i) { - MVT::ValueType VT = Op.getOperand(5+2*i).getValueType(); - Types.push_back(VT); - } - ArgumentLayout Layout(Types); - - unsigned NumBytes = Layout.getStackSize(); - - Chain = DAG.getCALLSEQ_START(Chain, - DAG.getConstant(NumBytes, MVT::i32)); - - //Build a sequence of stores - std::vector MemOpChains; - for (unsigned i = Layout.lastRegArg() + 1; i < NumOps; ++i) { - SDOperand Arg = Op.getOperand(5+2*i); - unsigned ArgOffset = Layout.getOffset(i); - SDOperand PtrOff = DAG.getConstant(ArgOffset, StackPtr.getValueType()); - PtrOff = DAG.getNode(ISD::ADD, MVT::i32, StackPtr, PtrOff); - MemOpChains.push_back(DAG.getStore(Chain, Arg, PtrOff, - DAG.getSrcValue(NULL))); - } - if (!MemOpChains.empty()) - Chain = DAG.getNode(ISD::TokenFactor, MVT::Other, - &MemOpChains[0], MemOpChains.size()); - - // If the callee is a GlobalAddress/ExternalSymbol node (quite common, every - // direct call is) turn it into a TargetGlobalAddress/TargetExternalSymbol - // node so that legalize doesn't hack it. - if (GlobalAddressSDNode *G = dyn_cast(Callee)) - Callee = DAG.getTargetGlobalAddress(G->getGlobal(), Callee.getValueType()); - - // If this is a direct call, pass the chain and the callee. - assert (Callee.Val); - std::vector Ops; - Ops.push_back(Chain); - Ops.push_back(Callee); - - // Build a sequence of copy-to-reg nodes chained together with token chain - // and flag operands which copy the outgoing args into the appropriate regs. - SDOperand InFlag; - for (int i = 0, e = Layout.lastRegArg(); i <= e; ++i) { - SDOperand Arg = Op.getOperand(5+2*i); - unsigned RegNum = Layout.getRegisterNum(i); - unsigned Reg1 = regs[RegNum]; - MVT::ValueType VT = Layout.getType(i); - assert(VT == Arg.getValueType()); - assert(VT == MVT::i32 || VT == MVT::f32 || VT == MVT::f64); - - // Add argument register to the end of the list so that it is known live - // into the call. - Ops.push_back(DAG.getRegister(Reg1, MVT::i32)); - if (VT == MVT::f64) { - unsigned Reg2 = regs[RegNum + 1]; - SDOperand SDReg1 = DAG.getRegister(Reg1, MVT::i32); - SDOperand SDReg2 = DAG.getRegister(Reg2, MVT::i32); - - Ops.push_back(DAG.getRegister(Reg2, MVT::i32)); - SDVTList VTs = DAG.getVTList(MVT::Other, MVT::Flag); - SDOperand Ops[] = {Chain, SDReg1, SDReg2, Arg}; //missing flag - Chain = DAG.getNode(ARMISD::FMRRD, VTs, Ops, 4); + Offset = N; + ARM_AM::ShiftOpc ShOpcVal = ARM_AM::getShiftOpcForNode(N); + unsigned ShAmt = 0; + if (ShOpcVal != ARM_AM::no_shift) { + // Check to see if the RHS of the shift is a constant, if not, we can't fold + // it. + if (ConstantSDNode *Sh = dyn_cast(N.getOperand(1))) { + ShAmt = Sh->getValue(); + Offset = N.getOperand(0); } else { - if (VT == MVT::f32) - Arg = DAG.getNode(ISD::BIT_CONVERT, MVT::i32, Arg); - Chain = DAG.getCopyToReg(Chain, Reg1, Arg, InFlag); - } - InFlag = Chain.getValue(1); - } - - std::vector NodeTys; - NodeTys.push_back(MVT::Other); // Returns a chain - NodeTys.push_back(MVT::Flag); // Returns a flag for retval copy to use. - - unsigned CallOpc = ARMISD::CALL; - if (InFlag.Val) - Ops.push_back(InFlag); - Chain = DAG.getNode(CallOpc, NodeTys, &Ops[0], Ops.size()); - InFlag = Chain.getValue(1); - - std::vector ResultVals; - NodeTys.clear(); - - // If the call has results, copy the values out of the ret val registers. - MVT::ValueType VT = Op.Val->getValueType(0); - if (VT != MVT::Other) { - assert(VT == MVT::i32 || VT == MVT::f32 || VT == MVT::f64); - SDOperand Value; - - SDOperand Value1 = DAG.getCopyFromReg(Chain, ARM::R0, MVT::i32, InFlag); - Chain = Value1.getValue(1); - InFlag = Value1.getValue(2); - if (VT == MVT::i32) - Value = Value1; - if (VT == MVT::f32) - Value = DAG.getNode(ISD::BIT_CONVERT, MVT::f32, Value1); - if (VT == MVT::f64) { - SDOperand Value2 = DAG.getCopyFromReg(Chain, ARM::R1, MVT::i32, InFlag); - Chain = Value2.getValue(1); - Value = DAG.getNode(ARMISD::FMDRR, MVT::f64, Value1, Value2); + ShOpcVal = ARM_AM::no_shift; } - ResultVals.push_back(Value); - NodeTys.push_back(VT); } - Chain = DAG.getNode(ISD::CALLSEQ_END, MVT::Other, Chain, - DAG.getConstant(NumBytes, MVT::i32)); - NodeTys.push_back(MVT::Other); - - if (ResultVals.empty()) - return Chain; - - ResultVals.push_back(Chain); - SDOperand Res = DAG.getNode(ISD::MERGE_VALUES, NodeTys, &ResultVals[0], - ResultVals.size()); - return Res.getValue(Op.ResNo); + Opc = CurDAG->getTargetConstant(ARM_AM::getAM2Opc(AddSub, ShAmt, ShOpcVal), + MVT::i32); + return true; } -static SDOperand LowerRET(SDOperand Op, SelectionDAG &DAG) { - SDOperand Copy; - SDOperand Chain = Op.getOperand(0); - SDOperand R0 = DAG.getRegister(ARM::R0, MVT::i32); - SDOperand R1 = DAG.getRegister(ARM::R1, MVT::i32); - - switch(Op.getNumOperands()) { - default: - assert(0 && "Do not know how to return this many arguments!"); - abort(); - case 1: { - SDOperand LR = DAG.getRegister(ARM::R14, MVT::i32); - return DAG.getNode(ARMISD::RET_FLAG, MVT::Other, Chain); - } - case 3: { - SDOperand Val = Op.getOperand(1); - assert(Val.getValueType() == MVT::i32 || - Val.getValueType() == MVT::f32 || - Val.getValueType() == MVT::f64); - - if (Val.getValueType() == MVT::f64) { - SDVTList VTs = DAG.getVTList(MVT::Other, MVT::Flag); - SDOperand Ops[] = {Chain, R0, R1, Val}; - Copy = DAG.getNode(ARMISD::FMRRD, VTs, Ops, 4); - } else { - if (Val.getValueType() == MVT::f32) - Val = DAG.getNode(ISD::BIT_CONVERT, MVT::i32, Val); - Copy = DAG.getCopyToReg(Chain, R0, Val, SDOperand()); - } - if (DAG.getMachineFunction().liveout_empty()) { - DAG.getMachineFunction().addLiveOut(ARM::R0); - if (Val.getValueType() == MVT::f64) - DAG.getMachineFunction().addLiveOut(ARM::R1); - } - break; +bool ARMDAGToDAGISel::SelectAddrMode3(SDOperand Op, SDOperand N, + SDOperand &Base, SDOperand &Offset, + SDOperand &Opc) { + if (N.getOpcode() == ISD::SUB) { + // X - C is canonicalize to X + -C, no need to handle it here. + Base = N.getOperand(0); + Offset = N.getOperand(1); + Opc = CurDAG->getTargetConstant(ARM_AM::getAM3Opc(ARM_AM::sub, 0),MVT::i32); + return true; } - case 5: - Copy = DAG.getCopyToReg(Chain, ARM::R1, Op.getOperand(3), SDOperand()); - Copy = DAG.getCopyToReg(Copy, ARM::R0, Op.getOperand(1), Copy.getValue(1)); - // If we haven't noted the R0+R1 are live out, do so now. - if (DAG.getMachineFunction().liveout_empty()) { - DAG.getMachineFunction().addLiveOut(ARM::R0); - DAG.getMachineFunction().addLiveOut(ARM::R1); + + if (N.getOpcode() != ISD::ADD) { + Base = N; + if (N.getOpcode() == ISD::FrameIndex) { + int FI = cast(N)->getIndex(); + Base = CurDAG->getTargetFrameIndex(FI, TLI.getPointerTy()); } - break; + Offset = CurDAG->getRegister(0, MVT::i32); + Opc = CurDAG->getTargetConstant(ARM_AM::getAM3Opc(ARM_AM::add, 0),MVT::i32); + return true; } + + // If the RHS is +/- imm8, fold into addr mode. + if (ConstantSDNode *RHS = dyn_cast(N.getOperand(1))) { + int RHSC = (int)RHS->getValue(); + if ((RHSC >= 0 && RHSC < 256) || + (RHSC < 0 && RHSC > -256)) { // note -256 itself isn't allowed. + Base = N.getOperand(0); + if (Base.getOpcode() == ISD::FrameIndex) { + int FI = cast(Base)->getIndex(); + Base = CurDAG->getTargetFrameIndex(FI, TLI.getPointerTy()); + } + Offset = CurDAG->getRegister(0, MVT::i32); - //We must use RET_FLAG instead of BRIND because BRIND doesn't have a flag - return DAG.getNode(ARMISD::RET_FLAG, MVT::Other, Copy, Copy.getValue(1)); + ARM_AM::AddrOpc AddSub = ARM_AM::add; + if (RHSC < 0) { + AddSub = ARM_AM::sub; + RHSC = - RHSC; + } + Opc = CurDAG->getTargetConstant(ARM_AM::getAM3Opc(AddSub, RHSC),MVT::i32); + return true; + } + } + + Base = N.getOperand(0); + Offset = N.getOperand(1); + Opc = CurDAG->getTargetConstant(ARM_AM::getAM3Opc(ARM_AM::add, 0), MVT::i32); + return true; } -static SDOperand LowerConstantPool(SDOperand Op, SelectionDAG &DAG) { - MVT::ValueType PtrVT = Op.getValueType(); - ConstantPoolSDNode *CP = cast(Op); - Constant *C = CP->getConstVal(); - SDOperand CPI = DAG.getTargetConstantPool(C, PtrVT, CP->getAlignment()); +bool ARMDAGToDAGISel::SelectAddrMode3Offset(SDOperand Op, SDOperand N, + SDOperand &Offset, SDOperand &Opc) { + unsigned Opcode = Op.getOpcode(); + ISD::MemIndexedMode AM = (Opcode == ISD::LOAD) + ? cast(Op)->getAddressingMode() + : cast(Op)->getAddressingMode(); + ARM_AM::AddrOpc AddSub = (AM == ISD::PRE_INC || AM == ISD::POST_INC) + ? ARM_AM::add : ARM_AM::sub; + if (ConstantSDNode *C = dyn_cast(N)) { + int Val = (int)C->getValue(); + if (Val >= 0 && Val < 256) { + Offset = CurDAG->getRegister(0, MVT::i32); + Opc = CurDAG->getTargetConstant(ARM_AM::getAM3Opc(AddSub, Val), MVT::i32); + return true; + } + } - return CPI; + Offset = N; + Opc = CurDAG->getTargetConstant(ARM_AM::getAM3Opc(AddSub, 0), MVT::i32); + return true; } -static SDOperand LowerGlobalAddress(SDOperand Op, - SelectionDAG &DAG) { - GlobalValue *GV = cast(Op)->getGlobal(); - int alignment = 2; - SDOperand CPAddr = DAG.getConstantPool(GV, MVT::i32, alignment); - return DAG.getLoad(MVT::i32, DAG.getEntryNode(), CPAddr, - DAG.getSrcValue(NULL)); + +bool ARMDAGToDAGISel::SelectAddrMode5(SDOperand Op, SDOperand N, + SDOperand &Base, SDOperand &Offset) { + if (N.getOpcode() != ISD::ADD) { + Base = N; + if (N.getOpcode() == ISD::FrameIndex) { + int FI = cast(N)->getIndex(); + Base = CurDAG->getTargetFrameIndex(FI, TLI.getPointerTy()); + } else if (N.getOpcode() == ARMISD::Wrapper) { + Base = N.getOperand(0); + } + Offset = CurDAG->getTargetConstant(ARM_AM::getAM5Opc(ARM_AM::add, 0), + MVT::i32); + return true; + } + + // If the RHS is +/- imm8, fold into addr mode. + if (ConstantSDNode *RHS = dyn_cast(N.getOperand(1))) { + int RHSC = (int)RHS->getValue(); + if ((RHSC & 3) == 0) { // The constant is implicitly multiplied by 4. + RHSC >>= 2; + if ((RHSC >= 0 && RHSC < 256) || + (RHSC < 0 && RHSC > -256)) { // note -256 itself isn't allowed. + Base = N.getOperand(0); + if (Base.getOpcode() == ISD::FrameIndex) { + int FI = cast(Base)->getIndex(); + Base = CurDAG->getTargetFrameIndex(FI, TLI.getPointerTy()); + } + + ARM_AM::AddrOpc AddSub = ARM_AM::add; + if (RHSC < 0) { + AddSub = ARM_AM::sub; + RHSC = - RHSC; + } + Offset = CurDAG->getTargetConstant(ARM_AM::getAM5Opc(AddSub, RHSC), + MVT::i32); + return true; + } + } + } + + Base = N; + Offset = CurDAG->getTargetConstant(ARM_AM::getAM5Opc(ARM_AM::add, 0), + MVT::i32); + return true; } -static SDOperand LowerVASTART(SDOperand Op, SelectionDAG &DAG, - unsigned VarArgsFrameIndex) { - // vastart just stores the address of the VarArgsFrameIndex slot into the - // memory location argument. - MVT::ValueType PtrVT = DAG.getTargetLoweringInfo().getPointerTy(); - SDOperand FR = DAG.getFrameIndex(VarArgsFrameIndex, PtrVT); - return DAG.getStore(Op.getOperand(0), FR, Op.getOperand(1), Op.getOperand(2)); +bool ARMDAGToDAGISel::SelectAddrModePC(SDOperand Op, SDOperand N, + SDOperand &Offset, SDOperand &Label) { + if (N.getOpcode() == ARMISD::PIC_ADD && N.hasOneUse()) { + Offset = N.getOperand(0); + SDOperand N1 = N.getOperand(1); + Label = CurDAG->getTargetConstant(cast(N1)->getValue(), + MVT::i32); + return true; + } + return false; } -static SDOperand LowerFORMAL_ARGUMENTS(SDOperand Op, SelectionDAG &DAG, - int &VarArgsFrameIndex) { - MachineFunction &MF = DAG.getMachineFunction(); - MachineFrameInfo *MFI = MF.getFrameInfo(); - SSARegMap *RegMap = MF.getSSARegMap(); - unsigned NumArgs = Op.Val->getNumValues()-1; - SDOperand Root = Op.getOperand(0); - bool isVarArg = cast(Op.getOperand(2))->getValue() != 0; - static const unsigned REGS[] = { - ARM::R0, ARM::R1, ARM::R2, ARM::R3 - }; - - std::vector Types(Op.Val->value_begin(), Op.Val->value_end() - 1); - ArgumentLayout Layout(Types); - - std::vector ArgValues; - for (unsigned ArgNo = 0; ArgNo < NumArgs; ++ArgNo) { - MVT::ValueType VT = Types[ArgNo]; - - SDOperand Value; - if (Layout.isRegister(ArgNo)) { - assert(VT == MVT::i32 || VT == MVT::f32 || VT == MVT::f64); - unsigned RegNum = Layout.getRegisterNum(ArgNo); - unsigned Reg1 = REGS[RegNum]; - unsigned VReg1 = RegMap->createVirtualRegister(&ARM::IntRegsRegClass); - SDOperand Value1 = DAG.getCopyFromReg(Root, VReg1, MVT::i32); - MF.addLiveIn(Reg1, VReg1); - if (VT == MVT::f64) { - unsigned Reg2 = REGS[RegNum + 1]; - unsigned VReg2 = RegMap->createVirtualRegister(&ARM::IntRegsRegClass); - SDOperand Value2 = DAG.getCopyFromReg(Root, VReg2, MVT::i32); - MF.addLiveIn(Reg2, VReg2); - Value = DAG.getNode(ARMISD::FMDRR, MVT::f64, Value1, Value2); - } else { - Value = Value1; - if (VT == MVT::f32) - Value = DAG.getNode(ISD::BIT_CONVERT, VT, Value); - } - } else { - // If the argument is actually used, emit a load from the right stack - // slot. - if (!Op.Val->hasNUsesOfValue(0, ArgNo)) { - unsigned Offset = Layout.getOffset(ArgNo); - unsigned Size = MVT::getSizeInBits(VT)/8; - int FI = MFI->CreateFixedObject(Size, Offset); - SDOperand FIN = DAG.getFrameIndex(FI, VT); - Value = DAG.getLoad(VT, Root, FIN, DAG.getSrcValue(NULL)); - } else { - Value = DAG.getNode(ISD::UNDEF, VT); - } - } - ArgValues.push_back(Value); +bool ARMDAGToDAGISel::SelectThumbAddrModeRR(SDOperand Op, SDOperand N, + SDOperand &Base, SDOperand &Offset){ + if (N.getOpcode() != ISD::ADD) { + Base = N; + // We must materialize a zero in a reg! Returning an constant here won't + // work since its node is -1 so it won't get added to the selection queue. + // Explicitly issue a tMOVri8 node! + Offset = SDOperand(CurDAG->getTargetNode(ARM::tMOVi8, MVT::i32, + CurDAG->getTargetConstant(0, MVT::i32)), 0); + return true; } - unsigned NextRegNum = Layout.lastRegNum() + 1; + Base = N.getOperand(0); + Offset = N.getOperand(1); + return true; +} - if (isVarArg) { - //If this function is vararg we must store the remaing - //registers so that they can be acessed with va_start - VarArgsFrameIndex = MFI->CreateFixedObject(MVT::getSizeInBits(MVT::i32)/8, - -16 + NextRegNum * 4); +bool +ARMDAGToDAGISel::SelectThumbAddrModeRI5(SDOperand Op, SDOperand N, + unsigned Scale, SDOperand &Base, + SDOperand &OffImm, SDOperand &Offset) { + if (Scale == 4) { + SDOperand TmpBase, TmpOffImm; + if (SelectThumbAddrModeSP(Op, N, TmpBase, TmpOffImm)) + return false; // We want to select tLDRspi / tSTRspi instead. + if (N.getOpcode() == ARMISD::Wrapper && + N.getOperand(0).getOpcode() == ISD::TargetConstantPool) + return false; // We want to select tLDRpci instead. + } - SmallVector MemOps; - for (unsigned RegNo = NextRegNum; RegNo < 4; ++RegNo) { - int RegOffset = - (4 - RegNo) * 4; - int FI = MFI->CreateFixedObject(MVT::getSizeInBits(MVT::i32)/8, - RegOffset); - SDOperand FIN = DAG.getFrameIndex(FI, MVT::i32); + if (N.getOpcode() != ISD::ADD) { + Base = (N.getOpcode() == ARMISD::Wrapper) ? N.getOperand(0) : N; + Offset = CurDAG->getRegister(0, MVT::i32); + OffImm = CurDAG->getTargetConstant(0, MVT::i32); + return true; + } - unsigned VReg = RegMap->createVirtualRegister(&ARM::IntRegsRegClass); - MF.addLiveIn(REGS[RegNo], VReg); + // Thumb does not have [sp, r] address mode. + RegisterSDNode *LHSR = dyn_cast(N.getOperand(0)); + RegisterSDNode *RHSR = dyn_cast(N.getOperand(1)); + if ((LHSR && LHSR->getReg() == ARM::SP) || + (RHSR && RHSR->getReg() == ARM::SP)) { + Base = N; + Offset = CurDAG->getRegister(0, MVT::i32); + OffImm = CurDAG->getTargetConstant(0, MVT::i32); + return true; + } - SDOperand Val = DAG.getCopyFromReg(Root, VReg, MVT::i32); - SDOperand Store = DAG.getStore(Val.getValue(1), Val, FIN, - DAG.getSrcValue(NULL)); - MemOps.push_back(Store); + // If the RHS is + imm5 * scale, fold into addr mode. + if (ConstantSDNode *RHS = dyn_cast(N.getOperand(1))) { + int RHSC = (int)RHS->getValue(); + if ((RHSC & (Scale-1)) == 0) { // The constant is implicitly multiplied. + RHSC /= Scale; + if (RHSC >= 0 && RHSC < 32) { + Base = N.getOperand(0); + Offset = CurDAG->getRegister(0, MVT::i32); + OffImm = CurDAG->getTargetConstant(RHSC, MVT::i32); + return true; + } } - Root = DAG.getNode(ISD::TokenFactor, MVT::Other,&MemOps[0],MemOps.size()); } - ArgValues.push_back(Root); - - // Return the new list of results. - std::vector RetVT(Op.Val->value_begin(), - Op.Val->value_end()); - return DAG.getNode(ISD::MERGE_VALUES, RetVT, &ArgValues[0], ArgValues.size()); + Base = N.getOperand(0); + Offset = N.getOperand(1); + OffImm = CurDAG->getTargetConstant(0, MVT::i32); + return true; } -static SDOperand LowerSELECT_CC(SDOperand Op, SelectionDAG &DAG) { - SDOperand LHS = Op.getOperand(0); - SDOperand RHS = Op.getOperand(1); - ISD::CondCode CC = cast(Op.getOperand(4))->get(); - SDOperand TrueVal = Op.getOperand(2); - SDOperand FalseVal = Op.getOperand(3); - SDOperand ARMCC = DAG.getConstant(DAGCCToARMCC(CC), MVT::i32); - - SDOperand Cmp = DAG.getNode(ARMISD::CMP, MVT::Flag, LHS, RHS); - return DAG.getNode(ARMISD::SELECT, MVT::i32, TrueVal, FalseVal, ARMCC, Cmp); +bool ARMDAGToDAGISel::SelectThumbAddrModeS1(SDOperand Op, SDOperand N, + SDOperand &Base, SDOperand &OffImm, + SDOperand &Offset) { + return SelectThumbAddrModeRI5(Op, N, 1, Base, OffImm, Offset); } -static SDOperand LowerBR_CC(SDOperand Op, SelectionDAG &DAG) { - SDOperand Chain = Op.getOperand(0); - ISD::CondCode CC = cast(Op.getOperand(1))->get(); - SDOperand LHS = Op.getOperand(2); - SDOperand RHS = Op.getOperand(3); - SDOperand Dest = Op.getOperand(4); - SDOperand ARMCC = DAG.getConstant(DAGCCToARMCC(CC), MVT::i32); - - SDOperand Cmp = DAG.getNode(ARMISD::CMP, MVT::Flag, LHS, RHS); - return DAG.getNode(ARMISD::BR, MVT::Other, Chain, Dest, ARMCC, Cmp); +bool ARMDAGToDAGISel::SelectThumbAddrModeS2(SDOperand Op, SDOperand N, + SDOperand &Base, SDOperand &OffImm, + SDOperand &Offset) { + return SelectThumbAddrModeRI5(Op, N, 2, Base, OffImm, Offset); } -static SDOperand LowerSINT_TO_FP(SDOperand Op, SelectionDAG &DAG) { - SDOperand IntVal = Op.getOperand(0); - assert(IntVal.getValueType() == MVT::i32); - MVT::ValueType vt = Op.getValueType(); - assert(vt == MVT::f32 || - vt == MVT::f64); - - SDOperand Tmp = DAG.getNode(ISD::BIT_CONVERT, MVT::f32, IntVal); - ARMISD::NodeType op = vt == MVT::f32 ? ARMISD::FSITOS : ARMISD::FSITOD; - return DAG.getNode(op, vt, Tmp); +bool ARMDAGToDAGISel::SelectThumbAddrModeS4(SDOperand Op, SDOperand N, + SDOperand &Base, SDOperand &OffImm, + SDOperand &Offset) { + return SelectThumbAddrModeRI5(Op, N, 4, Base, OffImm, Offset); } -SDOperand ARMTargetLowering::LowerOperation(SDOperand Op, SelectionDAG &DAG) { - switch (Op.getOpcode()) { - default: - assert(0 && "Should not custom lower this!"); - abort(); - case ISD::ConstantPool: - return LowerConstantPool(Op, DAG); - case ISD::GlobalAddress: - return LowerGlobalAddress(Op, DAG); - case ISD::SINT_TO_FP: - return LowerSINT_TO_FP(Op, DAG); - case ISD::FORMAL_ARGUMENTS: - return LowerFORMAL_ARGUMENTS(Op, DAG, VarArgsFrameIndex); - case ISD::CALL: - return LowerCALL(Op, DAG); - case ISD::RET: - return LowerRET(Op, DAG); - case ISD::SELECT_CC: - return LowerSELECT_CC(Op, DAG); - case ISD::BR_CC: - return LowerBR_CC(Op, DAG); - case ISD::VASTART: - return LowerVASTART(Op, DAG, VarArgsFrameIndex); +bool ARMDAGToDAGISel::SelectThumbAddrModeSP(SDOperand Op, SDOperand N, + SDOperand &Base, SDOperand &OffImm) { + if (N.getOpcode() == ISD::FrameIndex) { + int FI = cast(N)->getIndex(); + Base = CurDAG->getTargetFrameIndex(FI, TLI.getPointerTy()); + OffImm = CurDAG->getTargetConstant(0, MVT::i32); + return true; } -} - -//===----------------------------------------------------------------------===// -// Instruction Selector Implementation -//===----------------------------------------------------------------------===// -//===--------------------------------------------------------------------===// -/// ARMDAGToDAGISel - ARM specific code to select ARM machine -/// instructions for SelectionDAG operations. -/// -namespace { -class ARMDAGToDAGISel : public SelectionDAGISel { - ARMTargetLowering Lowering; + if (N.getOpcode() != ISD::ADD) + return false; -public: - ARMDAGToDAGISel(TargetMachine &TM) - : SelectionDAGISel(Lowering), Lowering(TM) { + RegisterSDNode *LHSR = dyn_cast(N.getOperand(0)); + if (N.getOperand(0).getOpcode() == ISD::FrameIndex || + (LHSR && LHSR->getReg() == ARM::SP)) { + // If the RHS is + imm8 * scale, fold into addr mode. + if (ConstantSDNode *RHS = dyn_cast(N.getOperand(1))) { + int RHSC = (int)RHS->getValue(); + if ((RHSC & 3) == 0) { // The constant is implicitly multiplied. + RHSC >>= 2; + if (RHSC >= 0 && RHSC < 256) { + Base = N.getOperand(0); + if (Base.getOpcode() == ISD::FrameIndex) { + int FI = cast(Base)->getIndex(); + Base = CurDAG->getTargetFrameIndex(FI, TLI.getPointerTy()); + } + OffImm = CurDAG->getTargetConstant(RHSC, MVT::i32); + return true; + } + } + } } - - SDNode *Select(SDOperand Op); - virtual void InstructionSelectBasicBlock(SelectionDAG &DAG); - bool SelectAddrRegImm(SDOperand N, SDOperand &Offset, SDOperand &Base); - bool SelectAddrMode1(SDOperand N, SDOperand &Arg, SDOperand &Shift, - SDOperand &ShiftType); - - // Include the pieces autogenerated from the target description. -#include "ARMGenDAGISel.inc" -}; - -void ARMDAGToDAGISel::InstructionSelectBasicBlock(SelectionDAG &DAG) { - DEBUG(BB->dump()); - - DAG.setRoot(SelectRoot(DAG.getRoot())); - DAG.RemoveDeadNodes(); - - ScheduleAndEmitDAG(DAG); + + return false; } -static bool isInt12Immediate(SDNode *N, short &Imm) { - if (N->getOpcode() != ISD::Constant) - return false; - - int32_t t = cast(N)->getValue(); - int max = 1<<12; - int min = -max; - if (t > min && t < max) { - Imm = t; - return true; +bool ARMDAGToDAGISel::SelectShifterOperandReg(SDOperand Op, + SDOperand N, + SDOperand &BaseReg, + SDOperand &ShReg, + SDOperand &Opc) { + ARM_AM::ShiftOpc ShOpcVal = ARM_AM::getShiftOpcForNode(N); + + // Don't match base register only case. That is matched to a separate + // lower complexity pattern with explicit register operand. + if (ShOpcVal == ARM_AM::no_shift) return false; + + BaseReg = N.getOperand(0); + unsigned ShImmVal = 0; + if (ConstantSDNode *RHS = dyn_cast(N.getOperand(1))) { + ShReg = CurDAG->getRegister(0, MVT::i32); + ShImmVal = RHS->getValue() & 31; + } else { + ShReg = N.getOperand(1); } - else - return false; + Opc = CurDAG->getTargetConstant(ARM_AM::getSORegOpc(ShOpcVal, ShImmVal), + MVT::i32); + return true; } -static bool isInt12Immediate(SDOperand Op, short &Imm) { - return isInt12Immediate(Op.Val, Imm); +/// getAL - Returns a ARMCC::AL immediate node. +static inline SDOperand getAL(SelectionDAG *CurDAG) { + return CurDAG->getTargetConstant((uint64_t)ARMCC::AL, MVT::i32); } -static uint32_t rotateL(uint32_t x) { - uint32_t bit31 = (x & (1 << 31)) >> 31; - uint32_t t = x << 1; - return t | bit31; -} -static bool isUInt8Immediate(uint32_t x) { - return x < (1 << 8); -} +SDNode *ARMDAGToDAGISel::Select(SDOperand Op) { + SDNode *N = Op.Val; + unsigned Opcode = N->getOpcode(); -static bool isRotInt8Immediate(uint32_t x) { - int r; - for (r = 0; r < 16; r++) { - if (isUInt8Immediate(x)) - return true; - x = rotateL(rotateL(x)); - } - return false; -} + if (Opcode >= ISD::BUILTIN_OP_END && Opcode < ARMISD::FIRST_NUMBER) + return NULL; // Already selected. -bool ARMDAGToDAGISel::SelectAddrMode1(SDOperand N, - SDOperand &Arg, - SDOperand &Shift, - SDOperand &ShiftType) { - switch(N.getOpcode()) { + switch (N->getOpcode()) { + default: break; case ISD::Constant: { - uint32_t val = cast(N)->getValue(); - if(!isRotInt8Immediate(val)) { - const Type *t = MVT::getTypeForValueType(MVT::i32); - Constant *C = ConstantUInt::get(t, val); - int alignment = 2; - SDOperand Addr = CurDAG->getTargetConstantPool(C, MVT::i32, alignment); - SDOperand Z = CurDAG->getTargetConstant(0, MVT::i32); - SDNode *n = CurDAG->getTargetNode(ARM::ldr, MVT::i32, Z, Addr); - Arg = SDOperand(n, 0); - } else - Arg = CurDAG->getTargetConstant(val, MVT::i32); - - Shift = CurDAG->getTargetConstant(0, MVT::i32); - ShiftType = CurDAG->getTargetConstant(ARMShift::LSL, MVT::i32); - return true; + unsigned Val = cast(N)->getValue(); + bool UseCP = true; + if (Subtarget->isThumb()) + UseCP = (Val > 255 && // MOV + ~Val > 255 && // MOV + MVN + !ARM_AM::isThumbImmShiftedVal(Val)); // MOV + LSL + else + UseCP = (ARM_AM::getSOImmVal(Val) == -1 && // MOV + ARM_AM::getSOImmVal(~Val) == -1 && // MVN + !ARM_AM::isSOImmTwoPartVal(Val)); // two instrs. + if (UseCP) { + SDOperand CPIdx = + CurDAG->getTargetConstantPool(ConstantInt::get(Type::Int32Ty, Val), + TLI.getPointerTy()); + + SDNode *ResNode; + if (Subtarget->isThumb()) + ResNode = CurDAG->getTargetNode(ARM::tLDRcp, MVT::i32, MVT::Other, + CPIdx, CurDAG->getEntryNode()); + else { + SDOperand Ops[] = { + CPIdx, + CurDAG->getRegister(0, MVT::i32), + CurDAG->getTargetConstant(0, MVT::i32), + getAL(CurDAG), + CurDAG->getRegister(0, MVT::i32), + CurDAG->getEntryNode() + }; + ResNode=CurDAG->getTargetNode(ARM::LDRcp, MVT::i32, MVT::Other, Ops, 6); + } + ReplaceUses(Op, SDOperand(ResNode, 0)); + return NULL; + } + + // Other cases are autogenerated. + break; } - case ISD::SRA: - Arg = N.getOperand(0); - Shift = N.getOperand(1); - ShiftType = CurDAG->getTargetConstant(ARMShift::ASR, MVT::i32); - return true; - case ISD::SRL: - Arg = N.getOperand(0); - Shift = N.getOperand(1); - ShiftType = CurDAG->getTargetConstant(ARMShift::LSR, MVT::i32); - return true; - case ISD::SHL: - Arg = N.getOperand(0); - Shift = N.getOperand(1); - ShiftType = CurDAG->getTargetConstant(ARMShift::LSL, MVT::i32); - return true; + case ISD::FrameIndex: { + // Selects to ADDri FI, 0 which in turn will become ADDri SP, imm. + int FI = cast(N)->getIndex(); + SDOperand TFI = CurDAG->getTargetFrameIndex(FI, TLI.getPointerTy()); + if (Subtarget->isThumb()) + return CurDAG->SelectNodeTo(N, ARM::tADDrSPi, MVT::i32, TFI, + CurDAG->getTargetConstant(0, MVT::i32)); + else { + SDOperand Ops[] = { TFI, CurDAG->getTargetConstant(0, MVT::i32), + getAL(CurDAG), CurDAG->getRegister(0, MVT::i32), + CurDAG->getRegister(0, MVT::i32) }; + return CurDAG->SelectNodeTo(N, ARM::ADDri, MVT::i32, Ops, 5); + } } - - Arg = N; - Shift = CurDAG->getTargetConstant(0, MVT::i32); - ShiftType = CurDAG->getTargetConstant(ARMShift::LSL, MVT::i32); - return true; -} - -//register plus/minus 12 bit offset -bool ARMDAGToDAGISel::SelectAddrRegImm(SDOperand N, SDOperand &Offset, - SDOperand &Base) { - if (FrameIndexSDNode *FIN = dyn_cast(N)) { - Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i32); - Offset = CurDAG->getTargetConstant(0, MVT::i32); - return true; + case ISD::ADD: { + // Select add sp, c to tADDhirr. + SDOperand N0 = Op.getOperand(0); + SDOperand N1 = Op.getOperand(1); + RegisterSDNode *LHSR = dyn_cast(Op.getOperand(0)); + RegisterSDNode *RHSR = dyn_cast(Op.getOperand(1)); + if (LHSR && LHSR->getReg() == ARM::SP) { + std::swap(N0, N1); + std::swap(LHSR, RHSR); + } + if (RHSR && RHSR->getReg() == ARM::SP) { + AddToISelQueue(N0); + AddToISelQueue(N1); + return CurDAG->SelectNodeTo(N, ARM::tADDhirr, Op.getValueType(), N0, N1); + } + break; } - if (N.getOpcode() == ISD::ADD) { - short imm = 0; - if (isInt12Immediate(N.getOperand(1), imm)) { - Offset = CurDAG->getTargetConstant(imm, MVT::i32); - if (FrameIndexSDNode *FI = dyn_cast(N.getOperand(0))) { - Base = CurDAG->getTargetFrameIndex(FI->getIndex(), N.getValueType()); - } else { - Base = N.getOperand(0); + case ISD::MUL: + if (Subtarget->isThumb()) + break; + if (ConstantSDNode *C = dyn_cast(Op.getOperand(1))) { + unsigned RHSV = C->getValue(); + if (!RHSV) break; + if (isPowerOf2_32(RHSV-1)) { // 2^n+1? + SDOperand V = Op.getOperand(0); + AddToISelQueue(V); + unsigned ShImm = ARM_AM::getSORegOpc(ARM_AM::lsl, Log2_32(RHSV-1)); + SDOperand Ops[] = { V, V, CurDAG->getRegister(0, MVT::i32), + CurDAG->getTargetConstant(ShImm, MVT::i32), + getAL(CurDAG), CurDAG->getRegister(0, MVT::i32), + CurDAG->getRegister(0, MVT::i32) }; + return CurDAG->SelectNodeTo(N, ARM::ADDrs, MVT::i32, Ops, 7); + } + if (isPowerOf2_32(RHSV+1)) { // 2^n-1? + SDOperand V = Op.getOperand(0); + AddToISelQueue(V); + unsigned ShImm = ARM_AM::getSORegOpc(ARM_AM::lsl, Log2_32(RHSV+1)); + SDOperand Ops[] = { V, V, CurDAG->getRegister(0, MVT::i32), + CurDAG->getTargetConstant(ShImm, MVT::i32), + getAL(CurDAG), CurDAG->getRegister(0, MVT::i32), + CurDAG->getRegister(0, MVT::i32) }; + return CurDAG->SelectNodeTo(N, ARM::RSBrs, MVT::i32, Ops, 7); } - return true; // [r+i] } + break; + case ARMISD::FMRRD: + AddToISelQueue(Op.getOperand(0)); + return CurDAG->getTargetNode(ARM::FMRRD, MVT::i32, MVT::i32, + Op.getOperand(0), getAL(CurDAG), + CurDAG->getRegister(0, MVT::i32)); + case ARMISD::MULHILOU: { + AddToISelQueue(Op.getOperand(0)); + AddToISelQueue(Op.getOperand(1)); + SDOperand Ops[] = { Op.getOperand(0), Op.getOperand(1), + getAL(CurDAG), CurDAG->getRegister(0, MVT::i32), + CurDAG->getRegister(0, MVT::i32) }; + return CurDAG->getTargetNode(ARM::UMULL, MVT::i32, MVT::i32, Ops, 5); + } + case ARMISD::MULHILOS: { + AddToISelQueue(Op.getOperand(0)); + AddToISelQueue(Op.getOperand(1)); + SDOperand Ops[] = { Op.getOperand(0), Op.getOperand(1), + getAL(CurDAG), CurDAG->getRegister(0, MVT::i32), + CurDAG->getRegister(0, MVT::i32) }; + return CurDAG->getTargetNode(ARM::SMULL, MVT::i32, MVT::i32, Ops, 5); } + case ISD::LOAD: { + LoadSDNode *LD = cast(Op); + ISD::MemIndexedMode AM = LD->getAddressingMode(); + MVT::ValueType LoadedVT = LD->getLoadedVT(); + if (AM != ISD::UNINDEXED) { + SDOperand Offset, AMOpc; + bool isPre = (AM == ISD::PRE_INC) || (AM == ISD::PRE_DEC); + unsigned Opcode = 0; + bool Match = false; + if (LoadedVT == MVT::i32 && + SelectAddrMode2Offset(Op, LD->getOffset(), Offset, AMOpc)) { + Opcode = isPre ? ARM::LDR_PRE : ARM::LDR_POST; + Match = true; + } else if (LoadedVT == MVT::i16 && + SelectAddrMode3Offset(Op, LD->getOffset(), Offset, AMOpc)) { + Match = true; + Opcode = (LD->getExtensionType() == ISD::SEXTLOAD) + ? (isPre ? ARM::LDRSH_PRE : ARM::LDRSH_POST) + : (isPre ? ARM::LDRH_PRE : ARM::LDRH_POST); + } else if (LoadedVT == MVT::i8 || LoadedVT == MVT::i1) { + if (LD->getExtensionType() == ISD::SEXTLOAD) { + if (SelectAddrMode3Offset(Op, LD->getOffset(), Offset, AMOpc)) { + Match = true; + Opcode = isPre ? ARM::LDRSB_PRE : ARM::LDRSB_POST; + } + } else { + if (SelectAddrMode2Offset(Op, LD->getOffset(), Offset, AMOpc)) { + Match = true; + Opcode = isPre ? ARM::LDRB_PRE : ARM::LDRB_POST; + } + } + } - Offset = CurDAG->getTargetConstant(0, MVT::i32); - if (FrameIndexSDNode *FI = dyn_cast(N)) { - Base = CurDAG->getTargetFrameIndex(FI->getIndex(), N.getValueType()); + if (Match) { + SDOperand Chain = LD->getChain(); + SDOperand Base = LD->getBasePtr(); + AddToISelQueue(Chain); + AddToISelQueue(Base); + AddToISelQueue(Offset); + SDOperand Ops[]= { Base, Offset, AMOpc, getAL(CurDAG), + CurDAG->getRegister(0, MVT::i32), Chain }; + return CurDAG->getTargetNode(Opcode, MVT::i32, MVT::i32, + MVT::Other, Ops, 6); + } + } + // Other cases are autogenerated. + break; } - else - Base = N; - return true; //any address fits in a register -} + case ARMISD::BRCOND: { + // Pattern: (ARMbrcond:void (bb:Other):$dst, (imm:i32):$cc) + // Emits: (Bcc:void (bb:Other):$dst, (imm:i32):$cc) + // Pattern complexity = 6 cost = 1 size = 0 + + // Pattern: (ARMbrcond:void (bb:Other):$dst, (imm:i32):$cc) + // Emits: (tBcc:void (bb:Other):$dst, (imm:i32):$cc) + // Pattern complexity = 6 cost = 1 size = 0 + + unsigned Opc = Subtarget->isThumb() ? ARM::tBcc : ARM::Bcc; + SDOperand Chain = Op.getOperand(0); + SDOperand N1 = Op.getOperand(1); + SDOperand N2 = Op.getOperand(2); + SDOperand N3 = Op.getOperand(3); + SDOperand InFlag = Op.getOperand(4); + assert(N1.getOpcode() == ISD::BasicBlock); + assert(N2.getOpcode() == ISD::Constant); + assert(N3.getOpcode() == ISD::Register); + + AddToISelQueue(Chain); + AddToISelQueue(N1); + AddToISelQueue(InFlag); + SDOperand Tmp2 = CurDAG->getTargetConstant(((unsigned) + cast(N2)->getValue()), MVT::i32); + SDOperand Ops[] = { N1, Tmp2, N3, Chain, InFlag }; + SDNode *ResNode = CurDAG->getTargetNode(Opc, MVT::Other, MVT::Flag, Ops, 5); + Chain = SDOperand(ResNode, 0); + InFlag = SDOperand(ResNode, 1); + ReplaceUses(SDOperand(Op.Val, 1), InFlag); + ReplaceUses(SDOperand(Op.Val, 0), SDOperand(Chain.Val, Chain.ResNo)); + return NULL; + } + case ARMISD::CMOV: { + bool isThumb = Subtarget->isThumb(); + MVT::ValueType VT = Op.getValueType(); + SDOperand N0 = Op.getOperand(0); + SDOperand N1 = Op.getOperand(1); + SDOperand N2 = Op.getOperand(2); + SDOperand N3 = Op.getOperand(3); + SDOperand InFlag = Op.getOperand(4); + assert(N2.getOpcode() == ISD::Constant); + assert(N3.getOpcode() == ISD::Register); + + // Pattern: (ARMcmov:i32 GPR:i32:$false, so_reg:i32:$true, (imm:i32):$cc) + // Emits: (MOVCCs:i32 GPR:i32:$false, so_reg:i32:$true, (imm:i32):$cc) + // Pattern complexity = 18 cost = 1 size = 0 + SDOperand CPTmp0; + SDOperand CPTmp1; + SDOperand CPTmp2; + if (!isThumb && VT == MVT::i32 && + SelectShifterOperandReg(Op, N1, CPTmp0, CPTmp1, CPTmp2)) { + AddToISelQueue(N0); + AddToISelQueue(CPTmp0); + AddToISelQueue(CPTmp1); + AddToISelQueue(CPTmp2); + AddToISelQueue(InFlag); + SDOperand Tmp2 = CurDAG->getTargetConstant(((unsigned) + cast(N2)->getValue()), MVT::i32); + SDOperand Ops[] = { N0, CPTmp0, CPTmp1, CPTmp2, Tmp2, N3, InFlag }; + return CurDAG->SelectNodeTo(Op.Val, ARM::MOVCCs, MVT::i32, Ops, 7); + } -SDNode *ARMDAGToDAGISel::Select(SDOperand Op) { - SDNode *N = Op.Val; + // Pattern: (ARMcmov:i32 GPR:i32:$false, + // (imm:i32)<><>:$true, + // (imm:i32):$cc) + // Emits: (MOVCCi:i32 GPR:i32:$false, + // (so_imm_XFORM:i32 (imm:i32):$true), (imm:i32):$cc) + // Pattern complexity = 10 cost = 1 size = 0 + if (VT == MVT::i32 && + N3.getOpcode() == ISD::Constant && + Predicate_so_imm(N3.Val)) { + AddToISelQueue(N0); + AddToISelQueue(InFlag); + SDOperand Tmp1 = CurDAG->getTargetConstant(((unsigned) + cast(N1)->getValue()), MVT::i32); + Tmp1 = Transform_so_imm_XFORM(Tmp1.Val); + SDOperand Tmp2 = CurDAG->getTargetConstant(((unsigned) + cast(N2)->getValue()), MVT::i32); + SDOperand Ops[] = { N0, Tmp1, Tmp2, N3, InFlag }; + return CurDAG->SelectNodeTo(Op.Val, ARM::MOVCCi, MVT::i32, Ops, 5); + } - switch (N->getOpcode()) { - default: - return SelectCode(Op); - break; + // Pattern: (ARMcmov:i32 GPR:i32:$false, GPR:i32:$true, (imm:i32):$cc) + // Emits: (MOVCCr:i32 GPR:i32:$false, GPR:i32:$true, (imm:i32):$cc) + // Pattern complexity = 6 cost = 1 size = 0 + // + // Pattern: (ARMcmov:i32 GPR:i32:$false, GPR:i32:$true, (imm:i32):$cc) + // Emits: (tMOVCCr:i32 GPR:i32:$false, GPR:i32:$true, (imm:i32):$cc) + // Pattern complexity = 6 cost = 11 size = 0 + // + // Also FCPYScc and FCPYDcc. + AddToISelQueue(N0); + AddToISelQueue(N1); + AddToISelQueue(InFlag); + SDOperand Tmp2 = CurDAG->getTargetConstant(((unsigned) + cast(N2)->getValue()), MVT::i32); + SDOperand Ops[] = { N0, N1, Tmp2, N3, InFlag }; + unsigned Opc = 0; + switch (VT) { + default: assert(false && "Illegal conditional move type!"); + break; + case MVT::i32: + Opc = isThumb ? ARM::tMOVCCr : ARM::MOVCCr; + break; + case MVT::f32: + Opc = ARM::FCPYScc; + break; + case MVT::f64: + Opc = ARM::FCPYDcc; + break; + } + return CurDAG->SelectNodeTo(Op.Val, Opc, VT, Ops, 5); + } + case ARMISD::CNEG: { + MVT::ValueType VT = Op.getValueType(); + SDOperand N0 = Op.getOperand(0); + SDOperand N1 = Op.getOperand(1); + SDOperand N2 = Op.getOperand(2); + SDOperand N3 = Op.getOperand(3); + SDOperand InFlag = Op.getOperand(4); + assert(N2.getOpcode() == ISD::Constant); + assert(N3.getOpcode() == ISD::Register); + + AddToISelQueue(N0); + AddToISelQueue(N1); + AddToISelQueue(InFlag); + SDOperand Tmp2 = CurDAG->getTargetConstant(((unsigned) + cast(N2)->getValue()), MVT::i32); + SDOperand Ops[] = { N0, N1, Tmp2, N3, InFlag }; + unsigned Opc = 0; + switch (VT) { + default: assert(false && "Illegal conditional move type!"); + break; + case MVT::f32: + Opc = ARM::FNEGScc; + break; + case MVT::f64: + Opc = ARM::FNEGDcc; + break; + } + return CurDAG->SelectNodeTo(Op.Val, Opc, VT, Ops, 5); + } } - return NULL; + return SelectCode(Op); } -} // end anonymous namespace - /// createARMISelDag - This pass converts a legalized DAG into a /// ARM-specific DAG, ready for instruction scheduling. /// -FunctionPass *llvm::createARMISelDag(TargetMachine &TM) { +FunctionPass *llvm::createARMISelDag(ARMTargetMachine &TM) { return new ARMDAGToDAGISel(TM); }