LLVM 19.0.0git
RISCVLegalizerInfo.cpp
Go to the documentation of this file.
1//===-- RISCVLegalizerInfo.cpp ----------------------------------*- C++ -*-===//
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/// \file
9/// This file implements the targeting of the Machinelegalizer class for RISC-V.
10/// \todo This should be generated by TableGen.
11//===----------------------------------------------------------------------===//
12
13#include "RISCVLegalizerInfo.h"
16#include "RISCVSubtarget.h"
26#include "llvm/IR/Type.h"
27
28using namespace llvm;
29using namespace LegalityPredicates;
30using namespace LegalizeMutations;
31
32// Is this type supported by scalar FP arithmetic operations given the current
33// subtarget.
34static LegalityPredicate typeIsScalarFPArith(unsigned TypeIdx,
35 const RISCVSubtarget &ST) {
36 return [=, &ST](const LegalityQuery &Query) {
37 return Query.Types[TypeIdx].isScalar() &&
38 ((ST.hasStdExtF() && Query.Types[TypeIdx].getSizeInBits() == 32) ||
39 (ST.hasStdExtD() && Query.Types[TypeIdx].getSizeInBits() == 64));
40 };
41}
42
44typeIsLegalIntOrFPVec(unsigned TypeIdx,
45 std::initializer_list<LLT> IntOrFPVecTys,
46 const RISCVSubtarget &ST) {
47 LegalityPredicate P = [=, &ST](const LegalityQuery &Query) {
48 return ST.hasVInstructions() &&
49 (Query.Types[TypeIdx].getScalarSizeInBits() != 64 ||
50 ST.hasVInstructionsI64()) &&
51 (Query.Types[TypeIdx].getElementCount().getKnownMinValue() != 1 ||
52 ST.getELen() == 64);
53 };
54
55 return all(typeInSet(TypeIdx, IntOrFPVecTys), P);
56}
57
59typeIsLegalBoolVec(unsigned TypeIdx, std::initializer_list<LLT> BoolVecTys,
60 const RISCVSubtarget &ST) {
61 LegalityPredicate P = [=, &ST](const LegalityQuery &Query) {
62 return ST.hasVInstructions() &&
63 (Query.Types[TypeIdx].getElementCount().getKnownMinValue() != 1 ||
64 ST.getELen() == 64);
65 };
66 return all(typeInSet(TypeIdx, BoolVecTys), P);
67}
68
70 : STI(ST), XLen(STI.getXLen()), sXLen(LLT::scalar(XLen)) {
71 const LLT sDoubleXLen = LLT::scalar(2 * XLen);
72 const LLT p0 = LLT::pointer(0, XLen);
73 const LLT s1 = LLT::scalar(1);
74 const LLT s8 = LLT::scalar(8);
75 const LLT s16 = LLT::scalar(16);
76 const LLT s32 = LLT::scalar(32);
77 const LLT s64 = LLT::scalar(64);
78
79 const LLT nxv1s1 = LLT::scalable_vector(1, s1);
80 const LLT nxv2s1 = LLT::scalable_vector(2, s1);
81 const LLT nxv4s1 = LLT::scalable_vector(4, s1);
82 const LLT nxv8s1 = LLT::scalable_vector(8, s1);
83 const LLT nxv16s1 = LLT::scalable_vector(16, s1);
84 const LLT nxv32s1 = LLT::scalable_vector(32, s1);
85 const LLT nxv64s1 = LLT::scalable_vector(64, s1);
86
87 const LLT nxv1s8 = LLT::scalable_vector(1, s8);
88 const LLT nxv2s8 = LLT::scalable_vector(2, s8);
89 const LLT nxv4s8 = LLT::scalable_vector(4, s8);
90 const LLT nxv8s8 = LLT::scalable_vector(8, s8);
91 const LLT nxv16s8 = LLT::scalable_vector(16, s8);
92 const LLT nxv32s8 = LLT::scalable_vector(32, s8);
93 const LLT nxv64s8 = LLT::scalable_vector(64, s8);
94
95 const LLT nxv1s16 = LLT::scalable_vector(1, s16);
96 const LLT nxv2s16 = LLT::scalable_vector(2, s16);
97 const LLT nxv4s16 = LLT::scalable_vector(4, s16);
98 const LLT nxv8s16 = LLT::scalable_vector(8, s16);
99 const LLT nxv16s16 = LLT::scalable_vector(16, s16);
100 const LLT nxv32s16 = LLT::scalable_vector(32, s16);
101
102 const LLT nxv1s32 = LLT::scalable_vector(1, s32);
103 const LLT nxv2s32 = LLT::scalable_vector(2, s32);
104 const LLT nxv4s32 = LLT::scalable_vector(4, s32);
105 const LLT nxv8s32 = LLT::scalable_vector(8, s32);
106 const LLT nxv16s32 = LLT::scalable_vector(16, s32);
107
108 const LLT nxv1s64 = LLT::scalable_vector(1, s64);
109 const LLT nxv2s64 = LLT::scalable_vector(2, s64);
110 const LLT nxv4s64 = LLT::scalable_vector(4, s64);
111 const LLT nxv8s64 = LLT::scalable_vector(8, s64);
112
113 using namespace TargetOpcode;
114
115 auto BoolVecTys = {nxv1s1, nxv2s1, nxv4s1, nxv8s1, nxv16s1, nxv32s1, nxv64s1};
116
117 auto IntOrFPVecTys = {nxv1s8, nxv2s8, nxv4s8, nxv8s8, nxv16s8, nxv32s8,
118 nxv64s8, nxv1s16, nxv2s16, nxv4s16, nxv8s16, nxv16s16,
119 nxv32s16, nxv1s32, nxv2s32, nxv4s32, nxv8s32, nxv16s32,
120 nxv1s64, nxv2s64, nxv4s64, nxv8s64};
121
122 getActionDefinitionsBuilder({G_ADD, G_SUB, G_AND, G_OR, G_XOR})
123 .legalFor({s32, sXLen})
124 .legalIf(typeIsLegalIntOrFPVec(0, IntOrFPVecTys, ST))
126 .clampScalar(0, s32, sXLen);
127
129 {G_UADDE, G_UADDO, G_USUBE, G_USUBO}).lower();
130
131 getActionDefinitionsBuilder({G_SADDO, G_SSUBO}).minScalar(0, sXLen).lower();
132
133 auto &ShiftActions = getActionDefinitionsBuilder({G_ASHR, G_LSHR, G_SHL});
134 if (ST.is64Bit())
135 ShiftActions.customFor({{s32, s32}});
136 ShiftActions.legalFor({{s32, s32}, {s32, sXLen}, {sXLen, sXLen}})
137 .widenScalarToNextPow2(0)
138 .clampScalar(1, s32, sXLen)
139 .clampScalar(0, s32, sXLen)
140 .minScalarSameAs(1, 0);
141
142 auto &ExtActions =
143 getActionDefinitionsBuilder({G_ZEXT, G_SEXT, G_ANYEXT})
144 .legalIf(all(typeIsLegalIntOrFPVec(0, IntOrFPVecTys, ST),
145 typeIsLegalIntOrFPVec(1, IntOrFPVecTys, ST)));
146 if (ST.is64Bit()) {
147 ExtActions.legalFor({{sXLen, s32}});
148 getActionDefinitionsBuilder(G_SEXT_INREG)
149 .customFor({sXLen})
150 .maxScalar(0, sXLen)
151 .lower();
152 } else {
153 getActionDefinitionsBuilder(G_SEXT_INREG).maxScalar(0, sXLen).lower();
154 }
155 ExtActions.customIf(typeIsLegalBoolVec(1, BoolVecTys, ST))
156 .maxScalar(0, sXLen);
157
158 // Merge/Unmerge
159 for (unsigned Op : {G_MERGE_VALUES, G_UNMERGE_VALUES}) {
160 auto &MergeUnmergeActions = getActionDefinitionsBuilder(Op);
161 unsigned BigTyIdx = Op == G_MERGE_VALUES ? 0 : 1;
162 unsigned LitTyIdx = Op == G_MERGE_VALUES ? 1 : 0;
163 if (XLen == 32 && ST.hasStdExtD()) {
164 MergeUnmergeActions.legalIf(
165 all(typeIs(BigTyIdx, s64), typeIs(LitTyIdx, s32)));
166 }
167 MergeUnmergeActions.widenScalarToNextPow2(LitTyIdx, XLen)
168 .widenScalarToNextPow2(BigTyIdx, XLen)
169 .clampScalar(LitTyIdx, sXLen, sXLen)
170 .clampScalar(BigTyIdx, sXLen, sXLen);
171 }
172
173 getActionDefinitionsBuilder({G_FSHL, G_FSHR}).lower();
174
175 auto &RotateActions = getActionDefinitionsBuilder({G_ROTL, G_ROTR});
176 if (ST.hasStdExtZbb() || ST.hasStdExtZbkb()) {
177 RotateActions.legalFor({{s32, sXLen}, {sXLen, sXLen}});
178 // Widen s32 rotate amount to s64 so SDAG patterns will match.
179 if (ST.is64Bit())
180 RotateActions.widenScalarIf(all(typeIs(0, s32), typeIs(1, s32)),
181 changeTo(1, sXLen));
182 }
183 RotateActions.lower();
184
185 getActionDefinitionsBuilder(G_BITREVERSE).maxScalar(0, sXLen).lower();
186
189 typeIsLegalBoolVec(0, BoolVecTys, ST)),
191 typeIsLegalBoolVec(1, BoolVecTys, ST))));
192
193 auto &BSWAPActions = getActionDefinitionsBuilder(G_BSWAP);
194 if (ST.hasStdExtZbb() || ST.hasStdExtZbkb())
195 BSWAPActions.legalFor({sXLen}).clampScalar(0, sXLen, sXLen);
196 else
197 BSWAPActions.maxScalar(0, sXLen).lower();
198
199 auto &CountZerosActions = getActionDefinitionsBuilder({G_CTLZ, G_CTTZ});
200 auto &CountZerosUndefActions =
201 getActionDefinitionsBuilder({G_CTLZ_ZERO_UNDEF, G_CTTZ_ZERO_UNDEF});
202 if (ST.hasStdExtZbb()) {
203 CountZerosActions.legalFor({{s32, s32}, {sXLen, sXLen}})
204 .clampScalar(0, s32, sXLen)
206 .scalarSameSizeAs(1, 0);
207 } else {
208 CountZerosActions.maxScalar(0, sXLen).scalarSameSizeAs(1, 0).lower();
209 CountZerosUndefActions.maxScalar(0, sXLen).scalarSameSizeAs(1, 0);
210 }
211 CountZerosUndefActions.lower();
212
213 auto &CTPOPActions = getActionDefinitionsBuilder(G_CTPOP);
214 if (ST.hasStdExtZbb()) {
215 CTPOPActions.legalFor({{s32, s32}, {sXLen, sXLen}})
216 .clampScalar(0, s32, sXLen)
217 .widenScalarToNextPow2(0)
218 .scalarSameSizeAs(1, 0);
219 } else {
220 CTPOPActions.maxScalar(0, sXLen).scalarSameSizeAs(1, 0).lower();
221 }
222
223 auto &ConstantActions = getActionDefinitionsBuilder(G_CONSTANT);
224 ConstantActions.legalFor({s32, p0});
225 if (ST.is64Bit())
226 ConstantActions.customFor({s64});
227 ConstantActions.widenScalarToNextPow2(0).clampScalar(0, s32, sXLen);
228
229 // TODO: transform illegal vector types into legal vector type
230 getActionDefinitionsBuilder(G_IMPLICIT_DEF)
231 .legalFor({s32, sXLen, p0})
232 .legalIf(typeIsLegalBoolVec(0, BoolVecTys, ST))
233 .legalIf(typeIsLegalIntOrFPVec(0, IntOrFPVecTys, ST))
235 .clampScalar(0, s32, sXLen);
236
238 .legalFor({{sXLen, sXLen}, {sXLen, p0}})
239 .legalIf(all(typeIsLegalBoolVec(0, BoolVecTys, ST),
240 typeIsLegalIntOrFPVec(1, IntOrFPVecTys, ST)))
242 .clampScalar(1, sXLen, sXLen)
243 .clampScalar(0, sXLen, sXLen);
244
245 auto &SelectActions =
247 .legalFor({{s32, sXLen}, {p0, sXLen}})
248 .legalIf(all(typeIsLegalIntOrFPVec(0, IntOrFPVecTys, ST),
249 typeIsLegalBoolVec(1, BoolVecTys, ST)));
250 if (XLen == 64 || ST.hasStdExtD())
251 SelectActions.legalFor({{s64, sXLen}});
252 SelectActions.widenScalarToNextPow2(0)
253 .clampScalar(0, s32, (XLen == 64 || ST.hasStdExtD()) ? s64 : s32)
254 .clampScalar(1, sXLen, sXLen);
255
256 auto &LoadStoreActions =
257 getActionDefinitionsBuilder({G_LOAD, G_STORE})
258 .legalForTypesWithMemDesc({{s32, p0, s8, 8},
259 {s32, p0, s16, 16},
260 {s32, p0, s32, 32},
261 {p0, p0, sXLen, XLen}});
262 auto &ExtLoadActions =
263 getActionDefinitionsBuilder({G_SEXTLOAD, G_ZEXTLOAD})
264 .legalForTypesWithMemDesc({{s32, p0, s8, 8}, {s32, p0, s16, 16}});
265 if (XLen == 64) {
266 LoadStoreActions.legalForTypesWithMemDesc({{s64, p0, s8, 8},
267 {s64, p0, s16, 16},
268 {s64, p0, s32, 32},
269 {s64, p0, s64, 64}});
270 ExtLoadActions.legalForTypesWithMemDesc(
271 {{s64, p0, s8, 8}, {s64, p0, s16, 16}, {s64, p0, s32, 32}});
272 } else if (ST.hasStdExtD()) {
273 LoadStoreActions.legalForTypesWithMemDesc({{s64, p0, s64, 64}});
274 }
275 LoadStoreActions.clampScalar(0, s32, sXLen).lower();
276 ExtLoadActions.widenScalarToNextPow2(0).clampScalar(0, s32, sXLen).lower();
277
278 getActionDefinitionsBuilder({G_PTR_ADD, G_PTRMASK}).legalFor({{p0, sXLen}});
279
281 .legalFor({{sXLen, p0}})
282 .clampScalar(0, sXLen, sXLen);
283
285 .legalFor({{p0, sXLen}})
286 .clampScalar(1, sXLen, sXLen);
287
288 getActionDefinitionsBuilder(G_BRCOND).legalFor({sXLen}).minScalar(0, sXLen);
289
290 getActionDefinitionsBuilder(G_BRJT).legalFor({{p0, sXLen}});
291
292 getActionDefinitionsBuilder(G_BRINDIRECT).legalFor({p0});
293
295 .legalFor({p0, sXLen})
296 .widenScalarToNextPow2(0)
297 .clampScalar(0, sXLen, sXLen);
298
299 getActionDefinitionsBuilder({G_GLOBAL_VALUE, G_JUMP_TABLE, G_CONSTANT_POOL})
300 .legalFor({p0});
301
302 if (ST.hasStdExtM() || ST.hasStdExtZmmul()) {
304 .legalFor({s32, sXLen})
305 .widenScalarToNextPow2(0)
306 .clampScalar(0, s32, sXLen);
307
308 // clang-format off
309 getActionDefinitionsBuilder({G_SMULH, G_UMULH})
310 .legalFor({sXLen})
311 .lower();
312 // clang-format on
313
314 getActionDefinitionsBuilder({G_SMULO, G_UMULO}).minScalar(0, sXLen).lower();
315 } else {
317 .libcallFor({sXLen, sDoubleXLen})
318 .widenScalarToNextPow2(0)
319 .clampScalar(0, sXLen, sDoubleXLen);
320
321 getActionDefinitionsBuilder({G_SMULH, G_UMULH}).lowerFor({sXLen});
322
323 getActionDefinitionsBuilder({G_SMULO, G_UMULO})
324 .minScalar(0, sXLen)
325 // Widen sXLen to sDoubleXLen so we can use a single libcall to get
326 // the low bits for the mul result and high bits to do the overflow
327 // check.
328 .widenScalarIf(typeIs(0, sXLen),
329 LegalizeMutations::changeTo(0, sDoubleXLen))
330 .lower();
331 }
332
333 if (ST.hasStdExtM()) {
334 getActionDefinitionsBuilder({G_UDIV, G_SDIV, G_UREM, G_SREM})
335 .legalFor({s32, sXLen})
336 .libcallFor({sDoubleXLen})
337 .clampScalar(0, s32, sDoubleXLen)
339 } else {
340 getActionDefinitionsBuilder({G_UDIV, G_SDIV, G_UREM, G_SREM})
341 .libcallFor({sXLen, sDoubleXLen})
342 .clampScalar(0, sXLen, sDoubleXLen)
344 }
345
346 auto &AbsActions = getActionDefinitionsBuilder(G_ABS);
347 if (ST.hasStdExtZbb())
348 AbsActions.customFor({s32, sXLen}).minScalar(0, sXLen);
349 AbsActions.lower();
350
351 auto &MinMaxActions =
352 getActionDefinitionsBuilder({G_UMAX, G_UMIN, G_SMAX, G_SMIN});
353 if (ST.hasStdExtZbb())
354 MinMaxActions.legalFor({sXLen}).minScalar(0, sXLen);
355 MinMaxActions.lower();
356
357 getActionDefinitionsBuilder(G_FRAME_INDEX).legalFor({p0});
358
359 getActionDefinitionsBuilder({G_MEMCPY, G_MEMMOVE, G_MEMSET}).libcall();
360
361 getActionDefinitionsBuilder(G_DYN_STACKALLOC).lower();
362
363 // FP Operations
364
365 getActionDefinitionsBuilder({G_FADD, G_FSUB, G_FMUL, G_FDIV, G_FMA, G_FNEG,
366 G_FABS, G_FSQRT, G_FMAXNUM, G_FMINNUM})
367 .legalIf(typeIsScalarFPArith(0, ST));
368
369 getActionDefinitionsBuilder(G_FCOPYSIGN)
371
373 [=, &ST](const LegalityQuery &Query) -> bool {
374 return (ST.hasStdExtD() && typeIs(0, s32)(Query) &&
375 typeIs(1, s64)(Query));
376 });
378 [=, &ST](const LegalityQuery &Query) -> bool {
379 return (ST.hasStdExtD() && typeIs(0, s64)(Query) &&
380 typeIs(1, s32)(Query));
381 });
382
384 .legalIf(all(typeIs(0, sXLen), typeIsScalarFPArith(1, ST)))
385 .clampScalar(0, sXLen, sXLen);
386
387 // TODO: Support vector version of G_IS_FPCLASS.
388 getActionDefinitionsBuilder(G_IS_FPCLASS)
389 .customIf(all(typeIs(0, s1), typeIsScalarFPArith(1, ST)));
390
391 getActionDefinitionsBuilder(G_FCONSTANT)
393 .lowerFor({s32, s64});
394
395 getActionDefinitionsBuilder({G_FPTOSI, G_FPTOUI})
396 .legalIf(all(typeInSet(0, {s32, sXLen}), typeIsScalarFPArith(1, ST)))
398 .clampScalar(0, s32, sXLen);
399
400 getActionDefinitionsBuilder({G_SITOFP, G_UITOFP})
401 .legalIf(all(typeIsScalarFPArith(0, ST), typeInSet(1, {s32, sXLen})))
403 .clampScalar(1, s32, sXLen);
404
405 // FIXME: We can do custom inline expansion like SelectionDAG.
406 // FIXME: Legal with Zfa.
407 getActionDefinitionsBuilder({G_FCEIL, G_FFLOOR})
408 .libcallFor({s32, s64});
409
410 getActionDefinitionsBuilder(G_VASTART).customFor({p0});
411
412 // va_list must be a pointer, but most sized types are pretty easy to handle
413 // as the destination.
415 // TODO: Implement narrowScalar and widenScalar for G_VAARG for types
416 // outside the [s32, sXLen] range.
417 .clampScalar(0, s32, sXLen)
418 .lowerForCartesianProduct({s32, sXLen, p0}, {p0});
419
421 .clampScalar(0, sXLen, sXLen)
422 .customFor({sXLen});
423
424 auto &SplatActions =
425 getActionDefinitionsBuilder(G_SPLAT_VECTOR)
426 .legalIf(all(typeIsLegalIntOrFPVec(0, IntOrFPVecTys, ST),
427 typeIs(1, sXLen)))
428 .customIf(all(typeIsLegalBoolVec(0, BoolVecTys, ST), typeIs(1, s1)));
429 // Handle case of s64 element vectors on RV32. If the subtarget does not have
430 // f64, then try to lower it to G_SPLAT_VECTOR_SPLIT_64_VL. If the subtarget
431 // does have f64, then we don't know whether the type is an f64 or an i64,
432 // so mark the G_SPLAT_VECTOR as legal and decide later what to do with it,
433 // depending on how the instructions it consumes are legalized. They are not
434 // legalized yet since legalization is in reverse postorder, so we cannot
435 // make the decision at this moment.
436 if (XLen == 32) {
437 if (ST.hasVInstructionsF64() && ST.hasStdExtD())
438 SplatActions.legalIf(all(
439 typeInSet(0, {nxv1s64, nxv2s64, nxv4s64, nxv8s64}), typeIs(1, s64)));
440 else if (ST.hasVInstructionsI64())
441 SplatActions.customIf(all(
442 typeInSet(0, {nxv1s64, nxv2s64, nxv4s64, nxv8s64}), typeIs(1, s64)));
443 }
444
445 SplatActions.clampScalar(1, sXLen, sXLen);
446
448}
449
451 if (Ty.isVector())
453 Ty.getNumElements());
454 return IntegerType::get(C, Ty.getSizeInBits());
455}
456
458 MachineInstr &MI) const {
459 Intrinsic::ID IntrinsicID = cast<GIntrinsic>(MI).getIntrinsicID();
460 switch (IntrinsicID) {
461 default:
462 return false;
463 case Intrinsic::vacopy: {
464 // vacopy arguments must be legal because of the intrinsic signature.
465 // No need to check here.
466
467 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
468 MachineRegisterInfo &MRI = *MIRBuilder.getMRI();
469 MachineFunction &MF = *MI.getMF();
470 const DataLayout &DL = MIRBuilder.getDataLayout();
471 LLVMContext &Ctx = MF.getFunction().getContext();
472
473 Register DstLst = MI.getOperand(1).getReg();
474 LLT PtrTy = MRI.getType(DstLst);
475
476 // Load the source va_list
477 Align Alignment = DL.getABITypeAlign(getTypeForLLT(PtrTy, Ctx));
479 MachinePointerInfo(), MachineMemOperand::MOLoad, PtrTy, Alignment);
480 auto Tmp = MIRBuilder.buildLoad(PtrTy, MI.getOperand(2), *LoadMMO);
481
482 // Store the result in the destination va_list
485 MIRBuilder.buildStore(Tmp, DstLst, *StoreMMO);
486
487 MI.eraseFromParent();
488 return true;
489 }
490 }
491}
492
493bool RISCVLegalizerInfo::legalizeShlAshrLshr(
494 MachineInstr &MI, MachineIRBuilder &MIRBuilder,
495 GISelChangeObserver &Observer) const {
496 assert(MI.getOpcode() == TargetOpcode::G_ASHR ||
497 MI.getOpcode() == TargetOpcode::G_LSHR ||
498 MI.getOpcode() == TargetOpcode::G_SHL);
499 MachineRegisterInfo &MRI = *MIRBuilder.getMRI();
500 // If the shift amount is a G_CONSTANT, promote it to a 64 bit type so the
501 // imported patterns can select it later. Either way, it will be legal.
502 Register AmtReg = MI.getOperand(2).getReg();
503 auto VRegAndVal = getIConstantVRegValWithLookThrough(AmtReg, MRI);
504 if (!VRegAndVal)
505 return true;
506 // Check the shift amount is in range for an immediate form.
507 uint64_t Amount = VRegAndVal->Value.getZExtValue();
508 if (Amount > 31)
509 return true; // This will have to remain a register variant.
510 auto ExtCst = MIRBuilder.buildConstant(LLT::scalar(64), Amount);
511 Observer.changingInstr(MI);
512 MI.getOperand(2).setReg(ExtCst.getReg(0));
513 Observer.changedInstr(MI);
514 return true;
515}
516
517bool RISCVLegalizerInfo::legalizeVAStart(MachineInstr &MI,
518 MachineIRBuilder &MIRBuilder) const {
519 // Stores the address of the VarArgsFrameIndex slot into the memory location
520 assert(MI.getOpcode() == TargetOpcode::G_VASTART);
521 MachineFunction *MF = MI.getParent()->getParent();
523 int FI = FuncInfo->getVarArgsFrameIndex();
524 LLT AddrTy = MIRBuilder.getMRI()->getType(MI.getOperand(0).getReg());
525 auto FINAddr = MIRBuilder.buildFrameIndex(AddrTy, FI);
526 assert(MI.hasOneMemOperand());
527 MIRBuilder.buildStore(FINAddr, MI.getOperand(0).getReg(),
528 *MI.memoperands()[0]);
529 MI.eraseFromParent();
530 return true;
531}
532
533bool RISCVLegalizerInfo::shouldBeInConstantPool(APInt APImm,
534 bool ShouldOptForSize) const {
535 assert(APImm.getBitWidth() == 32 || APImm.getBitWidth() == 64);
536 int64_t Imm = APImm.getSExtValue();
537 // All simm32 constants should be handled by isel.
538 // NOTE: The getMaxBuildIntsCost call below should return a value >= 2 making
539 // this check redundant, but small immediates are common so this check
540 // should have better compile time.
541 if (isInt<32>(Imm))
542 return false;
543
544 // We only need to cost the immediate, if constant pool lowering is enabled.
546 return false;
547
549 if (Seq.size() <= STI.getMaxBuildIntsCost())
550 return false;
551
552 // Optimizations below are disabled for opt size. If we're optimizing for
553 // size, use a constant pool.
554 if (ShouldOptForSize)
555 return true;
556 //
557 // Special case. See if we can build the constant as (ADD (SLLI X, C), X) do
558 // that if it will avoid a constant pool.
559 // It will require an extra temporary register though.
560 // If we have Zba we can use (ADD_UW X, (SLLI X, 32)) to handle cases where
561 // low and high 32 bits are the same and bit 31 and 63 are set.
562 unsigned ShiftAmt, AddOpc;
564 RISCVMatInt::generateTwoRegInstSeq(Imm, STI, ShiftAmt, AddOpc);
565 return !(!SeqLo.empty() && (SeqLo.size() + 2) <= STI.getMaxBuildIntsCost());
566}
567
568bool RISCVLegalizerInfo::legalizeVScale(MachineInstr &MI,
569 MachineIRBuilder &MIB) const {
570 const LLT XLenTy(STI.getXLenVT());
571 Register Dst = MI.getOperand(0).getReg();
572
573 // We define our scalable vector types for lmul=1 to use a 64 bit known
574 // minimum size. e.g. <vscale x 2 x i32>. VLENB is in bytes so we calculate
575 // vscale as VLENB / 8.
576 static_assert(RISCV::RVVBitsPerBlock == 64, "Unexpected bits per block!");
578 // Support for VLEN==32 is incomplete.
579 return false;
580
581 // We assume VLENB is a multiple of 8. We manually choose the best shift
582 // here because SimplifyDemandedBits isn't always able to simplify it.
583 uint64_t Val = MI.getOperand(1).getCImm()->getZExtValue();
584 if (isPowerOf2_64(Val)) {
585 uint64_t Log2 = Log2_64(Val);
586 if (Log2 < 3) {
587 auto VLENB = MIB.buildInstr(RISCV::G_READ_VLENB, {XLenTy}, {});
588 MIB.buildLShr(Dst, VLENB, MIB.buildConstant(XLenTy, 3 - Log2));
589 } else if (Log2 > 3) {
590 auto VLENB = MIB.buildInstr(RISCV::G_READ_VLENB, {XLenTy}, {});
591 MIB.buildShl(Dst, VLENB, MIB.buildConstant(XLenTy, Log2 - 3));
592 } else {
593 MIB.buildInstr(RISCV::G_READ_VLENB, {Dst}, {});
594 }
595 } else if ((Val % 8) == 0) {
596 // If the multiplier is a multiple of 8, scale it down to avoid needing
597 // to shift the VLENB value.
598 auto VLENB = MIB.buildInstr(RISCV::G_READ_VLENB, {XLenTy}, {});
599 MIB.buildMul(Dst, VLENB, MIB.buildConstant(XLenTy, Val / 8));
600 } else {
601 auto VLENB = MIB.buildInstr(RISCV::G_READ_VLENB, {XLenTy}, {});
602 auto VScale = MIB.buildLShr(XLenTy, VLENB, MIB.buildConstant(XLenTy, 3));
603 MIB.buildMul(Dst, VScale, MIB.buildConstant(XLenTy, Val));
604 }
605 MI.eraseFromParent();
606 return true;
607}
608
609// Custom-lower extensions from mask vectors by using a vselect either with 1
610// for zero/any-extension or -1 for sign-extension:
611// (vXiN = (s|z)ext vXi1:vmask) -> (vXiN = vselect vmask, (-1 or 1), 0)
612// Note that any-extension is lowered identically to zero-extension.
613bool RISCVLegalizerInfo::legalizeExt(MachineInstr &MI,
614 MachineIRBuilder &MIB) const {
615
616 unsigned Opc = MI.getOpcode();
617 assert(Opc == TargetOpcode::G_ZEXT || Opc == TargetOpcode::G_SEXT ||
618 Opc == TargetOpcode::G_ANYEXT);
619
621 Register Dst = MI.getOperand(0).getReg();
622 Register Src = MI.getOperand(1).getReg();
623
624 LLT DstTy = MRI.getType(Dst);
625 int64_t ExtTrueVal = Opc == TargetOpcode::G_SEXT ? -1 : 1;
626 LLT DstEltTy = DstTy.getElementType();
627 auto SplatZero = MIB.buildSplatVector(DstTy, MIB.buildConstant(DstEltTy, 0));
628 auto SplatTrue =
629 MIB.buildSplatVector(DstTy, MIB.buildConstant(DstEltTy, ExtTrueVal));
630 MIB.buildSelect(Dst, Src, SplatTrue, SplatZero);
631
632 MI.eraseFromParent();
633 return true;
634}
635
636/// Return the type of the mask type suitable for masking the provided
637/// vector type. This is simply an i1 element type vector of the same
638/// (possibly scalable) length.
639static LLT getMaskTypeFor(LLT VecTy) {
640 assert(VecTy.isVector());
641 ElementCount EC = VecTy.getElementCount();
642 return LLT::vector(EC, LLT::scalar(1));
643}
644
645/// Creates an all ones mask suitable for masking a vector of type VecTy with
646/// vector length VL.
648 MachineIRBuilder &MIB,
650 LLT MaskTy = getMaskTypeFor(VecTy);
651 return MIB.buildInstr(RISCV::G_VMSET_VL, {MaskTy}, {VL});
652}
653
654/// Gets the two common "VL" operands: an all-ones mask and the vector length.
655/// VecTy is a scalable vector type.
656static std::pair<MachineInstrBuilder, Register>
659 LLT VecTy = Dst.getLLTTy(MRI);
660 assert(VecTy.isScalableVector() && "Expecting scalable container type");
661 Register VL(RISCV::X0);
662 MachineInstrBuilder Mask = buildAllOnesMask(VecTy, VL, MIB, MRI);
663 return {Mask, VL};
664}
665
667buildSplatPartsS64WithVL(const DstOp &Dst, const SrcOp &Passthru, Register Lo,
670 // TODO: If the Hi bits of the splat are undefined, then it's fine to just
671 // splat Lo even if it might be sign extended. I don't think we have
672 // introduced a case where we're build a s64 where the upper bits are undef
673 // yet.
674
675 // Fall back to a stack store and stride x0 vector load.
676 // TODO: need to lower G_SPLAT_VECTOR_SPLIT_I64. This is done in
677 // preprocessDAG in SDAG.
678 return MIB.buildInstr(RISCV::G_SPLAT_VECTOR_SPLIT_I64_VL, {Dst},
679 {Passthru, Lo, Hi, VL});
680}
681
683buildSplatSplitS64WithVL(const DstOp &Dst, const SrcOp &Passthru,
684 const SrcOp &Scalar, Register VL,
686 assert(Scalar.getLLTTy(MRI) == LLT::scalar(64) && "Unexpected VecTy!");
687 auto Unmerge = MIB.buildUnmerge(LLT::scalar(32), Scalar);
688 return buildSplatPartsS64WithVL(Dst, Passthru, Unmerge.getReg(0),
689 Unmerge.getReg(1), VL, MIB, MRI);
690}
691
692// Lower splats of s1 types to G_ICMP. For each mask vector type, we have a
693// legal equivalently-sized i8 type, so we can use that as a go-between.
694// Splats of s1 types that have constant value can be legalized as VMSET_VL or
695// VMCLR_VL.
696bool RISCVLegalizerInfo::legalizeSplatVector(MachineInstr &MI,
697 MachineIRBuilder &MIB) const {
698 assert(MI.getOpcode() == TargetOpcode::G_SPLAT_VECTOR);
699
701
702 Register Dst = MI.getOperand(0).getReg();
703 Register SplatVal = MI.getOperand(1).getReg();
704
705 LLT VecTy = MRI.getType(Dst);
706 LLT XLenTy(STI.getXLenVT());
707
708 // Handle case of s64 element vectors on rv32
709 if (XLenTy.getSizeInBits() == 32 &&
710 VecTy.getElementType().getSizeInBits() == 64) {
711 auto [_, VL] = buildDefaultVLOps(Dst, MIB, MRI);
712 buildSplatSplitS64WithVL(Dst, MIB.buildUndef(VecTy), SplatVal, VL, MIB,
713 MRI);
714 MI.eraseFromParent();
715 return true;
716 }
717
718 // All-zeros or all-ones splats are handled specially.
719 MachineInstr &SplatValMI = *MRI.getVRegDef(SplatVal);
720 if (isAllOnesOrAllOnesSplat(SplatValMI, MRI)) {
721 auto VL = buildDefaultVLOps(VecTy, MIB, MRI).second;
722 MIB.buildInstr(RISCV::G_VMSET_VL, {Dst}, {VL});
723 MI.eraseFromParent();
724 return true;
725 }
726 if (isNullOrNullSplat(SplatValMI, MRI)) {
727 auto VL = buildDefaultVLOps(VecTy, MIB, MRI).second;
728 MIB.buildInstr(RISCV::G_VMCLR_VL, {Dst}, {VL});
729 MI.eraseFromParent();
730 return true;
731 }
732
733 // Handle non-constant mask splat (i.e. not sure if it's all zeros or all
734 // ones) by promoting it to an s8 splat.
735 LLT InterEltTy = LLT::scalar(8);
736 LLT InterTy = VecTy.changeElementType(InterEltTy);
737 auto ZExtSplatVal = MIB.buildZExt(InterEltTy, SplatVal);
738 auto And =
739 MIB.buildAnd(InterEltTy, ZExtSplatVal, MIB.buildConstant(InterEltTy, 1));
740 auto LHS = MIB.buildSplatVector(InterTy, And);
741 auto ZeroSplat =
742 MIB.buildSplatVector(InterTy, MIB.buildConstant(InterEltTy, 0));
743 MIB.buildICmp(CmpInst::Predicate::ICMP_NE, Dst, LHS, ZeroSplat);
744 MI.eraseFromParent();
745 return true;
746}
747
750 LostDebugLocObserver &LocObserver) const {
751 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
752 GISelChangeObserver &Observer = Helper.Observer;
753 MachineFunction &MF = *MI.getParent()->getParent();
754 switch (MI.getOpcode()) {
755 default:
756 // No idea what to do.
757 return false;
758 case TargetOpcode::G_ABS:
759 return Helper.lowerAbsToMaxNeg(MI);
760 // TODO: G_FCONSTANT
761 case TargetOpcode::G_CONSTANT: {
762 const Function &F = MF.getFunction();
763 // TODO: if PSI and BFI are present, add " ||
764 // llvm::shouldOptForSize(*CurMBB, PSI, BFI)".
765 bool ShouldOptForSize = F.hasOptSize() || F.hasMinSize();
766 const ConstantInt *ConstVal = MI.getOperand(1).getCImm();
767 if (!shouldBeInConstantPool(ConstVal->getValue(), ShouldOptForSize))
768 return true;
769 return Helper.lowerConstant(MI);
770 }
771 case TargetOpcode::G_SHL:
772 case TargetOpcode::G_ASHR:
773 case TargetOpcode::G_LSHR:
774 return legalizeShlAshrLshr(MI, MIRBuilder, Observer);
775 case TargetOpcode::G_SEXT_INREG: {
776 // Source size of 32 is sext.w.
777 int64_t SizeInBits = MI.getOperand(2).getImm();
778 if (SizeInBits == 32)
779 return true;
780
781 return Helper.lower(MI, 0, /* Unused hint type */ LLT()) ==
783 }
784 case TargetOpcode::G_IS_FPCLASS: {
785 Register GISFPCLASS = MI.getOperand(0).getReg();
786 Register Src = MI.getOperand(1).getReg();
787 const MachineOperand &ImmOp = MI.getOperand(2);
788 MachineIRBuilder MIB(MI);
789
790 // Turn LLVM IR's floating point classes to that in RISC-V,
791 // by simply rotating the 10-bit immediate right by two bits.
792 APInt GFpClassImm(10, static_cast<uint64_t>(ImmOp.getImm()));
793 auto FClassMask = MIB.buildConstant(sXLen, GFpClassImm.rotr(2).zext(XLen));
794 auto ConstZero = MIB.buildConstant(sXLen, 0);
795
796 auto GFClass = MIB.buildInstr(RISCV::G_FCLASS, {sXLen}, {Src});
797 auto And = MIB.buildAnd(sXLen, GFClass, FClassMask);
798 MIB.buildICmp(CmpInst::ICMP_NE, GISFPCLASS, And, ConstZero);
799
800 MI.eraseFromParent();
801 return true;
802 }
803 case TargetOpcode::G_VASTART:
804 return legalizeVAStart(MI, MIRBuilder);
805 case TargetOpcode::G_VSCALE:
806 return legalizeVScale(MI, MIRBuilder);
807 case TargetOpcode::G_ZEXT:
808 case TargetOpcode::G_SEXT:
809 case TargetOpcode::G_ANYEXT:
810 return legalizeExt(MI, MIRBuilder);
811 case TargetOpcode::G_SPLAT_VECTOR:
812 return legalizeSplatVector(MI, MIRBuilder);
813 }
814
815 llvm_unreachable("expected switch to return");
816}
unsigned const MachineRegisterInfo * MRI
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
static Type * getTypeForLLT(LLT Ty, LLVMContext &C)
Declares convenience wrapper classes for interpreting MachineInstr instances as specific generic oper...
#define _
IRTranslator LLVM IR MI
#define F(x, y, z)
Definition: MD5.cpp:55
This file declares the MachineConstantPool class which is an abstract constant pool to keep track of ...
This file declares the MachineIRBuilder class.
#define P(N)
static MachineInstrBuilder buildAllOnesMask(LLT VecTy, const SrcOp &VL, MachineIRBuilder &MIB, MachineRegisterInfo &MRI)
Creates an all ones mask suitable for masking a vector of type VecTy with vector length VL.
static LegalityPredicate typeIsLegalBoolVec(unsigned TypeIdx, std::initializer_list< LLT > BoolVecTys, const RISCVSubtarget &ST)
static LegalityPredicate typeIsScalarFPArith(unsigned TypeIdx, const RISCVSubtarget &ST)
static LegalityPredicate typeIsLegalIntOrFPVec(unsigned TypeIdx, std::initializer_list< LLT > IntOrFPVecTys, const RISCVSubtarget &ST)
static MachineInstrBuilder buildSplatPartsS64WithVL(const DstOp &Dst, const SrcOp &Passthru, Register Lo, Register Hi, Register VL, MachineIRBuilder &MIB, MachineRegisterInfo &MRI)
static MachineInstrBuilder buildSplatSplitS64WithVL(const DstOp &Dst, const SrcOp &Passthru, const SrcOp &Scalar, Register VL, MachineIRBuilder &MIB, MachineRegisterInfo &MRI)
static std::pair< MachineInstrBuilder, Register > buildDefaultVLOps(const DstOp &Dst, MachineIRBuilder &MIB, MachineRegisterInfo &MRI)
Gets the two common "VL" operands: an all-ones mask and the vector length.
static LLT getMaskTypeFor(LLT VecTy)
Return the type of the mask type suitable for masking the provided vector type.
This file declares the targeting of the Machinelegalizer class for RISC-V.
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
Value * LHS
Class for arbitrary precision integers.
Definition: APInt.h:76
APInt zext(unsigned width) const
Zero extend to a new width.
Definition: APInt.cpp:981
unsigned getBitWidth() const
Return the number of bits in the APInt.
Definition: APInt.h:1439
APInt rotr(unsigned rotateAmt) const
Rotate right by rotateAmt.
Definition: APInt.cpp:1124
int64_t getSExtValue() const
Get sign extended value.
Definition: APInt.h:1513
@ ICMP_NE
not equal
Definition: InstrTypes.h:1015
This is the shared class of boolean and integer constants.
Definition: Constants.h:80
const APInt & getValue() const
Return the constant as an APInt value reference.
Definition: Constants.h:145
This class represents an Operation in the Expression.
A parsed version of the target data layout string in and methods for querying it.
Definition: DataLayout.h:110
static FixedVectorType * get(Type *ElementType, unsigned NumElts)
Definition: Type.cpp:692
LLVMContext & getContext() const
getContext - Return a reference to the LLVMContext associated with this function.
Definition: Function.cpp:356
Abstract class that contains various methods for clients to notify about changes.
virtual void changingInstr(MachineInstr &MI)=0
This instruction is about to be mutated in some way.
virtual void changedInstr(MachineInstr &MI)=0
This instruction was mutated in some way.
static IntegerType * get(LLVMContext &C, unsigned NumBits)
This static method is the primary way of constructing an IntegerType.
Definition: Type.cpp:278
constexpr bool isScalableVector() const
Returns true if the LLT is a scalable vector.
Definition: LowLevelType.h:182
constexpr unsigned getScalarSizeInBits() const
Definition: LowLevelType.h:267
static constexpr LLT scalable_vector(unsigned MinNumElements, unsigned ScalarSizeInBits)
Get a low-level scalable vector of some number of elements and element width.
Definition: LowLevelType.h:113
constexpr LLT changeElementType(LLT NewEltTy) const
If this type is a vector, return a vector with the same number of elements but the new element type.
Definition: LowLevelType.h:214
static constexpr LLT vector(ElementCount EC, unsigned ScalarSizeInBits)
Get a low-level vector of some number of elements and element width.
Definition: LowLevelType.h:64
static constexpr LLT scalar(unsigned SizeInBits)
Get a low-level scalar or aggregate "bag of bits".
Definition: LowLevelType.h:42
constexpr uint16_t getNumElements() const
Returns the number of elements in a vector LLT.
Definition: LowLevelType.h:159
constexpr bool isVector() const
Definition: LowLevelType.h:148
static constexpr LLT pointer(unsigned AddressSpace, unsigned SizeInBits)
Get a low-level pointer in the given address space.
Definition: LowLevelType.h:57
constexpr TypeSize getSizeInBits() const
Returns the total size of the type. Must only be called on sized types.
Definition: LowLevelType.h:193
constexpr LLT getElementType() const
Returns the vector's element type. Only valid for vector types.
Definition: LowLevelType.h:290
constexpr ElementCount getElementCount() const
Definition: LowLevelType.h:184
This is an important class for using LLVM in a threaded context.
Definition: LLVMContext.h:67
void computeTables()
Compute any ancillary tables needed to quickly decide how an operation should be handled.
LegalizeRuleSet & widenScalarOrEltToNextPow2OrMinSize(unsigned TypeIdx, unsigned MinSize=0)
Widen the scalar or vector element type to the next power of two that is at least MinSize.
LegalizeRuleSet & legalFor(std::initializer_list< LLT > Types)
The instruction is legal when type index 0 is any type in the given list.
LegalizeRuleSet & scalarSameSizeAs(unsigned TypeIdx, unsigned SameSizeIdx)
Change the type TypeIdx to have the same scalar size as type SameSizeIdx.
LegalizeRuleSet & libcallFor(std::initializer_list< LLT > Types)
LegalizeRuleSet & maxScalar(unsigned TypeIdx, const LLT Ty)
Ensure the scalar is at most as wide as Ty.
LegalizeRuleSet & lower()
The instruction is lowered.
LegalizeRuleSet & lowerFor(std::initializer_list< LLT > Types)
The instruction is lowered when type index 0 is any type in the given list.
LegalizeRuleSet & clampScalar(unsigned TypeIdx, const LLT MinTy, const LLT MaxTy)
Limit the range of scalar sizes to MinTy and MaxTy.
LegalizeRuleSet & minScalarSameAs(unsigned TypeIdx, unsigned LargeTypeIdx)
Widen the scalar to match the size of another.
LegalizeRuleSet & widenScalarIf(LegalityPredicate Predicate, LegalizeMutation Mutation)
Widen the scalar to the one selected by the mutation if the predicate is true.
LegalizeRuleSet & customIf(LegalityPredicate Predicate)
LegalizeRuleSet & widenScalarToNextPow2(unsigned TypeIdx, unsigned MinSize=0)
Widen the scalar to the next power of two that is at least MinSize.
LegalizeRuleSet & lowerForCartesianProduct(std::initializer_list< LLT > Types0, std::initializer_list< LLT > Types1)
The instruction is lowered when type indexes 0 and 1 are both in their respective lists.
LegalizeRuleSet & legalForTypesWithMemDesc(std::initializer_list< LegalityPredicates::TypePairAndMemDesc > TypesAndMemDesc)
The instruction is legal when type indexes 0 and 1 along with the memory size and minimum alignment i...
LegalizeRuleSet & legalIf(LegalityPredicate Predicate)
The instruction is legal if predicate is true.
LegalizeRuleSet & customFor(std::initializer_list< LLT > Types)
LegalizeResult lowerAbsToMaxNeg(MachineInstr &MI)
@ Legalized
Instruction has been legalized and the MachineFunction changed.
LegalizeResult lower(MachineInstr &MI, unsigned TypeIdx, LLT Ty)
Legalize an instruction by splitting it into simpler parts, hopefully understood by the target.
GISelChangeObserver & Observer
To keep track of changes made by the LegalizerHelper.
MachineIRBuilder & MIRBuilder
Expose MIRBuilder so clients can set their own RecordInsertInstruction functions.
LegalizeResult lowerConstant(MachineInstr &MI)
LegalizeRuleSet & getActionDefinitionsBuilder(unsigned Opcode)
Get the action definition builder for the given opcode.
const LegacyLegalizerInfo & getLegacyLegalizerInfo() const
MachineMemOperand * getMachineMemOperand(MachinePointerInfo PtrInfo, MachineMemOperand::Flags f, LLT MemTy, Align base_alignment, const AAMDNodes &AAInfo=AAMDNodes(), const MDNode *Ranges=nullptr, SyncScope::ID SSID=SyncScope::System, AtomicOrdering Ordering=AtomicOrdering::NotAtomic, AtomicOrdering FailureOrdering=AtomicOrdering::NotAtomic)
getMachineMemOperand - Allocate a new MachineMemOperand.
Function & getFunction()
Return the LLVM function that this machine code represents.
Ty * getInfo()
getInfo - Keep track of various per-function pieces of information for backends that would like to do...
Helper class to build MachineInstr.
MachineInstrBuilder buildUndef(const DstOp &Res)
Build and insert Res = IMPLICIT_DEF.
MachineInstrBuilder buildUnmerge(ArrayRef< LLT > Res, const SrcOp &Op)
Build and insert Res0, ... = G_UNMERGE_VALUES Op.
MachineInstrBuilder buildSelect(const DstOp &Res, const SrcOp &Tst, const SrcOp &Op0, const SrcOp &Op1, std::optional< unsigned > Flags=std::nullopt)
Build and insert a Res = G_SELECT Tst, Op0, Op1.
MachineInstrBuilder buildMul(const DstOp &Dst, const SrcOp &Src0, const SrcOp &Src1, std::optional< unsigned > Flags=std::nullopt)
Build and insert Res = G_MUL Op0, Op1.
MachineInstrBuilder buildAnd(const DstOp &Dst, const SrcOp &Src0, const SrcOp &Src1)
Build and insert Res = G_AND Op0, Op1.
MachineInstrBuilder buildICmp(CmpInst::Predicate Pred, const DstOp &Res, const SrcOp &Op0, const SrcOp &Op1)
Build and insert a Res = G_ICMP Pred, Op0, Op1.
MachineInstrBuilder buildLShr(const DstOp &Dst, const SrcOp &Src0, const SrcOp &Src1, std::optional< unsigned > Flags=std::nullopt)
MachineInstrBuilder buildLoad(const DstOp &Res, const SrcOp &Addr, MachineMemOperand &MMO)
Build and insert Res = G_LOAD Addr, MMO.
MachineInstrBuilder buildShl(const DstOp &Dst, const SrcOp &Src0, const SrcOp &Src1, std::optional< unsigned > Flags=std::nullopt)
MachineInstrBuilder buildStore(const SrcOp &Val, const SrcOp &Addr, MachineMemOperand &MMO)
Build and insert G_STORE Val, Addr, MMO.
MachineInstrBuilder buildInstr(unsigned Opcode)
Build and insert <empty> = Opcode <empty>.
MachineInstrBuilder buildFrameIndex(const DstOp &Res, int Idx)
Build and insert Res = G_FRAME_INDEX Idx.
MachineInstrBuilder buildZExt(const DstOp &Res, const SrcOp &Op)
Build and insert Res = G_ZEXT Op.
MachineRegisterInfo * getMRI()
Getter for MRI.
const DataLayout & getDataLayout() const
MachineInstrBuilder buildSplatVector(const DstOp &Res, const SrcOp &Val)
Build and insert Res = G_SPLAT_VECTOR Val.
virtual MachineInstrBuilder buildConstant(const DstOp &Res, const ConstantInt &Val)
Build and insert Res = G_CONSTANT Val.
Representation of each machine instruction.
Definition: MachineInstr.h:69
A description of a memory reference used in the backend.
@ MOLoad
The memory access reads data.
@ MOStore
The memory access writes data.
MachineOperand class - Representation of each machine instruction operand.
int64_t getImm() const
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
LLT getType(Register Reg) const
Get the low-level type of Reg or LLT{} if Reg is not a generic (target independent) virtual register.
bool legalizeCustom(LegalizerHelper &Helper, MachineInstr &MI, LostDebugLocObserver &LocObserver) const override
Called for instructions with the Custom LegalizationAction.
bool legalizeIntrinsic(LegalizerHelper &Helper, MachineInstr &MI) const override
RISCVLegalizerInfo(const RISCVSubtarget &ST)
RISCVMachineFunctionInfo - This class is derived from MachineFunctionInfo and contains private RISCV-...
unsigned getRealMinVLen() const
unsigned getMaxBuildIntsCost() const
bool useConstantPoolForLargeInts() const
Wrapper class representing virtual and physical registers.
Definition: Register.h:19
bool empty() const
Definition: SmallVector.h:94
size_t size() const
Definition: SmallVector.h:91
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1209
Register getReg() const
The instances of the Type class are immutable: once they are created, they are never changed.
Definition: Type.h:45
#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
LegalityPredicate typeInSet(unsigned TypeIdx, std::initializer_list< LLT > TypesInit)
True iff the given type index is one of the specified types.
Predicate any(Predicate P0, Predicate P1)
True iff P0 or P1 are true.
Predicate all(Predicate P0, Predicate P1)
True iff P0 and P1 are true.
LegalityPredicate typeIs(unsigned TypeIdx, LLT TypesInit)
True iff the given type index is the specified type.
LegalizeMutation changeTo(unsigned TypeIdx, LLT Ty)
Select this specific type for the given type index.
InstSeq generateInstSeq(int64_t Val, const MCSubtargetInfo &STI)
InstSeq generateTwoRegInstSeq(int64_t Val, const MCSubtargetInfo &STI, unsigned &ShiftAmt, unsigned &AddOpc)
static constexpr unsigned RVVBitsPerBlock
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
bool isAllOnesOrAllOnesSplat(const MachineInstr &MI, const MachineRegisterInfo &MRI, bool AllowUndefs=false)
Return true if the value is a constant -1 integer or a splatted vector of a constant -1 integer (with...
Definition: Utils.cpp:1525
constexpr bool isPowerOf2_64(uint64_t Value)
Return true if the argument is a power of two > 0 (64 bit edition.)
Definition: MathExtras.h:269
bool isNullOrNullSplat(const MachineInstr &MI, const MachineRegisterInfo &MRI, bool AllowUndefs=false)
Return true if the value is a constant 0 integer or a splatted vector of a constant 0 integer (with n...
Definition: Utils.cpp:1507
unsigned Log2_64(uint64_t Value)
Return the floor log base 2 of the specified value, -1 if the value is zero.
Definition: MathExtras.h:319
@ And
Bitwise or logical AND of integers.
std::optional< ValueAndVReg > getIConstantVRegValWithLookThrough(Register VReg, const MachineRegisterInfo &MRI, bool LookThroughInstrs=true)
If VReg is defined by a statically evaluable chain of instructions rooted on a G_CONSTANT returns its...
Definition: Utils.cpp:413
unsigned Log2(Align A)
Returns the log2 of the alignment.
Definition: Alignment.h:208
std::function< bool(const LegalityQuery &)> LegalityPredicate
This struct is a compact representation of a valid (non-zero power of two) alignment.
Definition: Alignment.h:39
The LegalityQuery object bundles together all the information that's needed to decide whether a given...
This class contains a discriminated union of information about pointers in memory operands,...