diff options
Diffstat (limited to 'llvm/lib/Target/ARM/ARMISelDAGToDAG.cpp')
-rw-r--r-- | llvm/lib/Target/ARM/ARMISelDAGToDAG.cpp | 1436 |
1 files changed, 450 insertions, 986 deletions
diff --git a/llvm/lib/Target/ARM/ARMISelDAGToDAG.cpp b/llvm/lib/Target/ARM/ARMISelDAGToDAG.cpp index 2a5f3e360ca..f5f4599b5ce 100644 --- a/llvm/lib/Target/ARM/ARMISelDAGToDAG.cpp +++ b/llvm/lib/Target/ARM/ARMISelDAGToDAG.cpp @@ -12,14 +12,14 @@ //===----------------------------------------------------------------------===// #include "ARM.h" +#include "ARMISelLowering.h" #include "ARMTargetMachine.h" -#include "ARMCommon.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/ADT/VectorExtras.h" #include "llvm/CodeGen/MachineFrameInfo.h" #include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineInstrBuilder.h" @@ -28,1081 +28,545 @@ #include "llvm/CodeGen/SSARegMap.h" #include "llvm/Target/TargetLowering.h" #include "llvm/Support/Debug.h" -#include "llvm/Support/MathExtras.h" -#include <vector> +#include <iostream> 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; - std::vector<unsigned> - getRegClassForInlineAsmConstraint(const std::string &Constraint, - MVT::ValueType VT) const; - }; - -} - -ARMTargetLowering::ARMTargetLowering(TargetMachine &TM) - : TargetLowering(TM) { - addRegisterClass(MVT::i32, ARM::IntRegsRegisterClass); - addRegisterClass(MVT::f32, ARM::FPRegsRegisterClass); - addRegisterClass(MVT::f64, ARM::DFPRegsRegisterClass); - - setLoadXAction(ISD::EXTLOAD, MVT::f32, Expand); - - setOperationAction(ISD::FP_TO_SINT, MVT::i32, Custom); - setOperationAction(ISD::SINT_TO_FP, MVT::i32, Custom); - - setOperationAction(ISD::FP_TO_UINT, MVT::i32, Custom); - setOperationAction(ISD::UINT_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::SIGN_EXTEND_INREG, MVT::i16, Expand); - setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i8 , Expand); - setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i1 , Expand); - - setOperationAction(ISD::SELECT, MVT::i32, Expand); - setOperationAction(ISD::SELECT, MVT::f32, Expand); - setOperationAction(ISD::SELECT, MVT::f64, Expand); - - setOperationAction(ISD::SETCC, MVT::i32, Expand); - setOperationAction(ISD::SETCC, MVT::f32, Expand); - setOperationAction(ISD::SETCC, MVT::f64, Expand); - - setOperationAction(ISD::SELECT_CC, MVT::i32, Custom); - setOperationAction(ISD::SELECT_CC, MVT::f32, Custom); - setOperationAction(ISD::SELECT_CC, MVT::f64, Custom); - - setOperationAction(ISD::MEMMOVE, MVT::Other, Expand); - setOperationAction(ISD::MEMSET, MVT::Other, Expand); - setOperationAction(ISD::MEMCPY, MVT::Other, Expand); - - setOperationAction(ISD::BR_JT, MVT::Other, Expand); - setOperationAction(ISD::BRIND, MVT::Other, Expand); - setOperationAction(ISD::BR_CC, MVT::i32, Custom); - setOperationAction(ISD::BR_CC, MVT::f32, Custom); - setOperationAction(ISD::BR_CC, MVT::f64, Custom); - - setOperationAction(ISD::BRCOND, MVT::Other, Expand); - - setOperationAction(ISD::SHL_PARTS, MVT::i32, Expand); - setOperationAction(ISD::SRA_PARTS, MVT::i32, Expand); - setOperationAction(ISD::SRL_PARTS, MVT::i32, Expand); - setOperationAction(ISD::SDIV, MVT::i32, Expand); - setOperationAction(ISD::UDIV, MVT::i32, Expand); - setOperationAction(ISD::SREM, MVT::i32, Expand); - setOperationAction(ISD::UREM, MVT::i32, Expand); - - setOperationAction(ISD::VASTART, MVT::Other, Custom); - setOperationAction(ISD::VACOPY, MVT::Other, Expand); - setOperationAction(ISD::VAEND, MVT::Other, Expand); - setOperationAction(ISD::DYNAMIC_STACKALLOC, MVT::i32, Expand); - - setOperationAction(ISD::ConstantFP, MVT::f64, Custom); - setOperationAction(ISD::ConstantFP, MVT::f32, Custom); - - setOperationAction(ISD::FCOPYSIGN, MVT::f64, Expand); - setOperationAction(ISD::FCOPYSIGN, MVT::f32, Expand); - - setStackPointerRegisterToSaveRestore(ARM::R13); - - setSchedulingPreference(SchedulingForRegPressure); - computeRegisterProperties(); -} - -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, - FTOSIS, - - FSITOD, - FTOSID, - - FUITOS, - FTOUIS, - - FUITOD, - FTOUID, - - FMRRD, +class ARMDAGToDAGISel : public SelectionDAGISel { + ARMTargetLowering Lowering; - FMDRR, + /// 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; - FMSTAT - }; +public: + ARMDAGToDAGISel(ARMTargetMachine &TM) + : SelectionDAGISel(Lowering), Lowering(TM), + Subtarget(&TM.getSubtarget<ARMSubtarget>()) { } -} -/// DAGFPCCToARMCC - Convert a DAG fp condition code to an ARM CC -// Unordered = !N & !Z & C & V = V -// Ordered = N | Z | !C | !V = N | Z | !V -static std::vector<unsigned> DAGFPCCToARMCC(ISD::CondCode CC) { - switch (CC) { - default: - assert(0 && "Unknown fp condition code!"); -// SETOEQ = (N | Z | !V) & Z = Z = EQ - case ISD::SETEQ: - case ISD::SETOEQ: return make_vector<unsigned>(ARMCC::EQ, 0); -// SETOGT = (N | Z | !V) & !N & !Z = !V &!N &!Z = (N = V) & !Z = GT - case ISD::SETGT: - case ISD::SETOGT: return make_vector<unsigned>(ARMCC::GT, 0); -// SETOGE = (N | Z | !V) & !N = (Z | !V) & !N = !V & !N = GE - case ISD::SETGE: - case ISD::SETOGE: return make_vector<unsigned>(ARMCC::GE, 0); -// SETOLT = (N | Z | !V) & N = N = MI - case ISD::SETLT: - case ISD::SETOLT: return make_vector<unsigned>(ARMCC::MI, 0); -// SETOLE = (N | Z | !V) & (N | Z) = N | Z = !C | Z = LS - case ISD::SETLE: - case ISD::SETOLE: return make_vector<unsigned>(ARMCC::LS, 0); -// SETONE = OGT | OLT - case ISD::SETONE: return make_vector<unsigned>(ARMCC::GT, ARMCC::MI, 0); -// SETO = N | Z | !V = Z | !V = !V = VC - case ISD::SETO: return make_vector<unsigned>(ARMCC::VC, 0); -// SETUO = V = VS - case ISD::SETUO: return make_vector<unsigned>(ARMCC::VS, 0); -// SETUEQ = V | Z (need two instructions) = EQ/VS - case ISD::SETUEQ: return make_vector<unsigned>(ARMCC::EQ, ARMCC::VS, 0); -// SETUGT = V | (!Z & !N) = !Z & !N = !Z & C = HI - case ISD::SETUGT: return make_vector<unsigned>(ARMCC::HI, 0); -// SETUGE = V | !N = !N = PL - case ISD::SETUGE: return make_vector<unsigned>(ARMCC::PL, 0); -// SETULT = V | N = LT - case ISD::SETULT: return make_vector<unsigned>(ARMCC::LT, 0); -// SETULE = V | Z | N = LE - case ISD::SETULE: return make_vector<unsigned>(ARMCC::LE, 0); -// SETUNE = V | !Z = !Z = NE - case ISD::SETNE: - case ISD::SETUNE: return make_vector<unsigned>(ARMCC::NE, 0); - } -} + 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); -/// DAGIntCCToARMCC - Convert a DAG integer condition code to an ARM CC -static std::vector<unsigned> DAGIntCCToARMCC(ISD::CondCode CC) { - switch (CC) { - default: - assert(0 && "Unknown integer condition code!"); - case ISD::SETEQ: return make_vector<unsigned>(ARMCC::EQ, 0); - case ISD::SETNE: return make_vector<unsigned>(ARMCC::NE, 0); - case ISD::SETLT: return make_vector<unsigned>(ARMCC::LT, 0); - case ISD::SETLE: return make_vector<unsigned>(ARMCC::LE, 0); - case ISD::SETGT: return make_vector<unsigned>(ARMCC::GT, 0); - case ISD::SETGE: return make_vector<unsigned>(ARMCC::GE, 0); - case ISD::SETULT: return make_vector<unsigned>(ARMCC::CC, 0); - case ISD::SETULE: return make_vector<unsigned>(ARMCC::LS, 0); - case ISD::SETUGT: return make_vector<unsigned>(ARMCC::HI, 0); - case ISD::SETUGE: return make_vector<unsigned>(ARMCC::CS, 0); - } + bool SelectAddrModePC(SDOperand Op, SDOperand N, SDOperand &Offset, + SDOperand &Label); + + bool SelectThumbAddrModeRR(SDOperand Op, SDOperand N, SDOperand &Base, + SDOperand &Offset); + bool SelectThumbAddrModeRI5_1(SDOperand Op, SDOperand N, SDOperand &Base, + SDOperand &Offset); + bool SelectThumbAddrModeRI5_2(SDOperand Op, SDOperand N, SDOperand &Base, + SDOperand &Offset); + bool SelectThumbAddrModeRI5_4(SDOperand Op, SDOperand N, SDOperand &Base, + SDOperand &Offset); + bool SelectThumbAddrModeSP(SDOperand Op, SDOperand N, SDOperand &Base, + SDOperand &Offset); + + bool SelectShifterOperandReg(SDOperand Op, SDOperand N, SDOperand &A, + SDOperand &B, SDOperand &C); + + // Include the pieces autogenerated from the target description. +#include "ARMGenDAGISel.inc" +}; } -std::vector<unsigned> ARMTargetLowering:: -getRegClassForInlineAsmConstraint(const std::string &Constraint, - MVT::ValueType VT) const { - if (Constraint.size() == 1) { - // FIXME: handling only r regs - switch (Constraint[0]) { - default: break; // Unknown constraint letter - - case 'r': // GENERAL_REGS - case 'R': // LEGACY_REGS - if (VT == MVT::i32) - return make_vector<unsigned>(ARM::R0, ARM::R1, ARM::R2, ARM::R3, - ARM::R4, ARM::R5, ARM::R6, ARM::R7, - ARM::R8, ARM::R9, ARM::R10, ARM::R11, - ARM::R12, ARM::R13, ARM::R14, 0); - break; +void ARMDAGToDAGISel::InstructionSelectBasicBlock(SelectionDAG &DAG) { + DEBUG(BB->dump()); - } - } + DAG.setRoot(SelectRoot(DAG.getRoot())); + DAG.RemoveDeadNodes(); - return std::vector<unsigned>(); + ScheduleAndEmitDAG(DAG); } -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::FTOSIS: return "ARMISD::FTOSIS"; - case ARMISD::FSITOD: return "ARMISD::FSITOD"; - case ARMISD::FTOSID: return "ARMISD::FTOSID"; - case ARMISD::FUITOS: return "ARMISD::FUITOS"; - case ARMISD::FTOUIS: return "ARMISD::FTOUIS"; - case ARMISD::FUITOD: return "ARMISD::FUITOD"; - case ARMISD::FTOUID: return "ARMISD::FTOUID"; - case ARMISD::FMRRD: return "ARMISD::FMRRD"; - case ARMISD::FMDRR: return "ARMISD::FMDRR"; - case ARMISD::FMSTAT: return "ARMISD::FMSTAT"; +bool ARMDAGToDAGISel::SelectAddrMode2(SDOperand Op, SDOperand N, + SDOperand &Base, SDOperand &Offset, + SDOperand &Opc) { + if (N.getOpcode() != ISD::ADD && N.getOpcode() != ISD::SUB) { + Base = N; + if (N.getOpcode() == ISD::FrameIndex) { + int FI = cast<FrameIndexSDNode>(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<bool> is_reg; - std::vector<unsigned> pos; - std::vector<MVT::ValueType> types; -public: - ArgumentLayout(const std::vector<MVT::ValueType> &Types) { - types = Types; - - unsigned RegNum = 0; - unsigned StackOffset = 0; - for(std::vector<MVT::ValueType>::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; - } else { - unsigned bytes = size * 32/8; - StackOffset = ((StackOffset + bytes - 1) / bytes) * bytes; - pos.push_back(StackOffset); - is_reg.push_back(false); - StackOffset += bytes; + + // Match simple R +/- imm12 operands. + if (N.getOpcode() == ISD::ADD) + if (ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(N.getOperand(1))) { + int RHSC = (int)RHS->getValue(); + if (RHSC >= 0 && RHSC < 0x1000) { // 12 bits. + Base = N.getOperand(0); + Offset = CurDAG->getRegister(0, MVT::i32); + Opc = CurDAG->getTargetConstant(ARM_AM::getAM2Opc(ARM_AM::add, RHSC, + ARM_AM::no_shift), + MVT::i32); + return true; + } else if (RHSC < 0 && RHSC > -0x1000) { + Base = N.getOperand(0); + Offset = CurDAG->getRegister(0, MVT::i32); + Opc = CurDAG->getTargetConstant(ARM_AM::getAM2Opc(ARM_AM::sub, -RHSC, + ARM_AM::no_shift), + MVT::i32); + return true; } } - } - 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; - } -}; - -// 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<ConstantSDNode>(Op.getOperand(1))->getValue(); - assert((CallConv == CallingConv::C || - CallConv == CallingConv::Fast) - && "unknown calling convention"); - 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<MVT::ValueType> 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<SDOperand> 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, NULL, 0)); - } - if (!MemOpChains.empty()) - Chain = DAG.getNode(ISD::TokenFactor, MVT::Other, - &MemOpChains[0], MemOpChains.size()); - - // If the callee is a GlobalAddress node (quite common, every direct call is) - // turn it into a TargetGlobalAddress node so that legalize doesn't hack it. - // Likewise ExternalSymbol -> TargetExternalSymbol. - assert(Callee.getValueType() == MVT::i32); - if (GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(Callee)) - Callee = DAG.getTargetGlobalAddress(G->getGlobal(), MVT::i32); - else if (ExternalSymbolSDNode *E = dyn_cast<ExternalSymbolSDNode>(Callee)) - Callee = DAG.getTargetExternalSymbol(E->getSymbol(), MVT::i32); - - // If this is a direct call, pass the chain and the callee. - assert (Callee.Val); - std::vector<SDOperand> 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, InFlag}; - Chain = DAG.getNode(ARMISD::FMRRD, VTs, Ops, InFlag.Val ? 5 : 4); + + // 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<ConstantSDNode>(N.getOperand(1).getOperand(1))) { + ShAmt = Sh->getValue(); + Offset = N.getOperand(1).getOperand(0); } else { - if (VT == MVT::f32) - Arg = DAG.getNode(ISD::BIT_CONVERT, MVT::i32, Arg); - Chain = DAG.getCopyToReg(Chain, Reg1, Arg, InFlag); + ShOpcVal = ARM_AM::no_shift; } - InFlag = Chain.getValue(1); } - - std::vector<MVT::ValueType> 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<SDOperand> 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 Value1 = DAG.getCopyFromReg(Chain, ARM::R0, MVT::i32, InFlag); - Chain = Value1.getValue(1); - InFlag = Value1.getValue(2); - NodeTys.push_back(VT); - if (VT == MVT::i32) { - ResultVals.push_back(Value1); - if (Op.Val->getValueType(1) == MVT::i32) { - SDOperand Value2 = DAG.getCopyFromReg(Chain, ARM::R1, MVT::i32, InFlag); - Chain = Value2.getValue(1); - ResultVals.push_back(Value2); - NodeTys.push_back(VT); + + // 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<ConstantSDNode>(N.getOperand(0).getOperand(1))) { + ShAmt = Sh->getValue(); + Offset = N.getOperand(0).getOperand(0); + Base = N.getOperand(1); + } else { + ShOpcVal = ARM_AM::no_shift; } } - if (VT == MVT::f32) { - SDOperand Value = DAG.getNode(ISD::BIT_CONVERT, MVT::f32, Value1); - ResultVals.push_back(Value); - } - if (VT == MVT::f64) { - SDOperand Value2 = DAG.getCopyFromReg(Chain, ARM::R1, MVT::i32, InFlag); - Chain = Value2.getValue(1); - SDOperand Value = DAG.getNode(ARMISD::FMDRR, MVT::f64, Value1, Value2); - ResultVals.push_back(Value); - } } - - 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); +bool ARMDAGToDAGISel::SelectAddrMode2Offset(SDOperand Op, SDOperand N, + SDOperand &Offset, SDOperand &Opc) { + unsigned Opcode = Op.getOpcode(); + ISD::MemIndexedMode AM = (Opcode == ISD::LOAD) + ? cast<LoadSDNode>(Op)->getAddressingMode() + : cast<StoreSDNode>(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<ConstantSDNode>(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; + } } - 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); + 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<ConstantSDNode>(N.getOperand(1))) { + ShAmt = Sh->getValue(); + Offset = N.getOperand(0); } 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; - } - 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); + ShOpcVal = ARM_AM::no_shift; } - break; } - //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)); + Opc = CurDAG->getTargetConstant(ARM_AM::getAM2Opc(AddSub, ShAmt, ShOpcVal), + MVT::i32); + return true; } -static SDOperand LowerConstantPool(SDOperand Op, SelectionDAG &DAG) { - MVT::ValueType PtrVT = Op.getValueType(); - ConstantPoolSDNode *CP = cast<ConstantPoolSDNode>(Op); - Constant *C = CP->getConstVal(); - SDOperand CPI = DAG.getTargetConstantPool(C, PtrVT, CP->getAlignment()); - return CPI; -} - -SDOperand LegalizeImmediate(uint32_t immediate, SelectionDAG &DAG, - bool canReturnConstant){ - SDOperand Shift = DAG.getTargetConstant(0, MVT::i32); - SDOperand ShiftType = DAG.getTargetConstant(ARMShift::LSL, MVT::i32); - std::vector<unsigned>immediatePieces = splitImmediate(immediate); - if (immediatePieces.size()>1){ - unsigned movInst = ARM::MOV; - unsigned orInst = ARM::ORR; - SDNode *node; - //try mvn - std::vector<unsigned>immediateNegPieces = splitImmediate(~immediate); - if (immediatePieces.size() > immediateNegPieces.size()) { - //use mvn/eor - movInst = ARM::MVN; - orInst = ARM::EOR; - immediatePieces = immediateNegPieces; - } - SDOperand n = DAG.getTargetConstant(immediatePieces[0], MVT::i32); - node = DAG.getTargetNode(movInst, MVT::i32, n, Shift, ShiftType); - std::vector<unsigned>::iterator it; - for (it=immediatePieces.begin()+1; it != immediatePieces.end(); ++it){ - n = DAG.getTargetConstant(*it, MVT::i32); - SDOperand ops[] = {SDOperand(node, 0), n, Shift, ShiftType}; - node = DAG.getTargetNode(orInst, MVT::i32, ops, 4); +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; + } + + if (N.getOpcode() != ISD::ADD) { + Base = N; + if (N.getOpcode() == ISD::FrameIndex) { + int FI = cast<FrameIndexSDNode>(N)->getIndex(); + Base = CurDAG->getTargetFrameIndex(FI, TLI.getPointerTy()); } - return SDOperand(node, 0); - } else { - if (canReturnConstant) - return DAG.getTargetConstant(immediate, MVT::i32); - else { - SDOperand n = DAG.getTargetConstant(immediate, MVT::i32); - SDNode *node = DAG.getTargetNode(ARM::MOV, MVT::i32, n, Shift, - ShiftType); - return SDOperand(node, 0); + 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<ConstantSDNode>(N.getOperand(1))) { + int RHSC = (int)RHS->getValue(); + if (RHSC >= 0 && RHSC < 256) { + Base = N.getOperand(0); + Offset = CurDAG->getRegister(0, MVT::i32); + Opc = CurDAG->getTargetConstant(ARM_AM::getAM3Opc(ARM_AM::add, RHSC), + MVT::i32); + return true; + } else if (RHSC < 0 && RHSC > -256) { // note -256 itself isn't allowed. + Base = N.getOperand(0); + Offset = CurDAG->getRegister(0, MVT::i32); + Opc = CurDAG->getTargetConstant(ARM_AM::getAM3Opc(ARM_AM::sub, -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 LowerConstantFP(SDOperand Op, SelectionDAG &DAG) { - MVT::ValueType VT = Op.getValueType(); - SDOperand Shift = DAG.getTargetConstant(0, MVT::i32); - SDOperand ShiftType = DAG.getTargetConstant(ARMShift::LSL, MVT::i32); - SDNode *node; - switch (VT) { - default: assert(0 && "VT!=f32 && VT!=f64"); - case MVT::f32: { - float val = cast<ConstantFPSDNode>(Op)->getValue(); - uint32_t i32_val = FloatToBits(val); - SDOperand c = LegalizeImmediate(i32_val, DAG, false); - node = DAG.getTargetNode(ARM::FMSR, MVT::f32, c); - break; - } - case MVT::f64: { - double val = cast<ConstantFPSDNode>(Op)->getValue(); - uint64_t i64_val = DoubleToBits(val); - SDOperand hi = LegalizeImmediate(Hi_32(i64_val), DAG, false); - SDOperand lo = LegalizeImmediate(Lo_32(i64_val), DAG, false); - node = DAG.getTargetNode(ARM::FMDRR, MVT::f64, lo, hi); - break; - } +bool ARMDAGToDAGISel::SelectAddrMode3Offset(SDOperand Op, SDOperand N, + SDOperand &Offset, SDOperand &Opc) { + unsigned Opcode = Op.getOpcode(); + ISD::MemIndexedMode AM = (Opcode == ISD::LOAD) + ? cast<LoadSDNode>(Op)->getAddressingMode() + : cast<StoreSDNode>(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<ConstantSDNode>(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 SDOperand(node, 0); -} - -static SDOperand LowerGlobalAddress(SDOperand Op, - SelectionDAG &DAG) { - GlobalValue *GV = cast<GlobalAddressSDNode>(Op)->getGlobal(); - int alignment = 2; - SDOperand CPAddr = DAG.getConstantPool(GV, MVT::i32, alignment); - return DAG.getLoad(MVT::i32, DAG.getEntryNode(), CPAddr, NULL, 0); -} -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); - SrcValueSDNode *SV = cast<SrcValueSDNode>(Op.getOperand(2)); - return DAG.getStore(Op.getOperand(0), FR, Op.getOperand(1), SV->getValue(), - SV->getOffset()); + Offset = N; + Opc = CurDAG->getTargetConstant(ARM_AM::getAM3Opc(AddSub, 0), MVT::i32); + return true; } -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<ConstantSDNode>(Op.getOperand(2))->getValue() != 0; - static const unsigned REGS[] = { - ARM::R0, ARM::R1, ARM::R2, ARM::R3 - }; - - std::vector<MVT::ValueType> Types(Op.Val->value_begin(), Op.Val->value_end() - 1); - ArgumentLayout Layout(Types); - - std::vector<SDOperand> 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, NULL, 0); - } else { - Value = DAG.getNode(ISD::UNDEF, VT); - } +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<FrameIndexSDNode>(N)->getIndex(); + Base = CurDAG->getTargetFrameIndex(FI, TLI.getPointerTy()); + } else if (N.getOpcode() == ARMISD::Wrapper) { + Base = N.getOperand(0); } - ArgValues.push_back(Value); + Offset = CurDAG->getTargetConstant(ARM_AM::getAM5Opc(ARM_AM::add, 0), + MVT::i32); + return true; } - - unsigned NextRegNum = Layout.lastRegNum() + 1; - - 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); - - SmallVector<SDOperand, 4> 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); - - unsigned VReg = RegMap->createVirtualRegister(&ARM::IntRegsRegClass); - MF.addLiveIn(REGS[RegNo], VReg); - - SDOperand Val = DAG.getCopyFromReg(Root, VReg, MVT::i32); - SDOperand Store = DAG.getStore(Val.getValue(1), Val, FIN, NULL, 0); - MemOps.push_back(Store); + + // If the RHS is +/- imm8, fold into addr mode. + if (ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(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) { + Base = N.getOperand(0); + Offset = CurDAG->getTargetConstant(ARM_AM::getAM5Opc(ARM_AM::add, RHSC), + MVT::i32); + return true; + } else if (RHSC < 0 && RHSC > -256) { // note -256 itself isn't allowed. + Base = N.getOperand(0); + Offset = CurDAG->getTargetConstant(ARM_AM::getAM5Opc(ARM_AM::sub,-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<MVT::ValueType> RetVT(Op.Val->value_begin(), - Op.Val->value_end()); - return DAG.getNode(ISD::MERGE_VALUES, RetVT, &ArgValues[0], ArgValues.size()); -} - -static SDOperand GetCMP(ISD::CondCode CC, SDOperand LHS, SDOperand RHS, - SelectionDAG &DAG) { - MVT::ValueType vt = LHS.getValueType(); - assert(vt == MVT::i32 || vt == MVT::f32 || vt == MVT::f64); - - SDOperand Cmp = DAG.getNode(ARMISD::CMP, MVT::Flag, LHS, RHS); - - if (vt != MVT::i32) - Cmp = DAG.getNode(ARMISD::FMSTAT, MVT::Flag, Cmp); - return Cmp; -} - -static std::vector<SDOperand> GetARMCC(ISD::CondCode CC, MVT::ValueType vt, - SelectionDAG &DAG) { - assert(vt == MVT::i32 || vt == MVT::f32 || vt == MVT::f64); - std::vector<unsigned> vcc; - if (vt == MVT::i32) - vcc = DAGIntCCToARMCC(CC); - else - vcc = DAGFPCCToARMCC(CC); - - std::vector<unsigned>::iterator it; - std::vector<SDOperand> result; - for( it = vcc.begin(); it != vcc.end(); it++ ) - result.push_back(DAG.getConstant(*it,MVT::i32)); - return result; -} - -static bool isUInt8Immediate(uint32_t x) { - return x < (1 << 8); -} - -static uint32_t rotateL(uint32_t x) { - uint32_t bit31 = (x & (1 << 31)) >> 31; - uint32_t t = x << 1; - return t | bit31; + + Base = N; + Offset = CurDAG->getTargetConstant(ARM_AM::getAM5Opc(ARM_AM::add, 0), + MVT::i32); + return true; } -static bool isRotInt8Immediate(uint32_t x) { - int r; - for (r = 0; r < 16; r++) { - if (isUInt8Immediate(x)) - return true; - x = rotateL(rotateL(x)); +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<ConstantSDNode>(N1)->getValue(), + MVT::i32); + return true; } return false; } -static void LowerCMP(SDOperand &Cmp, std::vector<SDOperand> &ARMCC, - SDOperand LHS, SDOperand RHS, ISD::CondCode CC, - SelectionDAG &DAG) { - MVT::ValueType vt = LHS.getValueType(); - if (vt == MVT::i32) { - assert(!isa<ConstantSDNode>(LHS)); - if (ConstantSDNode *SD_C = dyn_cast<ConstantSDNode>(RHS.Val)) { - uint32_t C = SD_C->getValue(); - - uint32_t NC; - switch(CC) { - default: - NC = C; break; - case ISD::SETLT: - case ISD::SETULT: - case ISD::SETGE: - case ISD::SETUGE: - NC = C - 1; break; - case ISD::SETLE: - case ISD::SETULE: - case ISD::SETGT: - case ISD::SETUGT: - NC = C + 1; break; - } - - ISD::CondCode NCC; - switch(CC) { - default: - NCC = CC; break; - case ISD::SETLT: - NCC = ISD::SETLE; break; - case ISD::SETULT: - NCC = ISD::SETULE; break; - case ISD::SETGE: - NCC = ISD::SETGT; break; - case ISD::SETUGE: - NCC = ISD::SETUGT; break; - case ISD::SETLE: - NCC = ISD::SETLT; break; - case ISD::SETULE: - NCC = ISD::SETULT; break; - case ISD::SETGT: - NCC = ISD::SETGE; break; - case ISD::SETUGT: - NCC = ISD::SETUGE; break; - } - - if (!isRotInt8Immediate(C) && isRotInt8Immediate(NC)) { - RHS = DAG.getConstant(NC, MVT::i32); - CC = NCC; - } - } - } - Cmp = GetCMP(CC, LHS, RHS, DAG); - ARMCC = GetARMCC(CC, vt, DAG); +bool ARMDAGToDAGISel::SelectThumbAddrModeRR(SDOperand Op, SDOperand N, + SDOperand &Base, SDOperand &Offset){ + if (N.getOpcode() != ISD::ADD) + return false; + Base = N.getOperand(0); + Offset = N.getOperand(1); + return true; } -static SDOperand LowerSELECT_CC(SDOperand Op, SelectionDAG &DAG) { - SDOperand LHS = Op.getOperand(0); - SDOperand RHS = Op.getOperand(1); - ISD::CondCode CC = cast<CondCodeSDNode>(Op.getOperand(4))->get(); - SDOperand TrueVal = Op.getOperand(2); - SDOperand FalseVal = Op.getOperand(3); - SDOperand Cmp; - std::vector<SDOperand> ARMCC; - LowerCMP(Cmp, ARMCC, LHS, RHS, CC, DAG); - - SDOperand Aux = FalseVal; - SDVTList VTs = DAG.getVTList(Op.getValueType(), MVT::Flag); - std::vector<SDOperand>::iterator it; - for (it = ARMCC.begin(); it != ARMCC.end(); ++it){ - SDOperand Flag = it == ARMCC.begin() ? Cmp : Aux.getValue(1); - SDOperand Ops[] = {TrueVal, Aux, *it, Flag}; - Aux = DAG.getNode(ARMISD::SELECT, VTs, Ops, 4); +static bool SelectThumbAddrModeRI5(SDOperand N, unsigned Scale, + TargetLowering &TLI, SelectionDAG *CurDAG, + SDOperand &Base, SDOperand &Offset) { + if (N.getOpcode() == ISD::FrameIndex) + return false; + + if (N.getOpcode() != ISD::ADD) { + Base = (N.getOpcode() == ARMISD::Wrapper) ? N.getOperand(0) : N; + Offset = CurDAG->getTargetConstant(0, MVT::i32); + return true; } - return Aux; -} -static SDOperand LowerBR_CC(SDOperand Op, SelectionDAG &DAG) { - SDOperand Chain = Op.getOperand(0); - ISD::CondCode CC = cast<CondCodeSDNode>(Op.getOperand(1))->get(); - SDOperand LHS = Op.getOperand(2); - SDOperand RHS = Op.getOperand(3); - SDOperand Dest = Op.getOperand(4); - SDOperand Cmp; - std::vector<SDOperand> ARMCC; - LowerCMP(Cmp, ARMCC, LHS, RHS, CC, DAG); - - SDOperand Aux = Chain; - SDVTList VTs = DAG.getVTList(MVT::Other, MVT::Flag); - std::vector<SDOperand>::iterator it; - for (it = ARMCC.begin(); it != ARMCC.end(); it++){ - SDOperand Flag = it == ARMCC.begin() ? Cmp : Aux.getValue(1); - SDOperand Ops[] = {Aux, Dest, *it, Flag}; - Aux = DAG.getNode(ARMISD::BR, VTs, Ops, 4); + // If the RHS is + imm5 * scale, fold into addr mode. + if (ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(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->getTargetConstant(RHSC, MVT::i32); + return true; + } + } } - return Aux; -} -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); -} - -static SDOperand LowerFP_TO_SINT(SDOperand Op, SelectionDAG &DAG) { - assert(Op.getValueType() == MVT::i32); - SDOperand FloatVal = Op.getOperand(0); - MVT::ValueType vt = FloatVal.getValueType(); - assert(vt == MVT::f32 || vt == MVT::f64); - - ARMISD::NodeType op = vt == MVT::f32 ? ARMISD::FTOSIS : ARMISD::FTOSID; - SDOperand Tmp = DAG.getNode(op, MVT::f32, FloatVal); - return DAG.getNode(ISD::BIT_CONVERT, MVT::i32, Tmp); -} - -static SDOperand LowerUINT_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::FUITOS : ARMISD::FUITOD; - return DAG.getNode(op, vt, Tmp); -} - -static SDOperand LowerFP_TO_UINT(SDOperand Op, SelectionDAG &DAG) { - assert(Op.getValueType() == MVT::i32); - SDOperand FloatVal = Op.getOperand(0); - MVT::ValueType vt = FloatVal.getValueType(); - assert(vt == MVT::f32 || vt == MVT::f64); - - ARMISD::NodeType op = vt == MVT::f32 ? ARMISD::FTOUIS : ARMISD::FTOUID; - SDOperand Tmp = DAG.getNode(op, MVT::f32, FloatVal); - return DAG.getNode(ISD::BIT_CONVERT, MVT::i32, Tmp); -} - -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::ConstantFP: - return LowerConstantFP(Op, DAG); - case ISD::GlobalAddress: - return LowerGlobalAddress(Op, DAG); - case ISD::FP_TO_SINT: - return LowerFP_TO_SINT(Op, DAG); - case ISD::SINT_TO_FP: - return LowerSINT_TO_FP(Op, DAG); - case ISD::FP_TO_UINT: - return LowerFP_TO_UINT(Op, DAG); - case ISD::UINT_TO_FP: - return LowerUINT_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); - } + return false; } -//===----------------------------------------------------------------------===// -// Instruction Selector Implementation -//===----------------------------------------------------------------------===// - -//===--------------------------------------------------------------------===// -/// ARMDAGToDAGISel - ARM specific code to select ARM machine -/// instructions for SelectionDAG operations. -/// -namespace { -class ARMDAGToDAGISel : public SelectionDAGISel { - ARMTargetLowering Lowering; - -public: - ARMDAGToDAGISel(TargetMachine &TM) - : SelectionDAGISel(Lowering), Lowering(TM) { - } - - SDNode *Select(SDOperand Op); - virtual void InstructionSelectBasicBlock(SelectionDAG &DAG); - bool SelectAddrMode1(SDOperand Op, SDOperand N, SDOperand &Arg, - SDOperand &Shift, SDOperand &ShiftType); - bool SelectAddrMode1a(SDOperand Op, SDOperand N, SDOperand &Arg, - SDOperand &Shift, SDOperand &ShiftType); - bool SelectAddrMode2(SDOperand Op, SDOperand N, SDOperand &Arg, - SDOperand &Offset); - bool SelectAddrMode5(SDOperand Op, SDOperand N, SDOperand &Arg, - SDOperand &Offset); - - // 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); +bool ARMDAGToDAGISel::SelectThumbAddrModeRI5_1(SDOperand Op, SDOperand N, + SDOperand &Base, SDOperand &Offset){ + return SelectThumbAddrModeRI5(N, 1, TLI, CurDAG, Base, Offset); } -static bool isInt12Immediate(SDNode *N, short &Imm) { - if (N->getOpcode() != ISD::Constant) - return false; - - int32_t t = cast<ConstantSDNode>(N)->getValue(); - int max = 1<<12; - int min = -max; - if (t > min && t < max) { - Imm = t; - return true; - } - else - return false; +bool ARMDAGToDAGISel::SelectThumbAddrModeRI5_2(SDOperand Op, SDOperand N, + SDOperand &Base, SDOperand &Offset){ + return SelectThumbAddrModeRI5(N, 2, TLI, CurDAG, Base, Offset); } -static bool isInt12Immediate(SDOperand Op, short &Imm) { - return isInt12Immediate(Op.Val, Imm); +bool ARMDAGToDAGISel::SelectThumbAddrModeRI5_4(SDOperand Op, SDOperand N, + SDOperand &Base, SDOperand &Offset){ + return SelectThumbAddrModeRI5(N, 4, TLI, CurDAG, Base, Offset); } -bool ARMDAGToDAGISel::SelectAddrMode1(SDOperand Op, - SDOperand N, - SDOperand &Arg, - SDOperand &Shift, - SDOperand &ShiftType) { - switch(N.getOpcode()) { - case ISD::Constant: { - uint32_t val = cast<ConstantSDNode>(N)->getValue(); - Shift = CurDAG->getTargetConstant(0, MVT::i32); - ShiftType = CurDAG->getTargetConstant(ARMShift::LSL, MVT::i32); - Arg = LegalizeImmediate(val, *CurDAG, true); - return true; - } - - 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); +bool ARMDAGToDAGISel::SelectThumbAddrModeSP(SDOperand Op, SDOperand N, + SDOperand &Base, SDOperand &Offset) { + if (N.getOpcode() == ISD::FrameIndex) { + int FI = cast<FrameIndexSDNode>(N)->getIndex(); + Base = CurDAG->getTargetFrameIndex(FI, TLI.getPointerTy()); + Offset = CurDAG->getTargetConstant(0, MVT::i32); return true; } - - Arg = N; - Shift = CurDAG->getTargetConstant(0, MVT::i32); - ShiftType = CurDAG->getTargetConstant(ARMShift::LSL, MVT::i32); - return true; + + return false; } -bool ARMDAGToDAGISel::SelectAddrMode2(SDOperand Op, SDOperand N, - SDOperand &Arg, SDOperand &Offset) { - //TODO: complete and cleanup! - SDOperand Zero = CurDAG->getTargetConstant(0, MVT::i32); - if (FrameIndexSDNode *FIN = dyn_cast<FrameIndexSDNode>(N)) { - Arg = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i32); - Offset = Zero; - return true; - } - 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<FrameIndexSDNode>(N.getOperand(0))) { - Arg = CurDAG->getTargetFrameIndex(FI->getIndex(), N.getValueType()); - } else { - Arg = N.getOperand(0); - } - return true; // [r+i] - } +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<ConstantSDNode>(N.getOperand(1))) { + ShReg = CurDAG->getRegister(0, MVT::i32); + ShImmVal = RHS->getValue() & 31; + } else { + ShReg = N.getOperand(1); } - Offset = Zero; - if (FrameIndexSDNode *FI = dyn_cast<FrameIndexSDNode>(N)) - Arg = CurDAG->getTargetFrameIndex(FI->getIndex(), N.getValueType()); - else - Arg = N; + Opc = CurDAG->getTargetConstant(ARM_AM::getSORegOpc(ShOpcVal, ShImmVal), + MVT::i32); return true; } -bool ARMDAGToDAGISel::SelectAddrMode5(SDOperand Op, - SDOperand N, SDOperand &Arg, - SDOperand &Offset) { - //TODO: detect offset - Offset = CurDAG->getTargetConstant(0, MVT::i32); - Arg = N; - return true; -} SDNode *ARMDAGToDAGISel::Select(SDOperand Op) { SDNode *N = Op.Val; + unsigned Opcode = N->getOpcode(); + + if (Opcode >= ISD::BUILTIN_OP_END && Opcode < ARMISD::FIRST_NUMBER) + return NULL; // Already selected. switch (N->getOpcode()) { - default: - return SelectCode(Op); + default: break; + case ISD::Constant: { + unsigned Val = cast<ConstantSDNode>(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()); + SDOperand Ops[] = { + CPIdx, + CurDAG->getRegister(0, MVT::i32), + CurDAG->getTargetConstant(0, MVT::i32), + CurDAG->getEntryNode() + }; + SDNode *ResNode = + CurDAG->getTargetNode(ARM::LDR, MVT::i32, MVT::Other, Ops, 4); + ReplaceUses(Op, SDOperand(ResNode, 0)); + return NULL; + } + + // Other cases are autogenerated. break; + } case ISD::FrameIndex: { + // Selects to ADDri FI, 0 which in turn will become ADDri SP, imm. int FI = cast<FrameIndexSDNode>(N)->getIndex(); - SDOperand Ops[] = {CurDAG->getTargetFrameIndex(FI, MVT::i32), - CurDAG->getTargetConstant(0, MVT::i32), - CurDAG->getTargetConstant(0, MVT::i32), - CurDAG->getTargetConstant(ARMShift::LSL, MVT::i32)}; + unsigned Opc = Subtarget->isThumb() ? ARM::tADDrSPi : ARM::ADDri; + SDOperand TFI = CurDAG->getTargetFrameIndex(FI, TLI.getPointerTy()); + return CurDAG->SelectNodeTo(N, Opc, MVT::i32, TFI, + CurDAG->getTargetConstant(0, MVT::i32)); + } + case ISD::MUL: + if (ConstantSDNode *C = dyn_cast<ConstantSDNode>(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) + }; + return CurDAG->SelectNodeTo(N, ARM::ADDrs, MVT::i32, Ops, 4); + } + 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) + }; + return CurDAG->SelectNodeTo(N, ARM::RSBrs, MVT::i32, Ops, 4); + } + } + break; + case ARMISD::FMRRD: + AddToISelQueue(Op.getOperand(0)); + return CurDAG->getTargetNode(ARM::FMRRD, MVT::i32, MVT::i32, + Op.getOperand(0)); + case ARMISD::MULHILOU: + AddToISelQueue(Op.getOperand(0)); + AddToISelQueue(Op.getOperand(1)); + return CurDAG->getTargetNode(ARM::UMULL, MVT::i32, MVT::i32, + Op.getOperand(0), Op.getOperand(1)); + case ARMISD::MULHILOS: + AddToISelQueue(Op.getOperand(0)); + AddToISelQueue(Op.getOperand(1)); + return CurDAG->getTargetNode(ARM::SMULL, MVT::i32, MVT::i32, + Op.getOperand(0), Op.getOperand(1)); + case ISD::LOAD: { + LoadSDNode *LD = cast<LoadSDNode>(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; + } + } + } - return CurDAG->SelectNodeTo(N, ARM::ADD, MVT::i32, Ops, - sizeof(Ops)/sizeof(SDOperand)); + if (Match) { + SDOperand Chain = LD->getChain(); + SDOperand Base = LD->getBasePtr(); + AddToISelQueue(Chain); + AddToISelQueue(Base); + AddToISelQueue(Offset); + SDOperand Ops[] = { Base, Offset, AMOpc, Chain }; + return CurDAG->getTargetNode(Opcode, MVT::i32, MVT::i32, + MVT::Other, Ops, 4); + } + } + // Other cases are autogenerated. break; } } -} -} // end anonymous namespace + return SelectCode(Op); +} /// 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); } |