aboutsummaryrefslogtreecommitdiff
path: root/lib/Target/ARM/ARMISelDAGToDAG.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Target/ARM/ARMISelDAGToDAG.cpp')
-rw-r--r--lib/Target/ARM/ARMISelDAGToDAG.cpp1436
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();