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 
46 #include "CSKYGenDAGISel.inc"
47 };
48 } // namespace
49 
50 void CSKYDAGToDAGISel::Select(SDNode *N) {
51   // If we have a custom node, we have already selected
52   if (N->isMachineOpcode()) {
53     LLVM_DEBUG(dbgs() << "== "; N->dump(CurDAG); dbgs() << "\n");
54     N->setNodeId(-1);
55     return;
56   }
57 
58   SDLoc Dl(N);
59   unsigned Opcode = N->getOpcode();
60   bool IsSelected = false;
61 
62   switch (Opcode) {
63   default:
64     break;
65   case ISD::ADDCARRY:
66     IsSelected = selectAddCarry(N);
67     break;
68   case ISD::SUBCARRY:
69     IsSelected = selectSubCarry(N);
70     break;
71   case ISD::FrameIndex: {
72     SDValue Imm = CurDAG->getTargetConstant(0, Dl, MVT::i32);
73     int FI = cast<FrameIndexSDNode>(N)->getIndex();
74     SDValue TFI = CurDAG->getTargetFrameIndex(FI, MVT::i32);
75     ReplaceNode(N, CurDAG->getMachineNode(Subtarget->hasE2() ? CSKY::ADDI32
76                                                              : CSKY::ADDI16XZ,
77                                           Dl, MVT::i32, TFI, Imm));
78 
79     IsSelected = true;
80     break;
81   }
82   }
83 
84   if (IsSelected)
85     return;
86 
87   // Select the default instruction.
88   SelectCode(N);
89 }
90 
91 bool CSKYDAGToDAGISel::selectAddCarry(SDNode *N) {
92   MachineSDNode *NewNode = nullptr;
93   auto Type0 = N->getValueType(0);
94   auto Type1 = N->getValueType(1);
95   auto Op0 = N->getOperand(0);
96   auto Op1 = N->getOperand(1);
97   auto Op2 = N->getOperand(2);
98 
99   SDLoc Dl(N);
100 
101   if (isNullConstant(Op2)) {
102     auto *CA = CurDAG->getMachineNode(
103         Subtarget->has2E3() ? CSKY::CLRC32 : CSKY::CLRC16, Dl, Type1);
104     NewNode = CurDAG->getMachineNode(
105         Subtarget->has2E3() ? CSKY::ADDC32 : CSKY::ADDC16, Dl, {Type0, Type1},
106         {Op0, Op1, SDValue(CA, 0)});
107   } else if (isOneConstant(Op2)) {
108     auto *CA = CurDAG->getMachineNode(
109         Subtarget->has2E3() ? CSKY::SETC32 : CSKY::SETC16, Dl, Type1);
110     NewNode = CurDAG->getMachineNode(
111         Subtarget->has2E3() ? CSKY::ADDC32 : CSKY::ADDC16, Dl, {Type0, Type1},
112         {Op0, Op1, SDValue(CA, 0)});
113   } else {
114     NewNode = CurDAG->getMachineNode(Subtarget->has2E3() ? CSKY::ADDC32
115                                                          : CSKY::ADDC16,
116                                      Dl, {Type0, Type1}, {Op0, Op1, Op2});
117   }
118   ReplaceNode(N, NewNode);
119   return true;
120 }
121 
122 static SDValue InvertCarryFlag(const CSKYSubtarget *Subtarget,
123                                SelectionDAG *DAG, SDLoc Dl, SDValue OldCarry) {
124   auto NewCarryReg =
125       DAG->getMachineNode(Subtarget->has2E3() ? CSKY::MVCV32 : CSKY::MVCV16, Dl,
126                           MVT::i32, OldCarry);
127   auto NewCarry =
128       DAG->getMachineNode(Subtarget->hasE2() ? CSKY::BTSTI32 : CSKY::BTSTI16,
129                           Dl, OldCarry.getValueType(), SDValue(NewCarryReg, 0),
130                           DAG->getTargetConstant(0, Dl, MVT::i32));
131   return SDValue(NewCarry, 0);
132 }
133 
134 bool CSKYDAGToDAGISel::selectSubCarry(SDNode *N) {
135   MachineSDNode *NewNode = nullptr;
136   auto Type0 = N->getValueType(0);
137   auto Type1 = N->getValueType(1);
138   auto Op0 = N->getOperand(0);
139   auto Op1 = N->getOperand(1);
140   auto Op2 = N->getOperand(2);
141 
142   SDLoc Dl(N);
143 
144   if (isNullConstant(Op2)) {
145     auto *CA = CurDAG->getMachineNode(
146         Subtarget->has2E3() ? CSKY::SETC32 : CSKY::SETC16, Dl, Type1);
147     NewNode = CurDAG->getMachineNode(
148         Subtarget->has2E3() ? CSKY::SUBC32 : CSKY::SUBC16, Dl, {Type0, Type1},
149         {Op0, Op1, SDValue(CA, 0)});
150   } else if (isOneConstant(Op2)) {
151     auto *CA = CurDAG->getMachineNode(
152         Subtarget->has2E3() ? CSKY::CLRC32 : CSKY::CLRC16, Dl, Type1);
153     NewNode = CurDAG->getMachineNode(
154         Subtarget->has2E3() ? CSKY::SUBC32 : CSKY::SUBC16, Dl, {Type0, Type1},
155         {Op0, Op1, SDValue(CA, 0)});
156   } else {
157     auto CarryIn = InvertCarryFlag(Subtarget, CurDAG, Dl, Op2);
158     NewNode = CurDAG->getMachineNode(Subtarget->has2E3() ? CSKY::SUBC32
159                                                          : CSKY::SUBC16,
160                                      Dl, {Type0, Type1}, {Op0, Op1, CarryIn});
161   }
162   auto CarryOut = InvertCarryFlag(Subtarget, CurDAG, Dl, SDValue(NewNode, 1));
163 
164   ReplaceUses(SDValue(N, 0), SDValue(NewNode, 0));
165   ReplaceUses(SDValue(N, 1), CarryOut);
166   CurDAG->RemoveDeadNode(N);
167 
168   return true;
169 }
170 
171 FunctionPass *llvm::createCSKYISelDag(CSKYTargetMachine &TM) {
172   return new CSKYDAGToDAGISel(TM);
173 }
174