diff options
Diffstat (limited to 'lib/Target/ARM/ARMISelDAGToDAG.cpp')
-rw-r--r-- | lib/Target/ARM/ARMISelDAGToDAG.cpp | 1436 |
1 files changed, 450 insertions, 986 deletions
diff --git a/lib/Target/ARM/ARMISelDAGToDAG.cpp b/lib/Target/ARM/ARMISelDAGToDAG.cpp index 2a5f3e360c..f5f4599b5c 100644 --- a/lib/Target/ARM/ARMISelDAGToDAG.cpp +++ b/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(); |