X-Git-Url: http://demsky.eecs.uci.edu/git/?a=blobdiff_plain;f=lib%2FTarget%2FARM%2FARMISelDAGToDAG.cpp;h=3c6d21fc4097be68181c6f484973d87fa2104499;hb=9d7b5309c267048114f1438ec0366923c99ca34d;hp=2adf4073ba02134c039c1a1773e622b018f3a892;hpb=cd71da5cf05cd023d2082e2a13a2524ee7d5af3f;p=oota-llvm.git diff --git a/lib/Target/ARM/ARMISelDAGToDAG.cpp b/lib/Target/ARM/ARMISelDAGToDAG.cpp index 2adf4073ba0..3c6d21fc409 100644 --- a/lib/Target/ARM/ARMISelDAGToDAG.cpp +++ b/lib/Target/ARM/ARMISelDAGToDAG.cpp @@ -2,8 +2,8 @@ // // The LLVM Compiler Infrastructure // -// This file was developed by Chris Lattner and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // @@ -12,641 +12,876 @@ //===----------------------------------------------------------------------===// #include "ARM.h" +#include "ARMAddressingModes.h" +#include "ARMConstantPoolValue.h" +#include "ARMISelLowering.h" #include "ARMTargetMachine.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" #include "llvm/CodeGen/MachineInstrBuilder.h" #include "llvm/CodeGen/SelectionDAG.h" #include "llvm/CodeGen/SelectionDAGISel.h" -#include "llvm/CodeGen/SSARegMap.h" #include "llvm/Target/TargetLowering.h" +#include "llvm/Target/TargetOptions.h" +#include "llvm/Support/Compiler.h" #include "llvm/Support/Debug.h" -#include -#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); +class ARMDAGToDAGISel : public SelectionDAGISel { + ARMTargetMachine &TM; - setOperationAction(ISD::RET, MVT::Other, Custom); - setOperationAction(ISD::GlobalAddress, MVT::i32, Custom); - setOperationAction(ISD::ConstantPool, MVT::i32, Custom); + /// 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::SETCC, MVT::i32, Expand); - setOperationAction(ISD::SELECT_CC, MVT::i32, Custom); - setOperationAction(ISD::BR_CC, MVT::i32, Custom); +public: + explicit ARMDAGToDAGISel(ARMTargetMachine &tm) + : SelectionDAGISel(tm), TM(tm), + Subtarget(&TM.getSubtarget()) { + } - setOperationAction(ISD::VASTART, MVT::Other, Custom); - setOperationAction(ISD::VAEND, MVT::Other, Expand); + virtual const char *getPassName() const { + return "ARM Instruction Selection"; + } + + SDNode *Select(SDValue Op); + virtual void InstructionSelect(); + bool SelectAddrMode2(SDValue Op, SDValue N, SDValue &Base, + SDValue &Offset, SDValue &Opc); + bool SelectAddrMode2Offset(SDValue Op, SDValue N, + SDValue &Offset, SDValue &Opc); + bool SelectAddrMode3(SDValue Op, SDValue N, SDValue &Base, + SDValue &Offset, SDValue &Opc); + bool SelectAddrMode3Offset(SDValue Op, SDValue N, + SDValue &Offset, SDValue &Opc); + bool SelectAddrMode5(SDValue Op, SDValue N, SDValue &Base, + SDValue &Offset); + + bool SelectAddrModePC(SDValue Op, SDValue N, SDValue &Offset, + SDValue &Label); + + bool SelectThumbAddrModeRR(SDValue Op, SDValue N, SDValue &Base, + SDValue &Offset); + bool SelectThumbAddrModeRI5(SDValue Op, SDValue N, unsigned Scale, + SDValue &Base, SDValue &OffImm, + SDValue &Offset); + bool SelectThumbAddrModeS1(SDValue Op, SDValue N, SDValue &Base, + SDValue &OffImm, SDValue &Offset); + bool SelectThumbAddrModeS2(SDValue Op, SDValue N, SDValue &Base, + SDValue &OffImm, SDValue &Offset); + bool SelectThumbAddrModeS4(SDValue Op, SDValue N, SDValue &Base, + SDValue &OffImm, SDValue &Offset); + bool SelectThumbAddrModeSP(SDValue Op, SDValue N, SDValue &Base, + SDValue &OffImm); + + bool SelectShifterOperandReg(SDValue Op, SDValue N, SDValue &A, + SDValue &B, SDValue &C); + + // Include the pieces autogenerated from the target description. +#include "ARMGenDAGISel.inc" +}; +} - setOperationAction(ISD::ConstantFP, MVT::f64, Expand); - setOperationAction(ISD::ConstantFP, MVT::f32, Expand); +void ARMDAGToDAGISel::InstructionSelect() { + DEBUG(BB->dump()); - setSchedulingPreference(SchedulingForRegPressure); - computeRegisterProperties(); + SelectRoot(*CurDAG); + CurDAG->RemoveDeadNodes(); } -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, +bool ARMDAGToDAGISel::SelectAddrMode2(SDValue Op, SDValue N, + SDValue &Base, SDValue &Offset, + SDValue &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->getZExtValue(); + 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; + } + } + } + } - CMP, + 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; + } + + // Match simple R +/- imm12 operands. + if (N.getOpcode() == ISD::ADD) + if (ConstantSDNode *RHS = dyn_cast(N.getOperand(1))) { + int RHSC = (int)RHS->getZExtValue(); + 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->getZExtValue(); + 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->getZExtValue(); + Offset = N.getOperand(0).getOperand(0); + Base = N.getOperand(1); + } else { + ShOpcVal = ARM_AM::no_shift; + } + } + } + + Opc = CurDAG->getTargetConstant(ARM_AM::getAM2Opc(AddSub, ShAmt, ShOpcVal), + MVT::i32); + return true; +} - SELECT, +bool ARMDAGToDAGISel::SelectAddrMode2Offset(SDValue Op, SDValue N, + SDValue &Offset, SDValue &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->getZExtValue(); + 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; + } + } - BR, + 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->getZExtValue(); + Offset = N.getOperand(0); + } else { + ShOpcVal = ARM_AM::no_shift; + } + } - FSITOS, + Opc = CurDAG->getTargetConstant(ARM_AM::getAM2Opc(AddSub, ShAmt, ShOpcVal), + MVT::i32); + return true; +} - FSITOD, - FMRRD - }; +bool ARMDAGToDAGISel::SelectAddrMode3(SDValue Op, SDValue N, + SDValue &Base, SDValue &Offset, + SDValue &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; } -} - -/// 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; + + if (N.getOpcode() != ISD::ADD) { + Base = N; + if (N.getOpcode() == ISD::FrameIndex) { + int FI = cast(N)->getIndex(); + Base = CurDAG->getTargetFrameIndex(FI, TLI.getPointerTy()); + } + 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->getZExtValue(); + 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); -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"; + 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; } -// 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; - - // Count how many bytes are to be pushed on the stack. - unsigned NumBytes = 0; - - // Add up all the space actually used. - for (unsigned i = 4; i < NumOps; ++i) - NumBytes += MVT::getSizeInBits(Op.getOperand(5+2*i).getValueType())/8; - - // Adjust the stack pointer for the new arguments... - // These operations are automatically eliminated by the prolog/epilog pass - Chain = DAG.getCALLSEQ_START(Chain, - DAG.getConstant(NumBytes, MVT::i32)); - - SDOperand StackPtr = DAG.getRegister(ARM::R13, MVT::i32); - - static const unsigned int num_regs = 4; - static const unsigned regs[num_regs] = { - ARM::R0, ARM::R1, ARM::R2, ARM::R3 - }; - - std::vector > RegsToPass; - std::vector MemOpChains; - - for (unsigned i = 0; i != NumOps; ++i) { - SDOperand Arg = Op.getOperand(5+2*i); - assert(Arg.getValueType() == MVT::i32); - if (i < num_regs) - RegsToPass.push_back(std::make_pair(regs[i], Arg)); - else { - unsigned ArgOffset = (i - num_regs) * 4; - SDOperand PtrOff = DAG.getConstant(ArgOffset, StackPtr.getValueType()); - PtrOff = DAG.getNode(ISD::ADD, MVT::i32, StackPtr, PtrOff); - MemOpChains.push_back(DAG.getNode(ISD::STORE, MVT::Other, Chain, - Arg, PtrOff, DAG.getSrcValue(NULL))); +bool ARMDAGToDAGISel::SelectAddrMode3Offset(SDValue Op, SDValue N, + SDValue &Offset, SDValue &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->getZExtValue(); + if (Val >= 0 && Val < 256) { + Offset = CurDAG->getRegister(0, MVT::i32); + Opc = CurDAG->getTargetConstant(ARM_AM::getAM3Opc(AddSub, Val), MVT::i32); + return true; } } - if (!MemOpChains.empty()) - Chain = DAG.getNode(ISD::TokenFactor, MVT::Other, - &MemOpChains[0], MemOpChains.size()); - - // 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 (unsigned i = 0, e = RegsToPass.size(); i != e; ++i) { - Chain = DAG.getCopyToReg(Chain, RegsToPass[i].first, RegsToPass[i].second, - 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. - - // 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); - - // Add argument registers to the end of the list so that they are known live - // into the call. - for (unsigned i = 0, e = RegsToPass.size(); i != e; ++i) - Ops.push_back(DAG.getRegister(RegsToPass[i].first, - RegsToPass[i].second.getValueType())); - - 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. - switch (Op.Val->getValueType(0)) { - default: assert(0 && "Unexpected ret value!"); - case MVT::Other: - break; - case MVT::i32: - Chain = DAG.getCopyFromReg(Chain, ARM::R0, MVT::i32, InFlag).getValue(1); - ResultVals.push_back(Chain.getValue(0)); - NodeTys.push_back(MVT::i32); - } - 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); + Offset = N; + Opc = CurDAG->getTargetConstant(ARM_AM::getAM3Opc(AddSub, 0), 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); +bool ARMDAGToDAGISel::SelectAddrMode5(SDValue Op, SDValue N, + SDValue &Base, SDValue &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); } - break; + Offset = CurDAG->getTargetConstant(ARM_AM::getAM5Opc(ARM_AM::add, 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 the RHS is +/- imm8, fold into addr mode. + if (ConstantSDNode *RHS = dyn_cast(N.getOperand(1))) { + int RHSC = (int)RHS->getZExtValue(); + 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; + } } - 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)); + + Base = N; + Offset = CurDAG->getTargetConstant(ARM_AM::getAM5Opc(ARM_AM::add, 0), + MVT::i32); + return true; } -static SDOperand LowerFORMAL_ARGUMENT(SDOperand Op, SelectionDAG &DAG, - unsigned *vRegs, - unsigned ArgNo) { - MachineFunction &MF = DAG.getMachineFunction(); - MVT::ValueType ObjectVT = Op.getValue(ArgNo).getValueType(); - assert (ObjectVT == MVT::i32); - SDOperand Root = Op.getOperand(0); - SSARegMap *RegMap = MF.getSSARegMap(); - - unsigned num_regs = 4; - static const unsigned REGS[] = { - ARM::R0, ARM::R1, ARM::R2, ARM::R3 - }; - - if(ArgNo < num_regs) { - unsigned VReg = RegMap->createVirtualRegister(&ARM::IntRegsRegClass); - MF.addLiveIn(REGS[ArgNo], VReg); - vRegs[ArgNo] = VReg; - return DAG.getCopyFromReg(Root, VReg, MVT::i32); - } else { - // If the argument is actually used, emit a load from the right stack - // slot. - if (!Op.Val->hasNUsesOfValue(0, ArgNo)) { - unsigned ArgOffset = (ArgNo - num_regs) * 4; - - MachineFrameInfo *MFI = MF.getFrameInfo(); - unsigned ObjSize = MVT::getSizeInBits(ObjectVT)/8; - int FI = MFI->CreateFixedObject(ObjSize, ArgOffset); - SDOperand FIN = DAG.getFrameIndex(FI, MVT::i32); - return DAG.getLoad(ObjectVT, Root, FIN, - DAG.getSrcValue(NULL)); - } else { - // Don't emit a dead load. - return DAG.getNode(ISD::UNDEF, ObjectVT); - } +bool ARMDAGToDAGISel::SelectAddrModePC(SDValue Op, SDValue N, + SDValue &Offset, SDValue &Label) { + if (N.getOpcode() == ARMISD::PIC_ADD && N.hasOneUse()) { + Offset = N.getOperand(0); + SDValue N1 = N.getOperand(1); + Label = CurDAG->getTargetConstant(cast(N1)->getZExtValue(), + MVT::i32); + return true; } + return false; } -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::SelectThumbAddrModeRR(SDValue Op, SDValue N, + SDValue &Base, SDValue &Offset){ + // FIXME dl should come from the parent load or store, not the address + DebugLoc dl = Op.getDebugLoc(); + if (N.getOpcode() != ISD::ADD) { + Base = N; + // We must materialize a zero in a reg! Returning a constant here + // wouldn't work without additional code to position the node within + // ISel's topological ordering in a place where ISel will process it + // normally. Instead, just explicitly issue a tMOVri8 node! + Offset = SDValue(CurDAG->getTargetNode(ARM::tMOVi8, dl, MVT::i32, + CurDAG->getTargetConstant(0, MVT::i32)), 0); + return true; + } - return CPI; + Base = N.getOperand(0); + Offset = N.getOperand(1); + 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::SelectThumbAddrModeRI5(SDValue Op, SDValue N, + unsigned Scale, SDValue &Base, + SDValue &OffImm, SDValue &Offset) { + if (Scale == 4) { + SDValue 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. + } -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.getNode(ISD::STORE, MVT::Other, Op.getOperand(0), FR, - Op.getOperand(1), Op.getOperand(2)); -} + 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; + } -static SDOperand LowerFORMAL_ARGUMENTS(SDOperand Op, SelectionDAG &DAG, - int &VarArgsFrameIndex) { - std::vector ArgValues; - SDOperand Root = Op.getOperand(0); - unsigned VRegs[4]; - - unsigned NumArgs = Op.Val->getNumValues()-1; - for (unsigned ArgNo = 0; ArgNo < NumArgs; ++ArgNo) { - SDOperand ArgVal = LowerFORMAL_ARGUMENT(Op, DAG, VRegs, ArgNo); - - ArgValues.push_back(ArgVal); - } - - bool isVarArg = cast(Op.getOperand(2))->getValue() != 0; - if (isVarArg) { - MachineFunction &MF = DAG.getMachineFunction(); - SSARegMap *RegMap = MF.getSSARegMap(); - MachineFrameInfo *MFI = MF.getFrameInfo(); - VarArgsFrameIndex = MFI->CreateFixedObject(MVT::getSizeInBits(MVT::i32)/8, - -16 + NumArgs * 4); - - - static const unsigned REGS[] = { - ARM::R0, ARM::R1, ARM::R2, ARM::R3 - }; - // If this function is vararg, store r0-r3 to their spots on the stack - // so that they may be loaded by deferencing the result of va_next. - SmallVector MemOps; - for (unsigned ArgNo = 0; ArgNo < 4; ++ArgNo) { - int ArgOffset = - (4 - ArgNo) * 4; - int FI = MFI->CreateFixedObject(MVT::getSizeInBits(MVT::i32)/8, - ArgOffset); - SDOperand FIN = DAG.getFrameIndex(FI, MVT::i32); - - unsigned VReg; - if (ArgNo < NumArgs) - VReg = VRegs[ArgNo]; - else - VReg = RegMap->createVirtualRegister(&ARM::IntRegsRegClass); - if (ArgNo >= NumArgs) - MF.addLiveIn(REGS[ArgNo], VReg); - - SDOperand Val = DAG.getCopyFromReg(Root, VReg, MVT::i32); - SDOperand Store = DAG.getNode(ISD::STORE, MVT::Other, Val.getValue(1), - Val, FIN, DAG.getSrcValue(NULL)); - MemOps.push_back(Store); - } - Root = DAG.getNode(ISD::TokenFactor, MVT::Other,&MemOps[0],MemOps.size()); + // 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; } - ArgValues.push_back(Root); + // If the RHS is + imm5 * scale, fold into addr mode. + if (ConstantSDNode *RHS = dyn_cast(N.getOperand(1))) { + int RHSC = (int)RHS->getZExtValue(); + 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; + } + } + } - // 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(SDValue Op, SDValue N, + SDValue &Base, SDValue &OffImm, + SDValue &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(SDValue Op, SDValue N, + SDValue &Base, SDValue &OffImm, + SDValue &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(SDValue Op, SDValue N, + SDValue &Base, SDValue &OffImm, + SDValue &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(SDValue Op, SDValue N, + SDValue &Base, SDValue &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->getZExtValue(); + 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(SDValue Op, + SDValue N, + SDValue &BaseReg, + SDValue &ShReg, + SDValue &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->getZExtValue() & 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 SDValue 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(SDValue Op) { + SDNode *N = Op.getNode(); + DebugLoc dl = N->getDebugLoc(); -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 (N->isMachineOpcode()) + 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)->getZExtValue(); + 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) { + SDValue CPIdx = + CurDAG->getTargetConstantPool(ConstantInt::get(Type::Int32Ty, Val), + TLI.getPointerTy()); + + SDNode *ResNode; + if (Subtarget->isThumb()) + ResNode = CurDAG->getTargetNode(ARM::tLDRcp, dl, MVT::i32, MVT::Other, + CPIdx, CurDAG->getEntryNode()); + else { + SDValue 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, dl, MVT::i32, MVT::Other, + Ops, 6); + } + ReplaceUses(Op, SDValue(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(); + SDValue TFI = CurDAG->getTargetFrameIndex(FI, TLI.getPointerTy()); + if (Subtarget->isThumb()) + return CurDAG->SelectNodeTo(N, ARM::tADDrSPi, MVT::i32, TFI, + CurDAG->getTargetConstant(0, MVT::i32)); + else { + SDValue 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: { + if (!Subtarget->isThumb()) + break; + // Select add sp, c to tADDhirr. + SDValue N0 = Op.getOperand(0); + SDValue 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) { + 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->getZExtValue(); + if (!RHSV) break; + if (isPowerOf2_32(RHSV-1)) { // 2^n+1? + SDValue V = Op.getOperand(0); + unsigned ShImm = ARM_AM::getSORegOpc(ARM_AM::lsl, Log2_32(RHSV-1)); + SDValue 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? + SDValue V = Op.getOperand(0); + unsigned ShImm = ARM_AM::getSORegOpc(ARM_AM::lsl, Log2_32(RHSV+1)); + SDValue 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: + return CurDAG->getTargetNode(ARM::FMRRD, dl, MVT::i32, MVT::i32, + Op.getOperand(0), getAL(CurDAG), + CurDAG->getRegister(0, MVT::i32)); + case ISD::UMUL_LOHI: { + SDValue Ops[] = { Op.getOperand(0), Op.getOperand(1), + getAL(CurDAG), CurDAG->getRegister(0, MVT::i32), + CurDAG->getRegister(0, MVT::i32) }; + return CurDAG->getTargetNode(ARM::UMULL, dl, MVT::i32, MVT::i32, Ops, 5); + } + case ISD::SMUL_LOHI: { + SDValue Ops[] = { Op.getOperand(0), Op.getOperand(1), + getAL(CurDAG), CurDAG->getRegister(0, MVT::i32), + CurDAG->getRegister(0, MVT::i32) }; + return CurDAG->getTargetNode(ARM::SMULL, dl, MVT::i32, MVT::i32, Ops, 5); } + case ISD::LOAD: { + LoadSDNode *LD = cast(Op); + ISD::MemIndexedMode AM = LD->getAddressingMode(); + MVT LoadedVT = LD->getMemoryVT(); + if (AM != ISD::UNINDEXED) { + SDValue 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) { + SDValue Chain = LD->getChain(); + SDValue Base = LD->getBasePtr(); + SDValue Ops[]= { Base, Offset, AMOpc, getAL(CurDAG), + CurDAG->getRegister(0, MVT::i32), Chain }; + return CurDAG->getTargetNode(Opcode, dl, 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; + SDValue Chain = Op.getOperand(0); + SDValue N1 = Op.getOperand(1); + SDValue N2 = Op.getOperand(2); + SDValue N3 = Op.getOperand(3); + SDValue InFlag = Op.getOperand(4); + assert(N1.getOpcode() == ISD::BasicBlock); + assert(N2.getOpcode() == ISD::Constant); + assert(N3.getOpcode() == ISD::Register); + + SDValue Tmp2 = CurDAG->getTargetConstant(((unsigned) + cast(N2)->getZExtValue()), + MVT::i32); + SDValue Ops[] = { N1, Tmp2, N3, Chain, InFlag }; + SDNode *ResNode = CurDAG->getTargetNode(Opc, dl, MVT::Other, + MVT::Flag, Ops, 5); + Chain = SDValue(ResNode, 0); + if (Op.getNode()->getNumValues() == 2) { + InFlag = SDValue(ResNode, 1); + ReplaceUses(SDValue(Op.getNode(), 1), InFlag); + } + ReplaceUses(SDValue(Op.getNode(), 0), SDValue(Chain.getNode(), Chain.getResNo())); + return NULL; + } + case ARMISD::CMOV: { + bool isThumb = Subtarget->isThumb(); + MVT VT = Op.getValueType(); + SDValue N0 = Op.getOperand(0); + SDValue N1 = Op.getOperand(1); + SDValue N2 = Op.getOperand(2); + SDValue N3 = Op.getOperand(3); + SDValue 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 + SDValue CPTmp0; + SDValue CPTmp1; + SDValue CPTmp2; + if (!isThumb && VT == MVT::i32 && + SelectShifterOperandReg(Op, N1, CPTmp0, CPTmp1, CPTmp2)) { + SDValue Tmp2 = CurDAG->getTargetConstant(((unsigned) + cast(N2)->getZExtValue()), + MVT::i32); + SDValue Ops[] = { N0, CPTmp0, CPTmp1, CPTmp2, Tmp2, N3, InFlag }; + return CurDAG->SelectNodeTo(Op.getNode(), 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.getNode())) { + SDValue Tmp1 = CurDAG->getTargetConstant(((unsigned) + cast(N1)->getZExtValue()), + MVT::i32); + Tmp1 = Transform_so_imm_XFORM(Tmp1.getNode()); + SDValue Tmp2 = CurDAG->getTargetConstant(((unsigned) + cast(N2)->getZExtValue()), + MVT::i32); + SDValue Ops[] = { N0, Tmp1, Tmp2, N3, InFlag }; + return CurDAG->SelectNodeTo(Op.getNode(), 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. + SDValue Tmp2 = CurDAG->getTargetConstant(((unsigned) + cast(N2)->getZExtValue()), + MVT::i32); + SDValue Ops[] = { N0, N1, Tmp2, N3, InFlag }; + unsigned Opc = 0; + switch (VT.getSimpleVT()) { + 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.getNode(), Opc, VT, Ops, 5); + } + case ARMISD::CNEG: { + MVT VT = Op.getValueType(); + SDValue N0 = Op.getOperand(0); + SDValue N1 = Op.getOperand(1); + SDValue N2 = Op.getOperand(2); + SDValue N3 = Op.getOperand(3); + SDValue InFlag = Op.getOperand(4); + assert(N2.getOpcode() == ISD::Constant); + assert(N3.getOpcode() == ISD::Register); + + SDValue Tmp2 = CurDAG->getTargetConstant(((unsigned) + cast(N2)->getZExtValue()), + MVT::i32); + SDValue Ops[] = { N0, N1, Tmp2, N3, InFlag }; + unsigned Opc = 0; + switch (VT.getSimpleVT()) { + 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.getNode(), Opc, VT, Ops, 5); } - return NULL; -} -} // end anonymous namespace + case ISD::DECLARE: { + SDValue Chain = Op.getOperand(0); + SDValue N1 = Op.getOperand(1); + SDValue N2 = Op.getOperand(2); + FrameIndexSDNode *FINode = dyn_cast(N1); + // FIXME: handle VLAs. + if (!FINode) { + ReplaceUses(Op.getValue(0), Chain); + return NULL; + } + if (N2.getOpcode() == ARMISD::PIC_ADD && isa(N2.getOperand(0))) + N2 = N2.getOperand(0); + LoadSDNode *Ld = dyn_cast(N2); + if (!Ld) { + ReplaceUses(Op.getValue(0), Chain); + return NULL; + } + SDValue BasePtr = Ld->getBasePtr(); + assert(BasePtr.getOpcode() == ARMISD::Wrapper && + isa(BasePtr.getOperand(0)) && + "llvm.dbg.variable should be a constantpool node"); + ConstantPoolSDNode *CP = cast(BasePtr.getOperand(0)); + GlobalValue *GV = 0; + if (CP->isMachineConstantPoolEntry()) { + ARMConstantPoolValue *ACPV = (ARMConstantPoolValue*)CP->getMachineCPVal(); + GV = ACPV->getGV(); + } else + GV = dyn_cast(CP->getConstVal()); + if (!GV) { + ReplaceUses(Op.getValue(0), Chain); + return NULL; + } + + SDValue Tmp1 = CurDAG->getTargetFrameIndex(FINode->getIndex(), + TLI.getPointerTy()); + SDValue Tmp2 = CurDAG->getTargetGlobalAddress(GV, TLI.getPointerTy()); + SDValue Ops[] = { Tmp1, Tmp2, Chain }; + return CurDAG->getTargetNode(TargetInstrInfo::DECLARE, dl, + MVT::Other, Ops, 3); + } + } + + 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); }