xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/CSKY/CSKYISelDAGToDAG.cpp (revision 81ad626541db97eb356e2c1d4a20eb2a26a766ab)
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"
17*81ad6265SDimitry 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"
24349cc55cSDimitry Andric 
25349cc55cSDimitry Andric namespace {
26349cc55cSDimitry Andric class CSKYDAGToDAGISel : public SelectionDAGISel {
27349cc55cSDimitry Andric   const CSKYSubtarget *Subtarget;
28349cc55cSDimitry Andric 
29349cc55cSDimitry Andric public:
30349cc55cSDimitry Andric   explicit CSKYDAGToDAGISel(CSKYTargetMachine &TM) : SelectionDAGISel(TM) {}
31349cc55cSDimitry Andric 
32349cc55cSDimitry Andric   StringRef getPassName() const override {
33349cc55cSDimitry Andric     return "CSKY DAG->DAG Pattern Instruction Selection";
34349cc55cSDimitry Andric   }
35349cc55cSDimitry Andric 
36349cc55cSDimitry Andric   bool runOnMachineFunction(MachineFunction &MF) override {
37349cc55cSDimitry Andric     // Reset the subtarget each time through.
38349cc55cSDimitry Andric     Subtarget = &MF.getSubtarget<CSKYSubtarget>();
39349cc55cSDimitry Andric     SelectionDAGISel::runOnMachineFunction(MF);
40349cc55cSDimitry Andric     return true;
41349cc55cSDimitry Andric   }
42349cc55cSDimitry Andric 
43349cc55cSDimitry Andric   void Select(SDNode *N) override;
440eae32dcSDimitry Andric   bool selectAddCarry(SDNode *N);
450eae32dcSDimitry Andric   bool selectSubCarry(SDNode *N);
46*81ad6265SDimitry Andric   bool selectBITCAST_TO_LOHI(SDNode *N);
47*81ad6265SDimitry Andric   bool selectInlineAsm(SDNode *N);
48*81ad6265SDimitry Andric 
49*81ad6265SDimitry Andric   SDNode *createGPRPairNode(EVT VT, SDValue V0, SDValue V1);
50*81ad6265SDimitry Andric 
51*81ad6265SDimitry Andric   bool SelectInlineAsmMemoryOperand(const SDValue &Op, unsigned ConstraintID,
52*81ad6265SDimitry Andric                                     std::vector<SDValue> &OutOps) override;
53349cc55cSDimitry Andric 
54349cc55cSDimitry Andric #include "CSKYGenDAGISel.inc"
55349cc55cSDimitry Andric };
56349cc55cSDimitry Andric } // namespace
57349cc55cSDimitry Andric 
58349cc55cSDimitry Andric void CSKYDAGToDAGISel::Select(SDNode *N) {
59349cc55cSDimitry Andric   // If we have a custom node, we have already selected
60349cc55cSDimitry Andric   if (N->isMachineOpcode()) {
61349cc55cSDimitry Andric     LLVM_DEBUG(dbgs() << "== "; N->dump(CurDAG); dbgs() << "\n");
62349cc55cSDimitry Andric     N->setNodeId(-1);
63349cc55cSDimitry Andric     return;
64349cc55cSDimitry Andric   }
65349cc55cSDimitry Andric 
66349cc55cSDimitry Andric   SDLoc Dl(N);
67349cc55cSDimitry Andric   unsigned Opcode = N->getOpcode();
68349cc55cSDimitry Andric   bool IsSelected = false;
69349cc55cSDimitry Andric 
70349cc55cSDimitry Andric   switch (Opcode) {
71349cc55cSDimitry Andric   default:
72349cc55cSDimitry Andric     break;
730eae32dcSDimitry Andric   case ISD::ADDCARRY:
740eae32dcSDimitry Andric     IsSelected = selectAddCarry(N);
750eae32dcSDimitry Andric     break;
760eae32dcSDimitry Andric   case ISD::SUBCARRY:
770eae32dcSDimitry Andric     IsSelected = selectSubCarry(N);
780eae32dcSDimitry Andric     break;
7904eeddc0SDimitry Andric   case ISD::GLOBAL_OFFSET_TABLE: {
8004eeddc0SDimitry Andric     Register GP = Subtarget->getInstrInfo()->getGlobalBaseReg(*MF);
8104eeddc0SDimitry Andric     ReplaceNode(N, CurDAG->getRegister(GP, N->getValueType(0)).getNode());
8204eeddc0SDimitry Andric 
8304eeddc0SDimitry Andric     IsSelected = true;
8404eeddc0SDimitry Andric     break;
8504eeddc0SDimitry Andric   }
8604eeddc0SDimitry Andric   case ISD::FrameIndex: {
8704eeddc0SDimitry Andric     SDValue Imm = CurDAG->getTargetConstant(0, Dl, MVT::i32);
8804eeddc0SDimitry Andric     int FI = cast<FrameIndexSDNode>(N)->getIndex();
8904eeddc0SDimitry Andric     SDValue TFI = CurDAG->getTargetFrameIndex(FI, MVT::i32);
9004eeddc0SDimitry Andric     ReplaceNode(N, CurDAG->getMachineNode(Subtarget->hasE2() ? CSKY::ADDI32
9104eeddc0SDimitry Andric                                                              : CSKY::ADDI16XZ,
9204eeddc0SDimitry Andric                                           Dl, MVT::i32, TFI, Imm));
9304eeddc0SDimitry Andric 
9404eeddc0SDimitry Andric     IsSelected = true;
9504eeddc0SDimitry Andric     break;
9604eeddc0SDimitry Andric   }
97*81ad6265SDimitry Andric   case CSKYISD::BITCAST_TO_LOHI:
98*81ad6265SDimitry Andric     IsSelected = selectBITCAST_TO_LOHI(N);
99*81ad6265SDimitry Andric     break;
100*81ad6265SDimitry Andric   case ISD::INLINEASM:
101*81ad6265SDimitry Andric   case ISD::INLINEASM_BR:
102*81ad6265SDimitry Andric     IsSelected = selectInlineAsm(N);
103*81ad6265SDimitry Andric     break;
104349cc55cSDimitry Andric   }
105349cc55cSDimitry Andric 
106349cc55cSDimitry Andric   if (IsSelected)
107349cc55cSDimitry Andric     return;
108349cc55cSDimitry Andric 
109349cc55cSDimitry Andric   // Select the default instruction.
110349cc55cSDimitry Andric   SelectCode(N);
111349cc55cSDimitry Andric }
112349cc55cSDimitry Andric 
113*81ad6265SDimitry Andric bool CSKYDAGToDAGISel::selectInlineAsm(SDNode *N) {
114*81ad6265SDimitry Andric   std::vector<SDValue> AsmNodeOperands;
115*81ad6265SDimitry Andric   unsigned Flag, Kind;
116*81ad6265SDimitry Andric   bool Changed = false;
117*81ad6265SDimitry Andric   unsigned NumOps = N->getNumOperands();
118*81ad6265SDimitry Andric 
119*81ad6265SDimitry Andric   // Normally, i64 data is bounded to two arbitrary GRPs for "%r" constraint.
120*81ad6265SDimitry Andric   // However, some instructions (e.g. mula.s32) require GPR pair.
121*81ad6265SDimitry Andric   // Since there is no constraint to explicitly specify a
122*81ad6265SDimitry Andric   // reg pair, we use GPRPair reg class for "%r" for 64-bit data.
123*81ad6265SDimitry Andric 
124*81ad6265SDimitry Andric   SDLoc dl(N);
125*81ad6265SDimitry Andric   SDValue Glue =
126*81ad6265SDimitry Andric       N->getGluedNode() ? N->getOperand(NumOps - 1) : SDValue(nullptr, 0);
127*81ad6265SDimitry Andric 
128*81ad6265SDimitry Andric   SmallVector<bool, 8> OpChanged;
129*81ad6265SDimitry Andric   // Glue node will be appended late.
130*81ad6265SDimitry Andric   for (unsigned i = 0, e = N->getGluedNode() ? NumOps - 1 : NumOps; i < e;
131*81ad6265SDimitry Andric        ++i) {
132*81ad6265SDimitry Andric     SDValue op = N->getOperand(i);
133*81ad6265SDimitry Andric     AsmNodeOperands.push_back(op);
134*81ad6265SDimitry Andric 
135*81ad6265SDimitry Andric     if (i < InlineAsm::Op_FirstOperand)
136*81ad6265SDimitry Andric       continue;
137*81ad6265SDimitry Andric 
138*81ad6265SDimitry Andric     if (ConstantSDNode *C = dyn_cast<ConstantSDNode>(N->getOperand(i))) {
139*81ad6265SDimitry Andric       Flag = C->getZExtValue();
140*81ad6265SDimitry Andric       Kind = InlineAsm::getKind(Flag);
141*81ad6265SDimitry Andric     } else
142*81ad6265SDimitry Andric       continue;
143*81ad6265SDimitry Andric 
144*81ad6265SDimitry Andric     // Immediate operands to inline asm in the SelectionDAG are modeled with
145*81ad6265SDimitry Andric     // two operands. The first is a constant of value InlineAsm::Kind_Imm, and
146*81ad6265SDimitry Andric     // the second is a constant with the value of the immediate. If we get here
147*81ad6265SDimitry Andric     // and we have a Kind_Imm, skip the next operand, and continue.
148*81ad6265SDimitry Andric     if (Kind == InlineAsm::Kind_Imm) {
149*81ad6265SDimitry Andric       SDValue op = N->getOperand(++i);
150*81ad6265SDimitry Andric       AsmNodeOperands.push_back(op);
151*81ad6265SDimitry Andric       continue;
152*81ad6265SDimitry Andric     }
153*81ad6265SDimitry Andric 
154*81ad6265SDimitry Andric     unsigned NumRegs = InlineAsm::getNumOperandRegisters(Flag);
155*81ad6265SDimitry Andric     if (NumRegs)
156*81ad6265SDimitry Andric       OpChanged.push_back(false);
157*81ad6265SDimitry Andric 
158*81ad6265SDimitry Andric     unsigned DefIdx = 0;
159*81ad6265SDimitry Andric     bool IsTiedToChangedOp = false;
160*81ad6265SDimitry Andric     // If it's a use that is tied with a previous def, it has no
161*81ad6265SDimitry Andric     // reg class constraint.
162*81ad6265SDimitry Andric     if (Changed && InlineAsm::isUseOperandTiedToDef(Flag, DefIdx))
163*81ad6265SDimitry Andric       IsTiedToChangedOp = OpChanged[DefIdx];
164*81ad6265SDimitry Andric 
165*81ad6265SDimitry Andric     // Memory operands to inline asm in the SelectionDAG are modeled with two
166*81ad6265SDimitry Andric     // operands: a constant of value InlineAsm::Kind_Mem followed by the input
167*81ad6265SDimitry Andric     // operand. If we get here and we have a Kind_Mem, skip the next operand (so
168*81ad6265SDimitry Andric     // it doesn't get misinterpreted), and continue. We do this here because
169*81ad6265SDimitry Andric     // it's important to update the OpChanged array correctly before moving on.
170*81ad6265SDimitry Andric     if (Kind == InlineAsm::Kind_Mem) {
171*81ad6265SDimitry Andric       SDValue op = N->getOperand(++i);
172*81ad6265SDimitry Andric       AsmNodeOperands.push_back(op);
173*81ad6265SDimitry Andric       continue;
174*81ad6265SDimitry Andric     }
175*81ad6265SDimitry Andric 
176*81ad6265SDimitry Andric     if (Kind != InlineAsm::Kind_RegUse && Kind != InlineAsm::Kind_RegDef &&
177*81ad6265SDimitry Andric         Kind != InlineAsm::Kind_RegDefEarlyClobber)
178*81ad6265SDimitry Andric       continue;
179*81ad6265SDimitry Andric 
180*81ad6265SDimitry Andric     unsigned RC;
181*81ad6265SDimitry Andric     bool HasRC = InlineAsm::hasRegClassConstraint(Flag, RC);
182*81ad6265SDimitry Andric     if ((!IsTiedToChangedOp && (!HasRC || RC != CSKY::GPRRegClassID)) ||
183*81ad6265SDimitry Andric         NumRegs != 2)
184*81ad6265SDimitry Andric       continue;
185*81ad6265SDimitry Andric 
186*81ad6265SDimitry Andric     assert((i + 2 < NumOps) && "Invalid number of operands in inline asm");
187*81ad6265SDimitry Andric     SDValue V0 = N->getOperand(i + 1);
188*81ad6265SDimitry Andric     SDValue V1 = N->getOperand(i + 2);
189*81ad6265SDimitry Andric     unsigned Reg0 = cast<RegisterSDNode>(V0)->getReg();
190*81ad6265SDimitry Andric     unsigned Reg1 = cast<RegisterSDNode>(V1)->getReg();
191*81ad6265SDimitry Andric     SDValue PairedReg;
192*81ad6265SDimitry Andric     MachineRegisterInfo &MRI = MF->getRegInfo();
193*81ad6265SDimitry Andric 
194*81ad6265SDimitry Andric     if (Kind == InlineAsm::Kind_RegDef ||
195*81ad6265SDimitry Andric         Kind == InlineAsm::Kind_RegDefEarlyClobber) {
196*81ad6265SDimitry Andric       // Replace the two GPRs with 1 GPRPair and copy values from GPRPair to
197*81ad6265SDimitry Andric       // the original GPRs.
198*81ad6265SDimitry Andric 
199*81ad6265SDimitry Andric       Register GPVR = MRI.createVirtualRegister(&CSKY::GPRPairRegClass);
200*81ad6265SDimitry Andric       PairedReg = CurDAG->getRegister(GPVR, MVT::i64);
201*81ad6265SDimitry Andric       SDValue Chain = SDValue(N, 0);
202*81ad6265SDimitry Andric 
203*81ad6265SDimitry Andric       SDNode *GU = N->getGluedUser();
204*81ad6265SDimitry Andric       SDValue RegCopy =
205*81ad6265SDimitry Andric           CurDAG->getCopyFromReg(Chain, dl, GPVR, MVT::i64, Chain.getValue(1));
206*81ad6265SDimitry Andric 
207*81ad6265SDimitry Andric       // Extract values from a GPRPair reg and copy to the original GPR reg.
208*81ad6265SDimitry Andric       SDValue Sub0 =
209*81ad6265SDimitry Andric           CurDAG->getTargetExtractSubreg(CSKY::sub32_0, dl, MVT::i32, RegCopy);
210*81ad6265SDimitry Andric       SDValue Sub1 =
211*81ad6265SDimitry Andric           CurDAG->getTargetExtractSubreg(CSKY::sub32_32, dl, MVT::i32, RegCopy);
212*81ad6265SDimitry Andric       SDValue T0 =
213*81ad6265SDimitry Andric           CurDAG->getCopyToReg(Sub0, dl, Reg0, Sub0, RegCopy.getValue(1));
214*81ad6265SDimitry Andric       SDValue T1 = CurDAG->getCopyToReg(Sub1, dl, Reg1, Sub1, T0.getValue(1));
215*81ad6265SDimitry Andric 
216*81ad6265SDimitry Andric       // Update the original glue user.
217*81ad6265SDimitry Andric       std::vector<SDValue> Ops(GU->op_begin(), GU->op_end() - 1);
218*81ad6265SDimitry Andric       Ops.push_back(T1.getValue(1));
219*81ad6265SDimitry Andric       CurDAG->UpdateNodeOperands(GU, Ops);
220*81ad6265SDimitry Andric     } else {
221*81ad6265SDimitry Andric       // For Kind  == InlineAsm::Kind_RegUse, we first copy two GPRs into a
222*81ad6265SDimitry Andric       // GPRPair and then pass the GPRPair to the inline asm.
223*81ad6265SDimitry Andric       SDValue Chain = AsmNodeOperands[InlineAsm::Op_InputChain];
224*81ad6265SDimitry Andric 
225*81ad6265SDimitry Andric       // As REG_SEQ doesn't take RegisterSDNode, we copy them first.
226*81ad6265SDimitry Andric       SDValue T0 =
227*81ad6265SDimitry Andric           CurDAG->getCopyFromReg(Chain, dl, Reg0, MVT::i32, Chain.getValue(1));
228*81ad6265SDimitry Andric       SDValue T1 =
229*81ad6265SDimitry Andric           CurDAG->getCopyFromReg(Chain, dl, Reg1, MVT::i32, T0.getValue(1));
230*81ad6265SDimitry Andric       SDValue Pair = SDValue(createGPRPairNode(MVT::i64, T0, T1), 0);
231*81ad6265SDimitry Andric 
232*81ad6265SDimitry Andric       // Copy REG_SEQ into a GPRPair-typed VR and replace the original two
233*81ad6265SDimitry Andric       // i32 VRs of inline asm with it.
234*81ad6265SDimitry Andric       Register GPVR = MRI.createVirtualRegister(&CSKY::GPRPairRegClass);
235*81ad6265SDimitry Andric       PairedReg = CurDAG->getRegister(GPVR, MVT::i64);
236*81ad6265SDimitry Andric       Chain = CurDAG->getCopyToReg(T1, dl, GPVR, Pair, T1.getValue(1));
237*81ad6265SDimitry Andric 
238*81ad6265SDimitry Andric       AsmNodeOperands[InlineAsm::Op_InputChain] = Chain;
239*81ad6265SDimitry Andric       Glue = Chain.getValue(1);
240*81ad6265SDimitry Andric     }
241*81ad6265SDimitry Andric 
242*81ad6265SDimitry Andric     Changed = true;
243*81ad6265SDimitry Andric 
244*81ad6265SDimitry Andric     if (PairedReg.getNode()) {
245*81ad6265SDimitry Andric       OpChanged[OpChanged.size() - 1] = true;
246*81ad6265SDimitry Andric       Flag = InlineAsm::getFlagWord(Kind, 1 /* RegNum*/);
247*81ad6265SDimitry Andric       if (IsTiedToChangedOp)
248*81ad6265SDimitry Andric         Flag = InlineAsm::getFlagWordForMatchingOp(Flag, DefIdx);
249*81ad6265SDimitry Andric       else
250*81ad6265SDimitry Andric         Flag = InlineAsm::getFlagWordForRegClass(Flag, CSKY::GPRPairRegClassID);
251*81ad6265SDimitry Andric       // Replace the current flag.
252*81ad6265SDimitry Andric       AsmNodeOperands[AsmNodeOperands.size() - 1] =
253*81ad6265SDimitry Andric           CurDAG->getTargetConstant(Flag, dl, MVT::i32);
254*81ad6265SDimitry Andric       // Add the new register node and skip the original two GPRs.
255*81ad6265SDimitry Andric       AsmNodeOperands.push_back(PairedReg);
256*81ad6265SDimitry Andric       // Skip the next two GPRs.
257*81ad6265SDimitry Andric       i += 2;
258*81ad6265SDimitry Andric     }
259*81ad6265SDimitry Andric   }
260*81ad6265SDimitry Andric 
261*81ad6265SDimitry Andric   if (Glue.getNode())
262*81ad6265SDimitry Andric     AsmNodeOperands.push_back(Glue);
263*81ad6265SDimitry Andric   if (!Changed)
264*81ad6265SDimitry Andric     return false;
265*81ad6265SDimitry Andric 
266*81ad6265SDimitry Andric   SDValue New = CurDAG->getNode(N->getOpcode(), SDLoc(N),
267*81ad6265SDimitry Andric                                 CurDAG->getVTList(MVT::Other, MVT::Glue),
268*81ad6265SDimitry Andric                                 AsmNodeOperands);
269*81ad6265SDimitry Andric   New->setNodeId(-1);
270*81ad6265SDimitry Andric   ReplaceNode(N, New.getNode());
271*81ad6265SDimitry Andric   return true;
272*81ad6265SDimitry Andric }
273*81ad6265SDimitry Andric 
274*81ad6265SDimitry Andric bool CSKYDAGToDAGISel::selectBITCAST_TO_LOHI(SDNode *N) {
275*81ad6265SDimitry Andric   SDLoc Dl(N);
276*81ad6265SDimitry Andric   auto VT = N->getValueType(0);
277*81ad6265SDimitry Andric   auto V = N->getOperand(0);
278*81ad6265SDimitry Andric 
279*81ad6265SDimitry Andric   if (!Subtarget->hasFPUv2DoubleFloat())
280*81ad6265SDimitry Andric     return false;
281*81ad6265SDimitry Andric 
282*81ad6265SDimitry Andric   SDValue V1 = SDValue(CurDAG->getMachineNode(CSKY::FMFVRL_D, Dl, VT, V), 0);
283*81ad6265SDimitry Andric   SDValue V2 = SDValue(CurDAG->getMachineNode(CSKY::FMFVRH_D, Dl, VT, V), 0);
284*81ad6265SDimitry Andric 
285*81ad6265SDimitry Andric   ReplaceUses(SDValue(N, 0), V1);
286*81ad6265SDimitry Andric   ReplaceUses(SDValue(N, 1), V2);
287*81ad6265SDimitry Andric   CurDAG->RemoveDeadNode(N);
288*81ad6265SDimitry Andric 
289*81ad6265SDimitry Andric   return true;
290*81ad6265SDimitry Andric }
291*81ad6265SDimitry Andric 
2920eae32dcSDimitry Andric bool CSKYDAGToDAGISel::selectAddCarry(SDNode *N) {
2930eae32dcSDimitry Andric   MachineSDNode *NewNode = nullptr;
2940eae32dcSDimitry Andric   auto Type0 = N->getValueType(0);
2950eae32dcSDimitry Andric   auto Type1 = N->getValueType(1);
2960eae32dcSDimitry Andric   auto Op0 = N->getOperand(0);
2970eae32dcSDimitry Andric   auto Op1 = N->getOperand(1);
2980eae32dcSDimitry Andric   auto Op2 = N->getOperand(2);
2990eae32dcSDimitry Andric 
3000eae32dcSDimitry Andric   SDLoc Dl(N);
3010eae32dcSDimitry Andric 
3020eae32dcSDimitry Andric   if (isNullConstant(Op2)) {
3030eae32dcSDimitry Andric     auto *CA = CurDAG->getMachineNode(
3040eae32dcSDimitry Andric         Subtarget->has2E3() ? CSKY::CLRC32 : CSKY::CLRC16, Dl, Type1);
3050eae32dcSDimitry Andric     NewNode = CurDAG->getMachineNode(
3060eae32dcSDimitry Andric         Subtarget->has2E3() ? CSKY::ADDC32 : CSKY::ADDC16, Dl, {Type0, Type1},
3070eae32dcSDimitry Andric         {Op0, Op1, SDValue(CA, 0)});
3080eae32dcSDimitry Andric   } else if (isOneConstant(Op2)) {
3090eae32dcSDimitry Andric     auto *CA = CurDAG->getMachineNode(
3100eae32dcSDimitry Andric         Subtarget->has2E3() ? CSKY::SETC32 : CSKY::SETC16, Dl, Type1);
3110eae32dcSDimitry Andric     NewNode = CurDAG->getMachineNode(
3120eae32dcSDimitry Andric         Subtarget->has2E3() ? CSKY::ADDC32 : CSKY::ADDC16, Dl, {Type0, Type1},
3130eae32dcSDimitry Andric         {Op0, Op1, SDValue(CA, 0)});
3140eae32dcSDimitry Andric   } else {
3150eae32dcSDimitry Andric     NewNode = CurDAG->getMachineNode(Subtarget->has2E3() ? CSKY::ADDC32
3160eae32dcSDimitry Andric                                                          : CSKY::ADDC16,
3170eae32dcSDimitry Andric                                      Dl, {Type0, Type1}, {Op0, Op1, Op2});
3180eae32dcSDimitry Andric   }
3190eae32dcSDimitry Andric   ReplaceNode(N, NewNode);
3200eae32dcSDimitry Andric   return true;
3210eae32dcSDimitry Andric }
3220eae32dcSDimitry Andric 
3230eae32dcSDimitry Andric static SDValue InvertCarryFlag(const CSKYSubtarget *Subtarget,
3240eae32dcSDimitry Andric                                SelectionDAG *DAG, SDLoc Dl, SDValue OldCarry) {
3250eae32dcSDimitry Andric   auto NewCarryReg =
3260eae32dcSDimitry Andric       DAG->getMachineNode(Subtarget->has2E3() ? CSKY::MVCV32 : CSKY::MVCV16, Dl,
3270eae32dcSDimitry Andric                           MVT::i32, OldCarry);
3280eae32dcSDimitry Andric   auto NewCarry =
3290eae32dcSDimitry Andric       DAG->getMachineNode(Subtarget->hasE2() ? CSKY::BTSTI32 : CSKY::BTSTI16,
3300eae32dcSDimitry Andric                           Dl, OldCarry.getValueType(), SDValue(NewCarryReg, 0),
3310eae32dcSDimitry Andric                           DAG->getTargetConstant(0, Dl, MVT::i32));
3320eae32dcSDimitry Andric   return SDValue(NewCarry, 0);
3330eae32dcSDimitry Andric }
3340eae32dcSDimitry Andric 
3350eae32dcSDimitry Andric bool CSKYDAGToDAGISel::selectSubCarry(SDNode *N) {
3360eae32dcSDimitry Andric   MachineSDNode *NewNode = nullptr;
3370eae32dcSDimitry Andric   auto Type0 = N->getValueType(0);
3380eae32dcSDimitry Andric   auto Type1 = N->getValueType(1);
3390eae32dcSDimitry Andric   auto Op0 = N->getOperand(0);
3400eae32dcSDimitry Andric   auto Op1 = N->getOperand(1);
3410eae32dcSDimitry Andric   auto Op2 = N->getOperand(2);
3420eae32dcSDimitry Andric 
3430eae32dcSDimitry Andric   SDLoc Dl(N);
3440eae32dcSDimitry Andric 
3450eae32dcSDimitry Andric   if (isNullConstant(Op2)) {
3460eae32dcSDimitry Andric     auto *CA = CurDAG->getMachineNode(
3470eae32dcSDimitry Andric         Subtarget->has2E3() ? CSKY::SETC32 : CSKY::SETC16, Dl, Type1);
3480eae32dcSDimitry Andric     NewNode = CurDAG->getMachineNode(
3490eae32dcSDimitry Andric         Subtarget->has2E3() ? CSKY::SUBC32 : CSKY::SUBC16, Dl, {Type0, Type1},
3500eae32dcSDimitry Andric         {Op0, Op1, SDValue(CA, 0)});
3510eae32dcSDimitry Andric   } else if (isOneConstant(Op2)) {
3520eae32dcSDimitry Andric     auto *CA = CurDAG->getMachineNode(
3530eae32dcSDimitry Andric         Subtarget->has2E3() ? CSKY::CLRC32 : CSKY::CLRC16, Dl, Type1);
3540eae32dcSDimitry Andric     NewNode = CurDAG->getMachineNode(
3550eae32dcSDimitry Andric         Subtarget->has2E3() ? CSKY::SUBC32 : CSKY::SUBC16, Dl, {Type0, Type1},
3560eae32dcSDimitry Andric         {Op0, Op1, SDValue(CA, 0)});
3570eae32dcSDimitry Andric   } else {
3580eae32dcSDimitry Andric     auto CarryIn = InvertCarryFlag(Subtarget, CurDAG, Dl, Op2);
3590eae32dcSDimitry Andric     NewNode = CurDAG->getMachineNode(Subtarget->has2E3() ? CSKY::SUBC32
3600eae32dcSDimitry Andric                                                          : CSKY::SUBC16,
3610eae32dcSDimitry Andric                                      Dl, {Type0, Type1}, {Op0, Op1, CarryIn});
3620eae32dcSDimitry Andric   }
3630eae32dcSDimitry Andric   auto CarryOut = InvertCarryFlag(Subtarget, CurDAG, Dl, SDValue(NewNode, 1));
3640eae32dcSDimitry Andric 
3650eae32dcSDimitry Andric   ReplaceUses(SDValue(N, 0), SDValue(NewNode, 0));
3660eae32dcSDimitry Andric   ReplaceUses(SDValue(N, 1), CarryOut);
3670eae32dcSDimitry Andric   CurDAG->RemoveDeadNode(N);
3680eae32dcSDimitry Andric 
3690eae32dcSDimitry Andric   return true;
3700eae32dcSDimitry Andric }
3710eae32dcSDimitry Andric 
372*81ad6265SDimitry Andric SDNode *CSKYDAGToDAGISel::createGPRPairNode(EVT VT, SDValue V0, SDValue V1) {
373*81ad6265SDimitry Andric   SDLoc dl(V0.getNode());
374*81ad6265SDimitry Andric   SDValue RegClass =
375*81ad6265SDimitry Andric       CurDAG->getTargetConstant(CSKY::GPRPairRegClassID, dl, MVT::i32);
376*81ad6265SDimitry Andric   SDValue SubReg0 = CurDAG->getTargetConstant(CSKY::sub32_0, dl, MVT::i32);
377*81ad6265SDimitry Andric   SDValue SubReg1 = CurDAG->getTargetConstant(CSKY::sub32_32, dl, MVT::i32);
378*81ad6265SDimitry Andric   const SDValue Ops[] = {RegClass, V0, SubReg0, V1, SubReg1};
379*81ad6265SDimitry Andric   return CurDAG->getMachineNode(TargetOpcode::REG_SEQUENCE, dl, VT, Ops);
380*81ad6265SDimitry Andric }
381*81ad6265SDimitry Andric 
382*81ad6265SDimitry Andric bool CSKYDAGToDAGISel::SelectInlineAsmMemoryOperand(
383*81ad6265SDimitry Andric     const SDValue &Op, unsigned ConstraintID, std::vector<SDValue> &OutOps) {
384*81ad6265SDimitry Andric   switch (ConstraintID) {
385*81ad6265SDimitry Andric   case InlineAsm::Constraint_m:
386*81ad6265SDimitry Andric     // We just support simple memory operands that have a single address
387*81ad6265SDimitry Andric     // operand and need no special handling.
388*81ad6265SDimitry Andric     OutOps.push_back(Op);
389*81ad6265SDimitry Andric     return false;
390*81ad6265SDimitry Andric   default:
391*81ad6265SDimitry Andric     break;
392*81ad6265SDimitry Andric   }
393*81ad6265SDimitry Andric 
394*81ad6265SDimitry Andric   return true;
395*81ad6265SDimitry Andric }
396*81ad6265SDimitry Andric 
397349cc55cSDimitry Andric FunctionPass *llvm::createCSKYISelDag(CSKYTargetMachine &TM) {
398349cc55cSDimitry Andric   return new CSKYDAGToDAGISel(TM);
399349cc55cSDimitry Andric }
400