xref: /freebsd/contrib/llvm-project/llvm/lib/Target/Sparc/SparcISelDAGToDAG.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
10b57cec5SDimitry Andric //===-- SparcISelDAGToDAG.cpp - A dag to dag inst selector for Sparc ------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This file defines an instruction selector for the SPARC target.
100b57cec5SDimitry Andric //
110b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
120b57cec5SDimitry Andric 
130b57cec5SDimitry Andric #include "SparcTargetMachine.h"
140b57cec5SDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h"
150b57cec5SDimitry Andric #include "llvm/CodeGen/SelectionDAGISel.h"
160b57cec5SDimitry Andric #include "llvm/IR/Intrinsics.h"
170b57cec5SDimitry Andric #include "llvm/Support/Debug.h"
180b57cec5SDimitry Andric #include "llvm/Support/ErrorHandling.h"
190b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
200b57cec5SDimitry Andric using namespace llvm;
210b57cec5SDimitry Andric 
22bdd1243dSDimitry Andric #define DEBUG_TYPE "sparc-isel"
23bdd1243dSDimitry Andric #define PASS_NAME "SPARC DAG->DAG Pattern Instruction Selection"
24bdd1243dSDimitry Andric 
250b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
260b57cec5SDimitry Andric // Instruction Selector Implementation
270b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
280b57cec5SDimitry Andric 
290b57cec5SDimitry Andric //===--------------------------------------------------------------------===//
300b57cec5SDimitry Andric /// SparcDAGToDAGISel - SPARC specific code to select SPARC machine
310b57cec5SDimitry Andric /// instructions for SelectionDAG operations.
320b57cec5SDimitry Andric ///
330b57cec5SDimitry Andric namespace {
340b57cec5SDimitry Andric class SparcDAGToDAGISel : public SelectionDAGISel {
350b57cec5SDimitry Andric   /// Subtarget - Keep a pointer to the Sparc Subtarget around so that we can
360b57cec5SDimitry Andric   /// make the right decision when generating code for different targets.
37480093f4SDimitry Andric   const SparcSubtarget *Subtarget = nullptr;
38bdd1243dSDimitry Andric 
39*0fca6ea1SDimitry Andric public:
40bdd1243dSDimitry Andric   SparcDAGToDAGISel() = delete;
41bdd1243dSDimitry Andric 
SparcDAGToDAGISel(SparcTargetMachine & tm)42*0fca6ea1SDimitry Andric   explicit SparcDAGToDAGISel(SparcTargetMachine &tm) : SelectionDAGISel(tm) {}
430b57cec5SDimitry Andric 
runOnMachineFunction(MachineFunction & MF)440b57cec5SDimitry Andric   bool runOnMachineFunction(MachineFunction &MF) override {
450b57cec5SDimitry Andric     Subtarget = &MF.getSubtarget<SparcSubtarget>();
460b57cec5SDimitry Andric     return SelectionDAGISel::runOnMachineFunction(MF);
470b57cec5SDimitry Andric   }
480b57cec5SDimitry Andric 
490b57cec5SDimitry Andric   void Select(SDNode *N) override;
500b57cec5SDimitry Andric 
510b57cec5SDimitry Andric   // Complex Pattern Selectors.
520b57cec5SDimitry Andric   bool SelectADDRrr(SDValue N, SDValue &R1, SDValue &R2);
530b57cec5SDimitry Andric   bool SelectADDRri(SDValue N, SDValue &Base, SDValue &Offset);
540b57cec5SDimitry Andric 
550b57cec5SDimitry Andric   /// SelectInlineAsmMemoryOperand - Implement addressing mode selection for
560b57cec5SDimitry Andric   /// inline asm expressions.
570b57cec5SDimitry Andric   bool SelectInlineAsmMemoryOperand(const SDValue &Op,
585f757f3fSDimitry Andric                                     InlineAsm::ConstraintCode ConstraintID,
590b57cec5SDimitry Andric                                     std::vector<SDValue> &OutOps) override;
600b57cec5SDimitry Andric 
610b57cec5SDimitry Andric   // Include the pieces autogenerated from the target description.
620b57cec5SDimitry Andric #include "SparcGenDAGISel.inc"
630b57cec5SDimitry Andric 
640b57cec5SDimitry Andric private:
650b57cec5SDimitry Andric   SDNode* getGlobalBaseReg();
660b57cec5SDimitry Andric   bool tryInlineAsm(SDNode *N);
670b57cec5SDimitry Andric };
68*0fca6ea1SDimitry Andric 
69*0fca6ea1SDimitry Andric class SparcDAGToDAGISelLegacy : public SelectionDAGISelLegacy {
70*0fca6ea1SDimitry Andric public:
71*0fca6ea1SDimitry Andric   static char ID;
SparcDAGToDAGISelLegacy(SparcTargetMachine & tm)72*0fca6ea1SDimitry Andric   explicit SparcDAGToDAGISelLegacy(SparcTargetMachine &tm)
73*0fca6ea1SDimitry Andric       : SelectionDAGISelLegacy(ID, std::make_unique<SparcDAGToDAGISel>(tm)) {}
74*0fca6ea1SDimitry Andric };
750b57cec5SDimitry Andric }  // end anonymous namespace
760b57cec5SDimitry Andric 
77*0fca6ea1SDimitry Andric char SparcDAGToDAGISelLegacy::ID = 0;
78bdd1243dSDimitry Andric 
INITIALIZE_PASS(SparcDAGToDAGISelLegacy,DEBUG_TYPE,PASS_NAME,false,false)79*0fca6ea1SDimitry Andric INITIALIZE_PASS(SparcDAGToDAGISelLegacy, DEBUG_TYPE, PASS_NAME, false, false)
80bdd1243dSDimitry Andric 
810b57cec5SDimitry Andric SDNode* SparcDAGToDAGISel::getGlobalBaseReg() {
8204eeddc0SDimitry Andric   Register GlobalBaseReg = Subtarget->getInstrInfo()->getGlobalBaseReg(MF);
830b57cec5SDimitry Andric   return CurDAG->getRegister(GlobalBaseReg,
840b57cec5SDimitry Andric                              TLI->getPointerTy(CurDAG->getDataLayout()))
850b57cec5SDimitry Andric       .getNode();
860b57cec5SDimitry Andric }
870b57cec5SDimitry Andric 
SelectADDRri(SDValue Addr,SDValue & Base,SDValue & Offset)880b57cec5SDimitry Andric bool SparcDAGToDAGISel::SelectADDRri(SDValue Addr,
890b57cec5SDimitry Andric                                      SDValue &Base, SDValue &Offset) {
900b57cec5SDimitry Andric   if (FrameIndexSDNode *FIN = dyn_cast<FrameIndexSDNode>(Addr)) {
910b57cec5SDimitry Andric     Base = CurDAG->getTargetFrameIndex(
920b57cec5SDimitry Andric         FIN->getIndex(), TLI->getPointerTy(CurDAG->getDataLayout()));
930b57cec5SDimitry Andric     Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32);
940b57cec5SDimitry Andric     return true;
950b57cec5SDimitry Andric   }
960b57cec5SDimitry Andric   if (Addr.getOpcode() == ISD::TargetExternalSymbol ||
970b57cec5SDimitry Andric       Addr.getOpcode() == ISD::TargetGlobalAddress ||
980b57cec5SDimitry Andric       Addr.getOpcode() == ISD::TargetGlobalTLSAddress)
990b57cec5SDimitry Andric     return false;  // direct calls.
1000b57cec5SDimitry Andric 
1010b57cec5SDimitry Andric   if (Addr.getOpcode() == ISD::ADD) {
1020b57cec5SDimitry Andric     if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Addr.getOperand(1))) {
1030b57cec5SDimitry Andric       if (isInt<13>(CN->getSExtValue())) {
1040b57cec5SDimitry Andric         if (FrameIndexSDNode *FIN =
1050b57cec5SDimitry Andric                 dyn_cast<FrameIndexSDNode>(Addr.getOperand(0))) {
1060b57cec5SDimitry Andric           // Constant offset from frame ref.
1070b57cec5SDimitry Andric           Base = CurDAG->getTargetFrameIndex(
1080b57cec5SDimitry Andric               FIN->getIndex(), TLI->getPointerTy(CurDAG->getDataLayout()));
1090b57cec5SDimitry Andric         } else {
1100b57cec5SDimitry Andric           Base = Addr.getOperand(0);
1110b57cec5SDimitry Andric         }
1120b57cec5SDimitry Andric         Offset = CurDAG->getTargetConstant(CN->getZExtValue(), SDLoc(Addr),
1130b57cec5SDimitry Andric                                            MVT::i32);
1140b57cec5SDimitry Andric         return true;
1150b57cec5SDimitry Andric       }
1160b57cec5SDimitry Andric     }
1170b57cec5SDimitry Andric     if (Addr.getOperand(0).getOpcode() == SPISD::Lo) {
1180b57cec5SDimitry Andric       Base = Addr.getOperand(1);
1190b57cec5SDimitry Andric       Offset = Addr.getOperand(0).getOperand(0);
1200b57cec5SDimitry Andric       return true;
1210b57cec5SDimitry Andric     }
1220b57cec5SDimitry Andric     if (Addr.getOperand(1).getOpcode() == SPISD::Lo) {
1230b57cec5SDimitry Andric       Base = Addr.getOperand(0);
1240b57cec5SDimitry Andric       Offset = Addr.getOperand(1).getOperand(0);
1250b57cec5SDimitry Andric       return true;
1260b57cec5SDimitry Andric     }
1270b57cec5SDimitry Andric   }
1280b57cec5SDimitry Andric   Base = Addr;
1290b57cec5SDimitry Andric   Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32);
1300b57cec5SDimitry Andric   return true;
1310b57cec5SDimitry Andric }
1320b57cec5SDimitry Andric 
SelectADDRrr(SDValue Addr,SDValue & R1,SDValue & R2)1330b57cec5SDimitry Andric bool SparcDAGToDAGISel::SelectADDRrr(SDValue Addr, SDValue &R1, SDValue &R2) {
1340b57cec5SDimitry Andric   if (Addr.getOpcode() == ISD::FrameIndex) return false;
1350b57cec5SDimitry Andric   if (Addr.getOpcode() == ISD::TargetExternalSymbol ||
1360b57cec5SDimitry Andric       Addr.getOpcode() == ISD::TargetGlobalAddress ||
1370b57cec5SDimitry Andric       Addr.getOpcode() == ISD::TargetGlobalTLSAddress)
1380b57cec5SDimitry Andric     return false;  // direct calls.
1390b57cec5SDimitry Andric 
1400b57cec5SDimitry Andric   if (Addr.getOpcode() == ISD::ADD) {
1410b57cec5SDimitry Andric     if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Addr.getOperand(1)))
1420b57cec5SDimitry Andric       if (isInt<13>(CN->getSExtValue()))
1430b57cec5SDimitry Andric         return false;  // Let the reg+imm pattern catch this!
1440b57cec5SDimitry Andric     if (Addr.getOperand(0).getOpcode() == SPISD::Lo ||
1450b57cec5SDimitry Andric         Addr.getOperand(1).getOpcode() == SPISD::Lo)
1460b57cec5SDimitry Andric       return false;  // Let the reg+imm pattern catch this!
1470b57cec5SDimitry Andric     R1 = Addr.getOperand(0);
1480b57cec5SDimitry Andric     R2 = Addr.getOperand(1);
1490b57cec5SDimitry Andric     return true;
1500b57cec5SDimitry Andric   }
1510b57cec5SDimitry Andric 
1520b57cec5SDimitry Andric   R1 = Addr;
1530b57cec5SDimitry Andric   R2 = CurDAG->getRegister(SP::G0, TLI->getPointerTy(CurDAG->getDataLayout()));
1540b57cec5SDimitry Andric   return true;
1550b57cec5SDimitry Andric }
1560b57cec5SDimitry Andric 
1570b57cec5SDimitry Andric 
1580b57cec5SDimitry Andric // Re-assemble i64 arguments split up in SelectionDAGBuilder's
1590b57cec5SDimitry Andric // visitInlineAsm / GetRegistersForValue functions.
1600b57cec5SDimitry Andric //
1610b57cec5SDimitry Andric // Note: This function was copied from, and is essentially identical
1620b57cec5SDimitry Andric // to ARMISelDAGToDAG::SelectInlineAsm. It is very unfortunate that
1630b57cec5SDimitry Andric // such hacking-up is necessary; a rethink of how inline asm operands
1640b57cec5SDimitry Andric // are handled may be in order to make doing this more sane.
1650b57cec5SDimitry Andric //
1660b57cec5SDimitry Andric // TODO: fix inline asm support so I can simply tell it that 'i64'
1670b57cec5SDimitry Andric // inputs to asm need to be allocated to the IntPair register type,
1680b57cec5SDimitry Andric // and have that work. Then, delete this function.
tryInlineAsm(SDNode * N)1690b57cec5SDimitry Andric bool SparcDAGToDAGISel::tryInlineAsm(SDNode *N){
1700b57cec5SDimitry Andric   std::vector<SDValue> AsmNodeOperands;
1715f757f3fSDimitry Andric   InlineAsm::Flag Flag;
1720b57cec5SDimitry Andric   bool Changed = false;
1730b57cec5SDimitry Andric   unsigned NumOps = N->getNumOperands();
1740b57cec5SDimitry Andric 
1750b57cec5SDimitry Andric   // Normally, i64 data is bounded to two arbitrary GPRs for "%r"
1760b57cec5SDimitry Andric   // constraint.  However, some instructions (e.g. ldd/std) require
1770b57cec5SDimitry Andric   // (even/even+1) GPRs.
1780b57cec5SDimitry Andric 
1790b57cec5SDimitry Andric   // So, here, we check for this case, and mutate the inlineasm to use
1800b57cec5SDimitry Andric   // a single IntPair register instead, which guarantees such even/odd
1810b57cec5SDimitry Andric   // placement.
1820b57cec5SDimitry Andric 
1830b57cec5SDimitry Andric   SDLoc dl(N);
18404eeddc0SDimitry Andric   SDValue Glue = N->getGluedNode() ? N->getOperand(NumOps - 1) : SDValue();
1850b57cec5SDimitry Andric 
1860b57cec5SDimitry Andric   SmallVector<bool, 8> OpChanged;
1870b57cec5SDimitry Andric   // Glue node will be appended late.
1880b57cec5SDimitry Andric   for(unsigned i = 0, e = N->getGluedNode() ? NumOps - 1 : NumOps; i < e; ++i) {
1890b57cec5SDimitry Andric     SDValue op = N->getOperand(i);
1900b57cec5SDimitry Andric     AsmNodeOperands.push_back(op);
1910b57cec5SDimitry Andric 
1920b57cec5SDimitry Andric     if (i < InlineAsm::Op_FirstOperand)
1930b57cec5SDimitry Andric       continue;
1940b57cec5SDimitry Andric 
1955f757f3fSDimitry Andric     if (const auto *C = dyn_cast<ConstantSDNode>(N->getOperand(i)))
1965f757f3fSDimitry Andric       Flag = InlineAsm::Flag(C->getZExtValue());
1970b57cec5SDimitry Andric     else
1980b57cec5SDimitry Andric       continue;
1990b57cec5SDimitry Andric 
2000b57cec5SDimitry Andric     // Immediate operands to inline asm in the SelectionDAG are modeled with
2015f757f3fSDimitry Andric     // two operands. The first is a constant of value InlineAsm::Kind::Imm, and
2020b57cec5SDimitry Andric     // the second is a constant with the value of the immediate. If we get here
2035f757f3fSDimitry Andric     // and we have a Kind::Imm, skip the next operand, and continue.
2045f757f3fSDimitry Andric     if (Flag.isImmKind()) {
2050b57cec5SDimitry Andric       SDValue op = N->getOperand(++i);
2060b57cec5SDimitry Andric       AsmNodeOperands.push_back(op);
2070b57cec5SDimitry Andric       continue;
2080b57cec5SDimitry Andric     }
2090b57cec5SDimitry Andric 
2105f757f3fSDimitry Andric     const unsigned NumRegs = Flag.getNumOperandRegisters();
2110b57cec5SDimitry Andric     if (NumRegs)
2120b57cec5SDimitry Andric       OpChanged.push_back(false);
2130b57cec5SDimitry Andric 
2140b57cec5SDimitry Andric     unsigned DefIdx = 0;
2150b57cec5SDimitry Andric     bool IsTiedToChangedOp = false;
2160b57cec5SDimitry Andric     // If it's a use that is tied with a previous def, it has no
2170b57cec5SDimitry Andric     // reg class constraint.
2185f757f3fSDimitry Andric     if (Changed && Flag.isUseOperandTiedToDef(DefIdx))
2190b57cec5SDimitry Andric       IsTiedToChangedOp = OpChanged[DefIdx];
2200b57cec5SDimitry Andric 
2215f757f3fSDimitry Andric     if (!Flag.isRegUseKind() && !Flag.isRegDefKind() &&
2225f757f3fSDimitry Andric         !Flag.isRegDefEarlyClobberKind())
2230b57cec5SDimitry Andric       continue;
2240b57cec5SDimitry Andric 
2250b57cec5SDimitry Andric     unsigned RC;
2265f757f3fSDimitry Andric     const bool HasRC = Flag.hasRegClassConstraint(RC);
2270b57cec5SDimitry Andric     if ((!IsTiedToChangedOp && (!HasRC || RC != SP::IntRegsRegClassID))
2280b57cec5SDimitry Andric         || NumRegs != 2)
2290b57cec5SDimitry Andric       continue;
2300b57cec5SDimitry Andric 
2310b57cec5SDimitry Andric     assert((i+2 < NumOps) && "Invalid number of operands in inline asm");
2320b57cec5SDimitry Andric     SDValue V0 = N->getOperand(i+1);
2330b57cec5SDimitry Andric     SDValue V1 = N->getOperand(i+2);
23404eeddc0SDimitry Andric     Register Reg0 = cast<RegisterSDNode>(V0)->getReg();
23504eeddc0SDimitry Andric     Register Reg1 = cast<RegisterSDNode>(V1)->getReg();
2360b57cec5SDimitry Andric     SDValue PairedReg;
2370b57cec5SDimitry Andric     MachineRegisterInfo &MRI = MF->getRegInfo();
2380b57cec5SDimitry Andric 
2395f757f3fSDimitry Andric     if (Flag.isRegDefKind() || Flag.isRegDefEarlyClobberKind()) {
2400b57cec5SDimitry Andric       // Replace the two GPRs with 1 GPRPair and copy values from GPRPair to
2410b57cec5SDimitry Andric       // the original GPRs.
2420b57cec5SDimitry Andric 
2438bcb0991SDimitry Andric       Register GPVR = MRI.createVirtualRegister(&SP::IntPairRegClass);
2440b57cec5SDimitry Andric       PairedReg = CurDAG->getRegister(GPVR, MVT::v2i32);
2450b57cec5SDimitry Andric       SDValue Chain = SDValue(N,0);
2460b57cec5SDimitry Andric 
2470b57cec5SDimitry Andric       SDNode *GU = N->getGluedUser();
2480b57cec5SDimitry Andric       SDValue RegCopy = CurDAG->getCopyFromReg(Chain, dl, GPVR, MVT::v2i32,
2490b57cec5SDimitry Andric                                                Chain.getValue(1));
2500b57cec5SDimitry Andric 
2510b57cec5SDimitry Andric       // Extract values from a GPRPair reg and copy to the original GPR reg.
2520b57cec5SDimitry Andric       SDValue Sub0 = CurDAG->getTargetExtractSubreg(SP::sub_even, dl, MVT::i32,
2530b57cec5SDimitry Andric                                                     RegCopy);
2540b57cec5SDimitry Andric       SDValue Sub1 = CurDAG->getTargetExtractSubreg(SP::sub_odd, dl, MVT::i32,
2550b57cec5SDimitry Andric                                                     RegCopy);
2560b57cec5SDimitry Andric       SDValue T0 = CurDAG->getCopyToReg(Sub0, dl, Reg0, Sub0,
2570b57cec5SDimitry Andric                                         RegCopy.getValue(1));
2580b57cec5SDimitry Andric       SDValue T1 = CurDAG->getCopyToReg(Sub1, dl, Reg1, Sub1, T0.getValue(1));
2590b57cec5SDimitry Andric 
2600b57cec5SDimitry Andric       // Update the original glue user.
2610b57cec5SDimitry Andric       std::vector<SDValue> Ops(GU->op_begin(), GU->op_end()-1);
2620b57cec5SDimitry Andric       Ops.push_back(T1.getValue(1));
2630b57cec5SDimitry Andric       CurDAG->UpdateNodeOperands(GU, Ops);
2645f757f3fSDimitry Andric     } else {
2655f757f3fSDimitry Andric       // For Kind  == InlineAsm::Kind::RegUse, we first copy two GPRs into a
2660b57cec5SDimitry Andric       // GPRPair and then pass the GPRPair to the inline asm.
2670b57cec5SDimitry Andric       SDValue Chain = AsmNodeOperands[InlineAsm::Op_InputChain];
2680b57cec5SDimitry Andric 
2690b57cec5SDimitry Andric       // As REG_SEQ doesn't take RegisterSDNode, we copy them first.
2700b57cec5SDimitry Andric       SDValue T0 = CurDAG->getCopyFromReg(Chain, dl, Reg0, MVT::i32,
2710b57cec5SDimitry Andric                                           Chain.getValue(1));
2720b57cec5SDimitry Andric       SDValue T1 = CurDAG->getCopyFromReg(Chain, dl, Reg1, MVT::i32,
2730b57cec5SDimitry Andric                                           T0.getValue(1));
2740b57cec5SDimitry Andric       SDValue Pair = SDValue(
2750b57cec5SDimitry Andric           CurDAG->getMachineNode(
2760b57cec5SDimitry Andric               TargetOpcode::REG_SEQUENCE, dl, MVT::v2i32,
2770b57cec5SDimitry Andric               {
2780b57cec5SDimitry Andric                   CurDAG->getTargetConstant(SP::IntPairRegClassID, dl,
2790b57cec5SDimitry Andric                                             MVT::i32),
2800b57cec5SDimitry Andric                   T0,
2810b57cec5SDimitry Andric                   CurDAG->getTargetConstant(SP::sub_even, dl, MVT::i32),
2820b57cec5SDimitry Andric                   T1,
2830b57cec5SDimitry Andric                   CurDAG->getTargetConstant(SP::sub_odd, dl, MVT::i32),
2840b57cec5SDimitry Andric               }),
2850b57cec5SDimitry Andric           0);
2860b57cec5SDimitry Andric 
2870b57cec5SDimitry Andric       // Copy REG_SEQ into a GPRPair-typed VR and replace the original two
2880b57cec5SDimitry Andric       // i32 VRs of inline asm with it.
2898bcb0991SDimitry Andric       Register GPVR = MRI.createVirtualRegister(&SP::IntPairRegClass);
2900b57cec5SDimitry Andric       PairedReg = CurDAG->getRegister(GPVR, MVT::v2i32);
2910b57cec5SDimitry Andric       Chain = CurDAG->getCopyToReg(T1, dl, GPVR, Pair, T1.getValue(1));
2920b57cec5SDimitry Andric 
2930b57cec5SDimitry Andric       AsmNodeOperands[InlineAsm::Op_InputChain] = Chain;
2940b57cec5SDimitry Andric       Glue = Chain.getValue(1);
2950b57cec5SDimitry Andric     }
2960b57cec5SDimitry Andric 
2970b57cec5SDimitry Andric     Changed = true;
2980b57cec5SDimitry Andric 
2990b57cec5SDimitry Andric     if(PairedReg.getNode()) {
3000b57cec5SDimitry Andric       OpChanged[OpChanged.size() -1 ] = true;
3015f757f3fSDimitry Andric       Flag = InlineAsm::Flag(Flag.getKind(), 1 /* RegNum*/);
3020b57cec5SDimitry Andric       if (IsTiedToChangedOp)
3035f757f3fSDimitry Andric         Flag.setMatchingOp(DefIdx);
3040b57cec5SDimitry Andric       else
3055f757f3fSDimitry Andric         Flag.setRegClass(SP::IntPairRegClassID);
3060b57cec5SDimitry Andric       // Replace the current flag.
3070b57cec5SDimitry Andric       AsmNodeOperands[AsmNodeOperands.size() -1] = CurDAG->getTargetConstant(
3080b57cec5SDimitry Andric           Flag, dl, MVT::i32);
3090b57cec5SDimitry Andric       // Add the new register node and skip the original two GPRs.
3100b57cec5SDimitry Andric       AsmNodeOperands.push_back(PairedReg);
3110b57cec5SDimitry Andric       // Skip the next two GPRs.
3120b57cec5SDimitry Andric       i += 2;
3130b57cec5SDimitry Andric     }
3140b57cec5SDimitry Andric   }
3150b57cec5SDimitry Andric 
3160b57cec5SDimitry Andric   if (Glue.getNode())
3170b57cec5SDimitry Andric     AsmNodeOperands.push_back(Glue);
3180b57cec5SDimitry Andric   if (!Changed)
3190b57cec5SDimitry Andric     return false;
3200b57cec5SDimitry Andric 
3210b57cec5SDimitry Andric   SelectInlineAsmMemoryOperands(AsmNodeOperands, SDLoc(N));
3220b57cec5SDimitry Andric 
3230b57cec5SDimitry Andric   SDValue New = CurDAG->getNode(N->getOpcode(), SDLoc(N),
3240b57cec5SDimitry Andric       CurDAG->getVTList(MVT::Other, MVT::Glue), AsmNodeOperands);
3250b57cec5SDimitry Andric   New->setNodeId(-1);
3260b57cec5SDimitry Andric   ReplaceNode(N, New.getNode());
3270b57cec5SDimitry Andric   return true;
3280b57cec5SDimitry Andric }
3290b57cec5SDimitry Andric 
Select(SDNode * N)3300b57cec5SDimitry Andric void SparcDAGToDAGISel::Select(SDNode *N) {
3310b57cec5SDimitry Andric   SDLoc dl(N);
3320b57cec5SDimitry Andric   if (N->isMachineOpcode()) {
3330b57cec5SDimitry Andric     N->setNodeId(-1);
3340b57cec5SDimitry Andric     return;   // Already selected.
3350b57cec5SDimitry Andric   }
3360b57cec5SDimitry Andric 
3370b57cec5SDimitry Andric   switch (N->getOpcode()) {
3380b57cec5SDimitry Andric   default: break;
3390b57cec5SDimitry Andric   case ISD::INLINEASM:
3400b57cec5SDimitry Andric   case ISD::INLINEASM_BR: {
3410b57cec5SDimitry Andric     if (tryInlineAsm(N))
3420b57cec5SDimitry Andric       return;
3430b57cec5SDimitry Andric     break;
3440b57cec5SDimitry Andric   }
3450b57cec5SDimitry Andric   case SPISD::GLOBAL_BASE_REG:
3460b57cec5SDimitry Andric     ReplaceNode(N, getGlobalBaseReg());
3470b57cec5SDimitry Andric     return;
3480b57cec5SDimitry Andric 
3490b57cec5SDimitry Andric   case ISD::SDIV:
3500b57cec5SDimitry Andric   case ISD::UDIV: {
3510b57cec5SDimitry Andric     // sdivx / udivx handle 64-bit divides.
3520b57cec5SDimitry Andric     if (N->getValueType(0) == MVT::i64)
3530b57cec5SDimitry Andric       break;
3540b57cec5SDimitry Andric     // FIXME: should use a custom expander to expose the SRA to the dag.
3550b57cec5SDimitry Andric     SDValue DivLHS = N->getOperand(0);
3560b57cec5SDimitry Andric     SDValue DivRHS = N->getOperand(1);
3570b57cec5SDimitry Andric 
3580b57cec5SDimitry Andric     // Set the Y register to the high-part.
3590b57cec5SDimitry Andric     SDValue TopPart;
3600b57cec5SDimitry Andric     if (N->getOpcode() == ISD::SDIV) {
3610b57cec5SDimitry Andric       TopPart = SDValue(CurDAG->getMachineNode(SP::SRAri, dl, MVT::i32, DivLHS,
3620b57cec5SDimitry Andric                                    CurDAG->getTargetConstant(31, dl, MVT::i32)),
3630b57cec5SDimitry Andric                         0);
3640b57cec5SDimitry Andric     } else {
3650b57cec5SDimitry Andric       TopPart = CurDAG->getRegister(SP::G0, MVT::i32);
3660b57cec5SDimitry Andric     }
3670b57cec5SDimitry Andric     TopPart = CurDAG->getCopyToReg(CurDAG->getEntryNode(), dl, SP::Y, TopPart,
3680b57cec5SDimitry Andric                                    SDValue())
3690b57cec5SDimitry Andric                   .getValue(1);
3700b57cec5SDimitry Andric 
3710b57cec5SDimitry Andric     // FIXME: Handle div by immediate.
3720b57cec5SDimitry Andric     unsigned Opcode = N->getOpcode() == ISD::SDIV ? SP::SDIVrr : SP::UDIVrr;
3730b57cec5SDimitry Andric     CurDAG->SelectNodeTo(N, Opcode, MVT::i32, DivLHS, DivRHS, TopPart);
3740b57cec5SDimitry Andric     return;
3750b57cec5SDimitry Andric   }
3760b57cec5SDimitry Andric   }
3770b57cec5SDimitry Andric 
3780b57cec5SDimitry Andric   SelectCode(N);
3790b57cec5SDimitry Andric }
3800b57cec5SDimitry Andric 
3810b57cec5SDimitry Andric 
3820b57cec5SDimitry Andric /// SelectInlineAsmMemoryOperand - Implement addressing mode selection for
3830b57cec5SDimitry Andric /// inline asm expressions.
SelectInlineAsmMemoryOperand(const SDValue & Op,InlineAsm::ConstraintCode ConstraintID,std::vector<SDValue> & OutOps)3845f757f3fSDimitry Andric bool SparcDAGToDAGISel::SelectInlineAsmMemoryOperand(
3855f757f3fSDimitry Andric     const SDValue &Op, InlineAsm::ConstraintCode ConstraintID,
3860b57cec5SDimitry Andric     std::vector<SDValue> &OutOps) {
3870b57cec5SDimitry Andric   SDValue Op0, Op1;
3880b57cec5SDimitry Andric   switch (ConstraintID) {
3890b57cec5SDimitry Andric   default: return true;
3905f757f3fSDimitry Andric   case InlineAsm::ConstraintCode::o:
3915f757f3fSDimitry Andric   case InlineAsm::ConstraintCode::m: // memory
3920b57cec5SDimitry Andric     if (!SelectADDRrr(Op, Op0, Op1))
3930b57cec5SDimitry Andric       SelectADDRri(Op, Op0, Op1);
3940b57cec5SDimitry Andric     break;
3950b57cec5SDimitry Andric   }
3960b57cec5SDimitry Andric 
3970b57cec5SDimitry Andric   OutOps.push_back(Op0);
3980b57cec5SDimitry Andric   OutOps.push_back(Op1);
3990b57cec5SDimitry Andric   return false;
4000b57cec5SDimitry Andric }
4010b57cec5SDimitry Andric 
4020b57cec5SDimitry Andric /// createSparcISelDag - This pass converts a legalized DAG into a
4030b57cec5SDimitry Andric /// SPARC-specific DAG, ready for instruction scheduling.
4040b57cec5SDimitry Andric ///
createSparcISelDag(SparcTargetMachine & TM)4050b57cec5SDimitry Andric FunctionPass *llvm::createSparcISelDag(SparcTargetMachine &TM) {
406*0fca6ea1SDimitry Andric   return new SparcDAGToDAGISelLegacy(TM);
4070b57cec5SDimitry Andric }
408