1 //=- LoongArchISelDAGToDAG.cpp - A dag to dag inst selector for LoongArch -===//
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 LoongArch target.
10 //
11 //===----------------------------------------------------------------------===//
12
13 #include "LoongArchISelDAGToDAG.h"
14 #include "LoongArchISelLowering.h"
15 #include "MCTargetDesc/LoongArchMCTargetDesc.h"
16 #include "MCTargetDesc/LoongArchMatInt.h"
17 #include "llvm/Support/KnownBits.h"
18
19 using namespace llvm;
20
21 #define DEBUG_TYPE "loongarch-isel"
22 #define PASS_NAME "LoongArch DAG->DAG Pattern Instruction Selection"
23
24 char LoongArchDAGToDAGISel::ID;
25
INITIALIZE_PASS(LoongArchDAGToDAGISel,DEBUG_TYPE,PASS_NAME,false,false)26 INITIALIZE_PASS(LoongArchDAGToDAGISel, DEBUG_TYPE, PASS_NAME, false, false)
27
28 void LoongArchDAGToDAGISel::Select(SDNode *Node) {
29 // If we have a custom node, we have already selected.
30 if (Node->isMachineOpcode()) {
31 LLVM_DEBUG(dbgs() << "== "; Node->dump(CurDAG); dbgs() << "\n");
32 Node->setNodeId(-1);
33 return;
34 }
35
36 // Instruction Selection not handled by the auto-generated tablegen selection
37 // should be handled here.
38 unsigned Opcode = Node->getOpcode();
39 MVT GRLenVT = Subtarget->getGRLenVT();
40 SDLoc DL(Node);
41 MVT VT = Node->getSimpleValueType(0);
42
43 switch (Opcode) {
44 default:
45 break;
46 case ISD::Constant: {
47 int64_t Imm = cast<ConstantSDNode>(Node)->getSExtValue();
48 if (Imm == 0 && VT == GRLenVT) {
49 SDValue New = CurDAG->getCopyFromReg(CurDAG->getEntryNode(), DL,
50 LoongArch::R0, GRLenVT);
51 ReplaceNode(Node, New.getNode());
52 return;
53 }
54 SDNode *Result = nullptr;
55 SDValue SrcReg = CurDAG->getRegister(LoongArch::R0, GRLenVT);
56 // The instructions in the sequence are handled here.
57 for (LoongArchMatInt::Inst &Inst : LoongArchMatInt::generateInstSeq(Imm)) {
58 SDValue SDImm = CurDAG->getTargetConstant(Inst.Imm, DL, GRLenVT);
59 if (Inst.Opc == LoongArch::LU12I_W)
60 Result = CurDAG->getMachineNode(LoongArch::LU12I_W, DL, GRLenVT, SDImm);
61 else
62 Result = CurDAG->getMachineNode(Inst.Opc, DL, GRLenVT, SrcReg, SDImm);
63 SrcReg = SDValue(Result, 0);
64 }
65
66 ReplaceNode(Node, Result);
67 return;
68 }
69 case ISD::FrameIndex: {
70 SDValue Imm = CurDAG->getTargetConstant(0, DL, GRLenVT);
71 int FI = cast<FrameIndexSDNode>(Node)->getIndex();
72 SDValue TFI = CurDAG->getTargetFrameIndex(FI, VT);
73 unsigned ADDIOp =
74 Subtarget->is64Bit() ? LoongArch::ADDI_D : LoongArch::ADDI_W;
75 ReplaceNode(Node, CurDAG->getMachineNode(ADDIOp, DL, VT, TFI, Imm));
76 return;
77 }
78 // TODO: Add selection nodes needed later.
79 }
80
81 // Select the default instruction.
82 SelectCode(Node);
83 }
84
SelectInlineAsmMemoryOperand(const SDValue & Op,unsigned ConstraintID,std::vector<SDValue> & OutOps)85 bool LoongArchDAGToDAGISel::SelectInlineAsmMemoryOperand(
86 const SDValue &Op, unsigned ConstraintID, std::vector<SDValue> &OutOps) {
87 SDValue Base = Op;
88 SDValue Offset =
89 CurDAG->getTargetConstant(0, SDLoc(Op), Subtarget->getGRLenVT());
90 switch (ConstraintID) {
91 default:
92 llvm_unreachable("unexpected asm memory constraint");
93 // Reg+Reg addressing.
94 case InlineAsm::Constraint_k:
95 Base = Op.getOperand(0);
96 Offset = Op.getOperand(1);
97 break;
98 // Reg+simm12 addressing.
99 case InlineAsm::Constraint_m:
100 if (CurDAG->isBaseWithConstantOffset(Op)) {
101 ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Op.getOperand(1));
102 if (isIntN(12, CN->getSExtValue())) {
103 Base = Op.getOperand(0);
104 Offset = CurDAG->getTargetConstant(CN->getZExtValue(), SDLoc(Op),
105 Op.getValueType());
106 }
107 }
108 break;
109 // Reg+0 addressing.
110 case InlineAsm::Constraint_ZB:
111 break;
112 // Reg+(simm14<<2) addressing.
113 case InlineAsm::Constraint_ZC:
114 if (CurDAG->isBaseWithConstantOffset(Op)) {
115 ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Op.getOperand(1));
116 if (isIntN(16, CN->getSExtValue()) &&
117 isAligned(Align(4ULL), CN->getZExtValue())) {
118 Base = Op.getOperand(0);
119 Offset = CurDAG->getTargetConstant(CN->getZExtValue(), SDLoc(Op),
120 Op.getValueType());
121 }
122 }
123 break;
124 }
125 OutOps.push_back(Base);
126 OutOps.push_back(Offset);
127 return false;
128 }
129
SelectBaseAddr(SDValue Addr,SDValue & Base)130 bool LoongArchDAGToDAGISel::SelectBaseAddr(SDValue Addr, SDValue &Base) {
131 // If this is FrameIndex, select it directly. Otherwise just let it get
132 // selected to a register independently.
133 if (auto *FIN = dyn_cast<FrameIndexSDNode>(Addr))
134 Base =
135 CurDAG->getTargetFrameIndex(FIN->getIndex(), Subtarget->getGRLenVT());
136 else
137 Base = Addr;
138 return true;
139 }
140
selectNonFIBaseAddr(SDValue Addr,SDValue & Base)141 bool LoongArchDAGToDAGISel::selectNonFIBaseAddr(SDValue Addr, SDValue &Base) {
142 // If this is FrameIndex, don't select it.
143 if (isa<FrameIndexSDNode>(Addr))
144 return false;
145 Base = Addr;
146 return true;
147 }
148
selectShiftMask(SDValue N,unsigned ShiftWidth,SDValue & ShAmt)149 bool LoongArchDAGToDAGISel::selectShiftMask(SDValue N, unsigned ShiftWidth,
150 SDValue &ShAmt) {
151 // Shift instructions on LoongArch only read the lower 5 or 6 bits of the
152 // shift amount. If there is an AND on the shift amount, we can bypass it if
153 // it doesn't affect any of those bits.
154 if (N.getOpcode() == ISD::AND && isa<ConstantSDNode>(N.getOperand(1))) {
155 const APInt &AndMask = N->getConstantOperandAPInt(1);
156
157 // Since the max shift amount is a power of 2 we can subtract 1 to make a
158 // mask that covers the bits needed to represent all shift amounts.
159 assert(isPowerOf2_32(ShiftWidth) && "Unexpected max shift amount!");
160 APInt ShMask(AndMask.getBitWidth(), ShiftWidth - 1);
161
162 if (ShMask.isSubsetOf(AndMask)) {
163 ShAmt = N.getOperand(0);
164 return true;
165 }
166
167 // SimplifyDemandedBits may have optimized the mask so try restoring any
168 // bits that are known zero.
169 KnownBits Known = CurDAG->computeKnownBits(N->getOperand(0));
170 if (ShMask.isSubsetOf(AndMask | Known.Zero)) {
171 ShAmt = N.getOperand(0);
172 return true;
173 }
174 } else if (N.getOpcode() == LoongArchISD::BSTRPICK) {
175 // Similar to the above AND, if there is a BSTRPICK on the shift amount, we
176 // can bypass it.
177 assert(isPowerOf2_32(ShiftWidth) && "Unexpected max shift amount!");
178 assert(isa<ConstantSDNode>(N.getOperand(1)) && "Illegal msb operand!");
179 assert(isa<ConstantSDNode>(N.getOperand(2)) && "Illegal lsb operand!");
180 uint64_t msb = N.getConstantOperandVal(1), lsb = N.getConstantOperandVal(2);
181 if (lsb == 0 && Log2_32(ShiftWidth) <= msb + 1) {
182 ShAmt = N.getOperand(0);
183 return true;
184 }
185 } else if (N.getOpcode() == ISD::SUB &&
186 isa<ConstantSDNode>(N.getOperand(0))) {
187 uint64_t Imm = N.getConstantOperandVal(0);
188 // If we are shifting by N-X where N == 0 mod Size, then just shift by -X to
189 // generate a NEG instead of a SUB of a constant.
190 if (Imm != 0 && Imm % ShiftWidth == 0) {
191 SDLoc DL(N);
192 EVT VT = N.getValueType();
193 SDValue Zero =
194 CurDAG->getCopyFromReg(CurDAG->getEntryNode(), DL, LoongArch::R0, VT);
195 unsigned NegOpc = VT == MVT::i64 ? LoongArch::SUB_D : LoongArch::SUB_W;
196 MachineSDNode *Neg =
197 CurDAG->getMachineNode(NegOpc, DL, VT, Zero, N.getOperand(1));
198 ShAmt = SDValue(Neg, 0);
199 return true;
200 }
201 }
202
203 ShAmt = N;
204 return true;
205 }
206
selectSExti32(SDValue N,SDValue & Val)207 bool LoongArchDAGToDAGISel::selectSExti32(SDValue N, SDValue &Val) {
208 if (N.getOpcode() == ISD::SIGN_EXTEND_INREG &&
209 cast<VTSDNode>(N.getOperand(1))->getVT() == MVT::i32) {
210 Val = N.getOperand(0);
211 return true;
212 }
213 if (N.getOpcode() == LoongArchISD::BSTRPICK &&
214 N.getConstantOperandVal(1) < UINT64_C(0X1F) &&
215 N.getConstantOperandVal(2) == UINT64_C(0)) {
216 Val = N;
217 return true;
218 }
219 MVT VT = N.getSimpleValueType();
220 if (CurDAG->ComputeNumSignBits(N) > (VT.getSizeInBits() - 32)) {
221 Val = N;
222 return true;
223 }
224
225 return false;
226 }
227
selectZExti32(SDValue N,SDValue & Val)228 bool LoongArchDAGToDAGISel::selectZExti32(SDValue N, SDValue &Val) {
229 if (N.getOpcode() == ISD::AND) {
230 auto *C = dyn_cast<ConstantSDNode>(N.getOperand(1));
231 if (C && C->getZExtValue() == UINT64_C(0xFFFFFFFF)) {
232 Val = N.getOperand(0);
233 return true;
234 }
235 }
236 MVT VT = N.getSimpleValueType();
237 APInt Mask = APInt::getHighBitsSet(VT.getSizeInBits(), 32);
238 if (CurDAG->MaskedValueIsZero(N, Mask)) {
239 Val = N;
240 return true;
241 }
242
243 return false;
244 }
245
246 // This pass converts a legalized DAG into a LoongArch-specific DAG, ready
247 // for instruction scheduling.
createLoongArchISelDag(LoongArchTargetMachine & TM)248 FunctionPass *llvm::createLoongArchISelDag(LoongArchTargetMachine &TM) {
249 return new LoongArchDAGToDAGISel(TM);
250 }
251