LLVM 20.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"
27#include "llvm/IR/Type.h"
28
29using namespace llvm;
30using namespace LegalityPredicates;
31using namespace LegalizeMutations;
32
33// Is this type supported by scalar FP arithmetic operations given the current
34// subtarget.
35static LegalityPredicate typeIsScalarFPArith(unsigned TypeIdx,
36 const RISCVSubtarget &ST) {
37 return [=, &ST](const LegalityQuery &Query) {
38 return Query.Types[TypeIdx].isScalar() &&
39 ((ST.hasStdExtZfh() && Query.Types[TypeIdx].getSizeInBits() == 16) ||
40 (ST.hasStdExtF() && Query.Types[TypeIdx].getSizeInBits() == 32) ||
41 (ST.hasStdExtD() && Query.Types[TypeIdx].getSizeInBits() == 64));
42 };
43}
44
46typeIsLegalIntOrFPVec(unsigned TypeIdx,
47 std::initializer_list<LLT> IntOrFPVecTys,
48 const RISCVSubtarget &ST) {
49 LegalityPredicate P = [=, &ST](const LegalityQuery &Query) {
50 return ST.hasVInstructions() &&
51 (Query.Types[TypeIdx].getScalarSizeInBits() != 64 ||
52 ST.hasVInstructionsI64()) &&
53 (Query.Types[TypeIdx].getElementCount().getKnownMinValue() != 1 ||
54 ST.getELen() == 64);
55 };
56
57 return all(typeInSet(TypeIdx, IntOrFPVecTys), P);
58}
59
61typeIsLegalBoolVec(unsigned TypeIdx, std::initializer_list<LLT> BoolVecTys,
62 const RISCVSubtarget &ST) {
63 LegalityPredicate P = [=, &ST](const LegalityQuery &Query) {
64 return ST.hasVInstructions() &&
65 (Query.Types[TypeIdx].getElementCount().getKnownMinValue() != 1 ||
66 ST.getELen() == 64);
67 };
68 return all(typeInSet(TypeIdx, BoolVecTys), P);
69}
70
71static LegalityPredicate typeIsLegalPtrVec(unsigned TypeIdx,
72 std::initializer_list<LLT> PtrVecTys,
73 const RISCVSubtarget &ST) {
74 LegalityPredicate P = [=, &ST](const LegalityQuery &Query) {
75 return ST.hasVInstructions() &&
76 (Query.Types[TypeIdx].getElementCount().getKnownMinValue() != 1 ||
77 ST.getELen() == 64);
78 };
79 return all(typeInSet(TypeIdx, PtrVecTys), P);
80}
81
83 : STI(ST), XLen(STI.getXLen()), sXLen(LLT::scalar(XLen)) {
84 const LLT sDoubleXLen = LLT::scalar(2 * XLen);
85 const LLT p0 = LLT::pointer(0, XLen);
86 const LLT s1 = LLT::scalar(1);
87 const LLT s8 = LLT::scalar(8);
88 const LLT s16 = LLT::scalar(16);
89 const LLT s32 = LLT::scalar(32);
90 const LLT s64 = LLT::scalar(64);
91
92 const LLT nxv1s1 = LLT::scalable_vector(1, s1);
93 const LLT nxv2s1 = LLT::scalable_vector(2, s1);
94 const LLT nxv4s1 = LLT::scalable_vector(4, s1);
95 const LLT nxv8s1 = LLT::scalable_vector(8, s1);
96 const LLT nxv16s1 = LLT::scalable_vector(16, s1);
97 const LLT nxv32s1 = LLT::scalable_vector(32, s1);
98 const LLT nxv64s1 = LLT::scalable_vector(64, s1);
99
100 const LLT nxv1s8 = LLT::scalable_vector(1, s8);
101 const LLT nxv2s8 = LLT::scalable_vector(2, s8);
102 const LLT nxv4s8 = LLT::scalable_vector(4, s8);
103 const LLT nxv8s8 = LLT::scalable_vector(8, s8);
104 const LLT nxv16s8 = LLT::scalable_vector(16, s8);
105 const LLT nxv32s8 = LLT::scalable_vector(32, s8);
106 const LLT nxv64s8 = LLT::scalable_vector(64, s8);
107
108 const LLT nxv1s16 = LLT::scalable_vector(1, s16);
109 const LLT nxv2s16 = LLT::scalable_vector(2, s16);
110 const LLT nxv4s16 = LLT::scalable_vector(4, s16);
111 const LLT nxv8s16 = LLT::scalable_vector(8, s16);
112 const LLT nxv16s16 = LLT::scalable_vector(16, s16);
113 const LLT nxv32s16 = LLT::scalable_vector(32, s16);
114
115 const LLT nxv1s32 = LLT::scalable_vector(1, s32);
116 const LLT nxv2s32 = LLT::scalable_vector(2, s32);
117 const LLT nxv4s32 = LLT::scalable_vector(4, s32);
118 const LLT nxv8s32 = LLT::scalable_vector(8, s32);
119 const LLT nxv16s32 = LLT::scalable_vector(16, s32);
120
121 const LLT nxv1s64 = LLT::scalable_vector(1, s64);
122 const LLT nxv2s64 = LLT::scalable_vector(2, s64);
123 const LLT nxv4s64 = LLT::scalable_vector(4, s64);
124 const LLT nxv8s64 = LLT::scalable_vector(8, s64);
125
126 const LLT nxv1p0 = LLT::scalable_vector(1, p0);
127 const LLT nxv2p0 = LLT::scalable_vector(2, p0);
128 const LLT nxv4p0 = LLT::scalable_vector(4, p0);
129 const LLT nxv8p0 = LLT::scalable_vector(8, p0);
130
131 using namespace TargetOpcode;
132
133 auto BoolVecTys = {nxv1s1, nxv2s1, nxv4s1, nxv8s1, nxv16s1, nxv32s1, nxv64s1};
134
135 auto IntOrFPVecTys = {nxv1s8, nxv2s8, nxv4s8, nxv8s8, nxv16s8, nxv32s8,
136 nxv64s8, nxv1s16, nxv2s16, nxv4s16, nxv8s16, nxv16s16,
137 nxv32s16, nxv1s32, nxv2s32, nxv4s32, nxv8s32, nxv16s32,
138 nxv1s64, nxv2s64, nxv4s64, nxv8s64};
139
140 auto PtrVecTys = {nxv1p0, nxv2p0, nxv4p0, nxv8p0};
141
142 getActionDefinitionsBuilder({G_ADD, G_SUB, G_AND, G_OR, G_XOR})
143 .legalFor({s32, sXLen})
144 .legalIf(typeIsLegalIntOrFPVec(0, IntOrFPVecTys, ST))
146 .clampScalar(0, s32, sXLen);
147
149 {G_UADDE, G_UADDO, G_USUBE, G_USUBO}).lower();
150
151 getActionDefinitionsBuilder({G_SADDO, G_SSUBO}).minScalar(0, sXLen).lower();
152
153 // TODO: Use Vector Single-Width Saturating Instructions for vector types.
154 getActionDefinitionsBuilder({G_UADDSAT, G_SADDSAT, G_USUBSAT, G_SSUBSAT})
155 .lower();
156
157 auto &ShiftActions = getActionDefinitionsBuilder({G_ASHR, G_LSHR, G_SHL});
158 if (ST.is64Bit())
159 ShiftActions.customFor({{s32, s32}});
160 ShiftActions.legalFor({{s32, s32}, {s32, sXLen}, {sXLen, sXLen}})
161 .widenScalarToNextPow2(0)
162 .clampScalar(1, s32, sXLen)
163 .clampScalar(0, s32, sXLen)
164 .minScalarSameAs(1, 0)
166
167 auto &ExtActions =
168 getActionDefinitionsBuilder({G_ZEXT, G_SEXT, G_ANYEXT})
169 .legalIf(all(typeIsLegalIntOrFPVec(0, IntOrFPVecTys, ST),
170 typeIsLegalIntOrFPVec(1, IntOrFPVecTys, ST)));
171 if (ST.is64Bit()) {
172 ExtActions.legalFor({{sXLen, s32}});
173 getActionDefinitionsBuilder(G_SEXT_INREG)
174 .customFor({sXLen})
175 .maxScalar(0, sXLen)
176 .lower();
177 } else {
178 getActionDefinitionsBuilder(G_SEXT_INREG).maxScalar(0, sXLen).lower();
179 }
180 ExtActions.customIf(typeIsLegalBoolVec(1, BoolVecTys, ST))
181 .maxScalar(0, sXLen);
182
183 // Merge/Unmerge
184 for (unsigned Op : {G_MERGE_VALUES, G_UNMERGE_VALUES}) {
185 auto &MergeUnmergeActions = getActionDefinitionsBuilder(Op);
186 unsigned BigTyIdx = Op == G_MERGE_VALUES ? 0 : 1;
187 unsigned LitTyIdx = Op == G_MERGE_VALUES ? 1 : 0;
188 if (XLen == 32 && ST.hasStdExtD()) {
189 MergeUnmergeActions.legalIf(
190 all(typeIs(BigTyIdx, s64), typeIs(LitTyIdx, s32)));
191 }
192 MergeUnmergeActions.widenScalarToNextPow2(LitTyIdx, XLen)
193 .widenScalarToNextPow2(BigTyIdx, XLen)
194 .clampScalar(LitTyIdx, sXLen, sXLen)
195 .clampScalar(BigTyIdx, sXLen, sXLen);
196 }
197
198 getActionDefinitionsBuilder({G_FSHL, G_FSHR}).lower();
199
200 auto &RotateActions = getActionDefinitionsBuilder({G_ROTL, G_ROTR});
201 if (ST.hasStdExtZbb() || ST.hasStdExtZbkb()) {
202 RotateActions.legalFor({{s32, sXLen}, {sXLen, sXLen}});
203 // Widen s32 rotate amount to s64 so SDAG patterns will match.
204 if (ST.is64Bit())
205 RotateActions.widenScalarIf(all(typeIs(0, s32), typeIs(1, s32)),
206 changeTo(1, sXLen));
207 }
208 RotateActions.lower();
209
210 getActionDefinitionsBuilder(G_BITREVERSE).maxScalar(0, sXLen).lower();
211
214 typeIsLegalBoolVec(0, BoolVecTys, ST)),
216 typeIsLegalBoolVec(1, BoolVecTys, ST))));
217
218 auto &BSWAPActions = getActionDefinitionsBuilder(G_BSWAP);
219 if (ST.hasStdExtZbb() || ST.hasStdExtZbkb())
220 BSWAPActions.legalFor({sXLen}).clampScalar(0, sXLen, sXLen);
221 else
222 BSWAPActions.maxScalar(0, sXLen).lower();
223
224 auto &CountZerosActions = getActionDefinitionsBuilder({G_CTLZ, G_CTTZ});
225 auto &CountZerosUndefActions =
226 getActionDefinitionsBuilder({G_CTLZ_ZERO_UNDEF, G_CTTZ_ZERO_UNDEF});
227 if (ST.hasStdExtZbb()) {
228 CountZerosActions.legalFor({{s32, s32}, {sXLen, sXLen}})
229 .clampScalar(0, s32, sXLen)
231 .scalarSameSizeAs(1, 0);
232 } else {
233 CountZerosActions.maxScalar(0, sXLen).scalarSameSizeAs(1, 0).lower();
234 CountZerosUndefActions.maxScalar(0, sXLen).scalarSameSizeAs(1, 0);
235 }
236 CountZerosUndefActions.lower();
237
238 auto &CTPOPActions = getActionDefinitionsBuilder(G_CTPOP);
239 if (ST.hasStdExtZbb()) {
240 CTPOPActions.legalFor({{s32, s32}, {sXLen, sXLen}})
241 .clampScalar(0, s32, sXLen)
242 .widenScalarToNextPow2(0)
243 .scalarSameSizeAs(1, 0);
244 } else {
245 CTPOPActions.maxScalar(0, sXLen).scalarSameSizeAs(1, 0).lower();
246 }
247
248 auto &ConstantActions = getActionDefinitionsBuilder(G_CONSTANT);
249 ConstantActions.legalFor({s32, p0});
250 if (ST.is64Bit())
251 ConstantActions.customFor({s64});
252 ConstantActions.widenScalarToNextPow2(0).clampScalar(0, s32, sXLen);
253
254 // TODO: transform illegal vector types into legal vector type
256 {G_IMPLICIT_DEF, G_CONSTANT_FOLD_BARRIER, G_FREEZE})
257 .legalFor({s32, sXLen, p0})
258 .legalIf(typeIsLegalBoolVec(0, BoolVecTys, ST))
259 .legalIf(typeIsLegalIntOrFPVec(0, IntOrFPVecTys, ST))
261 .clampScalar(0, s32, sXLen);
262
264 .legalFor({{sXLen, sXLen}, {sXLen, p0}})
265 .legalIf(all(typeIsLegalBoolVec(0, BoolVecTys, ST),
266 typeIsLegalIntOrFPVec(1, IntOrFPVecTys, ST)))
268 .clampScalar(1, sXLen, sXLen)
269 .clampScalar(0, sXLen, sXLen);
270
271 auto &SelectActions =
273 .legalFor({{s32, sXLen}, {p0, sXLen}})
274 .legalIf(all(typeIsLegalIntOrFPVec(0, IntOrFPVecTys, ST),
275 typeIsLegalBoolVec(1, BoolVecTys, ST)));
276 if (XLen == 64 || ST.hasStdExtD())
277 SelectActions.legalFor({{s64, sXLen}});
278 SelectActions.widenScalarToNextPow2(0)
279 .clampScalar(0, s32, (XLen == 64 || ST.hasStdExtD()) ? s64 : s32)
280 .clampScalar(1, sXLen, sXLen);
281
282 auto &LoadStoreActions =
283 getActionDefinitionsBuilder({G_LOAD, G_STORE})
284 .legalForTypesWithMemDesc({{s32, p0, s8, 8},
285 {s32, p0, s16, 16},
286 {s32, p0, s32, 32},
287 {p0, p0, sXLen, XLen}});
288 if (ST.hasVInstructions())
289 LoadStoreActions.legalForTypesWithMemDesc({{nxv2s8, p0, nxv2s8, 8},
290 {nxv4s8, p0, nxv4s8, 8},
291 {nxv8s8, p0, nxv8s8, 8},
292 {nxv16s8, p0, nxv16s8, 8},
293 {nxv32s8, p0, nxv32s8, 8},
294 {nxv64s8, p0, nxv64s8, 8},
295 {nxv2s16, p0, nxv2s16, 16},
296 {nxv4s16, p0, nxv4s16, 16},
297 {nxv8s16, p0, nxv8s16, 16},
298 {nxv16s16, p0, nxv16s16, 16},
299 {nxv32s16, p0, nxv32s16, 16},
300 {nxv2s32, p0, nxv2s32, 32},
301 {nxv4s32, p0, nxv4s32, 32},
302 {nxv8s32, p0, nxv8s32, 32},
303 {nxv16s32, p0, nxv16s32, 32}});
304
305 auto &ExtLoadActions =
306 getActionDefinitionsBuilder({G_SEXTLOAD, G_ZEXTLOAD})
307 .legalForTypesWithMemDesc({{s32, p0, s8, 8}, {s32, p0, s16, 16}});
308 if (XLen == 64) {
309 LoadStoreActions.legalForTypesWithMemDesc({{s64, p0, s8, 8},
310 {s64, p0, s16, 16},
311 {s64, p0, s32, 32},
312 {s64, p0, s64, 64}});
313 ExtLoadActions.legalForTypesWithMemDesc(
314 {{s64, p0, s8, 8}, {s64, p0, s16, 16}, {s64, p0, s32, 32}});
315 } else if (ST.hasStdExtD()) {
316 LoadStoreActions.legalForTypesWithMemDesc({{s64, p0, s64, 64}});
317 }
318 if (ST.hasVInstructions() && ST.getELen() == 64)
319 LoadStoreActions.legalForTypesWithMemDesc({{nxv1s8, p0, nxv1s8, 8},
320 {nxv1s16, p0, nxv1s16, 16},
321 {nxv1s32, p0, nxv1s32, 32}});
322
323 if (ST.hasVInstructionsI64())
324 LoadStoreActions.legalForTypesWithMemDesc({{nxv1s64, p0, nxv1s64, 64},
325
326 {nxv2s64, p0, nxv2s64, 64},
327 {nxv4s64, p0, nxv4s64, 64},
328 {nxv8s64, p0, nxv8s64, 64}});
329
330 LoadStoreActions.widenScalarToNextPow2(0, /* MinSize = */ 8)
332 // we will take the custom lowering logic if we have scalable vector types
333 // with non-standard alignments
336 typeIsLegalPtrVec(0, PtrVecTys, ST))))
337 .clampScalar(0, s32, sXLen)
338 .lower();
339
340 ExtLoadActions.widenScalarToNextPow2(0).clampScalar(0, s32, sXLen).lower();
341
342 getActionDefinitionsBuilder({G_PTR_ADD, G_PTRMASK}).legalFor({{p0, sXLen}});
343
345 .legalFor({{sXLen, p0}})
346 .clampScalar(0, sXLen, sXLen);
347
349 .legalFor({{p0, sXLen}})
350 .clampScalar(1, sXLen, sXLen);
351
352 getActionDefinitionsBuilder(G_BRCOND).legalFor({sXLen}).minScalar(0, sXLen);
353
354 getActionDefinitionsBuilder(G_BRJT).legalFor({{p0, sXLen}});
355
356 getActionDefinitionsBuilder(G_BRINDIRECT).legalFor({p0});
357
359 .legalFor({p0, sXLen})
360 .widenScalarToNextPow2(0)
361 .clampScalar(0, sXLen, sXLen);
362
363 getActionDefinitionsBuilder({G_GLOBAL_VALUE, G_JUMP_TABLE, G_CONSTANT_POOL})
364 .legalFor({p0});
365
366 if (ST.hasStdExtZmmul()) {
368 .legalFor({s32, sXLen})
369 .widenScalarToNextPow2(0)
370 .clampScalar(0, s32, sXLen);
371
372 // clang-format off
373 getActionDefinitionsBuilder({G_SMULH, G_UMULH})
374 .legalFor({sXLen})
375 .lower();
376 // clang-format on
377
378 getActionDefinitionsBuilder({G_SMULO, G_UMULO}).minScalar(0, sXLen).lower();
379 } else {
381 .libcallFor({sXLen, sDoubleXLen})
382 .widenScalarToNextPow2(0)
383 .clampScalar(0, sXLen, sDoubleXLen);
384
385 getActionDefinitionsBuilder({G_SMULH, G_UMULH}).lowerFor({sXLen});
386
387 getActionDefinitionsBuilder({G_SMULO, G_UMULO})
388 .minScalar(0, sXLen)
389 // Widen sXLen to sDoubleXLen so we can use a single libcall to get
390 // the low bits for the mul result and high bits to do the overflow
391 // check.
392 .widenScalarIf(typeIs(0, sXLen),
393 LegalizeMutations::changeTo(0, sDoubleXLen))
394 .lower();
395 }
396
397 if (ST.hasStdExtM()) {
398 getActionDefinitionsBuilder({G_UDIV, G_SDIV, G_UREM, G_SREM})
399 .legalFor({s32, sXLen})
400 .libcallFor({sDoubleXLen})
401 .clampScalar(0, s32, sDoubleXLen)
403 } else {
404 getActionDefinitionsBuilder({G_UDIV, G_SDIV, G_UREM, G_SREM})
405 .libcallFor({sXLen, sDoubleXLen})
406 .clampScalar(0, sXLen, sDoubleXLen)
408 }
409
410 // TODO: Use libcall for sDoubleXLen.
411 getActionDefinitionsBuilder({G_UDIVREM, G_SDIVREM}).lower();
412
413 auto &AbsActions = getActionDefinitionsBuilder(G_ABS);
414 if (ST.hasStdExtZbb())
415 AbsActions.customFor({s32, sXLen}).minScalar(0, sXLen);
416 AbsActions.lower();
417
418 auto &MinMaxActions =
419 getActionDefinitionsBuilder({G_UMAX, G_UMIN, G_SMAX, G_SMIN});
420 if (ST.hasStdExtZbb())
421 MinMaxActions.legalFor({sXLen}).minScalar(0, sXLen);
422 MinMaxActions.lower();
423
424 getActionDefinitionsBuilder(G_FRAME_INDEX).legalFor({p0});
425
426 getActionDefinitionsBuilder({G_MEMCPY, G_MEMMOVE, G_MEMSET}).libcall();
427
428 getActionDefinitionsBuilder(G_DYN_STACKALLOC).lower();
429
430 // FP Operations
431
432 getActionDefinitionsBuilder({G_FADD, G_FSUB, G_FMUL, G_FDIV, G_FMA, G_FNEG,
433 G_FABS, G_FSQRT, G_FMAXNUM, G_FMINNUM})
434 .legalIf(typeIsScalarFPArith(0, ST));
435
437 .libcallFor({s32, s64})
438 .minScalar(0, s32)
439 .scalarize(0);
440
441 getActionDefinitionsBuilder(G_FCOPYSIGN)
443
444 // FIXME: Use Zfhmin.
446 [=, &ST](const LegalityQuery &Query) -> bool {
447 return (ST.hasStdExtD() && typeIs(0, s32)(Query) &&
448 typeIs(1, s64)(Query)) ||
449 (ST.hasStdExtZfh() && typeIs(0, s16)(Query) &&
450 typeIs(1, s32)(Query)) ||
451 (ST.hasStdExtZfh() && ST.hasStdExtD() && typeIs(0, s16)(Query) &&
452 typeIs(1, s64)(Query));
453 });
455 [=, &ST](const LegalityQuery &Query) -> bool {
456 return (ST.hasStdExtD() && typeIs(0, s64)(Query) &&
457 typeIs(1, s32)(Query)) ||
458 (ST.hasStdExtZfh() && typeIs(0, s32)(Query) &&
459 typeIs(1, s16)(Query)) ||
460 (ST.hasStdExtZfh() && ST.hasStdExtD() && typeIs(0, s64)(Query) &&
461 typeIs(1, s16)(Query));
462 });
463
465 .legalIf(all(typeIs(0, sXLen), typeIsScalarFPArith(1, ST)))
466 .clampScalar(0, sXLen, sXLen);
467
468 // TODO: Support vector version of G_IS_FPCLASS.
469 getActionDefinitionsBuilder(G_IS_FPCLASS)
470 .customIf(all(typeIs(0, s1), typeIsScalarFPArith(1, ST)));
471
472 getActionDefinitionsBuilder(G_FCONSTANT)
474 .lowerFor({s32, s64});
475
476 getActionDefinitionsBuilder({G_FPTOSI, G_FPTOUI})
477 .legalIf(all(typeInSet(0, {s32, sXLen}), typeIsScalarFPArith(1, ST)))
479 .clampScalar(0, s32, sXLen)
480 .libcall();
481
482 getActionDefinitionsBuilder({G_SITOFP, G_UITOFP})
483 .legalIf(all(typeIsScalarFPArith(0, ST), typeInSet(1, {s32, sXLen})))
485 .clampScalar(1, s32, sXLen);
486
487 // FIXME: We can do custom inline expansion like SelectionDAG.
488 // FIXME: Legal with Zfa.
489 getActionDefinitionsBuilder({G_FCEIL, G_FFLOOR})
490 .libcallFor({s32, s64});
491
492 getActionDefinitionsBuilder(G_VASTART).customFor({p0});
493
494 // va_list must be a pointer, but most sized types are pretty easy to handle
495 // as the destination.
497 // TODO: Implement narrowScalar and widenScalar for G_VAARG for types
498 // outside the [s32, sXLen] range.
499 .clampScalar(0, s32, sXLen)
500 .lowerForCartesianProduct({s32, sXLen, p0}, {p0});
501
503 .clampScalar(0, sXLen, sXLen)
504 .customFor({sXLen});
505
506 auto &SplatActions =
507 getActionDefinitionsBuilder(G_SPLAT_VECTOR)
508 .legalIf(all(typeIsLegalIntOrFPVec(0, IntOrFPVecTys, ST),
509 typeIs(1, sXLen)))
510 .customIf(all(typeIsLegalBoolVec(0, BoolVecTys, ST), typeIs(1, s1)));
511 // Handle case of s64 element vectors on RV32. If the subtarget does not have
512 // f64, then try to lower it to G_SPLAT_VECTOR_SPLIT_64_VL. If the subtarget
513 // does have f64, then we don't know whether the type is an f64 or an i64,
514 // so mark the G_SPLAT_VECTOR as legal and decide later what to do with it,
515 // depending on how the instructions it consumes are legalized. They are not
516 // legalized yet since legalization is in reverse postorder, so we cannot
517 // make the decision at this moment.
518 if (XLen == 32) {
519 if (ST.hasVInstructionsF64() && ST.hasStdExtD())
520 SplatActions.legalIf(all(
521 typeInSet(0, {nxv1s64, nxv2s64, nxv4s64, nxv8s64}), typeIs(1, s64)));
522 else if (ST.hasVInstructionsI64())
523 SplatActions.customIf(all(
524 typeInSet(0, {nxv1s64, nxv2s64, nxv4s64, nxv8s64}), typeIs(1, s64)));
525 }
526
527 SplatActions.clampScalar(1, sXLen, sXLen);
528
530}
531
533 MachineInstr &MI) const {
534 Intrinsic::ID IntrinsicID = cast<GIntrinsic>(MI).getIntrinsicID();
535 switch (IntrinsicID) {
536 default:
537 return false;
538 case Intrinsic::vacopy: {
539 // vacopy arguments must be legal because of the intrinsic signature.
540 // No need to check here.
541
542 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
543 MachineRegisterInfo &MRI = *MIRBuilder.getMRI();
544 MachineFunction &MF = *MI.getMF();
545 const DataLayout &DL = MIRBuilder.getDataLayout();
546 LLVMContext &Ctx = MF.getFunction().getContext();
547
548 Register DstLst = MI.getOperand(1).getReg();
549 LLT PtrTy = MRI.getType(DstLst);
550
551 // Load the source va_list
552 Align Alignment = DL.getABITypeAlign(getTypeForLLT(PtrTy, Ctx));
554 MachinePointerInfo(), MachineMemOperand::MOLoad, PtrTy, Alignment);
555 auto Tmp = MIRBuilder.buildLoad(PtrTy, MI.getOperand(2), *LoadMMO);
556
557 // Store the result in the destination va_list
560 MIRBuilder.buildStore(Tmp, DstLst, *StoreMMO);
561
562 MI.eraseFromParent();
563 return true;
564 }
565 }
566}
567
568bool RISCVLegalizerInfo::legalizeShlAshrLshr(
569 MachineInstr &MI, MachineIRBuilder &MIRBuilder,
570 GISelChangeObserver &Observer) const {
571 assert(MI.getOpcode() == TargetOpcode::G_ASHR ||
572 MI.getOpcode() == TargetOpcode::G_LSHR ||
573 MI.getOpcode() == TargetOpcode::G_SHL);
574 MachineRegisterInfo &MRI = *MIRBuilder.getMRI();
575 // If the shift amount is a G_CONSTANT, promote it to a 64 bit type so the
576 // imported patterns can select it later. Either way, it will be legal.
577 Register AmtReg = MI.getOperand(2).getReg();
578 auto VRegAndVal = getIConstantVRegValWithLookThrough(AmtReg, MRI);
579 if (!VRegAndVal)
580 return true;
581 // Check the shift amount is in range for an immediate form.
582 uint64_t Amount = VRegAndVal->Value.getZExtValue();
583 if (Amount > 31)
584 return true; // This will have to remain a register variant.
585 auto ExtCst = MIRBuilder.buildConstant(LLT::scalar(64), Amount);
586 Observer.changingInstr(MI);
587 MI.getOperand(2).setReg(ExtCst.getReg(0));
588 Observer.changedInstr(MI);
589 return true;
590}
591
592bool RISCVLegalizerInfo::legalizeVAStart(MachineInstr &MI,
593 MachineIRBuilder &MIRBuilder) const {
594 // Stores the address of the VarArgsFrameIndex slot into the memory location
595 assert(MI.getOpcode() == TargetOpcode::G_VASTART);
596 MachineFunction *MF = MI.getParent()->getParent();
598 int FI = FuncInfo->getVarArgsFrameIndex();
599 LLT AddrTy = MIRBuilder.getMRI()->getType(MI.getOperand(0).getReg());
600 auto FINAddr = MIRBuilder.buildFrameIndex(AddrTy, FI);
601 assert(MI.hasOneMemOperand());
602 MIRBuilder.buildStore(FINAddr, MI.getOperand(0).getReg(),
603 *MI.memoperands()[0]);
604 MI.eraseFromParent();
605 return true;
606}
607
608bool RISCVLegalizerInfo::shouldBeInConstantPool(APInt APImm,
609 bool ShouldOptForSize) const {
610 assert(APImm.getBitWidth() == 32 || APImm.getBitWidth() == 64);
611 int64_t Imm = APImm.getSExtValue();
612 // All simm32 constants should be handled by isel.
613 // NOTE: The getMaxBuildIntsCost call below should return a value >= 2 making
614 // this check redundant, but small immediates are common so this check
615 // should have better compile time.
616 if (isInt<32>(Imm))
617 return false;
618
619 // We only need to cost the immediate, if constant pool lowering is enabled.
621 return false;
622
624 if (Seq.size() <= STI.getMaxBuildIntsCost())
625 return false;
626
627 // Optimizations below are disabled for opt size. If we're optimizing for
628 // size, use a constant pool.
629 if (ShouldOptForSize)
630 return true;
631 //
632 // Special case. See if we can build the constant as (ADD (SLLI X, C), X) do
633 // that if it will avoid a constant pool.
634 // It will require an extra temporary register though.
635 // If we have Zba we can use (ADD_UW X, (SLLI X, 32)) to handle cases where
636 // low and high 32 bits are the same and bit 31 and 63 are set.
637 unsigned ShiftAmt, AddOpc;
639 RISCVMatInt::generateTwoRegInstSeq(Imm, STI, ShiftAmt, AddOpc);
640 return !(!SeqLo.empty() && (SeqLo.size() + 2) <= STI.getMaxBuildIntsCost());
641}
642
643bool RISCVLegalizerInfo::legalizeVScale(MachineInstr &MI,
644 MachineIRBuilder &MIB) const {
645 const LLT XLenTy(STI.getXLenVT());
646 Register Dst = MI.getOperand(0).getReg();
647
648 // We define our scalable vector types for lmul=1 to use a 64 bit known
649 // minimum size. e.g. <vscale x 2 x i32>. VLENB is in bytes so we calculate
650 // vscale as VLENB / 8.
651 static_assert(RISCV::RVVBitsPerBlock == 64, "Unexpected bits per block!");
653 // Support for VLEN==32 is incomplete.
654 return false;
655
656 // We assume VLENB is a multiple of 8. We manually choose the best shift
657 // here because SimplifyDemandedBits isn't always able to simplify it.
658 uint64_t Val = MI.getOperand(1).getCImm()->getZExtValue();
659 if (isPowerOf2_64(Val)) {
660 uint64_t Log2 = Log2_64(Val);
661 if (Log2 < 3) {
662 auto VLENB = MIB.buildInstr(RISCV::G_READ_VLENB, {XLenTy}, {});
663 MIB.buildLShr(Dst, VLENB, MIB.buildConstant(XLenTy, 3 - Log2));
664 } else if (Log2 > 3) {
665 auto VLENB = MIB.buildInstr(RISCV::G_READ_VLENB, {XLenTy}, {});
666 MIB.buildShl(Dst, VLENB, MIB.buildConstant(XLenTy, Log2 - 3));
667 } else {
668 MIB.buildInstr(RISCV::G_READ_VLENB, {Dst}, {});
669 }
670 } else if ((Val % 8) == 0) {
671 // If the multiplier is a multiple of 8, scale it down to avoid needing
672 // to shift the VLENB value.
673 auto VLENB = MIB.buildInstr(RISCV::G_READ_VLENB, {XLenTy}, {});
674 MIB.buildMul(Dst, VLENB, MIB.buildConstant(XLenTy, Val / 8));
675 } else {
676 auto VLENB = MIB.buildInstr(RISCV::G_READ_VLENB, {XLenTy}, {});
677 auto VScale = MIB.buildLShr(XLenTy, VLENB, MIB.buildConstant(XLenTy, 3));
678 MIB.buildMul(Dst, VScale, MIB.buildConstant(XLenTy, Val));
679 }
680 MI.eraseFromParent();
681 return true;
682}
683
684// Custom-lower extensions from mask vectors by using a vselect either with 1
685// for zero/any-extension or -1 for sign-extension:
686// (vXiN = (s|z)ext vXi1:vmask) -> (vXiN = vselect vmask, (-1 or 1), 0)
687// Note that any-extension is lowered identically to zero-extension.
688bool RISCVLegalizerInfo::legalizeExt(MachineInstr &MI,
689 MachineIRBuilder &MIB) const {
690
691 unsigned Opc = MI.getOpcode();
692 assert(Opc == TargetOpcode::G_ZEXT || Opc == TargetOpcode::G_SEXT ||
693 Opc == TargetOpcode::G_ANYEXT);
694
696 Register Dst = MI.getOperand(0).getReg();
697 Register Src = MI.getOperand(1).getReg();
698
699 LLT DstTy = MRI.getType(Dst);
700 int64_t ExtTrueVal = Opc == TargetOpcode::G_SEXT ? -1 : 1;
701 LLT DstEltTy = DstTy.getElementType();
702 auto SplatZero = MIB.buildSplatVector(DstTy, MIB.buildConstant(DstEltTy, 0));
703 auto SplatTrue =
704 MIB.buildSplatVector(DstTy, MIB.buildConstant(DstEltTy, ExtTrueVal));
705 MIB.buildSelect(Dst, Src, SplatTrue, SplatZero);
706
707 MI.eraseFromParent();
708 return true;
709}
710
711bool RISCVLegalizerInfo::legalizeLoadStore(MachineInstr &MI,
712 LegalizerHelper &Helper,
713 MachineIRBuilder &MIB) const {
714 assert((isa<GLoad>(MI) || isa<GStore>(MI)) &&
715 "Machine instructions must be Load/Store.");
717 MachineFunction *MF = MI.getMF();
718 const DataLayout &DL = MIB.getDataLayout();
719 LLVMContext &Ctx = MF->getFunction().getContext();
720
721 Register DstReg = MI.getOperand(0).getReg();
722 LLT DataTy = MRI.getType(DstReg);
723 if (!DataTy.isVector())
724 return false;
725
726 if (!MI.hasOneMemOperand())
727 return false;
728
729 MachineMemOperand *MMO = *MI.memoperands_begin();
730
731 const auto *TLI = STI.getTargetLowering();
732 EVT VT = EVT::getEVT(getTypeForLLT(DataTy, Ctx));
733
734 if (TLI->allowsMemoryAccessForAlignment(Ctx, DL, VT, *MMO))
735 return true;
736
737 unsigned EltSizeBits = DataTy.getScalarSizeInBits();
738 assert((EltSizeBits == 16 || EltSizeBits == 32 || EltSizeBits == 64) &&
739 "Unexpected unaligned RVV load type");
740
741 // Calculate the new vector type with i8 elements
742 unsigned NumElements =
743 DataTy.getElementCount().getKnownMinValue() * (EltSizeBits / 8);
744 LLT NewDataTy = LLT::scalable_vector(NumElements, 8);
745
746 Helper.bitcast(MI, 0, NewDataTy);
747
748 return true;
749}
750
751/// Return the type of the mask type suitable for masking the provided
752/// vector type. This is simply an i1 element type vector of the same
753/// (possibly scalable) length.
754static LLT getMaskTypeFor(LLT VecTy) {
755 assert(VecTy.isVector());
756 ElementCount EC = VecTy.getElementCount();
757 return LLT::vector(EC, LLT::scalar(1));
758}
759
760/// Creates an all ones mask suitable for masking a vector of type VecTy with
761/// vector length VL.
763 MachineIRBuilder &MIB,
765 LLT MaskTy = getMaskTypeFor(VecTy);
766 return MIB.buildInstr(RISCV::G_VMSET_VL, {MaskTy}, {VL});
767}
768
769/// Gets the two common "VL" operands: an all-ones mask and the vector length.
770/// VecTy is a scalable vector type.
771static std::pair<MachineInstrBuilder, Register>
774 LLT VecTy = Dst.getLLTTy(MRI);
775 assert(VecTy.isScalableVector() && "Expecting scalable container type");
776 Register VL(RISCV::X0);
777 MachineInstrBuilder Mask = buildAllOnesMask(VecTy, VL, MIB, MRI);
778 return {Mask, VL};
779}
780
782buildSplatPartsS64WithVL(const DstOp &Dst, const SrcOp &Passthru, Register Lo,
785 // TODO: If the Hi bits of the splat are undefined, then it's fine to just
786 // splat Lo even if it might be sign extended. I don't think we have
787 // introduced a case where we're build a s64 where the upper bits are undef
788 // yet.
789
790 // Fall back to a stack store and stride x0 vector load.
791 // TODO: need to lower G_SPLAT_VECTOR_SPLIT_I64. This is done in
792 // preprocessDAG in SDAG.
793 return MIB.buildInstr(RISCV::G_SPLAT_VECTOR_SPLIT_I64_VL, {Dst},
794 {Passthru, Lo, Hi, VL});
795}
796
798buildSplatSplitS64WithVL(const DstOp &Dst, const SrcOp &Passthru,
799 const SrcOp &Scalar, Register VL,
801 assert(Scalar.getLLTTy(MRI) == LLT::scalar(64) && "Unexpected VecTy!");
802 auto Unmerge = MIB.buildUnmerge(LLT::scalar(32), Scalar);
803 return buildSplatPartsS64WithVL(Dst, Passthru, Unmerge.getReg(0),
804 Unmerge.getReg(1), VL, MIB, MRI);
805}
806
807// Lower splats of s1 types to G_ICMP. For each mask vector type, we have a
808// legal equivalently-sized i8 type, so we can use that as a go-between.
809// Splats of s1 types that have constant value can be legalized as VMSET_VL or
810// VMCLR_VL.
811bool RISCVLegalizerInfo::legalizeSplatVector(MachineInstr &MI,
812 MachineIRBuilder &MIB) const {
813 assert(MI.getOpcode() == TargetOpcode::G_SPLAT_VECTOR);
814
816
817 Register Dst = MI.getOperand(0).getReg();
818 Register SplatVal = MI.getOperand(1).getReg();
819
820 LLT VecTy = MRI.getType(Dst);
821 LLT XLenTy(STI.getXLenVT());
822
823 // Handle case of s64 element vectors on rv32
824 if (XLenTy.getSizeInBits() == 32 &&
825 VecTy.getElementType().getSizeInBits() == 64) {
826 auto [_, VL] = buildDefaultVLOps(Dst, MIB, MRI);
827 buildSplatSplitS64WithVL(Dst, MIB.buildUndef(VecTy), SplatVal, VL, MIB,
828 MRI);
829 MI.eraseFromParent();
830 return true;
831 }
832
833 // All-zeros or all-ones splats are handled specially.
834 MachineInstr &SplatValMI = *MRI.getVRegDef(SplatVal);
835 if (isAllOnesOrAllOnesSplat(SplatValMI, MRI)) {
836 auto VL = buildDefaultVLOps(VecTy, MIB, MRI).second;
837 MIB.buildInstr(RISCV::G_VMSET_VL, {Dst}, {VL});
838 MI.eraseFromParent();
839 return true;
840 }
841 if (isNullOrNullSplat(SplatValMI, MRI)) {
842 auto VL = buildDefaultVLOps(VecTy, MIB, MRI).second;
843 MIB.buildInstr(RISCV::G_VMCLR_VL, {Dst}, {VL});
844 MI.eraseFromParent();
845 return true;
846 }
847
848 // Handle non-constant mask splat (i.e. not sure if it's all zeros or all
849 // ones) by promoting it to an s8 splat.
850 LLT InterEltTy = LLT::scalar(8);
851 LLT InterTy = VecTy.changeElementType(InterEltTy);
852 auto ZExtSplatVal = MIB.buildZExt(InterEltTy, SplatVal);
853 auto And =
854 MIB.buildAnd(InterEltTy, ZExtSplatVal, MIB.buildConstant(InterEltTy, 1));
855 auto LHS = MIB.buildSplatVector(InterTy, And);
856 auto ZeroSplat =
857 MIB.buildSplatVector(InterTy, MIB.buildConstant(InterEltTy, 0));
858 MIB.buildICmp(CmpInst::Predicate::ICMP_NE, Dst, LHS, ZeroSplat);
859 MI.eraseFromParent();
860 return true;
861}
862
865 LostDebugLocObserver &LocObserver) const {
866 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
867 GISelChangeObserver &Observer = Helper.Observer;
868 MachineFunction &MF = *MI.getParent()->getParent();
869 switch (MI.getOpcode()) {
870 default:
871 // No idea what to do.
872 return false;
873 case TargetOpcode::G_ABS:
874 return Helper.lowerAbsToMaxNeg(MI);
875 // TODO: G_FCONSTANT
876 case TargetOpcode::G_CONSTANT: {
877 const Function &F = MF.getFunction();
878 // TODO: if PSI and BFI are present, add " ||
879 // llvm::shouldOptForSize(*CurMBB, PSI, BFI)".
880 bool ShouldOptForSize = F.hasOptSize() || F.hasMinSize();
881 const ConstantInt *ConstVal = MI.getOperand(1).getCImm();
882 if (!shouldBeInConstantPool(ConstVal->getValue(), ShouldOptForSize))
883 return true;
884 return Helper.lowerConstant(MI);
885 }
886 case TargetOpcode::G_SHL:
887 case TargetOpcode::G_ASHR:
888 case TargetOpcode::G_LSHR:
889 return legalizeShlAshrLshr(MI, MIRBuilder, Observer);
890 case TargetOpcode::G_SEXT_INREG: {
891 // Source size of 32 is sext.w.
892 int64_t SizeInBits = MI.getOperand(2).getImm();
893 if (SizeInBits == 32)
894 return true;
895
896 return Helper.lower(MI, 0, /* Unused hint type */ LLT()) ==
898 }
899 case TargetOpcode::G_IS_FPCLASS: {
900 Register GISFPCLASS = MI.getOperand(0).getReg();
901 Register Src = MI.getOperand(1).getReg();
902 const MachineOperand &ImmOp = MI.getOperand(2);
903 MachineIRBuilder MIB(MI);
904
905 // Turn LLVM IR's floating point classes to that in RISC-V,
906 // by simply rotating the 10-bit immediate right by two bits.
907 APInt GFpClassImm(10, static_cast<uint64_t>(ImmOp.getImm()));
908 auto FClassMask = MIB.buildConstant(sXLen, GFpClassImm.rotr(2).zext(XLen));
909 auto ConstZero = MIB.buildConstant(sXLen, 0);
910
911 auto GFClass = MIB.buildInstr(RISCV::G_FCLASS, {sXLen}, {Src});
912 auto And = MIB.buildAnd(sXLen, GFClass, FClassMask);
913 MIB.buildICmp(CmpInst::ICMP_NE, GISFPCLASS, And, ConstZero);
914
915 MI.eraseFromParent();
916 return true;
917 }
918 case TargetOpcode::G_VASTART:
919 return legalizeVAStart(MI, MIRBuilder);
920 case TargetOpcode::G_VSCALE:
921 return legalizeVScale(MI, MIRBuilder);
922 case TargetOpcode::G_ZEXT:
923 case TargetOpcode::G_SEXT:
924 case TargetOpcode::G_ANYEXT:
925 return legalizeExt(MI, MIRBuilder);
926 case TargetOpcode::G_SPLAT_VECTOR:
927 return legalizeSplatVector(MI, MIRBuilder);
928 case TargetOpcode::G_LOAD:
929 case TargetOpcode::G_STORE:
930 return legalizeLoadStore(MI, Helper, MIRBuilder);
931 }
932
933 llvm_unreachable("expected switch to return");
934}
unsigned const MachineRegisterInfo * MRI
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
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.
static LegalityPredicate typeIsLegalPtrVec(unsigned TypeIdx, std::initializer_list< LLT > PtrVecTys, const RISCVSubtarget &ST)
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:78
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:1448
APInt rotr(unsigned rotateAmt) const
Rotate right by rotateAmt.
Definition: APInt.cpp:1124
int64_t getSExtValue() const
Get sign extended value.
Definition: APInt.h:1522
@ ICMP_NE
not equal
Definition: InstrTypes.h:779
This is the shared class of boolean and integer constants.
Definition: Constants.h:81
const APInt & getValue() const
Return the constant as an APInt value reference.
Definition: Constants.h:146
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
LLVMContext & getContext() const
getContext - Return a reference to the LLVMContext associated with this function.
Definition: Function.cpp:380
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.
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 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 & libcall()
The instruction is emitted as a library call.
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 & lowerIfMemSizeNotByteSizePow2()
Lower a memory operation if the memory access size is not a round power of 2 byte size.
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 & scalarize(unsigned TypeIdx)
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)
LegalizeResult bitcast(MachineInstr &MI, unsigned TypeIdx, LLT Ty)
Legalize an instruction by replacing the value type.
@ 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 buildZExt(const DstOp &Res, const SrcOp &Op, std::optional< unsigned > Flags=std::nullopt)
Build and insert Res = G_ZEXT Op.
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.
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
const RISCVTargetLowering * getTargetLowering() const override
Wrapper class representing virtual and physical registers.
Definition: Register.h:19
bool empty() const
Definition: SmallVector.h:95
size_t size() const
Definition: SmallVector.h:92
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1210
Register getReg() const
constexpr ScalarTy getKnownMinValue() const
Returns the minimum value this quantity can represent.
Definition: TypeSize.h:168
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
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
Type * getTypeForLLT(LLT Ty, LLVMContext &C)
Get the type back from LLT.
Definition: Utils.cpp:1981
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:1553
constexpr bool isPowerOf2_64(uint64_t Value)
Return true if the argument is a power of two > 0 (64 bit edition.)
Definition: MathExtras.h:296
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:1535
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:346
@ 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:433
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
Extended Value Type.
Definition: ValueTypes.h:34
static EVT getEVT(Type *Ty, bool HandleUnknown=false)
Return the value type corresponding to the specified type.
Definition: ValueTypes.cpp:274
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,...