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