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

source code of llvm/lib/Target/LoongArch/LoongArchISelDAGToDAG.cpp