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