1349cc55cSDimitry Andric //===-- CSKYISelDAGToDAG.cpp - A dag to dag inst selector for CSKY---------===//
2349cc55cSDimitry Andric //
3349cc55cSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4349cc55cSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5349cc55cSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6349cc55cSDimitry Andric //
7349cc55cSDimitry Andric //===----------------------------------------------------------------------===//
8349cc55cSDimitry Andric //
9349cc55cSDimitry Andric // This file defines an instruction selector for the CSKY target.
10349cc55cSDimitry Andric //
11349cc55cSDimitry Andric //===----------------------------------------------------------------------===//
12349cc55cSDimitry Andric
13349cc55cSDimitry Andric #include "CSKY.h"
14349cc55cSDimitry Andric #include "CSKYSubtarget.h"
15349cc55cSDimitry Andric #include "CSKYTargetMachine.h"
16349cc55cSDimitry Andric #include "MCTargetDesc/CSKYMCTargetDesc.h"
1781ad6265SDimitry Andric #include "llvm/CodeGen/MachineFrameInfo.h"
18349cc55cSDimitry Andric #include "llvm/CodeGen/SelectionDAG.h"
19349cc55cSDimitry Andric #include "llvm/CodeGen/SelectionDAGISel.h"
20349cc55cSDimitry Andric
21349cc55cSDimitry Andric using namespace llvm;
22349cc55cSDimitry Andric
23349cc55cSDimitry Andric #define DEBUG_TYPE "csky-isel"
24bdd1243dSDimitry Andric #define PASS_NAME "CSKY DAG->DAG Pattern Instruction Selection"
25349cc55cSDimitry Andric
26349cc55cSDimitry Andric namespace {
27349cc55cSDimitry Andric class CSKYDAGToDAGISel : public SelectionDAGISel {
28349cc55cSDimitry Andric const CSKYSubtarget *Subtarget;
29349cc55cSDimitry Andric
30349cc55cSDimitry Andric public:
CSKYDAGToDAGISel(CSKYTargetMachine & TM,CodeGenOptLevel OptLevel)315f757f3fSDimitry Andric explicit CSKYDAGToDAGISel(CSKYTargetMachine &TM, CodeGenOptLevel OptLevel)
32*0fca6ea1SDimitry Andric : SelectionDAGISel(TM, OptLevel) {}
33349cc55cSDimitry Andric
runOnMachineFunction(MachineFunction & MF)34349cc55cSDimitry Andric bool runOnMachineFunction(MachineFunction &MF) override {
35349cc55cSDimitry Andric // Reset the subtarget each time through.
36349cc55cSDimitry Andric Subtarget = &MF.getSubtarget<CSKYSubtarget>();
37349cc55cSDimitry Andric SelectionDAGISel::runOnMachineFunction(MF);
38349cc55cSDimitry Andric return true;
39349cc55cSDimitry Andric }
40349cc55cSDimitry Andric
41349cc55cSDimitry Andric void Select(SDNode *N) override;
420eae32dcSDimitry Andric bool selectAddCarry(SDNode *N);
430eae32dcSDimitry Andric bool selectSubCarry(SDNode *N);
4481ad6265SDimitry Andric bool selectBITCAST_TO_LOHI(SDNode *N);
4581ad6265SDimitry Andric bool selectInlineAsm(SDNode *N);
4681ad6265SDimitry Andric
4781ad6265SDimitry Andric SDNode *createGPRPairNode(EVT VT, SDValue V0, SDValue V1);
4881ad6265SDimitry Andric
495f757f3fSDimitry Andric bool SelectInlineAsmMemoryOperand(const SDValue &Op,
505f757f3fSDimitry Andric InlineAsm::ConstraintCode ConstraintID,
5181ad6265SDimitry Andric std::vector<SDValue> &OutOps) override;
52349cc55cSDimitry Andric
53349cc55cSDimitry Andric #include "CSKYGenDAGISel.inc"
54349cc55cSDimitry Andric };
55*0fca6ea1SDimitry Andric
56*0fca6ea1SDimitry Andric class CSKYDAGToDAGISelLegacy : public SelectionDAGISelLegacy {
57*0fca6ea1SDimitry Andric public:
58*0fca6ea1SDimitry Andric static char ID;
CSKYDAGToDAGISelLegacy(CSKYTargetMachine & TM,CodeGenOptLevel OptLevel)59*0fca6ea1SDimitry Andric explicit CSKYDAGToDAGISelLegacy(CSKYTargetMachine &TM,
60*0fca6ea1SDimitry Andric CodeGenOptLevel OptLevel)
61*0fca6ea1SDimitry Andric : SelectionDAGISelLegacy(
62*0fca6ea1SDimitry Andric ID, std::make_unique<CSKYDAGToDAGISel>(TM, OptLevel)) {}
63*0fca6ea1SDimitry Andric };
64349cc55cSDimitry Andric } // namespace
65349cc55cSDimitry Andric
66*0fca6ea1SDimitry Andric char CSKYDAGToDAGISelLegacy::ID = 0;
67bdd1243dSDimitry Andric
INITIALIZE_PASS(CSKYDAGToDAGISelLegacy,DEBUG_TYPE,PASS_NAME,false,false)68*0fca6ea1SDimitry Andric INITIALIZE_PASS(CSKYDAGToDAGISelLegacy, DEBUG_TYPE, PASS_NAME, false, false)
69bdd1243dSDimitry Andric
70349cc55cSDimitry Andric void CSKYDAGToDAGISel::Select(SDNode *N) {
71349cc55cSDimitry Andric // If we have a custom node, we have already selected
72349cc55cSDimitry Andric if (N->isMachineOpcode()) {
73349cc55cSDimitry Andric LLVM_DEBUG(dbgs() << "== "; N->dump(CurDAG); dbgs() << "\n");
74349cc55cSDimitry Andric N->setNodeId(-1);
75349cc55cSDimitry Andric return;
76349cc55cSDimitry Andric }
77349cc55cSDimitry Andric
78349cc55cSDimitry Andric SDLoc Dl(N);
79349cc55cSDimitry Andric unsigned Opcode = N->getOpcode();
80349cc55cSDimitry Andric bool IsSelected = false;
81349cc55cSDimitry Andric
82349cc55cSDimitry Andric switch (Opcode) {
83349cc55cSDimitry Andric default:
84349cc55cSDimitry Andric break;
8506c3fb27SDimitry Andric case ISD::UADDO_CARRY:
860eae32dcSDimitry Andric IsSelected = selectAddCarry(N);
870eae32dcSDimitry Andric break;
8806c3fb27SDimitry Andric case ISD::USUBO_CARRY:
890eae32dcSDimitry Andric IsSelected = selectSubCarry(N);
900eae32dcSDimitry Andric break;
9104eeddc0SDimitry Andric case ISD::GLOBAL_OFFSET_TABLE: {
9204eeddc0SDimitry Andric Register GP = Subtarget->getInstrInfo()->getGlobalBaseReg(*MF);
9304eeddc0SDimitry Andric ReplaceNode(N, CurDAG->getRegister(GP, N->getValueType(0)).getNode());
9404eeddc0SDimitry Andric
9504eeddc0SDimitry Andric IsSelected = true;
9604eeddc0SDimitry Andric break;
9704eeddc0SDimitry Andric }
9804eeddc0SDimitry Andric case ISD::FrameIndex: {
9904eeddc0SDimitry Andric SDValue Imm = CurDAG->getTargetConstant(0, Dl, MVT::i32);
10004eeddc0SDimitry Andric int FI = cast<FrameIndexSDNode>(N)->getIndex();
10104eeddc0SDimitry Andric SDValue TFI = CurDAG->getTargetFrameIndex(FI, MVT::i32);
10204eeddc0SDimitry Andric ReplaceNode(N, CurDAG->getMachineNode(Subtarget->hasE2() ? CSKY::ADDI32
10304eeddc0SDimitry Andric : CSKY::ADDI16XZ,
10404eeddc0SDimitry Andric Dl, MVT::i32, TFI, Imm));
10504eeddc0SDimitry Andric
10604eeddc0SDimitry Andric IsSelected = true;
10704eeddc0SDimitry Andric break;
10804eeddc0SDimitry Andric }
10981ad6265SDimitry Andric case CSKYISD::BITCAST_TO_LOHI:
11081ad6265SDimitry Andric IsSelected = selectBITCAST_TO_LOHI(N);
11181ad6265SDimitry Andric break;
11281ad6265SDimitry Andric case ISD::INLINEASM:
11381ad6265SDimitry Andric case ISD::INLINEASM_BR:
11481ad6265SDimitry Andric IsSelected = selectInlineAsm(N);
11581ad6265SDimitry Andric break;
116349cc55cSDimitry Andric }
117349cc55cSDimitry Andric
118349cc55cSDimitry Andric if (IsSelected)
119349cc55cSDimitry Andric return;
120349cc55cSDimitry Andric
121349cc55cSDimitry Andric // Select the default instruction.
122349cc55cSDimitry Andric SelectCode(N);
123349cc55cSDimitry Andric }
124349cc55cSDimitry Andric
selectInlineAsm(SDNode * N)12581ad6265SDimitry Andric bool CSKYDAGToDAGISel::selectInlineAsm(SDNode *N) {
12681ad6265SDimitry Andric std::vector<SDValue> AsmNodeOperands;
1275f757f3fSDimitry Andric InlineAsm::Flag Flag;
12881ad6265SDimitry Andric bool Changed = false;
12981ad6265SDimitry Andric unsigned NumOps = N->getNumOperands();
13081ad6265SDimitry Andric
13181ad6265SDimitry Andric // Normally, i64 data is bounded to two arbitrary GRPs for "%r" constraint.
13281ad6265SDimitry Andric // However, some instructions (e.g. mula.s32) require GPR pair.
13381ad6265SDimitry Andric // Since there is no constraint to explicitly specify a
13481ad6265SDimitry Andric // reg pair, we use GPRPair reg class for "%r" for 64-bit data.
13581ad6265SDimitry Andric
13681ad6265SDimitry Andric SDLoc dl(N);
13781ad6265SDimitry Andric SDValue Glue =
13881ad6265SDimitry Andric N->getGluedNode() ? N->getOperand(NumOps - 1) : SDValue(nullptr, 0);
13981ad6265SDimitry Andric
14081ad6265SDimitry Andric SmallVector<bool, 8> OpChanged;
14181ad6265SDimitry Andric // Glue node will be appended late.
14281ad6265SDimitry Andric for (unsigned i = 0, e = N->getGluedNode() ? NumOps - 1 : NumOps; i < e;
14381ad6265SDimitry Andric ++i) {
14481ad6265SDimitry Andric SDValue op = N->getOperand(i);
14581ad6265SDimitry Andric AsmNodeOperands.push_back(op);
14681ad6265SDimitry Andric
14781ad6265SDimitry Andric if (i < InlineAsm::Op_FirstOperand)
14881ad6265SDimitry Andric continue;
14981ad6265SDimitry Andric
1505f757f3fSDimitry Andric if (const auto *C = dyn_cast<ConstantSDNode>(N->getOperand(i)))
1515f757f3fSDimitry Andric Flag = InlineAsm::Flag(C->getZExtValue());
1525f757f3fSDimitry Andric else
15381ad6265SDimitry Andric continue;
15481ad6265SDimitry Andric
15581ad6265SDimitry Andric // Immediate operands to inline asm in the SelectionDAG are modeled with
1565f757f3fSDimitry Andric // two operands. The first is a constant of value InlineAsm::Kind::Imm, and
15781ad6265SDimitry Andric // the second is a constant with the value of the immediate. If we get here
1585f757f3fSDimitry Andric // and we have a Kind::Imm, skip the next operand, and continue.
1595f757f3fSDimitry Andric if (Flag.isImmKind()) {
16081ad6265SDimitry Andric SDValue op = N->getOperand(++i);
16181ad6265SDimitry Andric AsmNodeOperands.push_back(op);
16281ad6265SDimitry Andric continue;
16381ad6265SDimitry Andric }
16481ad6265SDimitry Andric
1655f757f3fSDimitry Andric const unsigned NumRegs = Flag.getNumOperandRegisters();
16681ad6265SDimitry Andric if (NumRegs)
16781ad6265SDimitry Andric OpChanged.push_back(false);
16881ad6265SDimitry Andric
16981ad6265SDimitry Andric unsigned DefIdx = 0;
17081ad6265SDimitry Andric bool IsTiedToChangedOp = false;
17181ad6265SDimitry Andric // If it's a use that is tied with a previous def, it has no
17281ad6265SDimitry Andric // reg class constraint.
1735f757f3fSDimitry Andric if (Changed && Flag.isUseOperandTiedToDef(DefIdx))
17481ad6265SDimitry Andric IsTiedToChangedOp = OpChanged[DefIdx];
17581ad6265SDimitry Andric
17681ad6265SDimitry Andric // Memory operands to inline asm in the SelectionDAG are modeled with two
1775f757f3fSDimitry Andric // operands: a constant of value InlineAsm::Kind::Mem followed by the input
1785f757f3fSDimitry Andric // operand. If we get here and we have a Kind::Mem, skip the next operand
1795f757f3fSDimitry Andric // (so it doesn't get misinterpreted), and continue. We do this here because
18081ad6265SDimitry Andric // it's important to update the OpChanged array correctly before moving on.
1815f757f3fSDimitry Andric if (Flag.isMemKind()) {
18281ad6265SDimitry Andric SDValue op = N->getOperand(++i);
18381ad6265SDimitry Andric AsmNodeOperands.push_back(op);
18481ad6265SDimitry Andric continue;
18581ad6265SDimitry Andric }
18681ad6265SDimitry Andric
1875f757f3fSDimitry Andric if (!Flag.isRegUseKind() && !Flag.isRegDefKind() &&
1885f757f3fSDimitry Andric !Flag.isRegDefEarlyClobberKind())
18981ad6265SDimitry Andric continue;
19081ad6265SDimitry Andric
19181ad6265SDimitry Andric unsigned RC;
1925f757f3fSDimitry Andric const bool HasRC = Flag.hasRegClassConstraint(RC);
19381ad6265SDimitry Andric if ((!IsTiedToChangedOp && (!HasRC || RC != CSKY::GPRRegClassID)) ||
19481ad6265SDimitry Andric NumRegs != 2)
19581ad6265SDimitry Andric continue;
19681ad6265SDimitry Andric
19781ad6265SDimitry Andric assert((i + 2 < NumOps) && "Invalid number of operands in inline asm");
19881ad6265SDimitry Andric SDValue V0 = N->getOperand(i + 1);
19981ad6265SDimitry Andric SDValue V1 = N->getOperand(i + 2);
20081ad6265SDimitry Andric unsigned Reg0 = cast<RegisterSDNode>(V0)->getReg();
20181ad6265SDimitry Andric unsigned Reg1 = cast<RegisterSDNode>(V1)->getReg();
20281ad6265SDimitry Andric SDValue PairedReg;
20381ad6265SDimitry Andric MachineRegisterInfo &MRI = MF->getRegInfo();
20481ad6265SDimitry Andric
2055f757f3fSDimitry Andric if (Flag.isRegDefKind() || Flag.isRegDefEarlyClobberKind()) {
20681ad6265SDimitry Andric // Replace the two GPRs with 1 GPRPair and copy values from GPRPair to
20781ad6265SDimitry Andric // the original GPRs.
20881ad6265SDimitry Andric
20981ad6265SDimitry Andric Register GPVR = MRI.createVirtualRegister(&CSKY::GPRPairRegClass);
21081ad6265SDimitry Andric PairedReg = CurDAG->getRegister(GPVR, MVT::i64);
21181ad6265SDimitry Andric SDValue Chain = SDValue(N, 0);
21281ad6265SDimitry Andric
21381ad6265SDimitry Andric SDNode *GU = N->getGluedUser();
21481ad6265SDimitry Andric SDValue RegCopy =
21581ad6265SDimitry Andric CurDAG->getCopyFromReg(Chain, dl, GPVR, MVT::i64, Chain.getValue(1));
21681ad6265SDimitry Andric
21781ad6265SDimitry Andric // Extract values from a GPRPair reg and copy to the original GPR reg.
21881ad6265SDimitry Andric SDValue Sub0 =
21981ad6265SDimitry Andric CurDAG->getTargetExtractSubreg(CSKY::sub32_0, dl, MVT::i32, RegCopy);
22081ad6265SDimitry Andric SDValue Sub1 =
22181ad6265SDimitry Andric CurDAG->getTargetExtractSubreg(CSKY::sub32_32, dl, MVT::i32, RegCopy);
22281ad6265SDimitry Andric SDValue T0 =
22381ad6265SDimitry Andric CurDAG->getCopyToReg(Sub0, dl, Reg0, Sub0, RegCopy.getValue(1));
22481ad6265SDimitry Andric SDValue T1 = CurDAG->getCopyToReg(Sub1, dl, Reg1, Sub1, T0.getValue(1));
22581ad6265SDimitry Andric
22681ad6265SDimitry Andric // Update the original glue user.
22781ad6265SDimitry Andric std::vector<SDValue> Ops(GU->op_begin(), GU->op_end() - 1);
22881ad6265SDimitry Andric Ops.push_back(T1.getValue(1));
22981ad6265SDimitry Andric CurDAG->UpdateNodeOperands(GU, Ops);
23081ad6265SDimitry Andric } else {
2315f757f3fSDimitry Andric // For Kind == InlineAsm::Kind::RegUse, we first copy two GPRs into a
23281ad6265SDimitry Andric // GPRPair and then pass the GPRPair to the inline asm.
23381ad6265SDimitry Andric SDValue Chain = AsmNodeOperands[InlineAsm::Op_InputChain];
23481ad6265SDimitry Andric
23581ad6265SDimitry Andric // As REG_SEQ doesn't take RegisterSDNode, we copy them first.
23681ad6265SDimitry Andric SDValue T0 =
23781ad6265SDimitry Andric CurDAG->getCopyFromReg(Chain, dl, Reg0, MVT::i32, Chain.getValue(1));
23881ad6265SDimitry Andric SDValue T1 =
23981ad6265SDimitry Andric CurDAG->getCopyFromReg(Chain, dl, Reg1, MVT::i32, T0.getValue(1));
24081ad6265SDimitry Andric SDValue Pair = SDValue(createGPRPairNode(MVT::i64, T0, T1), 0);
24181ad6265SDimitry Andric
24281ad6265SDimitry Andric // Copy REG_SEQ into a GPRPair-typed VR and replace the original two
24381ad6265SDimitry Andric // i32 VRs of inline asm with it.
24481ad6265SDimitry Andric Register GPVR = MRI.createVirtualRegister(&CSKY::GPRPairRegClass);
24581ad6265SDimitry Andric PairedReg = CurDAG->getRegister(GPVR, MVT::i64);
24681ad6265SDimitry Andric Chain = CurDAG->getCopyToReg(T1, dl, GPVR, Pair, T1.getValue(1));
24781ad6265SDimitry Andric
24881ad6265SDimitry Andric AsmNodeOperands[InlineAsm::Op_InputChain] = Chain;
24981ad6265SDimitry Andric Glue = Chain.getValue(1);
25081ad6265SDimitry Andric }
25181ad6265SDimitry Andric
25281ad6265SDimitry Andric Changed = true;
25381ad6265SDimitry Andric
25481ad6265SDimitry Andric if (PairedReg.getNode()) {
25581ad6265SDimitry Andric OpChanged[OpChanged.size() - 1] = true;
2565f757f3fSDimitry Andric // TODO: maybe a setter for getNumOperandRegisters?
2575f757f3fSDimitry Andric Flag = InlineAsm::Flag(Flag.getKind(), 1 /* RegNum*/);
25881ad6265SDimitry Andric if (IsTiedToChangedOp)
2595f757f3fSDimitry Andric Flag.setMatchingOp(DefIdx);
26081ad6265SDimitry Andric else
2615f757f3fSDimitry Andric Flag.setRegClass(CSKY::GPRPairRegClassID);
26281ad6265SDimitry Andric // Replace the current flag.
26381ad6265SDimitry Andric AsmNodeOperands[AsmNodeOperands.size() - 1] =
26481ad6265SDimitry Andric CurDAG->getTargetConstant(Flag, dl, MVT::i32);
26581ad6265SDimitry Andric // Add the new register node and skip the original two GPRs.
26681ad6265SDimitry Andric AsmNodeOperands.push_back(PairedReg);
26781ad6265SDimitry Andric // Skip the next two GPRs.
26881ad6265SDimitry Andric i += 2;
26981ad6265SDimitry Andric }
27081ad6265SDimitry Andric }
27181ad6265SDimitry Andric
27281ad6265SDimitry Andric if (Glue.getNode())
27381ad6265SDimitry Andric AsmNodeOperands.push_back(Glue);
27481ad6265SDimitry Andric if (!Changed)
27581ad6265SDimitry Andric return false;
27681ad6265SDimitry Andric
27781ad6265SDimitry Andric SDValue New = CurDAG->getNode(N->getOpcode(), SDLoc(N),
27881ad6265SDimitry Andric CurDAG->getVTList(MVT::Other, MVT::Glue),
27981ad6265SDimitry Andric AsmNodeOperands);
28081ad6265SDimitry Andric New->setNodeId(-1);
28181ad6265SDimitry Andric ReplaceNode(N, New.getNode());
28281ad6265SDimitry Andric return true;
28381ad6265SDimitry Andric }
28481ad6265SDimitry Andric
selectBITCAST_TO_LOHI(SDNode * N)28581ad6265SDimitry Andric bool CSKYDAGToDAGISel::selectBITCAST_TO_LOHI(SDNode *N) {
28681ad6265SDimitry Andric SDLoc Dl(N);
28781ad6265SDimitry Andric auto VT = N->getValueType(0);
28881ad6265SDimitry Andric auto V = N->getOperand(0);
28981ad6265SDimitry Andric
29081ad6265SDimitry Andric if (!Subtarget->hasFPUv2DoubleFloat())
29181ad6265SDimitry Andric return false;
29281ad6265SDimitry Andric
29381ad6265SDimitry Andric SDValue V1 = SDValue(CurDAG->getMachineNode(CSKY::FMFVRL_D, Dl, VT, V), 0);
29481ad6265SDimitry Andric SDValue V2 = SDValue(CurDAG->getMachineNode(CSKY::FMFVRH_D, Dl, VT, V), 0);
29581ad6265SDimitry Andric
29681ad6265SDimitry Andric ReplaceUses(SDValue(N, 0), V1);
29781ad6265SDimitry Andric ReplaceUses(SDValue(N, 1), V2);
29881ad6265SDimitry Andric CurDAG->RemoveDeadNode(N);
29981ad6265SDimitry Andric
30081ad6265SDimitry Andric return true;
30181ad6265SDimitry Andric }
30281ad6265SDimitry Andric
selectAddCarry(SDNode * N)3030eae32dcSDimitry Andric bool CSKYDAGToDAGISel::selectAddCarry(SDNode *N) {
3040eae32dcSDimitry Andric MachineSDNode *NewNode = nullptr;
3050eae32dcSDimitry Andric auto Type0 = N->getValueType(0);
3060eae32dcSDimitry Andric auto Type1 = N->getValueType(1);
3070eae32dcSDimitry Andric auto Op0 = N->getOperand(0);
3080eae32dcSDimitry Andric auto Op1 = N->getOperand(1);
3090eae32dcSDimitry Andric auto Op2 = N->getOperand(2);
3100eae32dcSDimitry Andric
3110eae32dcSDimitry Andric SDLoc Dl(N);
3120eae32dcSDimitry Andric
3130eae32dcSDimitry Andric if (isNullConstant(Op2)) {
3140eae32dcSDimitry Andric auto *CA = CurDAG->getMachineNode(
3150eae32dcSDimitry Andric Subtarget->has2E3() ? CSKY::CLRC32 : CSKY::CLRC16, Dl, Type1);
3160eae32dcSDimitry Andric NewNode = CurDAG->getMachineNode(
3170eae32dcSDimitry Andric Subtarget->has2E3() ? CSKY::ADDC32 : CSKY::ADDC16, Dl, {Type0, Type1},
3180eae32dcSDimitry Andric {Op0, Op1, SDValue(CA, 0)});
3190eae32dcSDimitry Andric } else if (isOneConstant(Op2)) {
3200eae32dcSDimitry Andric auto *CA = CurDAG->getMachineNode(
3210eae32dcSDimitry Andric Subtarget->has2E3() ? CSKY::SETC32 : CSKY::SETC16, Dl, Type1);
3220eae32dcSDimitry Andric NewNode = CurDAG->getMachineNode(
3230eae32dcSDimitry Andric Subtarget->has2E3() ? CSKY::ADDC32 : CSKY::ADDC16, Dl, {Type0, Type1},
3240eae32dcSDimitry Andric {Op0, Op1, SDValue(CA, 0)});
3250eae32dcSDimitry Andric } else {
3260eae32dcSDimitry Andric NewNode = CurDAG->getMachineNode(Subtarget->has2E3() ? CSKY::ADDC32
3270eae32dcSDimitry Andric : CSKY::ADDC16,
3280eae32dcSDimitry Andric Dl, {Type0, Type1}, {Op0, Op1, Op2});
3290eae32dcSDimitry Andric }
3300eae32dcSDimitry Andric ReplaceNode(N, NewNode);
3310eae32dcSDimitry Andric return true;
3320eae32dcSDimitry Andric }
3330eae32dcSDimitry Andric
InvertCarryFlag(const CSKYSubtarget * Subtarget,SelectionDAG * DAG,SDLoc Dl,SDValue OldCarry)3340eae32dcSDimitry Andric static SDValue InvertCarryFlag(const CSKYSubtarget *Subtarget,
3350eae32dcSDimitry Andric SelectionDAG *DAG, SDLoc Dl, SDValue OldCarry) {
3360eae32dcSDimitry Andric auto NewCarryReg =
3370eae32dcSDimitry Andric DAG->getMachineNode(Subtarget->has2E3() ? CSKY::MVCV32 : CSKY::MVCV16, Dl,
3380eae32dcSDimitry Andric MVT::i32, OldCarry);
3390eae32dcSDimitry Andric auto NewCarry =
3400eae32dcSDimitry Andric DAG->getMachineNode(Subtarget->hasE2() ? CSKY::BTSTI32 : CSKY::BTSTI16,
3410eae32dcSDimitry Andric Dl, OldCarry.getValueType(), SDValue(NewCarryReg, 0),
3420eae32dcSDimitry Andric DAG->getTargetConstant(0, Dl, MVT::i32));
3430eae32dcSDimitry Andric return SDValue(NewCarry, 0);
3440eae32dcSDimitry Andric }
3450eae32dcSDimitry Andric
selectSubCarry(SDNode * N)3460eae32dcSDimitry Andric bool CSKYDAGToDAGISel::selectSubCarry(SDNode *N) {
3470eae32dcSDimitry Andric MachineSDNode *NewNode = nullptr;
3480eae32dcSDimitry Andric auto Type0 = N->getValueType(0);
3490eae32dcSDimitry Andric auto Type1 = N->getValueType(1);
3500eae32dcSDimitry Andric auto Op0 = N->getOperand(0);
3510eae32dcSDimitry Andric auto Op1 = N->getOperand(1);
3520eae32dcSDimitry Andric auto Op2 = N->getOperand(2);
3530eae32dcSDimitry Andric
3540eae32dcSDimitry Andric SDLoc Dl(N);
3550eae32dcSDimitry Andric
3560eae32dcSDimitry Andric if (isNullConstant(Op2)) {
3570eae32dcSDimitry Andric auto *CA = CurDAG->getMachineNode(
3580eae32dcSDimitry Andric Subtarget->has2E3() ? CSKY::SETC32 : CSKY::SETC16, Dl, Type1);
3590eae32dcSDimitry Andric NewNode = CurDAG->getMachineNode(
3600eae32dcSDimitry Andric Subtarget->has2E3() ? CSKY::SUBC32 : CSKY::SUBC16, Dl, {Type0, Type1},
3610eae32dcSDimitry Andric {Op0, Op1, SDValue(CA, 0)});
3620eae32dcSDimitry Andric } else if (isOneConstant(Op2)) {
3630eae32dcSDimitry Andric auto *CA = CurDAG->getMachineNode(
3640eae32dcSDimitry Andric Subtarget->has2E3() ? CSKY::CLRC32 : CSKY::CLRC16, Dl, Type1);
3650eae32dcSDimitry Andric NewNode = CurDAG->getMachineNode(
3660eae32dcSDimitry Andric Subtarget->has2E3() ? CSKY::SUBC32 : CSKY::SUBC16, Dl, {Type0, Type1},
3670eae32dcSDimitry Andric {Op0, Op1, SDValue(CA, 0)});
3680eae32dcSDimitry Andric } else {
3690eae32dcSDimitry Andric auto CarryIn = InvertCarryFlag(Subtarget, CurDAG, Dl, Op2);
3700eae32dcSDimitry Andric NewNode = CurDAG->getMachineNode(Subtarget->has2E3() ? CSKY::SUBC32
3710eae32dcSDimitry Andric : CSKY::SUBC16,
3720eae32dcSDimitry Andric Dl, {Type0, Type1}, {Op0, Op1, CarryIn});
3730eae32dcSDimitry Andric }
3740eae32dcSDimitry Andric auto CarryOut = InvertCarryFlag(Subtarget, CurDAG, Dl, SDValue(NewNode, 1));
3750eae32dcSDimitry Andric
3760eae32dcSDimitry Andric ReplaceUses(SDValue(N, 0), SDValue(NewNode, 0));
3770eae32dcSDimitry Andric ReplaceUses(SDValue(N, 1), CarryOut);
3780eae32dcSDimitry Andric CurDAG->RemoveDeadNode(N);
3790eae32dcSDimitry Andric
3800eae32dcSDimitry Andric return true;
3810eae32dcSDimitry Andric }
3820eae32dcSDimitry Andric
createGPRPairNode(EVT VT,SDValue V0,SDValue V1)38381ad6265SDimitry Andric SDNode *CSKYDAGToDAGISel::createGPRPairNode(EVT VT, SDValue V0, SDValue V1) {
38481ad6265SDimitry Andric SDLoc dl(V0.getNode());
38581ad6265SDimitry Andric SDValue RegClass =
38681ad6265SDimitry Andric CurDAG->getTargetConstant(CSKY::GPRPairRegClassID, dl, MVT::i32);
38781ad6265SDimitry Andric SDValue SubReg0 = CurDAG->getTargetConstant(CSKY::sub32_0, dl, MVT::i32);
38881ad6265SDimitry Andric SDValue SubReg1 = CurDAG->getTargetConstant(CSKY::sub32_32, dl, MVT::i32);
38981ad6265SDimitry Andric const SDValue Ops[] = {RegClass, V0, SubReg0, V1, SubReg1};
39081ad6265SDimitry Andric return CurDAG->getMachineNode(TargetOpcode::REG_SEQUENCE, dl, VT, Ops);
39181ad6265SDimitry Andric }
39281ad6265SDimitry Andric
SelectInlineAsmMemoryOperand(const SDValue & Op,const InlineAsm::ConstraintCode ConstraintID,std::vector<SDValue> & OutOps)39381ad6265SDimitry Andric bool CSKYDAGToDAGISel::SelectInlineAsmMemoryOperand(
3945f757f3fSDimitry Andric const SDValue &Op, const InlineAsm::ConstraintCode ConstraintID,
3955f757f3fSDimitry Andric std::vector<SDValue> &OutOps) {
39681ad6265SDimitry Andric switch (ConstraintID) {
3975f757f3fSDimitry Andric case InlineAsm::ConstraintCode::m:
39881ad6265SDimitry Andric // We just support simple memory operands that have a single address
39981ad6265SDimitry Andric // operand and need no special handling.
40081ad6265SDimitry Andric OutOps.push_back(Op);
40181ad6265SDimitry Andric return false;
40281ad6265SDimitry Andric default:
40381ad6265SDimitry Andric break;
40481ad6265SDimitry Andric }
40581ad6265SDimitry Andric
40681ad6265SDimitry Andric return true;
40781ad6265SDimitry Andric }
40881ad6265SDimitry Andric
createCSKYISelDag(CSKYTargetMachine & TM,CodeGenOptLevel OptLevel)409bdd1243dSDimitry Andric FunctionPass *llvm::createCSKYISelDag(CSKYTargetMachine &TM,
4105f757f3fSDimitry Andric CodeGenOptLevel OptLevel) {
411*0fca6ea1SDimitry Andric return new CSKYDAGToDAGISelLegacy(TM, OptLevel);
412349cc55cSDimitry Andric }
413