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