Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/llvm/lib/Target/LoongArch/LoongArchISelDAGToDAG.cpp
35269 views
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
27
LoongArchDAGToDAGISelLegacy::LoongArchDAGToDAGISelLegacy(
28
LoongArchTargetMachine &TM)
29
: SelectionDAGISelLegacy(ID, std::make_unique<LoongArchDAGToDAGISel>(TM)) {}
30
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
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
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.
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
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
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
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
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
329
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>
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
377
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
398
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.
421
FunctionPass *llvm::createLoongArchISelDag(LoongArchTargetMachine &TM) {
422
return new LoongArchDAGToDAGISelLegacy(TM);
423
}
424
425