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