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 #include "llvm/Support/raw_ostream.h"
19
20 using namespace llvm;
21
22 #define DEBUG_TYPE "loongarch-isel"
23 #define PASS_NAME "LoongArch DAG->DAG Pattern Instruction Selection"
24
25 char LoongArchDAGToDAGISelLegacy::ID;
26
LoongArchDAGToDAGISelLegacy(LoongArchTargetMachine & TM)27 LoongArchDAGToDAGISelLegacy::LoongArchDAGToDAGISelLegacy(
28 LoongArchTargetMachine &TM)
29 : SelectionDAGISelLegacy(ID, std::make_unique<LoongArchDAGToDAGISel>(TM)) {}
30
INITIALIZE_PASS(LoongArchDAGToDAGISelLegacy,DEBUG_TYPE,PASS_NAME,false,false)31 INITIALIZE_PASS(LoongArchDAGToDAGISelLegacy, DEBUG_TYPE, PASS_NAME, false,
32 false)
33
34 void LoongArchDAGToDAGISel::Select(SDNode *Node) {
35 // If we have a custom node, we have already selected.
36 if (Node->isMachineOpcode()) {
37 LLVM_DEBUG(dbgs() << "== "; Node->dump(CurDAG); dbgs() << "\n");
38 Node->setNodeId(-1);
39 return;
40 }
41
42 // Instruction Selection not handled by the auto-generated tablegen selection
43 // should be handled here.
44 unsigned Opcode = Node->getOpcode();
45 MVT GRLenVT = Subtarget->getGRLenVT();
46 SDLoc DL(Node);
47 MVT VT = Node->getSimpleValueType(0);
48
49 switch (Opcode) {
50 default:
51 break;
52 case ISD::Constant: {
53 int64_t Imm = cast<ConstantSDNode>(Node)->getSExtValue();
54 if (Imm == 0 && VT == GRLenVT) {
55 SDValue New = CurDAG->getCopyFromReg(CurDAG->getEntryNode(), DL,
56 LoongArch::R0, GRLenVT);
57 ReplaceNode(Node, New.getNode());
58 return;
59 }
60 SDNode *Result = nullptr;
61 SDValue SrcReg = CurDAG->getRegister(LoongArch::R0, GRLenVT);
62 // The instructions in the sequence are handled here.
63 for (LoongArchMatInt::Inst &Inst : LoongArchMatInt::generateInstSeq(Imm)) {
64 SDValue SDImm = CurDAG->getTargetConstant(Inst.Imm, DL, GRLenVT);
65 if (Inst.Opc == LoongArch::LU12I_W)
66 Result = CurDAG->getMachineNode(LoongArch::LU12I_W, DL, GRLenVT, SDImm);
67 else
68 Result = CurDAG->getMachineNode(Inst.Opc, DL, GRLenVT, SrcReg, SDImm);
69 SrcReg = SDValue(Result, 0);
70 }
71
72 ReplaceNode(Node, Result);
73 return;
74 }
75 case ISD::FrameIndex: {
76 SDValue Imm = CurDAG->getTargetConstant(0, DL, GRLenVT);
77 int FI = cast<FrameIndexSDNode>(Node)->getIndex();
78 SDValue TFI = CurDAG->getTargetFrameIndex(FI, VT);
79 unsigned ADDIOp =
80 Subtarget->is64Bit() ? LoongArch::ADDI_D : LoongArch::ADDI_W;
81 ReplaceNode(Node, CurDAG->getMachineNode(ADDIOp, DL, VT, TFI, Imm));
82 return;
83 }
84 case ISD::BITCAST: {
85 if (VT.is128BitVector() || VT.is256BitVector()) {
86 ReplaceUses(SDValue(Node, 0), Node->getOperand(0));
87 CurDAG->RemoveDeadNode(Node);
88 return;
89 }
90 break;
91 }
92 case ISD::BUILD_VECTOR: {
93 // Select appropriate [x]vrepli.[bhwd] instructions for constant splats of
94 // 128/256-bit when LSX/LASX is enabled.
95 BuildVectorSDNode *BVN = cast<BuildVectorSDNode>(Node);
96 APInt SplatValue, SplatUndef;
97 unsigned SplatBitSize;
98 bool HasAnyUndefs;
99 unsigned Op;
100 EVT ViaVecTy;
101 bool Is128Vec = BVN->getValueType(0).is128BitVector();
102 bool Is256Vec = BVN->getValueType(0).is256BitVector();
103
104 if (!Subtarget->hasExtLSX() || (!Is128Vec && !Is256Vec))
105 break;
106 if (!BVN->isConstantSplat(SplatValue, SplatUndef, SplatBitSize,
107 HasAnyUndefs, 8))
108 break;
109
110 switch (SplatBitSize) {
111 default:
112 break;
113 case 8:
114 Op = Is256Vec ? LoongArch::PseudoXVREPLI_B : LoongArch::PseudoVREPLI_B;
115 ViaVecTy = Is256Vec ? MVT::v32i8 : MVT::v16i8;
116 break;
117 case 16:
118 Op = Is256Vec ? LoongArch::PseudoXVREPLI_H : LoongArch::PseudoVREPLI_H;
119 ViaVecTy = Is256Vec ? MVT::v16i16 : MVT::v8i16;
120 break;
121 case 32:
122 Op = Is256Vec ? LoongArch::PseudoXVREPLI_W : LoongArch::PseudoVREPLI_W;
123 ViaVecTy = Is256Vec ? MVT::v8i32 : MVT::v4i32;
124 break;
125 case 64:
126 Op = Is256Vec ? LoongArch::PseudoXVREPLI_D : LoongArch::PseudoVREPLI_D;
127 ViaVecTy = Is256Vec ? MVT::v4i64 : MVT::v2i64;
128 break;
129 }
130
131 SDNode *Res;
132 // If we have a signed 10 bit integer, we can splat it directly.
133 if (SplatValue.isSignedIntN(10)) {
134 SDValue Imm = CurDAG->getTargetConstant(SplatValue, DL,
135 ViaVecTy.getVectorElementType());
136 Res = CurDAG->getMachineNode(Op, DL, ViaVecTy, Imm);
137 ReplaceNode(Node, Res);
138 return;
139 }
140 break;
141 }
142 }
143
144 // Select the default instruction.
145 SelectCode(Node);
146 }
147
SelectInlineAsmMemoryOperand(const SDValue & Op,InlineAsm::ConstraintCode ConstraintID,std::vector<SDValue> & OutOps)148 bool LoongArchDAGToDAGISel::SelectInlineAsmMemoryOperand(
149 const SDValue &Op, InlineAsm::ConstraintCode ConstraintID,
150 std::vector<SDValue> &OutOps) {
151 SDValue Base = Op;
152 SDValue Offset =
153 CurDAG->getTargetConstant(0, SDLoc(Op), Subtarget->getGRLenVT());
154 switch (ConstraintID) {
155 default:
156 llvm_unreachable("unexpected asm memory constraint");
157 // Reg+Reg addressing.
158 case InlineAsm::ConstraintCode::k:
159 Base = Op.getOperand(0);
160 Offset = Op.getOperand(1);
161 break;
162 // Reg+simm12 addressing.
163 case InlineAsm::ConstraintCode::m:
164 if (CurDAG->isBaseWithConstantOffset(Op)) {
165 ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Op.getOperand(1));
166 if (isIntN(12, CN->getSExtValue())) {
167 Base = Op.getOperand(0);
168 Offset = CurDAG->getTargetConstant(CN->getZExtValue(), SDLoc(Op),
169 Op.getValueType());
170 }
171 }
172 break;
173 // Reg+0 addressing.
174 case InlineAsm::ConstraintCode::ZB:
175 break;
176 // Reg+(simm14<<2) addressing.
177 case InlineAsm::ConstraintCode::ZC:
178 if (CurDAG->isBaseWithConstantOffset(Op)) {
179 ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Op.getOperand(1));
180 if (isIntN(16, CN->getSExtValue()) &&
181 isAligned(Align(4ULL), CN->getZExtValue())) {
182 Base = Op.getOperand(0);
183 Offset = CurDAG->getTargetConstant(CN->getZExtValue(), SDLoc(Op),
184 Op.getValueType());
185 }
186 }
187 break;
188 }
189 OutOps.push_back(Base);
190 OutOps.push_back(Offset);
191 return false;
192 }
193
SelectBaseAddr(SDValue Addr,SDValue & Base)194 bool LoongArchDAGToDAGISel::SelectBaseAddr(SDValue Addr, SDValue &Base) {
195 // If this is FrameIndex, select it directly. Otherwise just let it get
196 // selected to a register independently.
197 if (auto *FIN = dyn_cast<FrameIndexSDNode>(Addr))
198 Base =
199 CurDAG->getTargetFrameIndex(FIN->getIndex(), Subtarget->getGRLenVT());
200 else
201 Base = Addr;
202 return true;
203 }
204
205 // Fold constant addresses.
SelectAddrConstant(SDValue Addr,SDValue & Base,SDValue & Offset)206 bool LoongArchDAGToDAGISel::SelectAddrConstant(SDValue Addr, SDValue &Base,
207 SDValue &Offset) {
208 SDLoc DL(Addr);
209 MVT VT = Addr.getSimpleValueType();
210
211 if (!isa<ConstantSDNode>(Addr))
212 return false;
213
214 // If the constant is a simm12, we can fold the whole constant and use R0 as
215 // the base.
216 int64_t CVal = cast<ConstantSDNode>(Addr)->getSExtValue();
217 if (!isInt<12>(CVal))
218 return false;
219 Base = CurDAG->getRegister(LoongArch::R0, VT);
220 Offset = CurDAG->getTargetConstant(SignExtend64<12>(CVal), DL, VT);
221 return true;
222 }
223
selectNonFIBaseAddr(SDValue Addr,SDValue & Base)224 bool LoongArchDAGToDAGISel::selectNonFIBaseAddr(SDValue Addr, SDValue &Base) {
225 // If this is FrameIndex, don't select it.
226 if (isa<FrameIndexSDNode>(Addr))
227 return false;
228 Base = Addr;
229 return true;
230 }
231
selectShiftMask(SDValue N,unsigned ShiftWidth,SDValue & ShAmt)232 bool LoongArchDAGToDAGISel::selectShiftMask(SDValue N, unsigned ShiftWidth,
233 SDValue &ShAmt) {
234 // Shift instructions on LoongArch only read the lower 5 or 6 bits of the
235 // shift amount. If there is an AND on the shift amount, we can bypass it if
236 // it doesn't affect any of those bits.
237 if (N.getOpcode() == ISD::AND && isa<ConstantSDNode>(N.getOperand(1))) {
238 const APInt &AndMask = N->getConstantOperandAPInt(1);
239
240 // Since the max shift amount is a power of 2 we can subtract 1 to make a
241 // mask that covers the bits needed to represent all shift amounts.
242 assert(isPowerOf2_32(ShiftWidth) && "Unexpected max shift amount!");
243 APInt ShMask(AndMask.getBitWidth(), ShiftWidth - 1);
244
245 if (ShMask.isSubsetOf(AndMask)) {
246 ShAmt = N.getOperand(0);
247 return true;
248 }
249
250 // SimplifyDemandedBits may have optimized the mask so try restoring any
251 // bits that are known zero.
252 KnownBits Known = CurDAG->computeKnownBits(N->getOperand(0));
253 if (ShMask.isSubsetOf(AndMask | Known.Zero)) {
254 ShAmt = N.getOperand(0);
255 return true;
256 }
257 } else if (N.getOpcode() == LoongArchISD::BSTRPICK) {
258 // Similar to the above AND, if there is a BSTRPICK on the shift amount, we
259 // can bypass it.
260 assert(isPowerOf2_32(ShiftWidth) && "Unexpected max shift amount!");
261 assert(isa<ConstantSDNode>(N.getOperand(1)) && "Illegal msb operand!");
262 assert(isa<ConstantSDNode>(N.getOperand(2)) && "Illegal lsb operand!");
263 uint64_t msb = N.getConstantOperandVal(1), lsb = N.getConstantOperandVal(2);
264 if (lsb == 0 && Log2_32(ShiftWidth) <= msb + 1) {
265 ShAmt = N.getOperand(0);
266 return true;
267 }
268 } else if (N.getOpcode() == ISD::SUB &&
269 isa<ConstantSDNode>(N.getOperand(0))) {
270 uint64_t Imm = N.getConstantOperandVal(0);
271 // If we are shifting by N-X where N == 0 mod Size, then just shift by -X to
272 // generate a NEG instead of a SUB of a constant.
273 if (Imm != 0 && Imm % ShiftWidth == 0) {
274 SDLoc DL(N);
275 EVT VT = N.getValueType();
276 SDValue Zero =
277 CurDAG->getCopyFromReg(CurDAG->getEntryNode(), DL, LoongArch::R0, VT);
278 unsigned NegOpc = VT == MVT::i64 ? LoongArch::SUB_D : LoongArch::SUB_W;
279 MachineSDNode *Neg =
280 CurDAG->getMachineNode(NegOpc, DL, VT, Zero, N.getOperand(1));
281 ShAmt = SDValue(Neg, 0);
282 return true;
283 }
284 }
285
286 ShAmt = N;
287 return true;
288 }
289
selectSExti32(SDValue N,SDValue & Val)290 bool LoongArchDAGToDAGISel::selectSExti32(SDValue N, SDValue &Val) {
291 if (N.getOpcode() == ISD::SIGN_EXTEND_INREG &&
292 cast<VTSDNode>(N.getOperand(1))->getVT() == MVT::i32) {
293 Val = N.getOperand(0);
294 return true;
295 }
296 if (N.getOpcode() == LoongArchISD::BSTRPICK &&
297 N.getConstantOperandVal(1) < UINT64_C(0X1F) &&
298 N.getConstantOperandVal(2) == UINT64_C(0)) {
299 Val = N;
300 return true;
301 }
302 MVT VT = N.getSimpleValueType();
303 if (CurDAG->ComputeNumSignBits(N) > (VT.getSizeInBits() - 32)) {
304 Val = N;
305 return true;
306 }
307
308 return false;
309 }
310
selectZExti32(SDValue N,SDValue & Val)311 bool LoongArchDAGToDAGISel::selectZExti32(SDValue N, SDValue &Val) {
312 if (N.getOpcode() == ISD::AND) {
313 auto *C = dyn_cast<ConstantSDNode>(N.getOperand(1));
314 if (C && C->getZExtValue() == UINT64_C(0xFFFFFFFF)) {
315 Val = N.getOperand(0);
316 return true;
317 }
318 }
319 MVT VT = N.getSimpleValueType();
320 APInt Mask = APInt::getHighBitsSet(VT.getSizeInBits(), 32);
321 if (CurDAG->MaskedValueIsZero(N, Mask)) {
322 Val = N;
323 return true;
324 }
325
326 return false;
327 }
328
selectVSplat(SDNode * N,APInt & Imm,unsigned MinSizeInBits) const329 bool LoongArchDAGToDAGISel::selectVSplat(SDNode *N, APInt &Imm,
330 unsigned MinSizeInBits) const {
331 if (!Subtarget->hasExtLSX())
332 return false;
333
334 BuildVectorSDNode *Node = dyn_cast<BuildVectorSDNode>(N);
335
336 if (!Node)
337 return false;
338
339 APInt SplatValue, SplatUndef;
340 unsigned SplatBitSize;
341 bool HasAnyUndefs;
342
343 if (!Node->isConstantSplat(SplatValue, SplatUndef, SplatBitSize, HasAnyUndefs,
344 MinSizeInBits, /*IsBigEndian=*/false))
345 return false;
346
347 Imm = SplatValue;
348
349 return true;
350 }
351
352 template <unsigned ImmBitSize, bool IsSigned>
selectVSplatImm(SDValue N,SDValue & SplatVal)353 bool LoongArchDAGToDAGISel::selectVSplatImm(SDValue N, SDValue &SplatVal) {
354 APInt ImmValue;
355 EVT EltTy = N->getValueType(0).getVectorElementType();
356
357 if (N->getOpcode() == ISD::BITCAST)
358 N = N->getOperand(0);
359
360 if (selectVSplat(N.getNode(), ImmValue, EltTy.getSizeInBits()) &&
361 ImmValue.getBitWidth() == EltTy.getSizeInBits()) {
362 if (IsSigned && ImmValue.isSignedIntN(ImmBitSize)) {
363 SplatVal = CurDAG->getTargetConstant(ImmValue.getSExtValue(), SDLoc(N),
364 Subtarget->getGRLenVT());
365 return true;
366 }
367 if (!IsSigned && ImmValue.isIntN(ImmBitSize)) {
368 SplatVal = CurDAG->getTargetConstant(ImmValue.getZExtValue(), SDLoc(N),
369 Subtarget->getGRLenVT());
370 return true;
371 }
372 }
373
374 return false;
375 }
376
selectVSplatUimmInvPow2(SDValue N,SDValue & SplatImm) const377 bool LoongArchDAGToDAGISel::selectVSplatUimmInvPow2(SDValue N,
378 SDValue &SplatImm) const {
379 APInt ImmValue;
380 EVT EltTy = N->getValueType(0).getVectorElementType();
381
382 if (N->getOpcode() == ISD::BITCAST)
383 N = N->getOperand(0);
384
385 if (selectVSplat(N.getNode(), ImmValue, EltTy.getSizeInBits()) &&
386 ImmValue.getBitWidth() == EltTy.getSizeInBits()) {
387 int32_t Log2 = (~ImmValue).exactLogBase2();
388
389 if (Log2 != -1) {
390 SplatImm = CurDAG->getTargetConstant(Log2, SDLoc(N), EltTy);
391 return true;
392 }
393 }
394
395 return false;
396 }
397
selectVSplatUimmPow2(SDValue N,SDValue & SplatImm) const398 bool LoongArchDAGToDAGISel::selectVSplatUimmPow2(SDValue N,
399 SDValue &SplatImm) const {
400 APInt ImmValue;
401 EVT EltTy = N->getValueType(0).getVectorElementType();
402
403 if (N->getOpcode() == ISD::BITCAST)
404 N = N->getOperand(0);
405
406 if (selectVSplat(N.getNode(), ImmValue, EltTy.getSizeInBits()) &&
407 ImmValue.getBitWidth() == EltTy.getSizeInBits()) {
408 int32_t Log2 = ImmValue.exactLogBase2();
409
410 if (Log2 != -1) {
411 SplatImm = CurDAG->getTargetConstant(Log2, SDLoc(N), EltTy);
412 return true;
413 }
414 }
415
416 return false;
417 }
418
419 // This pass converts a legalized DAG into a LoongArch-specific DAG, ready
420 // for instruction scheduling.
createLoongArchISelDag(LoongArchTargetMachine & TM)421 FunctionPass *llvm::createLoongArchISelDag(LoongArchTargetMachine &TM) {
422 return new LoongArchDAGToDAGISelLegacy(TM);
423 }
424