1 //===-- CSKYISelDAGToDAG.cpp - A dag to dag inst selector for CSKY---------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file defines an instruction selector for the CSKY target.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #include "CSKY.h"
14 #include "CSKYSubtarget.h"
15 #include "CSKYTargetMachine.h"
16 #include "MCTargetDesc/CSKYMCTargetDesc.h"
17 #include "llvm/CodeGen/SelectionDAG.h"
18 #include "llvm/CodeGen/SelectionDAGISel.h"
19 
20 using namespace llvm;
21 
22 #define DEBUG_TYPE "csky-isel"
23 
24 namespace {
25 class CSKYDAGToDAGISel : public SelectionDAGISel {
26   const CSKYSubtarget *Subtarget;
27 
28 public:
29   explicit CSKYDAGToDAGISel(CSKYTargetMachine &TM) : SelectionDAGISel(TM) {}
30 
31   StringRef getPassName() const override {
32     return "CSKY DAG->DAG Pattern Instruction Selection";
33   }
34 
35   bool runOnMachineFunction(MachineFunction &MF) override {
36     // Reset the subtarget each time through.
37     Subtarget = &MF.getSubtarget<CSKYSubtarget>();
38     SelectionDAGISel::runOnMachineFunction(MF);
39     return true;
40   }
41 
42   void Select(SDNode *N) override;
43   bool selectAddCarry(SDNode *N);
44   bool selectSubCarry(SDNode *N);
45   bool selectInlineAsm(SDNode *N);
46 
47   SDNode *createGPRPairNode(EVT VT, SDValue V0, SDValue V1);
48 
49   bool SelectInlineAsmMemoryOperand(const SDValue &Op, unsigned ConstraintID,
50                                     std::vector<SDValue> &OutOps) override;
51 
52 #include "CSKYGenDAGISel.inc"
53 };
54 } // namespace
55 
56 void CSKYDAGToDAGISel::Select(SDNode *N) {
57   // If we have a custom node, we have already selected
58   if (N->isMachineOpcode()) {
59     LLVM_DEBUG(dbgs() << "== "; N->dump(CurDAG); dbgs() << "\n");
60     N->setNodeId(-1);
61     return;
62   }
63 
64   SDLoc Dl(N);
65   unsigned Opcode = N->getOpcode();
66   bool IsSelected = false;
67 
68   switch (Opcode) {
69   default:
70     break;
71   case ISD::ADDCARRY:
72     IsSelected = selectAddCarry(N);
73     break;
74   case ISD::SUBCARRY:
75     IsSelected = selectSubCarry(N);
76     break;
77   case ISD::GLOBAL_OFFSET_TABLE: {
78     Register GP = Subtarget->getInstrInfo()->getGlobalBaseReg(*MF);
79     ReplaceNode(N, CurDAG->getRegister(GP, N->getValueType(0)).getNode());
80 
81     IsSelected = true;
82     break;
83   }
84   case ISD::FrameIndex: {
85     SDValue Imm = CurDAG->getTargetConstant(0, Dl, MVT::i32);
86     int FI = cast<FrameIndexSDNode>(N)->getIndex();
87     SDValue TFI = CurDAG->getTargetFrameIndex(FI, MVT::i32);
88     ReplaceNode(N, CurDAG->getMachineNode(Subtarget->hasE2() ? CSKY::ADDI32
89                                                              : CSKY::ADDI16XZ,
90                                           Dl, MVT::i32, TFI, Imm));
91 
92     IsSelected = true;
93     break;
94   }
95   case ISD::INLINEASM:
96   case ISD::INLINEASM_BR:
97     IsSelected = selectInlineAsm(N);
98     break;
99   }
100 
101   if (IsSelected)
102     return;
103 
104   // Select the default instruction.
105   SelectCode(N);
106 }
107 
108 bool CSKYDAGToDAGISel::selectInlineAsm(SDNode *N) {
109   std::vector<SDValue> AsmNodeOperands;
110   unsigned Flag, Kind;
111   bool Changed = false;
112   unsigned NumOps = N->getNumOperands();
113 
114   // Normally, i64 data is bounded to two arbitrary GRPs for "%r" constraint.
115   // However, some instructions (e.g. mula.s32) require GPR pair.
116   // Since there is no constraint to explicitly specify a
117   // reg pair, we use GPRPair reg class for "%r" for 64-bit data.
118 
119   SDLoc dl(N);
120   SDValue Glue =
121       N->getGluedNode() ? N->getOperand(NumOps - 1) : SDValue(nullptr, 0);
122 
123   SmallVector<bool, 8> OpChanged;
124   // Glue node will be appended late.
125   for (unsigned i = 0, e = N->getGluedNode() ? NumOps - 1 : NumOps; i < e;
126        ++i) {
127     SDValue op = N->getOperand(i);
128     AsmNodeOperands.push_back(op);
129 
130     if (i < InlineAsm::Op_FirstOperand)
131       continue;
132 
133     if (ConstantSDNode *C = dyn_cast<ConstantSDNode>(N->getOperand(i))) {
134       Flag = C->getZExtValue();
135       Kind = InlineAsm::getKind(Flag);
136     } else
137       continue;
138 
139     // Immediate operands to inline asm in the SelectionDAG are modeled with
140     // two operands. The first is a constant of value InlineAsm::Kind_Imm, and
141     // the second is a constant with the value of the immediate. If we get here
142     // and we have a Kind_Imm, skip the next operand, and continue.
143     if (Kind == InlineAsm::Kind_Imm) {
144       SDValue op = N->getOperand(++i);
145       AsmNodeOperands.push_back(op);
146       continue;
147     }
148 
149     unsigned NumRegs = InlineAsm::getNumOperandRegisters(Flag);
150     if (NumRegs)
151       OpChanged.push_back(false);
152 
153     unsigned DefIdx = 0;
154     bool IsTiedToChangedOp = false;
155     // If it's a use that is tied with a previous def, it has no
156     // reg class constraint.
157     if (Changed && InlineAsm::isUseOperandTiedToDef(Flag, DefIdx))
158       IsTiedToChangedOp = OpChanged[DefIdx];
159 
160     // Memory operands to inline asm in the SelectionDAG are modeled with two
161     // operands: a constant of value InlineAsm::Kind_Mem followed by the input
162     // operand. If we get here and we have a Kind_Mem, skip the next operand (so
163     // it doesn't get misinterpreted), and continue. We do this here because
164     // it's important to update the OpChanged array correctly before moving on.
165     if (Kind == InlineAsm::Kind_Mem) {
166       SDValue op = N->getOperand(++i);
167       AsmNodeOperands.push_back(op);
168       continue;
169     }
170 
171     if (Kind != InlineAsm::Kind_RegUse && Kind != InlineAsm::Kind_RegDef &&
172         Kind != InlineAsm::Kind_RegDefEarlyClobber)
173       continue;
174 
175     unsigned RC;
176     bool HasRC = InlineAsm::hasRegClassConstraint(Flag, RC);
177     if ((!IsTiedToChangedOp && (!HasRC || RC != CSKY::GPRRegClassID)) ||
178         NumRegs != 2)
179       continue;
180 
181     assert((i + 2 < NumOps) && "Invalid number of operands in inline asm");
182     SDValue V0 = N->getOperand(i + 1);
183     SDValue V1 = N->getOperand(i + 2);
184     unsigned Reg0 = cast<RegisterSDNode>(V0)->getReg();
185     unsigned Reg1 = cast<RegisterSDNode>(V1)->getReg();
186     SDValue PairedReg;
187     MachineRegisterInfo &MRI = MF->getRegInfo();
188 
189     if (Kind == InlineAsm::Kind_RegDef ||
190         Kind == InlineAsm::Kind_RegDefEarlyClobber) {
191       // Replace the two GPRs with 1 GPRPair and copy values from GPRPair to
192       // the original GPRs.
193 
194       Register GPVR = MRI.createVirtualRegister(&CSKY::GPRPairRegClass);
195       PairedReg = CurDAG->getRegister(GPVR, MVT::i64);
196       SDValue Chain = SDValue(N, 0);
197 
198       SDNode *GU = N->getGluedUser();
199       SDValue RegCopy =
200           CurDAG->getCopyFromReg(Chain, dl, GPVR, MVT::i64, Chain.getValue(1));
201 
202       // Extract values from a GPRPair reg and copy to the original GPR reg.
203       SDValue Sub0 =
204           CurDAG->getTargetExtractSubreg(CSKY::sub32_0, dl, MVT::i32, RegCopy);
205       SDValue Sub1 =
206           CurDAG->getTargetExtractSubreg(CSKY::sub32_32, dl, MVT::i32, RegCopy);
207       SDValue T0 =
208           CurDAG->getCopyToReg(Sub0, dl, Reg0, Sub0, RegCopy.getValue(1));
209       SDValue T1 = CurDAG->getCopyToReg(Sub1, dl, Reg1, Sub1, T0.getValue(1));
210 
211       // Update the original glue user.
212       std::vector<SDValue> Ops(GU->op_begin(), GU->op_end() - 1);
213       Ops.push_back(T1.getValue(1));
214       CurDAG->UpdateNodeOperands(GU, Ops);
215     } else {
216       // For Kind  == InlineAsm::Kind_RegUse, we first copy two GPRs into a
217       // GPRPair and then pass the GPRPair to the inline asm.
218       SDValue Chain = AsmNodeOperands[InlineAsm::Op_InputChain];
219 
220       // As REG_SEQ doesn't take RegisterSDNode, we copy them first.
221       SDValue T0 =
222           CurDAG->getCopyFromReg(Chain, dl, Reg0, MVT::i32, Chain.getValue(1));
223       SDValue T1 =
224           CurDAG->getCopyFromReg(Chain, dl, Reg1, MVT::i32, T0.getValue(1));
225       SDValue Pair = SDValue(createGPRPairNode(MVT::i64, T0, T1), 0);
226 
227       // Copy REG_SEQ into a GPRPair-typed VR and replace the original two
228       // i32 VRs of inline asm with it.
229       Register GPVR = MRI.createVirtualRegister(&CSKY::GPRPairRegClass);
230       PairedReg = CurDAG->getRegister(GPVR, MVT::i64);
231       Chain = CurDAG->getCopyToReg(T1, dl, GPVR, Pair, T1.getValue(1));
232 
233       AsmNodeOperands[InlineAsm::Op_InputChain] = Chain;
234       Glue = Chain.getValue(1);
235     }
236 
237     Changed = true;
238 
239     if (PairedReg.getNode()) {
240       OpChanged[OpChanged.size() - 1] = true;
241       Flag = InlineAsm::getFlagWord(Kind, 1 /* RegNum*/);
242       if (IsTiedToChangedOp)
243         Flag = InlineAsm::getFlagWordForMatchingOp(Flag, DefIdx);
244       else
245         Flag = InlineAsm::getFlagWordForRegClass(Flag, CSKY::GPRPairRegClassID);
246       // Replace the current flag.
247       AsmNodeOperands[AsmNodeOperands.size() - 1] =
248           CurDAG->getTargetConstant(Flag, dl, MVT::i32);
249       // Add the new register node and skip the original two GPRs.
250       AsmNodeOperands.push_back(PairedReg);
251       // Skip the next two GPRs.
252       i += 2;
253     }
254   }
255 
256   if (Glue.getNode())
257     AsmNodeOperands.push_back(Glue);
258   if (!Changed)
259     return false;
260 
261   SDValue New = CurDAG->getNode(N->getOpcode(), SDLoc(N),
262                                 CurDAG->getVTList(MVT::Other, MVT::Glue),
263                                 AsmNodeOperands);
264   New->setNodeId(-1);
265   ReplaceNode(N, New.getNode());
266   return true;
267 }
268 
269 bool CSKYDAGToDAGISel::selectAddCarry(SDNode *N) {
270   MachineSDNode *NewNode = nullptr;
271   auto Type0 = N->getValueType(0);
272   auto Type1 = N->getValueType(1);
273   auto Op0 = N->getOperand(0);
274   auto Op1 = N->getOperand(1);
275   auto Op2 = N->getOperand(2);
276 
277   SDLoc Dl(N);
278 
279   if (isNullConstant(Op2)) {
280     auto *CA = CurDAG->getMachineNode(
281         Subtarget->has2E3() ? CSKY::CLRC32 : CSKY::CLRC16, Dl, Type1);
282     NewNode = CurDAG->getMachineNode(
283         Subtarget->has2E3() ? CSKY::ADDC32 : CSKY::ADDC16, Dl, {Type0, Type1},
284         {Op0, Op1, SDValue(CA, 0)});
285   } else if (isOneConstant(Op2)) {
286     auto *CA = CurDAG->getMachineNode(
287         Subtarget->has2E3() ? CSKY::SETC32 : CSKY::SETC16, Dl, Type1);
288     NewNode = CurDAG->getMachineNode(
289         Subtarget->has2E3() ? CSKY::ADDC32 : CSKY::ADDC16, Dl, {Type0, Type1},
290         {Op0, Op1, SDValue(CA, 0)});
291   } else {
292     NewNode = CurDAG->getMachineNode(Subtarget->has2E3() ? CSKY::ADDC32
293                                                          : CSKY::ADDC16,
294                                      Dl, {Type0, Type1}, {Op0, Op1, Op2});
295   }
296   ReplaceNode(N, NewNode);
297   return true;
298 }
299 
300 static SDValue InvertCarryFlag(const CSKYSubtarget *Subtarget,
301                                SelectionDAG *DAG, SDLoc Dl, SDValue OldCarry) {
302   auto NewCarryReg =
303       DAG->getMachineNode(Subtarget->has2E3() ? CSKY::MVCV32 : CSKY::MVCV16, Dl,
304                           MVT::i32, OldCarry);
305   auto NewCarry =
306       DAG->getMachineNode(Subtarget->hasE2() ? CSKY::BTSTI32 : CSKY::BTSTI16,
307                           Dl, OldCarry.getValueType(), SDValue(NewCarryReg, 0),
308                           DAG->getTargetConstant(0, Dl, MVT::i32));
309   return SDValue(NewCarry, 0);
310 }
311 
312 bool CSKYDAGToDAGISel::selectSubCarry(SDNode *N) {
313   MachineSDNode *NewNode = nullptr;
314   auto Type0 = N->getValueType(0);
315   auto Type1 = N->getValueType(1);
316   auto Op0 = N->getOperand(0);
317   auto Op1 = N->getOperand(1);
318   auto Op2 = N->getOperand(2);
319 
320   SDLoc Dl(N);
321 
322   if (isNullConstant(Op2)) {
323     auto *CA = CurDAG->getMachineNode(
324         Subtarget->has2E3() ? CSKY::SETC32 : CSKY::SETC16, Dl, Type1);
325     NewNode = CurDAG->getMachineNode(
326         Subtarget->has2E3() ? CSKY::SUBC32 : CSKY::SUBC16, Dl, {Type0, Type1},
327         {Op0, Op1, SDValue(CA, 0)});
328   } else if (isOneConstant(Op2)) {
329     auto *CA = CurDAG->getMachineNode(
330         Subtarget->has2E3() ? CSKY::CLRC32 : CSKY::CLRC16, Dl, Type1);
331     NewNode = CurDAG->getMachineNode(
332         Subtarget->has2E3() ? CSKY::SUBC32 : CSKY::SUBC16, Dl, {Type0, Type1},
333         {Op0, Op1, SDValue(CA, 0)});
334   } else {
335     auto CarryIn = InvertCarryFlag(Subtarget, CurDAG, Dl, Op2);
336     NewNode = CurDAG->getMachineNode(Subtarget->has2E3() ? CSKY::SUBC32
337                                                          : CSKY::SUBC16,
338                                      Dl, {Type0, Type1}, {Op0, Op1, CarryIn});
339   }
340   auto CarryOut = InvertCarryFlag(Subtarget, CurDAG, Dl, SDValue(NewNode, 1));
341 
342   ReplaceUses(SDValue(N, 0), SDValue(NewNode, 0));
343   ReplaceUses(SDValue(N, 1), CarryOut);
344   CurDAG->RemoveDeadNode(N);
345 
346   return true;
347 }
348 
349 SDNode *CSKYDAGToDAGISel::createGPRPairNode(EVT VT, SDValue V0, SDValue V1) {
350   SDLoc dl(V0.getNode());
351   SDValue RegClass =
352       CurDAG->getTargetConstant(CSKY::GPRPairRegClassID, dl, MVT::i32);
353   SDValue SubReg0 = CurDAG->getTargetConstant(CSKY::sub32_0, dl, MVT::i32);
354   SDValue SubReg1 = CurDAG->getTargetConstant(CSKY::sub32_32, dl, MVT::i32);
355   const SDValue Ops[] = {RegClass, V0, SubReg0, V1, SubReg1};
356   return CurDAG->getMachineNode(TargetOpcode::REG_SEQUENCE, dl, VT, Ops);
357 }
358 
359 bool CSKYDAGToDAGISel::SelectInlineAsmMemoryOperand(
360     const SDValue &Op, unsigned ConstraintID, std::vector<SDValue> &OutOps) {
361   switch (ConstraintID) {
362   case InlineAsm::Constraint_m:
363     // We just support simple memory operands that have a single address
364     // operand and need no special handling.
365     OutOps.push_back(Op);
366     return false;
367   default:
368     break;
369   }
370 
371   return true;
372 }
373 
374 FunctionPass *llvm::createCSKYISelDag(CSKYTargetMachine &TM) {
375   return new CSKYDAGToDAGISel(TM);
376 }
377