xref: /freebsd/contrib/llvm-project/llvm/lib/Target/CSKY/CSKYISelDAGToDAG.cpp (revision 4f5890a0fb086324a657f3cd7ba1abc57274e0db)
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::GLOBAL_OFFSET_TABLE: {
72     Register GP = Subtarget->getInstrInfo()->getGlobalBaseReg(*MF);
73     ReplaceNode(N, CurDAG->getRegister(GP, N->getValueType(0)).getNode());
74 
75     IsSelected = true;
76     break;
77   }
78   case ISD::FrameIndex: {
79     SDValue Imm = CurDAG->getTargetConstant(0, Dl, MVT::i32);
80     int FI = cast<FrameIndexSDNode>(N)->getIndex();
81     SDValue TFI = CurDAG->getTargetFrameIndex(FI, MVT::i32);
82     ReplaceNode(N, CurDAG->getMachineNode(Subtarget->hasE2() ? CSKY::ADDI32
83                                                              : CSKY::ADDI16XZ,
84                                           Dl, MVT::i32, TFI, Imm));
85 
86     IsSelected = true;
87     break;
88   }
89   }
90 
91   if (IsSelected)
92     return;
93 
94   // Select the default instruction.
95   SelectCode(N);
96 }
97 
98 bool CSKYDAGToDAGISel::selectAddCarry(SDNode *N) {
99   MachineSDNode *NewNode = nullptr;
100   auto Type0 = N->getValueType(0);
101   auto Type1 = N->getValueType(1);
102   auto Op0 = N->getOperand(0);
103   auto Op1 = N->getOperand(1);
104   auto Op2 = N->getOperand(2);
105 
106   SDLoc Dl(N);
107 
108   if (isNullConstant(Op2)) {
109     auto *CA = CurDAG->getMachineNode(
110         Subtarget->has2E3() ? CSKY::CLRC32 : CSKY::CLRC16, Dl, Type1);
111     NewNode = CurDAG->getMachineNode(
112         Subtarget->has2E3() ? CSKY::ADDC32 : CSKY::ADDC16, Dl, {Type0, Type1},
113         {Op0, Op1, SDValue(CA, 0)});
114   } else if (isOneConstant(Op2)) {
115     auto *CA = CurDAG->getMachineNode(
116         Subtarget->has2E3() ? CSKY::SETC32 : CSKY::SETC16, Dl, Type1);
117     NewNode = CurDAG->getMachineNode(
118         Subtarget->has2E3() ? CSKY::ADDC32 : CSKY::ADDC16, Dl, {Type0, Type1},
119         {Op0, Op1, SDValue(CA, 0)});
120   } else {
121     NewNode = CurDAG->getMachineNode(Subtarget->has2E3() ? CSKY::ADDC32
122                                                          : CSKY::ADDC16,
123                                      Dl, {Type0, Type1}, {Op0, Op1, Op2});
124   }
125   ReplaceNode(N, NewNode);
126   return true;
127 }
128 
129 static SDValue InvertCarryFlag(const CSKYSubtarget *Subtarget,
130                                SelectionDAG *DAG, SDLoc Dl, SDValue OldCarry) {
131   auto NewCarryReg =
132       DAG->getMachineNode(Subtarget->has2E3() ? CSKY::MVCV32 : CSKY::MVCV16, Dl,
133                           MVT::i32, OldCarry);
134   auto NewCarry =
135       DAG->getMachineNode(Subtarget->hasE2() ? CSKY::BTSTI32 : CSKY::BTSTI16,
136                           Dl, OldCarry.getValueType(), SDValue(NewCarryReg, 0),
137                           DAG->getTargetConstant(0, Dl, MVT::i32));
138   return SDValue(NewCarry, 0);
139 }
140 
141 bool CSKYDAGToDAGISel::selectSubCarry(SDNode *N) {
142   MachineSDNode *NewNode = nullptr;
143   auto Type0 = N->getValueType(0);
144   auto Type1 = N->getValueType(1);
145   auto Op0 = N->getOperand(0);
146   auto Op1 = N->getOperand(1);
147   auto Op2 = N->getOperand(2);
148 
149   SDLoc Dl(N);
150 
151   if (isNullConstant(Op2)) {
152     auto *CA = CurDAG->getMachineNode(
153         Subtarget->has2E3() ? CSKY::SETC32 : CSKY::SETC16, Dl, Type1);
154     NewNode = CurDAG->getMachineNode(
155         Subtarget->has2E3() ? CSKY::SUBC32 : CSKY::SUBC16, Dl, {Type0, Type1},
156         {Op0, Op1, SDValue(CA, 0)});
157   } else if (isOneConstant(Op2)) {
158     auto *CA = CurDAG->getMachineNode(
159         Subtarget->has2E3() ? CSKY::CLRC32 : CSKY::CLRC16, Dl, Type1);
160     NewNode = CurDAG->getMachineNode(
161         Subtarget->has2E3() ? CSKY::SUBC32 : CSKY::SUBC16, Dl, {Type0, Type1},
162         {Op0, Op1, SDValue(CA, 0)});
163   } else {
164     auto CarryIn = InvertCarryFlag(Subtarget, CurDAG, Dl, Op2);
165     NewNode = CurDAG->getMachineNode(Subtarget->has2E3() ? CSKY::SUBC32
166                                                          : CSKY::SUBC16,
167                                      Dl, {Type0, Type1}, {Op0, Op1, CarryIn});
168   }
169   auto CarryOut = InvertCarryFlag(Subtarget, CurDAG, Dl, SDValue(NewNode, 1));
170 
171   ReplaceUses(SDValue(N, 0), SDValue(NewNode, 0));
172   ReplaceUses(SDValue(N, 1), CarryOut);
173   CurDAG->RemoveDeadNode(N);
174 
175   return true;
176 }
177 
178 FunctionPass *llvm::createCSKYISelDag(CSKYTargetMachine &TM) {
179   return new CSKYDAGToDAGISel(TM);
180 }
181