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