LLVM 23.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"
29#include "llvm/IR/Intrinsics.h"
30#include "llvm/IR/IntrinsicsRISCV.h"
31#include "llvm/IR/Type.h"
32
33using namespace llvm;
34using namespace LegalityPredicates;
35using namespace LegalizeMutations;
36
38typeIsLegalIntOrFPVec(unsigned TypeIdx,
39 std::initializer_list<LLT> IntOrFPVecTys,
40 const RISCVSubtarget &ST) {
41 LegalityPredicate P = [=, &ST](const LegalityQuery &Query) {
42 return ST.hasVInstructions() &&
43 (Query.Types[TypeIdx].getScalarSizeInBits() != 64 ||
44 ST.hasVInstructionsI64()) &&
45 (Query.Types[TypeIdx].getElementCount().getKnownMinValue() != 1 ||
46 ST.getELen() == 64);
47 };
48
49 return all(typeInSet(TypeIdx, IntOrFPVecTys), P);
50}
51
53typeIsLegalBoolVec(unsigned TypeIdx, std::initializer_list<LLT> BoolVecTys,
54 const RISCVSubtarget &ST) {
55 LegalityPredicate P = [=, &ST](const LegalityQuery &Query) {
56 return ST.hasVInstructions() &&
57 (Query.Types[TypeIdx].getElementCount().getKnownMinValue() != 1 ||
58 ST.getELen() == 64);
59 };
60 return all(typeInSet(TypeIdx, BoolVecTys), P);
61}
62
63static LegalityPredicate typeIsLegalPtrVec(unsigned TypeIdx,
64 std::initializer_list<LLT> PtrVecTys,
65 const RISCVSubtarget &ST) {
66 LegalityPredicate P = [=, &ST](const LegalityQuery &Query) {
67 return ST.hasVInstructions() &&
68 (Query.Types[TypeIdx].getElementCount().getKnownMinValue() != 1 ||
69 ST.getELen() == 64) &&
70 (Query.Types[TypeIdx].getElementCount().getKnownMinValue() != 16 ||
71 Query.Types[TypeIdx].getScalarSizeInBits() == 32);
72 };
73 return all(typeInSet(TypeIdx, PtrVecTys), P);
74}
75
77 : STI(ST), XLen(STI.getXLen()), sXLen(LLT::scalar(XLen)) {
78 const LLT sDoubleXLen = LLT::scalar(2 * XLen);
79 const LLT p0 = LLT::pointer(0, XLen);
80 const LLT s1 = LLT::scalar(1);
81 const LLT s8 = LLT::scalar(8);
82 const LLT s16 = LLT::scalar(16);
83 const LLT s32 = LLT::scalar(32);
84 const LLT s64 = LLT::scalar(64);
85 const LLT s128 = LLT::scalar(128);
86
87 const LLT nxv1s1 = LLT::scalable_vector(1, s1);
88 const LLT nxv2s1 = LLT::scalable_vector(2, s1);
89 const LLT nxv4s1 = LLT::scalable_vector(4, s1);
90 const LLT nxv8s1 = LLT::scalable_vector(8, s1);
91 const LLT nxv16s1 = LLT::scalable_vector(16, s1);
92 const LLT nxv32s1 = LLT::scalable_vector(32, s1);
93 const LLT nxv64s1 = LLT::scalable_vector(64, s1);
94
95 const LLT nxv1s8 = LLT::scalable_vector(1, s8);
96 const LLT nxv2s8 = LLT::scalable_vector(2, s8);
97 const LLT nxv4s8 = LLT::scalable_vector(4, s8);
98 const LLT nxv8s8 = LLT::scalable_vector(8, s8);
99 const LLT nxv16s8 = LLT::scalable_vector(16, s8);
100 const LLT nxv32s8 = LLT::scalable_vector(32, s8);
101 const LLT nxv64s8 = LLT::scalable_vector(64, s8);
102
103 const LLT nxv1s16 = LLT::scalable_vector(1, s16);
104 const LLT nxv2s16 = LLT::scalable_vector(2, s16);
105 const LLT nxv4s16 = LLT::scalable_vector(4, s16);
106 const LLT nxv8s16 = LLT::scalable_vector(8, s16);
107 const LLT nxv16s16 = LLT::scalable_vector(16, s16);
108 const LLT nxv32s16 = LLT::scalable_vector(32, s16);
109
110 const LLT nxv1s32 = LLT::scalable_vector(1, s32);
111 const LLT nxv2s32 = LLT::scalable_vector(2, s32);
112 const LLT nxv4s32 = LLT::scalable_vector(4, s32);
113 const LLT nxv8s32 = LLT::scalable_vector(8, s32);
114 const LLT nxv16s32 = LLT::scalable_vector(16, s32);
115
116 const LLT nxv1s64 = LLT::scalable_vector(1, s64);
117 const LLT nxv2s64 = LLT::scalable_vector(2, s64);
118 const LLT nxv4s64 = LLT::scalable_vector(4, s64);
119 const LLT nxv8s64 = LLT::scalable_vector(8, s64);
120
121 const LLT nxv1p0 = LLT::scalable_vector(1, p0);
122 const LLT nxv2p0 = LLT::scalable_vector(2, p0);
123 const LLT nxv4p0 = LLT::scalable_vector(4, p0);
124 const LLT nxv8p0 = LLT::scalable_vector(8, p0);
125 const LLT nxv16p0 = LLT::scalable_vector(16, p0);
126
127 using namespace TargetOpcode;
128
129 auto BoolVecTys = {nxv1s1, nxv2s1, nxv4s1, nxv8s1, nxv16s1, nxv32s1, nxv64s1};
130
131 auto IntOrFPVecTys = {nxv1s8, nxv2s8, nxv4s8, nxv8s8, nxv16s8, nxv32s8,
132 nxv64s8, nxv1s16, nxv2s16, nxv4s16, nxv8s16, nxv16s16,
133 nxv32s16, nxv1s32, nxv2s32, nxv4s32, nxv8s32, nxv16s32,
134 nxv1s64, nxv2s64, nxv4s64, nxv8s64};
135
136 auto PtrVecTys = {nxv1p0, nxv2p0, nxv4p0, nxv8p0, nxv16p0};
137
138 getActionDefinitionsBuilder({G_ADD, G_SUB})
139 .legalFor({sXLen})
140 .legalIf(typeIsLegalIntOrFPVec(0, IntOrFPVecTys, ST))
141 .customFor(ST.is64Bit(), {s32})
143 .clampScalar(0, sXLen, sXLen);
144
145 getActionDefinitionsBuilder({G_AND, G_OR, G_XOR})
146 .legalFor({sXLen})
147 .legalIf(typeIsLegalIntOrFPVec(0, IntOrFPVecTys, ST))
149 .clampScalar(0, sXLen, sXLen);
150
152 {G_UADDE, G_UADDO, G_USUBE, G_USUBO, G_READ_REGISTER, G_WRITE_REGISTER})
153 .lower();
154
155 getActionDefinitionsBuilder({G_SADDE, G_SADDO, G_SSUBE, G_SSUBO})
156 .minScalar(0, sXLen)
157 .lower();
158
159 // TODO: Use Vector Single-Width Saturating Instructions for vector types.
161 {G_UADDSAT, G_SADDSAT, G_USUBSAT, G_SSUBSAT, G_SSHLSAT, G_USHLSAT})
162 .lower();
163
164 getActionDefinitionsBuilder({G_SHL, G_ASHR, G_LSHR})
165 .legalFor({{sXLen, sXLen}})
166 .customFor(ST.is64Bit(), {{s32, s32}})
167 .widenScalarToNextPow2(0)
168 .clampScalar(1, sXLen, sXLen)
169 .clampScalar(0, sXLen, sXLen);
170
171 getActionDefinitionsBuilder({G_ZEXT, G_SEXT, G_ANYEXT})
172 .legalFor({{s32, s16}})
173 .legalFor(ST.is64Bit(), {{s64, s16}, {s64, s32}})
174 .legalIf(all(typeIsLegalIntOrFPVec(0, IntOrFPVecTys, ST),
175 typeIsLegalIntOrFPVec(1, IntOrFPVecTys, ST)))
176 .customIf(typeIsLegalBoolVec(1, BoolVecTys, ST))
177 .maxScalar(0, sXLen);
178
179 getActionDefinitionsBuilder(G_TRUNC).alwaysLegal();
180
181 getActionDefinitionsBuilder(G_SEXT_INREG)
182 .customFor({sXLen})
183 .clampScalar(0, sXLen, sXLen)
184 .lower();
185
186 // Merge/Unmerge
187 for (unsigned Op : {G_MERGE_VALUES, G_UNMERGE_VALUES}) {
188 auto &MergeUnmergeActions = getActionDefinitionsBuilder(Op);
189 unsigned BigTyIdx = Op == G_MERGE_VALUES ? 0 : 1;
190 unsigned LitTyIdx = Op == G_MERGE_VALUES ? 1 : 0;
191 if (XLen == 32 && ST.hasStdExtD()) {
192 MergeUnmergeActions.legalIf(
193 all(typeIs(BigTyIdx, s64), typeIs(LitTyIdx, s32)));
194 }
195 MergeUnmergeActions.widenScalarToNextPow2(LitTyIdx, XLen)
196 .widenScalarToNextPow2(BigTyIdx, XLen)
197 .clampScalar(LitTyIdx, sXLen, sXLen)
198 .clampScalar(BigTyIdx, sXLen, sXLen);
199 }
200
201 getActionDefinitionsBuilder({G_FSHL, G_FSHR}).lower();
202
203 getActionDefinitionsBuilder({G_ROTR, G_ROTL})
204 .legalFor(ST.hasStdExtZbb() || ST.hasStdExtZbkb(), {{sXLen, sXLen}})
205 .customFor(ST.is64Bit() && (ST.hasStdExtZbb() || ST.hasStdExtZbkb()),
206 {{s32, s32}})
207 .lower();
208
209 getActionDefinitionsBuilder(G_BITREVERSE)
210 .customFor(ST.hasStdExtZbkb(), {s8})
211 .maxScalar(0, sXLen)
212 .lower();
213
214 getActionDefinitionsBuilder(G_BITCAST).legalIf(
216 typeIsLegalBoolVec(0, BoolVecTys, ST)),
218 typeIsLegalBoolVec(1, BoolVecTys, ST))));
219
220 auto &BSWAPActions = getActionDefinitionsBuilder(G_BSWAP);
221 if (ST.hasStdExtZbb() || ST.hasStdExtZbkb())
222 BSWAPActions.legalFor({sXLen}).clampScalar(0, sXLen, sXLen);
223 else
224 BSWAPActions.maxScalar(0, sXLen).lower();
225
226 auto &CountZerosActions = getActionDefinitionsBuilder({G_CTLZ, G_CTTZ});
227 auto &CountZerosPoisonActions =
228 getActionDefinitionsBuilder({G_CTLZ_ZERO_POISON, G_CTTZ_ZERO_POISON});
229 if (ST.hasStdExtZbb()) {
230 CountZerosActions.legalFor({{sXLen, sXLen}})
231 .customFor({{s32, s32}})
232 .clampScalar(0, s32, sXLen)
233 .widenScalarToNextPow2(0)
234 .scalarSameSizeAs(1, 0);
235 } else {
236 CountZerosActions.maxScalar(0, sXLen).scalarSameSizeAs(1, 0).lower();
237 CountZerosPoisonActions.maxScalar(0, sXLen).scalarSameSizeAs(1, 0);
238 }
239 CountZerosPoisonActions.lower();
240
241 auto &CountSignActions = getActionDefinitionsBuilder(G_CTLS);
242 if (ST.hasStdExtP()) {
243 CountSignActions.legalFor({{sXLen, sXLen}})
244 .customFor({{s32, s32}})
245 .clampScalar(0, s32, sXLen)
246 .widenScalarToNextPow2(0)
247 .scalarSameSizeAs(1, 0);
248 } else {
249 CountSignActions.maxScalar(0, sXLen).scalarSameSizeAs(1, 0).lower();
250 }
251
252 auto &CTPOPActions = getActionDefinitionsBuilder(G_CTPOP);
253 if (ST.hasStdExtZbb()) {
254 CTPOPActions.legalFor({{sXLen, sXLen}})
255 .clampScalar(0, sXLen, sXLen)
256 .scalarSameSizeAs(1, 0);
257 } else {
258 CTPOPActions.widenScalarToNextPow2(0, /*Min*/ 8)
259 .clampScalar(0, s8, sXLen)
260 .scalarSameSizeAs(1, 0)
261 .lower();
262 }
263
264 getActionDefinitionsBuilder(G_CONSTANT)
265 .legalFor({p0})
266 .legalFor(!ST.is64Bit(), {s32})
267 .customFor(ST.is64Bit(), {s64})
268 .widenScalarToNextPow2(0)
269 .clampScalar(0, sXLen, sXLen);
270
271 // TODO: transform illegal vector types into legal vector type
272 getActionDefinitionsBuilder(G_FREEZE)
273 .legalFor({s16, s32, p0})
274 .legalFor(ST.is64Bit(), {s64})
275 .legalIf(typeIsLegalBoolVec(0, BoolVecTys, ST))
276 .legalIf(typeIsLegalIntOrFPVec(0, IntOrFPVecTys, ST))
277 .widenScalarToNextPow2(0)
278 .clampScalar(0, s16, sXLen);
279
280 // TODO: transform illegal vector types into legal vector type
281 // TODO: Merge with G_FREEZE?
282 getActionDefinitionsBuilder(
283 {G_IMPLICIT_DEF, G_CONSTANT_FOLD_BARRIER})
284 .legalFor({s32, sXLen, p0})
285 .legalIf(typeIsLegalBoolVec(0, BoolVecTys, ST))
286 .legalIf(typeIsLegalIntOrFPVec(0, IntOrFPVecTys, ST))
287 .widenScalarToNextPow2(0)
288 .clampScalar(0, s32, sXLen);
289
290 getActionDefinitionsBuilder(G_ICMP)
291 .legalFor({{sXLen, sXLen}, {sXLen, p0}})
292 .legalIf(all(typeIsLegalBoolVec(0, BoolVecTys, ST),
293 typeIsLegalIntOrFPVec(1, IntOrFPVecTys, ST)))
294 .widenScalarOrEltToNextPow2OrMinSize(1, 8)
295 .clampScalar(1, sXLen, sXLen)
296 .clampScalar(0, sXLen, sXLen);
297
298 getActionDefinitionsBuilder(G_SELECT)
299 .legalFor({{s32, sXLen}, {p0, sXLen}})
300 .legalIf(all(typeIsLegalIntOrFPVec(0, IntOrFPVecTys, ST),
301 typeIsLegalBoolVec(1, BoolVecTys, ST)))
302 .legalFor(XLen == 64 || ST.hasStdExtD(), {{s64, sXLen}})
303 .widenScalarToNextPow2(0)
304 .clampScalar(0, s32, (XLen == 64 || ST.hasStdExtD()) ? s64 : s32)
305 .clampScalar(1, sXLen, sXLen);
306
307 auto &LoadActions = getActionDefinitionsBuilder(G_LOAD);
308 auto &StoreActions = getActionDefinitionsBuilder(G_STORE);
309 auto &ExtLoadActions = getActionDefinitionsBuilder({G_SEXTLOAD, G_ZEXTLOAD});
310
311 // Return the alignment needed for scalar memory ops. If unaligned scalar mem
312 // is supported, we only require byte alignment. Otherwise, we need the memory
313 // op to be natively aligned.
314 auto getScalarMemAlign = [&ST](unsigned Size) {
315 return ST.enableUnalignedScalarMem() ? 8 : Size;
316 };
317
318 LoadActions.legalForTypesWithMemDesc(
319 {{s16, p0, s8, getScalarMemAlign(8)},
320 {s32, p0, s8, getScalarMemAlign(8)},
321 {s16, p0, s16, getScalarMemAlign(16)},
322 {s32, p0, s16, getScalarMemAlign(16)},
323 {s32, p0, s32, getScalarMemAlign(32)},
324 {p0, p0, sXLen, getScalarMemAlign(XLen)}});
325 StoreActions.legalForTypesWithMemDesc(
326 {{s16, p0, s8, getScalarMemAlign(8)},
327 {s32, p0, s8, getScalarMemAlign(8)},
328 {s16, p0, s16, getScalarMemAlign(16)},
329 {s32, p0, s16, getScalarMemAlign(16)},
330 {s32, p0, s32, getScalarMemAlign(32)},
331 {p0, p0, sXLen, getScalarMemAlign(XLen)}});
332 ExtLoadActions.legalForTypesWithMemDesc(
333 {{sXLen, p0, s8, getScalarMemAlign(8)},
334 {sXLen, p0, s16, getScalarMemAlign(16)}});
335 if (XLen == 64) {
336 LoadActions.legalForTypesWithMemDesc(
337 {{s64, p0, s8, getScalarMemAlign(8)},
338 {s64, p0, s16, getScalarMemAlign(16)},
339 {s64, p0, s32, getScalarMemAlign(32)},
340 {s64, p0, s64, getScalarMemAlign(64)}});
341 StoreActions.legalForTypesWithMemDesc(
342 {{s64, p0, s8, getScalarMemAlign(8)},
343 {s64, p0, s16, getScalarMemAlign(16)},
344 {s64, p0, s32, getScalarMemAlign(32)},
345 {s64, p0, s64, getScalarMemAlign(64)}});
346 ExtLoadActions.legalForTypesWithMemDesc(
347 {{s64, p0, s32, getScalarMemAlign(32)}});
348 } else if (ST.hasStdExtD()) {
349 LoadActions.legalForTypesWithMemDesc(
350 {{s64, p0, s64, getScalarMemAlign(64)}});
351 StoreActions.legalForTypesWithMemDesc(
352 {{s64, p0, s64, getScalarMemAlign(64)}});
353 }
354
355 // Vector loads/stores.
356 if (ST.hasVInstructions()) {
357 LoadActions.legalForTypesWithMemDesc({{nxv2s8, p0, nxv2s8, 8},
358 {nxv4s8, p0, nxv4s8, 8},
359 {nxv8s8, p0, nxv8s8, 8},
360 {nxv16s8, p0, nxv16s8, 8},
361 {nxv32s8, p0, nxv32s8, 8},
362 {nxv64s8, p0, nxv64s8, 8},
363 {nxv2s16, p0, nxv2s16, 16},
364 {nxv4s16, p0, nxv4s16, 16},
365 {nxv8s16, p0, nxv8s16, 16},
366 {nxv16s16, p0, nxv16s16, 16},
367 {nxv32s16, p0, nxv32s16, 16},
368 {nxv2s32, p0, nxv2s32, 32},
369 {nxv4s32, p0, nxv4s32, 32},
370 {nxv8s32, p0, nxv8s32, 32},
371 {nxv16s32, p0, nxv16s32, 32}});
372 StoreActions.legalForTypesWithMemDesc({{nxv2s8, p0, nxv2s8, 8},
373 {nxv4s8, p0, nxv4s8, 8},
374 {nxv8s8, p0, nxv8s8, 8},
375 {nxv16s8, p0, nxv16s8, 8},
376 {nxv32s8, p0, nxv32s8, 8},
377 {nxv64s8, p0, nxv64s8, 8},
378 {nxv2s16, p0, nxv2s16, 16},
379 {nxv4s16, p0, nxv4s16, 16},
380 {nxv8s16, p0, nxv8s16, 16},
381 {nxv16s16, p0, nxv16s16, 16},
382 {nxv32s16, p0, nxv32s16, 16},
383 {nxv2s32, p0, nxv2s32, 32},
384 {nxv4s32, p0, nxv4s32, 32},
385 {nxv8s32, p0, nxv8s32, 32},
386 {nxv16s32, p0, nxv16s32, 32}});
387
388 if (ST.getELen() == 64) {
389 LoadActions.legalForTypesWithMemDesc({{nxv1s8, p0, nxv1s8, 8},
390 {nxv1s16, p0, nxv1s16, 16},
391 {nxv1s32, p0, nxv1s32, 32}});
392 StoreActions.legalForTypesWithMemDesc({{nxv1s8, p0, nxv1s8, 8},
393 {nxv1s16, p0, nxv1s16, 16},
394 {nxv1s32, p0, nxv1s32, 32}});
395 }
396
397 if (ST.hasVInstructionsI64()) {
398 LoadActions.legalForTypesWithMemDesc({{nxv1s64, p0, nxv1s64, 64},
399 {nxv2s64, p0, nxv2s64, 64},
400 {nxv4s64, p0, nxv4s64, 64},
401 {nxv8s64, p0, nxv8s64, 64}});
402 StoreActions.legalForTypesWithMemDesc({{nxv1s64, p0, nxv1s64, 64},
403 {nxv2s64, p0, nxv2s64, 64},
404 {nxv4s64, p0, nxv4s64, 64},
405 {nxv8s64, p0, nxv8s64, 64}});
406 }
407
408 // we will take the custom lowering logic if we have scalable vector types
409 // with non-standard alignments
410 LoadActions.customIf(typeIsLegalIntOrFPVec(0, IntOrFPVecTys, ST));
411 StoreActions.customIf(typeIsLegalIntOrFPVec(0, IntOrFPVecTys, ST));
412
413 // Pointers require that XLen sized elements are legal.
414 if (XLen <= ST.getELen()) {
415 LoadActions.customIf(typeIsLegalPtrVec(0, PtrVecTys, ST));
416 StoreActions.customIf(typeIsLegalPtrVec(0, PtrVecTys, ST));
417 }
418 }
419
420 LoadActions.widenScalarToNextPow2(0, /* MinSize = */ 8)
421 .lowerIfMemSizeNotByteSizePow2()
422 .clampScalar(0, s16, sXLen)
423 .lower();
424 StoreActions
425 .clampScalar(0, s16, sXLen)
426 .lowerIfMemSizeNotByteSizePow2()
427 .lower();
428
429 ExtLoadActions.widenScalarToNextPow2(0).clampScalar(0, sXLen, sXLen).lower();
430
431 getActionDefinitionsBuilder({G_PTR_ADD, G_PTRMASK}).legalFor({{p0, sXLen}});
432
433 getActionDefinitionsBuilder(G_PTRTOINT)
434 .legalFor({{sXLen, p0}})
435 .clampScalar(0, sXLen, sXLen);
436
437 getActionDefinitionsBuilder(G_INTTOPTR)
438 .legalFor({{p0, sXLen}})
439 .clampScalar(1, sXLen, sXLen);
440
441 getActionDefinitionsBuilder(G_BR).alwaysLegal();
442
443 getActionDefinitionsBuilder(G_BRCOND).legalFor({sXLen}).minScalar(0, sXLen);
444
445 getActionDefinitionsBuilder(G_BRJT).customFor({{p0, sXLen}});
446
447 getActionDefinitionsBuilder(G_BRINDIRECT).legalFor({p0});
448
449 getActionDefinitionsBuilder(G_PHI)
450 .legalFor({p0, s32, sXLen})
451 .widenScalarToNextPow2(0)
452 .clampScalar(0, s32, sXLen);
453
454 getActionDefinitionsBuilder({G_GLOBAL_VALUE, G_JUMP_TABLE, G_CONSTANT_POOL})
455 .legalFor({p0});
456
457 if (ST.hasStdExtZmmul()) {
458 getActionDefinitionsBuilder(G_MUL)
459 .legalFor({sXLen})
460 .widenScalarToNextPow2(0)
461 .clampScalar(0, sXLen, sXLen);
462
463 // clang-format off
464 getActionDefinitionsBuilder({G_SMULH, G_UMULH})
465 .legalFor({sXLen})
466 .lower();
467 // clang-format on
468
469 getActionDefinitionsBuilder({G_SMULO, G_UMULO}).minScalar(0, sXLen).lower();
470 } else {
471 getActionDefinitionsBuilder(G_MUL)
472 .libcallFor({sXLen, sDoubleXLen})
473 .widenScalarToNextPow2(0)
474 .clampScalar(0, sXLen, sDoubleXLen);
475
476 getActionDefinitionsBuilder({G_SMULH, G_UMULH}).lowerFor({sXLen});
477
478 getActionDefinitionsBuilder({G_SMULO, G_UMULO})
479 .minScalar(0, sXLen)
480 // Widen sXLen to sDoubleXLen so we can use a single libcall to get
481 // the low bits for the mul result and high bits to do the overflow
482 // check.
483 .widenScalarIf(typeIs(0, sXLen),
484 LegalizeMutations::changeTo(0, sDoubleXLen))
485 .lower();
486 }
487
488 if (ST.hasStdExtM()) {
489 getActionDefinitionsBuilder({G_SDIV, G_UDIV, G_UREM})
490 .legalFor({sXLen})
491 .customFor({s32})
492 .libcallFor({sDoubleXLen})
493 .clampScalar(0, s32, sDoubleXLen)
494 .widenScalarToNextPow2(0);
495 getActionDefinitionsBuilder(G_SREM)
496 .legalFor({sXLen})
497 .libcallFor({sDoubleXLen})
498 .clampScalar(0, sXLen, sDoubleXLen)
499 .widenScalarToNextPow2(0);
500 } else {
501 getActionDefinitionsBuilder({G_UDIV, G_SDIV, G_UREM, G_SREM})
502 .libcallFor({sXLen, sDoubleXLen})
503 .clampScalar(0, sXLen, sDoubleXLen)
504 .widenScalarToNextPow2(0);
505 }
506
507 // TODO: Use libcall for sDoubleXLen.
508 getActionDefinitionsBuilder({G_SDIVREM, G_UDIVREM}).lower();
509
510 getActionDefinitionsBuilder(G_ABS)
511 .customFor(ST.hasStdExtZbb(), {sXLen})
512 .minScalar(ST.hasStdExtZbb(), 0, sXLen)
513 .lower();
514
515 getActionDefinitionsBuilder({G_ABDS, G_ABDU})
516 .minScalar(ST.hasStdExtZbb(), 0, sXLen)
517 .lower();
518
519 getActionDefinitionsBuilder({G_UMAX, G_UMIN, G_SMAX, G_SMIN})
520 .legalFor(ST.hasStdExtZbb(), {sXLen})
521 .minScalar(ST.hasStdExtZbb(), 0, sXLen)
522 .lower();
523
524 getActionDefinitionsBuilder({G_SCMP, G_UCMP}).lower();
525
526 getActionDefinitionsBuilder(G_FRAME_INDEX).legalFor({p0});
527
528 getActionDefinitionsBuilder({G_MEMCPY, G_MEMMOVE, G_MEMSET}).libcall();
529
530 getActionDefinitionsBuilder({G_MEMCPY_INLINE, G_MEMSET_INLINE}).lower();
531
532 getActionDefinitionsBuilder({G_DYN_STACKALLOC, G_STACKSAVE, G_STACKRESTORE})
533 .lower();
534
535 // FP Operations
536
537 // FIXME: Support s128 for rv32 when libcall handling is able to use sret.
538 getActionDefinitionsBuilder({G_FADD, G_FSUB, G_FMUL, G_FDIV, G_FMA, G_FSQRT,
539 G_FMAXNUM, G_FMINNUM, G_FMAXIMUMNUM,
540 G_FMINIMUMNUM})
541 .legalFor(ST.hasStdExtF(), {s32})
542 .legalFor(ST.hasStdExtD(), {s64})
543 .legalFor(ST.hasStdExtZfh(), {s16})
544 .libcallFor({s32, s64})
545 .libcallFor(ST.is64Bit(), {s128});
546
547 getActionDefinitionsBuilder({G_FNEG, G_FABS})
548 .legalFor(ST.hasStdExtF(), {s32})
549 .legalFor(ST.hasStdExtD(), {s64})
550 .legalFor(ST.hasStdExtZfh(), {s16})
551 .lowerFor({s32, s64, s128});
552
553 getActionDefinitionsBuilder(G_FREM)
554 .libcallFor({s32, s64})
555 .libcallFor(ST.is64Bit(), {s128})
556 .minScalar(0, s32)
557 .scalarize(0);
558
559 getActionDefinitionsBuilder(G_FCOPYSIGN)
560 .legalFor(ST.hasStdExtF(), {{s32, s32}})
561 .legalFor(ST.hasStdExtD(), {{s64, s64}, {s32, s64}, {s64, s32}})
562 .legalFor(ST.hasStdExtZfh(), {{s16, s16}, {s16, s32}, {s32, s16}})
563 .legalFor(ST.hasStdExtZfh() && ST.hasStdExtD(), {{s16, s64}, {s64, s16}})
564 .lower();
565
566 // FIXME: Use Zfhmin.
567 getActionDefinitionsBuilder(G_FPTRUNC)
568 .legalFor(ST.hasStdExtD(), {{s32, s64}})
569 .legalFor(ST.hasStdExtZfh(), {{s16, s32}})
570 .legalFor(ST.hasStdExtZfh() && ST.hasStdExtD(), {{s16, s64}})
571 .libcallFor({{s32, s64}})
572 .libcallFor(ST.is64Bit(), {{s32, s128}, {s64, s128}});
573 getActionDefinitionsBuilder(G_FPEXT)
574 .legalFor(ST.hasStdExtD(), {{s64, s32}})
575 .legalFor(ST.hasStdExtZfh(), {{s32, s16}})
576 .legalFor(ST.hasStdExtZfh() && ST.hasStdExtD(), {{s64, s16}})
577 .libcallFor({{s64, s32}})
578 .libcallFor(ST.is64Bit(), {{s128, s32}, {s128, s64}});
579
580 getActionDefinitionsBuilder(G_FCMP)
581 .legalFor(ST.hasStdExtF(), {{sXLen, s32}})
582 .legalFor(ST.hasStdExtD(), {{sXLen, s64}})
583 .legalFor(ST.hasStdExtZfh(), {{sXLen, s16}})
584 .clampScalar(0, sXLen, sXLen)
585 .libcallFor({{sXLen, s32}, {sXLen, s64}})
586 .libcallFor(ST.is64Bit(), {{sXLen, s128}});
587
588 // TODO: Support vector version of G_IS_FPCLASS.
589 getActionDefinitionsBuilder(G_IS_FPCLASS)
590 .customFor(ST.hasStdExtF(), {{s1, s32}})
591 .customFor(ST.hasStdExtD(), {{s1, s64}})
592 .customFor(ST.hasStdExtZfh(), {{s1, s16}})
593 .lower();
594
595 getActionDefinitionsBuilder(G_FCONSTANT)
596 .legalFor(ST.hasStdExtF(), {s32})
597 .legalFor(ST.hasStdExtD(), {s64})
598 .legalFor(ST.hasStdExtZfh(), {s16})
599 .customFor(!ST.is64Bit(), {s32})
600 .customFor(ST.is64Bit(), {s32, s64})
601 .lowerFor({s64, s128});
602
603 getActionDefinitionsBuilder({G_FPTOSI, G_FPTOUI})
604 .legalFor(ST.hasStdExtF(), {{sXLen, s32}})
605 .legalFor(ST.hasStdExtD(), {{sXLen, s64}})
606 .legalFor(ST.hasStdExtZfh(), {{sXLen, s16}})
607 .customFor(ST.is64Bit() && ST.hasStdExtF(), {{s32, s32}})
608 .customFor(ST.is64Bit() && ST.hasStdExtD(), {{s32, s64}})
609 .customFor(ST.is64Bit() && ST.hasStdExtZfh(), {{s32, s16}})
610 .widenScalarToNextPow2(0)
611 .minScalar(0, s32)
612 .libcallFor({{s32, s32}, {s64, s32}, {s32, s64}, {s64, s64}})
613 .libcallFor(ST.is64Bit(), {{s32, s128}, {s64, s128}}) // FIXME RV32.
614 .libcallFor(ST.is64Bit(), {{s128, s32}, {s128, s64}, {s128, s128}});
615
616 getActionDefinitionsBuilder({G_SITOFP, G_UITOFP})
617 .legalFor(ST.hasStdExtF(), {{s32, sXLen}})
618 .legalFor(ST.hasStdExtD(), {{s64, sXLen}})
619 .legalFor(ST.hasStdExtZfh(), {{s16, sXLen}})
620 .widenScalarToNextPow2(1)
621 // Promote to XLen if the operation is legal.
622 .widenScalarIf(
623 [=, &ST](const LegalityQuery &Query) {
624 return Query.Types[0].isScalar() && Query.Types[1].isScalar() &&
625 (Query.Types[1].getSizeInBits() < ST.getXLen()) &&
626 ((ST.hasStdExtF() && Query.Types[0].getSizeInBits() == 32) ||
627 (ST.hasStdExtD() && Query.Types[0].getSizeInBits() == 64) ||
628 (ST.hasStdExtZfh() &&
629 Query.Types[0].getSizeInBits() == 16));
630 },
632 // Otherwise only promote to s32 since we have si libcalls.
633 .minScalar(1, s32)
634 .libcallFor({{s32, s32}, {s64, s32}, {s32, s64}, {s64, s64}})
635 .libcallFor(ST.is64Bit(), {{s128, s32}, {s128, s64}}) // FIXME RV32.
636 .libcallFor(ST.is64Bit(), {{s32, s128}, {s64, s128}, {s128, s128}});
637
638 // FIXME: We can do custom inline expansion like SelectionDAG.
639 getActionDefinitionsBuilder({G_FCEIL, G_FFLOOR, G_FRINT, G_FNEARBYINT,
640 G_INTRINSIC_TRUNC, G_INTRINSIC_ROUND,
641 G_INTRINSIC_ROUNDEVEN})
642 .legalFor(ST.hasStdExtZfa(), {s32})
643 .legalFor(ST.hasStdExtZfa() && ST.hasStdExtD(), {s64})
644 .legalFor(ST.hasStdExtZfa() && ST.hasStdExtZfh(), {s16})
645 .libcallFor({s32, s64})
646 .libcallFor(ST.is64Bit(), {s128});
647
648 getActionDefinitionsBuilder({G_FMAXIMUM, G_FMINIMUM})
649 .legalFor(ST.hasStdExtZfa(), {s32})
650 .legalFor(ST.hasStdExtZfa() && ST.hasStdExtD(), {s64})
651 .legalFor(ST.hasStdExtZfa() && ST.hasStdExtZfh(), {s16});
652
653 getActionDefinitionsBuilder({G_FCOS, G_FSIN, G_FTAN, G_FPOW, G_FLOG, G_FLOG2,
654 G_FLOG10, G_FEXP, G_FEXP2, G_FEXP10, G_FACOS,
655 G_FASIN, G_FATAN, G_FATAN2, G_FCOSH, G_FSINH,
656 G_FTANH, G_FMODF})
657 .libcallFor({s32, s64})
658 .libcallFor(ST.is64Bit(), {s128});
659 getActionDefinitionsBuilder({G_FPOWI, G_FLDEXP})
660 .libcallFor({{s32, s32}, {s64, s32}})
661 .libcallFor(ST.is64Bit(), {s128, s32});
662
663 getActionDefinitionsBuilder(G_FCANONICALIZE)
664 .legalFor(ST.hasStdExtF(), {s32})
665 .legalFor(ST.hasStdExtD(), {s64})
666 .legalFor(ST.hasStdExtZfh(), {s16});
667
668 getActionDefinitionsBuilder(G_VASTART).customFor({p0});
669
670 // va_list must be a pointer, but most sized types are pretty easy to handle
671 // as the destination.
672 getActionDefinitionsBuilder(G_VAARG)
673 // TODO: Implement narrowScalar and widenScalar for G_VAARG for types
674 // other than sXLen.
675 .clampScalar(0, sXLen, sXLen)
676 .lowerForCartesianProduct({sXLen, p0}, {p0});
677
678 getActionDefinitionsBuilder(G_VSCALE)
679 .clampScalar(0, sXLen, sXLen)
680 .customFor({sXLen});
681
682 auto &SplatActions =
683 getActionDefinitionsBuilder(G_SPLAT_VECTOR)
684 .legalIf(all(typeIsLegalIntOrFPVec(0, IntOrFPVecTys, ST),
685 typeIs(1, sXLen)))
686 .customIf(all(typeIsLegalBoolVec(0, BoolVecTys, ST), typeIs(1, s1)));
687 // Handle case of s64 element vectors on RV32. If the subtarget does not have
688 // f64, then try to lower it to G_SPLAT_VECTOR_SPLIT_64_VL. If the subtarget
689 // does have f64, then we don't know whether the type is an f64 or an i64,
690 // so mark the G_SPLAT_VECTOR as legal and decide later what to do with it,
691 // depending on how the instructions it consumes are legalized. They are not
692 // legalized yet since legalization is in reverse postorder, so we cannot
693 // make the decision at this moment.
694 if (XLen == 32) {
695 if (ST.hasVInstructionsF64() && ST.hasStdExtD())
696 SplatActions.legalIf(all(
697 typeInSet(0, {nxv1s64, nxv2s64, nxv4s64, nxv8s64}), typeIs(1, s64)));
698 else if (ST.hasVInstructionsI64())
699 SplatActions.customIf(all(
700 typeInSet(0, {nxv1s64, nxv2s64, nxv4s64, nxv8s64}), typeIs(1, s64)));
701 }
702
703 SplatActions.clampScalar(1, sXLen, sXLen);
704
705 LegalityPredicate ExtractSubvecBitcastPred = [=](const LegalityQuery &Query) {
706 LLT DstTy = Query.Types[0];
707 LLT SrcTy = Query.Types[1];
708 return DstTy.getElementType() == LLT::scalar(1) &&
709 DstTy.getElementCount().getKnownMinValue() >= 8 &&
710 SrcTy.getElementCount().getKnownMinValue() >= 8;
711 };
712 getActionDefinitionsBuilder(G_EXTRACT_SUBVECTOR)
713 // We don't have the ability to slide mask vectors down indexed by their
714 // i1 elements; the smallest we can do is i8. Often we are able to bitcast
715 // to equivalent i8 vectors.
716 .bitcastIf(
717 all(typeIsLegalBoolVec(0, BoolVecTys, ST),
718 typeIsLegalBoolVec(1, BoolVecTys, ST), ExtractSubvecBitcastPred),
719 [=](const LegalityQuery &Query) {
720 LLT CastTy = LLT::vector(
721 Query.Types[0].getElementCount().divideCoefficientBy(8), 8);
722 return std::pair(0, CastTy);
723 })
724 .customIf(LegalityPredicates::any(
725 all(typeIsLegalBoolVec(0, BoolVecTys, ST),
726 typeIsLegalBoolVec(1, BoolVecTys, ST)),
727 all(typeIsLegalIntOrFPVec(0, IntOrFPVecTys, ST),
728 typeIsLegalIntOrFPVec(1, IntOrFPVecTys, ST))));
729
730 getActionDefinitionsBuilder(G_INSERT_SUBVECTOR)
731 .customIf(all(typeIsLegalBoolVec(0, BoolVecTys, ST),
732 typeIsLegalBoolVec(1, BoolVecTys, ST)))
733 .customIf(all(typeIsLegalIntOrFPVec(0, IntOrFPVecTys, ST),
734 typeIsLegalIntOrFPVec(1, IntOrFPVecTys, ST)));
735
736 getActionDefinitionsBuilder(G_ATOMIC_CMPXCHG_WITH_SUCCESS)
737 .lowerIf(all(typeInSet(0, {s8, s16, s32, s64}), typeIs(2, p0)));
738
739 getActionDefinitionsBuilder({G_ATOMIC_CMPXCHG, G_ATOMICRMW_ADD,
740 G_ATOMICRMW_AND, G_ATOMICRMW_OR,
741 G_ATOMICRMW_XOR})
742 .legalFor(ST.hasStdExtA(), {{sXLen, p0}})
743 .libcallFor(!ST.hasStdExtA(), {{s8, p0}, {s16, p0}, {s32, p0}, {s64, p0}})
744 .clampScalar(0, sXLen, sXLen);
745
746 getActionDefinitionsBuilder(G_ATOMICRMW_SUB)
747 .libcallFor(!ST.hasStdExtA(), {{s8, p0}, {s16, p0}, {s32, p0}, {s64, p0}})
748 .clampScalar(0, sXLen, sXLen)
749 .lower();
750
751 LegalityPredicate InsertVectorEltPred = [=](const LegalityQuery &Query) {
752 LLT VecTy = Query.Types[0];
753 LLT EltTy = Query.Types[1];
754 return VecTy.getElementType() == EltTy;
755 };
756
757 getActionDefinitionsBuilder(G_INSERT_VECTOR_ELT)
758 .legalIf(all(typeIsLegalIntOrFPVec(0, IntOrFPVecTys, ST),
759 InsertVectorEltPred, typeIs(2, sXLen)))
760 .legalIf(all(typeIsLegalBoolVec(0, BoolVecTys, ST), InsertVectorEltPred,
761 typeIs(2, sXLen)));
762
763 getActionDefinitionsBuilder({G_INTRINSIC, G_INTRINSIC_W_SIDE_EFFECTS})
764 .alwaysLegal();
765
766 getActionDefinitionsBuilder(G_FENCE).alwaysLegal();
767
768 getActionDefinitionsBuilder({G_TRAP, G_DEBUGTRAP, G_UBSANTRAP}).alwaysLegal();
769
770 verify(*ST.getInstrInfo());
771}
772
774 MachineInstr &MI) const {
775 Intrinsic::ID IntrinsicID = cast<GIntrinsic>(MI).getIntrinsicID();
776
778 RISCVVIntrinsicsTable::getRISCVVIntrinsicInfo(IntrinsicID)) {
779 if (II->hasScalarOperand() && !II->IsFPIntrinsic) {
780 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
781 MachineRegisterInfo &MRI = *MIRBuilder.getMRI();
782
783 auto OldScalar = MI.getOperand(II->ScalarOperand + 2).getReg();
784 // Legalize integer vx form intrinsic.
785 if (MRI.getType(OldScalar).isScalar()) {
786 if (MRI.getType(OldScalar).getSizeInBits() < sXLen.getSizeInBits()) {
787 Helper.Observer.changingInstr(MI);
788 Helper.widenScalarSrc(MI, sXLen, II->ScalarOperand + 2,
789 TargetOpcode::G_ANYEXT);
790 Helper.Observer.changedInstr(MI);
791 } else if (MRI.getType(OldScalar).getSizeInBits() >
792 sXLen.getSizeInBits()) {
793 // TODO: i64 in riscv32.
794 return false;
795 }
796 }
797 }
798 return true;
799 }
800
801 switch (IntrinsicID) {
802 default:
803 return false;
804 case Intrinsic::vacopy: {
805 // vacopy arguments must be legal because of the intrinsic signature.
806 // No need to check here.
807
808 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
809 MachineRegisterInfo &MRI = *MIRBuilder.getMRI();
810 MachineFunction &MF = *MI.getMF();
811 const DataLayout &DL = MIRBuilder.getDataLayout();
812 LLVMContext &Ctx = MF.getFunction().getContext();
813
814 Register DstLst = MI.getOperand(1).getReg();
815 LLT PtrTy = MRI.getType(DstLst);
816
817 // Load the source va_list
818 Align Alignment = DL.getABITypeAlign(getTypeForLLT(PtrTy, Ctx));
820 MachinePointerInfo(), MachineMemOperand::MOLoad, PtrTy, Alignment);
821 auto Tmp = MIRBuilder.buildLoad(PtrTy, MI.getOperand(2), *LoadMMO);
822
823 // Store the result in the destination va_list
826 MIRBuilder.buildStore(Tmp, DstLst, *StoreMMO);
827
828 MI.eraseFromParent();
829 return true;
830 }
831 case Intrinsic::riscv_vsetvli:
832 case Intrinsic::riscv_vsetvlimax:
833 case Intrinsic::riscv_masked_atomicrmw_add:
834 case Intrinsic::riscv_masked_atomicrmw_sub:
835 case Intrinsic::riscv_masked_cmpxchg:
836 return true;
837 }
838}
839
840bool RISCVLegalizerInfo::legalizeVAStart(MachineInstr &MI,
841 MachineIRBuilder &MIRBuilder) const {
842 // Stores the address of the VarArgsFrameIndex slot into the memory location
843 assert(MI.getOpcode() == TargetOpcode::G_VASTART);
844 MachineFunction *MF = MI.getParent()->getParent();
846 int FI = FuncInfo->getVarArgsFrameIndex();
847 LLT AddrTy = MIRBuilder.getMRI()->getType(MI.getOperand(0).getReg());
848 auto FINAddr = MIRBuilder.buildFrameIndex(AddrTy, FI);
849 assert(MI.hasOneMemOperand());
850 MIRBuilder.buildStore(FINAddr, MI.getOperand(0).getReg(),
851 *MI.memoperands()[0]);
852 MI.eraseFromParent();
853 return true;
854}
855
856bool RISCVLegalizerInfo::legalizeBRJT(MachineInstr &MI,
857 MachineIRBuilder &MIRBuilder) const {
858 MachineRegisterInfo &MRI = *MIRBuilder.getMRI();
859 auto &MF = *MI.getParent()->getParent();
860 const MachineJumpTableInfo *MJTI = MF.getJumpTableInfo();
861 unsigned EntrySize = MJTI->getEntrySize(MF.getDataLayout());
862
863 Register PtrReg = MI.getOperand(0).getReg();
864 LLT PtrTy = MRI.getType(PtrReg);
865 Register IndexReg = MI.getOperand(2).getReg();
866 LLT IndexTy = MRI.getType(IndexReg);
867
868 if (!isPowerOf2_32(EntrySize))
869 return false;
870
871 auto ShiftAmt = MIRBuilder.buildConstant(IndexTy, Log2_32(EntrySize));
872 IndexReg = MIRBuilder.buildShl(IndexTy, IndexReg, ShiftAmt).getReg(0);
873
874 auto Addr = MIRBuilder.buildPtrAdd(PtrTy, PtrReg, IndexReg);
875
878 EntrySize, Align(MJTI->getEntryAlignment(MF.getDataLayout())));
879
880 Register TargetReg;
881 switch (MJTI->getEntryKind()) {
882 default:
883 return false;
885 // For PIC, the sequence is:
886 // BRIND(load(Jumptable + index) + RelocBase)
887 // RelocBase can be JumpTable, GOT or some sort of global base.
888 unsigned LoadOpc =
889 STI.is64Bit() ? TargetOpcode::G_SEXTLOAD : TargetOpcode::G_LOAD;
890 auto Load = MIRBuilder.buildLoadInstr(LoadOpc, IndexTy, Addr, *MMO);
891 TargetReg = MIRBuilder.buildPtrAdd(PtrTy, PtrReg, Load).getReg(0);
892 break;
893 }
895 auto Load = MIRBuilder.buildLoadInstr(TargetOpcode::G_SEXTLOAD, IndexTy,
896 Addr, *MMO);
897 TargetReg = MIRBuilder.buildIntToPtr(PtrTy, Load).getReg(0);
898 break;
899 }
901 TargetReg = MIRBuilder.buildLoad(PtrTy, Addr, *MMO).getReg(0);
902 break;
903 }
904
905 MIRBuilder.buildBrIndirect(TargetReg);
906
907 MI.eraseFromParent();
908 return true;
909}
910
911bool RISCVLegalizerInfo::shouldBeInConstantPool(const APInt &APImm,
912 bool ShouldOptForSize) const {
913 assert(APImm.getBitWidth() == 32 || APImm.getBitWidth() == 64);
914 int64_t Imm = APImm.getSExtValue();
915 // All simm32 constants should be handled by isel.
916 // NOTE: The getMaxBuildIntsCost call below should return a value >= 2 making
917 // this check redundant, but small immediates are common so this check
918 // should have better compile time.
919 if (isInt<32>(Imm))
920 return false;
921
922 // We only need to cost the immediate, if constant pool lowering is enabled.
923 if (!STI.useConstantPoolForLargeInts())
924 return false;
925
927 if (Seq.size() <= STI.getMaxBuildIntsCost())
928 return false;
929
930 // Optimizations below are disabled for opt size. If we're optimizing for
931 // size, use a constant pool.
932 if (ShouldOptForSize)
933 return true;
934 //
935 // Special case. See if we can build the constant as (ADD (SLLI X, C), X) do
936 // that if it will avoid a constant pool.
937 // It will require an extra temporary register though.
938 // If we have Zba we can use (ADD_UW X, (SLLI X, 32)) to handle cases where
939 // low and high 32 bits are the same and bit 31 and 63 are set.
940 unsigned ShiftAmt, AddOpc;
942 RISCVMatInt::generateTwoRegInstSeq(Imm, STI, ShiftAmt, AddOpc);
943 return !(!SeqLo.empty() && (SeqLo.size() + 2) <= STI.getMaxBuildIntsCost());
944}
945
946bool RISCVLegalizerInfo::legalizeVScale(MachineInstr &MI,
947 MachineIRBuilder &MIB) const {
948 Register Dst = MI.getOperand(0).getReg();
949
950 // We define our scalable vector types for lmul=1 to use a 64 bit known
951 // minimum size. e.g. <vscale x 2 x i32>. VLENB is in bytes so we calculate
952 // vscale as VLENB / 8.
953 static_assert(RISCV::RVVBitsPerBlock == 64, "Unexpected bits per block!");
954 if (STI.getRealMinVLen() < RISCV::RVVBitsPerBlock)
955 // Support for VLEN==32 is incomplete.
956 return false;
957
958 // We assume VLENB is a multiple of 8. We manually choose the best shift
959 // here because SimplifyDemandedBits isn't always able to simplify it.
960 uint64_t Val = MI.getOperand(1).getCImm()->getZExtValue();
961 if (isPowerOf2_64(Val)) {
962 uint64_t Log2 = Log2_64(Val);
963 if (Log2 < 3) {
964 auto VLENB = MIB.buildInstr(RISCV::G_READ_VLENB, {sXLen}, {});
965 MIB.buildLShr(Dst, VLENB, MIB.buildConstant(sXLen, 3 - Log2),
967 } else if (Log2 > 3) {
968 auto VLENB = MIB.buildInstr(RISCV::G_READ_VLENB, {sXLen}, {});
969 MIB.buildShl(Dst, VLENB, MIB.buildConstant(sXLen, Log2 - 3));
970 } else {
971 MIB.buildInstr(RISCV::G_READ_VLENB, {Dst}, {});
972 }
973 } else if ((Val % 8) == 0) {
974 // If the multiplier is a multiple of 8, scale it down to avoid needing
975 // to shift the VLENB value.
976 auto VLENB = MIB.buildInstr(RISCV::G_READ_VLENB, {sXLen}, {});
977 MIB.buildMul(Dst, VLENB, MIB.buildConstant(sXLen, Val / 8));
978 } else {
979 auto VLENB = MIB.buildInstr(RISCV::G_READ_VLENB, {sXLen}, {});
980 auto VScale = MIB.buildLShr(sXLen, VLENB, MIB.buildConstant(sXLen, 3),
982 MIB.buildMul(Dst, VScale, MIB.buildConstant(sXLen, Val));
983 }
984 MI.eraseFromParent();
985 return true;
986}
987
988// Custom-lower extensions from mask vectors by using a vselect either with 1
989// for zero/any-extension or -1 for sign-extension:
990// (vXiN = (s|z)ext vXi1:vmask) -> (vXiN = vselect vmask, (-1 or 1), 0)
991// Note that any-extension is lowered identically to zero-extension.
992bool RISCVLegalizerInfo::legalizeExt(MachineInstr &MI,
993 MachineIRBuilder &MIB) const {
994
995 unsigned Opc = MI.getOpcode();
996 assert(Opc == TargetOpcode::G_ZEXT || Opc == TargetOpcode::G_SEXT ||
997 Opc == TargetOpcode::G_ANYEXT);
998
999 MachineRegisterInfo &MRI = *MIB.getMRI();
1000 Register Dst = MI.getOperand(0).getReg();
1001 Register Src = MI.getOperand(1).getReg();
1002
1003 LLT DstTy = MRI.getType(Dst);
1004 int64_t ExtTrueVal = Opc == TargetOpcode::G_SEXT ? -1 : 1;
1005 LLT DstEltTy = DstTy.getElementType();
1006 auto SplatZero = MIB.buildSplatVector(DstTy, MIB.buildConstant(DstEltTy, 0));
1007 auto SplatTrue =
1008 MIB.buildSplatVector(DstTy, MIB.buildConstant(DstEltTy, ExtTrueVal));
1009 MIB.buildSelect(Dst, Src, SplatTrue, SplatZero);
1010
1011 MI.eraseFromParent();
1012 return true;
1013}
1014
1015bool RISCVLegalizerInfo::legalizeLoadStore(MachineInstr &MI,
1016 LegalizerHelper &Helper,
1017 MachineIRBuilder &MIB) const {
1019 "Machine instructions must be Load/Store.");
1020 MachineRegisterInfo &MRI = *MIB.getMRI();
1021 MachineFunction *MF = MI.getMF();
1022 const DataLayout &DL = MIB.getDataLayout();
1023 LLVMContext &Ctx = MF->getFunction().getContext();
1024
1025 Register DstReg = MI.getOperand(0).getReg();
1026 LLT DataTy = MRI.getType(DstReg);
1027 if (!DataTy.isVector())
1028 return false;
1029
1030 if (!MI.hasOneMemOperand())
1031 return false;
1032
1033 MachineMemOperand *MMO = *MI.memoperands_begin();
1034
1035 const auto *TLI = STI.getTargetLowering();
1036 EVT VT = EVT::getEVT(getTypeForLLT(DataTy, Ctx));
1037
1038 if (TLI->allowsMemoryAccessForAlignment(Ctx, DL, VT, *MMO))
1039 return true;
1040
1041 unsigned EltSizeBits = DataTy.getScalarSizeInBits();
1042 assert((EltSizeBits == 16 || EltSizeBits == 32 || EltSizeBits == 64) &&
1043 "Unexpected unaligned RVV load type");
1044
1045 // Calculate the new vector type with i8 elements
1046 unsigned NumElements =
1047 DataTy.getElementCount().getKnownMinValue() * (EltSizeBits / 8);
1048 LLT NewDataTy = LLT::scalable_vector(NumElements, 8);
1049
1050 Helper.bitcast(MI, 0, NewDataTy);
1051
1052 return true;
1053}
1054
1055/// Return the type of the mask type suitable for masking the provided
1056/// vector type. This is simply an i1 element type vector of the same
1057/// (possibly scalable) length.
1058static LLT getMaskTypeFor(LLT VecTy) {
1059 assert(VecTy.isVector());
1060 ElementCount EC = VecTy.getElementCount();
1061 return LLT::vector(EC, LLT::scalar(1));
1062}
1063
1064/// Creates an all ones mask suitable for masking a vector of type VecTy with
1065/// vector length VL.
1067 MachineIRBuilder &MIB,
1068 MachineRegisterInfo &MRI) {
1069 LLT MaskTy = getMaskTypeFor(VecTy);
1070 return MIB.buildInstr(RISCV::G_VMSET_VL, {MaskTy}, {VL});
1071}
1072
1073/// Gets the two common "VL" operands: an all-ones mask and the vector length.
1074/// VecTy is a scalable vector type.
1075static std::pair<MachineInstrBuilder, MachineInstrBuilder>
1077 assert(VecTy.isScalableVector() && "Expecting scalable container type");
1078 const RISCVSubtarget &STI = MIB.getMF().getSubtarget<RISCVSubtarget>();
1079 LLT XLenTy(STI.getXLenVT());
1080 auto VL = MIB.buildConstant(XLenTy, -1);
1081 auto Mask = buildAllOnesMask(VecTy, VL, MIB, MRI);
1082 return {Mask, VL};
1083}
1084
1086buildSplatPartsS64WithVL(const DstOp &Dst, const SrcOp &Passthru, Register Lo,
1087 Register Hi, const SrcOp &VL, MachineIRBuilder &MIB,
1088 MachineRegisterInfo &MRI) {
1089 // TODO: If the Hi bits of the splat are undefined, then it's fine to just
1090 // splat Lo even if it might be sign extended. I don't think we have
1091 // introduced a case where we're build a s64 where the upper bits are undef
1092 // yet.
1093
1094 // Fall back to a stack store and stride x0 vector load.
1095 // TODO: need to lower G_SPLAT_VECTOR_SPLIT_I64. This is done in
1096 // preprocessDAG in SDAG.
1097 return MIB.buildInstr(RISCV::G_SPLAT_VECTOR_SPLIT_I64_VL, {Dst},
1098 {Passthru, Lo, Hi, VL});
1099}
1100
1102buildSplatSplitS64WithVL(const DstOp &Dst, const SrcOp &Passthru,
1103 const SrcOp &Scalar, const SrcOp &VL,
1105 assert(Scalar.getLLTTy(MRI) == LLT::scalar(64) && "Unexpected VecTy!");
1106 auto Unmerge = MIB.buildUnmerge(LLT::scalar(32), Scalar);
1107 return buildSplatPartsS64WithVL(Dst, Passthru, Unmerge.getReg(0),
1108 Unmerge.getReg(1), VL, MIB, MRI);
1109}
1110
1111// Lower splats of s1 types to G_ICMP. For each mask vector type, we have a
1112// legal equivalently-sized i8 type, so we can use that as a go-between.
1113// Splats of s1 types that have constant value can be legalized as VMSET_VL or
1114// VMCLR_VL.
1115bool RISCVLegalizerInfo::legalizeSplatVector(MachineInstr &MI,
1116 MachineIRBuilder &MIB) const {
1117 assert(MI.getOpcode() == TargetOpcode::G_SPLAT_VECTOR);
1118
1119 MachineRegisterInfo &MRI = *MIB.getMRI();
1120
1121 Register Dst = MI.getOperand(0).getReg();
1122 Register SplatVal = MI.getOperand(1).getReg();
1123
1124 LLT VecTy = MRI.getType(Dst);
1125 LLT XLenTy(STI.getXLenVT());
1126
1127 // Handle case of s64 element vectors on rv32
1128 if (XLenTy.getSizeInBits() == 32 &&
1129 VecTy.getElementType().getSizeInBits() == 64) {
1130 auto [_, VL] = buildDefaultVLOps(MRI.getType(Dst), MIB, MRI);
1131 buildSplatSplitS64WithVL(Dst, MIB.buildUndef(VecTy), SplatVal, VL, MIB,
1132 MRI);
1133 MI.eraseFromParent();
1134 return true;
1135 }
1136
1137 // All-zeros or all-ones splats are handled specially.
1138 MachineInstr &SplatValMI = *MRI.getVRegDef(SplatVal);
1139 if (isAllOnesOrAllOnesSplat(SplatValMI, MRI)) {
1140 auto VL = buildDefaultVLOps(VecTy, MIB, MRI).second;
1141 MIB.buildInstr(RISCV::G_VMSET_VL, {Dst}, {VL});
1142 MI.eraseFromParent();
1143 return true;
1144 }
1145 if (isNullOrNullSplat(SplatValMI, MRI)) {
1146 auto VL = buildDefaultVLOps(VecTy, MIB, MRI).second;
1147 MIB.buildInstr(RISCV::G_VMCLR_VL, {Dst}, {VL});
1148 MI.eraseFromParent();
1149 return true;
1150 }
1151
1152 // Handle non-constant mask splat (i.e. not sure if it's all zeros or all
1153 // ones) by promoting it to an s8 splat.
1154 LLT InterEltTy = LLT::scalar(8);
1155 LLT InterTy = VecTy.changeElementType(InterEltTy);
1156 auto ZExtSplatVal = MIB.buildZExt(InterEltTy, SplatVal);
1157 auto And =
1158 MIB.buildAnd(InterEltTy, ZExtSplatVal, MIB.buildConstant(InterEltTy, 1));
1159 auto LHS = MIB.buildSplatVector(InterTy, And);
1160 auto ZeroSplat =
1161 MIB.buildSplatVector(InterTy, MIB.buildConstant(InterEltTy, 0));
1162 MIB.buildICmp(CmpInst::Predicate::ICMP_NE, Dst, LHS, ZeroSplat);
1163 MI.eraseFromParent();
1164 return true;
1165}
1166
1167static LLT getLMUL1Ty(LLT VecTy) {
1168 assert(VecTy.getElementType().getSizeInBits() <= 64 &&
1169 "Unexpected vector LLT");
1171 VecTy.getElementType().getSizeInBits(),
1172 VecTy.getElementType());
1173}
1174
1175bool RISCVLegalizerInfo::legalizeExtractSubvector(MachineInstr &MI,
1176 MachineIRBuilder &MIB) const {
1177 GExtractSubvector &ES = cast<GExtractSubvector>(MI);
1178
1179 MachineRegisterInfo &MRI = *MIB.getMRI();
1180
1181 Register Dst = ES.getReg(0);
1182 Register Src = ES.getSrcVec();
1183 uint64_t Idx = ES.getIndexImm();
1184
1185 // With an index of 0 this is a cast-like subvector, which can be performed
1186 // with subregister operations.
1187 if (Idx == 0)
1188 return true;
1189
1190 LLT LitTy = MRI.getType(Dst);
1191 LLT BigTy = MRI.getType(Src);
1192
1193 if (LitTy.getElementType() == LLT::scalar(1)) {
1194 // We can't slide this mask vector up indexed by its i1 elements.
1195 // This poses a problem when we wish to insert a scalable vector which
1196 // can't be re-expressed as a larger type. Just choose the slow path and
1197 // extend to a larger type, then truncate back down.
1198 LLT ExtBigTy = BigTy.changeElementType(LLT::scalar(8));
1199 LLT ExtLitTy = LitTy.changeElementType(LLT::scalar(8));
1200 auto BigZExt = MIB.buildZExt(ExtBigTy, Src);
1201 auto ExtractZExt = MIB.buildExtractSubvector(ExtLitTy, BigZExt, Idx);
1202 auto SplatZero = MIB.buildSplatVector(
1203 ExtLitTy, MIB.buildConstant(ExtLitTy.getElementType(), 0));
1204 MIB.buildICmp(CmpInst::Predicate::ICMP_NE, Dst, ExtractZExt, SplatZero);
1205 MI.eraseFromParent();
1206 return true;
1207 }
1208
1209 // extract_subvector scales the index by vscale if the subvector is scalable,
1210 // and decomposeSubvectorInsertExtractToSubRegs takes this into account.
1211 const RISCVRegisterInfo *TRI = STI.getRegisterInfo();
1212 MVT LitTyMVT = getMVTForLLT(LitTy);
1213 auto Decompose =
1215 getMVTForLLT(BigTy), LitTyMVT, Idx, TRI);
1216 unsigned RemIdx = Decompose.second;
1217
1218 // If the Idx has been completely eliminated then this is a subvector extract
1219 // which naturally aligns to a vector register. These can easily be handled
1220 // using subregister manipulation.
1221 if (RemIdx == 0)
1222 return true;
1223
1224 // Else LitTy is M1 or smaller and may need to be slid down: if LitTy
1225 // was > M1 then the index would need to be a multiple of VLMAX, and so would
1226 // divide exactly.
1227 assert(
1230
1231 // If the vector type is an LMUL-group type, extract a subvector equal to the
1232 // nearest full vector register type.
1233 LLT InterLitTy = BigTy;
1234 Register Vec = Src;
1236 getLMUL1Ty(BigTy).getSizeInBits())) {
1237 // If BigTy has an LMUL > 1, then LitTy should have a smaller LMUL, and
1238 // we should have successfully decomposed the extract into a subregister.
1239 assert(Decompose.first != RISCV::NoSubRegister);
1240 InterLitTy = getLMUL1Ty(BigTy);
1241 // SDAG builds a TargetExtractSubreg. We cannot create a a Copy with SubReg
1242 // specified on the source Register (the equivalent) since generic virtual
1243 // register does not allow subregister index.
1244 Vec = MIB.buildExtractSubvector(InterLitTy, Src, Idx - RemIdx).getReg(0);
1245 }
1246
1247 // Slide this vector register down by the desired number of elements in order
1248 // to place the desired subvector starting at element 0.
1249 const LLT XLenTy(STI.getXLenVT());
1250 auto SlidedownAmt = MIB.buildVScale(XLenTy, RemIdx);
1251 auto [Mask, VL] = buildDefaultVLOps(InterLitTy, MIB, MRI);
1253 auto Slidedown = MIB.buildInstr(
1254 RISCV::G_VSLIDEDOWN_VL, {InterLitTy},
1255 {MIB.buildUndef(InterLitTy), Vec, SlidedownAmt, Mask, VL, Policy});
1256
1257 // Now the vector is in the right position, extract our final subvector. This
1258 // should resolve to a COPY.
1259 MIB.buildExtractSubvector(Dst, Slidedown, 0);
1260
1261 MI.eraseFromParent();
1262 return true;
1263}
1264
1265bool RISCVLegalizerInfo::legalizeInsertSubvector(MachineInstr &MI,
1266 LegalizerHelper &Helper,
1267 MachineIRBuilder &MIB) const {
1268 GInsertSubvector &IS = cast<GInsertSubvector>(MI);
1269
1270 MachineRegisterInfo &MRI = *MIB.getMRI();
1271
1272 Register Dst = IS.getReg(0);
1273 Register BigVec = IS.getBigVec();
1274 Register LitVec = IS.getSubVec();
1275 uint64_t Idx = IS.getIndexImm();
1276
1277 LLT BigTy = MRI.getType(BigVec);
1278 LLT LitTy = MRI.getType(LitVec);
1279
1280 if (Idx == 0 &&
1281 MRI.getVRegDef(BigVec)->getOpcode() == TargetOpcode::G_IMPLICIT_DEF)
1282 return true;
1283
1284 // We don't have the ability to slide mask vectors up indexed by their i1
1285 // elements; the smallest we can do is i8. Often we are able to bitcast to
1286 // equivalent i8 vectors. Otherwise, we can must zeroextend to equivalent i8
1287 // vectors and truncate down after the insert.
1288 if (LitTy.getElementType() == LLT::scalar(1)) {
1289 auto BigTyMinElts = BigTy.getElementCount().getKnownMinValue();
1290 auto LitTyMinElts = LitTy.getElementCount().getKnownMinValue();
1291 if (BigTyMinElts >= 8 && LitTyMinElts >= 8)
1292 return Helper.bitcast(
1293 IS, 0,
1295
1296 // We can't slide this mask vector up indexed by its i1 elements.
1297 // This poses a problem when we wish to insert a scalable vector which
1298 // can't be re-expressed as a larger type. Just choose the slow path and
1299 // extend to a larger type, then truncate back down.
1300 LLT ExtBigTy = BigTy.changeElementType(LLT::scalar(8));
1301 return Helper.widenScalar(IS, 0, ExtBigTy);
1302 }
1303
1304 const RISCVRegisterInfo *TRI = STI.getRegisterInfo();
1305 unsigned SubRegIdx, RemIdx;
1306 std::tie(SubRegIdx, RemIdx) =
1308 getMVTForLLT(BigTy), getMVTForLLT(LitTy), Idx, TRI);
1309
1310 TypeSize VecRegSize = TypeSize::getScalable(RISCV::RVVBitsPerBlock);
1312 STI.expandVScale(LitTy.getSizeInBits()).getKnownMinValue()));
1313 bool ExactlyVecRegSized =
1314 STI.expandVScale(LitTy.getSizeInBits())
1315 .isKnownMultipleOf(STI.expandVScale(VecRegSize));
1316
1317 // If the Idx has been completely eliminated and this subvector's size is a
1318 // vector register or a multiple thereof, or the surrounding elements are
1319 // undef, then this is a subvector insert which naturally aligns to a vector
1320 // register. These can easily be handled using subregister manipulation.
1321 if (RemIdx == 0 && ExactlyVecRegSized)
1322 return true;
1323
1324 // If the subvector is smaller than a vector register, then the insertion
1325 // must preserve the undisturbed elements of the register. We do this by
1326 // lowering to an EXTRACT_SUBVECTOR grabbing the nearest LMUL=1 vector type
1327 // (which resolves to a subregister copy), performing a VSLIDEUP to place the
1328 // subvector within the vector register, and an INSERT_SUBVECTOR of that
1329 // LMUL=1 type back into the larger vector (resolving to another subregister
1330 // operation). See below for how our VSLIDEUP works. We go via a LMUL=1 type
1331 // to avoid allocating a large register group to hold our subvector.
1332
1333 // VSLIDEUP works by leaving elements 0<i<OFFSET undisturbed, elements
1334 // OFFSET<=i<VL set to the "subvector" and vl<=i<VLMAX set to the tail policy
1335 // (in our case undisturbed). This means we can set up a subvector insertion
1336 // where OFFSET is the insertion offset, and the VL is the OFFSET plus the
1337 // size of the subvector.
1338 const LLT XLenTy(STI.getXLenVT());
1339 LLT InterLitTy = BigTy;
1340 Register AlignedExtract = BigVec;
1341 unsigned AlignedIdx = Idx - RemIdx;
1343 getLMUL1Ty(BigTy).getSizeInBits())) {
1344 InterLitTy = getLMUL1Ty(BigTy);
1345 // Extract a subvector equal to the nearest full vector register type. This
1346 // should resolve to a G_EXTRACT on a subreg.
1347 AlignedExtract =
1348 MIB.buildExtractSubvector(InterLitTy, BigVec, AlignedIdx).getReg(0);
1349 }
1350
1351 auto Insert = MIB.buildInsertSubvector(InterLitTy, MIB.buildUndef(InterLitTy),
1352 LitVec, 0);
1353
1354 auto [Mask, _] = buildDefaultVLOps(InterLitTy, MIB, MRI);
1355 auto VL = MIB.buildVScale(XLenTy, LitTy.getElementCount().getKnownMinValue());
1356
1357 // If we're inserting into the lowest elements, use a tail undisturbed
1358 // vmv.v.v.
1359 MachineInstrBuilder Inserted;
1360 bool NeedInsertSubvec =
1361 TypeSize::isKnownGT(BigTy.getSizeInBits(), InterLitTy.getSizeInBits());
1362 Register InsertedDst =
1363 NeedInsertSubvec ? MRI.createGenericVirtualRegister(InterLitTy) : Dst;
1364 if (RemIdx == 0) {
1365 Inserted = MIB.buildInstr(RISCV::G_VMV_V_V_VL, {InsertedDst},
1366 {AlignedExtract, Insert, VL});
1367 } else {
1368 auto SlideupAmt = MIB.buildVScale(XLenTy, RemIdx);
1369 // Construct the vector length corresponding to RemIdx + length(LitTy).
1370 VL = MIB.buildAdd(XLenTy, SlideupAmt, VL);
1371 // Use tail agnostic policy if we're inserting over InterLitTy's tail.
1372 ElementCount EndIndex =
1375 if (STI.expandVScale(EndIndex) ==
1376 STI.expandVScale(InterLitTy.getElementCount()))
1378
1379 Inserted =
1380 MIB.buildInstr(RISCV::G_VSLIDEUP_VL, {InsertedDst},
1381 {AlignedExtract, Insert, SlideupAmt, Mask, VL, Policy});
1382 }
1383
1384 // If required, insert this subvector back into the correct vector register.
1385 // This should resolve to an INSERT_SUBREG instruction.
1386 if (NeedInsertSubvec)
1387 MIB.buildInsertSubvector(Dst, BigVec, Inserted, AlignedIdx);
1388
1389 MI.eraseFromParent();
1390 return true;
1391}
1392
1393bool RISCVLegalizerInfo::legalizeBitreverse(MachineInstr &MI,
1394 MachineIRBuilder &MIB) const {
1395 assert(MI.getOpcode() == TargetOpcode::G_BITREVERSE && "Unexpected opcode");
1396
1397 if (!STI.hasStdExtZbkb())
1398 return false;
1399
1400 MachineRegisterInfo &MRI = *MIB.getMRI();
1401
1402 Register Dst = MI.getOperand(0).getReg();
1403 Register Src = MI.getOperand(1).getReg();
1404
1405 if (!MRI.getType(Dst).isScalar(8))
1406 return false;
1407
1408 auto WideSrc = MIB.buildAnyExt(sXLen, Src);
1409 auto Brev = MIB.buildInstr(RISCV::G_BREV8, {sXLen}, {WideSrc.getReg(0)});
1410 MIB.buildTrunc(Dst, Brev.getReg(0));
1411
1412 MI.eraseFromParent();
1413 return true;
1414}
1415
1416static unsigned getRISCVWOpcode(unsigned Opcode) {
1417 switch (Opcode) {
1418 default:
1419 llvm_unreachable("Unexpected opcode");
1420 case TargetOpcode::G_ASHR:
1421 return RISCV::G_SRAW;
1422 case TargetOpcode::G_LSHR:
1423 return RISCV::G_SRLW;
1424 case TargetOpcode::G_SHL:
1425 return RISCV::G_SLLW;
1426 case TargetOpcode::G_SDIV:
1427 return RISCV::G_DIVW;
1428 case TargetOpcode::G_UDIV:
1429 return RISCV::G_DIVUW;
1430 case TargetOpcode::G_UREM:
1431 return RISCV::G_REMUW;
1432 case TargetOpcode::G_ROTL:
1433 return RISCV::G_ROLW;
1434 case TargetOpcode::G_ROTR:
1435 return RISCV::G_RORW;
1436 case TargetOpcode::G_CTLZ:
1437 return RISCV::G_CLZW;
1438 case TargetOpcode::G_CTTZ:
1439 return RISCV::G_CTZW;
1440 case TargetOpcode::G_CTLS:
1441 return RISCV::G_CLSW;
1442 case TargetOpcode::G_FPTOSI:
1443 return RISCV::G_FCVT_W_RV64;
1444 case TargetOpcode::G_FPTOUI:
1445 return RISCV::G_FCVT_WU_RV64;
1446 }
1447}
1448
1451 LostDebugLocObserver &LocObserver) const {
1452 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
1453 MachineRegisterInfo &MRI = *MIRBuilder.getMRI();
1454 MachineFunction &MF = *MI.getParent()->getParent();
1455 switch (MI.getOpcode()) {
1456 default:
1457 // No idea what to do.
1458 return false;
1459 case TargetOpcode::G_ABS:
1460 return Helper.lowerAbsToMaxNeg(MI);
1461 case TargetOpcode::G_FCONSTANT: {
1462 const APFloat &FVal = MI.getOperand(1).getFPImm()->getValueAPF();
1463
1464 // Convert G_FCONSTANT to G_CONSTANT.
1465 Register DstReg = MI.getOperand(0).getReg();
1466 MIRBuilder.buildConstant(DstReg, FVal.bitcastToAPInt());
1467
1468 MI.eraseFromParent();
1469 return true;
1470 }
1471 case TargetOpcode::G_CONSTANT: {
1472 const Function &F = MF.getFunction();
1473 // TODO: if PSI and BFI are present, add " ||
1474 // llvm::shouldOptForSize(*CurMBB, PSI, BFI)".
1475 bool ShouldOptForSize = F.hasOptSize();
1476 const ConstantInt *ConstVal = MI.getOperand(1).getCImm();
1477 if (!shouldBeInConstantPool(ConstVal->getValue(), ShouldOptForSize))
1478 return true;
1479 return Helper.lowerConstant(MI);
1480 }
1481 case TargetOpcode::G_SUB:
1482 case TargetOpcode::G_ADD: {
1483 Helper.Observer.changingInstr(MI);
1484 Helper.widenScalarSrc(MI, sXLen, 1, TargetOpcode::G_ANYEXT);
1485 Helper.widenScalarSrc(MI, sXLen, 2, TargetOpcode::G_ANYEXT);
1486
1487 Register DstALU = MRI.createGenericVirtualRegister(sXLen);
1488
1489 MachineOperand &MO = MI.getOperand(0);
1490 MIRBuilder.setInsertPt(MIRBuilder.getMBB(), ++MIRBuilder.getInsertPt());
1491 auto DstSext = MIRBuilder.buildSExtInReg(sXLen, DstALU, 32);
1492
1493 MIRBuilder.buildInstr(TargetOpcode::G_TRUNC, {MO}, {DstSext});
1494 MO.setReg(DstALU);
1495
1496 Helper.Observer.changedInstr(MI);
1497 return true;
1498 }
1499 case TargetOpcode::G_SEXT_INREG: {
1500 LLT DstTy = MRI.getType(MI.getOperand(0).getReg());
1501 int64_t SizeInBits = MI.getOperand(2).getImm();
1502 // Source size of 32 is sext.w.
1503 if (DstTy.getSizeInBits() == 64 && SizeInBits == 32)
1504 return true;
1505
1506 if (STI.hasStdExtZbb() && (SizeInBits == 8 || SizeInBits == 16))
1507 return true;
1508
1509 return Helper.lower(MI, 0, /* Unused hint type */ LLT()) ==
1511 }
1512 case TargetOpcode::G_ASHR:
1513 case TargetOpcode::G_LSHR:
1514 case TargetOpcode::G_SHL: {
1515 if (getIConstantVRegValWithLookThrough(MI.getOperand(2).getReg(), MRI)) {
1516 // We don't need a custom node for shift by constant. Just widen the
1517 // source and the shift amount.
1518 unsigned ExtOpc = TargetOpcode::G_ANYEXT;
1519 if (MI.getOpcode() == TargetOpcode::G_ASHR)
1520 ExtOpc = TargetOpcode::G_SEXT;
1521 else if (MI.getOpcode() == TargetOpcode::G_LSHR)
1522 ExtOpc = TargetOpcode::G_ZEXT;
1523
1524 Helper.Observer.changingInstr(MI);
1525 Helper.widenScalarSrc(MI, sXLen, 1, ExtOpc);
1526 Helper.widenScalarSrc(MI, sXLen, 2, TargetOpcode::G_ZEXT);
1527 Helper.widenScalarDst(MI, sXLen);
1528 Helper.Observer.changedInstr(MI);
1529 return true;
1530 }
1531
1532 Helper.Observer.changingInstr(MI);
1533 Helper.widenScalarSrc(MI, sXLen, 1, TargetOpcode::G_ANYEXT);
1534 Helper.widenScalarSrc(MI, sXLen, 2, TargetOpcode::G_ANYEXT);
1535 Helper.widenScalarDst(MI, sXLen);
1536 MI.setDesc(MIRBuilder.getTII().get(getRISCVWOpcode(MI.getOpcode())));
1537 Helper.Observer.changedInstr(MI);
1538 return true;
1539 }
1540 case TargetOpcode::G_SDIV:
1541 case TargetOpcode::G_UDIV:
1542 case TargetOpcode::G_UREM:
1543 case TargetOpcode::G_ROTL:
1544 case TargetOpcode::G_ROTR: {
1545 Helper.Observer.changingInstr(MI);
1546 Helper.widenScalarSrc(MI, sXLen, 1, TargetOpcode::G_ANYEXT);
1547 Helper.widenScalarSrc(MI, sXLen, 2, TargetOpcode::G_ANYEXT);
1548 Helper.widenScalarDst(MI, sXLen);
1549 MI.setDesc(MIRBuilder.getTII().get(getRISCVWOpcode(MI.getOpcode())));
1550 Helper.Observer.changedInstr(MI);
1551 return true;
1552 }
1553 case TargetOpcode::G_CTLZ:
1554 case TargetOpcode::G_CTTZ:
1555 case TargetOpcode::G_CTLS: {
1556 Helper.Observer.changingInstr(MI);
1557 Helper.widenScalarSrc(MI, sXLen, 1, TargetOpcode::G_ANYEXT);
1558 Helper.widenScalarDst(MI, sXLen);
1559 MI.setDesc(MIRBuilder.getTII().get(getRISCVWOpcode(MI.getOpcode())));
1560 Helper.Observer.changedInstr(MI);
1561 return true;
1562 }
1563 case TargetOpcode::G_FPTOSI:
1564 case TargetOpcode::G_FPTOUI: {
1565 Helper.Observer.changingInstr(MI);
1566 Helper.widenScalarDst(MI, sXLen);
1567 MI.setDesc(MIRBuilder.getTII().get(getRISCVWOpcode(MI.getOpcode())));
1569 Helper.Observer.changedInstr(MI);
1570 return true;
1571 }
1572 case TargetOpcode::G_IS_FPCLASS: {
1573 Register GISFPCLASS = MI.getOperand(0).getReg();
1574 Register Src = MI.getOperand(1).getReg();
1575 const MachineOperand &ImmOp = MI.getOperand(2);
1576 MachineIRBuilder MIB(MI);
1577
1578 // Turn LLVM IR's floating point classes to that in RISC-V,
1579 // by simply rotating the 10-bit immediate right by two bits.
1580 APInt GFpClassImm(10, static_cast<uint64_t>(ImmOp.getImm()));
1581 auto FClassMask = MIB.buildConstant(sXLen, GFpClassImm.rotr(2).zext(XLen));
1582 auto ConstZero = MIB.buildConstant(sXLen, 0);
1583
1584 auto GFClass = MIB.buildInstr(RISCV::G_FCLASS, {sXLen}, {Src});
1585 auto And = MIB.buildAnd(sXLen, GFClass, FClassMask);
1586 MIB.buildICmp(CmpInst::ICMP_NE, GISFPCLASS, And, ConstZero);
1587
1588 MI.eraseFromParent();
1589 return true;
1590 }
1591 case TargetOpcode::G_BRJT:
1592 return legalizeBRJT(MI, MIRBuilder);
1593 case TargetOpcode::G_VASTART:
1594 return legalizeVAStart(MI, MIRBuilder);
1595 case TargetOpcode::G_VSCALE:
1596 return legalizeVScale(MI, MIRBuilder);
1597 case TargetOpcode::G_ZEXT:
1598 case TargetOpcode::G_SEXT:
1599 case TargetOpcode::G_ANYEXT:
1600 return legalizeExt(MI, MIRBuilder);
1601 case TargetOpcode::G_SPLAT_VECTOR:
1602 return legalizeSplatVector(MI, MIRBuilder);
1603 case TargetOpcode::G_EXTRACT_SUBVECTOR:
1604 return legalizeExtractSubvector(MI, MIRBuilder);
1605 case TargetOpcode::G_INSERT_SUBVECTOR:
1606 return legalizeInsertSubvector(MI, Helper, MIRBuilder);
1607 case TargetOpcode::G_BITREVERSE:
1608 return legalizeBitreverse(MI, MIRBuilder);
1609 case TargetOpcode::G_LOAD:
1610 case TargetOpcode::G_STORE:
1611 return legalizeLoadStore(MI, Helper, MIRBuilder);
1612 }
1613
1614 llvm_unreachable("expected switch to return");
1615}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
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:54
This file declares the MachineConstantPool class which is an abstract constant pool to keep track of ...
This file declares the MachineIRBuilder class.
Register const TargetRegisterInfo * TRI
Promote Memory to Register
Definition Mem2Reg.cpp:110
uint64_t IntrinsicInst * II
#define P(N)
ppc ctr loops verify
static LLT getLMUL1Ty(LLT VecTy)
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 std::pair< MachineInstrBuilder, MachineInstrBuilder > buildDefaultVLOps(LLT VecTy, MachineIRBuilder &MIB, MachineRegisterInfo &MRI)
Gets the two common "VL" operands: an all-ones mask and the vector length.
static LegalityPredicate typeIsLegalBoolVec(unsigned TypeIdx, std::initializer_list< LLT > BoolVecTys, const RISCVSubtarget &ST)
static MachineInstrBuilder buildSplatSplitS64WithVL(const DstOp &Dst, const SrcOp &Passthru, const SrcOp &Scalar, const SrcOp &VL, MachineIRBuilder &MIB, MachineRegisterInfo &MRI)
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, const SrcOp &VL, MachineIRBuilder &MIB, MachineRegisterInfo &MRI)
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)
static unsigned getRISCVWOpcode(unsigned Opcode)
This file declares the targeting of the Machinelegalizer class for RISC-V.
Value * LHS
APInt bitcastToAPInt() const
Definition APFloat.h:1451
Class for arbitrary precision integers.
Definition APInt.h:78
LLVM_ABI APInt zext(unsigned width) const
Zero extend to a new width.
Definition APInt.cpp:1055
unsigned getBitWidth() const
Return the number of bits in the APInt.
Definition APInt.h:1513
LLVM_ABI APInt rotr(unsigned rotateAmt) const
Rotate right by rotateAmt.
Definition APInt.cpp:1197
int64_t getSExtValue() const
Get sign extended value.
Definition APInt.h:1587
@ ICMP_NE
not equal
Definition InstrTypes.h:762
This is the shared class of boolean and integer constants.
Definition Constants.h:87
const APInt & getValue() const
Return the constant as an APInt value reference.
Definition Constants.h:159
A parsed version of the target data layout string in and methods for querying it.
Definition DataLayout.h:64
static constexpr ElementCount getScalable(ScalarTy MinVal)
Definition TypeSize.h:312
LLVMContext & getContext() const
getContext - Return a reference to the LLVMContext associated with this function.
Definition Function.cpp:353
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.
Register getReg(unsigned Idx) const
Access the Idx'th operand as a register and return it.
constexpr bool isScalableVector() const
Returns true if the LLT is a scalable vector.
constexpr unsigned getScalarSizeInBits() const
constexpr bool isScalar() const
static constexpr LLT scalable_vector(unsigned MinNumElements, unsigned ScalarSizeInBits)
Get a low-level scalable vector of some number of elements and element width.
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.
static constexpr LLT vector(ElementCount EC, unsigned ScalarSizeInBits)
Get a low-level vector of some number of elements and element width.
static constexpr LLT scalar(unsigned SizeInBits)
Get a low-level scalar or aggregate "bag of bits".
constexpr bool isVector() const
static constexpr LLT pointer(unsigned AddressSpace, unsigned SizeInBits)
Get a low-level pointer in the given address space.
constexpr TypeSize getSizeInBits() const
Returns the total size of the type. Must only be called on sized types.
constexpr ElementCount getElementCount() const
LLT getElementType() const
Returns the vector's element type. Only valid for vector types.
This is an important class for using LLVM in a threaded context.
Definition LLVMContext.h:68
LegalizeRuleSet & maxScalar(unsigned TypeIdx, const LLT Ty)
Ensure the scalar is at most as wide as Ty.
LegalizeRuleSet & lower()
The instruction is lowered.
LegalizeRuleSet & clampScalar(unsigned TypeIdx, const LLT MinTy, const LLT MaxTy)
Limit the range of scalar sizes to MinTy and MaxTy.
LegalizeRuleSet & alwaysLegal()
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 & customFor(std::initializer_list< LLT > Types)
LLVM_ABI void widenScalarSrc(MachineInstr &MI, LLT WideTy, unsigned OpIdx, unsigned ExtOpcode)
Legalize a single operand OpIdx of the machine instruction MI as a Use by extending the operand's typ...
LLVM_ABI LegalizeResult lowerAbsToMaxNeg(MachineInstr &MI)
LLVM_ABI 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.
LLVM_ABI 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.
LLVM_ABI LegalizeResult widenScalar(MachineInstr &MI, unsigned TypeIdx, LLT WideTy)
Legalize an instruction by performing the operation on a wider scalar type (for example a 16-bit addi...
MachineIRBuilder & MIRBuilder
Expose MIRBuilder so clients can set their own RecordInsertInstruction functions.
LLVM_ABI LegalizeResult lowerConstant(MachineInstr &MI)
LLVM_ABI void widenScalarDst(MachineInstr &MI, LLT WideTy, unsigned OpIdx=0, unsigned TruncOpcode=TargetOpcode::G_TRUNC)
Legalize a single operand OpIdx of the machine instruction MI as a Def by extending the operand's typ...
LegalizeRuleSet & getActionDefinitionsBuilder(unsigned Opcode)
Get the action definition builder for the given opcode.
const MCInstrDesc & get(unsigned Opcode) const
Return the machine instruction descriptor that corresponds to the specified instruction opcode.
Definition MCInstrInfo.h:89
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
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.
const DataLayout & getDataLayout() const
Return the DataLayout attached to the Module associated to this MF.
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...
const MachineJumpTableInfo * getJumpTableInfo() const
getJumpTableInfo - Return the jump table info object for the current function.
Helper class to build MachineInstr.
void setInsertPt(MachineBasicBlock &MBB, MachineBasicBlock::iterator II)
Set the insertion point before the specified position.
MachineInstrBuilder buildAdd(const DstOp &Dst, const SrcOp &Src0, const SrcOp &Src1, std::optional< unsigned > Flags=std::nullopt)
Build and insert Res = G_ADD Op0, Op1.
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 buildInsertSubvector(const DstOp &Res, const SrcOp &Src0, const SrcOp &Src1, unsigned Index)
Build and insert Res = G_INSERT_SUBVECTOR Src0, Src1, Idx.
MachineInstrBuilder buildAnd(const DstOp &Dst, const SrcOp &Src0, const SrcOp &Src1)
Build and insert Res = G_AND Op0, Op1.
const TargetInstrInfo & getTII()
MachineInstrBuilder buildICmp(CmpInst::Predicate Pred, const DstOp &Res, const SrcOp &Op0, const SrcOp &Op1, std::optional< unsigned > Flags=std::nullopt)
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)
MachineBasicBlock::iterator getInsertPt()
Current insertion point for new instructions.
MachineInstrBuilder buildZExt(const DstOp &Res, const SrcOp &Op, std::optional< unsigned > Flags=std::nullopt)
Build and insert Res = G_ZEXT Op.
MachineInstrBuilder buildVScale(const DstOp &Res, unsigned MinElts)
Build and insert Res = G_VSCALE MinElts.
MachineInstrBuilder buildIntToPtr(const DstOp &Dst, const SrcOp &Src)
Build and insert a G_INTTOPTR instruction.
MachineInstrBuilder buildLoad(const DstOp &Res, const SrcOp &Addr, MachineMemOperand &MMO)
Build and insert Res = G_LOAD Addr, MMO.
MachineInstrBuilder buildPtrAdd(const DstOp &Res, const SrcOp &Op0, const SrcOp &Op1, std::optional< unsigned > Flags=std::nullopt)
Build and insert Res = G_PTR_ADD Op0, Op1.
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.
MachineFunction & getMF()
Getter for the function we currently build.
MachineInstrBuilder buildTrunc(const DstOp &Res, const SrcOp &Op, std::optional< unsigned > Flags=std::nullopt)
Build and insert Res = G_TRUNC Op.
const MachineBasicBlock & getMBB() const
Getter for the basic block we currently build.
MachineInstrBuilder buildAnyExt(const DstOp &Res, const SrcOp &Op)
Build and insert Res = G_ANYEXT Op0.
MachineRegisterInfo * getMRI()
Getter for MRI.
MachineInstrBuilder buildExtractSubvector(const DstOp &Res, const SrcOp &Src, unsigned Index)
Build and insert Res = G_EXTRACT_SUBVECTOR Src, Idx0.
const DataLayout & getDataLayout() const
MachineInstrBuilder buildBrIndirect(Register Tgt)
Build and insert G_BRINDIRECT Tgt.
MachineInstrBuilder buildSplatVector(const DstOp &Res, const SrcOp &Val)
Build and insert Res = G_SPLAT_VECTOR Val.
MachineInstrBuilder buildLoadInstr(unsigned Opcode, const DstOp &Res, const SrcOp &Addr, MachineMemOperand &MMO)
Build and insert Res = <opcode> Addr, MMO.
virtual MachineInstrBuilder buildConstant(const DstOp &Res, const ConstantInt &Val)
Build and insert Res = G_CONSTANT Val.
MachineInstrBuilder buildSExtInReg(const DstOp &Res, const SrcOp &Op, int64_t ImmOp)
Build and insert Res = G_SEXT_INREG Op, ImmOp.
Register getReg(unsigned Idx) const
Get the register for the operand index.
Representation of each machine instruction.
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
LLVM_ABI unsigned getEntrySize(const DataLayout &TD) const
getEntrySize - Return the size of each entry in the jump table.
@ EK_LabelDifference32
EK_LabelDifference32 - Each entry is the address of the block minus the address of the jump table.
@ EK_Custom32
EK_Custom32 - Each entry is a 32-bit value that is custom lowered by the TargetLowering::LowerCustomJ...
@ EK_BlockAddress
EK_BlockAddress - Each entry is a plain address of block, e.g.: .word LBB123.
LLVM_ABI unsigned getEntryAlignment(const DataLayout &TD) const
getEntryAlignment - Return the alignment of each entry in the jump table.
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
LLVM_ABI void setReg(Register Reg)
Change the register this operand corresponds to.
static MachineOperand CreateImm(int64_t Val)
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
LLVM_ABI MachineInstr * getVRegDef(Register Reg) const
getVRegDef - Return the machine instr that defines the specified virtual register or null if none is ...
LLT getType(Register Reg) const
Get the low-level type of Reg or LLT{} if Reg is not a generic (target independent) virtual register.
LLVM_ABI Register createGenericVirtualRegister(LLT Ty, StringRef Name="")
Create and return a new generic virtual register with low-level type Ty.
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-...
static std::pair< unsigned, unsigned > decomposeSubvectorInsertExtractToSubRegs(MVT VecVT, MVT SubVecVT, unsigned InsertExtractIdx, const RISCVRegisterInfo *TRI)
static RISCVVType::VLMUL getLMUL(MVT VT)
Wrapper class representing virtual and physical registers.
Definition Register.h:20
Register getReg() const
static constexpr TypeSize getScalable(ScalarTy MinimumSize)
Definition TypeSize.h:346
constexpr ScalarTy getKnownMinValue() const
Returns the minimum value this quantity can represent.
Definition TypeSize.h:165
static constexpr bool isKnownGT(const FixedOrScalableQuantity &LHS, const FixedOrScalableQuantity &RHS)
Definition TypeSize.h:223
constexpr LeafTy divideCoefficientBy(ScalarTy RHS) const
We do not provide the '/' operator here because division for polynomial types does not work in the sa...
Definition TypeSize.h:252
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
constexpr std::underlying_type_t< E > Mask()
Get a bitmask with 1s in all places up to the high-order bit of E's largest value.
LLVM_ABI 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.
LLVM_ABI LegalityPredicate typeIs(unsigned TypeIdx, LLT TypesInit)
True iff the given type index is the specified type.
LLVM_ABI 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)
SmallVector< Inst, 8 > InstSeq
Definition RISCVMatInt.h:43
LLVM_ABI std::pair< unsigned, bool > decodeVLMUL(VLMUL VLMul)
static constexpr unsigned RVVBitsPerBlock
Invariant opcodes: All instruction sets have these as their low opcodes.
This is an optimization pass for GlobalISel generic memory operations.
LLVM_ABI Type * getTypeForLLT(LLT Ty, LLVMContext &C)
Get the type back from LLT.
Definition Utils.cpp:1987
constexpr bool isInt(int64_t x)
Checks if an integer fits into the given bit width.
Definition MathExtras.h:165
LLVM_ABI 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:1572
LLVM_ABI MVT getMVTForLLT(LLT Ty)
Get a rough equivalent of an MVT for a given LLT.
constexpr bool isPowerOf2_64(uint64_t Value)
Return true if the argument is a power of two > 0 (64 bit edition.)
Definition MathExtras.h:284
LLVM_ABI 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:1554
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:337
unsigned Log2_32(uint32_t Value)
Return the floor log base 2 of the specified value, -1 if the value is zero.
Definition MathExtras.h:331
std::function< bool(const LegalityQuery &)> LegalityPredicate
constexpr bool isPowerOf2_32(uint32_t Value)
Return true if the argument is a power of two > 0.
Definition MathExtras.h:279
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
Definition Casting.h:547
@ And
Bitwise or logical AND of integers.
DWARFExpression::Operation Op
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:559
LLVM_ABI 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:436
unsigned Log2(Align A)
Returns the log2 of the alignment.
Definition Alignment.h:197
This struct is a compact representation of a valid (non-zero power of two) alignment.
Definition Alignment.h:39
static LLVM_ABI EVT getEVT(Type *Ty, bool HandleUnknown=false)
Return the value type corresponding to the specified type.
The LegalityQuery object bundles together all the information that's needed to decide whether a given...
ArrayRef< LLT > Types
Matching combinators.
This class contains a discriminated union of information about pointers in memory operands,...
static LLVM_ABI MachinePointerInfo getJumpTable(MachineFunction &MF)
Return a MachinePointerInfo record that refers to a jump table entry.