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 &LoadActions = getActionDefinitionsBuilder(G_LOAD);
289 auto &StoreActions = getActionDefinitionsBuilder(G_STORE);
290
291 LoadActions
292 .legalForTypesWithMemDesc({{s32, p0, s8, 8},
293 {s32, p0, s16, 16},
294 {s32, p0, s32, 32},
295 {p0, p0, sXLen, XLen}});
296 StoreActions
297 .legalForTypesWithMemDesc({{s32, p0, s8, 8},
298 {s32, p0, s16, 16},
299 {s32, p0, s32, 32},
300 {p0, p0, sXLen, XLen}});
301 auto &ExtLoadActions =
302 getActionDefinitionsBuilder({G_SEXTLOAD, G_ZEXTLOAD})
303 .legalForTypesWithMemDesc({{s32, p0, s8, 8}, {s32, p0, s16, 16}});
304 if (XLen == 64) {
305 LoadActions.legalForTypesWithMemDesc({{s64, p0, s8, 8},
306 {s64, p0, s16, 16},
307 {s64, p0, s32, 32},
308 {s64, p0, s64, 64}});
309 StoreActions.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 LoadActions.legalForTypesWithMemDesc({{s64, p0, s64, 64}});
317 StoreActions.legalForTypesWithMemDesc({{s64, p0, s64, 64}});
318 }
319
320 // Vector loads/stores.
321 if (ST.hasVInstructions()) {
322 LoadActions.legalForTypesWithMemDesc({{nxv2s8, p0, nxv2s8, 8},
323 {nxv4s8, p0, nxv4s8, 8},
324 {nxv8s8, p0, nxv8s8, 8},
325 {nxv16s8, p0, nxv16s8, 8},
326 {nxv32s8, p0, nxv32s8, 8},
327 {nxv64s8, p0, nxv64s8, 8},
328 {nxv2s16, p0, nxv2s16, 16},
329 {nxv4s16, p0, nxv4s16, 16},
330 {nxv8s16, p0, nxv8s16, 16},
331 {nxv16s16, p0, nxv16s16, 16},
332 {nxv32s16, p0, nxv32s16, 16},
333 {nxv2s32, p0, nxv2s32, 32},
334 {nxv4s32, p0, nxv4s32, 32},
335 {nxv8s32, p0, nxv8s32, 32},
336 {nxv16s32, p0, nxv16s32, 32}});
337 StoreActions.legalForTypesWithMemDesc({{nxv2s8, p0, nxv2s8, 8},
338 {nxv4s8, p0, nxv4s8, 8},
339 {nxv8s8, p0, nxv8s8, 8},
340 {nxv16s8, p0, nxv16s8, 8},
341 {nxv32s8, p0, nxv32s8, 8},
342 {nxv64s8, p0, nxv64s8, 8},
343 {nxv2s16, p0, nxv2s16, 16},
344 {nxv4s16, p0, nxv4s16, 16},
345 {nxv8s16, p0, nxv8s16, 16},
346 {nxv16s16, p0, nxv16s16, 16},
347 {nxv32s16, p0, nxv32s16, 16},
348 {nxv2s32, p0, nxv2s32, 32},
349 {nxv4s32, p0, nxv4s32, 32},
350 {nxv8s32, p0, nxv8s32, 32},
351 {nxv16s32, p0, nxv16s32, 32}});
352
353 if (ST.getELen() == 64) {
354 LoadActions.legalForTypesWithMemDesc({{nxv1s8, p0, nxv1s8, 8},
355 {nxv1s16, p0, nxv1s16, 16},
356 {nxv1s32, p0, nxv1s32, 32}});
357 StoreActions.legalForTypesWithMemDesc({{nxv1s8, p0, nxv1s8, 8},
358 {nxv1s16, p0, nxv1s16, 16},
359 {nxv1s32, p0, nxv1s32, 32}});
360 }
361
362 if (ST.hasVInstructionsI64()) {
363 LoadActions.legalForTypesWithMemDesc({{nxv1s64, p0, nxv1s64, 64},
364 {nxv2s64, p0, nxv2s64, 64},
365 {nxv4s64, p0, nxv4s64, 64},
366 {nxv8s64, p0, nxv8s64, 64}});
367 StoreActions.legalForTypesWithMemDesc({{nxv1s64, p0, nxv1s64, 64},
368 {nxv2s64, p0, nxv2s64, 64},
369 {nxv4s64, p0, nxv4s64, 64},
370 {nxv8s64, p0, nxv8s64, 64}});
371 }
372
373 // we will take the custom lowering logic if we have scalable vector types
374 // with non-standard alignments
375 LoadActions.customIf(typeIsLegalIntOrFPVec(0, IntOrFPVecTys, ST));
376 StoreActions.customIf(typeIsLegalIntOrFPVec(0, IntOrFPVecTys, ST));
377
378 // Pointers require that XLen sized elements are legal.
379 if (XLen <= ST.getELen()) {
380 LoadActions.customIf(typeIsLegalPtrVec(0, PtrVecTys, ST));
381 StoreActions.customIf(typeIsLegalPtrVec(0, PtrVecTys, ST));
382 }
383 }
384
385 LoadActions.widenScalarToNextPow2(0, /* MinSize = */ 8)
387 .clampScalar(0, s32, sXLen)
388 .lower();
389 StoreActions
390 .clampScalar(0, s32, sXLen)
392 .lower();
393
394 ExtLoadActions.widenScalarToNextPow2(0).clampScalar(0, s32, sXLen).lower();
395
396 getActionDefinitionsBuilder({G_PTR_ADD, G_PTRMASK}).legalFor({{p0, sXLen}});
397
399 .legalFor({{sXLen, p0}})
400 .clampScalar(0, sXLen, sXLen);
401
403 .legalFor({{p0, sXLen}})
404 .clampScalar(1, sXLen, sXLen);
405
406 getActionDefinitionsBuilder(G_BRCOND).legalFor({sXLen}).minScalar(0, sXLen);
407
408 getActionDefinitionsBuilder(G_BRJT).legalFor({{p0, sXLen}});
409
410 getActionDefinitionsBuilder(G_BRINDIRECT).legalFor({p0});
411
413 .legalFor({p0, sXLen})
414 .widenScalarToNextPow2(0)
415 .clampScalar(0, sXLen, sXLen);
416
417 getActionDefinitionsBuilder({G_GLOBAL_VALUE, G_JUMP_TABLE, G_CONSTANT_POOL})
418 .legalFor({p0});
419
420 if (ST.hasStdExtZmmul()) {
422 .legalFor({s32, sXLen})
423 .widenScalarToNextPow2(0)
424 .clampScalar(0, s32, sXLen);
425
426 // clang-format off
427 getActionDefinitionsBuilder({G_SMULH, G_UMULH})
428 .legalFor({sXLen})
429 .lower();
430 // clang-format on
431
432 getActionDefinitionsBuilder({G_SMULO, G_UMULO}).minScalar(0, sXLen).lower();
433 } else {
435 .libcallFor({sXLen, sDoubleXLen})
436 .widenScalarToNextPow2(0)
437 .clampScalar(0, sXLen, sDoubleXLen);
438
439 getActionDefinitionsBuilder({G_SMULH, G_UMULH}).lowerFor({sXLen});
440
441 getActionDefinitionsBuilder({G_SMULO, G_UMULO})
442 .minScalar(0, sXLen)
443 // Widen sXLen to sDoubleXLen so we can use a single libcall to get
444 // the low bits for the mul result and high bits to do the overflow
445 // check.
446 .widenScalarIf(typeIs(0, sXLen),
447 LegalizeMutations::changeTo(0, sDoubleXLen))
448 .lower();
449 }
450
451 if (ST.hasStdExtM()) {
452 getActionDefinitionsBuilder({G_UDIV, G_SDIV, G_UREM, G_SREM})
453 .legalFor({sXLen})
454 .libcallFor({sDoubleXLen})
455 .clampScalar(0, sXLen, sDoubleXLen)
457 } else {
458 getActionDefinitionsBuilder({G_UDIV, G_SDIV, G_UREM, G_SREM})
459 .libcallFor({sXLen, sDoubleXLen})
460 .clampScalar(0, sXLen, sDoubleXLen)
462 }
463
464 // TODO: Use libcall for sDoubleXLen.
465 getActionDefinitionsBuilder({G_UDIVREM, G_SDIVREM}).lower();
466
467 auto &AbsActions = getActionDefinitionsBuilder(G_ABS);
468 if (ST.hasStdExtZbb())
469 AbsActions.customFor({sXLen}).minScalar(0, sXLen);
470 AbsActions.lower();
471
472 auto &MinMaxActions =
473 getActionDefinitionsBuilder({G_UMAX, G_UMIN, G_SMAX, G_SMIN});
474 if (ST.hasStdExtZbb())
475 MinMaxActions.legalFor({sXLen}).minScalar(0, sXLen);
476 MinMaxActions.lower();
477
478 getActionDefinitionsBuilder(G_FRAME_INDEX).legalFor({p0});
479
480 getActionDefinitionsBuilder({G_MEMCPY, G_MEMMOVE, G_MEMSET}).libcall();
481
482 getActionDefinitionsBuilder(G_DYN_STACKALLOC).lower();
483
484 // FP Operations
485
486 getActionDefinitionsBuilder({G_FADD, G_FSUB, G_FMUL, G_FDIV, G_FMA, G_FNEG,
487 G_FABS, G_FSQRT, G_FMAXNUM, G_FMINNUM})
488 .legalIf(typeIsScalarFPArith(0, ST));
489
491 .libcallFor({s32, s64})
492 .minScalar(0, s32)
493 .scalarize(0);
494
495 getActionDefinitionsBuilder(G_FCOPYSIGN)
497
498 // FIXME: Use Zfhmin.
500 [=, &ST](const LegalityQuery &Query) -> bool {
501 return (ST.hasStdExtD() && typeIs(0, s32)(Query) &&
502 typeIs(1, s64)(Query)) ||
503 (ST.hasStdExtZfh() && typeIs(0, s16)(Query) &&
504 typeIs(1, s32)(Query)) ||
505 (ST.hasStdExtZfh() && ST.hasStdExtD() && typeIs(0, s16)(Query) &&
506 typeIs(1, s64)(Query));
507 });
509 [=, &ST](const LegalityQuery &Query) -> bool {
510 return (ST.hasStdExtD() && typeIs(0, s64)(Query) &&
511 typeIs(1, s32)(Query)) ||
512 (ST.hasStdExtZfh() && typeIs(0, s32)(Query) &&
513 typeIs(1, s16)(Query)) ||
514 (ST.hasStdExtZfh() && ST.hasStdExtD() && typeIs(0, s64)(Query) &&
515 typeIs(1, s16)(Query));
516 });
517
519 .legalIf(all(typeIs(0, sXLen), typeIsScalarFPArith(1, ST)))
520 .clampScalar(0, sXLen, sXLen);
521
522 // TODO: Support vector version of G_IS_FPCLASS.
523 getActionDefinitionsBuilder(G_IS_FPCLASS)
524 .customIf(all(typeIs(0, s1), typeIsScalarFPArith(1, ST)));
525
526 getActionDefinitionsBuilder(G_FCONSTANT)
528 .lowerFor({s32, s64});
529
530 getActionDefinitionsBuilder({G_FPTOSI, G_FPTOUI})
531 .legalIf(all(typeInSet(0, {s32, sXLen}), typeIsScalarFPArith(1, ST)))
533 .clampScalar(0, s32, sXLen)
534 .libcall();
535
536 getActionDefinitionsBuilder({G_SITOFP, G_UITOFP})
537 .legalIf(all(typeIsScalarFPArith(0, ST), typeInSet(1, {s32, sXLen})))
539 .clampScalar(1, s32, sXLen);
540
541 // FIXME: We can do custom inline expansion like SelectionDAG.
542 // FIXME: Legal with Zfa.
543 getActionDefinitionsBuilder({G_FCEIL, G_FFLOOR})
544 .libcallFor({s32, s64});
545
546 getActionDefinitionsBuilder(G_VASTART).customFor({p0});
547
548 // va_list must be a pointer, but most sized types are pretty easy to handle
549 // as the destination.
551 // TODO: Implement narrowScalar and widenScalar for G_VAARG for types
552 // other than sXLen.
553 .clampScalar(0, sXLen, sXLen)
554 .lowerForCartesianProduct({sXLen, p0}, {p0});
555
557 .clampScalar(0, sXLen, sXLen)
558 .customFor({sXLen});
559
560 auto &SplatActions =
561 getActionDefinitionsBuilder(G_SPLAT_VECTOR)
562 .legalIf(all(typeIsLegalIntOrFPVec(0, IntOrFPVecTys, ST),
563 typeIs(1, sXLen)))
564 .customIf(all(typeIsLegalBoolVec(0, BoolVecTys, ST), typeIs(1, s1)));
565 // Handle case of s64 element vectors on RV32. If the subtarget does not have
566 // f64, then try to lower it to G_SPLAT_VECTOR_SPLIT_64_VL. If the subtarget
567 // does have f64, then we don't know whether the type is an f64 or an i64,
568 // so mark the G_SPLAT_VECTOR as legal and decide later what to do with it,
569 // depending on how the instructions it consumes are legalized. They are not
570 // legalized yet since legalization is in reverse postorder, so we cannot
571 // make the decision at this moment.
572 if (XLen == 32) {
573 if (ST.hasVInstructionsF64() && ST.hasStdExtD())
574 SplatActions.legalIf(all(
575 typeInSet(0, {nxv1s64, nxv2s64, nxv4s64, nxv8s64}), typeIs(1, s64)));
576 else if (ST.hasVInstructionsI64())
577 SplatActions.customIf(all(
578 typeInSet(0, {nxv1s64, nxv2s64, nxv4s64, nxv8s64}), typeIs(1, s64)));
579 }
580
581 SplatActions.clampScalar(1, sXLen, sXLen);
582
584}
585
587 MachineInstr &MI) const {
588 Intrinsic::ID IntrinsicID = cast<GIntrinsic>(MI).getIntrinsicID();
589 switch (IntrinsicID) {
590 default:
591 return false;
592 case Intrinsic::vacopy: {
593 // vacopy arguments must be legal because of the intrinsic signature.
594 // No need to check here.
595
596 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
597 MachineRegisterInfo &MRI = *MIRBuilder.getMRI();
598 MachineFunction &MF = *MI.getMF();
599 const DataLayout &DL = MIRBuilder.getDataLayout();
600 LLVMContext &Ctx = MF.getFunction().getContext();
601
602 Register DstLst = MI.getOperand(1).getReg();
603 LLT PtrTy = MRI.getType(DstLst);
604
605 // Load the source va_list
606 Align Alignment = DL.getABITypeAlign(getTypeForLLT(PtrTy, Ctx));
608 MachinePointerInfo(), MachineMemOperand::MOLoad, PtrTy, Alignment);
609 auto Tmp = MIRBuilder.buildLoad(PtrTy, MI.getOperand(2), *LoadMMO);
610
611 // Store the result in the destination va_list
614 MIRBuilder.buildStore(Tmp, DstLst, *StoreMMO);
615
616 MI.eraseFromParent();
617 return true;
618 }
619 }
620}
621
622bool RISCVLegalizerInfo::legalizeShlAshrLshr(
623 MachineInstr &MI, MachineIRBuilder &MIRBuilder,
624 GISelChangeObserver &Observer) const {
625 assert(MI.getOpcode() == TargetOpcode::G_ASHR ||
626 MI.getOpcode() == TargetOpcode::G_LSHR ||
627 MI.getOpcode() == TargetOpcode::G_SHL);
628 MachineRegisterInfo &MRI = *MIRBuilder.getMRI();
629 // If the shift amount is a G_CONSTANT, promote it to a 64 bit type so the
630 // imported patterns can select it later. Either way, it will be legal.
631 Register AmtReg = MI.getOperand(2).getReg();
632 auto VRegAndVal = getIConstantVRegValWithLookThrough(AmtReg, MRI);
633 if (!VRegAndVal)
634 return true;
635 // Check the shift amount is in range for an immediate form.
636 uint64_t Amount = VRegAndVal->Value.getZExtValue();
637 if (Amount > 31)
638 return true; // This will have to remain a register variant.
639 auto ExtCst = MIRBuilder.buildConstant(LLT::scalar(64), Amount);
640 Observer.changingInstr(MI);
641 MI.getOperand(2).setReg(ExtCst.getReg(0));
642 Observer.changedInstr(MI);
643 return true;
644}
645
646bool RISCVLegalizerInfo::legalizeVAStart(MachineInstr &MI,
647 MachineIRBuilder &MIRBuilder) const {
648 // Stores the address of the VarArgsFrameIndex slot into the memory location
649 assert(MI.getOpcode() == TargetOpcode::G_VASTART);
650 MachineFunction *MF = MI.getParent()->getParent();
652 int FI = FuncInfo->getVarArgsFrameIndex();
653 LLT AddrTy = MIRBuilder.getMRI()->getType(MI.getOperand(0).getReg());
654 auto FINAddr = MIRBuilder.buildFrameIndex(AddrTy, FI);
655 assert(MI.hasOneMemOperand());
656 MIRBuilder.buildStore(FINAddr, MI.getOperand(0).getReg(),
657 *MI.memoperands()[0]);
658 MI.eraseFromParent();
659 return true;
660}
661
662bool RISCVLegalizerInfo::shouldBeInConstantPool(APInt APImm,
663 bool ShouldOptForSize) const {
664 assert(APImm.getBitWidth() == 32 || APImm.getBitWidth() == 64);
665 int64_t Imm = APImm.getSExtValue();
666 // All simm32 constants should be handled by isel.
667 // NOTE: The getMaxBuildIntsCost call below should return a value >= 2 making
668 // this check redundant, but small immediates are common so this check
669 // should have better compile time.
670 if (isInt<32>(Imm))
671 return false;
672
673 // We only need to cost the immediate, if constant pool lowering is enabled.
675 return false;
676
678 if (Seq.size() <= STI.getMaxBuildIntsCost())
679 return false;
680
681 // Optimizations below are disabled for opt size. If we're optimizing for
682 // size, use a constant pool.
683 if (ShouldOptForSize)
684 return true;
685 //
686 // Special case. See if we can build the constant as (ADD (SLLI X, C), X) do
687 // that if it will avoid a constant pool.
688 // It will require an extra temporary register though.
689 // If we have Zba we can use (ADD_UW X, (SLLI X, 32)) to handle cases where
690 // low and high 32 bits are the same and bit 31 and 63 are set.
691 unsigned ShiftAmt, AddOpc;
693 RISCVMatInt::generateTwoRegInstSeq(Imm, STI, ShiftAmt, AddOpc);
694 return !(!SeqLo.empty() && (SeqLo.size() + 2) <= STI.getMaxBuildIntsCost());
695}
696
697bool RISCVLegalizerInfo::legalizeVScale(MachineInstr &MI,
698 MachineIRBuilder &MIB) const {
699 const LLT XLenTy(STI.getXLenVT());
700 Register Dst = MI.getOperand(0).getReg();
701
702 // We define our scalable vector types for lmul=1 to use a 64 bit known
703 // minimum size. e.g. <vscale x 2 x i32>. VLENB is in bytes so we calculate
704 // vscale as VLENB / 8.
705 static_assert(RISCV::RVVBitsPerBlock == 64, "Unexpected bits per block!");
707 // Support for VLEN==32 is incomplete.
708 return false;
709
710 // We assume VLENB is a multiple of 8. We manually choose the best shift
711 // here because SimplifyDemandedBits isn't always able to simplify it.
712 uint64_t Val = MI.getOperand(1).getCImm()->getZExtValue();
713 if (isPowerOf2_64(Val)) {
714 uint64_t Log2 = Log2_64(Val);
715 if (Log2 < 3) {
716 auto VLENB = MIB.buildInstr(RISCV::G_READ_VLENB, {XLenTy}, {});
717 MIB.buildLShr(Dst, VLENB, MIB.buildConstant(XLenTy, 3 - Log2));
718 } else if (Log2 > 3) {
719 auto VLENB = MIB.buildInstr(RISCV::G_READ_VLENB, {XLenTy}, {});
720 MIB.buildShl(Dst, VLENB, MIB.buildConstant(XLenTy, Log2 - 3));
721 } else {
722 MIB.buildInstr(RISCV::G_READ_VLENB, {Dst}, {});
723 }
724 } else if ((Val % 8) == 0) {
725 // If the multiplier is a multiple of 8, scale it down to avoid needing
726 // to shift the VLENB value.
727 auto VLENB = MIB.buildInstr(RISCV::G_READ_VLENB, {XLenTy}, {});
728 MIB.buildMul(Dst, VLENB, MIB.buildConstant(XLenTy, Val / 8));
729 } else {
730 auto VLENB = MIB.buildInstr(RISCV::G_READ_VLENB, {XLenTy}, {});
731 auto VScale = MIB.buildLShr(XLenTy, VLENB, MIB.buildConstant(XLenTy, 3));
732 MIB.buildMul(Dst, VScale, MIB.buildConstant(XLenTy, Val));
733 }
734 MI.eraseFromParent();
735 return true;
736}
737
738// Custom-lower extensions from mask vectors by using a vselect either with 1
739// for zero/any-extension or -1 for sign-extension:
740// (vXiN = (s|z)ext vXi1:vmask) -> (vXiN = vselect vmask, (-1 or 1), 0)
741// Note that any-extension is lowered identically to zero-extension.
742bool RISCVLegalizerInfo::legalizeExt(MachineInstr &MI,
743 MachineIRBuilder &MIB) const {
744
745 unsigned Opc = MI.getOpcode();
746 assert(Opc == TargetOpcode::G_ZEXT || Opc == TargetOpcode::G_SEXT ||
747 Opc == TargetOpcode::G_ANYEXT);
748
750 Register Dst = MI.getOperand(0).getReg();
751 Register Src = MI.getOperand(1).getReg();
752
753 LLT DstTy = MRI.getType(Dst);
754 int64_t ExtTrueVal = Opc == TargetOpcode::G_SEXT ? -1 : 1;
755 LLT DstEltTy = DstTy.getElementType();
756 auto SplatZero = MIB.buildSplatVector(DstTy, MIB.buildConstant(DstEltTy, 0));
757 auto SplatTrue =
758 MIB.buildSplatVector(DstTy, MIB.buildConstant(DstEltTy, ExtTrueVal));
759 MIB.buildSelect(Dst, Src, SplatTrue, SplatZero);
760
761 MI.eraseFromParent();
762 return true;
763}
764
765bool RISCVLegalizerInfo::legalizeLoadStore(MachineInstr &MI,
766 LegalizerHelper &Helper,
767 MachineIRBuilder &MIB) const {
768 assert((isa<GLoad>(MI) || isa<GStore>(MI)) &&
769 "Machine instructions must be Load/Store.");
771 MachineFunction *MF = MI.getMF();
772 const DataLayout &DL = MIB.getDataLayout();
773 LLVMContext &Ctx = MF->getFunction().getContext();
774
775 Register DstReg = MI.getOperand(0).getReg();
776 LLT DataTy = MRI.getType(DstReg);
777 if (!DataTy.isVector())
778 return false;
779
780 if (!MI.hasOneMemOperand())
781 return false;
782
783 MachineMemOperand *MMO = *MI.memoperands_begin();
784
785 const auto *TLI = STI.getTargetLowering();
786 EVT VT = EVT::getEVT(getTypeForLLT(DataTy, Ctx));
787
788 if (TLI->allowsMemoryAccessForAlignment(Ctx, DL, VT, *MMO))
789 return true;
790
791 unsigned EltSizeBits = DataTy.getScalarSizeInBits();
792 assert((EltSizeBits == 16 || EltSizeBits == 32 || EltSizeBits == 64) &&
793 "Unexpected unaligned RVV load type");
794
795 // Calculate the new vector type with i8 elements
796 unsigned NumElements =
797 DataTy.getElementCount().getKnownMinValue() * (EltSizeBits / 8);
798 LLT NewDataTy = LLT::scalable_vector(NumElements, 8);
799
800 Helper.bitcast(MI, 0, NewDataTy);
801
802 return true;
803}
804
805/// Return the type of the mask type suitable for masking the provided
806/// vector type. This is simply an i1 element type vector of the same
807/// (possibly scalable) length.
808static LLT getMaskTypeFor(LLT VecTy) {
809 assert(VecTy.isVector());
810 ElementCount EC = VecTy.getElementCount();
811 return LLT::vector(EC, LLT::scalar(1));
812}
813
814/// Creates an all ones mask suitable for masking a vector of type VecTy with
815/// vector length VL.
817 MachineIRBuilder &MIB,
819 LLT MaskTy = getMaskTypeFor(VecTy);
820 return MIB.buildInstr(RISCV::G_VMSET_VL, {MaskTy}, {VL});
821}
822
823/// Gets the two common "VL" operands: an all-ones mask and the vector length.
824/// VecTy is a scalable vector type.
825static std::pair<MachineInstrBuilder, Register>
828 LLT VecTy = Dst.getLLTTy(MRI);
829 assert(VecTy.isScalableVector() && "Expecting scalable container type");
830 Register VL(RISCV::X0);
831 MachineInstrBuilder Mask = buildAllOnesMask(VecTy, VL, MIB, MRI);
832 return {Mask, VL};
833}
834
836buildSplatPartsS64WithVL(const DstOp &Dst, const SrcOp &Passthru, Register Lo,
839 // TODO: If the Hi bits of the splat are undefined, then it's fine to just
840 // splat Lo even if it might be sign extended. I don't think we have
841 // introduced a case where we're build a s64 where the upper bits are undef
842 // yet.
843
844 // Fall back to a stack store and stride x0 vector load.
845 // TODO: need to lower G_SPLAT_VECTOR_SPLIT_I64. This is done in
846 // preprocessDAG in SDAG.
847 return MIB.buildInstr(RISCV::G_SPLAT_VECTOR_SPLIT_I64_VL, {Dst},
848 {Passthru, Lo, Hi, VL});
849}
850
852buildSplatSplitS64WithVL(const DstOp &Dst, const SrcOp &Passthru,
853 const SrcOp &Scalar, Register VL,
855 assert(Scalar.getLLTTy(MRI) == LLT::scalar(64) && "Unexpected VecTy!");
856 auto Unmerge = MIB.buildUnmerge(LLT::scalar(32), Scalar);
857 return buildSplatPartsS64WithVL(Dst, Passthru, Unmerge.getReg(0),
858 Unmerge.getReg(1), VL, MIB, MRI);
859}
860
861// Lower splats of s1 types to G_ICMP. For each mask vector type, we have a
862// legal equivalently-sized i8 type, so we can use that as a go-between.
863// Splats of s1 types that have constant value can be legalized as VMSET_VL or
864// VMCLR_VL.
865bool RISCVLegalizerInfo::legalizeSplatVector(MachineInstr &MI,
866 MachineIRBuilder &MIB) const {
867 assert(MI.getOpcode() == TargetOpcode::G_SPLAT_VECTOR);
868
870
871 Register Dst = MI.getOperand(0).getReg();
872 Register SplatVal = MI.getOperand(1).getReg();
873
874 LLT VecTy = MRI.getType(Dst);
875 LLT XLenTy(STI.getXLenVT());
876
877 // Handle case of s64 element vectors on rv32
878 if (XLenTy.getSizeInBits() == 32 &&
879 VecTy.getElementType().getSizeInBits() == 64) {
880 auto [_, VL] = buildDefaultVLOps(Dst, MIB, MRI);
881 buildSplatSplitS64WithVL(Dst, MIB.buildUndef(VecTy), SplatVal, VL, MIB,
882 MRI);
883 MI.eraseFromParent();
884 return true;
885 }
886
887 // All-zeros or all-ones splats are handled specially.
888 MachineInstr &SplatValMI = *MRI.getVRegDef(SplatVal);
889 if (isAllOnesOrAllOnesSplat(SplatValMI, MRI)) {
890 auto VL = buildDefaultVLOps(VecTy, MIB, MRI).second;
891 MIB.buildInstr(RISCV::G_VMSET_VL, {Dst}, {VL});
892 MI.eraseFromParent();
893 return true;
894 }
895 if (isNullOrNullSplat(SplatValMI, MRI)) {
896 auto VL = buildDefaultVLOps(VecTy, MIB, MRI).second;
897 MIB.buildInstr(RISCV::G_VMCLR_VL, {Dst}, {VL});
898 MI.eraseFromParent();
899 return true;
900 }
901
902 // Handle non-constant mask splat (i.e. not sure if it's all zeros or all
903 // ones) by promoting it to an s8 splat.
904 LLT InterEltTy = LLT::scalar(8);
905 LLT InterTy = VecTy.changeElementType(InterEltTy);
906 auto ZExtSplatVal = MIB.buildZExt(InterEltTy, SplatVal);
907 auto And =
908 MIB.buildAnd(InterEltTy, ZExtSplatVal, MIB.buildConstant(InterEltTy, 1));
909 auto LHS = MIB.buildSplatVector(InterTy, And);
910 auto ZeroSplat =
911 MIB.buildSplatVector(InterTy, MIB.buildConstant(InterEltTy, 0));
912 MIB.buildICmp(CmpInst::Predicate::ICMP_NE, Dst, LHS, ZeroSplat);
913 MI.eraseFromParent();
914 return true;
915}
916
919 LostDebugLocObserver &LocObserver) const {
920 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
921 MachineRegisterInfo &MRI = *MIRBuilder.getMRI();
922 GISelChangeObserver &Observer = Helper.Observer;
923 MachineFunction &MF = *MI.getParent()->getParent();
924 switch (MI.getOpcode()) {
925 default:
926 // No idea what to do.
927 return false;
928 case TargetOpcode::G_ABS:
929 return Helper.lowerAbsToMaxNeg(MI);
930 // TODO: G_FCONSTANT
931 case TargetOpcode::G_CONSTANT: {
932 const Function &F = MF.getFunction();
933 // TODO: if PSI and BFI are present, add " ||
934 // llvm::shouldOptForSize(*CurMBB, PSI, BFI)".
935 bool ShouldOptForSize = F.hasOptSize() || F.hasMinSize();
936 const ConstantInt *ConstVal = MI.getOperand(1).getCImm();
937 if (!shouldBeInConstantPool(ConstVal->getValue(), ShouldOptForSize))
938 return true;
939 return Helper.lowerConstant(MI);
940 }
941 case TargetOpcode::G_SHL:
942 case TargetOpcode::G_ASHR:
943 case TargetOpcode::G_LSHR:
944 return legalizeShlAshrLshr(MI, MIRBuilder, Observer);
945 case TargetOpcode::G_SEXT_INREG: {
946 LLT DstTy = MRI.getType(MI.getOperand(0).getReg());
947 int64_t SizeInBits = MI.getOperand(2).getImm();
948 // Source size of 32 is sext.w.
949 if (DstTy.getSizeInBits() == 64 && SizeInBits == 32)
950 return true;
951
952 if (STI.hasStdExtZbb() && (SizeInBits == 8 || SizeInBits == 16))
953 return true;
954
955 return Helper.lower(MI, 0, /* Unused hint type */ LLT()) ==
957 }
958 case TargetOpcode::G_IS_FPCLASS: {
959 Register GISFPCLASS = MI.getOperand(0).getReg();
960 Register Src = MI.getOperand(1).getReg();
961 const MachineOperand &ImmOp = MI.getOperand(2);
962 MachineIRBuilder MIB(MI);
963
964 // Turn LLVM IR's floating point classes to that in RISC-V,
965 // by simply rotating the 10-bit immediate right by two bits.
966 APInt GFpClassImm(10, static_cast<uint64_t>(ImmOp.getImm()));
967 auto FClassMask = MIB.buildConstant(sXLen, GFpClassImm.rotr(2).zext(XLen));
968 auto ConstZero = MIB.buildConstant(sXLen, 0);
969
970 auto GFClass = MIB.buildInstr(RISCV::G_FCLASS, {sXLen}, {Src});
971 auto And = MIB.buildAnd(sXLen, GFClass, FClassMask);
972 MIB.buildICmp(CmpInst::ICMP_NE, GISFPCLASS, And, ConstZero);
973
974 MI.eraseFromParent();
975 return true;
976 }
977 case TargetOpcode::G_VASTART:
978 return legalizeVAStart(MI, MIRBuilder);
979 case TargetOpcode::G_VSCALE:
980 return legalizeVScale(MI, MIRBuilder);
981 case TargetOpcode::G_ZEXT:
982 case TargetOpcode::G_SEXT:
983 case TargetOpcode::G_ANYEXT:
984 return legalizeExt(MI, MIRBuilder);
985 case TargetOpcode::G_SPLAT_VECTOR:
986 return legalizeSplatVector(MI, MIRBuilder);
987 case TargetOpcode::G_LOAD:
988 case TargetOpcode::G_STORE:
989 return legalizeLoadStore(MI, Helper, MIRBuilder);
990 }
991
992 llvm_unreachable("expected switch to return");
993}
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,...