LLVM 20.0.0git
LoongArchISelDAGToDAG.cpp
Go to the documentation of this file.
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
19
20using namespace llvm;
21
22#define DEBUG_TYPE "loongarch-isel"
23#define PASS_NAME "LoongArch DAG->DAG Pattern Instruction Selection"
24
26
29 : SelectionDAGISelLegacy(ID, std::make_unique<LoongArchDAGToDAGISel>(TM)) {}
30
32 false)
33
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.
64 SDValue SDImm = CurDAG->getSignedTargetConstant(Inst.Imm, DL, GRLenVT);
65 switch (Inst.Opc) {
66 case LoongArch::LU12I_W:
67 Result = CurDAG->getMachineNode(Inst.Opc, DL, GRLenVT, SDImm);
68 break;
69 case LoongArch::ADDI_W:
70 case LoongArch::ORI:
71 case LoongArch::LU32I_D:
72 case LoongArch::LU52I_D:
73 Result = CurDAG->getMachineNode(Inst.Opc, DL, GRLenVT, SrcReg, SDImm);
74 break;
75 case LoongArch::BSTRINS_D:
76 Result = CurDAG->getMachineNode(
77 Inst.Opc, DL, GRLenVT,
78 {SrcReg, SrcReg,
79 CurDAG->getTargetConstant(Inst.Imm >> 32, DL, GRLenVT),
80 CurDAG->getTargetConstant(Inst.Imm & 0xFF, DL, GRLenVT)});
81 break;
82 default:
83 llvm_unreachable("unexpected opcode generated by LoongArchMatInt");
84 }
85 SrcReg = SDValue(Result, 0);
86 }
87
88 ReplaceNode(Node, Result);
89 return;
90 }
91 case ISD::FrameIndex: {
92 SDValue Imm = CurDAG->getTargetConstant(0, DL, GRLenVT);
93 int FI = cast<FrameIndexSDNode>(Node)->getIndex();
94 SDValue TFI = CurDAG->getTargetFrameIndex(FI, VT);
95 unsigned ADDIOp =
96 Subtarget->is64Bit() ? LoongArch::ADDI_D : LoongArch::ADDI_W;
97 ReplaceNode(Node, CurDAG->getMachineNode(ADDIOp, DL, VT, TFI, Imm));
98 return;
99 }
100 case ISD::BITCAST: {
101 if (VT.is128BitVector() || VT.is256BitVector()) {
102 ReplaceUses(SDValue(Node, 0), Node->getOperand(0));
103 CurDAG->RemoveDeadNode(Node);
104 return;
105 }
106 break;
107 }
108 case ISD::BUILD_VECTOR: {
109 // Select appropriate [x]vrepli.[bhwd] instructions for constant splats of
110 // 128/256-bit when LSX/LASX is enabled.
111 BuildVectorSDNode *BVN = cast<BuildVectorSDNode>(Node);
112 APInt SplatValue, SplatUndef;
113 unsigned SplatBitSize;
114 bool HasAnyUndefs;
115 unsigned Op;
116 EVT ViaVecTy;
117 bool Is128Vec = BVN->getValueType(0).is128BitVector();
118 bool Is256Vec = BVN->getValueType(0).is256BitVector();
119
120 if (!Subtarget->hasExtLSX() || (!Is128Vec && !Is256Vec))
121 break;
122 if (!BVN->isConstantSplat(SplatValue, SplatUndef, SplatBitSize,
123 HasAnyUndefs, 8))
124 break;
125
126 switch (SplatBitSize) {
127 default:
128 break;
129 case 8:
130 Op = Is256Vec ? LoongArch::PseudoXVREPLI_B : LoongArch::PseudoVREPLI_B;
131 ViaVecTy = Is256Vec ? MVT::v32i8 : MVT::v16i8;
132 break;
133 case 16:
134 Op = Is256Vec ? LoongArch::PseudoXVREPLI_H : LoongArch::PseudoVREPLI_H;
135 ViaVecTy = Is256Vec ? MVT::v16i16 : MVT::v8i16;
136 break;
137 case 32:
138 Op = Is256Vec ? LoongArch::PseudoXVREPLI_W : LoongArch::PseudoVREPLI_W;
139 ViaVecTy = Is256Vec ? MVT::v8i32 : MVT::v4i32;
140 break;
141 case 64:
142 Op = Is256Vec ? LoongArch::PseudoXVREPLI_D : LoongArch::PseudoVREPLI_D;
143 ViaVecTy = Is256Vec ? MVT::v4i64 : MVT::v2i64;
144 break;
145 }
146
147 SDNode *Res;
148 // If we have a signed 10 bit integer, we can splat it directly.
149 if (SplatValue.isSignedIntN(10)) {
150 SDValue Imm = CurDAG->getTargetConstant(SplatValue, DL,
151 ViaVecTy.getVectorElementType());
152 Res = CurDAG->getMachineNode(Op, DL, ViaVecTy, Imm);
153 ReplaceNode(Node, Res);
154 return;
155 }
156 break;
157 }
158 }
159
160 // Select the default instruction.
161 SelectCode(Node);
162}
163
165 const SDValue &Op, InlineAsm::ConstraintCode ConstraintID,
166 std::vector<SDValue> &OutOps) {
167 SDValue Base = Op;
169 CurDAG->getTargetConstant(0, SDLoc(Op), Subtarget->getGRLenVT());
170 switch (ConstraintID) {
171 default:
172 llvm_unreachable("unexpected asm memory constraint");
173 // Reg+Reg addressing.
175 Base = Op.getOperand(0);
176 Offset = Op.getOperand(1);
177 break;
178 // Reg+simm12 addressing.
181 ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Op.getOperand(1));
182 if (isIntN(12, CN->getSExtValue())) {
183 Base = Op.getOperand(0);
185 Op.getValueType());
186 }
187 }
188 break;
189 // Reg+0 addressing.
191 break;
192 // Reg+(simm14<<2) addressing.
195 ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Op.getOperand(1));
196 if (isIntN(16, CN->getSExtValue()) &&
197 isAligned(Align(4ULL), CN->getZExtValue())) {
198 Base = Op.getOperand(0);
200 Op.getValueType());
201 }
202 }
203 break;
204 }
205 OutOps.push_back(Base);
206 OutOps.push_back(Offset);
207 return false;
208}
209
211 // If this is FrameIndex, select it directly. Otherwise just let it get
212 // selected to a register independently.
213 if (auto *FIN = dyn_cast<FrameIndexSDNode>(Addr))
214 Base =
215 CurDAG->getTargetFrameIndex(FIN->getIndex(), Subtarget->getGRLenVT());
216 else
217 Base = Addr;
218 return true;
219}
220
221// Fold constant addresses.
223 SDValue &Offset) {
224 SDLoc DL(Addr);
225 MVT VT = Addr.getSimpleValueType();
226
227 if (!isa<ConstantSDNode>(Addr))
228 return false;
229
230 // If the constant is a simm12, we can fold the whole constant and use R0 as
231 // the base.
232 int64_t CVal = cast<ConstantSDNode>(Addr)->getSExtValue();
233 if (!isInt<12>(CVal))
234 return false;
235 Base = CurDAG->getRegister(LoongArch::R0, VT);
236 Offset = CurDAG->getTargetConstant(SignExtend64<12>(CVal), DL, VT);
237 return true;
238}
239
241 // If this is FrameIndex, don't select it.
242 if (isa<FrameIndexSDNode>(Addr))
243 return false;
244 Base = Addr;
245 return true;
246}
247
249 SDValue &ShAmt) {
250 // Shift instructions on LoongArch only read the lower 5 or 6 bits of the
251 // shift amount. If there is an AND on the shift amount, we can bypass it if
252 // it doesn't affect any of those bits.
253 if (N.getOpcode() == ISD::AND && isa<ConstantSDNode>(N.getOperand(1))) {
254 const APInt &AndMask = N->getConstantOperandAPInt(1);
255
256 // Since the max shift amount is a power of 2 we can subtract 1 to make a
257 // mask that covers the bits needed to represent all shift amounts.
258 assert(isPowerOf2_32(ShiftWidth) && "Unexpected max shift amount!");
259 APInt ShMask(AndMask.getBitWidth(), ShiftWidth - 1);
260
261 if (ShMask.isSubsetOf(AndMask)) {
262 ShAmt = N.getOperand(0);
263 return true;
264 }
265
266 // SimplifyDemandedBits may have optimized the mask so try restoring any
267 // bits that are known zero.
268 KnownBits Known = CurDAG->computeKnownBits(N->getOperand(0));
269 if (ShMask.isSubsetOf(AndMask | Known.Zero)) {
270 ShAmt = N.getOperand(0);
271 return true;
272 }
273 } else if (N.getOpcode() == LoongArchISD::BSTRPICK) {
274 // Similar to the above AND, if there is a BSTRPICK on the shift amount, we
275 // can bypass it.
276 assert(isPowerOf2_32(ShiftWidth) && "Unexpected max shift amount!");
277 assert(isa<ConstantSDNode>(N.getOperand(1)) && "Illegal msb operand!");
278 assert(isa<ConstantSDNode>(N.getOperand(2)) && "Illegal lsb operand!");
279 uint64_t msb = N.getConstantOperandVal(1), lsb = N.getConstantOperandVal(2);
280 if (lsb == 0 && Log2_32(ShiftWidth) <= msb + 1) {
281 ShAmt = N.getOperand(0);
282 return true;
283 }
284 } else if (N.getOpcode() == ISD::SUB &&
285 isa<ConstantSDNode>(N.getOperand(0))) {
286 uint64_t Imm = N.getConstantOperandVal(0);
287 // If we are shifting by N-X where N == 0 mod Size, then just shift by -X to
288 // generate a NEG instead of a SUB of a constant.
289 if (Imm != 0 && Imm % ShiftWidth == 0) {
290 SDLoc DL(N);
291 EVT VT = N.getValueType();
292 SDValue Zero =
293 CurDAG->getCopyFromReg(CurDAG->getEntryNode(), DL, LoongArch::R0, VT);
294 unsigned NegOpc = VT == MVT::i64 ? LoongArch::SUB_D : LoongArch::SUB_W;
295 MachineSDNode *Neg =
296 CurDAG->getMachineNode(NegOpc, DL, VT, Zero, N.getOperand(1));
297 ShAmt = SDValue(Neg, 0);
298 return true;
299 }
300 }
301
302 ShAmt = N;
303 return true;
304}
305
307 if (N.getOpcode() == ISD::SIGN_EXTEND_INREG &&
308 cast<VTSDNode>(N.getOperand(1))->getVT() == MVT::i32) {
309 Val = N.getOperand(0);
310 return true;
311 }
312 if (N.getOpcode() == LoongArchISD::BSTRPICK &&
313 N.getConstantOperandVal(1) < UINT64_C(0X1F) &&
314 N.getConstantOperandVal(2) == UINT64_C(0)) {
315 Val = N;
316 return true;
317 }
318 MVT VT = N.getSimpleValueType();
319 if (CurDAG->ComputeNumSignBits(N) > (VT.getSizeInBits() - 32)) {
320 Val = N;
321 return true;
322 }
323
324 return false;
325}
326
328 if (N.getOpcode() == ISD::AND) {
329 auto *C = dyn_cast<ConstantSDNode>(N.getOperand(1));
330 if (C && C->getZExtValue() == UINT64_C(0xFFFFFFFF)) {
331 Val = N.getOperand(0);
332 return true;
333 }
334 }
335 MVT VT = N.getSimpleValueType();
337 if (CurDAG->MaskedValueIsZero(N, Mask)) {
338 Val = N;
339 return true;
340 }
341
342 return false;
343}
344
346 unsigned MinSizeInBits) const {
347 if (!Subtarget->hasExtLSX())
348 return false;
349
350 BuildVectorSDNode *Node = dyn_cast<BuildVectorSDNode>(N);
351
352 if (!Node)
353 return false;
354
355 APInt SplatValue, SplatUndef;
356 unsigned SplatBitSize;
357 bool HasAnyUndefs;
358
359 if (!Node->isConstantSplat(SplatValue, SplatUndef, SplatBitSize, HasAnyUndefs,
360 MinSizeInBits, /*IsBigEndian=*/false))
361 return false;
362
363 Imm = SplatValue;
364
365 return true;
366}
367
368template <unsigned ImmBitSize, bool IsSigned>
370 APInt ImmValue;
371 EVT EltTy = N->getValueType(0).getVectorElementType();
372
373 if (N->getOpcode() == ISD::BITCAST)
374 N = N->getOperand(0);
375
376 if (selectVSplat(N.getNode(), ImmValue, EltTy.getSizeInBits()) &&
377 ImmValue.getBitWidth() == EltTy.getSizeInBits()) {
378 if (IsSigned && ImmValue.isSignedIntN(ImmBitSize)) {
379 SplatVal = CurDAG->getTargetConstant(ImmValue.getSExtValue(), SDLoc(N),
380 Subtarget->getGRLenVT());
381 return true;
382 }
383 if (!IsSigned && ImmValue.isIntN(ImmBitSize)) {
384 SplatVal = CurDAG->getTargetConstant(ImmValue.getZExtValue(), SDLoc(N),
385 Subtarget->getGRLenVT());
386 return true;
387 }
388 }
389
390 return false;
391}
392
394 SDValue &SplatImm) const {
395 APInt ImmValue;
396 EVT EltTy = N->getValueType(0).getVectorElementType();
397
398 if (N->getOpcode() == ISD::BITCAST)
399 N = N->getOperand(0);
400
401 if (selectVSplat(N.getNode(), ImmValue, EltTy.getSizeInBits()) &&
402 ImmValue.getBitWidth() == EltTy.getSizeInBits()) {
403 int32_t Log2 = (~ImmValue).exactLogBase2();
404
405 if (Log2 != -1) {
406 SplatImm = CurDAG->getTargetConstant(Log2, SDLoc(N), EltTy);
407 return true;
408 }
409 }
410
411 return false;
412}
413
415 SDValue &SplatImm) const {
416 APInt ImmValue;
417 EVT EltTy = N->getValueType(0).getVectorElementType();
418
419 if (N->getOpcode() == ISD::BITCAST)
420 N = N->getOperand(0);
421
422 if (selectVSplat(N.getNode(), ImmValue, EltTy.getSizeInBits()) &&
423 ImmValue.getBitWidth() == EltTy.getSizeInBits()) {
424 int32_t Log2 = ImmValue.exactLogBase2();
425
426 if (Log2 != -1) {
427 SplatImm = CurDAG->getTargetConstant(Log2, SDLoc(N), EltTy);
428 return true;
429 }
430 }
431
432 return false;
433}
434
435// This pass converts a legalized DAG into a LoongArch-specific DAG, ready
436// for instruction scheduling.
438 return new LoongArchDAGToDAGISelLegacy(TM);
439}
AMDGPU Register Bank Select
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
#define LLVM_DEBUG(...)
Definition: Debug.h:106
uint64_t Addr
#define DEBUG_TYPE
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
Definition: PassSupport.h:38
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
#define PASS_NAME
DEMANGLE_DUMP_METHOD void dump() const
Class for arbitrary precision integers.
Definition: APInt.h:78
uint64_t getZExtValue() const
Get zero extended value.
Definition: APInt.h:1520
unsigned getBitWidth() const
Return the number of bits in the APInt.
Definition: APInt.h:1468
int32_t exactLogBase2() const
Definition: APInt.h:1761
bool isSignedIntN(unsigned N) const
Check if this APInt has an N-bits signed integer value.
Definition: APInt.h:435
bool isSubsetOf(const APInt &RHS) const
This operation checks that all bits set in this APInt are also set in RHS.
Definition: APInt.h:1257
static APInt getHighBitsSet(unsigned numBits, unsigned hiBitsSet)
Constructs an APInt value that has the top hiBitsSet bits set.
Definition: APInt.h:296
bool isIntN(unsigned N) const
Check if this APInt has an N-bits unsigned integer value.
Definition: APInt.h:432
int64_t getSExtValue() const
Get sign extended value.
Definition: APInt.h:1542
A "pseudo-class" with methods for operating on BUILD_VECTORs.
bool isConstantSplat(APInt &SplatValue, APInt &SplatUndef, unsigned &SplatBitSize, bool &HasAnyUndefs, unsigned MinSplatBits=0, bool isBigEndian=false) const
Check if this is a constant splat, and if so, find the smallest element size that splats the vector.
uint64_t getZExtValue() const
int64_t getSExtValue() const
This class represents an Operation in the Expression.
FunctionPass class - This class is used to implement most global optimizations.
Definition: Pass.h:310
LoongArchDAGToDAGISelLegacy(LoongArchTargetMachine &TM)
bool selectNonFIBaseAddr(SDValue Addr, SDValue &Base)
bool selectSExti32(SDValue N, SDValue &Val)
bool SelectInlineAsmMemoryOperand(const SDValue &Op, InlineAsm::ConstraintCode ConstraintID, std::vector< SDValue > &OutOps) override
SelectInlineAsmMemoryOperand - Select the specified address as a target addressing mode,...
bool selectVSplatUimmPow2(SDValue N, SDValue &SplatImm) const
bool selectShiftMask(SDValue N, unsigned ShiftWidth, SDValue &ShAmt)
bool selectZExti32(SDValue N, SDValue &Val)
bool SelectAddrConstant(SDValue Addr, SDValue &Base, SDValue &Offset)
bool selectVSplat(SDNode *N, APInt &Imm, unsigned MinSizeInBits) const
bool selectVSplatImm(SDValue N, SDValue &SplatVal)
bool selectVSplatUimmInvPow2(SDValue N, SDValue &SplatImm) const
bool SelectBaseAddr(SDValue Addr, SDValue &Base)
Machine Value Type.
bool is128BitVector() const
Return true if this is a 128-bit vector type.
TypeSize getSizeInBits() const
Returns the size of the specified MVT in bits.
bool is256BitVector() const
Return true if this is a 256-bit vector type.
An SDNode that represents everything that will be needed to construct a MachineInstr.
Wrapper class for IR location info (IR ordering and DebugLoc) to be passed into SDNode creation funct...
Represents one node in the SelectionDAG.
EVT getValueType(unsigned ResNo) const
Return the type of a specified result.
Unlike LLVM values, Selection DAG nodes may return multiple values as the result of a computation.
MachineSDNode * getMachineNode(unsigned Opcode, const SDLoc &dl, EVT VT)
These are used for target selectors to create a new node with specified return type(s),...
SDValue getRegister(Register Reg, EVT VT)
SDValue getCopyFromReg(SDValue Chain, const SDLoc &dl, Register Reg, EVT VT)
Definition: SelectionDAG.h:825
SDValue getTargetFrameIndex(int FI, EVT VT)
Definition: SelectionDAG.h:753
SDValue getTargetConstant(uint64_t Val, const SDLoc &DL, EVT VT, bool isOpaque=false)
Definition: SelectionDAG.h:698
unsigned ComputeNumSignBits(SDValue Op, unsigned Depth=0) const
Return the number of times the sign bit of the register is replicated into the other bits.
bool isBaseWithConstantOffset(SDValue Op) const
Return true if the specified operand is an ISD::ADD with a ConstantSDNode on the right-hand side,...
KnownBits computeKnownBits(SDValue Op, unsigned Depth=0) const
Determine which bits of Op are known to be either zero or one and return them in Known.
bool MaskedValueIsZero(SDValue Op, const APInt &Mask, unsigned Depth=0) const
Return true if 'Op & Mask' is known to be zero.
SDValue getEntryNode() const
Return the token chain corresponding to the entry of the function.
Definition: SelectionDAG.h:578
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
@ C
The default llvm calling convention, compatible with C.
Definition: CallingConv.h:34
@ BITCAST
BITCAST - This operator converts between integer, vector and FP values, as if the value was stored to...
Definition: ISDOpcodes.h:954
@ FrameIndex
Definition: ISDOpcodes.h:80
@ SIGN_EXTEND_INREG
SIGN_EXTEND_INREG - This operator atomically performs a SHL/SRA pair to sign extend a small value in ...
Definition: ISDOpcodes.h:849
@ AND
Bitwise operators - logical and, logical or, logical xor.
Definition: ISDOpcodes.h:709
@ BUILD_VECTOR
BUILD_VECTOR(ELT0, ELT1, ELT2, ELT3,...) - Return a fixed-width vector with the specified,...
Definition: ISDOpcodes.h:530
InstSeq generateInstSeq(int64_t Val)
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
@ Offset
Definition: DWP.cpp:480
bool isAligned(Align Lhs, uint64_t SizeInBytes)
Checks that SizeInBytes is a multiple of the alignment.
Definition: Alignment.h:145
FunctionPass * createLoongArchISelDag(LoongArchTargetMachine &TM)
unsigned Log2_32(uint32_t Value)
Return the floor log base 2 of the specified value, -1 if the value is zero.
Definition: MathExtras.h:340
constexpr bool isPowerOf2_32(uint32_t Value)
Return true if the argument is a power of two > 0.
Definition: MathExtras.h:291
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition: Debug.cpp:163
bool isIntN(unsigned N, int64_t x)
Checks if an signed integer fits into the given (dynamic) bit width.
Definition: MathExtras.h:260
DWARFExpression::Operation Op
unsigned Log2(Align A)
Returns the log2 of the alignment.
Definition: Alignment.h:208
Implement std::hash so that hash_code can be used in STL containers.
Definition: BitVector.h:858
#define N
This struct is a compact representation of a valid (non-zero power of two) alignment.
Definition: Alignment.h:39
Extended Value Type.
Definition: ValueTypes.h:35
TypeSize getSizeInBits() const
Return the size of the specified value type in bits.
Definition: ValueTypes.h:368
bool is128BitVector() const
Return true if this is a 128-bit vector type.
Definition: ValueTypes.h:207
bool is256BitVector() const
Return true if this is a 256-bit vector type.
Definition: ValueTypes.h:212
EVT getVectorElementType() const
Given a vector type, return the type of each element.
Definition: ValueTypes.h:323