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_LROUND, G_LLROUND})
625 .legalFor(ST.hasStdExtF(), {{sXLen, s32}})
626 .legalFor(ST.hasStdExtD(), {{sXLen, s64}})
627 .legalFor(ST.hasStdExtZfh(), {{sXLen, s16}})
628 .customFor(ST.is64Bit() && ST.hasStdExtF(), {{s32, s32}})
629 .customFor(ST.is64Bit() && ST.hasStdExtD(), {{s32, s64}})
630 .customFor(ST.is64Bit() && ST.hasStdExtZfh(), {{s32, s16}})
631 .widenScalarIf(typeIs(1, s16), LegalizeMutations::changeTo(1, s32))
632 .libcallFor({{s32, s32},
633 {s64, s32},
634 {s32, s64},
635 {s64, s64},
636 {s32, s128},
637 {s64, s128}});
638
639 getActionDefinitionsBuilder({G_SITOFP, G_UITOFP})
640 .legalFor(ST.hasStdExtF(), {{s32, sXLen}})
641 .legalFor(ST.hasStdExtD(), {{s64, sXLen}})
642 .legalFor(ST.hasStdExtZfh(), {{s16, sXLen}})
643 .widenScalarToNextPow2(1)
644 // Promote to XLen if the operation is legal.
645 .widenScalarIf(
646 [=, &ST](const LegalityQuery &Query) {
647 return Query.Types[0].isScalar() && Query.Types[1].isScalar() &&
648 (Query.Types[1].getSizeInBits() < ST.getXLen()) &&
649 ((ST.hasStdExtF() && Query.Types[0].getSizeInBits() == 32) ||
650 (ST.hasStdExtD() && Query.Types[0].getSizeInBits() == 64) ||
651 (ST.hasStdExtZfh() &&
652 Query.Types[0].getSizeInBits() == 16));
653 },
655 // Otherwise only promote to s32 since we have si libcalls.
656 .minScalar(1, s32)
657 .libcallFor({{s32, s32}, {s64, s32}, {s32, s64}, {s64, s64}})
658 .libcallFor(ST.is64Bit(), {{s128, s32}, {s128, s64}}) // FIXME RV32.
659 .libcallFor(ST.is64Bit(), {{s32, s128}, {s64, s128}, {s128, s128}});
660
661 // FIXME: We can do custom inline expansion like SelectionDAG.
662 getActionDefinitionsBuilder({G_FCEIL, G_FFLOOR, G_FRINT, G_FNEARBYINT,
663 G_INTRINSIC_TRUNC, G_INTRINSIC_ROUND,
664 G_INTRINSIC_ROUNDEVEN})
665 .legalFor(ST.hasStdExtZfa(), {s32})
666 .legalFor(ST.hasStdExtZfa() && ST.hasStdExtD(), {s64})
667 .legalFor(ST.hasStdExtZfa() && ST.hasStdExtZfh(), {s16})
668 .libcallFor({s32, s64})
669 .libcallFor(ST.is64Bit(), {s128});
670
671 getActionDefinitionsBuilder({G_FMAXIMUM, G_FMINIMUM})
672 .legalFor(ST.hasStdExtZfa(), {s32})
673 .legalFor(ST.hasStdExtZfa() && ST.hasStdExtD(), {s64})
674 .legalFor(ST.hasStdExtZfa() && ST.hasStdExtZfh(), {s16});
675
676 getActionDefinitionsBuilder({G_FCOS, G_FSIN, G_FTAN, G_FPOW, G_FLOG, G_FLOG2,
677 G_FLOG10, G_FEXP, G_FEXP2, G_FEXP10, G_FACOS,
678 G_FASIN, G_FATAN, G_FATAN2, G_FCOSH, G_FSINH,
679 G_FTANH, G_FMODF})
680 .libcallFor({s32, s64})
681 .libcallFor(ST.is64Bit(), {s128});
682 getActionDefinitionsBuilder({G_FPOWI, G_FLDEXP})
683 .libcallFor({{s32, s32}, {s64, s32}})
684 .libcallFor(ST.is64Bit(), {s128, s32});
685
686 getActionDefinitionsBuilder(G_FCANONICALIZE)
687 .legalFor(ST.hasStdExtF(), {s32})
688 .legalFor(ST.hasStdExtD(), {s64})
689 .legalFor(ST.hasStdExtZfh(), {s16});
690
691 getActionDefinitionsBuilder(G_VASTART).customFor({p0});
692
693 // va_list must be a pointer, but most sized types are pretty easy to handle
694 // as the destination.
695 getActionDefinitionsBuilder(G_VAARG)
696 // TODO: Implement narrowScalar and widenScalar for G_VAARG for types
697 // other than sXLen.
698 .clampScalar(0, sXLen, sXLen)
699 .lowerForCartesianProduct({sXLen, p0}, {p0});
700
701 getActionDefinitionsBuilder(G_VSCALE)
702 .clampScalar(0, sXLen, sXLen)
703 .customFor({sXLen});
704
705 auto &SplatActions =
706 getActionDefinitionsBuilder(G_SPLAT_VECTOR)
707 .legalIf(all(typeIsLegalIntOrFPVec(0, IntOrFPVecTys, ST),
708 typeIs(1, sXLen)))
709 .customIf(all(typeIsLegalBoolVec(0, BoolVecTys, ST), typeIs(1, s1)));
710 // Handle case of s64 element vectors on RV32. If the subtarget does not have
711 // f64, then try to lower it to G_SPLAT_VECTOR_SPLIT_64_VL. If the subtarget
712 // does have f64, then we don't know whether the type is an f64 or an i64,
713 // so mark the G_SPLAT_VECTOR as legal and decide later what to do with it,
714 // depending on how the instructions it consumes are legalized. They are not
715 // legalized yet since legalization is in reverse postorder, so we cannot
716 // make the decision at this moment.
717 if (XLen == 32) {
718 if (ST.hasVInstructionsF64() && ST.hasStdExtD())
719 SplatActions.legalIf(all(
720 typeInSet(0, {nxv1s64, nxv2s64, nxv4s64, nxv8s64}), typeIs(1, s64)));
721 else if (ST.hasVInstructionsI64())
722 SplatActions.customIf(all(
723 typeInSet(0, {nxv1s64, nxv2s64, nxv4s64, nxv8s64}), typeIs(1, s64)));
724 }
725
726 SplatActions.clampScalar(1, sXLen, sXLen);
727
728 LegalityPredicate ExtractSubvecBitcastPred = [=](const LegalityQuery &Query) {
729 LLT DstTy = Query.Types[0];
730 LLT SrcTy = Query.Types[1];
731 return DstTy.getElementType() == LLT::scalar(1) &&
732 DstTy.getElementCount().getKnownMinValue() >= 8 &&
733 SrcTy.getElementCount().getKnownMinValue() >= 8;
734 };
735 getActionDefinitionsBuilder(G_EXTRACT_SUBVECTOR)
736 // We don't have the ability to slide mask vectors down indexed by their
737 // i1 elements; the smallest we can do is i8. Often we are able to bitcast
738 // to equivalent i8 vectors.
739 .bitcastIf(
740 all(typeIsLegalBoolVec(0, BoolVecTys, ST),
741 typeIsLegalBoolVec(1, BoolVecTys, ST), ExtractSubvecBitcastPred),
742 [=](const LegalityQuery &Query) {
743 LLT CastTy = LLT::vector(
744 Query.Types[0].getElementCount().divideCoefficientBy(8), 8);
745 return std::pair(0, CastTy);
746 })
747 .customIf(LegalityPredicates::any(
748 all(typeIsLegalBoolVec(0, BoolVecTys, ST),
749 typeIsLegalBoolVec(1, BoolVecTys, ST)),
750 all(typeIsLegalIntOrFPVec(0, IntOrFPVecTys, ST),
751 typeIsLegalIntOrFPVec(1, IntOrFPVecTys, ST))));
752
753 getActionDefinitionsBuilder(G_INSERT_SUBVECTOR)
754 .customIf(all(typeIsLegalBoolVec(0, BoolVecTys, ST),
755 typeIsLegalBoolVec(1, BoolVecTys, ST)))
756 .customIf(all(typeIsLegalIntOrFPVec(0, IntOrFPVecTys, ST),
757 typeIsLegalIntOrFPVec(1, IntOrFPVecTys, ST)));
758
759 getActionDefinitionsBuilder(G_ATOMIC_CMPXCHG_WITH_SUCCESS)
760 .lowerIf(all(typeInSet(0, {s8, s16, s32, s64}), typeIs(2, p0)));
761
762 getActionDefinitionsBuilder({G_ATOMIC_CMPXCHG, G_ATOMICRMW_ADD,
763 G_ATOMICRMW_XCHG, G_ATOMICRMW_AND,
764 G_ATOMICRMW_OR, G_ATOMICRMW_XOR})
765 .legalFor(ST.hasStdExtA(), {{sXLen, p0}})
766 .libcallFor(!ST.hasStdExtA(), {{s8, p0}, {s16, p0}, {s32, p0}, {s64, p0}})
767 .clampScalar(0, sXLen, sXLen);
768
769 getActionDefinitionsBuilder(G_ATOMICRMW_SUB)
770 .libcallFor(!ST.hasStdExtA(), {{s8, p0}, {s16, p0}, {s32, p0}, {s64, p0}})
771 .clampScalar(0, sXLen, sXLen)
772 .lower();
773
774 getActionDefinitionsBuilder(
775 {G_ATOMICRMW_MAX, G_ATOMICRMW_MIN, G_ATOMICRMW_UMAX, G_ATOMICRMW_UMIN})
776 .legalFor(ST.hasStdExtA(), {{sXLen, p0}})
777 .clampScalar(0, sXLen, sXLen)
778 .unsupported();
779
780 LegalityPredicate InsertVectorEltPred = [=](const LegalityQuery &Query) {
781 LLT VecTy = Query.Types[0];
782 LLT EltTy = Query.Types[1];
783 return VecTy.getElementType() == EltTy;
784 };
785
786 getActionDefinitionsBuilder(G_INSERT_VECTOR_ELT)
787 .legalIf(all(typeIsLegalIntOrFPVec(0, IntOrFPVecTys, ST),
788 InsertVectorEltPred, typeIs(2, sXLen)))
789 .legalIf(all(typeIsLegalBoolVec(0, BoolVecTys, ST), InsertVectorEltPred,
790 typeIs(2, sXLen)));
791
792 getActionDefinitionsBuilder({G_INTRINSIC, G_INTRINSIC_W_SIDE_EFFECTS})
793 .alwaysLegal();
794
795 getActionDefinitionsBuilder(G_FENCE).alwaysLegal();
796
797 getActionDefinitionsBuilder({G_TRAP, G_DEBUGTRAP, G_UBSANTRAP}).alwaysLegal();
798
799 verify(*ST.getInstrInfo());
800}
801
803 MachineInstr &MI) const {
804 Intrinsic::ID IntrinsicID = cast<GIntrinsic>(MI).getIntrinsicID();
805
807 RISCVVIntrinsicsTable::getRISCVVIntrinsicInfo(IntrinsicID)) {
808 if (II->hasScalarOperand() && !II->IsFPIntrinsic) {
809 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
810 MachineRegisterInfo &MRI = *MIRBuilder.getMRI();
811
812 auto OldScalar = MI.getOperand(II->ScalarOperand + 2).getReg();
813 // Legalize integer vx form intrinsic.
814 if (MRI.getType(OldScalar).isScalar()) {
815 if (MRI.getType(OldScalar).getSizeInBits() < sXLen.getSizeInBits()) {
816 Helper.Observer.changingInstr(MI);
817 Helper.widenScalarSrc(MI, sXLen, II->ScalarOperand + 2,
818 TargetOpcode::G_ANYEXT);
819 Helper.Observer.changedInstr(MI);
820 } else if (MRI.getType(OldScalar).getSizeInBits() >
821 sXLen.getSizeInBits()) {
822 // TODO: i64 in riscv32.
823 return false;
824 }
825 }
826 }
827 return true;
828 }
829
830 switch (IntrinsicID) {
831 default:
832 return false;
833 case Intrinsic::vacopy: {
834 // vacopy arguments must be legal because of the intrinsic signature.
835 // No need to check here.
836
837 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
838 MachineRegisterInfo &MRI = *MIRBuilder.getMRI();
839 MachineFunction &MF = *MI.getMF();
840 const DataLayout &DL = MIRBuilder.getDataLayout();
841 LLVMContext &Ctx = MF.getFunction().getContext();
842
843 Register DstLst = MI.getOperand(1).getReg();
844 LLT PtrTy = MRI.getType(DstLst);
845
846 // Load the source va_list
847 Align Alignment = DL.getABITypeAlign(getTypeForLLT(PtrTy, Ctx));
849 MachinePointerInfo(), MachineMemOperand::MOLoad, PtrTy, Alignment);
850 auto Tmp = MIRBuilder.buildLoad(PtrTy, MI.getOperand(2), *LoadMMO);
851
852 // Store the result in the destination va_list
855 MIRBuilder.buildStore(Tmp, DstLst, *StoreMMO);
856
857 MI.eraseFromParent();
858 return true;
859 }
860 case Intrinsic::riscv_vsetvli:
861 case Intrinsic::riscv_vsetvlimax:
862 case Intrinsic::riscv_masked_atomicrmw_add:
863 case Intrinsic::riscv_masked_atomicrmw_sub:
864 case Intrinsic::riscv_masked_atomicrmw_xchg:
865 case Intrinsic::riscv_masked_atomicrmw_max:
866 case Intrinsic::riscv_masked_atomicrmw_min:
867 case Intrinsic::riscv_masked_atomicrmw_umax:
868 case Intrinsic::riscv_masked_atomicrmw_umin:
869 case Intrinsic::riscv_masked_cmpxchg:
870 return true;
871 }
872}
873
874bool RISCVLegalizerInfo::legalizeVAStart(MachineInstr &MI,
875 MachineIRBuilder &MIRBuilder) const {
876 // Stores the address of the VarArgsFrameIndex slot into the memory location
877 assert(MI.getOpcode() == TargetOpcode::G_VASTART);
878 MachineFunction *MF = MI.getParent()->getParent();
880 int FI = FuncInfo->getVarArgsFrameIndex();
881 LLT AddrTy = MIRBuilder.getMRI()->getType(MI.getOperand(0).getReg());
882 auto FINAddr = MIRBuilder.buildFrameIndex(AddrTy, FI);
883 assert(MI.hasOneMemOperand());
884 MIRBuilder.buildStore(FINAddr, MI.getOperand(0).getReg(),
885 *MI.memoperands()[0]);
886 MI.eraseFromParent();
887 return true;
888}
889
890bool RISCVLegalizerInfo::legalizeBRJT(MachineInstr &MI,
891 MachineIRBuilder &MIRBuilder) const {
892 MachineRegisterInfo &MRI = *MIRBuilder.getMRI();
893 auto &MF = *MI.getParent()->getParent();
894 const MachineJumpTableInfo *MJTI = MF.getJumpTableInfo();
895 unsigned EntrySize = MJTI->getEntrySize(MF.getDataLayout());
896
897 Register PtrReg = MI.getOperand(0).getReg();
898 LLT PtrTy = MRI.getType(PtrReg);
899 Register IndexReg = MI.getOperand(2).getReg();
900 LLT IndexTy = MRI.getType(IndexReg);
901
902 if (!isPowerOf2_32(EntrySize))
903 return false;
904
905 auto ShiftAmt = MIRBuilder.buildConstant(IndexTy, Log2_32(EntrySize));
906 IndexReg = MIRBuilder.buildShl(IndexTy, IndexReg, ShiftAmt).getReg(0);
907
908 auto Addr = MIRBuilder.buildPtrAdd(PtrTy, PtrReg, IndexReg);
909
912 EntrySize, Align(MJTI->getEntryAlignment(MF.getDataLayout())));
913
914 Register TargetReg;
915 switch (MJTI->getEntryKind()) {
916 default:
917 return false;
919 // For PIC, the sequence is:
920 // BRIND(load(Jumptable + index) + RelocBase)
921 // RelocBase can be JumpTable, GOT or some sort of global base.
922 unsigned LoadOpc =
923 STI.is64Bit() ? TargetOpcode::G_SEXTLOAD : TargetOpcode::G_LOAD;
924 auto Load = MIRBuilder.buildLoadInstr(LoadOpc, IndexTy, Addr, *MMO);
925 TargetReg = MIRBuilder.buildPtrAdd(PtrTy, PtrReg, Load).getReg(0);
926 break;
927 }
929 auto Load = MIRBuilder.buildLoadInstr(TargetOpcode::G_SEXTLOAD, IndexTy,
930 Addr, *MMO);
931 TargetReg = MIRBuilder.buildIntToPtr(PtrTy, Load).getReg(0);
932 break;
933 }
935 TargetReg = MIRBuilder.buildLoad(PtrTy, Addr, *MMO).getReg(0);
936 break;
937 }
938
939 MIRBuilder.buildBrIndirect(TargetReg);
940
941 MI.eraseFromParent();
942 return true;
943}
944
945bool RISCVLegalizerInfo::shouldBeInConstantPool(const APInt &APImm,
946 bool ShouldOptForSize) const {
947 assert(APImm.getBitWidth() == 32 || APImm.getBitWidth() == 64);
948 int64_t Imm = APImm.getSExtValue();
949 // All simm32 constants should be handled by isel.
950 // NOTE: The getMaxBuildIntsCost call below should return a value >= 2 making
951 // this check redundant, but small immediates are common so this check
952 // should have better compile time.
953 if (isInt<32>(Imm))
954 return false;
955
956 // We only need to cost the immediate, if constant pool lowering is enabled.
957 if (!STI.useConstantPoolForLargeInts())
958 return false;
959
961 if (Seq.size() <= STI.getMaxBuildIntsCost())
962 return false;
963
964 // Optimizations below are disabled for opt size. If we're optimizing for
965 // size, use a constant pool.
966 if (ShouldOptForSize)
967 return true;
968 //
969 // Special case. See if we can build the constant as (ADD (SLLI X, C), X) do
970 // that if it will avoid a constant pool.
971 // It will require an extra temporary register though.
972 // If we have Zba we can use (ADD_UW X, (SLLI X, 32)) to handle cases where
973 // low and high 32 bits are the same and bit 31 and 63 are set.
974 unsigned ShiftAmt, AddOpc;
976 RISCVMatInt::generateTwoRegInstSeq(Imm, STI, ShiftAmt, AddOpc);
977 return !(!SeqLo.empty() && (SeqLo.size() + 2) <= STI.getMaxBuildIntsCost());
978}
979
980bool RISCVLegalizerInfo::legalizeVScale(MachineInstr &MI,
981 MachineIRBuilder &MIB) const {
982 Register Dst = MI.getOperand(0).getReg();
983
984 // We define our scalable vector types for lmul=1 to use a 64 bit known
985 // minimum size. e.g. <vscale x 2 x i32>. VLENB is in bytes so we calculate
986 // vscale as VLENB / 8.
987 static_assert(RISCV::RVVBitsPerBlock == 64, "Unexpected bits per block!");
988 if (STI.getRealMinVLen() < RISCV::RVVBitsPerBlock)
989 // Support for VLEN==32 is incomplete.
990 return false;
991
992 // We assume VLENB is a multiple of 8. We manually choose the best shift
993 // here because SimplifyDemandedBits isn't always able to simplify it.
994 uint64_t Val = MI.getOperand(1).getCImm()->getZExtValue();
995 if (isPowerOf2_64(Val)) {
996 uint64_t Log2 = Log2_64(Val);
997 if (Log2 < 3) {
998 auto VLENB = MIB.buildInstr(RISCV::G_READ_VLENB, {sXLen}, {});
999 MIB.buildLShr(Dst, VLENB, MIB.buildConstant(sXLen, 3 - Log2),
1001 } else if (Log2 > 3) {
1002 auto VLENB = MIB.buildInstr(RISCV::G_READ_VLENB, {sXLen}, {});
1003 MIB.buildShl(Dst, VLENB, MIB.buildConstant(sXLen, Log2 - 3));
1004 } else {
1005 MIB.buildInstr(RISCV::G_READ_VLENB, {Dst}, {});
1006 }
1007 } else if ((Val % 8) == 0) {
1008 // If the multiplier is a multiple of 8, scale it down to avoid needing
1009 // to shift the VLENB value.
1010 auto VLENB = MIB.buildInstr(RISCV::G_READ_VLENB, {sXLen}, {});
1011 MIB.buildMul(Dst, VLENB, MIB.buildConstant(sXLen, Val / 8));
1012 } else {
1013 auto VLENB = MIB.buildInstr(RISCV::G_READ_VLENB, {sXLen}, {});
1014 auto VScale = MIB.buildLShr(sXLen, VLENB, MIB.buildConstant(sXLen, 3),
1016 MIB.buildMul(Dst, VScale, MIB.buildConstant(sXLen, Val));
1017 }
1018 MI.eraseFromParent();
1019 return true;
1020}
1021
1022// Custom-lower extensions from mask vectors by using a vselect either with 1
1023// for zero/any-extension or -1 for sign-extension:
1024// (vXiN = (s|z)ext vXi1:vmask) -> (vXiN = vselect vmask, (-1 or 1), 0)
1025// Note that any-extension is lowered identically to zero-extension.
1026bool RISCVLegalizerInfo::legalizeExt(MachineInstr &MI,
1027 MachineIRBuilder &MIB) const {
1028
1029 unsigned Opc = MI.getOpcode();
1030 assert(Opc == TargetOpcode::G_ZEXT || Opc == TargetOpcode::G_SEXT ||
1031 Opc == TargetOpcode::G_ANYEXT);
1032
1033 MachineRegisterInfo &MRI = *MIB.getMRI();
1034 Register Dst = MI.getOperand(0).getReg();
1035 Register Src = MI.getOperand(1).getReg();
1036
1037 LLT DstTy = MRI.getType(Dst);
1038 int64_t ExtTrueVal = Opc == TargetOpcode::G_SEXT ? -1 : 1;
1039 LLT DstEltTy = DstTy.getElementType();
1040 auto SplatZero = MIB.buildSplatVector(DstTy, MIB.buildConstant(DstEltTy, 0));
1041 auto SplatTrue =
1042 MIB.buildSplatVector(DstTy, MIB.buildConstant(DstEltTy, ExtTrueVal));
1043 MIB.buildSelect(Dst, Src, SplatTrue, SplatZero);
1044
1045 MI.eraseFromParent();
1046 return true;
1047}
1048
1049bool RISCVLegalizerInfo::legalizeLoadStore(MachineInstr &MI,
1050 LegalizerHelper &Helper,
1051 MachineIRBuilder &MIB) const {
1053 "Machine instructions must be Load/Store.");
1054 MachineRegisterInfo &MRI = *MIB.getMRI();
1055 MachineFunction *MF = MI.getMF();
1056 const DataLayout &DL = MIB.getDataLayout();
1057 LLVMContext &Ctx = MF->getFunction().getContext();
1058
1059 Register DstReg = MI.getOperand(0).getReg();
1060 LLT DataTy = MRI.getType(DstReg);
1061 if (!DataTy.isVector())
1062 return false;
1063
1064 if (!MI.hasOneMemOperand())
1065 return false;
1066
1067 MachineMemOperand *MMO = *MI.memoperands_begin();
1068
1069 const auto *TLI = STI.getTargetLowering();
1070 EVT VT = EVT::getEVT(getTypeForLLT(DataTy, Ctx));
1071
1072 if (TLI->allowsMemoryAccessForAlignment(Ctx, DL, VT, *MMO))
1073 return true;
1074
1075 unsigned EltSizeBits = DataTy.getScalarSizeInBits();
1076 assert((EltSizeBits == 16 || EltSizeBits == 32 || EltSizeBits == 64) &&
1077 "Unexpected unaligned RVV load type");
1078
1079 // Calculate the new vector type with i8 elements
1080 unsigned NumElements =
1081 DataTy.getElementCount().getKnownMinValue() * (EltSizeBits / 8);
1082 LLT NewDataTy = LLT::scalable_vector(NumElements, 8);
1083
1084 Helper.bitcast(MI, 0, NewDataTy);
1085
1086 return true;
1087}
1088
1089/// Return the type of the mask type suitable for masking the provided
1090/// vector type. This is simply an i1 element type vector of the same
1091/// (possibly scalable) length.
1092static LLT getMaskTypeFor(LLT VecTy) {
1093 assert(VecTy.isVector());
1094 ElementCount EC = VecTy.getElementCount();
1095 return LLT::vector(EC, LLT::scalar(1));
1096}
1097
1098/// Creates an all ones mask suitable for masking a vector of type VecTy with
1099/// vector length VL.
1101 MachineIRBuilder &MIB,
1102 MachineRegisterInfo &MRI) {
1103 LLT MaskTy = getMaskTypeFor(VecTy);
1104 return MIB.buildInstr(RISCV::G_VMSET_VL, {MaskTy}, {VL});
1105}
1106
1107/// Gets the two common "VL" operands: an all-ones mask and the vector length.
1108/// VecTy is a scalable vector type.
1109static std::pair<MachineInstrBuilder, MachineInstrBuilder>
1111 assert(VecTy.isScalableVector() && "Expecting scalable container type");
1112 const RISCVSubtarget &STI = MIB.getMF().getSubtarget<RISCVSubtarget>();
1113 LLT XLenTy(STI.getXLenVT());
1114 auto VL = MIB.buildConstant(XLenTy, -1);
1115 auto Mask = buildAllOnesMask(VecTy, VL, MIB, MRI);
1116 return {Mask, VL};
1117}
1118
1120buildSplatPartsS64WithVL(const DstOp &Dst, const SrcOp &Passthru, Register Lo,
1121 Register Hi, const SrcOp &VL, MachineIRBuilder &MIB,
1122 MachineRegisterInfo &MRI) {
1123 // TODO: If the Hi bits of the splat are undefined, then it's fine to just
1124 // splat Lo even if it might be sign extended. I don't think we have
1125 // introduced a case where we're build a s64 where the upper bits are undef
1126 // yet.
1127
1128 // Fall back to a stack store and stride x0 vector load.
1129 // TODO: need to lower G_SPLAT_VECTOR_SPLIT_I64. This is done in
1130 // preprocessDAG in SDAG.
1131 return MIB.buildInstr(RISCV::G_SPLAT_VECTOR_SPLIT_I64_VL, {Dst},
1132 {Passthru, Lo, Hi, VL});
1133}
1134
1136buildSplatSplitS64WithVL(const DstOp &Dst, const SrcOp &Passthru,
1137 const SrcOp &Scalar, const SrcOp &VL,
1139 assert(Scalar.getLLTTy(MRI) == LLT::scalar(64) && "Unexpected VecTy!");
1140 auto Unmerge = MIB.buildUnmerge(LLT::scalar(32), Scalar);
1141 return buildSplatPartsS64WithVL(Dst, Passthru, Unmerge.getReg(0),
1142 Unmerge.getReg(1), VL, MIB, MRI);
1143}
1144
1145// Lower splats of s1 types to G_ICMP. For each mask vector type, we have a
1146// legal equivalently-sized i8 type, so we can use that as a go-between.
1147// Splats of s1 types that have constant value can be legalized as VMSET_VL or
1148// VMCLR_VL.
1149bool RISCVLegalizerInfo::legalizeSplatVector(MachineInstr &MI,
1150 MachineIRBuilder &MIB) const {
1151 assert(MI.getOpcode() == TargetOpcode::G_SPLAT_VECTOR);
1152
1153 MachineRegisterInfo &MRI = *MIB.getMRI();
1154
1155 Register Dst = MI.getOperand(0).getReg();
1156 Register SplatVal = MI.getOperand(1).getReg();
1157
1158 LLT VecTy = MRI.getType(Dst);
1159 LLT XLenTy(STI.getXLenVT());
1160
1161 // Handle case of s64 element vectors on rv32
1162 if (XLenTy.getSizeInBits() == 32 &&
1163 VecTy.getElementType().getSizeInBits() == 64) {
1164 auto [_, VL] = buildDefaultVLOps(MRI.getType(Dst), MIB, MRI);
1165 buildSplatSplitS64WithVL(Dst, MIB.buildUndef(VecTy), SplatVal, VL, MIB,
1166 MRI);
1167 MI.eraseFromParent();
1168 return true;
1169 }
1170
1171 // All-zeros or all-ones splats are handled specially.
1172 MachineInstr &SplatValMI = *MRI.getVRegDef(SplatVal);
1173 if (isAllOnesOrAllOnesSplat(SplatValMI, MRI)) {
1174 auto VL = buildDefaultVLOps(VecTy, MIB, MRI).second;
1175 MIB.buildInstr(RISCV::G_VMSET_VL, {Dst}, {VL});
1176 MI.eraseFromParent();
1177 return true;
1178 }
1179 if (isNullOrNullSplat(SplatValMI, MRI)) {
1180 auto VL = buildDefaultVLOps(VecTy, MIB, MRI).second;
1181 MIB.buildInstr(RISCV::G_VMCLR_VL, {Dst}, {VL});
1182 MI.eraseFromParent();
1183 return true;
1184 }
1185
1186 // Handle non-constant mask splat (i.e. not sure if it's all zeros or all
1187 // ones) by promoting it to an s8 splat.
1188 LLT InterEltTy = LLT::scalar(8);
1189 LLT InterTy = VecTy.changeElementType(InterEltTy);
1190 auto ZExtSplatVal = MIB.buildZExt(InterEltTy, SplatVal);
1191 auto And =
1192 MIB.buildAnd(InterEltTy, ZExtSplatVal, MIB.buildConstant(InterEltTy, 1));
1193 auto LHS = MIB.buildSplatVector(InterTy, And);
1194 auto ZeroSplat =
1195 MIB.buildSplatVector(InterTy, MIB.buildConstant(InterEltTy, 0));
1196 MIB.buildICmp(CmpInst::Predicate::ICMP_NE, Dst, LHS, ZeroSplat);
1197 MI.eraseFromParent();
1198 return true;
1199}
1200
1201static LLT getLMUL1Ty(LLT VecTy) {
1202 assert(VecTy.getElementType().getSizeInBits() <= 64 &&
1203 "Unexpected vector LLT");
1205 VecTy.getElementType().getSizeInBits(),
1206 VecTy.getElementType());
1207}
1208
1209bool RISCVLegalizerInfo::legalizeExtractSubvector(MachineInstr &MI,
1210 MachineIRBuilder &MIB) const {
1211 GExtractSubvector &ES = cast<GExtractSubvector>(MI);
1212
1213 MachineRegisterInfo &MRI = *MIB.getMRI();
1214
1215 Register Dst = ES.getReg(0);
1216 Register Src = ES.getSrcVec();
1217 uint64_t Idx = ES.getIndexImm();
1218
1219 // With an index of 0 this is a cast-like subvector, which can be performed
1220 // with subregister operations.
1221 if (Idx == 0)
1222 return true;
1223
1224 LLT LitTy = MRI.getType(Dst);
1225 LLT BigTy = MRI.getType(Src);
1226
1227 if (LitTy.getElementType() == LLT::scalar(1)) {
1228 // We can't slide this mask vector up indexed by its i1 elements.
1229 // This poses a problem when we wish to insert a scalable vector which
1230 // can't be re-expressed as a larger type. Just choose the slow path and
1231 // extend to a larger type, then truncate back down.
1232 LLT ExtBigTy = BigTy.changeElementType(LLT::scalar(8));
1233 LLT ExtLitTy = LitTy.changeElementType(LLT::scalar(8));
1234 auto BigZExt = MIB.buildZExt(ExtBigTy, Src);
1235 auto ExtractZExt = MIB.buildExtractSubvector(ExtLitTy, BigZExt, Idx);
1236 auto SplatZero = MIB.buildSplatVector(
1237 ExtLitTy, MIB.buildConstant(ExtLitTy.getElementType(), 0));
1238 MIB.buildICmp(CmpInst::Predicate::ICMP_NE, Dst, ExtractZExt, SplatZero);
1239 MI.eraseFromParent();
1240 return true;
1241 }
1242
1243 // extract_subvector scales the index by vscale if the subvector is scalable,
1244 // and decomposeSubvectorInsertExtractToSubRegs takes this into account.
1245 const RISCVRegisterInfo *TRI = STI.getRegisterInfo();
1246 MVT LitTyMVT = getMVTForLLT(LitTy);
1247 auto Decompose =
1249 getMVTForLLT(BigTy), LitTyMVT, Idx, TRI);
1250 unsigned RemIdx = Decompose.second;
1251
1252 // If the Idx has been completely eliminated then this is a subvector extract
1253 // which naturally aligns to a vector register. These can easily be handled
1254 // using subregister manipulation.
1255 if (RemIdx == 0)
1256 return true;
1257
1258 // Else LitTy is M1 or smaller and may need to be slid down: if LitTy
1259 // was > M1 then the index would need to be a multiple of VLMAX, and so would
1260 // divide exactly.
1261 assert(
1264
1265 // If the vector type is an LMUL-group type, extract a subvector equal to the
1266 // nearest full vector register type.
1267 LLT InterLitTy = BigTy;
1268 Register Vec = Src;
1270 getLMUL1Ty(BigTy).getSizeInBits())) {
1271 // If BigTy has an LMUL > 1, then LitTy should have a smaller LMUL, and
1272 // we should have successfully decomposed the extract into a subregister.
1273 assert(Decompose.first != RISCV::NoSubRegister);
1274 InterLitTy = getLMUL1Ty(BigTy);
1275 // SDAG builds a TargetExtractSubreg. We cannot create a a Copy with SubReg
1276 // specified on the source Register (the equivalent) since generic virtual
1277 // register does not allow subregister index.
1278 Vec = MIB.buildExtractSubvector(InterLitTy, Src, Idx - RemIdx).getReg(0);
1279 }
1280
1281 // Slide this vector register down by the desired number of elements in order
1282 // to place the desired subvector starting at element 0.
1283 const LLT XLenTy(STI.getXLenVT());
1284 auto SlidedownAmt = MIB.buildVScale(XLenTy, RemIdx);
1285 auto [Mask, VL] = buildDefaultVLOps(InterLitTy, MIB, MRI);
1287 auto Slidedown = MIB.buildInstr(
1288 RISCV::G_VSLIDEDOWN_VL, {InterLitTy},
1289 {MIB.buildUndef(InterLitTy), Vec, SlidedownAmt, Mask, VL, Policy});
1290
1291 // Now the vector is in the right position, extract our final subvector. This
1292 // should resolve to a COPY.
1293 MIB.buildExtractSubvector(Dst, Slidedown, 0);
1294
1295 MI.eraseFromParent();
1296 return true;
1297}
1298
1299bool RISCVLegalizerInfo::legalizeInsertSubvector(MachineInstr &MI,
1300 LegalizerHelper &Helper,
1301 MachineIRBuilder &MIB) const {
1302 GInsertSubvector &IS = cast<GInsertSubvector>(MI);
1303
1304 MachineRegisterInfo &MRI = *MIB.getMRI();
1305
1306 Register Dst = IS.getReg(0);
1307 Register BigVec = IS.getBigVec();
1308 Register LitVec = IS.getSubVec();
1309 uint64_t Idx = IS.getIndexImm();
1310
1311 LLT BigTy = MRI.getType(BigVec);
1312 LLT LitTy = MRI.getType(LitVec);
1313
1314 if (Idx == 0 &&
1315 MRI.getVRegDef(BigVec)->getOpcode() == TargetOpcode::G_IMPLICIT_DEF)
1316 return true;
1317
1318 // We don't have the ability to slide mask vectors up indexed by their i1
1319 // elements; the smallest we can do is i8. Often we are able to bitcast to
1320 // equivalent i8 vectors. Otherwise, we can must zeroextend to equivalent i8
1321 // vectors and truncate down after the insert.
1322 if (LitTy.getElementType() == LLT::scalar(1)) {
1323 auto BigTyMinElts = BigTy.getElementCount().getKnownMinValue();
1324 auto LitTyMinElts = LitTy.getElementCount().getKnownMinValue();
1325 if (BigTyMinElts >= 8 && LitTyMinElts >= 8)
1326 return Helper.bitcast(
1327 IS, 0,
1329
1330 // We can't slide this mask vector up indexed by its i1 elements.
1331 // This poses a problem when we wish to insert a scalable vector which
1332 // can't be re-expressed as a larger type. Just choose the slow path and
1333 // extend to a larger type, then truncate back down.
1334 LLT ExtBigTy = BigTy.changeElementType(LLT::scalar(8));
1335 return Helper.widenScalar(IS, 0, ExtBigTy);
1336 }
1337
1338 const RISCVRegisterInfo *TRI = STI.getRegisterInfo();
1339 unsigned SubRegIdx, RemIdx;
1340 std::tie(SubRegIdx, RemIdx) =
1342 getMVTForLLT(BigTy), getMVTForLLT(LitTy), Idx, TRI);
1343
1344 TypeSize VecRegSize = TypeSize::getScalable(RISCV::RVVBitsPerBlock);
1346 STI.expandVScale(LitTy.getSizeInBits()).getKnownMinValue()));
1347 bool ExactlyVecRegSized =
1348 STI.expandVScale(LitTy.getSizeInBits())
1349 .isKnownMultipleOf(STI.expandVScale(VecRegSize));
1350
1351 // If the Idx has been completely eliminated and this subvector's size is a
1352 // vector register or a multiple thereof, or the surrounding elements are
1353 // undef, then this is a subvector insert which naturally aligns to a vector
1354 // register. These can easily be handled using subregister manipulation.
1355 if (RemIdx == 0 && ExactlyVecRegSized)
1356 return true;
1357
1358 // If the subvector is smaller than a vector register, then the insertion
1359 // must preserve the undisturbed elements of the register. We do this by
1360 // lowering to an EXTRACT_SUBVECTOR grabbing the nearest LMUL=1 vector type
1361 // (which resolves to a subregister copy), performing a VSLIDEUP to place the
1362 // subvector within the vector register, and an INSERT_SUBVECTOR of that
1363 // LMUL=1 type back into the larger vector (resolving to another subregister
1364 // operation). See below for how our VSLIDEUP works. We go via a LMUL=1 type
1365 // to avoid allocating a large register group to hold our subvector.
1366
1367 // VSLIDEUP works by leaving elements 0<i<OFFSET undisturbed, elements
1368 // OFFSET<=i<VL set to the "subvector" and vl<=i<VLMAX set to the tail policy
1369 // (in our case undisturbed). This means we can set up a subvector insertion
1370 // where OFFSET is the insertion offset, and the VL is the OFFSET plus the
1371 // size of the subvector.
1372 const LLT XLenTy(STI.getXLenVT());
1373 LLT InterLitTy = BigTy;
1374 Register AlignedExtract = BigVec;
1375 unsigned AlignedIdx = Idx - RemIdx;
1377 getLMUL1Ty(BigTy).getSizeInBits())) {
1378 InterLitTy = getLMUL1Ty(BigTy);
1379 // Extract a subvector equal to the nearest full vector register type. This
1380 // should resolve to a G_EXTRACT on a subreg.
1381 AlignedExtract =
1382 MIB.buildExtractSubvector(InterLitTy, BigVec, AlignedIdx).getReg(0);
1383 }
1384
1385 auto Insert = MIB.buildInsertSubvector(InterLitTy, MIB.buildUndef(InterLitTy),
1386 LitVec, 0);
1387
1388 auto [Mask, _] = buildDefaultVLOps(InterLitTy, MIB, MRI);
1389 auto VL = MIB.buildVScale(XLenTy, LitTy.getElementCount().getKnownMinValue());
1390
1391 // If we're inserting into the lowest elements, use a tail undisturbed
1392 // vmv.v.v.
1393 MachineInstrBuilder Inserted;
1394 bool NeedInsertSubvec =
1395 TypeSize::isKnownGT(BigTy.getSizeInBits(), InterLitTy.getSizeInBits());
1396 Register InsertedDst =
1397 NeedInsertSubvec ? MRI.createGenericVirtualRegister(InterLitTy) : Dst;
1398 if (RemIdx == 0) {
1399 Inserted = MIB.buildInstr(RISCV::G_VMV_V_V_VL, {InsertedDst},
1400 {AlignedExtract, Insert, VL});
1401 } else {
1402 auto SlideupAmt = MIB.buildVScale(XLenTy, RemIdx);
1403 // Construct the vector length corresponding to RemIdx + length(LitTy).
1404 VL = MIB.buildAdd(XLenTy, SlideupAmt, VL);
1405 // Use tail agnostic policy if we're inserting over InterLitTy's tail.
1406 ElementCount EndIndex =
1409 if (STI.expandVScale(EndIndex) ==
1410 STI.expandVScale(InterLitTy.getElementCount()))
1412
1413 Inserted =
1414 MIB.buildInstr(RISCV::G_VSLIDEUP_VL, {InsertedDst},
1415 {AlignedExtract, Insert, SlideupAmt, Mask, VL, Policy});
1416 }
1417
1418 // If required, insert this subvector back into the correct vector register.
1419 // This should resolve to an INSERT_SUBREG instruction.
1420 if (NeedInsertSubvec)
1421 MIB.buildInsertSubvector(Dst, BigVec, Inserted, AlignedIdx);
1422
1423 MI.eraseFromParent();
1424 return true;
1425}
1426
1427bool RISCVLegalizerInfo::legalizeBitreverse(MachineInstr &MI,
1428 MachineIRBuilder &MIB) const {
1429 assert(MI.getOpcode() == TargetOpcode::G_BITREVERSE && "Unexpected opcode");
1430
1431 if (!STI.hasStdExtZbkb())
1432 return false;
1433
1434 MachineRegisterInfo &MRI = *MIB.getMRI();
1435
1436 Register Dst = MI.getOperand(0).getReg();
1437 Register Src = MI.getOperand(1).getReg();
1438
1439 if (!MRI.getType(Dst).isScalar(8))
1440 return false;
1441
1442 auto WideSrc = MIB.buildAnyExt(sXLen, Src);
1443 auto Brev = MIB.buildInstr(RISCV::G_BREV8, {sXLen}, {WideSrc.getReg(0)});
1444 MIB.buildTrunc(Dst, Brev.getReg(0));
1445
1446 MI.eraseFromParent();
1447 return true;
1448}
1449
1450static unsigned getRISCVWOpcode(unsigned Opcode) {
1451 switch (Opcode) {
1452 default:
1453 llvm_unreachable("Unexpected opcode");
1454 case TargetOpcode::G_ASHR:
1455 return RISCV::G_SRAW;
1456 case TargetOpcode::G_LSHR:
1457 return RISCV::G_SRLW;
1458 case TargetOpcode::G_SHL:
1459 return RISCV::G_SLLW;
1460 case TargetOpcode::G_SDIV:
1461 return RISCV::G_DIVW;
1462 case TargetOpcode::G_UDIV:
1463 return RISCV::G_DIVUW;
1464 case TargetOpcode::G_UREM:
1465 return RISCV::G_REMUW;
1466 case TargetOpcode::G_ROTL:
1467 return RISCV::G_ROLW;
1468 case TargetOpcode::G_ROTR:
1469 return RISCV::G_RORW;
1470 case TargetOpcode::G_CTLZ:
1471 return RISCV::G_CLZW;
1472 case TargetOpcode::G_CTTZ:
1473 return RISCV::G_CTZW;
1474 case TargetOpcode::G_CTLS:
1475 return RISCV::G_CLSW;
1476 case TargetOpcode::G_FPTOSI:
1477 return RISCV::G_FCVT_W_RV64;
1478 case TargetOpcode::G_FPTOUI:
1479 return RISCV::G_FCVT_WU_RV64;
1480 }
1481}
1482
1485 LostDebugLocObserver &LocObserver) const {
1486 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
1487 MachineRegisterInfo &MRI = *MIRBuilder.getMRI();
1488 MachineFunction &MF = *MI.getParent()->getParent();
1489 switch (MI.getOpcode()) {
1490 default:
1491 // No idea what to do.
1492 return false;
1493 case TargetOpcode::G_ABS:
1494 return Helper.lowerAbsToMaxNeg(MI);
1495 case TargetOpcode::G_FCONSTANT: {
1496 const APFloat &FVal = MI.getOperand(1).getFPImm()->getValueAPF();
1497
1498 // Convert G_FCONSTANT to G_CONSTANT.
1499 Register DstReg = MI.getOperand(0).getReg();
1500 MIRBuilder.buildConstant(DstReg, FVal.bitcastToAPInt());
1501
1502 MI.eraseFromParent();
1503 return true;
1504 }
1505 case TargetOpcode::G_CONSTANT: {
1506 const Function &F = MF.getFunction();
1507 // TODO: if PSI and BFI are present, add " ||
1508 // llvm::shouldOptForSize(*CurMBB, PSI, BFI)".
1509 bool ShouldOptForSize = F.hasOptSize();
1510 const ConstantInt *ConstVal = MI.getOperand(1).getCImm();
1511 if (!shouldBeInConstantPool(ConstVal->getValue(), ShouldOptForSize))
1512 return true;
1513 return Helper.lowerConstant(MI);
1514 }
1515 case TargetOpcode::G_SUB:
1516 case TargetOpcode::G_ADD: {
1517 Helper.Observer.changingInstr(MI);
1518 Helper.widenScalarSrc(MI, sXLen, 1, TargetOpcode::G_ANYEXT);
1519 Helper.widenScalarSrc(MI, sXLen, 2, TargetOpcode::G_ANYEXT);
1520
1521 Register DstALU = MRI.createGenericVirtualRegister(sXLen);
1522
1523 MachineOperand &MO = MI.getOperand(0);
1524 MIRBuilder.setInsertPt(MIRBuilder.getMBB(), ++MIRBuilder.getInsertPt());
1525 auto DstSext = MIRBuilder.buildSExtInReg(sXLen, DstALU, 32);
1526
1527 MIRBuilder.buildInstr(TargetOpcode::G_TRUNC, {MO}, {DstSext});
1528 MO.setReg(DstALU);
1529
1530 Helper.Observer.changedInstr(MI);
1531 return true;
1532 }
1533 case TargetOpcode::G_ASHR:
1534 case TargetOpcode::G_LSHR:
1535 case TargetOpcode::G_SHL: {
1536 if (getIConstantVRegValWithLookThrough(MI.getOperand(2).getReg(), MRI)) {
1537 // We don't need a custom node for shift by constant. Just widen the
1538 // source and the shift amount.
1539 unsigned ExtOpc = TargetOpcode::G_ANYEXT;
1540 if (MI.getOpcode() == TargetOpcode::G_ASHR)
1541 ExtOpc = TargetOpcode::G_SEXT;
1542 else if (MI.getOpcode() == TargetOpcode::G_LSHR)
1543 ExtOpc = TargetOpcode::G_ZEXT;
1544
1545 Helper.Observer.changingInstr(MI);
1546 Helper.widenScalarSrc(MI, sXLen, 1, ExtOpc);
1547 Helper.widenScalarSrc(MI, sXLen, 2, TargetOpcode::G_ZEXT);
1548 Helper.widenScalarDst(MI, sXLen);
1549 Helper.Observer.changedInstr(MI);
1550 return true;
1551 }
1552
1553 Helper.Observer.changingInstr(MI);
1554 Helper.widenScalarSrc(MI, sXLen, 1, TargetOpcode::G_ANYEXT);
1555 Helper.widenScalarSrc(MI, sXLen, 2, TargetOpcode::G_ANYEXT);
1556 Helper.widenScalarDst(MI, sXLen);
1557 MI.setDesc(MIRBuilder.getTII().get(getRISCVWOpcode(MI.getOpcode())));
1558 Helper.Observer.changedInstr(MI);
1559 return true;
1560 }
1561 case TargetOpcode::G_SDIV:
1562 case TargetOpcode::G_UDIV:
1563 case TargetOpcode::G_UREM:
1564 case TargetOpcode::G_ROTL:
1565 case TargetOpcode::G_ROTR: {
1566 Helper.Observer.changingInstr(MI);
1567 Helper.widenScalarSrc(MI, sXLen, 1, TargetOpcode::G_ANYEXT);
1568 Helper.widenScalarSrc(MI, sXLen, 2, TargetOpcode::G_ANYEXT);
1569 Helper.widenScalarDst(MI, sXLen);
1570 MI.setDesc(MIRBuilder.getTII().get(getRISCVWOpcode(MI.getOpcode())));
1571 Helper.Observer.changedInstr(MI);
1572 return true;
1573 }
1574 case TargetOpcode::G_CTLZ:
1575 case TargetOpcode::G_CTTZ:
1576 case TargetOpcode::G_CTLS: {
1577 Helper.Observer.changingInstr(MI);
1578 Helper.widenScalarSrc(MI, sXLen, 1, TargetOpcode::G_ANYEXT);
1579 Helper.widenScalarDst(MI, sXLen);
1580 MI.setDesc(MIRBuilder.getTII().get(getRISCVWOpcode(MI.getOpcode())));
1581 Helper.Observer.changedInstr(MI);
1582 return true;
1583 }
1584 case TargetOpcode::G_FPTOSI:
1585 case TargetOpcode::G_FPTOUI: {
1586 Helper.Observer.changingInstr(MI);
1587 Helper.widenScalarDst(MI, sXLen);
1588 MI.setDesc(MIRBuilder.getTII().get(getRISCVWOpcode(MI.getOpcode())));
1590 Helper.Observer.changedInstr(MI);
1591 return true;
1592 }
1593 case TargetOpcode::G_LROUND: {
1594 // The (i32 any_lround) Pat is IsRV32-only; on RV64 lower to
1595 // riscv_fcvt_w_rv64 with FRM_RMM.
1596 Helper.Observer.changingInstr(MI);
1597 Helper.widenScalarDst(MI, sXLen);
1598 MI.setDesc(MIRBuilder.getTII().get(RISCV::G_FCVT_W_RV64));
1600 Helper.Observer.changedInstr(MI);
1601 return true;
1602 }
1603 case TargetOpcode::G_IS_FPCLASS: {
1604 Register GISFPCLASS = MI.getOperand(0).getReg();
1605 Register Src = MI.getOperand(1).getReg();
1606 const MachineOperand &ImmOp = MI.getOperand(2);
1607 MachineIRBuilder MIB(MI);
1608
1609 // Turn LLVM IR's floating point classes to that in RISC-V,
1610 // by simply rotating the 10-bit immediate right by two bits.
1611 APInt GFpClassImm(10, static_cast<uint64_t>(ImmOp.getImm()));
1612 auto FClassMask = MIB.buildConstant(sXLen, GFpClassImm.rotr(2).zext(XLen));
1613 auto ConstZero = MIB.buildConstant(sXLen, 0);
1614
1615 auto GFClass = MIB.buildInstr(RISCV::G_FCLASS, {sXLen}, {Src});
1616 auto And = MIB.buildAnd(sXLen, GFClass, FClassMask);
1617 MIB.buildICmp(CmpInst::ICMP_NE, GISFPCLASS, And, ConstZero);
1618
1619 MI.eraseFromParent();
1620 return true;
1621 }
1622 case TargetOpcode::G_BRJT:
1623 return legalizeBRJT(MI, MIRBuilder);
1624 case TargetOpcode::G_VASTART:
1625 return legalizeVAStart(MI, MIRBuilder);
1626 case TargetOpcode::G_VSCALE:
1627 return legalizeVScale(MI, MIRBuilder);
1628 case TargetOpcode::G_ZEXT:
1629 case TargetOpcode::G_SEXT:
1630 case TargetOpcode::G_ANYEXT:
1631 return legalizeExt(MI, MIRBuilder);
1632 case TargetOpcode::G_SPLAT_VECTOR:
1633 return legalizeSplatVector(MI, MIRBuilder);
1634 case TargetOpcode::G_EXTRACT_SUBVECTOR:
1635 return legalizeExtractSubvector(MI, MIRBuilder);
1636 case TargetOpcode::G_INSERT_SUBVECTOR:
1637 return legalizeInsertSubvector(MI, Helper, MIRBuilder);
1638 case TargetOpcode::G_BITREVERSE:
1639 return legalizeBitreverse(MI, MIRBuilder);
1640 case TargetOpcode::G_LOAD:
1641 case TargetOpcode::G_STORE:
1642 return legalizeLoadStore(MI, Helper, MIRBuilder);
1643 }
1644
1645 llvm_unreachable("expected switch to return");
1646}
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.
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...
MachineMemOperand * getMachineMemOperand(MachinePointerInfo PtrInfo, MachineMemOperand::Flags F, LLT MemTy, Align BaseAlignment, const MMOMetadata &Metadata=MMOMetadata(), SyncScope::ID SSID=SyncScope::System, AtomicOrdering Ordering=AtomicOrdering::NotAtomic, AtomicOrdering FailureOrdering=AtomicOrdering::NotAtomic)
getMachineMemOperand - Allocate a new MachineMemOperand.
const MachineJumpTableInfo * getJumpTableInfo() const
getJumpTableInfo - Return the jump table info object for the current function.
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.