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