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;
117 EVT ViaVecTy;
118 bool Is128Vec = BVN->getValueType(ResNo: 0).is128BitVector();
119 bool Is256Vec = BVN->getValueType(ResNo: 0).is256BitVector();
120
121 if (!Subtarget->hasExtLSX() || (!Is128Vec && !Is256Vec))
122 break;
123 if (!BVN->isConstantSplat(SplatValue, SplatUndef, SplatBitSize,
124 HasAnyUndefs, MinSplatBits: 8))
125 break;
126
127 switch (SplatBitSize) {
128 default:
129 break;
130 case 8:
131 Op = Is256Vec ? LoongArch::PseudoXVREPLI_B : LoongArch::PseudoVREPLI_B;
132 ViaVecTy = Is256Vec ? MVT::v32i8 : MVT::v16i8;
133 break;
134 case 16:
135 Op = Is256Vec ? LoongArch::PseudoXVREPLI_H : LoongArch::PseudoVREPLI_H;
136 ViaVecTy = Is256Vec ? MVT::v16i16 : MVT::v8i16;
137 break;
138 case 32:
139 Op = Is256Vec ? LoongArch::PseudoXVREPLI_W : LoongArch::PseudoVREPLI_W;
140 ViaVecTy = Is256Vec ? MVT::v8i32 : MVT::v4i32;
141 break;
142 case 64:
143 Op = Is256Vec ? LoongArch::PseudoXVREPLI_D : LoongArch::PseudoVREPLI_D;
144 ViaVecTy = Is256Vec ? MVT::v4i64 : MVT::v2i64;
145 break;
146 }
147
148 SDNode *Res;
149 // If we have a signed 10 bit integer, we can splat it directly.
150 if (SplatValue.isSignedIntN(N: 10)) {
151 SDValue Imm = CurDAG->getTargetConstant(Val: SplatValue, DL,
152 VT: ViaVecTy.getVectorElementType());
153 Res = CurDAG->getMachineNode(Opcode: Op, dl: DL, VT: ViaVecTy, Op1: Imm);
154 ReplaceNode(F: Node, T: Res);
155 return;
156 }
157 break;
158 }
159 }
160
161 // Select the default instruction.
162 SelectCode(N: Node);
163}
164
165bool LoongArchDAGToDAGISel::SelectInlineAsmMemoryOperand(
166 const SDValue &Op, InlineAsm::ConstraintCode ConstraintID,
167 std::vector<SDValue> &OutOps) {
168 SDValue Base = Op;
169 SDValue Offset =
170 CurDAG->getTargetConstant(Val: 0, DL: SDLoc(Op), VT: Subtarget->getGRLenVT());
171 switch (ConstraintID) {
172 default:
173 llvm_unreachable("unexpected asm memory constraint");
174 // Reg+Reg addressing.
175 case InlineAsm::ConstraintCode::k:
176 Base = Op.getOperand(i: 0);
177 Offset = Op.getOperand(i: 1);
178 break;
179 // Reg+simm12 addressing.
180 case InlineAsm::ConstraintCode::m:
181 if (CurDAG->isBaseWithConstantOffset(Op)) {
182 ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Val: Op.getOperand(i: 1));
183 if (isIntN(N: 12, x: CN->getSExtValue())) {
184 Base = Op.getOperand(i: 0);
185 Offset = CurDAG->getTargetConstant(Val: CN->getZExtValue(), DL: SDLoc(Op),
186 VT: Op.getValueType());
187 }
188 }
189 break;
190 // Reg+0 addressing.
191 case InlineAsm::ConstraintCode::ZB:
192 break;
193 // Reg+(simm14<<2) addressing.
194 case InlineAsm::ConstraintCode::ZC:
195 if (CurDAG->isBaseWithConstantOffset(Op)) {
196 ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Val: Op.getOperand(i: 1));
197 if (isIntN(N: 16, x: CN->getSExtValue()) &&
198 isAligned(Lhs: Align(4ULL), SizeInBytes: CN->getZExtValue())) {
199 Base = Op.getOperand(i: 0);
200 Offset = CurDAG->getTargetConstant(Val: CN->getZExtValue(), DL: SDLoc(Op),
201 VT: Op.getValueType());
202 }
203 }
204 break;
205 }
206 OutOps.push_back(x: Base);
207 OutOps.push_back(x: Offset);
208 return false;
209}
210
211bool LoongArchDAGToDAGISel::SelectBaseAddr(SDValue Addr, SDValue &Base) {
212 // If this is FrameIndex, select it directly. Otherwise just let it get
213 // selected to a register independently.
214 if (auto *FIN = dyn_cast<FrameIndexSDNode>(Val&: Addr))
215 Base =
216 CurDAG->getTargetFrameIndex(FI: FIN->getIndex(), VT: Subtarget->getGRLenVT());
217 else
218 Base = Addr;
219 return true;
220}
221
222// Fold constant addresses.
223bool LoongArchDAGToDAGISel::SelectAddrConstant(SDValue Addr, SDValue &Base,
224 SDValue &Offset) {
225 SDLoc DL(Addr);
226 MVT VT = Addr.getSimpleValueType();
227
228 if (!isa<ConstantSDNode>(Val: Addr))
229 return false;
230
231 // If the constant is a simm12, we can fold the whole constant and use R0 as
232 // the base.
233 int64_t CVal = cast<ConstantSDNode>(Val&: Addr)->getSExtValue();
234 if (!isInt<12>(x: CVal))
235 return false;
236 Base = CurDAG->getRegister(Reg: LoongArch::R0, VT);
237 Offset = CurDAG->getSignedTargetConstant(Val: SignExtend64<12>(x: CVal), DL, VT);
238 return true;
239}
240
241bool LoongArchDAGToDAGISel::selectNonFIBaseAddr(SDValue Addr, SDValue &Base) {
242 // If this is FrameIndex, don't select it.
243 if (isa<FrameIndexSDNode>(Val: Addr))
244 return false;
245 Base = Addr;
246 return true;
247}
248
249bool LoongArchDAGToDAGISel::SelectAddrRegImm12(SDValue Addr, SDValue &Base,
250 SDValue &Offset) {
251 SDLoc DL(Addr);
252 MVT VT = Addr.getSimpleValueType();
253
254 // The address is the result of an ADD. Here we only consider reg+simm12.
255 if (CurDAG->isBaseWithConstantOffset(Op: Addr)) {
256 int64_t Imm = cast<ConstantSDNode>(Val: Addr.getOperand(i: 1))->getSExtValue();
257 if (isInt<12>(x: Imm)) {
258 Base = Addr.getOperand(i: 0);
259 Offset = CurDAG->getSignedTargetConstant(Val: SignExtend64<12>(x: Imm), DL, VT);
260 return true;
261 }
262 }
263
264 // Otherwise, we assume Addr as the base address and use constant 0 as the
265 // offset.
266 Base = Addr;
267 Offset = CurDAG->getTargetConstant(Val: 0, DL, VT);
268 return true;
269}
270
271bool LoongArchDAGToDAGISel::selectShiftMask(SDValue N, unsigned ShiftWidth,
272 SDValue &ShAmt) {
273 // Shift instructions on LoongArch only read the lower 5 or 6 bits of the
274 // shift amount. If there is an AND on the shift amount, we can bypass it if
275 // it doesn't affect any of those bits.
276 if (N.getOpcode() == ISD::AND && isa<ConstantSDNode>(Val: N.getOperand(i: 1))) {
277 const APInt &AndMask = N->getConstantOperandAPInt(Num: 1);
278
279 // Since the max shift amount is a power of 2 we can subtract 1 to make a
280 // mask that covers the bits needed to represent all shift amounts.
281 assert(isPowerOf2_32(ShiftWidth) && "Unexpected max shift amount!");
282 APInt ShMask(AndMask.getBitWidth(), ShiftWidth - 1);
283
284 if (ShMask.isSubsetOf(RHS: AndMask)) {
285 ShAmt = N.getOperand(i: 0);
286 return true;
287 }
288
289 // SimplifyDemandedBits may have optimized the mask so try restoring any
290 // bits that are known zero.
291 KnownBits Known = CurDAG->computeKnownBits(Op: N->getOperand(Num: 0));
292 if (ShMask.isSubsetOf(RHS: AndMask | Known.Zero)) {
293 ShAmt = N.getOperand(i: 0);
294 return true;
295 }
296 } else if (N.getOpcode() == LoongArchISD::BSTRPICK) {
297 // Similar to the above AND, if there is a BSTRPICK on the shift amount, we
298 // can bypass it.
299 assert(isPowerOf2_32(ShiftWidth) && "Unexpected max shift amount!");
300 assert(isa<ConstantSDNode>(N.getOperand(1)) && "Illegal msb operand!");
301 assert(isa<ConstantSDNode>(N.getOperand(2)) && "Illegal lsb operand!");
302 uint64_t msb = N.getConstantOperandVal(i: 1), lsb = N.getConstantOperandVal(i: 2);
303 if (lsb == 0 && Log2_32(Value: ShiftWidth) <= msb + 1) {
304 ShAmt = N.getOperand(i: 0);
305 return true;
306 }
307 } else if (N.getOpcode() == ISD::SUB &&
308 isa<ConstantSDNode>(Val: N.getOperand(i: 0))) {
309 uint64_t Imm = N.getConstantOperandVal(i: 0);
310 // If we are shifting by N-X where N == 0 mod Size, then just shift by -X to
311 // generate a NEG instead of a SUB of a constant.
312 if (Imm != 0 && Imm % ShiftWidth == 0) {
313 SDLoc DL(N);
314 EVT VT = N.getValueType();
315 SDValue Zero =
316 CurDAG->getCopyFromReg(Chain: CurDAG->getEntryNode(), dl: DL, Reg: LoongArch::R0, VT);
317 unsigned NegOpc = VT == MVT::i64 ? LoongArch::SUB_D : LoongArch::SUB_W;
318 MachineSDNode *Neg =
319 CurDAG->getMachineNode(Opcode: NegOpc, dl: DL, VT, Op1: Zero, Op2: N.getOperand(i: 1));
320 ShAmt = SDValue(Neg, 0);
321 return true;
322 }
323 }
324
325 ShAmt = N;
326 return true;
327}
328
329bool LoongArchDAGToDAGISel::selectSExti32(SDValue N, SDValue &Val) {
330 if (N.getOpcode() == ISD::SIGN_EXTEND_INREG &&
331 cast<VTSDNode>(Val: N.getOperand(i: 1))->getVT() == MVT::i32) {
332 Val = N.getOperand(i: 0);
333 return true;
334 }
335 if (N.getOpcode() == LoongArchISD::BSTRPICK &&
336 N.getConstantOperandVal(i: 1) < UINT64_C(0X1F) &&
337 N.getConstantOperandVal(i: 2) == UINT64_C(0)) {
338 Val = N;
339 return true;
340 }
341 MVT VT = N.getSimpleValueType();
342 if (CurDAG->ComputeNumSignBits(Op: N) > (VT.getSizeInBits() - 32)) {
343 Val = N;
344 return true;
345 }
346
347 return false;
348}
349
350bool LoongArchDAGToDAGISel::selectZExti32(SDValue N, SDValue &Val) {
351 if (N.getOpcode() == ISD::AND) {
352 auto *C = dyn_cast<ConstantSDNode>(Val: N.getOperand(i: 1));
353 if (C && C->getZExtValue() == UINT64_C(0xFFFFFFFF)) {
354 Val = N.getOperand(i: 0);
355 return true;
356 }
357 }
358 MVT VT = N.getSimpleValueType();
359 APInt Mask = APInt::getHighBitsSet(numBits: VT.getSizeInBits(), hiBitsSet: 32);
360 if (CurDAG->MaskedValueIsZero(Op: N, Mask)) {
361 Val = N;
362 return true;
363 }
364
365 return false;
366}
367
368bool LoongArchDAGToDAGISel::selectVSplat(SDNode *N, APInt &Imm,
369 unsigned MinSizeInBits) const {
370 if (!Subtarget->hasExtLSX())
371 return false;
372
373 BuildVectorSDNode *Node = dyn_cast<BuildVectorSDNode>(Val: N);
374
375 if (!Node)
376 return false;
377
378 APInt SplatValue, SplatUndef;
379 unsigned SplatBitSize;
380 bool HasAnyUndefs;
381
382 if (!Node->isConstantSplat(SplatValue, SplatUndef, SplatBitSize, HasAnyUndefs,
383 MinSplatBits: MinSizeInBits, /*IsBigEndian=*/isBigEndian: false))
384 return false;
385
386 Imm = SplatValue;
387
388 return true;
389}
390
391template <unsigned ImmBitSize, bool IsSigned>
392bool LoongArchDAGToDAGISel::selectVSplatImm(SDValue N, SDValue &SplatVal) {
393 APInt ImmValue;
394 EVT EltTy = N->getValueType(ResNo: 0).getVectorElementType();
395
396 if (N->getOpcode() == ISD::BITCAST)
397 N = N->getOperand(Num: 0);
398
399 if (selectVSplat(N: N.getNode(), Imm&: ImmValue, MinSizeInBits: EltTy.getSizeInBits()) &&
400 ImmValue.getBitWidth() == EltTy.getSizeInBits()) {
401 if (IsSigned && ImmValue.isSignedIntN(N: ImmBitSize)) {
402 SplatVal = CurDAG->getSignedTargetConstant(
403 Val: ImmValue.getSExtValue(), DL: SDLoc(N), VT: Subtarget->getGRLenVT());
404 return true;
405 }
406 if (!IsSigned && ImmValue.isIntN(N: ImmBitSize)) {
407 SplatVal = CurDAG->getTargetConstant(Val: ImmValue.getZExtValue(), DL: SDLoc(N),
408 VT: Subtarget->getGRLenVT());
409 return true;
410 }
411 }
412
413 return false;
414}
415
416bool LoongArchDAGToDAGISel::selectVSplatUimmInvPow2(SDValue N,
417 SDValue &SplatImm) const {
418 APInt ImmValue;
419 EVT EltTy = N->getValueType(ResNo: 0).getVectorElementType();
420
421 if (N->getOpcode() == ISD::BITCAST)
422 N = N->getOperand(Num: 0);
423
424 if (selectVSplat(N: N.getNode(), Imm&: ImmValue, MinSizeInBits: EltTy.getSizeInBits()) &&
425 ImmValue.getBitWidth() == EltTy.getSizeInBits()) {
426 int32_t Log2 = (~ImmValue).exactLogBase2();
427
428 if (Log2 != -1) {
429 SplatImm = CurDAG->getSignedTargetConstant(Val: Log2, DL: SDLoc(N), VT: EltTy);
430 return true;
431 }
432 }
433
434 return false;
435}
436
437bool LoongArchDAGToDAGISel::selectVSplatUimmPow2(SDValue N,
438 SDValue &SplatImm) const {
439 APInt ImmValue;
440 EVT EltTy = N->getValueType(ResNo: 0).getVectorElementType();
441
442 if (N->getOpcode() == ISD::BITCAST)
443 N = N->getOperand(Num: 0);
444
445 if (selectVSplat(N: N.getNode(), Imm&: ImmValue, MinSizeInBits: EltTy.getSizeInBits()) &&
446 ImmValue.getBitWidth() == EltTy.getSizeInBits()) {
447 int32_t Log2 = ImmValue.exactLogBase2();
448
449 if (Log2 != -1) {
450 SplatImm = CurDAG->getSignedTargetConstant(Val: Log2, DL: SDLoc(N), VT: EltTy);
451 return true;
452 }
453 }
454
455 return false;
456}
457
458// This pass converts a legalized DAG into a LoongArch-specific DAG, ready
459// for instruction scheduling.
460FunctionPass *llvm::createLoongArchISelDag(LoongArchTargetMachine &TM,
461 CodeGenOptLevel OptLevel) {
462 return new LoongArchDAGToDAGISelLegacy(TM, OptLevel);
463}
464