LLVM 24.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"
30#include "llvm/IR/Intrinsics.h"
31#include "llvm/IR/IntrinsicsRISCV.h"
32#include "llvm/IR/Type.h"
33
34using namespace llvm;
35using namespace LegalityPredicates;
36using namespace LegalizeMutations;
37using namespace MIPatternMatch;
38
40typeIsLegalIntOrFPVec(unsigned TypeIdx,
41 std::initializer_list<LLT> IntOrFPVecTys,
42 const RISCVSubtarget &ST) {
43 LegalityPredicate P = [=, &ST](const LegalityQuery &Query) {
44 return ST.hasVInstructions() &&
45 (Query.Types[TypeIdx].getScalarSizeInBits() != 64 ||
46 ST.hasVInstructionsI64()) &&
47 (Query.Types[TypeIdx].getElementCount().getKnownMinValue() != 1 ||
48 ST.getELen() == 64);
49 };
50
51 return all(typeInSet(TypeIdx, IntOrFPVecTys), P);
52}
53
55typeIsLegalBoolVec(unsigned TypeIdx, std::initializer_list<LLT> BoolVecTys,
56 const RISCVSubtarget &ST) {
57 LegalityPredicate P = [=, &ST](const LegalityQuery &Query) {
58 return ST.hasVInstructions() &&
59 (Query.Types[TypeIdx].getElementCount().getKnownMinValue() != 1 ||
60 ST.getELen() == 64);
61 };
62 return all(typeInSet(TypeIdx, BoolVecTys), P);
63}
64
65static LegalityPredicate typeIsLegalPtrVec(unsigned TypeIdx,
66 std::initializer_list<LLT> PtrVecTys,
67 const RISCVSubtarget &ST) {
68 LegalityPredicate P = [=, &ST](const LegalityQuery &Query) {
69 return ST.hasVInstructions() &&
70 (Query.Types[TypeIdx].getElementCount().getKnownMinValue() != 1 ||
71 ST.getELen() == 64) &&
72 (Query.Types[TypeIdx].getElementCount().getKnownMinValue() != 16 ||
73 Query.Types[TypeIdx].getScalarSizeInBits() == 32);
74 };
75 return all(typeInSet(TypeIdx, PtrVecTys), P);
76}
77
79 : STI(ST), XLen(STI.getXLen()), sXLen(LLT::scalar(XLen)) {
80 const LLT sDoubleXLen = LLT::scalar(2 * XLen);
81 const LLT p0 = LLT::pointer(0, XLen);
82 const LLT s1 = LLT::scalar(1);
83 const LLT s8 = LLT::scalar(8);
84 const LLT s16 = LLT::scalar(16);
85 const LLT f16 = LLT::float16();
86 const LLT s32 = LLT::scalar(32);
87 const LLT s64 = LLT::scalar(64);
88 const LLT s128 = LLT::scalar(128);
89
90 const LLT nxv1s1 = LLT::scalable_vector(1, s1);
91 const LLT nxv2s1 = LLT::scalable_vector(2, s1);
92 const LLT nxv4s1 = LLT::scalable_vector(4, s1);
93 const LLT nxv8s1 = LLT::scalable_vector(8, s1);
94 const LLT nxv16s1 = LLT::scalable_vector(16, s1);
95 const LLT nxv32s1 = LLT::scalable_vector(32, s1);
96 const LLT nxv64s1 = LLT::scalable_vector(64, s1);
97
98 const LLT nxv1s8 = LLT::scalable_vector(1, s8);
99 const LLT nxv2s8 = LLT::scalable_vector(2, s8);
100 const LLT nxv4s8 = LLT::scalable_vector(4, s8);
101 const LLT nxv8s8 = LLT::scalable_vector(8, s8);
102 const LLT nxv16s8 = LLT::scalable_vector(16, s8);
103 const LLT nxv32s8 = LLT::scalable_vector(32, s8);
104 const LLT nxv64s8 = LLT::scalable_vector(64, s8);
105
106 const LLT nxv1s16 = LLT::scalable_vector(1, s16);
107 const LLT nxv2s16 = LLT::scalable_vector(2, s16);
108 const LLT nxv4s16 = LLT::scalable_vector(4, s16);
109 const LLT nxv8s16 = LLT::scalable_vector(8, s16);
110 const LLT nxv16s16 = LLT::scalable_vector(16, s16);
111 const LLT nxv32s16 = LLT::scalable_vector(32, s16);
112
113 const LLT nxv1s32 = LLT::scalable_vector(1, s32);
114 const LLT nxv2s32 = LLT::scalable_vector(2, s32);
115 const LLT nxv4s32 = LLT::scalable_vector(4, s32);
116 const LLT nxv8s32 = LLT::scalable_vector(8, s32);
117 const LLT nxv16s32 = LLT::scalable_vector(16, s32);
118
119 const LLT nxv1s64 = LLT::scalable_vector(1, s64);
120 const LLT nxv2s64 = LLT::scalable_vector(2, s64);
121 const LLT nxv4s64 = LLT::scalable_vector(4, s64);
122 const LLT nxv8s64 = LLT::scalable_vector(8, s64);
123
124 const LLT nxv1p0 = LLT::scalable_vector(1, p0);
125 const LLT nxv2p0 = LLT::scalable_vector(2, p0);
126 const LLT nxv4p0 = LLT::scalable_vector(4, p0);
127 const LLT nxv8p0 = LLT::scalable_vector(8, p0);
128 const LLT nxv16p0 = LLT::scalable_vector(16, p0);
129
130 using namespace TargetOpcode;
131
132 auto BoolVecTys = {nxv1s1, nxv2s1, nxv4s1, nxv8s1, nxv16s1, nxv32s1, nxv64s1};
133
134 auto IntOrFPVecTys = {nxv1s8, nxv2s8, nxv4s8, nxv8s8, nxv16s8, nxv32s8,
135 nxv64s8, nxv1s16, nxv2s16, nxv4s16, nxv8s16, nxv16s16,
136 nxv32s16, nxv1s32, nxv2s32, nxv4s32, nxv8s32, nxv16s32,
137 nxv1s64, nxv2s64, nxv4s64, nxv8s64};
138
139 auto PtrVecTys = {nxv1p0, nxv2p0, nxv4p0, nxv8p0, nxv16p0};
140
141 getActionDefinitionsBuilder({G_ADD, G_SUB})
142 .legalFor({sXLen})
143 .legalIf(typeIsLegalIntOrFPVec(0, IntOrFPVecTys, ST))
144 .customFor(ST.is64Bit(), {s32})
146 .clampScalar(0, sXLen, sXLen);
147
148 getActionDefinitionsBuilder({G_AND, G_OR, G_XOR})
149 .legalFor({sXLen})
150 .legalIf(typeIsLegalIntOrFPVec(0, IntOrFPVecTys, ST))
152 .clampScalar(0, sXLen, sXLen);
153
155 {G_UADDE, G_UADDO, G_USUBE, G_USUBO, G_READ_REGISTER, G_WRITE_REGISTER})
156 .lower();
157
158 getActionDefinitionsBuilder({G_SADDE, G_SADDO, G_SSUBE, G_SSUBO})
159 .minScalar(0, sXLen)
160 .lower();
161
162 // TODO: Use Vector Single-Width Saturating Instructions for vector types.
164 {G_UADDSAT, G_SADDSAT, G_USUBSAT, G_SSUBSAT, G_SSHLSAT, G_USHLSAT})
165 .lower();
166
167 getActionDefinitionsBuilder({G_SHL, G_ASHR, G_LSHR})
168 .legalFor({{sXLen, sXLen}})
169 .customFor(ST.is64Bit(), {{s32, s32}})
170 .widenScalarToNextPow2(0)
171 .clampScalar(1, sXLen, sXLen)
172 .clampScalar(0, sXLen, sXLen);
173
174 getActionDefinitionsBuilder({G_ZEXT, G_SEXT, G_ANYEXT})
175 .legalFor({{s32, s16}})
176 .legalFor(ST.is64Bit(), {{s64, s16}, {s64, s32}})
177 .legalIf(all(typeIsLegalIntOrFPVec(0, IntOrFPVecTys, ST),
178 typeIsLegalIntOrFPVec(1, IntOrFPVecTys, ST)))
179 .customIf(typeIsLegalBoolVec(1, BoolVecTys, ST))
180 .maxScalar(0, sXLen);
181
182 getActionDefinitionsBuilder(G_TRUNC).alwaysLegal();
183
184 {
185 LegalityPredicate ValidSextInRegWidth = all(sizeIs(0, 64), immIs(0, 32));
186
187 if (STI.hasStdExtZbb())
188 ValidSextInRegWidth =
189 LegalityPredicates::any(ValidSextInRegWidth, immInSet(0, {8, 16}));
190
191 getActionDefinitionsBuilder(G_SEXT_INREG)
192 .legalIf(all(typeIs(0, sXLen), ValidSextInRegWidth))
193 .clampScalar(0, sXLen, sXLen)
194 .lower();
195 }
196
197 // Merge/Unmerge
198 for (unsigned Op : {G_MERGE_VALUES, G_UNMERGE_VALUES}) {
199 auto &MergeUnmergeActions = getActionDefinitionsBuilder(Op);
200 unsigned BigTyIdx = Op == G_MERGE_VALUES ? 0 : 1;
201 unsigned LitTyIdx = Op == G_MERGE_VALUES ? 1 : 0;
202 if (XLen == 32 && (ST.hasStdExtD() || ST.hasStdExtZilsd())) {
203 MergeUnmergeActions.legalIf(
204 all(typeIs(BigTyIdx, s64), typeIs(LitTyIdx, s32)));
205 }
206 MergeUnmergeActions.widenScalarToNextPow2(LitTyIdx, XLen)
207 .widenScalarToNextPow2(BigTyIdx, XLen)
208 .clampScalar(LitTyIdx, sXLen, sXLen)
209 .clampScalar(BigTyIdx, sXLen, sXLen);
210 }
211
212 getActionDefinitionsBuilder({G_FSHL, G_FSHR}).lower();
213
214 getActionDefinitionsBuilder({G_ROTR, G_ROTL})
215 .legalFor(ST.hasStdExtZbb() || ST.hasStdExtZbkb(), {{sXLen, sXLen}})
216 .customFor(ST.is64Bit() && (ST.hasStdExtZbb() || ST.hasStdExtZbkb()),
217 {{s32, s32}})
218 .lower();
219
220 getActionDefinitionsBuilder(G_BITREVERSE)
221 .customFor(ST.hasStdExtZbkb(), {s8})
222 .maxScalar(0, sXLen)
223 .lower();
224
225 getActionDefinitionsBuilder(G_BITCAST).legalIf(
227 typeIsLegalBoolVec(0, BoolVecTys, ST)),
229 typeIsLegalBoolVec(1, BoolVecTys, ST))));
230
231 auto &BSWAPActions = getActionDefinitionsBuilder(G_BSWAP);
232 if (ST.hasStdExtZbb() || ST.hasStdExtZbkb())
233 BSWAPActions.legalFor({sXLen}).clampScalar(0, sXLen, sXLen);
234 else
235 BSWAPActions.maxScalar(0, sXLen).lower();
236
237 getActionDefinitionsBuilder(G_CLMUL)
238 .legalFor(ST.hasStdExtZbkc(), {sXLen})
239 .unsupported();
240
241 getActionDefinitionsBuilder(G_CLMULH)
242 .legalFor(ST.hasStdExtZbkc(), {sXLen})
243 .customFor(ST.is64Bit() && ST.hasStdExtZbkc(), {s32})
244 .unsupported();
245
246 // CLMULR is Zbc-only; Zbkc is a subset that has CLMUL/CLMULH but not CLMULR.
247 getActionDefinitionsBuilder(G_CLMULR)
248 .legalFor(ST.hasStdExtZbc(), {sXLen})
249 .customFor(ST.is64Bit() && ST.hasStdExtZbc(), {s32})
250 .unsupported();
251
252 auto &CTLZPoisonActions = getActionDefinitionsBuilder(G_CTLZ_ZERO_POISON);
253 auto &CTTZPoisonActions = getActionDefinitionsBuilder(G_CTTZ_ZERO_POISON);
254 if (ST.hasStdExtZbb()) {
255 getActionDefinitionsBuilder({G_CTLZ, G_CTTZ})
256 .legalFor({{sXLen, sXLen}})
257 .customFor({{s32, s32}})
258 .clampScalar(0, s32, sXLen)
259 .widenScalarToNextPow2(0)
260 .scalarSameSizeAs(1, 0);
261 } else {
262 auto &CTLZActions = getActionDefinitionsBuilder(G_CTLZ);
263 if (ST.hasVendorXTHeadBb())
264 CTLZActions.legalFor({{sXLen, sXLen}})
265 .clampScalar(0, sXLen, sXLen)
266 .scalarSameSizeAs(1, 0);
267 else
268 CTLZActions.maxScalar(0, sXLen).scalarSameSizeAs(1, 0).lower();
269
270 auto &CTTZActions = getActionDefinitionsBuilder(G_CTTZ);
271 if (ST.hasVendorXTHeadBb()) {
272 CTTZActions.clampScalar(0, sXLen, sXLen).scalarSameSizeAs(1, 0).lower();
273 CTLZPoisonActions.clampScalar(0, sXLen, sXLen).scalarSameSizeAs(1, 0);
274 CTTZPoisonActions.clampScalar(0, sXLen, sXLen).scalarSameSizeAs(1, 0);
275 } else {
276 CTTZActions.maxScalar(0, sXLen).scalarSameSizeAs(1, 0).lower();
277 CTLZPoisonActions.maxScalar(0, sXLen).scalarSameSizeAs(1, 0);
278 CTTZPoisonActions.maxScalar(0, sXLen).scalarSameSizeAs(1, 0);
279 }
280 }
281 CTLZPoisonActions.lower();
282 CTTZPoisonActions.lower();
283
284 auto &CountSignActions = getActionDefinitionsBuilder(G_CTLS);
285 if (ST.hasStdExtP()) {
286 CountSignActions.legalFor({{sXLen, sXLen}})
287 .customFor({{s32, s32}})
288 .clampScalar(0, s32, sXLen)
289 .widenScalarToNextPow2(0)
290 .scalarSameSizeAs(1, 0);
291 } else {
292 CountSignActions.maxScalar(0, sXLen).scalarSameSizeAs(1, 0).lower();
293 }
294
295 auto &CTPOPActions = getActionDefinitionsBuilder(G_CTPOP);
296 if (ST.hasStdExtZbb()) {
297 CTPOPActions.legalFor({{sXLen, sXLen}})
298 .clampScalar(0, sXLen, sXLen)
299 .scalarSameSizeAs(1, 0);
300 } else {
301 CTPOPActions.widenScalarToNextPow2(0, /*Min*/ 8)
302 .clampScalar(0, s8, sXLen)
303 .scalarSameSizeAs(1, 0)
304 .lower();
305 }
306
307 getActionDefinitionsBuilder(G_CONSTANT)
308 .legalFor({p0})
309 .legalFor(!ST.is64Bit(), {s32})
310 .customFor(ST.is64Bit(), {s64})
311 .widenScalarToNextPow2(0)
312 .clampScalar(0, sXLen, sXLen);
313
314 // TODO: transform illegal vector types into legal vector type
315 getActionDefinitionsBuilder(G_FREEZE)
316 .legalFor({s16, s32, p0})
317 .legalFor(ST.is64Bit(), {s64})
318 .legalIf(typeIsLegalBoolVec(0, BoolVecTys, ST))
319 .legalIf(typeIsLegalIntOrFPVec(0, IntOrFPVecTys, ST))
320 .widenScalarToNextPow2(0)
321 .clampScalar(0, s16, sXLen);
322
323 // TODO: transform illegal vector types into legal vector type
324 // TODO: Merge with G_FREEZE?
325 getActionDefinitionsBuilder(
326 {G_IMPLICIT_DEF, G_CONSTANT_FOLD_BARRIER})
327 .legalFor({s32, sXLen, p0})
328 .legalIf(typeIsLegalBoolVec(0, BoolVecTys, ST))
329 .legalIf(typeIsLegalIntOrFPVec(0, IntOrFPVecTys, ST))
330 .widenScalarToNextPow2(0)
331 .clampScalar(0, s32, sXLen);
332
333 getActionDefinitionsBuilder(G_ICMP)
334 .legalFor({{sXLen, sXLen}, {sXLen, p0}})
335 .legalIf(all(typeIsLegalBoolVec(0, BoolVecTys, ST),
336 typeIsLegalIntOrFPVec(1, IntOrFPVecTys, ST)))
337 .widenScalarOrEltToNextPow2OrMinSize(1, 8)
338 .clampScalar(1, sXLen, sXLen)
339 .clampScalar(0, sXLen, sXLen);
340
341 getActionDefinitionsBuilder(G_SELECT)
342 .legalFor({{s32, sXLen}, {p0, sXLen}})
343 .legalIf(all(typeIsLegalIntOrFPVec(0, IntOrFPVecTys, ST),
344 typeIsLegalBoolVec(1, BoolVecTys, ST)))
345 .legalFor(XLen == 64 || ST.hasStdExtD(), {{s64, sXLen}})
346 .widenScalarToNextPow2(0)
347 .clampScalar(0, s32, (XLen == 64 || ST.hasStdExtD()) ? s64 : s32)
348 .clampScalar(1, sXLen, sXLen);
349
350 auto &LoadActions = getActionDefinitionsBuilder(G_LOAD);
351 auto &StoreActions = getActionDefinitionsBuilder(G_STORE);
352 auto &ExtLoadActions = getActionDefinitionsBuilder({G_SEXTLOAD, G_ZEXTLOAD});
353
354 // Return the alignment needed for scalar memory ops. If unaligned scalar mem
355 // is supported, we only require byte alignment. Otherwise, we need the memory
356 // op to be natively aligned.
357 auto getScalarMemAlign = [&ST](unsigned Size) {
358 return ST.enableUnalignedScalarMem() ? 8 : Size;
359 };
360
361 LoadActions.legalForTypesWithMemDesc(
362 {{s16, p0, s8, getScalarMemAlign(8)},
363 {s32, p0, s8, getScalarMemAlign(8)},
364 {s16, p0, s16, getScalarMemAlign(16)},
365 {s32, p0, s16, getScalarMemAlign(16)},
366 {s32, p0, s32, getScalarMemAlign(32)},
367 {p0, p0, sXLen, getScalarMemAlign(XLen)}});
368 StoreActions.legalForTypesWithMemDesc(
369 {{s16, p0, s8, getScalarMemAlign(8)},
370 {s32, p0, s8, getScalarMemAlign(8)},
371 {s16, p0, s16, getScalarMemAlign(16)},
372 {s32, p0, s16, getScalarMemAlign(16)},
373 {s32, p0, s32, getScalarMemAlign(32)},
374 {p0, p0, sXLen, getScalarMemAlign(XLen)}});
375 ExtLoadActions.legalForTypesWithMemDesc(
376 {{sXLen, p0, s8, getScalarMemAlign(8)},
377 {sXLen, p0, s16, getScalarMemAlign(16)}});
378 if (XLen == 64) {
379 LoadActions.legalForTypesWithMemDesc(
380 {{s64, p0, s8, getScalarMemAlign(8)},
381 {s64, p0, s16, getScalarMemAlign(16)},
382 {s64, p0, s32, getScalarMemAlign(32)},
383 {s64, p0, s64, getScalarMemAlign(64)}});
384 StoreActions.legalForTypesWithMemDesc(
385 {{s64, p0, s8, getScalarMemAlign(8)},
386 {s64, p0, s16, getScalarMemAlign(16)},
387 {s64, p0, s32, getScalarMemAlign(32)},
388 {s64, p0, s64, getScalarMemAlign(64)}});
389 ExtLoadActions.legalForTypesWithMemDesc(
390 {{s64, p0, s32, getScalarMemAlign(32)}});
391 } else if (ST.hasStdExtD() || ST.hasStdExtZilsd()) {
392 // RV32: s64 is legal for f64 (D/Zdinx) or i64 (Zilsd); LLT cannot tell the
393 // two apart, so one rule covers both.
394 // FIXME: We require natural alignment, so under -mzilsd-word-align an
395 // align-4 i64 access is split into two s32 ones. riscv-prera-zilsd-opt
396 // merges them back into LD_RV32/SD_RV32, but it is skipped at -O0.
397 LoadActions.legalForTypesWithMemDesc(
398 {{s64, p0, s64, getScalarMemAlign(64)}});
399 StoreActions.legalForTypesWithMemDesc(
400 {{s64, p0, s64, getScalarMemAlign(64)}});
401 }
402
403 // Vector loads/stores.
404 if (ST.hasVInstructions()) {
405 LoadActions.legalForTypesWithMemDesc({{nxv2s8, p0, nxv2s8, 8},
406 {nxv4s8, p0, nxv4s8, 8},
407 {nxv8s8, p0, nxv8s8, 8},
408 {nxv16s8, p0, nxv16s8, 8},
409 {nxv32s8, p0, nxv32s8, 8},
410 {nxv64s8, p0, nxv64s8, 8},
411 {nxv2s16, p0, nxv2s16, 16},
412 {nxv4s16, p0, nxv4s16, 16},
413 {nxv8s16, p0, nxv8s16, 16},
414 {nxv16s16, p0, nxv16s16, 16},
415 {nxv32s16, p0, nxv32s16, 16},
416 {nxv2s32, p0, nxv2s32, 32},
417 {nxv4s32, p0, nxv4s32, 32},
418 {nxv8s32, p0, nxv8s32, 32},
419 {nxv16s32, p0, nxv16s32, 32}});
420 StoreActions.legalForTypesWithMemDesc({{nxv2s8, p0, nxv2s8, 8},
421 {nxv4s8, p0, nxv4s8, 8},
422 {nxv8s8, p0, nxv8s8, 8},
423 {nxv16s8, p0, nxv16s8, 8},
424 {nxv32s8, p0, nxv32s8, 8},
425 {nxv64s8, p0, nxv64s8, 8},
426 {nxv2s16, p0, nxv2s16, 16},
427 {nxv4s16, p0, nxv4s16, 16},
428 {nxv8s16, p0, nxv8s16, 16},
429 {nxv16s16, p0, nxv16s16, 16},
430 {nxv32s16, p0, nxv32s16, 16},
431 {nxv2s32, p0, nxv2s32, 32},
432 {nxv4s32, p0, nxv4s32, 32},
433 {nxv8s32, p0, nxv8s32, 32},
434 {nxv16s32, p0, nxv16s32, 32}});
435
436 if (ST.getELen() == 64) {
437 LoadActions.legalForTypesWithMemDesc({{nxv1s8, p0, nxv1s8, 8},
438 {nxv1s16, p0, nxv1s16, 16},
439 {nxv1s32, p0, nxv1s32, 32}});
440 StoreActions.legalForTypesWithMemDesc({{nxv1s8, p0, nxv1s8, 8},
441 {nxv1s16, p0, nxv1s16, 16},
442 {nxv1s32, p0, nxv1s32, 32}});
443 }
444
445 if (ST.hasVInstructionsI64()) {
446 LoadActions.legalForTypesWithMemDesc({{nxv1s64, p0, nxv1s64, 64},
447 {nxv2s64, p0, nxv2s64, 64},
448 {nxv4s64, p0, nxv4s64, 64},
449 {nxv8s64, p0, nxv8s64, 64}});
450 StoreActions.legalForTypesWithMemDesc({{nxv1s64, p0, nxv1s64, 64},
451 {nxv2s64, p0, nxv2s64, 64},
452 {nxv4s64, p0, nxv4s64, 64},
453 {nxv8s64, p0, nxv8s64, 64}});
454 }
455
456 // we will take the custom lowering logic if we have scalable vector types
457 // with non-standard alignments
458 LoadActions.customIf(typeIsLegalIntOrFPVec(0, IntOrFPVecTys, ST));
459 StoreActions.customIf(typeIsLegalIntOrFPVec(0, IntOrFPVecTys, ST));
460
461 // Pointers require that XLen sized elements are legal.
462 if (XLen <= ST.getELen()) {
463 LoadActions.customIf(typeIsLegalPtrVec(0, PtrVecTys, ST));
464 StoreActions.customIf(typeIsLegalPtrVec(0, PtrVecTys, ST));
465 }
466 }
467
468 LoadActions.widenScalarToNextPow2(0, /* MinSize = */ 8)
469 .lowerIfMemSizeNotByteSizePow2()
470 .clampScalar(0, s16, sXLen)
471 .lower();
472 StoreActions
473 .clampScalar(0, s16, sXLen)
474 .lowerIfMemSizeNotByteSizePow2()
475 .lower();
476
477 ExtLoadActions.widenScalarToNextPow2(0).clampScalar(0, sXLen, sXLen).lower();
478
479 getActionDefinitionsBuilder({G_PTR_ADD, G_PTRMASK}).legalFor({{p0, sXLen}});
480
481 getActionDefinitionsBuilder(G_PTRTOINT)
482 .legalFor({{sXLen, p0}})
483 .clampScalar(0, sXLen, sXLen);
484
485 getActionDefinitionsBuilder(G_INTTOPTR)
486 .legalFor({{p0, sXLen}})
487 .clampScalar(1, sXLen, sXLen);
488
489 getActionDefinitionsBuilder(G_BR).alwaysLegal();
490
491 getActionDefinitionsBuilder(G_BRCOND).legalFor({sXLen}).minScalar(0, sXLen);
492
493 getActionDefinitionsBuilder(G_BRJT).customFor({{p0, sXLen}});
494
495 getActionDefinitionsBuilder(G_BRINDIRECT).legalFor({p0});
496
497 getActionDefinitionsBuilder(G_PHI)
498 .legalFor({p0, s32, sXLen})
499 .widenScalarToNextPow2(0)
500 .clampScalar(0, s32, sXLen);
501
502 getActionDefinitionsBuilder({G_GLOBAL_VALUE, G_JUMP_TABLE, G_CONSTANT_POOL})
503 .legalFor({p0});
504
505 if (ST.hasStdExtZmmul()) {
506 getActionDefinitionsBuilder(G_MUL)
507 .legalFor({sXLen})
508 .widenScalarToNextPow2(0)
509 .clampScalar(0, sXLen, sXLen);
510
511 // clang-format off
512 getActionDefinitionsBuilder({G_SMULH, G_UMULH})
513 .legalFor({sXLen})
514 .lower();
515 // clang-format on
516
517 getActionDefinitionsBuilder({G_SMULO, G_UMULO}).minScalar(0, sXLen).lower();
518 } else {
519 getActionDefinitionsBuilder(G_MUL)
520 .libcallFor({sXLen, sDoubleXLen})
521 .widenScalarToNextPow2(0)
522 .clampScalar(0, sXLen, sDoubleXLen);
523
524 getActionDefinitionsBuilder({G_SMULH, G_UMULH}).lowerFor({sXLen});
525
526 getActionDefinitionsBuilder({G_SMULO, G_UMULO})
527 .minScalar(0, sXLen)
528 // Widen sXLen to sDoubleXLen so we can use a single libcall to get
529 // the low bits for the mul result and high bits to do the overflow
530 // check.
531 .widenScalarIf(typeIs(0, sXLen),
532 LegalizeMutations::changeTo(0, sDoubleXLen))
533 .lower();
534 }
535
536 if (ST.hasStdExtM()) {
537 getActionDefinitionsBuilder({G_SDIV, G_UDIV, G_UREM})
538 .legalFor({sXLen})
539 .customFor({s32})
540 .libcallFor({sDoubleXLen})
541 .clampScalar(0, s32, sDoubleXLen)
542 .widenScalarToNextPow2(0);
543 getActionDefinitionsBuilder(G_SREM)
544 .legalFor({sXLen})
545 .libcallFor({sDoubleXLen})
546 .clampScalar(0, sXLen, sDoubleXLen)
547 .widenScalarToNextPow2(0);
548 } else {
549 getActionDefinitionsBuilder({G_UDIV, G_SDIV, G_UREM, G_SREM})
550 .libcallFor({sXLen, sDoubleXLen})
551 .clampScalar(0, sXLen, sDoubleXLen)
552 .widenScalarToNextPow2(0);
553 }
554
555 // TODO: Use libcall for sDoubleXLen.
556 getActionDefinitionsBuilder({G_SDIVREM, G_UDIVREM}).lower();
557
558 getActionDefinitionsBuilder(G_ABS)
559 .customFor(ST.hasStdExtZbb(), {sXLen})
560 .minScalar(ST.hasStdExtZbb(), 0, sXLen)
561 .lower();
562
563 getActionDefinitionsBuilder({G_ABDS, G_ABDU})
564 .minScalar(ST.hasStdExtZbb(), 0, sXLen)
565 .lower();
566
567 getActionDefinitionsBuilder({G_UMAX, G_UMIN, G_SMAX, G_SMIN})
568 .legalFor(ST.hasStdExtZbb(), {sXLen})
569 .minScalar(ST.hasStdExtZbb(), 0, sXLen)
570 .lower();
571
572 getActionDefinitionsBuilder({G_SCMP, G_UCMP}).lower();
573
574 getActionDefinitionsBuilder(G_FRAME_INDEX).legalFor({p0});
575
576 getActionDefinitionsBuilder({G_MEMCPY, G_MEMMOVE, G_MEMSET}).libcall();
577
578 getActionDefinitionsBuilder({G_MEMCPY_INLINE, G_MEMSET_INLINE}).lower();
579
580 getActionDefinitionsBuilder({G_DYN_STACKALLOC, G_STACKSAVE, G_STACKRESTORE})
581 .lower();
582
583 // On RV64 the 64-bit counter CSRs (cycle/time) are read directly. On RV32
584 // they are custom-legally lowered to a re-read-the-high-half loop (see
585 // legalizeReadCounter).
586 getActionDefinitionsBuilder({G_READCYCLECOUNTER, G_READSTEADYCOUNTER})
587 .legalFor(ST.is64Bit(), {s64})
588 .customFor(!ST.is64Bit(), {s64});
589
590 // FP Operations
591
592 // FIXME: Support s128 for rv32 when libcall handling is able to use sret.
593 getActionDefinitionsBuilder({G_FADD, G_FSUB, G_FMUL, G_FDIV, G_FMA, G_FSQRT,
594 G_FMAXNUM, G_FMINNUM, G_FMAXIMUMNUM,
595 G_FMINIMUMNUM})
596 .legalFor(ST.hasStdExtF(), {s32})
597 .legalFor(ST.hasStdExtD(), {s64})
598 .legalFor(ST.hasStdExtZfh(), {s16})
599 .libcallFor({s32, s64})
600 .libcallFor(ST.is64Bit(), {s128});
601
602 getActionDefinitionsBuilder({G_FNEG, G_FABS})
603 .legalFor(ST.hasStdExtF(), {s32})
604 .legalFor(ST.hasStdExtD(), {s64})
605 .legalFor(ST.hasStdExtZfh(), {s16})
606 .lowerFor({s32, s64, s128});
607
608 getActionDefinitionsBuilder(G_FREM)
609 .libcallFor({s32, s64})
610 .libcallFor(ST.is64Bit(), {s128})
611 .minScalar(0, s32)
612 .scalarize(0);
613
614 getActionDefinitionsBuilder(G_FCOPYSIGN)
615 .legalFor(ST.hasStdExtF(), {{s32, s32}})
616 .legalFor(ST.hasStdExtD(), {{s64, s64}, {s32, s64}, {s64, s32}})
617 .legalFor(ST.hasStdExtZfh(), {{s16, s16}, {s16, s32}, {s32, s16}})
618 .legalFor(ST.hasStdExtZfh() && ST.hasStdExtD(), {{s16, s64}, {s64, s16}})
619 .lower();
620
621 getActionDefinitionsBuilder(G_FPTRUNC)
622 .legalFor(ST.hasStdExtD(), {{s32, s64}})
623 .legalFor(ST.hasStdExtZfhmin(), {{s16, s32}})
624 .legalFor(ST.hasStdExtZfhmin() && ST.hasStdExtD(), {{s16, s64}})
625 .libcallFor({{s16, s32}, {s16, s64}, {s32, s64}})
626 .libcallFor(ST.is64Bit(), {{s32, s128}, {s64, s128}});
627 getActionDefinitionsBuilder(G_FPEXT)
628 .legalFor(ST.hasStdExtD(), {{s64, s32}})
629 .legalFor(ST.hasStdExtZfhmin(), {{s32, s16}})
630 .legalFor(ST.hasStdExtZfhmin() && ST.hasStdExtD(), {{s64, s16}})
631 .libcallFor(!ST.hasStdExtZfhmin(), {{s32, s16}})
632 .libcallFor(!(ST.hasStdExtZfhmin() && ST.hasStdExtD()), {{s64, s16}})
633 .libcallFor({{s64, s32}})
634 .libcallFor(ST.is64Bit(), {{s128, s32}, {s128, s64}});
635
636 getActionDefinitionsBuilder(G_FCMP)
637 .legalFor(ST.hasStdExtF(), {{sXLen, s32}})
638 .legalFor(ST.hasStdExtD(), {{sXLen, s64}})
639 .legalFor(ST.hasStdExtZfh(), {{sXLen, s16}})
640 .clampScalar(0, sXLen, sXLen)
641 .minScalar(1, s32)
642 .libcallFor({{sXLen, s32}, {sXLen, s64}})
643 .libcallFor(ST.is64Bit(), {{sXLen, s128}});
644
645 // TODO: Support vector version of G_IS_FPCLASS.
646 getActionDefinitionsBuilder(G_IS_FPCLASS)
647 .customFor(ST.hasStdExtF(), {{s1, s32}})
648 .customFor(ST.hasStdExtD(), {{s1, s64}})
649 .customFor(ST.hasStdExtZfh(), {{s1, s16}})
650 .lower();
651
652 getActionDefinitionsBuilder(G_FCONSTANT)
653 .legalFor(ST.hasStdExtF(), {s32})
654 .legalFor(ST.hasStdExtD(), {s64})
655 .legalFor(ST.hasStdExtZfhmin(), {s16})
656 .lowerFor({s32, s64, s128});
657
658 getActionDefinitionsBuilder({G_FPTOSI, G_FPTOUI})
659 .legalFor(ST.hasStdExtF(), {{sXLen, s32}})
660 .legalFor(ST.hasStdExtD(), {{sXLen, s64}})
661 .legalFor(ST.hasStdExtZfh(), {{sXLen, s16}})
662 .customFor(ST.is64Bit() && ST.hasStdExtF(), {{s32, s32}})
663 .customFor(ST.is64Bit() && ST.hasStdExtD(), {{s32, s64}})
664 .customFor(ST.is64Bit() && ST.hasStdExtZfh(), {{s32, s16}})
665 .widenScalarToNextPow2(0)
666 .minScalar(0, s32)
667 // The magnitude of a half is at most 65504, so with Zfh use fcvt.w[u].h
668 // and extend the i32 result. Otherwise promote the half source to float
669 // (via fcvt.s.h with Zfhmin, __extendhfsf2 without) and use the float
670 // conversion. On RV32, exclude i64 results here so that they get
671 // narrowed to i32 first.
672 .widenScalarIf(
673 [=, &ST](const LegalityQuery &Query) {
674 return Query.Types[1] == f16 && !ST.hasStdExtZfh() &&
675 (ST.is64Bit() || Query.Types[0] == s32);
676 },
677 changeTo(1, s32))
678 .libcallFor(!ST.hasStdExtZfhmin(), {{s64, f16}})
679 .narrowScalarFor({{s64, f16}}, changeTo(0, s32))
680 .libcallFor({{s32, s32}, {s64, s32}, {s32, s64}, {s64, s64}})
681 .libcallFor(ST.is64Bit(), {{s32, s128}, {s64, s128}}) // FIXME RV32.
682 .libcallFor(ST.is64Bit(), {{s128, s32}, {s128, s64}, {s128, s128}});
683
684 // Unlike G_FPTOSI/G_FPTOUI these need no libcalls for out-of-range values:
685 // the RISC-V conversions already saturate. There is no legalFor() because
686 // they do not produce 0 for NaN, which legalizeCustom fixes up with a
687 // compare and a select. The remaining cases fall back to the generic
688 // lowering, which clamps before converting and only handles scalars.
689 getActionDefinitionsBuilder({G_FPTOSI_SAT, G_FPTOUI_SAT})
690 .customFor(ST.hasStdExtF(), {{sXLen, s32}})
691 .customFor(ST.hasStdExtD(), {{sXLen, s64}})
692 .customFor(ST.hasStdExtZfh(), {{sXLen, s16}})
693 .customFor(ST.is64Bit() && ST.hasStdExtF(), {{s32, s32}})
694 .customFor(ST.is64Bit() && ST.hasStdExtD(), {{s32, s64}})
695 .customFor(ST.is64Bit() && ST.hasStdExtZfh(), {{s32, s16}})
696 // f16 extends exactly to f32; converting via f32 avoids needing rules
697 // for every {sXX, s16} combination.
698 .widenScalarIf(typeIs(1, s16), changeTo(1, s32))
699 .lowerIf(all(isScalar(0), isScalar(1)));
700
701 getActionDefinitionsBuilder({G_LROUND, G_LLROUND})
702 .legalFor(ST.hasStdExtF(), {{sXLen, s32}})
703 .legalFor(ST.hasStdExtD(), {{sXLen, s64}})
704 .legalFor(ST.hasStdExtZfh(), {{sXLen, s16}})
705 .customFor(ST.is64Bit() && ST.hasStdExtF(), {{s32, s32}})
706 .customFor(ST.is64Bit() && ST.hasStdExtD(), {{s32, s64}})
707 .customFor(ST.is64Bit() && ST.hasStdExtZfh(), {{s32, s16}})
708 .minScalar(1, s32)
709 .libcallFor({{s32, s32},
710 {s64, s32},
711 {s32, s64},
712 {s64, s64},
713 {s32, s128},
714 {s64, s128}});
715
716 getActionDefinitionsBuilder({G_INTRINSIC_LRINT, G_INTRINSIC_LLRINT})
717 .legalFor(ST.hasStdExtF(), {{sXLen, s32}})
718 .legalFor(ST.hasStdExtD(), {{sXLen, s64}})
719 .legalFor(ST.hasStdExtZfh(), {{sXLen, s16}})
720 .minScalar(0, sXLen)
721 .minScalar(1, s32)
722 .libcallFor({{s32, s32},
723 {s64, s32},
724 {s32, s64},
725 {s64, s64},
726 {s32, s128},
727 {s64, s128}});
728
729 getActionDefinitionsBuilder({G_SITOFP, G_UITOFP})
730 .legalFor(ST.hasStdExtF(), {{s32, sXLen}})
731 .legalFor(ST.hasStdExtD(), {{s64, sXLen}})
732 .legalFor(ST.hasStdExtZfh(), {{s16, sXLen}})
733 .widenScalarToNextPow2(1)
734 // Promote to XLen if the operation is legal.
735 .widenScalarIf(
736 [=, &ST](const LegalityQuery &Query) {
737 return Query.Types[0].isScalar() && Query.Types[1].isScalar() &&
738 (Query.Types[1].getSizeInBits() < ST.getXLen()) &&
739 ((ST.hasStdExtF() && Query.Types[0].getSizeInBits() == 32) ||
740 (ST.hasStdExtD() && Query.Types[0].getSizeInBits() == 64) ||
741 (ST.hasStdExtZfh() &&
742 Query.Types[0].getSizeInBits() == 16));
743 },
745 // Otherwise only promote to s32 since we have si libcalls.
746 .minScalar(1, s32)
747 .libcallFor({{s32, s32}, {s64, s32}, {s32, s64}, {s64, s64}})
748 .libcallFor(ST.is64Bit(), {{s128, s32}, {s128, s64}}) // FIXME RV32.
749 .libcallFor(ST.is64Bit(), {{s32, s128}, {s64, s128}, {s128, s128}});
750
751 // FIXME: We can do custom inline expansion like SelectionDAG.
752 getActionDefinitionsBuilder({G_FCEIL, G_FFLOOR, G_FRINT, G_FNEARBYINT,
753 G_INTRINSIC_TRUNC, G_INTRINSIC_ROUND,
754 G_INTRINSIC_ROUNDEVEN})
755 .legalFor(ST.hasStdExtZfa(), {s32})
756 .legalFor(ST.hasStdExtZfa() && ST.hasStdExtD(), {s64})
757 .legalFor(ST.hasStdExtZfa() && ST.hasStdExtZfh(), {s16})
758 .libcallFor({s32, s64})
759 .libcallFor(ST.is64Bit(), {s128});
760
761 getActionDefinitionsBuilder({G_FMAXIMUM, G_FMINIMUM})
762 .legalFor(ST.hasStdExtZfa(), {s32})
763 .legalFor(ST.hasStdExtZfa() && ST.hasStdExtD(), {s64})
764 .legalFor(ST.hasStdExtZfa() && ST.hasStdExtZfh(), {s16});
765
766 getActionDefinitionsBuilder({G_FCOS, G_FSIN, G_FTAN, G_FPOW, G_FLOG, G_FLOG2,
767 G_FLOG10, G_FEXP, G_FEXP2, G_FEXP10, G_FACOS,
768 G_FASIN, G_FATAN, G_FATAN2, G_FCOSH, G_FSINH,
769 G_FTANH, G_FMODF, G_FSINCOS})
770 .libcallFor({s32, s64})
771 .libcallFor(ST.is64Bit(), {s128});
772 getActionDefinitionsBuilder({G_FPOWI, G_FLDEXP})
773 .libcallFor({{s32, s32}, {s64, s32}})
774 .libcallFor(ST.is64Bit(), {s128, s32});
775
776 getActionDefinitionsBuilder(G_FCANONICALIZE)
777 .legalFor(ST.hasStdExtF(), {s32})
778 .legalFor(ST.hasStdExtD(), {s64})
779 .legalFor(ST.hasStdExtZfh(), {s16});
780
781 getActionDefinitionsBuilder(G_VASTART).customFor({p0});
782
783 // va_list must be a pointer, but most sized types are pretty easy to handle
784 // as the destination.
785 getActionDefinitionsBuilder(G_VAARG)
786 // TODO: Implement narrowScalar and widenScalar for G_VAARG for types
787 // other than sXLen.
788 .clampScalar(0, sXLen, sXLen)
789 .lowerForCartesianProduct({sXLen, p0}, {p0});
790
791 getActionDefinitionsBuilder(G_VSCALE)
792 .clampScalar(0, sXLen, sXLen)
793 .customFor({sXLen});
794
795 auto &SplatActions =
796 getActionDefinitionsBuilder(G_SPLAT_VECTOR)
797 .legalIf(all(typeIsLegalIntOrFPVec(0, IntOrFPVecTys, ST),
798 typeIs(1, sXLen)))
799 .customIf(all(typeIsLegalBoolVec(0, BoolVecTys, ST), typeIs(1, s1)));
800 // Handle case of s64 element vectors on RV32. If the subtarget does not have
801 // f64, then try to lower it to G_SPLAT_VECTOR_SPLIT_64_VL. If the subtarget
802 // does have f64, then we don't know whether the type is an f64 or an i64,
803 // so mark the G_SPLAT_VECTOR as legal and decide later what to do with it,
804 // depending on how the instructions it consumes are legalized. They are not
805 // legalized yet since legalization is in reverse postorder, so we cannot
806 // make the decision at this moment.
807 if (XLen == 32) {
808 if (ST.hasVInstructionsF64() && ST.hasStdExtD())
809 SplatActions.legalIf(all(
810 typeInSet(0, {nxv1s64, nxv2s64, nxv4s64, nxv8s64}), typeIs(1, s64)));
811 else if (ST.hasVInstructionsI64())
812 SplatActions.customIf(all(
813 typeInSet(0, {nxv1s64, nxv2s64, nxv4s64, nxv8s64}), typeIs(1, s64)));
814 }
815
816 SplatActions.clampScalar(1, sXLen, sXLen);
817
818 LegalityPredicate ExtractSubvecBitcastPred = [=](const LegalityQuery &Query) {
819 LLT DstTy = Query.Types[0];
820 LLT SrcTy = Query.Types[1];
821 return DstTy.getElementType() == LLT::scalar(1) &&
822 DstTy.getElementCount().getKnownMinValue() >= 8 &&
823 SrcTy.getElementCount().getKnownMinValue() >= 8;
824 };
825 getActionDefinitionsBuilder(G_EXTRACT_SUBVECTOR)
826 // We don't have the ability to slide mask vectors down indexed by their
827 // i1 elements; the smallest we can do is i8. Often we are able to bitcast
828 // to equivalent i8 vectors.
829 .bitcastIf(
830 all(typeIsLegalBoolVec(0, BoolVecTys, ST),
831 typeIsLegalBoolVec(1, BoolVecTys, ST), ExtractSubvecBitcastPred),
832 [=](const LegalityQuery &Query) {
833 LLT CastTy = LLT::vector(
834 Query.Types[0].getElementCount().divideCoefficientBy(8), 8);
835 return std::pair(0, CastTy);
836 })
837 .customIf(LegalityPredicates::any(
838 all(typeIsLegalBoolVec(0, BoolVecTys, ST),
839 typeIsLegalBoolVec(1, BoolVecTys, ST)),
840 all(typeIsLegalIntOrFPVec(0, IntOrFPVecTys, ST),
841 typeIsLegalIntOrFPVec(1, IntOrFPVecTys, ST))));
842
843 getActionDefinitionsBuilder(G_INSERT_SUBVECTOR)
844 .customIf(all(typeIsLegalBoolVec(0, BoolVecTys, ST),
845 typeIsLegalBoolVec(1, BoolVecTys, ST)))
846 .customIf(all(typeIsLegalIntOrFPVec(0, IntOrFPVecTys, ST),
847 typeIsLegalIntOrFPVec(1, IntOrFPVecTys, ST)));
848
849 getActionDefinitionsBuilder(G_ATOMIC_CMPXCHG_WITH_SUCCESS)
850 .lowerIf(all(typeInSet(0, {s8, s16, s32, s64}), typeIs(2, p0)));
851
852 getActionDefinitionsBuilder({G_ATOMIC_CMPXCHG, G_ATOMICRMW_ADD,
853 G_ATOMICRMW_XCHG, G_ATOMICRMW_AND,
854 G_ATOMICRMW_OR, G_ATOMICRMW_XOR})
855 .legalFor(ST.hasStdExtA(), {{sXLen, p0}})
856 .libcallFor(!ST.hasStdExtA(), {{s8, p0}, {s16, p0}, {s32, p0}, {s64, p0}})
857 .clampScalar(0, sXLen, sXLen);
858
859 getActionDefinitionsBuilder(G_ATOMICRMW_SUB)
860 .libcallFor(!ST.hasStdExtA(), {{s8, p0}, {s16, p0}, {s32, p0}, {s64, p0}})
861 .clampScalar(0, sXLen, sXLen)
862 .lower();
863
864 getActionDefinitionsBuilder(
865 {G_ATOMICRMW_MAX, G_ATOMICRMW_MIN, G_ATOMICRMW_UMAX, G_ATOMICRMW_UMIN})
866 .legalFor(ST.hasStdExtA(), {{sXLen, p0}})
867 .clampScalar(0, sXLen, sXLen)
868 .unsupported();
869
870 getActionDefinitionsBuilder(G_PREFETCH).legalIf(typeIs(0, p0));
871
872 LegalityPredicate InsertVectorEltPred = [=](const LegalityQuery &Query) {
873 LLT VecTy = Query.Types[0];
874 LLT EltTy = Query.Types[1];
875 return VecTy.getElementType() == EltTy;
876 };
877
878 getActionDefinitionsBuilder(G_INSERT_VECTOR_ELT)
879 .legalIf(all(typeIsLegalIntOrFPVec(0, IntOrFPVecTys, ST),
880 InsertVectorEltPred, typeIs(2, sXLen)))
881 .legalIf(all(typeIsLegalBoolVec(0, BoolVecTys, ST), InsertVectorEltPred,
882 typeIs(2, sXLen)));
883
884 getActionDefinitionsBuilder({G_INTRINSIC, G_INTRINSIC_W_SIDE_EFFECTS})
885 .alwaysLegal();
886
887 getActionDefinitionsBuilder(G_FENCE).alwaysLegal();
888
889 getActionDefinitionsBuilder({G_TRAP, G_DEBUGTRAP, G_UBSANTRAP}).alwaysLegal();
890
891 verify(*ST.getInstrInfo());
892}
893
895 MachineInstr &MI) const {
896 Intrinsic::ID IntrinsicID = cast<GIntrinsic>(MI).getIntrinsicID();
897
899 RISCVVIntrinsicsTable::getRISCVVIntrinsicInfo(IntrinsicID)) {
900 if (II->hasScalarOperand() && !II->IsFPIntrinsic) {
901 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
902 MachineRegisterInfo &MRI = *MIRBuilder.getMRI();
903
904 auto OldScalar = MI.getOperand(II->ScalarOperand + 2).getReg();
905 // Legalize integer vx form intrinsic.
906 if (MRI.getType(OldScalar).isScalar()) {
907 if (MRI.getType(OldScalar).getSizeInBits() < sXLen.getSizeInBits()) {
908 Helper.Observer.changingInstr(MI);
909 Helper.widenScalarSrc(MI, sXLen, II->ScalarOperand + 2,
910 TargetOpcode::G_ANYEXT);
911 Helper.Observer.changedInstr(MI);
912 } else if (MRI.getType(OldScalar).getSizeInBits() >
913 sXLen.getSizeInBits()) {
914 // TODO: i64 in riscv32.
915 return false;
916 }
917 }
918 }
919 return true;
920 }
921
922 switch (IntrinsicID) {
923 default:
924 return false;
925 case Intrinsic::riscv_orc_b: {
926 if (!STI.hasStdExtZbb())
927 return false;
928
929 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
930 MachineRegisterInfo &MRI = *MIRBuilder.getMRI();
931 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
932 if (Ty == sXLen)
933 return true;
934 if (!STI.is64Bit() || Ty != LLT::scalar(32))
935 return false;
936
937 // Each output byte depends only on the corresponding input byte.
938 auto Src = MIRBuilder.buildAnyExt(sXLen, MI.getOperand(2));
939 auto Result = MIRBuilder.buildIntrinsic(IntrinsicID, {DstOp(sXLen)})
940 .addUse(Src.getReg(0));
941 MIRBuilder.buildTrunc(MI.getOperand(0), Result);
942 MI.eraseFromParent();
943 return true;
944 }
945 case Intrinsic::riscv_clmulh:
946 Helper.MIRBuilder.buildInstr(TargetOpcode::G_CLMULH, {MI.getOperand(0)},
947 {MI.getOperand(2), MI.getOperand(3)});
948 MI.eraseFromParent();
949 return true;
950 case Intrinsic::riscv_clmulr:
951 Helper.MIRBuilder.buildInstr(TargetOpcode::G_CLMULR, {MI.getOperand(0)},
952 {MI.getOperand(2), MI.getOperand(3)});
953 MI.eraseFromParent();
954 return true;
955 case Intrinsic::vacopy: {
956 // vacopy arguments must be legal because of the intrinsic signature.
957 // No need to check here.
958
959 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
960 MachineRegisterInfo &MRI = *MIRBuilder.getMRI();
961 MachineFunction &MF = *MI.getMF();
962 const DataLayout &DL = MIRBuilder.getDataLayout();
963 LLVMContext &Ctx = MF.getFunction().getContext();
964
965 Register DstLst = MI.getOperand(1).getReg();
966 LLT PtrTy = MRI.getType(DstLst);
967
968 // Load the source va_list
969 Align Alignment = DL.getABITypeAlign(getTypeForLLT(PtrTy, Ctx));
971 MachinePointerInfo(), MachineMemOperand::MOLoad, PtrTy, Alignment);
972 auto Tmp = MIRBuilder.buildLoad(PtrTy, MI.getOperand(2), *LoadMMO);
973
974 // Store the result in the destination va_list
977 MIRBuilder.buildStore(Tmp, DstLst, *StoreMMO);
978
979 MI.eraseFromParent();
980 return true;
981 }
982 case Intrinsic::riscv_vsetvli:
983 case Intrinsic::riscv_vsetvlimax:
984 case Intrinsic::riscv_masked_atomicrmw_add:
985 case Intrinsic::riscv_masked_atomicrmw_sub:
986 case Intrinsic::riscv_masked_atomicrmw_xchg:
987 case Intrinsic::riscv_masked_atomicrmw_max:
988 case Intrinsic::riscv_masked_atomicrmw_min:
989 case Intrinsic::riscv_masked_atomicrmw_umax:
990 case Intrinsic::riscv_masked_atomicrmw_umin:
991 case Intrinsic::riscv_masked_cmpxchg:
992 return true;
993 }
994}
995
996bool RISCVLegalizerInfo::legalizeVAStart(MachineInstr &MI,
997 MachineIRBuilder &MIRBuilder) const {
998 // Stores the address of the VarArgsFrameIndex slot into the memory location
999 assert(MI.getOpcode() == TargetOpcode::G_VASTART);
1000 MachineFunction *MF = MI.getParent()->getParent();
1002 int FI = FuncInfo->getVarArgsFrameIndex();
1003 LLT AddrTy = MIRBuilder.getMRI()->getType(MI.getOperand(0).getReg());
1004 auto FINAddr = MIRBuilder.buildFrameIndex(AddrTy, FI);
1005 assert(MI.hasOneMemOperand());
1006 MIRBuilder.buildStore(FINAddr, MI.getOperand(0).getReg(),
1007 *MI.memoperands()[0]);
1008 MI.eraseFromParent();
1009 return true;
1010}
1011
1012bool RISCVLegalizerInfo::legalizeReadCounter(
1013 MachineInstr &MI, MachineIRBuilder &MIRBuilder,
1014 GISelChangeObserver &Observer) const {
1015 assert((MI.getOpcode() == TargetOpcode::G_READCYCLECOUNTER ||
1016 MI.getOpcode() == TargetOpcode::G_READSTEADYCOUNTER) &&
1017 "Unexpected opcode");
1018 assert(!STI.is64Bit() && "READCYCLECOUNTER/READSTEADYCOUNTER only "
1019 "has custom type legalization on riscv32");
1020
1021 // On RV32 a 64-bit counter CSR must be read as two 32-bit halves. Because
1022 // the count may wrap between the two reads, re-read the high half and loop
1023 // until the two high reads agree.
1024 int64_t LoCounter, HiCounter;
1025 if (MI.getOpcode() == TargetOpcode::G_READCYCLECOUNTER) {
1026 LoCounter = RISCVSysReg::cycle;
1027 HiCounter = RISCVSysReg::cycleh;
1028 } else {
1029 LoCounter = RISCVSysReg::time;
1030 HiCounter = RISCVSysReg::timeh;
1031 }
1032
1033 MachineBasicBlock *BB = MI.getParent();
1034 MachineFunction &MF = *BB->getParent();
1035 const BasicBlock *LLVMBB = BB->getBasicBlock();
1036 DebugLoc DL = MI.getDebugLoc();
1037 MachineRegisterInfo &MRI = *MIRBuilder.getMRI();
1038
1039 // Split BB into an entry that falls through into a loop block, and a done
1040 // block that receives the remainder of BB and its original successors.
1041 MachineFunction::iterator It = std::next(BB->getIterator());
1042 MachineBasicBlock *LoopMBB = MF.CreateMachineBasicBlock(LLVMBB);
1043 MachineBasicBlock *DoneMBB = MF.CreateMachineBasicBlock(LLVMBB);
1044 MF.insert(It, LoopMBB);
1045 MF.insert(It, DoneMBB);
1046
1047 // Splice the instructions after the readcyclecounter into DoneMBB, notifying
1048 // the observer about each moved instruction so CSEInfo stays consistent.
1049 for (MachineBasicBlock::iterator I = std::next(MI.getIterator()),
1050 E = BB->end();
1051 I != E; ++I)
1052 Observer.changingInstr(*I);
1053 DoneMBB->splice(DoneMBB->begin(), BB,
1054 std::next(MachineBasicBlock::iterator(MI)), BB->end());
1055 for (MachineInstr &MovedMI : DoneMBB->instrs())
1056 Observer.changedInstr(MovedMI);
1058 BB->addSuccessor(LoopMBB);
1059
1060 LLT S32 = LLT::scalar(32);
1061 // Generic vregs carry the s32 type for G_MERGE_VALUES below, but are also
1062 // constrained to GPR so the target CSRRS/BNE instructions satisfy the
1063 // verifier's register-class constraints.
1064 auto CreateGPR = [&]() {
1066 MRI.setRegClass(R, &RISCV::GPRRegClass);
1067 return R;
1068 };
1069 Register LoReg = CreateGPR();
1070 Register HiReg = CreateGPR();
1071 Register ReadAgainReg = CreateGPR();
1072
1073 // read:
1074 // csrrs HiReg, counterh # high word
1075 // csrrs LoReg, counter # low word
1076 // csrrs ReadAgainReg, counterh
1077 // bne HiReg, ReadAgainReg, read
1078 // Emit the target instructions directly with BuildMI.
1079 const RISCVInstrInfo *TII = STI.getInstrInfo();
1080 BuildMI(LoopMBB, DL, TII->get(RISCV::CSRRS), HiReg)
1081 .addImm(HiCounter)
1082 .addReg(RISCV::X0);
1083 BuildMI(LoopMBB, DL, TII->get(RISCV::CSRRS), LoReg)
1084 .addImm(LoCounter)
1085 .addReg(RISCV::X0);
1086 BuildMI(LoopMBB, DL, TII->get(RISCV::CSRRS), ReadAgainReg)
1087 .addImm(HiCounter)
1088 .addReg(RISCV::X0);
1089
1090 BuildMI(LoopMBB, DL, TII->get(RISCV::BNE))
1091 .addReg(HiReg)
1092 .addReg(ReadAgainReg)
1093 .addMBB(LoopMBB);
1094
1095 LoopMBB->addSuccessor(LoopMBB);
1096 LoopMBB->addSuccessor(DoneMBB);
1097
1098 // Re-pair the two halves into the 64-bit result.
1099 Register DstReg = MI.getOperand(0).getReg();
1100 Observer.erasingInstr(MI);
1101 MI.eraseFromParent();
1102
1103 MIRBuilder.setInsertPt(*DoneMBB, DoneMBB->begin());
1104 MIRBuilder.setDebugLoc(DL);
1105 MIRBuilder.buildMergeValues(DstReg, {LoReg, HiReg});
1106 return true;
1107}
1108
1109bool RISCVLegalizerInfo::legalizeBRJT(MachineInstr &MI,
1110 MachineIRBuilder &MIRBuilder) const {
1111 MachineRegisterInfo &MRI = *MIRBuilder.getMRI();
1112 auto &MF = *MI.getParent()->getParent();
1113 const MachineJumpTableInfo *MJTI = MF.getJumpTableInfo();
1114 unsigned EntrySize = MJTI->getEntrySize(MF.getDataLayout());
1115
1116 Register PtrReg = MI.getOperand(0).getReg();
1117 LLT PtrTy = MRI.getType(PtrReg);
1118 Register IndexReg = MI.getOperand(2).getReg();
1119 LLT IndexTy = MRI.getType(IndexReg);
1120
1121 if (!isPowerOf2_32(EntrySize))
1122 return false;
1123
1124 auto ShiftAmt = MIRBuilder.buildConstant(IndexTy, Log2_32(EntrySize));
1125 IndexReg = MIRBuilder.buildShl(IndexTy, IndexReg, ShiftAmt).getReg(0);
1126
1127 auto Addr = MIRBuilder.buildPtrAdd(PtrTy, PtrReg, IndexReg);
1128
1129 MachineMemOperand *MMO = MF.getMachineMemOperand(
1131 EntrySize, Align(MJTI->getEntryAlignment(MF.getDataLayout())));
1132
1133 Register TargetReg;
1134 switch (MJTI->getEntryKind()) {
1135 default:
1136 return false;
1138 // For PIC, the sequence is:
1139 // BRIND(load(Jumptable + index) + RelocBase)
1140 // RelocBase can be JumpTable, GOT or some sort of global base.
1141 unsigned LoadOpc =
1142 STI.is64Bit() ? TargetOpcode::G_SEXTLOAD : TargetOpcode::G_LOAD;
1143 auto Load = MIRBuilder.buildLoadInstr(LoadOpc, IndexTy, Addr, *MMO);
1144 TargetReg = MIRBuilder.buildPtrAdd(PtrTy, PtrReg, Load).getReg(0);
1145 break;
1146 }
1148 auto Load = MIRBuilder.buildLoadInstr(TargetOpcode::G_SEXTLOAD, IndexTy,
1149 Addr, *MMO);
1150 TargetReg = MIRBuilder.buildIntToPtr(PtrTy, Load).getReg(0);
1151 break;
1152 }
1154 TargetReg = MIRBuilder.buildLoad(PtrTy, Addr, *MMO).getReg(0);
1155 break;
1156 }
1157
1158 if (MF.getInfo<RISCVMachineFunctionInfo>()->hasCFProtectionBranch()) {
1159 // When cf-protection-branch is enabled, we need to use a software
1160 // guarded branch for jump table branch.
1161 MIRBuilder.buildInstr(RISCV::G_SW_GUARDED_BRIND, {}, {TargetReg});
1162 } else {
1163 MIRBuilder.buildBrIndirect(TargetReg);
1164 }
1165
1166 MI.eraseFromParent();
1167 return true;
1168}
1169
1170bool RISCVLegalizerInfo::shouldBeInConstantPool(const APInt &APImm,
1171 bool ShouldOptForSize) const {
1172 assert(APImm.getBitWidth() == 32 || APImm.getBitWidth() == 64);
1173 int64_t Imm = APImm.getSExtValue();
1174 // All simm32 constants should be handled by isel.
1175 // NOTE: The getMaxBuildIntsCost call below should return a value >= 2 making
1176 // this check redundant, but small immediates are common so this check
1177 // should have better compile time.
1178 if (isInt<32>(Imm))
1179 return false;
1180
1181 // We only need to cost the immediate, if constant pool lowering is enabled.
1182 if (!STI.useConstantPoolForLargeInts())
1183 return false;
1184
1186 if (Seq.size() <= STI.getMaxBuildIntsCost())
1187 return false;
1188
1189 // Optimizations below are disabled for opt size. If we're optimizing for
1190 // size, use a constant pool.
1191 if (ShouldOptForSize)
1192 return true;
1193 //
1194 // Special case. See if we can build the constant as (ADD (SLLI X, C), X) do
1195 // that if it will avoid a constant pool.
1196 // It will require an extra temporary register though.
1197 // If we have Zba we can use (ADD_UW X, (SLLI X, 32)) to handle cases where
1198 // low and high 32 bits are the same and bit 31 and 63 are set.
1199 unsigned ShiftAmt, AddOpc;
1200 RISCVMatInt::InstSeq SeqLo =
1201 RISCVMatInt::generateTwoRegInstSeq(Imm, STI, ShiftAmt, AddOpc);
1202 return !(!SeqLo.empty() && (SeqLo.size() + 2) <= STI.getMaxBuildIntsCost());
1203}
1204
1205bool RISCVLegalizerInfo::legalizeVScale(MachineInstr &MI,
1206 MachineIRBuilder &MIB) const {
1207 Register Dst = MI.getOperand(0).getReg();
1208
1209 // We define our scalable vector types for lmul=1 to use a 64 bit known
1210 // minimum size. e.g. <vscale x 2 x i32>. VLENB is in bytes so we calculate
1211 // vscale as VLENB / 8.
1212 static_assert(RISCV::RVVBitsPerBlock == 64, "Unexpected bits per block!");
1213 if (STI.getRealMinVLen() < RISCV::RVVBitsPerBlock)
1214 // Support for VLEN==32 is incomplete.
1215 return false;
1216
1217 // We assume VLENB is a multiple of 8. We manually choose the best shift
1218 // here because SimplifyDemandedBits isn't always able to simplify it.
1219 uint64_t Val = MI.getOperand(1).getCImm()->getZExtValue();
1220 if (isPowerOf2_64(Val)) {
1221 uint64_t Log2 = Log2_64(Val);
1222 if (Log2 < 3) {
1223 auto VLENB = MIB.buildInstr(RISCV::G_READ_VLENB, {sXLen}, {});
1224 MIB.buildLShr(Dst, VLENB, MIB.buildConstant(sXLen, 3 - Log2),
1226 } else if (Log2 > 3) {
1227 auto VLENB = MIB.buildInstr(RISCV::G_READ_VLENB, {sXLen}, {});
1228 MIB.buildShl(Dst, VLENB, MIB.buildConstant(sXLen, Log2 - 3));
1229 } else {
1230 MIB.buildInstr(RISCV::G_READ_VLENB, {Dst}, {});
1231 }
1232 } else if ((Val % 8) == 0) {
1233 // If the multiplier is a multiple of 8, scale it down to avoid needing
1234 // to shift the VLENB value.
1235 auto VLENB = MIB.buildInstr(RISCV::G_READ_VLENB, {sXLen}, {});
1236 MIB.buildMul(Dst, VLENB, MIB.buildConstant(sXLen, Val / 8));
1237 } else {
1238 auto VLENB = MIB.buildInstr(RISCV::G_READ_VLENB, {sXLen}, {});
1239 auto VScale = MIB.buildLShr(sXLen, VLENB, MIB.buildConstant(sXLen, 3),
1241 MIB.buildMul(Dst, VScale, MIB.buildConstant(sXLen, Val));
1242 }
1243 MI.eraseFromParent();
1244 return true;
1245}
1246
1247// Custom-lower extensions from mask vectors by using a vselect either with 1
1248// for zero/any-extension or -1 for sign-extension:
1249// (vXiN = (s|z)ext vXi1:vmask) -> (vXiN = vselect vmask, (-1 or 1), 0)
1250// Note that any-extension is lowered identically to zero-extension.
1251bool RISCVLegalizerInfo::legalizeExt(MachineInstr &MI,
1252 MachineIRBuilder &MIB) const {
1253
1254 unsigned Opc = MI.getOpcode();
1255 assert(Opc == TargetOpcode::G_ZEXT || Opc == TargetOpcode::G_SEXT ||
1256 Opc == TargetOpcode::G_ANYEXT);
1257
1258 MachineRegisterInfo &MRI = *MIB.getMRI();
1259 Register Dst = MI.getOperand(0).getReg();
1260 Register Src = MI.getOperand(1).getReg();
1261
1262 LLT DstTy = MRI.getType(Dst);
1263 int64_t ExtTrueVal = Opc == TargetOpcode::G_SEXT ? -1 : 1;
1264 LLT DstEltTy = DstTy.getElementType();
1265 auto SplatZero = MIB.buildSplatVector(DstTy, MIB.buildConstant(DstEltTy, 0));
1266 auto SplatTrue =
1267 MIB.buildSplatVector(DstTy, MIB.buildConstant(DstEltTy, ExtTrueVal));
1268 MIB.buildSelect(Dst, Src, SplatTrue, SplatZero);
1269
1270 MI.eraseFromParent();
1271 return true;
1272}
1273
1274bool RISCVLegalizerInfo::legalizeLoadStore(MachineInstr &MI,
1275 LegalizerHelper &Helper,
1276 MachineIRBuilder &MIB) const {
1278 "Machine instructions must be Load/Store.");
1279 MachineRegisterInfo &MRI = *MIB.getMRI();
1280 MachineFunction *MF = MI.getMF();
1281 const DataLayout &DL = MIB.getDataLayout();
1282 LLVMContext &Ctx = MF->getFunction().getContext();
1283
1284 Register DstReg = MI.getOperand(0).getReg();
1285 LLT DataTy = MRI.getType(DstReg);
1286 if (!DataTy.isVector())
1287 return false;
1288
1289 if (!MI.hasOneMemOperand())
1290 return false;
1291
1292 MachineMemOperand *MMO = *MI.memoperands_begin();
1293
1294 const auto *TLI = STI.getTargetLowering();
1295 EVT VT = EVT::getEVT(getTypeForLLT(DataTy, Ctx));
1296
1297 if (TLI->allowsMemoryAccessForAlignment(Ctx, DL, VT, *MMO))
1298 return true;
1299
1300 unsigned EltSizeBits = DataTy.getScalarSizeInBits();
1301 assert((EltSizeBits == 16 || EltSizeBits == 32 || EltSizeBits == 64) &&
1302 "Unexpected unaligned RVV load type");
1303
1304 // Calculate the new vector type with i8 elements
1305 unsigned NumElements =
1306 DataTy.getElementCount().getKnownMinValue() * (EltSizeBits / 8);
1307 LLT NewDataTy = LLT::scalable_vector(NumElements, 8);
1308
1309 Helper.bitcast(MI, 0, NewDataTy);
1310
1311 return true;
1312}
1313
1314/// Return the type of the mask type suitable for masking the provided
1315/// vector type. This is simply an i1 element type vector of the same
1316/// (possibly scalable) length.
1317static LLT getMaskTypeFor(LLT VecTy) {
1318 assert(VecTy.isVector());
1319 ElementCount EC = VecTy.getElementCount();
1320 return LLT::vector(EC, LLT::scalar(1));
1321}
1322
1323/// Creates an all ones mask suitable for masking a vector of type VecTy with
1324/// vector length VL.
1326 MachineIRBuilder &MIB,
1328 LLT MaskTy = getMaskTypeFor(VecTy);
1329 return MIB.buildInstr(RISCV::G_VMSET_VL, {MaskTy}, {VL});
1330}
1331
1332/// Gets the two common "VL" operands: an all-ones mask and the vector length.
1333/// VecTy is a scalable vector type.
1334static std::pair<MachineInstrBuilder, MachineInstrBuilder>
1336 assert(VecTy.isScalableVector() && "Expecting scalable container type");
1337 const RISCVSubtarget &STI = MIB.getMF().getSubtarget<RISCVSubtarget>();
1338 LLT XLenTy(STI.getXLenVT());
1339 auto VL = MIB.buildConstant(XLenTy, -1);
1340 auto Mask = buildAllOnesMask(VecTy, VL, MIB, MRI);
1341 return {Mask, VL};
1342}
1343
1345buildSplatPartsS64WithVL(const DstOp &Dst, const SrcOp &Passthru, Register Lo,
1346 Register Hi, const SrcOp &VL, MachineIRBuilder &MIB,
1348 // TODO: If the Hi bits of the splat are undefined, then it's fine to just
1349 // splat Lo even if it might be sign extended. I don't think we have
1350 // introduced a case where we're build a s64 where the upper bits are undef
1351 // yet.
1352
1353 // Fall back to a stack store and stride x0 vector load.
1354 // TODO: need to lower G_SPLAT_VECTOR_SPLIT_I64. This is done in
1355 // preprocessDAG in SDAG.
1356 return MIB.buildInstr(RISCV::G_SPLAT_VECTOR_SPLIT_I64_VL, {Dst},
1357 {Passthru, Lo, Hi, VL});
1358}
1359
1361buildSplatSplitS64WithVL(const DstOp &Dst, const SrcOp &Passthru,
1362 const SrcOp &Scalar, const SrcOp &VL,
1364 assert(Scalar.getLLTTy(MRI) == LLT::scalar(64) && "Unexpected VecTy!");
1365 auto Unmerge = MIB.buildUnmerge(LLT::scalar(32), Scalar);
1366 return buildSplatPartsS64WithVL(Dst, Passthru, Unmerge.getReg(0),
1367 Unmerge.getReg(1), VL, MIB, MRI);
1368}
1369
1370// Lower splats of s1 types to G_ICMP. For each mask vector type, we have a
1371// legal equivalently-sized i8 type, so we can use that as a go-between.
1372// Splats of s1 types that have constant value can be legalized as VMSET_VL or
1373// VMCLR_VL.
1374bool RISCVLegalizerInfo::legalizeSplatVector(MachineInstr &MI,
1375 MachineIRBuilder &MIB) const {
1376 assert(MI.getOpcode() == TargetOpcode::G_SPLAT_VECTOR);
1377
1378 MachineRegisterInfo &MRI = *MIB.getMRI();
1379
1380 Register Dst = MI.getOperand(0).getReg();
1381 Register SplatVal = MI.getOperand(1).getReg();
1382
1383 LLT VecTy = MRI.getType(Dst);
1384 LLT XLenTy(STI.getXLenVT());
1385
1386 // Handle case of s64 element vectors on rv32
1387 if (XLenTy.getSizeInBits() == 32 &&
1388 VecTy.getElementType().getSizeInBits() == 64) {
1389 auto [_, VL] = buildDefaultVLOps(MRI.getType(Dst), MIB, MRI);
1390 buildSplatSplitS64WithVL(Dst, MIB.buildUndef(VecTy), SplatVal, VL, MIB,
1391 MRI);
1392 MI.eraseFromParent();
1393 return true;
1394 }
1395
1396 // All-zeros or all-ones splats are handled specially.
1397 MachineInstr &SplatValMI = *MRI.getVRegDef(SplatVal);
1398 if (isAllOnesOrAllOnesSplat(SplatValMI, MRI)) {
1399 auto VL = buildDefaultVLOps(VecTy, MIB, MRI).second;
1400 MIB.buildInstr(RISCV::G_VMSET_VL, {Dst}, {VL});
1401 MI.eraseFromParent();
1402 return true;
1403 }
1404 if (isNullOrNullSplat(SplatValMI, MRI)) {
1405 auto VL = buildDefaultVLOps(VecTy, MIB, MRI).second;
1406 MIB.buildInstr(RISCV::G_VMCLR_VL, {Dst}, {VL});
1407 MI.eraseFromParent();
1408 return true;
1409 }
1410
1411 // Handle non-constant mask splat (i.e. not sure if it's all zeros or all
1412 // ones) by promoting it to an s8 splat.
1413 LLT InterEltTy = LLT::scalar(8);
1414 LLT InterTy = VecTy.changeElementType(InterEltTy);
1415 auto ZExtSplatVal = MIB.buildZExt(InterEltTy, SplatVal);
1416 auto And =
1417 MIB.buildAnd(InterEltTy, ZExtSplatVal, MIB.buildConstant(InterEltTy, 1));
1418 auto LHS = MIB.buildSplatVector(InterTy, And);
1419 auto ZeroSplat =
1420 MIB.buildSplatVector(InterTy, MIB.buildConstant(InterEltTy, 0));
1421 MIB.buildICmp(CmpInst::Predicate::ICMP_NE, Dst, LHS, ZeroSplat);
1422 MI.eraseFromParent();
1423 return true;
1424}
1425
1426static LLT getLMUL1Ty(LLT VecTy) {
1427 assert(VecTy.getElementType().getSizeInBits() <= 64 &&
1428 "Unexpected vector LLT");
1430 VecTy.getElementType().getSizeInBits(),
1431 VecTy.getElementType());
1432}
1433
1434bool RISCVLegalizerInfo::legalizeExtractSubvector(MachineInstr &MI,
1435 MachineIRBuilder &MIB) const {
1436 GExtractSubvector &ES = cast<GExtractSubvector>(MI);
1437
1438 MachineRegisterInfo &MRI = *MIB.getMRI();
1439
1440 Register Dst = ES.getReg(0);
1441 Register Src = ES.getSrcVec();
1442 uint64_t Idx = ES.getIndexImm();
1443
1444 // With an index of 0 this is a cast-like subvector, which can be performed
1445 // with subregister operations.
1446 if (Idx == 0)
1447 return true;
1448
1449 LLT LitTy = MRI.getType(Dst);
1450 LLT BigTy = MRI.getType(Src);
1451
1452 if (LitTy.getElementType() == LLT::scalar(1)) {
1453 // We can't slide this mask vector up indexed by its i1 elements.
1454 // This poses a problem when we wish to insert a scalable vector which
1455 // can't be re-expressed as a larger type. Just choose the slow path and
1456 // extend to a larger type, then truncate back down.
1457 LLT ExtBigTy = BigTy.changeElementType(LLT::scalar(8));
1458 LLT ExtLitTy = LitTy.changeElementType(LLT::scalar(8));
1459 auto BigZExt = MIB.buildZExt(ExtBigTy, Src);
1460 auto ExtractZExt = MIB.buildExtractSubvector(ExtLitTy, BigZExt, Idx);
1461 auto SplatZero = MIB.buildSplatVector(
1462 ExtLitTy, MIB.buildConstant(ExtLitTy.getElementType(), 0));
1463 MIB.buildICmp(CmpInst::Predicate::ICMP_NE, Dst, ExtractZExt, SplatZero);
1464 MI.eraseFromParent();
1465 return true;
1466 }
1467
1468 // extract_subvector scales the index by vscale if the subvector is scalable,
1469 // and decomposeSubvectorInsertExtractToSubRegs takes this into account.
1470 const RISCVRegisterInfo *TRI = STI.getRegisterInfo();
1471 MVT LitTyMVT = getMVTForLLT(LitTy);
1472 auto Decompose =
1474 getMVTForLLT(BigTy), LitTyMVT, Idx, TRI);
1475 unsigned RemIdx = Decompose.second;
1476
1477 // If the Idx has been completely eliminated then this is a subvector extract
1478 // which naturally aligns to a vector register. These can easily be handled
1479 // using subregister manipulation.
1480 if (RemIdx == 0)
1481 return true;
1482
1483 // Else LitTy is M1 or smaller and may need to be slid down: if LitTy
1484 // was > M1 then the index would need to be a multiple of VLMAX, and so would
1485 // divide exactly.
1486 assert(
1489
1490 // If the vector type is an LMUL-group type, extract a subvector equal to the
1491 // nearest full vector register type.
1492 LLT InterLitTy = BigTy;
1493 Register Vec = Src;
1495 getLMUL1Ty(BigTy).getSizeInBits())) {
1496 // If BigTy has an LMUL > 1, then LitTy should have a smaller LMUL, and
1497 // we should have successfully decomposed the extract into a subregister.
1498 assert(Decompose.first != RISCV::NoSubRegister);
1499 InterLitTy = getLMUL1Ty(BigTy);
1500 // SDAG builds a TargetExtractSubreg. We cannot create a a Copy with SubReg
1501 // specified on the source Register (the equivalent) since generic virtual
1502 // register does not allow subregister index.
1503 Vec = MIB.buildExtractSubvector(InterLitTy, Src, Idx - RemIdx).getReg(0);
1504 }
1505
1506 // Slide this vector register down by the desired number of elements in order
1507 // to place the desired subvector starting at element 0.
1508 const LLT XLenTy(STI.getXLenVT());
1509 auto SlidedownAmt = MIB.buildVScale(XLenTy, RemIdx);
1510 auto [Mask, VL] = buildDefaultVLOps(InterLitTy, MIB, MRI);
1512 auto Slidedown = MIB.buildInstr(
1513 RISCV::G_VSLIDEDOWN_VL, {InterLitTy},
1514 {MIB.buildUndef(InterLitTy), Vec, SlidedownAmt, Mask, VL, Policy});
1515
1516 // Now the vector is in the right position, extract our final subvector. This
1517 // should resolve to a COPY.
1518 MIB.buildExtractSubvector(Dst, Slidedown, 0);
1519
1520 MI.eraseFromParent();
1521 return true;
1522}
1523
1524bool RISCVLegalizerInfo::legalizeInsertSubvector(MachineInstr &MI,
1525 LegalizerHelper &Helper,
1526 MachineIRBuilder &MIB) const {
1527 GInsertSubvector &IS = cast<GInsertSubvector>(MI);
1528
1529 MachineRegisterInfo &MRI = *MIB.getMRI();
1530
1531 Register Dst = IS.getReg(0);
1532 Register BigVec = IS.getBigVec();
1533 Register LitVec = IS.getSubVec();
1534 uint64_t Idx = IS.getIndexImm();
1535
1536 LLT BigTy = MRI.getType(BigVec);
1537 LLT LitTy = MRI.getType(LitVec);
1538
1539 if (Idx == 0 && mi_match(BigVec, MRI, m_GImplicitDef()))
1540 return true;
1541
1542 // We don't have the ability to slide mask vectors up indexed by their i1
1543 // elements; the smallest we can do is i8. Often we are able to bitcast to
1544 // equivalent i8 vectors. Otherwise, we can must zeroextend to equivalent i8
1545 // vectors and truncate down after the insert.
1546 if (LitTy.getElementType() == LLT::scalar(1)) {
1547 auto BigTyMinElts = BigTy.getElementCount().getKnownMinValue();
1548 auto LitTyMinElts = LitTy.getElementCount().getKnownMinValue();
1549 if (BigTyMinElts >= 8 && LitTyMinElts >= 8)
1550 return Helper.bitcast(
1551 IS, 0,
1553
1554 // We can't slide this mask vector up indexed by its i1 elements.
1555 // This poses a problem when we wish to insert a scalable vector which
1556 // can't be re-expressed as a larger type. Just choose the slow path and
1557 // extend to a larger type, then truncate back down.
1558 LLT ExtBigTy = BigTy.changeElementType(LLT::scalar(8));
1559 return Helper.widenScalar(IS, 0, ExtBigTy);
1560 }
1561
1562 const RISCVRegisterInfo *TRI = STI.getRegisterInfo();
1563 unsigned SubRegIdx, RemIdx;
1564 std::tie(SubRegIdx, RemIdx) =
1566 getMVTForLLT(BigTy), getMVTForLLT(LitTy), Idx, TRI);
1567
1568 TypeSize VecRegSize = TypeSize::getScalable(RISCV::RVVBitsPerBlock);
1570 STI.expandVScale(LitTy.getSizeInBits()).getKnownMinValue()));
1571 bool ExactlyVecRegSized =
1572 STI.expandVScale(LitTy.getSizeInBits())
1573 .isKnownMultipleOf(STI.expandVScale(VecRegSize));
1574
1575 // If the Idx has been completely eliminated and this subvector's size is a
1576 // vector register or a multiple thereof, or the surrounding elements are
1577 // undef, then this is a subvector insert which naturally aligns to a vector
1578 // register. These can easily be handled using subregister manipulation.
1579 if (RemIdx == 0 && ExactlyVecRegSized)
1580 return true;
1581
1582 // If the subvector is smaller than a vector register, then the insertion
1583 // must preserve the undisturbed elements of the register. We do this by
1584 // lowering to an EXTRACT_SUBVECTOR grabbing the nearest LMUL=1 vector type
1585 // (which resolves to a subregister copy), performing a VSLIDEUP to place the
1586 // subvector within the vector register, and an INSERT_SUBVECTOR of that
1587 // LMUL=1 type back into the larger vector (resolving to another subregister
1588 // operation). See below for how our VSLIDEUP works. We go via a LMUL=1 type
1589 // to avoid allocating a large register group to hold our subvector.
1590
1591 // VSLIDEUP works by leaving elements 0<i<OFFSET undisturbed, elements
1592 // OFFSET<=i<VL set to the "subvector" and vl<=i<VLMAX set to the tail policy
1593 // (in our case undisturbed). This means we can set up a subvector insertion
1594 // where OFFSET is the insertion offset, and the VL is the OFFSET plus the
1595 // size of the subvector.
1596 const LLT XLenTy(STI.getXLenVT());
1597 LLT InterLitTy = BigTy;
1598 Register AlignedExtract = BigVec;
1599 unsigned AlignedIdx = Idx - RemIdx;
1601 getLMUL1Ty(BigTy).getSizeInBits())) {
1602 InterLitTy = getLMUL1Ty(BigTy);
1603 // Extract a subvector equal to the nearest full vector register type. This
1604 // should resolve to a G_EXTRACT on a subreg.
1605 AlignedExtract =
1606 MIB.buildExtractSubvector(InterLitTy, BigVec, AlignedIdx).getReg(0);
1607 }
1608
1609 auto Insert = MIB.buildInsertSubvector(InterLitTy, MIB.buildUndef(InterLitTy),
1610 LitVec, 0);
1611
1612 auto [Mask, _] = buildDefaultVLOps(InterLitTy, MIB, MRI);
1613 auto VL = MIB.buildVScale(XLenTy, LitTy.getElementCount().getKnownMinValue());
1614
1615 // If we're inserting into the lowest elements, use a tail undisturbed
1616 // vmv.v.v.
1617 MachineInstrBuilder Inserted;
1618 bool NeedInsertSubvec =
1619 TypeSize::isKnownGT(BigTy.getSizeInBits(), InterLitTy.getSizeInBits());
1620 Register InsertedDst =
1621 NeedInsertSubvec ? MRI.createGenericVirtualRegister(InterLitTy) : Dst;
1622 if (RemIdx == 0) {
1623 Inserted = MIB.buildInstr(RISCV::G_VMV_V_V_VL, {InsertedDst},
1624 {AlignedExtract, Insert, VL});
1625 } else {
1626 auto SlideupAmt = MIB.buildVScale(XLenTy, RemIdx);
1627 // Construct the vector length corresponding to RemIdx + length(LitTy).
1628 VL = MIB.buildAdd(XLenTy, SlideupAmt, VL);
1629 // Use tail agnostic policy if we're inserting over InterLitTy's tail.
1630 ElementCount EndIndex =
1633 if (STI.expandVScale(EndIndex) ==
1634 STI.expandVScale(InterLitTy.getElementCount()))
1636
1637 Inserted =
1638 MIB.buildInstr(RISCV::G_VSLIDEUP_VL, {InsertedDst},
1639 {AlignedExtract, Insert, SlideupAmt, Mask, VL, Policy});
1640 }
1641
1642 // If required, insert this subvector back into the correct vector register.
1643 // This should resolve to an INSERT_SUBREG instruction.
1644 if (NeedInsertSubvec)
1645 MIB.buildInsertSubvector(Dst, BigVec, Inserted, AlignedIdx);
1646
1647 MI.eraseFromParent();
1648 return true;
1649}
1650
1651bool RISCVLegalizerInfo::legalizeBitreverse(MachineInstr &MI,
1652 MachineIRBuilder &MIB) const {
1653 assert(MI.getOpcode() == TargetOpcode::G_BITREVERSE && "Unexpected opcode");
1654
1655 if (!STI.hasStdExtZbkb())
1656 return false;
1657
1658 MachineRegisterInfo &MRI = *MIB.getMRI();
1659
1660 Register Dst = MI.getOperand(0).getReg();
1661 Register Src = MI.getOperand(1).getReg();
1662
1663 if (!MRI.getType(Dst).isScalar(8))
1664 return false;
1665
1666 auto WideSrc = MIB.buildAnyExt(sXLen, Src);
1667 auto Brev = MIB.buildInstr(RISCV::G_BREV8, {sXLen}, {WideSrc.getReg(0)});
1668 MIB.buildTrunc(Dst, Brev.getReg(0));
1669
1670 MI.eraseFromParent();
1671 return true;
1672}
1673
1674static unsigned getRISCVWOpcode(unsigned Opcode) {
1675 switch (Opcode) {
1676 default:
1677 llvm_unreachable("Unexpected opcode");
1678 case TargetOpcode::G_ASHR:
1679 return RISCV::G_SRAW;
1680 case TargetOpcode::G_LSHR:
1681 return RISCV::G_SRLW;
1682 case TargetOpcode::G_SHL:
1683 return RISCV::G_SLLW;
1684 case TargetOpcode::G_SDIV:
1685 return RISCV::G_DIVW;
1686 case TargetOpcode::G_UDIV:
1687 return RISCV::G_DIVUW;
1688 case TargetOpcode::G_UREM:
1689 return RISCV::G_REMUW;
1690 case TargetOpcode::G_ROTL:
1691 return RISCV::G_ROLW;
1692 case TargetOpcode::G_ROTR:
1693 return RISCV::G_RORW;
1694 case TargetOpcode::G_CTLZ:
1695 return RISCV::G_CLZW;
1696 case TargetOpcode::G_CTTZ:
1697 return RISCV::G_CTZW;
1698 case TargetOpcode::G_CTLS:
1699 return RISCV::G_CLSW;
1700 case TargetOpcode::G_FPTOSI:
1701 return RISCV::G_FCVT_W_RV64;
1702 case TargetOpcode::G_FPTOUI:
1703 return RISCV::G_FCVT_WU_RV64;
1704 }
1705}
1706
1709 LostDebugLocObserver &LocObserver) const {
1710 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
1711 MachineRegisterInfo &MRI = *MIRBuilder.getMRI();
1712 MachineFunction &MF = *MI.getParent()->getParent();
1713 switch (MI.getOpcode()) {
1714 default:
1715 // No idea what to do.
1716 return false;
1717 case TargetOpcode::G_ABS:
1718 return Helper.lowerAbsToMaxNeg(MI);
1719 case TargetOpcode::G_CLMULH:
1720 case TargetOpcode::G_CLMULR: {
1721 assert(STI.is64Bit() &&
1722 MRI.getType(MI.getOperand(0).getReg()) == LLT::scalar(32) &&
1723 "Unexpected custom legalization");
1724 // Shift both inputs by 32 so the full product has 64 trailing zeros.
1725 // Perform CLMULH or CLMULR on the shifted inputs, then extract the upper
1726 // 32 bits of the result.
1727 auto Shift = MIRBuilder.buildConstant(sXLen, 32);
1728 auto LHS = MIRBuilder.buildAnyExt(sXLen, MI.getOperand(1));
1729 auto RHS = MIRBuilder.buildAnyExt(sXLen, MI.getOperand(2));
1730 auto ShiftedLHS = MIRBuilder.buildShl(sXLen, LHS, Shift);
1731 auto ShiftedRHS = MIRBuilder.buildShl(sXLen, RHS, Shift);
1732 auto Product = MIRBuilder.buildInstr(MI.getOpcode(), {sXLen},
1733 {ShiftedLHS, ShiftedRHS});
1734 auto High = MIRBuilder.buildLShr(sXLen, Product, Shift);
1735 MIRBuilder.buildTrunc(MI.getOperand(0), High);
1736 MI.eraseFromParent();
1737 return true;
1738 }
1739 case TargetOpcode::G_CONSTANT: {
1740 const Function &F = MF.getFunction();
1741 // TODO: if PSI and BFI are present, add " ||
1742 // llvm::shouldOptForSize(*CurMBB, PSI, BFI)".
1743 bool ShouldOptForSize = F.hasOptSize();
1744 const ConstantInt *ConstVal = MI.getOperand(1).getCImm();
1745 if (!shouldBeInConstantPool(ConstVal->getValue(), ShouldOptForSize))
1746 return true;
1747 return Helper.lowerConstant(MI);
1748 }
1749 case TargetOpcode::G_SUB:
1750 case TargetOpcode::G_ADD: {
1751 Helper.Observer.changingInstr(MI);
1752 // The G_ANYEXTs below leave the new high bits unconstrained, so no-wrap
1753 // claims proved at the narrow width no longer hold.
1755 Helper.widenScalarSrc(MI, sXLen, 1, TargetOpcode::G_ANYEXT);
1756 Helper.widenScalarSrc(MI, sXLen, 2, TargetOpcode::G_ANYEXT);
1757
1758 Register DstALU = MRI.createGenericVirtualRegister(sXLen);
1759
1760 MachineOperand &MO = MI.getOperand(0);
1761 MIRBuilder.setInsertPt(MIRBuilder.getMBB(), ++MIRBuilder.getInsertPt());
1762 auto DstSext = MIRBuilder.buildSExtInReg(sXLen, DstALU, 32);
1763
1764 MIRBuilder.buildInstr(TargetOpcode::G_TRUNC, {MO}, {DstSext});
1765 MO.setReg(DstALU);
1766
1767 Helper.Observer.changedInstr(MI);
1768 return true;
1769 }
1770 case TargetOpcode::G_ASHR:
1771 case TargetOpcode::G_LSHR:
1772 case TargetOpcode::G_SHL: {
1773 if (getIConstantVRegValWithLookThrough(MI.getOperand(2).getReg(), MRI)) {
1774 // We don't need a custom node for shift by constant. Just widen the
1775 // source and the shift amount.
1776 unsigned ExtOpc = TargetOpcode::G_ANYEXT;
1777 if (MI.getOpcode() == TargetOpcode::G_ASHR)
1778 ExtOpc = TargetOpcode::G_SEXT;
1779 else if (MI.getOpcode() == TargetOpcode::G_LSHR)
1780 ExtOpc = TargetOpcode::G_ZEXT;
1781
1782 Helper.Observer.changingInstr(MI);
1783 // The G_ANYEXT leave the new high bits unconstrained, so no-wrap
1784 // claims proved at the narrow width no longer hold.
1785 if (ExtOpc == TargetOpcode::G_ANYEXT)
1787 Helper.widenScalarSrc(MI, sXLen, 1, ExtOpc);
1788 Helper.widenScalarSrc(MI, sXLen, 2, TargetOpcode::G_ZEXT);
1789 Helper.widenScalarDst(MI, sXLen);
1790 Helper.Observer.changedInstr(MI);
1791 return true;
1792 }
1793
1794 Helper.Observer.changingInstr(MI);
1795 Helper.widenScalarSrc(MI, sXLen, 1, TargetOpcode::G_ANYEXT);
1796 Helper.widenScalarSrc(MI, sXLen, 2, TargetOpcode::G_ANYEXT);
1797 Helper.widenScalarDst(MI, sXLen);
1798 MI.setDesc(MIRBuilder.getTII().get(getRISCVWOpcode(MI.getOpcode())));
1799 Helper.Observer.changedInstr(MI);
1800 return true;
1801 }
1802 case TargetOpcode::G_SDIV:
1803 case TargetOpcode::G_UDIV:
1804 case TargetOpcode::G_UREM:
1805 case TargetOpcode::G_ROTL:
1806 case TargetOpcode::G_ROTR: {
1807 Helper.Observer.changingInstr(MI);
1808 Helper.widenScalarSrc(MI, sXLen, 1, TargetOpcode::G_ANYEXT);
1809 Helper.widenScalarSrc(MI, sXLen, 2, TargetOpcode::G_ANYEXT);
1810 Helper.widenScalarDst(MI, sXLen);
1811 MI.setDesc(MIRBuilder.getTII().get(getRISCVWOpcode(MI.getOpcode())));
1812 Helper.Observer.changedInstr(MI);
1813 return true;
1814 }
1815 case TargetOpcode::G_CTLZ:
1816 case TargetOpcode::G_CTTZ:
1817 case TargetOpcode::G_CTLS: {
1818 Helper.Observer.changingInstr(MI);
1819 Helper.widenScalarSrc(MI, sXLen, 1, TargetOpcode::G_ANYEXT);
1820 Helper.widenScalarDst(MI, sXLen);
1821 MI.setDesc(MIRBuilder.getTII().get(getRISCVWOpcode(MI.getOpcode())));
1822 Helper.Observer.changedInstr(MI);
1823 return true;
1824 }
1825 case TargetOpcode::G_FPTOSI:
1826 case TargetOpcode::G_FPTOUI: {
1827 Helper.Observer.changingInstr(MI);
1828 Helper.widenScalarDst(MI, sXLen);
1829 MI.setDesc(MIRBuilder.getTII().get(getRISCVWOpcode(MI.getOpcode())));
1831 Helper.Observer.changedInstr(MI);
1832 return true;
1833 }
1834 case TargetOpcode::G_FPTOSI_SAT:
1835 case TargetOpcode::G_FPTOUI_SAT: {
1836 // Mirror lowerFP_TO_INT_SAT (RISCVISelLowering.cpp): the conversion
1837 // saturates out-of-range values, but we need to select 0 for NaN as
1838 // required by the intrinsics.
1839 Register Dst = MI.getOperand(0).getReg();
1840 Register Src = MI.getOperand(1).getReg();
1841 LLT DstTy = MRI.getType(Dst);
1842 unsigned DstBits = DstTy.getScalarSizeInBits();
1843 bool IsSigned = MI.getOpcode() == TargetOpcode::G_FPTOSI_SAT;
1844
1845 unsigned FCvtOp;
1846 if (DstBits == XLen) {
1847 FCvtOp = IsSigned ? RISCV::G_FCVT_X : RISCV::G_FCVT_XU;
1848 } else {
1849 assert(STI.is64Bit() && "Non-XLen results are only custom on RV64");
1850 FCvtOp = IsSigned ? RISCV::G_FCVT_W_RV64 : RISCV::G_FCVT_WU_RV64;
1851 }
1852
1853 auto FCvt = MIRBuilder.buildInstr(FCvtOp, {sXLen}, {Src})
1854 .addImm(RISCVFPRndMode::RTZ);
1855
1856 // RISC-V G_FCMP results are XLen wide, and so are G_SELECT conditions.
1857 auto IsNaN = MIRBuilder.buildFCmp(CmpInst::FCMP_UNO, sXLen, Src, Src);
1858
1859 Register FCvtReg = FCvt.getReg(0);
1860 if (DstBits != XLen)
1861 FCvtReg = MIRBuilder.buildTrunc(DstTy, FCvtReg).getReg(0);
1862
1863 MIRBuilder.buildSelect(Dst, IsNaN, MIRBuilder.buildConstant(DstTy, 0),
1864 FCvtReg);
1865
1866 MI.eraseFromParent();
1867 return true;
1868 }
1869 case TargetOpcode::G_LROUND: {
1870 // The (i32 any_lround) Pat is IsRV32-only; on RV64 lower to
1871 // riscv_fcvt_w_rv64 with FRM_RMM.
1872 Helper.Observer.changingInstr(MI);
1873 Helper.widenScalarDst(MI, sXLen);
1874 MI.setDesc(MIRBuilder.getTII().get(RISCV::G_FCVT_W_RV64));
1876 Helper.Observer.changedInstr(MI);
1877 return true;
1878 }
1879 case TargetOpcode::G_READCYCLECOUNTER:
1880 case TargetOpcode::G_READSTEADYCOUNTER:
1881 return legalizeReadCounter(MI, MIRBuilder, Helper.Observer);
1882 case TargetOpcode::G_IS_FPCLASS: {
1883 Register GISFPCLASS = MI.getOperand(0).getReg();
1884 Register Src = MI.getOperand(1).getReg();
1885 const MachineOperand &ImmOp = MI.getOperand(2);
1886 MachineIRBuilder MIB(MI);
1887
1888 // Turn LLVM IR's floating point classes to that in RISC-V,
1889 // by simply rotating the 10-bit immediate right by two bits.
1890 APInt GFpClassImm(10, static_cast<uint64_t>(ImmOp.getImm()));
1891 auto FClassMask = MIB.buildConstant(sXLen, GFpClassImm.rotr(2).zext(XLen));
1892 auto ConstZero = MIB.buildConstant(sXLen, 0);
1893
1894 auto GFClass = MIB.buildInstr(RISCV::G_FCLASS, {sXLen}, {Src});
1895 auto And = MIB.buildAnd(sXLen, GFClass, FClassMask);
1896 MIB.buildICmp(CmpInst::ICMP_NE, GISFPCLASS, And, ConstZero);
1897
1898 MI.eraseFromParent();
1899 return true;
1900 }
1901 case TargetOpcode::G_BRJT:
1902 return legalizeBRJT(MI, MIRBuilder);
1903 case TargetOpcode::G_VASTART:
1904 return legalizeVAStart(MI, MIRBuilder);
1905 case TargetOpcode::G_VSCALE:
1906 return legalizeVScale(MI, MIRBuilder);
1907 case TargetOpcode::G_ZEXT:
1908 case TargetOpcode::G_SEXT:
1909 case TargetOpcode::G_ANYEXT:
1910 return legalizeExt(MI, MIRBuilder);
1911 case TargetOpcode::G_SPLAT_VECTOR:
1912 return legalizeSplatVector(MI, MIRBuilder);
1913 case TargetOpcode::G_EXTRACT_SUBVECTOR:
1914 return legalizeExtractSubvector(MI, MIRBuilder);
1915 case TargetOpcode::G_INSERT_SUBVECTOR:
1916 return legalizeInsertSubvector(MI, Helper, MIRBuilder);
1917 case TargetOpcode::G_BITREVERSE:
1918 return legalizeBitreverse(MI, MIRBuilder);
1919 case TargetOpcode::G_LOAD:
1920 case TargetOpcode::G_STORE:
1921 return legalizeLoadStore(MI, Helper, MIRBuilder);
1922 }
1923
1924 llvm_unreachable("expected switch to return");
1925}
const TargetLowering & TLI
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
uint64_t uint64_t
uint64_t Imm
constexpr LLT S32
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
bpf unwind lower
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
Declares convenience wrapper classes for interpreting MachineInstr instances as specific generic oper...
const HexagonInstrInfo * TII
#define _
IRTranslator LLVM IR MI
#define F(x, y, z)
Definition MD5.cpp:54
#define I(x, y, z)
Definition MD5.cpp:57
Contains matchers for matching SSA Machine Instructions.
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 High
uint64_t IntrinsicInst * II
#define P(N)
ppc ctr loops verify
MachineRegisterInfo & MRI
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.
MachineInstr *& Lo
Value * LHS
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:1057
unsigned getBitWidth() const
Return the number of bits in the APInt.
Definition APInt.h:1508
LLVM_ABI APInt rotr(unsigned rotateAmt) const
Rotate right by rotateAmt.
Definition APInt.cpp:1199
int64_t getSExtValue() const
Get sign extended value.
Definition APInt.h:1582
@ ICMP_NE
not equal
Definition InstrTypes.h:762
@ FCMP_UNO
1 0 0 0 True if unordered: isnan(X) | isnan(Y)
Definition InstrTypes.h:750
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:309
LLVMContext & getContext() const
getContext - Return a reference to the LLVMContext associated with this function.
Definition Function.cpp:352
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.
virtual void erasingInstr(MachineInstr &MI)=0
An instruction is about to be erased.
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
static constexpr LLT float16()
Get a 16-bit IEEE half value.
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:76
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.
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
LLVM_ABI void transferSuccessorsAndUpdatePHIs(MachineBasicBlock *FromMBB)
Transfers all the successors, as in transferSuccessors, and update PHI operands in the successor bloc...
const BasicBlock * getBasicBlock() const
Return the LLVM basic block that this instance corresponded to originally.
LLVM_ABI void addSuccessor(MachineBasicBlock *Succ, BranchProbability Prob=BranchProbability::getUnknown())
Add Succ as a successor of this MachineBasicBlock.
const MachineFunction * getParent() const
Return the MachineFunction containing this basic block.
void splice(iterator Where, MachineBasicBlock *Other, iterator From)
Take an instruction from MBB 'Other' at the position From, and insert it into this MBB right before '...
MachineInstrBundleIterator< MachineInstr > iterator
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
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.
BasicBlockListType::iterator iterator
Ty * getInfo()
getInfo - Keep track of various per-function pieces of information for backends that would like to do...
MachineMemOperand * getMachineMemOperand(MachinePointerInfo PtrInfo, MachineMemOperand::Flags F, LLT MemTy, Align BaseAlignment, const MMOMetadata &Metadata=MMOMetadata(), SyncScope::ID SSID=SyncScope::System, AtomicOrdering Ordering=AtomicOrdering::NotAtomic, AtomicOrdering FailureOrdering=AtomicOrdering::NotAtomic)
getMachineMemOperand - Allocate a new MachineMemOperand.
const MachineJumpTableInfo * getJumpTableInfo() const
getJumpTableInfo - Return the jump table info object for the current function.
MachineBasicBlock * CreateMachineBasicBlock(const BasicBlock *BB=nullptr, std::optional< UniqueBBID > BBID=std::nullopt)
CreateMachineInstr - Allocate a new MachineInstr.
void insert(iterator MBBI, MachineBasicBlock *MBB)
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 buildIntrinsic(Intrinsic::ID ID, ArrayRef< Register > Res, bool HasSideEffects, bool isConvergent)
Build and insert a G_INTRINSIC instruction.
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 buildMergeValues(const DstOp &Res, ArrayRef< Register > Ops)
Build and insert Res = G_MERGE_VALUES Op0, ...
MachineInstrBuilder buildTrunc(const DstOp &Res, const SrcOp &Op, std::optional< unsigned > Flags=std::nullopt)
Build and insert Res = G_TRUNC Op.
void setDebugLoc(const DebugLoc &DL)
Set the debug location to DL for all the next build instructions.
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 buildFCmp(CmpInst::Predicate Pred, const DstOp &Res, const SrcOp &Op0, const SrcOp &Op1, std::optional< unsigned > Flags=std::nullopt)
Build and insert a Res = G_FCMP PredOp0, Op1.
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.
const MachineInstrBuilder & addReg(Register RegNo, RegState Flags={}, unsigned SubReg=0) const
Add a new virtual register operand.
const MachineInstrBuilder & addImm(int64_t Val) const
Add a new immediate operand.
const MachineInstrBuilder & addMBB(MachineBasicBlock *MBB, unsigned TargetFlags=0) const
Representation of each machine instruction.
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 LLVM_READONLY 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 void setRegClass(Register Reg, const TargetRegisterClass *RC)
setRegClass - Set the register class of the specified 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
bool allowsMemoryAccessForAlignment(LLVMContext &Context, const DataLayout &DL, EVT VT, unsigned AddrSpace=0, Align Alignment=Align(1), MachineMemOperand::Flags Flags=MachineMemOperand::MONone, unsigned *Fast=nullptr) const
This function returns true if the memory access is aligned or if the target allows this specific unal...
static constexpr TypeSize getScalable(ScalarTy MinimumSize)
Definition TypeSize.h:355
constexpr ScalarTy getKnownMinValue() const
Returns the minimum value this quantity can represent.
Definition TypeSize.h:166
static constexpr bool isKnownGT(const FixedOrScalableQuantity &LHS, const FixedOrScalableQuantity &RHS)
Definition TypeSize.h:224
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:253
self_iterator getIterator()
Definition ilist_node.h:123
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
constexpr char Align[]
Key for Kernel::Arg::Metadata::mAlign.
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.
@ BasicBlock
Various leaf nodes.
Definition ISDOpcodes.h:83
LLVM_ABI LegalityPredicate isScalar(unsigned TypeIdx)
True iff the specified type index is a scalar.
LLVM_ABI LegalityPredicate typeInSet(unsigned TypeIdx, std::initializer_list< LLT > TypesInit)
True iff the given type index is one of the specified types.
LLVM_ABI LegalityPredicate immIs(unsigned ImmIdx, int64_t Imm)
True iff the immediate at the given index has the specified value.
Predicate any(Predicate P0, Predicate P1)
True iff P0 or P1 are true.
LLVM_ABI LegalityPredicate sizeIs(unsigned TypeIdx, unsigned Size)
True if the total bitwidth of the specified type index is Size bits.
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 LegalityPredicate immInSet(unsigned ImmIdx, std::initializer_list< int64_t > ImmsInit)
True iff the immediate at the given index has one of the specified values.
LLVM_ABI LegalizeMutation changeTo(unsigned TypeIdx, LLT Ty)
Select this specific type for the given type index.
ImplicitDefMatch m_GImplicitDef()
bool mi_match(Reg R, const MachineRegisterInfo &MRI, Pattern &&P)
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:2138
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
constexpr bool isInt(int64_t x)
Checks if an integer fits into the given bit width.
Definition MathExtras.h:166
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:1717
@ Load
The value being inserted comes from a load (InsertElement only).
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:285
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:1699
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:332
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:326
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:280
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:440
unsigned Log2(Align A)
Returns the log2 of the alignment.
Definition Alignment.h:202
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.