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