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 // On RV64 the 64-bit counter CSRs (cycle/time) are read directly. On RV32
546 // they are custom-legally lowered to a re-read-the-high-half loop (see
547 // legalizeReadCounter).
548 getActionDefinitionsBuilder({G_READCYCLECOUNTER, G_READSTEADYCOUNTER})
549 .legalFor(ST.is64Bit(), {s64})
550 .customFor(!ST.is64Bit(), {s64});
551
552 // FP Operations
553
554 // FIXME: Support s128 for rv32 when libcall handling is able to use sret.
555 getActionDefinitionsBuilder({G_FADD, G_FSUB, G_FMUL, G_FDIV, G_FMA, G_FSQRT,
556 G_FMAXNUM, G_FMINNUM, G_FMAXIMUMNUM,
557 G_FMINIMUMNUM})
558 .legalFor(ST.hasStdExtF(), {s32})
559 .legalFor(ST.hasStdExtD(), {s64})
560 .legalFor(ST.hasStdExtZfh(), {s16})
561 .libcallFor({s32, s64})
562 .libcallFor(ST.is64Bit(), {s128});
563
564 getActionDefinitionsBuilder({G_FNEG, G_FABS})
565 .legalFor(ST.hasStdExtF(), {s32})
566 .legalFor(ST.hasStdExtD(), {s64})
567 .legalFor(ST.hasStdExtZfh(), {s16})
568 .lowerFor({s32, s64, s128});
569
570 getActionDefinitionsBuilder(G_FREM)
571 .libcallFor({s32, s64})
572 .libcallFor(ST.is64Bit(), {s128})
573 .minScalar(0, s32)
574 .scalarize(0);
575
576 getActionDefinitionsBuilder(G_FCOPYSIGN)
577 .legalFor(ST.hasStdExtF(), {{s32, s32}})
578 .legalFor(ST.hasStdExtD(), {{s64, s64}, {s32, s64}, {s64, s32}})
579 .legalFor(ST.hasStdExtZfh(), {{s16, s16}, {s16, s32}, {s32, s16}})
580 .legalFor(ST.hasStdExtZfh() && ST.hasStdExtD(), {{s16, s64}, {s64, s16}})
581 .lower();
582
583 // FIXME: Use Zfhmin.
584 getActionDefinitionsBuilder(G_FPTRUNC)
585 .legalFor(ST.hasStdExtD(), {{s32, s64}})
586 .legalFor(ST.hasStdExtZfh(), {{s16, s32}})
587 .legalFor(ST.hasStdExtZfh() && ST.hasStdExtD(), {{s16, s64}})
588 .libcallFor({{s32, s64}})
589 .libcallFor(ST.is64Bit(), {{s32, s128}, {s64, s128}});
590 getActionDefinitionsBuilder(G_FPEXT)
591 .legalFor(ST.hasStdExtD(), {{s64, s32}})
592 .legalFor(ST.hasStdExtZfh(), {{s32, s16}})
593 .legalFor(ST.hasStdExtZfh() && ST.hasStdExtD(), {{s64, s16}})
594 .libcallFor({{s64, s32}})
595 .libcallFor(ST.is64Bit(), {{s128, s32}, {s128, s64}});
596
597 getActionDefinitionsBuilder(G_FCMP)
598 .legalFor(ST.hasStdExtF(), {{sXLen, s32}})
599 .legalFor(ST.hasStdExtD(), {{sXLen, s64}})
600 .legalFor(ST.hasStdExtZfh(), {{sXLen, s16}})
601 .clampScalar(0, sXLen, sXLen)
602 .libcallFor({{sXLen, s32}, {sXLen, s64}})
603 .libcallFor(ST.is64Bit(), {{sXLen, s128}});
604
605 // TODO: Support vector version of G_IS_FPCLASS.
606 getActionDefinitionsBuilder(G_IS_FPCLASS)
607 .customFor(ST.hasStdExtF(), {{s1, s32}})
608 .customFor(ST.hasStdExtD(), {{s1, s64}})
609 .customFor(ST.hasStdExtZfh(), {{s1, s16}})
610 .lower();
611
612 getActionDefinitionsBuilder(G_FCONSTANT)
613 .legalFor(ST.hasStdExtF(), {s32})
614 .legalFor(ST.hasStdExtD(), {s64})
615 .legalFor(ST.hasStdExtZfh(), {s16})
616 .customFor(!ST.is64Bit(), {s32})
617 .customFor(ST.is64Bit(), {s32, s64})
618 .lowerFor({s64, s128});
619
620 getActionDefinitionsBuilder({G_FPTOSI, G_FPTOUI})
621 .legalFor(ST.hasStdExtF(), {{sXLen, s32}})
622 .legalFor(ST.hasStdExtD(), {{sXLen, s64}})
623 .legalFor(ST.hasStdExtZfh(), {{sXLen, s16}})
624 .customFor(ST.is64Bit() && ST.hasStdExtF(), {{s32, s32}})
625 .customFor(ST.is64Bit() && ST.hasStdExtD(), {{s32, s64}})
626 .customFor(ST.is64Bit() && ST.hasStdExtZfh(), {{s32, s16}})
627 .widenScalarToNextPow2(0)
628 .minScalar(0, s32)
629 .libcallFor({{s32, s32}, {s64, s32}, {s32, s64}, {s64, s64}})
630 .libcallFor(ST.is64Bit(), {{s32, s128}, {s64, s128}}) // FIXME RV32.
631 .libcallFor(ST.is64Bit(), {{s128, s32}, {s128, s64}, {s128, s128}});
632
633 getActionDefinitionsBuilder({G_LROUND, G_LLROUND})
634 .legalFor(ST.hasStdExtF(), {{sXLen, s32}})
635 .legalFor(ST.hasStdExtD(), {{sXLen, s64}})
636 .legalFor(ST.hasStdExtZfh(), {{sXLen, s16}})
637 .customFor(ST.is64Bit() && ST.hasStdExtF(), {{s32, s32}})
638 .customFor(ST.is64Bit() && ST.hasStdExtD(), {{s32, s64}})
639 .customFor(ST.is64Bit() && ST.hasStdExtZfh(), {{s32, s16}})
640 .widenScalarIf(typeIs(1, s16), LegalizeMutations::changeTo(1, s32))
641 .libcallFor({{s32, s32},
642 {s64, s32},
643 {s32, s64},
644 {s64, s64},
645 {s32, s128},
646 {s64, s128}});
647
648 getActionDefinitionsBuilder({G_SITOFP, G_UITOFP})
649 .legalFor(ST.hasStdExtF(), {{s32, sXLen}})
650 .legalFor(ST.hasStdExtD(), {{s64, sXLen}})
651 .legalFor(ST.hasStdExtZfh(), {{s16, sXLen}})
652 .widenScalarToNextPow2(1)
653 // Promote to XLen if the operation is legal.
654 .widenScalarIf(
655 [=, &ST](const LegalityQuery &Query) {
656 return Query.Types[0].isScalar() && Query.Types[1].isScalar() &&
657 (Query.Types[1].getSizeInBits() < ST.getXLen()) &&
658 ((ST.hasStdExtF() && Query.Types[0].getSizeInBits() == 32) ||
659 (ST.hasStdExtD() && Query.Types[0].getSizeInBits() == 64) ||
660 (ST.hasStdExtZfh() &&
661 Query.Types[0].getSizeInBits() == 16));
662 },
664 // Otherwise only promote to s32 since we have si libcalls.
665 .minScalar(1, s32)
666 .libcallFor({{s32, s32}, {s64, s32}, {s32, s64}, {s64, s64}})
667 .libcallFor(ST.is64Bit(), {{s128, s32}, {s128, s64}}) // FIXME RV32.
668 .libcallFor(ST.is64Bit(), {{s32, s128}, {s64, s128}, {s128, s128}});
669
670 // FIXME: We can do custom inline expansion like SelectionDAG.
671 getActionDefinitionsBuilder({G_FCEIL, G_FFLOOR, G_FRINT, G_FNEARBYINT,
672 G_INTRINSIC_TRUNC, G_INTRINSIC_ROUND,
673 G_INTRINSIC_ROUNDEVEN})
674 .legalFor(ST.hasStdExtZfa(), {s32})
675 .legalFor(ST.hasStdExtZfa() && ST.hasStdExtD(), {s64})
676 .legalFor(ST.hasStdExtZfa() && ST.hasStdExtZfh(), {s16})
677 .libcallFor({s32, s64})
678 .libcallFor(ST.is64Bit(), {s128});
679
680 getActionDefinitionsBuilder({G_FMAXIMUM, G_FMINIMUM})
681 .legalFor(ST.hasStdExtZfa(), {s32})
682 .legalFor(ST.hasStdExtZfa() && ST.hasStdExtD(), {s64})
683 .legalFor(ST.hasStdExtZfa() && ST.hasStdExtZfh(), {s16});
684
685 getActionDefinitionsBuilder({G_FCOS, G_FSIN, G_FTAN, G_FPOW, G_FLOG, G_FLOG2,
686 G_FLOG10, G_FEXP, G_FEXP2, G_FEXP10, G_FACOS,
687 G_FASIN, G_FATAN, G_FATAN2, G_FCOSH, G_FSINH,
688 G_FTANH, G_FMODF})
689 .libcallFor({s32, s64})
690 .libcallFor(ST.is64Bit(), {s128});
691 getActionDefinitionsBuilder({G_FPOWI, G_FLDEXP})
692 .libcallFor({{s32, s32}, {s64, s32}})
693 .libcallFor(ST.is64Bit(), {s128, s32});
694
695 getActionDefinitionsBuilder(G_FCANONICALIZE)
696 .legalFor(ST.hasStdExtF(), {s32})
697 .legalFor(ST.hasStdExtD(), {s64})
698 .legalFor(ST.hasStdExtZfh(), {s16});
699
700 getActionDefinitionsBuilder(G_VASTART).customFor({p0});
701
702 // va_list must be a pointer, but most sized types are pretty easy to handle
703 // as the destination.
704 getActionDefinitionsBuilder(G_VAARG)
705 // TODO: Implement narrowScalar and widenScalar for G_VAARG for types
706 // other than sXLen.
707 .clampScalar(0, sXLen, sXLen)
708 .lowerForCartesianProduct({sXLen, p0}, {p0});
709
710 getActionDefinitionsBuilder(G_VSCALE)
711 .clampScalar(0, sXLen, sXLen)
712 .customFor({sXLen});
713
714 auto &SplatActions =
715 getActionDefinitionsBuilder(G_SPLAT_VECTOR)
716 .legalIf(all(typeIsLegalIntOrFPVec(0, IntOrFPVecTys, ST),
717 typeIs(1, sXLen)))
718 .customIf(all(typeIsLegalBoolVec(0, BoolVecTys, ST), typeIs(1, s1)));
719 // Handle case of s64 element vectors on RV32. If the subtarget does not have
720 // f64, then try to lower it to G_SPLAT_VECTOR_SPLIT_64_VL. If the subtarget
721 // does have f64, then we don't know whether the type is an f64 or an i64,
722 // so mark the G_SPLAT_VECTOR as legal and decide later what to do with it,
723 // depending on how the instructions it consumes are legalized. They are not
724 // legalized yet since legalization is in reverse postorder, so we cannot
725 // make the decision at this moment.
726 if (XLen == 32) {
727 if (ST.hasVInstructionsF64() && ST.hasStdExtD())
728 SplatActions.legalIf(all(
729 typeInSet(0, {nxv1s64, nxv2s64, nxv4s64, nxv8s64}), typeIs(1, s64)));
730 else if (ST.hasVInstructionsI64())
731 SplatActions.customIf(all(
732 typeInSet(0, {nxv1s64, nxv2s64, nxv4s64, nxv8s64}), typeIs(1, s64)));
733 }
734
735 SplatActions.clampScalar(1, sXLen, sXLen);
736
737 LegalityPredicate ExtractSubvecBitcastPred = [=](const LegalityQuery &Query) {
738 LLT DstTy = Query.Types[0];
739 LLT SrcTy = Query.Types[1];
740 return DstTy.getElementType() == LLT::scalar(1) &&
741 DstTy.getElementCount().getKnownMinValue() >= 8 &&
742 SrcTy.getElementCount().getKnownMinValue() >= 8;
743 };
744 getActionDefinitionsBuilder(G_EXTRACT_SUBVECTOR)
745 // We don't have the ability to slide mask vectors down indexed by their
746 // i1 elements; the smallest we can do is i8. Often we are able to bitcast
747 // to equivalent i8 vectors.
748 .bitcastIf(
749 all(typeIsLegalBoolVec(0, BoolVecTys, ST),
750 typeIsLegalBoolVec(1, BoolVecTys, ST), ExtractSubvecBitcastPred),
751 [=](const LegalityQuery &Query) {
752 LLT CastTy = LLT::vector(
753 Query.Types[0].getElementCount().divideCoefficientBy(8), 8);
754 return std::pair(0, CastTy);
755 })
756 .customIf(LegalityPredicates::any(
757 all(typeIsLegalBoolVec(0, BoolVecTys, ST),
758 typeIsLegalBoolVec(1, BoolVecTys, ST)),
759 all(typeIsLegalIntOrFPVec(0, IntOrFPVecTys, ST),
760 typeIsLegalIntOrFPVec(1, IntOrFPVecTys, ST))));
761
762 getActionDefinitionsBuilder(G_INSERT_SUBVECTOR)
763 .customIf(all(typeIsLegalBoolVec(0, BoolVecTys, ST),
764 typeIsLegalBoolVec(1, BoolVecTys, ST)))
765 .customIf(all(typeIsLegalIntOrFPVec(0, IntOrFPVecTys, ST),
766 typeIsLegalIntOrFPVec(1, IntOrFPVecTys, ST)));
767
768 getActionDefinitionsBuilder(G_ATOMIC_CMPXCHG_WITH_SUCCESS)
769 .lowerIf(all(typeInSet(0, {s8, s16, s32, s64}), typeIs(2, p0)));
770
771 getActionDefinitionsBuilder({G_ATOMIC_CMPXCHG, G_ATOMICRMW_ADD,
772 G_ATOMICRMW_XCHG, G_ATOMICRMW_AND,
773 G_ATOMICRMW_OR, G_ATOMICRMW_XOR})
774 .legalFor(ST.hasStdExtA(), {{sXLen, p0}})
775 .libcallFor(!ST.hasStdExtA(), {{s8, p0}, {s16, p0}, {s32, p0}, {s64, p0}})
776 .clampScalar(0, sXLen, sXLen);
777
778 getActionDefinitionsBuilder(G_ATOMICRMW_SUB)
779 .libcallFor(!ST.hasStdExtA(), {{s8, p0}, {s16, p0}, {s32, p0}, {s64, p0}})
780 .clampScalar(0, sXLen, sXLen)
781 .lower();
782
783 getActionDefinitionsBuilder(
784 {G_ATOMICRMW_MAX, G_ATOMICRMW_MIN, G_ATOMICRMW_UMAX, G_ATOMICRMW_UMIN})
785 .legalFor(ST.hasStdExtA(), {{sXLen, p0}})
786 .clampScalar(0, sXLen, sXLen)
787 .unsupported();
788
789 getActionDefinitionsBuilder(G_PREFETCH).legalIf(typeIs(0, p0));
790
791 LegalityPredicate InsertVectorEltPred = [=](const LegalityQuery &Query) {
792 LLT VecTy = Query.Types[0];
793 LLT EltTy = Query.Types[1];
794 return VecTy.getElementType() == EltTy;
795 };
796
797 getActionDefinitionsBuilder(G_INSERT_VECTOR_ELT)
798 .legalIf(all(typeIsLegalIntOrFPVec(0, IntOrFPVecTys, ST),
799 InsertVectorEltPred, typeIs(2, sXLen)))
800 .legalIf(all(typeIsLegalBoolVec(0, BoolVecTys, ST), InsertVectorEltPred,
801 typeIs(2, sXLen)));
802
803 getActionDefinitionsBuilder({G_INTRINSIC, G_INTRINSIC_W_SIDE_EFFECTS})
804 .alwaysLegal();
805
806 getActionDefinitionsBuilder(G_FENCE).alwaysLegal();
807
808 getActionDefinitionsBuilder({G_TRAP, G_DEBUGTRAP, G_UBSANTRAP}).alwaysLegal();
809
810 verify(*ST.getInstrInfo());
811}
812
814 MachineInstr &MI) const {
815 Intrinsic::ID IntrinsicID = cast<GIntrinsic>(MI).getIntrinsicID();
816
818 RISCVVIntrinsicsTable::getRISCVVIntrinsicInfo(IntrinsicID)) {
819 if (II->hasScalarOperand() && !II->IsFPIntrinsic) {
820 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
821 MachineRegisterInfo &MRI = *MIRBuilder.getMRI();
822
823 auto OldScalar = MI.getOperand(II->ScalarOperand + 2).getReg();
824 // Legalize integer vx form intrinsic.
825 if (MRI.getType(OldScalar).isScalar()) {
826 if (MRI.getType(OldScalar).getSizeInBits() < sXLen.getSizeInBits()) {
827 Helper.Observer.changingInstr(MI);
828 Helper.widenScalarSrc(MI, sXLen, II->ScalarOperand + 2,
829 TargetOpcode::G_ANYEXT);
830 Helper.Observer.changedInstr(MI);
831 } else if (MRI.getType(OldScalar).getSizeInBits() >
832 sXLen.getSizeInBits()) {
833 // TODO: i64 in riscv32.
834 return false;
835 }
836 }
837 }
838 return true;
839 }
840
841 switch (IntrinsicID) {
842 default:
843 return false;
844 case Intrinsic::vacopy: {
845 // vacopy arguments must be legal because of the intrinsic signature.
846 // No need to check here.
847
848 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
849 MachineRegisterInfo &MRI = *MIRBuilder.getMRI();
850 MachineFunction &MF = *MI.getMF();
851 const DataLayout &DL = MIRBuilder.getDataLayout();
852 LLVMContext &Ctx = MF.getFunction().getContext();
853
854 Register DstLst = MI.getOperand(1).getReg();
855 LLT PtrTy = MRI.getType(DstLst);
856
857 // Load the source va_list
858 Align Alignment = DL.getABITypeAlign(getTypeForLLT(PtrTy, Ctx));
860 MachinePointerInfo(), MachineMemOperand::MOLoad, PtrTy, Alignment);
861 auto Tmp = MIRBuilder.buildLoad(PtrTy, MI.getOperand(2), *LoadMMO);
862
863 // Store the result in the destination va_list
866 MIRBuilder.buildStore(Tmp, DstLst, *StoreMMO);
867
868 MI.eraseFromParent();
869 return true;
870 }
871 case Intrinsic::riscv_vsetvli:
872 case Intrinsic::riscv_vsetvlimax:
873 case Intrinsic::riscv_masked_atomicrmw_add:
874 case Intrinsic::riscv_masked_atomicrmw_sub:
875 case Intrinsic::riscv_masked_atomicrmw_xchg:
876 case Intrinsic::riscv_masked_atomicrmw_max:
877 case Intrinsic::riscv_masked_atomicrmw_min:
878 case Intrinsic::riscv_masked_atomicrmw_umax:
879 case Intrinsic::riscv_masked_atomicrmw_umin:
880 case Intrinsic::riscv_masked_cmpxchg:
881 return true;
882 }
883}
884
885bool RISCVLegalizerInfo::legalizeVAStart(MachineInstr &MI,
886 MachineIRBuilder &MIRBuilder) const {
887 // Stores the address of the VarArgsFrameIndex slot into the memory location
888 assert(MI.getOpcode() == TargetOpcode::G_VASTART);
889 MachineFunction *MF = MI.getParent()->getParent();
891 int FI = FuncInfo->getVarArgsFrameIndex();
892 LLT AddrTy = MIRBuilder.getMRI()->getType(MI.getOperand(0).getReg());
893 auto FINAddr = MIRBuilder.buildFrameIndex(AddrTy, FI);
894 assert(MI.hasOneMemOperand());
895 MIRBuilder.buildStore(FINAddr, MI.getOperand(0).getReg(),
896 *MI.memoperands()[0]);
897 MI.eraseFromParent();
898 return true;
899}
900
901bool RISCVLegalizerInfo::legalizeReadCounter(
902 MachineInstr &MI, MachineIRBuilder &MIRBuilder,
903 GISelChangeObserver &Observer) const {
904 assert((MI.getOpcode() == TargetOpcode::G_READCYCLECOUNTER ||
905 MI.getOpcode() == TargetOpcode::G_READSTEADYCOUNTER) &&
906 "Unexpected opcode");
907 assert(!STI.is64Bit() && "READCYCLECOUNTER/READSTEADYCOUNTER only "
908 "has custom type legalization on riscv32");
909
910 // On RV32 a 64-bit counter CSR must be read as two 32-bit halves. Because
911 // the count may wrap between the two reads, re-read the high half and loop
912 // until the two high reads agree.
913 int64_t LoCounter, HiCounter;
914 if (MI.getOpcode() == TargetOpcode::G_READCYCLECOUNTER) {
915 LoCounter = RISCVSysReg::cycle;
916 HiCounter = RISCVSysReg::cycleh;
917 } else {
918 LoCounter = RISCVSysReg::time;
919 HiCounter = RISCVSysReg::timeh;
920 }
921
922 MachineBasicBlock *BB = MI.getParent();
923 MachineFunction &MF = *BB->getParent();
924 const BasicBlock *LLVMBB = BB->getBasicBlock();
925 DebugLoc DL = MI.getDebugLoc();
926 MachineRegisterInfo &MRI = *MIRBuilder.getMRI();
927
928 // Split BB into an entry that falls through into a loop block, and a done
929 // block that receives the remainder of BB and its original successors.
930 MachineFunction::iterator It = std::next(BB->getIterator());
931 MachineBasicBlock *LoopMBB = MF.CreateMachineBasicBlock(LLVMBB);
932 MachineBasicBlock *DoneMBB = MF.CreateMachineBasicBlock(LLVMBB);
933 MF.insert(It, LoopMBB);
934 MF.insert(It, DoneMBB);
935
936 // Splice the instructions after the readcyclecounter into DoneMBB, notifying
937 // the observer about each moved instruction so CSEInfo stays consistent.
938 for (MachineBasicBlock::iterator I = std::next(MI.getIterator()),
939 E = BB->end();
940 I != E; ++I)
941 Observer.changingInstr(*I);
942 DoneMBB->splice(DoneMBB->begin(), BB,
943 std::next(MachineBasicBlock::iterator(MI)), BB->end());
944 for (MachineInstr &MovedMI : DoneMBB->instrs())
945 Observer.changedInstr(MovedMI);
947 BB->addSuccessor(LoopMBB);
948
949 LLT S32 = LLT::scalar(32);
950 // Generic vregs carry the s32 type for G_MERGE_VALUES below, but are also
951 // constrained to GPR so the target CSRRS/BNE instructions satisfy the
952 // verifier's register-class constraints.
953 auto CreateGPR = [&]() {
955 MRI.setRegClass(R, &RISCV::GPRRegClass);
956 return R;
957 };
958 Register LoReg = CreateGPR();
959 Register HiReg = CreateGPR();
960 Register ReadAgainReg = CreateGPR();
961
962 // read:
963 // csrrs HiReg, counterh # high word
964 // csrrs LoReg, counter # low word
965 // csrrs ReadAgainReg, counterh
966 // bne HiReg, ReadAgainReg, read
967 // Emit the target instructions directly with BuildMI.
968 const RISCVInstrInfo *TII = STI.getInstrInfo();
969 BuildMI(LoopMBB, DL, TII->get(RISCV::CSRRS), HiReg)
970 .addImm(HiCounter)
971 .addReg(RISCV::X0);
972 BuildMI(LoopMBB, DL, TII->get(RISCV::CSRRS), LoReg)
973 .addImm(LoCounter)
974 .addReg(RISCV::X0);
975 BuildMI(LoopMBB, DL, TII->get(RISCV::CSRRS), ReadAgainReg)
976 .addImm(HiCounter)
977 .addReg(RISCV::X0);
978
979 BuildMI(LoopMBB, DL, TII->get(RISCV::BNE))
980 .addReg(HiReg)
981 .addReg(ReadAgainReg)
982 .addMBB(LoopMBB);
983
984 LoopMBB->addSuccessor(LoopMBB);
985 LoopMBB->addSuccessor(DoneMBB);
986
987 // Re-pair the two halves into the 64-bit result.
988 Register DstReg = MI.getOperand(0).getReg();
989 Observer.erasingInstr(MI);
990 MI.eraseFromParent();
991
992 MIRBuilder.setInsertPt(*DoneMBB, DoneMBB->begin());
993 MIRBuilder.setDebugLoc(DL);
994 MIRBuilder.buildMergeValues(DstReg, {LoReg, HiReg});
995 return true;
996}
997
998bool RISCVLegalizerInfo::legalizeBRJT(MachineInstr &MI,
999 MachineIRBuilder &MIRBuilder) const {
1000 MachineRegisterInfo &MRI = *MIRBuilder.getMRI();
1001 auto &MF = *MI.getParent()->getParent();
1002 const MachineJumpTableInfo *MJTI = MF.getJumpTableInfo();
1003 unsigned EntrySize = MJTI->getEntrySize(MF.getDataLayout());
1004
1005 Register PtrReg = MI.getOperand(0).getReg();
1006 LLT PtrTy = MRI.getType(PtrReg);
1007 Register IndexReg = MI.getOperand(2).getReg();
1008 LLT IndexTy = MRI.getType(IndexReg);
1009
1010 if (!isPowerOf2_32(EntrySize))
1011 return false;
1012
1013 auto ShiftAmt = MIRBuilder.buildConstant(IndexTy, Log2_32(EntrySize));
1014 IndexReg = MIRBuilder.buildShl(IndexTy, IndexReg, ShiftAmt).getReg(0);
1015
1016 auto Addr = MIRBuilder.buildPtrAdd(PtrTy, PtrReg, IndexReg);
1017
1018 MachineMemOperand *MMO = MF.getMachineMemOperand(
1020 EntrySize, Align(MJTI->getEntryAlignment(MF.getDataLayout())));
1021
1022 Register TargetReg;
1023 switch (MJTI->getEntryKind()) {
1024 default:
1025 return false;
1027 // For PIC, the sequence is:
1028 // BRIND(load(Jumptable + index) + RelocBase)
1029 // RelocBase can be JumpTable, GOT or some sort of global base.
1030 unsigned LoadOpc =
1031 STI.is64Bit() ? TargetOpcode::G_SEXTLOAD : TargetOpcode::G_LOAD;
1032 auto Load = MIRBuilder.buildLoadInstr(LoadOpc, IndexTy, Addr, *MMO);
1033 TargetReg = MIRBuilder.buildPtrAdd(PtrTy, PtrReg, Load).getReg(0);
1034 break;
1035 }
1037 auto Load = MIRBuilder.buildLoadInstr(TargetOpcode::G_SEXTLOAD, IndexTy,
1038 Addr, *MMO);
1039 TargetReg = MIRBuilder.buildIntToPtr(PtrTy, Load).getReg(0);
1040 break;
1041 }
1043 TargetReg = MIRBuilder.buildLoad(PtrTy, Addr, *MMO).getReg(0);
1044 break;
1045 }
1046
1047 MIRBuilder.buildBrIndirect(TargetReg);
1048
1049 MI.eraseFromParent();
1050 return true;
1051}
1052
1053bool RISCVLegalizerInfo::shouldBeInConstantPool(const APInt &APImm,
1054 bool ShouldOptForSize) const {
1055 assert(APImm.getBitWidth() == 32 || APImm.getBitWidth() == 64);
1056 int64_t Imm = APImm.getSExtValue();
1057 // All simm32 constants should be handled by isel.
1058 // NOTE: The getMaxBuildIntsCost call below should return a value >= 2 making
1059 // this check redundant, but small immediates are common so this check
1060 // should have better compile time.
1061 if (isInt<32>(Imm))
1062 return false;
1063
1064 // We only need to cost the immediate, if constant pool lowering is enabled.
1065 if (!STI.useConstantPoolForLargeInts())
1066 return false;
1067
1069 if (Seq.size() <= STI.getMaxBuildIntsCost())
1070 return false;
1071
1072 // Optimizations below are disabled for opt size. If we're optimizing for
1073 // size, use a constant pool.
1074 if (ShouldOptForSize)
1075 return true;
1076 //
1077 // Special case. See if we can build the constant as (ADD (SLLI X, C), X) do
1078 // that if it will avoid a constant pool.
1079 // It will require an extra temporary register though.
1080 // If we have Zba we can use (ADD_UW X, (SLLI X, 32)) to handle cases where
1081 // low and high 32 bits are the same and bit 31 and 63 are set.
1082 unsigned ShiftAmt, AddOpc;
1083 RISCVMatInt::InstSeq SeqLo =
1084 RISCVMatInt::generateTwoRegInstSeq(Imm, STI, ShiftAmt, AddOpc);
1085 return !(!SeqLo.empty() && (SeqLo.size() + 2) <= STI.getMaxBuildIntsCost());
1086}
1087
1088bool RISCVLegalizerInfo::legalizeVScale(MachineInstr &MI,
1089 MachineIRBuilder &MIB) const {
1090 Register Dst = MI.getOperand(0).getReg();
1091
1092 // We define our scalable vector types for lmul=1 to use a 64 bit known
1093 // minimum size. e.g. <vscale x 2 x i32>. VLENB is in bytes so we calculate
1094 // vscale as VLENB / 8.
1095 static_assert(RISCV::RVVBitsPerBlock == 64, "Unexpected bits per block!");
1096 if (STI.getRealMinVLen() < RISCV::RVVBitsPerBlock)
1097 // Support for VLEN==32 is incomplete.
1098 return false;
1099
1100 // We assume VLENB is a multiple of 8. We manually choose the best shift
1101 // here because SimplifyDemandedBits isn't always able to simplify it.
1102 uint64_t Val = MI.getOperand(1).getCImm()->getZExtValue();
1103 if (isPowerOf2_64(Val)) {
1104 uint64_t Log2 = Log2_64(Val);
1105 if (Log2 < 3) {
1106 auto VLENB = MIB.buildInstr(RISCV::G_READ_VLENB, {sXLen}, {});
1107 MIB.buildLShr(Dst, VLENB, MIB.buildConstant(sXLen, 3 - Log2),
1109 } else if (Log2 > 3) {
1110 auto VLENB = MIB.buildInstr(RISCV::G_READ_VLENB, {sXLen}, {});
1111 MIB.buildShl(Dst, VLENB, MIB.buildConstant(sXLen, Log2 - 3));
1112 } else {
1113 MIB.buildInstr(RISCV::G_READ_VLENB, {Dst}, {});
1114 }
1115 } else if ((Val % 8) == 0) {
1116 // If the multiplier is a multiple of 8, scale it down to avoid needing
1117 // to shift the VLENB value.
1118 auto VLENB = MIB.buildInstr(RISCV::G_READ_VLENB, {sXLen}, {});
1119 MIB.buildMul(Dst, VLENB, MIB.buildConstant(sXLen, Val / 8));
1120 } else {
1121 auto VLENB = MIB.buildInstr(RISCV::G_READ_VLENB, {sXLen}, {});
1122 auto VScale = MIB.buildLShr(sXLen, VLENB, MIB.buildConstant(sXLen, 3),
1124 MIB.buildMul(Dst, VScale, MIB.buildConstant(sXLen, Val));
1125 }
1126 MI.eraseFromParent();
1127 return true;
1128}
1129
1130// Custom-lower extensions from mask vectors by using a vselect either with 1
1131// for zero/any-extension or -1 for sign-extension:
1132// (vXiN = (s|z)ext vXi1:vmask) -> (vXiN = vselect vmask, (-1 or 1), 0)
1133// Note that any-extension is lowered identically to zero-extension.
1134bool RISCVLegalizerInfo::legalizeExt(MachineInstr &MI,
1135 MachineIRBuilder &MIB) const {
1136
1137 unsigned Opc = MI.getOpcode();
1138 assert(Opc == TargetOpcode::G_ZEXT || Opc == TargetOpcode::G_SEXT ||
1139 Opc == TargetOpcode::G_ANYEXT);
1140
1141 MachineRegisterInfo &MRI = *MIB.getMRI();
1142 Register Dst = MI.getOperand(0).getReg();
1143 Register Src = MI.getOperand(1).getReg();
1144
1145 LLT DstTy = MRI.getType(Dst);
1146 int64_t ExtTrueVal = Opc == TargetOpcode::G_SEXT ? -1 : 1;
1147 LLT DstEltTy = DstTy.getElementType();
1148 auto SplatZero = MIB.buildSplatVector(DstTy, MIB.buildConstant(DstEltTy, 0));
1149 auto SplatTrue =
1150 MIB.buildSplatVector(DstTy, MIB.buildConstant(DstEltTy, ExtTrueVal));
1151 MIB.buildSelect(Dst, Src, SplatTrue, SplatZero);
1152
1153 MI.eraseFromParent();
1154 return true;
1155}
1156
1157bool RISCVLegalizerInfo::legalizeLoadStore(MachineInstr &MI,
1158 LegalizerHelper &Helper,
1159 MachineIRBuilder &MIB) const {
1161 "Machine instructions must be Load/Store.");
1162 MachineRegisterInfo &MRI = *MIB.getMRI();
1163 MachineFunction *MF = MI.getMF();
1164 const DataLayout &DL = MIB.getDataLayout();
1165 LLVMContext &Ctx = MF->getFunction().getContext();
1166
1167 Register DstReg = MI.getOperand(0).getReg();
1168 LLT DataTy = MRI.getType(DstReg);
1169 if (!DataTy.isVector())
1170 return false;
1171
1172 if (!MI.hasOneMemOperand())
1173 return false;
1174
1175 MachineMemOperand *MMO = *MI.memoperands_begin();
1176
1177 const auto *TLI = STI.getTargetLowering();
1178 EVT VT = EVT::getEVT(getTypeForLLT(DataTy, Ctx));
1179
1180 if (TLI->allowsMemoryAccessForAlignment(Ctx, DL, VT, *MMO))
1181 return true;
1182
1183 unsigned EltSizeBits = DataTy.getScalarSizeInBits();
1184 assert((EltSizeBits == 16 || EltSizeBits == 32 || EltSizeBits == 64) &&
1185 "Unexpected unaligned RVV load type");
1186
1187 // Calculate the new vector type with i8 elements
1188 unsigned NumElements =
1189 DataTy.getElementCount().getKnownMinValue() * (EltSizeBits / 8);
1190 LLT NewDataTy = LLT::scalable_vector(NumElements, 8);
1191
1192 Helper.bitcast(MI, 0, NewDataTy);
1193
1194 return true;
1195}
1196
1197/// Return the type of the mask type suitable for masking the provided
1198/// vector type. This is simply an i1 element type vector of the same
1199/// (possibly scalable) length.
1200static LLT getMaskTypeFor(LLT VecTy) {
1201 assert(VecTy.isVector());
1202 ElementCount EC = VecTy.getElementCount();
1203 return LLT::vector(EC, LLT::scalar(1));
1204}
1205
1206/// Creates an all ones mask suitable for masking a vector of type VecTy with
1207/// vector length VL.
1209 MachineIRBuilder &MIB,
1210 MachineRegisterInfo &MRI) {
1211 LLT MaskTy = getMaskTypeFor(VecTy);
1212 return MIB.buildInstr(RISCV::G_VMSET_VL, {MaskTy}, {VL});
1213}
1214
1215/// Gets the two common "VL" operands: an all-ones mask and the vector length.
1216/// VecTy is a scalable vector type.
1217static std::pair<MachineInstrBuilder, MachineInstrBuilder>
1219 assert(VecTy.isScalableVector() && "Expecting scalable container type");
1220 const RISCVSubtarget &STI = MIB.getMF().getSubtarget<RISCVSubtarget>();
1221 LLT XLenTy(STI.getXLenVT());
1222 auto VL = MIB.buildConstant(XLenTy, -1);
1223 auto Mask = buildAllOnesMask(VecTy, VL, MIB, MRI);
1224 return {Mask, VL};
1225}
1226
1228buildSplatPartsS64WithVL(const DstOp &Dst, const SrcOp &Passthru, Register Lo,
1229 Register Hi, const SrcOp &VL, MachineIRBuilder &MIB,
1230 MachineRegisterInfo &MRI) {
1231 // TODO: If the Hi bits of the splat are undefined, then it's fine to just
1232 // splat Lo even if it might be sign extended. I don't think we have
1233 // introduced a case where we're build a s64 where the upper bits are undef
1234 // yet.
1235
1236 // Fall back to a stack store and stride x0 vector load.
1237 // TODO: need to lower G_SPLAT_VECTOR_SPLIT_I64. This is done in
1238 // preprocessDAG in SDAG.
1239 return MIB.buildInstr(RISCV::G_SPLAT_VECTOR_SPLIT_I64_VL, {Dst},
1240 {Passthru, Lo, Hi, VL});
1241}
1242
1244buildSplatSplitS64WithVL(const DstOp &Dst, const SrcOp &Passthru,
1245 const SrcOp &Scalar, const SrcOp &VL,
1247 assert(Scalar.getLLTTy(MRI) == LLT::scalar(64) && "Unexpected VecTy!");
1248 auto Unmerge = MIB.buildUnmerge(LLT::scalar(32), Scalar);
1249 return buildSplatPartsS64WithVL(Dst, Passthru, Unmerge.getReg(0),
1250 Unmerge.getReg(1), VL, MIB, MRI);
1251}
1252
1253// Lower splats of s1 types to G_ICMP. For each mask vector type, we have a
1254// legal equivalently-sized i8 type, so we can use that as a go-between.
1255// Splats of s1 types that have constant value can be legalized as VMSET_VL or
1256// VMCLR_VL.
1257bool RISCVLegalizerInfo::legalizeSplatVector(MachineInstr &MI,
1258 MachineIRBuilder &MIB) const {
1259 assert(MI.getOpcode() == TargetOpcode::G_SPLAT_VECTOR);
1260
1261 MachineRegisterInfo &MRI = *MIB.getMRI();
1262
1263 Register Dst = MI.getOperand(0).getReg();
1264 Register SplatVal = MI.getOperand(1).getReg();
1265
1266 LLT VecTy = MRI.getType(Dst);
1267 LLT XLenTy(STI.getXLenVT());
1268
1269 // Handle case of s64 element vectors on rv32
1270 if (XLenTy.getSizeInBits() == 32 &&
1271 VecTy.getElementType().getSizeInBits() == 64) {
1272 auto [_, VL] = buildDefaultVLOps(MRI.getType(Dst), MIB, MRI);
1273 buildSplatSplitS64WithVL(Dst, MIB.buildUndef(VecTy), SplatVal, VL, MIB,
1274 MRI);
1275 MI.eraseFromParent();
1276 return true;
1277 }
1278
1279 // All-zeros or all-ones splats are handled specially.
1280 MachineInstr &SplatValMI = *MRI.getVRegDef(SplatVal);
1281 if (isAllOnesOrAllOnesSplat(SplatValMI, MRI)) {
1282 auto VL = buildDefaultVLOps(VecTy, MIB, MRI).second;
1283 MIB.buildInstr(RISCV::G_VMSET_VL, {Dst}, {VL});
1284 MI.eraseFromParent();
1285 return true;
1286 }
1287 if (isNullOrNullSplat(SplatValMI, MRI)) {
1288 auto VL = buildDefaultVLOps(VecTy, MIB, MRI).second;
1289 MIB.buildInstr(RISCV::G_VMCLR_VL, {Dst}, {VL});
1290 MI.eraseFromParent();
1291 return true;
1292 }
1293
1294 // Handle non-constant mask splat (i.e. not sure if it's all zeros or all
1295 // ones) by promoting it to an s8 splat.
1296 LLT InterEltTy = LLT::scalar(8);
1297 LLT InterTy = VecTy.changeElementType(InterEltTy);
1298 auto ZExtSplatVal = MIB.buildZExt(InterEltTy, SplatVal);
1299 auto And =
1300 MIB.buildAnd(InterEltTy, ZExtSplatVal, MIB.buildConstant(InterEltTy, 1));
1301 auto LHS = MIB.buildSplatVector(InterTy, And);
1302 auto ZeroSplat =
1303 MIB.buildSplatVector(InterTy, MIB.buildConstant(InterEltTy, 0));
1304 MIB.buildICmp(CmpInst::Predicate::ICMP_NE, Dst, LHS, ZeroSplat);
1305 MI.eraseFromParent();
1306 return true;
1307}
1308
1309static LLT getLMUL1Ty(LLT VecTy) {
1310 assert(VecTy.getElementType().getSizeInBits() <= 64 &&
1311 "Unexpected vector LLT");
1313 VecTy.getElementType().getSizeInBits(),
1314 VecTy.getElementType());
1315}
1316
1317bool RISCVLegalizerInfo::legalizeExtractSubvector(MachineInstr &MI,
1318 MachineIRBuilder &MIB) const {
1319 GExtractSubvector &ES = cast<GExtractSubvector>(MI);
1320
1321 MachineRegisterInfo &MRI = *MIB.getMRI();
1322
1323 Register Dst = ES.getReg(0);
1324 Register Src = ES.getSrcVec();
1325 uint64_t Idx = ES.getIndexImm();
1326
1327 // With an index of 0 this is a cast-like subvector, which can be performed
1328 // with subregister operations.
1329 if (Idx == 0)
1330 return true;
1331
1332 LLT LitTy = MRI.getType(Dst);
1333 LLT BigTy = MRI.getType(Src);
1334
1335 if (LitTy.getElementType() == LLT::scalar(1)) {
1336 // We can't slide this mask vector up indexed by its i1 elements.
1337 // This poses a problem when we wish to insert a scalable vector which
1338 // can't be re-expressed as a larger type. Just choose the slow path and
1339 // extend to a larger type, then truncate back down.
1340 LLT ExtBigTy = BigTy.changeElementType(LLT::scalar(8));
1341 LLT ExtLitTy = LitTy.changeElementType(LLT::scalar(8));
1342 auto BigZExt = MIB.buildZExt(ExtBigTy, Src);
1343 auto ExtractZExt = MIB.buildExtractSubvector(ExtLitTy, BigZExt, Idx);
1344 auto SplatZero = MIB.buildSplatVector(
1345 ExtLitTy, MIB.buildConstant(ExtLitTy.getElementType(), 0));
1346 MIB.buildICmp(CmpInst::Predicate::ICMP_NE, Dst, ExtractZExt, SplatZero);
1347 MI.eraseFromParent();
1348 return true;
1349 }
1350
1351 // extract_subvector scales the index by vscale if the subvector is scalable,
1352 // and decomposeSubvectorInsertExtractToSubRegs takes this into account.
1353 const RISCVRegisterInfo *TRI = STI.getRegisterInfo();
1354 MVT LitTyMVT = getMVTForLLT(LitTy);
1355 auto Decompose =
1357 getMVTForLLT(BigTy), LitTyMVT, Idx, TRI);
1358 unsigned RemIdx = Decompose.second;
1359
1360 // If the Idx has been completely eliminated then this is a subvector extract
1361 // which naturally aligns to a vector register. These can easily be handled
1362 // using subregister manipulation.
1363 if (RemIdx == 0)
1364 return true;
1365
1366 // Else LitTy is M1 or smaller and may need to be slid down: if LitTy
1367 // was > M1 then the index would need to be a multiple of VLMAX, and so would
1368 // divide exactly.
1369 assert(
1372
1373 // If the vector type is an LMUL-group type, extract a subvector equal to the
1374 // nearest full vector register type.
1375 LLT InterLitTy = BigTy;
1376 Register Vec = Src;
1378 getLMUL1Ty(BigTy).getSizeInBits())) {
1379 // If BigTy has an LMUL > 1, then LitTy should have a smaller LMUL, and
1380 // we should have successfully decomposed the extract into a subregister.
1381 assert(Decompose.first != RISCV::NoSubRegister);
1382 InterLitTy = getLMUL1Ty(BigTy);
1383 // SDAG builds a TargetExtractSubreg. We cannot create a a Copy with SubReg
1384 // specified on the source Register (the equivalent) since generic virtual
1385 // register does not allow subregister index.
1386 Vec = MIB.buildExtractSubvector(InterLitTy, Src, Idx - RemIdx).getReg(0);
1387 }
1388
1389 // Slide this vector register down by the desired number of elements in order
1390 // to place the desired subvector starting at element 0.
1391 const LLT XLenTy(STI.getXLenVT());
1392 auto SlidedownAmt = MIB.buildVScale(XLenTy, RemIdx);
1393 auto [Mask, VL] = buildDefaultVLOps(InterLitTy, MIB, MRI);
1395 auto Slidedown = MIB.buildInstr(
1396 RISCV::G_VSLIDEDOWN_VL, {InterLitTy},
1397 {MIB.buildUndef(InterLitTy), Vec, SlidedownAmt, Mask, VL, Policy});
1398
1399 // Now the vector is in the right position, extract our final subvector. This
1400 // should resolve to a COPY.
1401 MIB.buildExtractSubvector(Dst, Slidedown, 0);
1402
1403 MI.eraseFromParent();
1404 return true;
1405}
1406
1407bool RISCVLegalizerInfo::legalizeInsertSubvector(MachineInstr &MI,
1408 LegalizerHelper &Helper,
1409 MachineIRBuilder &MIB) const {
1410 GInsertSubvector &IS = cast<GInsertSubvector>(MI);
1411
1412 MachineRegisterInfo &MRI = *MIB.getMRI();
1413
1414 Register Dst = IS.getReg(0);
1415 Register BigVec = IS.getBigVec();
1416 Register LitVec = IS.getSubVec();
1417 uint64_t Idx = IS.getIndexImm();
1418
1419 LLT BigTy = MRI.getType(BigVec);
1420 LLT LitTy = MRI.getType(LitVec);
1421
1422 if (Idx == 0 && mi_match(BigVec, MRI, m_GImplicitDef()))
1423 return true;
1424
1425 // We don't have the ability to slide mask vectors up indexed by their i1
1426 // elements; the smallest we can do is i8. Often we are able to bitcast to
1427 // equivalent i8 vectors. Otherwise, we can must zeroextend to equivalent i8
1428 // vectors and truncate down after the insert.
1429 if (LitTy.getElementType() == LLT::scalar(1)) {
1430 auto BigTyMinElts = BigTy.getElementCount().getKnownMinValue();
1431 auto LitTyMinElts = LitTy.getElementCount().getKnownMinValue();
1432 if (BigTyMinElts >= 8 && LitTyMinElts >= 8)
1433 return Helper.bitcast(
1434 IS, 0,
1436
1437 // We can't slide this mask vector up indexed by its i1 elements.
1438 // This poses a problem when we wish to insert a scalable vector which
1439 // can't be re-expressed as a larger type. Just choose the slow path and
1440 // extend to a larger type, then truncate back down.
1441 LLT ExtBigTy = BigTy.changeElementType(LLT::scalar(8));
1442 return Helper.widenScalar(IS, 0, ExtBigTy);
1443 }
1444
1445 const RISCVRegisterInfo *TRI = STI.getRegisterInfo();
1446 unsigned SubRegIdx, RemIdx;
1447 std::tie(SubRegIdx, RemIdx) =
1449 getMVTForLLT(BigTy), getMVTForLLT(LitTy), Idx, TRI);
1450
1451 TypeSize VecRegSize = TypeSize::getScalable(RISCV::RVVBitsPerBlock);
1453 STI.expandVScale(LitTy.getSizeInBits()).getKnownMinValue()));
1454 bool ExactlyVecRegSized =
1455 STI.expandVScale(LitTy.getSizeInBits())
1456 .isKnownMultipleOf(STI.expandVScale(VecRegSize));
1457
1458 // If the Idx has been completely eliminated and this subvector's size is a
1459 // vector register or a multiple thereof, or the surrounding elements are
1460 // undef, then this is a subvector insert which naturally aligns to a vector
1461 // register. These can easily be handled using subregister manipulation.
1462 if (RemIdx == 0 && ExactlyVecRegSized)
1463 return true;
1464
1465 // If the subvector is smaller than a vector register, then the insertion
1466 // must preserve the undisturbed elements of the register. We do this by
1467 // lowering to an EXTRACT_SUBVECTOR grabbing the nearest LMUL=1 vector type
1468 // (which resolves to a subregister copy), performing a VSLIDEUP to place the
1469 // subvector within the vector register, and an INSERT_SUBVECTOR of that
1470 // LMUL=1 type back into the larger vector (resolving to another subregister
1471 // operation). See below for how our VSLIDEUP works. We go via a LMUL=1 type
1472 // to avoid allocating a large register group to hold our subvector.
1473
1474 // VSLIDEUP works by leaving elements 0<i<OFFSET undisturbed, elements
1475 // OFFSET<=i<VL set to the "subvector" and vl<=i<VLMAX set to the tail policy
1476 // (in our case undisturbed). This means we can set up a subvector insertion
1477 // where OFFSET is the insertion offset, and the VL is the OFFSET plus the
1478 // size of the subvector.
1479 const LLT XLenTy(STI.getXLenVT());
1480 LLT InterLitTy = BigTy;
1481 Register AlignedExtract = BigVec;
1482 unsigned AlignedIdx = Idx - RemIdx;
1484 getLMUL1Ty(BigTy).getSizeInBits())) {
1485 InterLitTy = getLMUL1Ty(BigTy);
1486 // Extract a subvector equal to the nearest full vector register type. This
1487 // should resolve to a G_EXTRACT on a subreg.
1488 AlignedExtract =
1489 MIB.buildExtractSubvector(InterLitTy, BigVec, AlignedIdx).getReg(0);
1490 }
1491
1492 auto Insert = MIB.buildInsertSubvector(InterLitTy, MIB.buildUndef(InterLitTy),
1493 LitVec, 0);
1494
1495 auto [Mask, _] = buildDefaultVLOps(InterLitTy, MIB, MRI);
1496 auto VL = MIB.buildVScale(XLenTy, LitTy.getElementCount().getKnownMinValue());
1497
1498 // If we're inserting into the lowest elements, use a tail undisturbed
1499 // vmv.v.v.
1500 MachineInstrBuilder Inserted;
1501 bool NeedInsertSubvec =
1502 TypeSize::isKnownGT(BigTy.getSizeInBits(), InterLitTy.getSizeInBits());
1503 Register InsertedDst =
1504 NeedInsertSubvec ? MRI.createGenericVirtualRegister(InterLitTy) : Dst;
1505 if (RemIdx == 0) {
1506 Inserted = MIB.buildInstr(RISCV::G_VMV_V_V_VL, {InsertedDst},
1507 {AlignedExtract, Insert, VL});
1508 } else {
1509 auto SlideupAmt = MIB.buildVScale(XLenTy, RemIdx);
1510 // Construct the vector length corresponding to RemIdx + length(LitTy).
1511 VL = MIB.buildAdd(XLenTy, SlideupAmt, VL);
1512 // Use tail agnostic policy if we're inserting over InterLitTy's tail.
1513 ElementCount EndIndex =
1516 if (STI.expandVScale(EndIndex) ==
1517 STI.expandVScale(InterLitTy.getElementCount()))
1519
1520 Inserted =
1521 MIB.buildInstr(RISCV::G_VSLIDEUP_VL, {InsertedDst},
1522 {AlignedExtract, Insert, SlideupAmt, Mask, VL, Policy});
1523 }
1524
1525 // If required, insert this subvector back into the correct vector register.
1526 // This should resolve to an INSERT_SUBREG instruction.
1527 if (NeedInsertSubvec)
1528 MIB.buildInsertSubvector(Dst, BigVec, Inserted, AlignedIdx);
1529
1530 MI.eraseFromParent();
1531 return true;
1532}
1533
1534bool RISCVLegalizerInfo::legalizeBitreverse(MachineInstr &MI,
1535 MachineIRBuilder &MIB) const {
1536 assert(MI.getOpcode() == TargetOpcode::G_BITREVERSE && "Unexpected opcode");
1537
1538 if (!STI.hasStdExtZbkb())
1539 return false;
1540
1541 MachineRegisterInfo &MRI = *MIB.getMRI();
1542
1543 Register Dst = MI.getOperand(0).getReg();
1544 Register Src = MI.getOperand(1).getReg();
1545
1546 if (!MRI.getType(Dst).isScalar(8))
1547 return false;
1548
1549 auto WideSrc = MIB.buildAnyExt(sXLen, Src);
1550 auto Brev = MIB.buildInstr(RISCV::G_BREV8, {sXLen}, {WideSrc.getReg(0)});
1551 MIB.buildTrunc(Dst, Brev.getReg(0));
1552
1553 MI.eraseFromParent();
1554 return true;
1555}
1556
1557static unsigned getRISCVWOpcode(unsigned Opcode) {
1558 switch (Opcode) {
1559 default:
1560 llvm_unreachable("Unexpected opcode");
1561 case TargetOpcode::G_ASHR:
1562 return RISCV::G_SRAW;
1563 case TargetOpcode::G_LSHR:
1564 return RISCV::G_SRLW;
1565 case TargetOpcode::G_SHL:
1566 return RISCV::G_SLLW;
1567 case TargetOpcode::G_SDIV:
1568 return RISCV::G_DIVW;
1569 case TargetOpcode::G_UDIV:
1570 return RISCV::G_DIVUW;
1571 case TargetOpcode::G_UREM:
1572 return RISCV::G_REMUW;
1573 case TargetOpcode::G_ROTL:
1574 return RISCV::G_ROLW;
1575 case TargetOpcode::G_ROTR:
1576 return RISCV::G_RORW;
1577 case TargetOpcode::G_CTLZ:
1578 return RISCV::G_CLZW;
1579 case TargetOpcode::G_CTTZ:
1580 return RISCV::G_CTZW;
1581 case TargetOpcode::G_CTLS:
1582 return RISCV::G_CLSW;
1583 case TargetOpcode::G_FPTOSI:
1584 return RISCV::G_FCVT_W_RV64;
1585 case TargetOpcode::G_FPTOUI:
1586 return RISCV::G_FCVT_WU_RV64;
1587 }
1588}
1589
1592 LostDebugLocObserver &LocObserver) const {
1593 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
1594 MachineRegisterInfo &MRI = *MIRBuilder.getMRI();
1595 MachineFunction &MF = *MI.getParent()->getParent();
1596 switch (MI.getOpcode()) {
1597 default:
1598 // No idea what to do.
1599 return false;
1600 case TargetOpcode::G_ABS:
1601 return Helper.lowerAbsToMaxNeg(MI);
1602 case TargetOpcode::G_FCONSTANT: {
1603 const APFloat &FVal = MI.getOperand(1).getFPImm()->getValueAPF();
1604
1605 // Convert G_FCONSTANT to G_CONSTANT.
1606 Register DstReg = MI.getOperand(0).getReg();
1607 MIRBuilder.buildConstant(DstReg, FVal.bitcastToAPInt());
1608
1609 MI.eraseFromParent();
1610 return true;
1611 }
1612 case TargetOpcode::G_CONSTANT: {
1613 const Function &F = MF.getFunction();
1614 // TODO: if PSI and BFI are present, add " ||
1615 // llvm::shouldOptForSize(*CurMBB, PSI, BFI)".
1616 bool ShouldOptForSize = F.hasOptSize();
1617 const ConstantInt *ConstVal = MI.getOperand(1).getCImm();
1618 if (!shouldBeInConstantPool(ConstVal->getValue(), ShouldOptForSize))
1619 return true;
1620 return Helper.lowerConstant(MI);
1621 }
1622 case TargetOpcode::G_SUB:
1623 case TargetOpcode::G_ADD: {
1624 Helper.Observer.changingInstr(MI);
1625 Helper.widenScalarSrc(MI, sXLen, 1, TargetOpcode::G_ANYEXT);
1626 Helper.widenScalarSrc(MI, sXLen, 2, TargetOpcode::G_ANYEXT);
1627
1628 Register DstALU = MRI.createGenericVirtualRegister(sXLen);
1629
1630 MachineOperand &MO = MI.getOperand(0);
1631 MIRBuilder.setInsertPt(MIRBuilder.getMBB(), ++MIRBuilder.getInsertPt());
1632 auto DstSext = MIRBuilder.buildSExtInReg(sXLen, DstALU, 32);
1633
1634 MIRBuilder.buildInstr(TargetOpcode::G_TRUNC, {MO}, {DstSext});
1635 MO.setReg(DstALU);
1636
1637 Helper.Observer.changedInstr(MI);
1638 return true;
1639 }
1640 case TargetOpcode::G_ASHR:
1641 case TargetOpcode::G_LSHR:
1642 case TargetOpcode::G_SHL: {
1643 if (getIConstantVRegValWithLookThrough(MI.getOperand(2).getReg(), MRI)) {
1644 // We don't need a custom node for shift by constant. Just widen the
1645 // source and the shift amount.
1646 unsigned ExtOpc = TargetOpcode::G_ANYEXT;
1647 if (MI.getOpcode() == TargetOpcode::G_ASHR)
1648 ExtOpc = TargetOpcode::G_SEXT;
1649 else if (MI.getOpcode() == TargetOpcode::G_LSHR)
1650 ExtOpc = TargetOpcode::G_ZEXT;
1651
1652 Helper.Observer.changingInstr(MI);
1653 Helper.widenScalarSrc(MI, sXLen, 1, ExtOpc);
1654 Helper.widenScalarSrc(MI, sXLen, 2, TargetOpcode::G_ZEXT);
1655 Helper.widenScalarDst(MI, sXLen);
1656 Helper.Observer.changedInstr(MI);
1657 return true;
1658 }
1659
1660 Helper.Observer.changingInstr(MI);
1661 Helper.widenScalarSrc(MI, sXLen, 1, TargetOpcode::G_ANYEXT);
1662 Helper.widenScalarSrc(MI, sXLen, 2, TargetOpcode::G_ANYEXT);
1663 Helper.widenScalarDst(MI, sXLen);
1664 MI.setDesc(MIRBuilder.getTII().get(getRISCVWOpcode(MI.getOpcode())));
1665 Helper.Observer.changedInstr(MI);
1666 return true;
1667 }
1668 case TargetOpcode::G_SDIV:
1669 case TargetOpcode::G_UDIV:
1670 case TargetOpcode::G_UREM:
1671 case TargetOpcode::G_ROTL:
1672 case TargetOpcode::G_ROTR: {
1673 Helper.Observer.changingInstr(MI);
1674 Helper.widenScalarSrc(MI, sXLen, 1, TargetOpcode::G_ANYEXT);
1675 Helper.widenScalarSrc(MI, sXLen, 2, TargetOpcode::G_ANYEXT);
1676 Helper.widenScalarDst(MI, sXLen);
1677 MI.setDesc(MIRBuilder.getTII().get(getRISCVWOpcode(MI.getOpcode())));
1678 Helper.Observer.changedInstr(MI);
1679 return true;
1680 }
1681 case TargetOpcode::G_CTLZ:
1682 case TargetOpcode::G_CTTZ:
1683 case TargetOpcode::G_CTLS: {
1684 Helper.Observer.changingInstr(MI);
1685 Helper.widenScalarSrc(MI, sXLen, 1, TargetOpcode::G_ANYEXT);
1686 Helper.widenScalarDst(MI, sXLen);
1687 MI.setDesc(MIRBuilder.getTII().get(getRISCVWOpcode(MI.getOpcode())));
1688 Helper.Observer.changedInstr(MI);
1689 return true;
1690 }
1691 case TargetOpcode::G_FPTOSI:
1692 case TargetOpcode::G_FPTOUI: {
1693 Helper.Observer.changingInstr(MI);
1694 Helper.widenScalarDst(MI, sXLen);
1695 MI.setDesc(MIRBuilder.getTII().get(getRISCVWOpcode(MI.getOpcode())));
1697 Helper.Observer.changedInstr(MI);
1698 return true;
1699 }
1700 case TargetOpcode::G_LROUND: {
1701 // The (i32 any_lround) Pat is IsRV32-only; on RV64 lower to
1702 // riscv_fcvt_w_rv64 with FRM_RMM.
1703 Helper.Observer.changingInstr(MI);
1704 Helper.widenScalarDst(MI, sXLen);
1705 MI.setDesc(MIRBuilder.getTII().get(RISCV::G_FCVT_W_RV64));
1707 Helper.Observer.changedInstr(MI);
1708 return true;
1709 }
1710 case TargetOpcode::G_READCYCLECOUNTER:
1711 case TargetOpcode::G_READSTEADYCOUNTER:
1712 return legalizeReadCounter(MI, MIRBuilder, Helper.Observer);
1713 case TargetOpcode::G_IS_FPCLASS: {
1714 Register GISFPCLASS = MI.getOperand(0).getReg();
1715 Register Src = MI.getOperand(1).getReg();
1716 const MachineOperand &ImmOp = MI.getOperand(2);
1717 MachineIRBuilder MIB(MI);
1718
1719 // Turn LLVM IR's floating point classes to that in RISC-V,
1720 // by simply rotating the 10-bit immediate right by two bits.
1721 APInt GFpClassImm(10, static_cast<uint64_t>(ImmOp.getImm()));
1722 auto FClassMask = MIB.buildConstant(sXLen, GFpClassImm.rotr(2).zext(XLen));
1723 auto ConstZero = MIB.buildConstant(sXLen, 0);
1724
1725 auto GFClass = MIB.buildInstr(RISCV::G_FCLASS, {sXLen}, {Src});
1726 auto And = MIB.buildAnd(sXLen, GFClass, FClassMask);
1727 MIB.buildICmp(CmpInst::ICMP_NE, GISFPCLASS, And, ConstZero);
1728
1729 MI.eraseFromParent();
1730 return true;
1731 }
1732 case TargetOpcode::G_BRJT:
1733 return legalizeBRJT(MI, MIRBuilder);
1734 case TargetOpcode::G_VASTART:
1735 return legalizeVAStart(MI, MIRBuilder);
1736 case TargetOpcode::G_VSCALE:
1737 return legalizeVScale(MI, MIRBuilder);
1738 case TargetOpcode::G_ZEXT:
1739 case TargetOpcode::G_SEXT:
1740 case TargetOpcode::G_ANYEXT:
1741 return legalizeExt(MI, MIRBuilder);
1742 case TargetOpcode::G_SPLAT_VECTOR:
1743 return legalizeSplatVector(MI, MIRBuilder);
1744 case TargetOpcode::G_EXTRACT_SUBVECTOR:
1745 return legalizeExtractSubvector(MI, MIRBuilder);
1746 case TargetOpcode::G_INSERT_SUBVECTOR:
1747 return legalizeInsertSubvector(MI, Helper, MIRBuilder);
1748 case TargetOpcode::G_BITREVERSE:
1749 return legalizeBitreverse(MI, MIRBuilder);
1750 case TargetOpcode::G_LOAD:
1751 case TargetOpcode::G_STORE:
1752 return legalizeLoadStore(MI, Helper, MIRBuilder);
1753 }
1754
1755 llvm_unreachable("expected switch to return");
1756}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
unsigned Imm
unsigned uint64_t
constexpr LLT S32
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
Declares convenience wrapper classes for interpreting MachineInstr instances as specific generic oper...
const HexagonInstrInfo * TII
#define _
IRTranslator LLVM IR MI
#define F(x, y, z)
Definition MD5.cpp:54
#define I(x, y, z)
Definition MD5.cpp:57
Contains matchers for matching SSA Machine Instructions.
This file declares the MachineConstantPool class which is an abstract constant pool to keep track of ...
This file declares the MachineIRBuilder class.
Register const TargetRegisterInfo * TRI
Promote Memory to Register
Definition Mem2Reg.cpp:110
uint64_t 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:1056
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:1198
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
Abstract class that contains various methods for clients to notify about changes.
virtual void changingInstr(MachineInstr &MI)=0
This instruction is about to be mutated in some way.
virtual void changedInstr(MachineInstr &MI)=0
This instruction was mutated in some way.
virtual void erasingInstr(MachineInstr &MI)=0
An instruction is about to be erased.
Register getReg(unsigned Idx) const
Access the Idx'th operand as a register and return it.
constexpr bool isScalableVector() const
Returns true if the LLT is a scalable vector.
constexpr unsigned getScalarSizeInBits() const
constexpr bool isScalar() const
static constexpr LLT scalable_vector(unsigned MinNumElements, unsigned ScalarSizeInBits)
Get a low-level scalable vector of some number of elements and element width.
constexpr LLT changeElementType(LLT NewEltTy) const
If this type is a vector, return a vector with the same number of elements but the new element type.
static constexpr LLT vector(ElementCount EC, unsigned ScalarSizeInBits)
Get a low-level vector of some number of elements and element width.
static constexpr LLT scalar(unsigned SizeInBits)
Get a low-level scalar or aggregate "bag of bits".
constexpr bool isVector() const
static constexpr LLT pointer(unsigned AddressSpace, unsigned SizeInBits)
Get a low-level pointer in the given address space.
constexpr TypeSize getSizeInBits() const
Returns the total size of the type. Must only be called on sized types.
constexpr ElementCount getElementCount() const
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
LLVM_ABI void transferSuccessorsAndUpdatePHIs(MachineBasicBlock *FromMBB)
Transfers all the successors, as in transferSuccessors, and update PHI operands in the successor bloc...
const BasicBlock * getBasicBlock() const
Return the LLVM basic block that this instance corresponded to originally.
LLVM_ABI void addSuccessor(MachineBasicBlock *Succ, BranchProbability Prob=BranchProbability::getUnknown())
Add Succ as a successor of this MachineBasicBlock.
const MachineFunction * getParent() const
Return the MachineFunction containing this basic block.
void splice(iterator Where, MachineBasicBlock *Other, iterator From)
Take an instruction from MBB 'Other' at the position From, and insert it into this MBB right before '...
MachineInstrBundleIterator< MachineInstr > iterator
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
const DataLayout & getDataLayout() const
Return the DataLayout attached to the Module associated to this MF.
Function & getFunction()
Return the LLVM function that this machine code represents.
BasicBlockListType::iterator iterator
Ty * getInfo()
getInfo - Keep track of various per-function pieces of information for backends that would like to do...
MachineMemOperand * getMachineMemOperand(MachinePointerInfo PtrInfo, MachineMemOperand::Flags F, LLT MemTy, Align BaseAlignment, const MMOMetadata &Metadata=MMOMetadata(), SyncScope::ID SSID=SyncScope::System, AtomicOrdering Ordering=AtomicOrdering::NotAtomic, AtomicOrdering FailureOrdering=AtomicOrdering::NotAtomic)
getMachineMemOperand - Allocate a new MachineMemOperand.
const MachineJumpTableInfo * getJumpTableInfo() const
getJumpTableInfo - Return the jump table info object for the current function.
MachineBasicBlock * CreateMachineBasicBlock(const BasicBlock *BB=nullptr, std::optional< UniqueBBID > BBID=std::nullopt)
CreateMachineInstr - Allocate a new MachineInstr.
void insert(iterator MBBI, MachineBasicBlock *MBB)
Helper class to build MachineInstr.
void setInsertPt(MachineBasicBlock &MBB, MachineBasicBlock::iterator II)
Set the insertion point before the specified position.
MachineInstrBuilder buildAdd(const DstOp &Dst, const SrcOp &Src0, const SrcOp &Src1, std::optional< unsigned > Flags=std::nullopt)
Build and insert Res = G_ADD Op0, Op1.
MachineInstrBuilder buildUndef(const DstOp &Res)
Build and insert Res = IMPLICIT_DEF.
MachineInstrBuilder buildUnmerge(ArrayRef< LLT > Res, const SrcOp &Op)
Build and insert Res0, ... = G_UNMERGE_VALUES Op.
MachineInstrBuilder buildSelect(const DstOp &Res, const SrcOp &Tst, const SrcOp &Op0, const SrcOp &Op1, std::optional< unsigned > Flags=std::nullopt)
Build and insert a Res = G_SELECT Tst, Op0, Op1.
MachineInstrBuilder buildMul(const DstOp &Dst, const SrcOp &Src0, const SrcOp &Src1, std::optional< unsigned > Flags=std::nullopt)
Build and insert Res = G_MUL Op0, Op1.
MachineInstrBuilder buildInsertSubvector(const DstOp &Res, const SrcOp &Src0, const SrcOp &Src1, unsigned Index)
Build and insert Res = G_INSERT_SUBVECTOR Src0, Src1, Idx.
MachineInstrBuilder buildAnd(const DstOp &Dst, const SrcOp &Src0, const SrcOp &Src1)
Build and insert Res = G_AND Op0, Op1.
const TargetInstrInfo & getTII()
MachineInstrBuilder buildICmp(CmpInst::Predicate Pred, const DstOp &Res, const SrcOp &Op0, const SrcOp &Op1, std::optional< unsigned > Flags=std::nullopt)
Build and insert a Res = G_ICMP Pred, Op0, Op1.
MachineInstrBuilder buildLShr(const DstOp &Dst, const SrcOp &Src0, const SrcOp &Src1, std::optional< unsigned > Flags=std::nullopt)
MachineBasicBlock::iterator getInsertPt()
Current insertion point for new instructions.
MachineInstrBuilder buildZExt(const DstOp &Res, const SrcOp &Op, std::optional< unsigned > Flags=std::nullopt)
Build and insert Res = G_ZEXT Op.
MachineInstrBuilder buildVScale(const DstOp &Res, unsigned MinElts)
Build and insert Res = G_VSCALE MinElts.
MachineInstrBuilder buildIntToPtr(const DstOp &Dst, const SrcOp &Src)
Build and insert a G_INTTOPTR instruction.
MachineInstrBuilder buildLoad(const DstOp &Res, const SrcOp &Addr, MachineMemOperand &MMO)
Build and insert Res = G_LOAD Addr, MMO.
MachineInstrBuilder buildPtrAdd(const DstOp &Res, const SrcOp &Op0, const SrcOp &Op1, std::optional< unsigned > Flags=std::nullopt)
Build and insert Res = G_PTR_ADD Op0, Op1.
MachineInstrBuilder buildShl(const DstOp &Dst, const SrcOp &Src0, const SrcOp &Src1, std::optional< unsigned > Flags=std::nullopt)
MachineInstrBuilder buildStore(const SrcOp &Val, const SrcOp &Addr, MachineMemOperand &MMO)
Build and insert G_STORE Val, Addr, MMO.
MachineInstrBuilder buildInstr(unsigned Opcode)
Build and insert <empty> = Opcode <empty>.
MachineInstrBuilder buildFrameIndex(const DstOp &Res, int Idx)
Build and insert Res = G_FRAME_INDEX Idx.
MachineFunction & getMF()
Getter for the function we currently build.
MachineInstrBuilder buildMergeValues(const DstOp &Res, ArrayRef< Register > Ops)
Build and insert Res = G_MERGE_VALUES Op0, ...
MachineInstrBuilder buildTrunc(const DstOp &Res, const SrcOp &Op, std::optional< unsigned > Flags=std::nullopt)
Build and insert Res = G_TRUNC Op.
void setDebugLoc(const DebugLoc &DL)
Set the debug location to DL for all the next build instructions.
const MachineBasicBlock & getMBB() const
Getter for the basic block we currently build.
MachineInstrBuilder buildAnyExt(const DstOp &Res, const SrcOp &Op)
Build and insert Res = G_ANYEXT Op0.
MachineRegisterInfo * getMRI()
Getter for MRI.
MachineInstrBuilder buildExtractSubvector(const DstOp &Res, const SrcOp &Src, unsigned Index)
Build and insert Res = G_EXTRACT_SUBVECTOR Src, Idx0.
const DataLayout & getDataLayout() const
MachineInstrBuilder buildBrIndirect(Register Tgt)
Build and insert G_BRINDIRECT Tgt.
MachineInstrBuilder buildSplatVector(const DstOp &Res, const SrcOp &Val)
Build and insert Res = G_SPLAT_VECTOR Val.
MachineInstrBuilder buildLoadInstr(unsigned Opcode, const DstOp &Res, const SrcOp &Addr, MachineMemOperand &MMO)
Build and insert Res = <opcode> Addr, MMO.
virtual MachineInstrBuilder buildConstant(const DstOp &Res, const ConstantInt &Val)
Build and insert Res = G_CONSTANT Val.
MachineInstrBuilder buildSExtInReg(const DstOp &Res, const SrcOp &Op, int64_t ImmOp)
Build and insert Res = G_SEXT_INREG Op, ImmOp.
Register getReg(unsigned Idx) const
Get the register for the operand index.
const MachineInstrBuilder & addReg(Register RegNo, RegState Flags={}, unsigned SubReg=0) const
Add a new virtual register operand.
const MachineInstrBuilder & addImm(int64_t Val) const
Add a new immediate operand.
const MachineInstrBuilder & addMBB(MachineBasicBlock *MBB, unsigned TargetFlags=0) const
Representation of each machine instruction.
LLVM_ABI unsigned getEntrySize(const DataLayout &TD) const
getEntrySize - Return the size of each entry in the jump table.
@ EK_LabelDifference32
EK_LabelDifference32 - Each entry is the address of the block minus the address of the jump table.
@ EK_Custom32
EK_Custom32 - Each entry is a 32-bit value that is custom lowered by the TargetLowering::LowerCustomJ...
@ EK_BlockAddress
EK_BlockAddress - Each entry is a plain address of block, e.g.: .word LBB123.
LLVM_ABI unsigned getEntryAlignment(const DataLayout &TD) const
getEntryAlignment - Return the alignment of each entry in the jump table.
A description of a memory reference used in the backend.
@ MOLoad
The memory access reads data.
@ MOStore
The memory access writes data.
MachineOperand class - Representation of each machine instruction operand.
int64_t getImm() const
LLVM_ABI void setReg(Register Reg)
Change the register this operand corresponds to.
static MachineOperand CreateImm(int64_t Val)
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
LLVM_ABI LLVM_READONLY MachineInstr * getVRegDef(Register Reg) const
getVRegDef - Return the machine instr that defines the specified virtual register or null if none is ...
LLT getType(Register Reg) const
Get the low-level type of Reg or LLT{} if Reg is not a generic (target independent) virtual register.
LLVM_ABI void setRegClass(Register Reg, const TargetRegisterClass *RC)
setRegClass - Set the register class of the specified virtual register.
LLVM_ABI Register createGenericVirtualRegister(LLT Ty, StringRef Name="")
Create and return a new generic virtual register with low-level type Ty.
bool legalizeCustom(LegalizerHelper &Helper, MachineInstr &MI, LostDebugLocObserver &LocObserver) const override
Called for instructions with the Custom LegalizationAction.
bool legalizeIntrinsic(LegalizerHelper &Helper, MachineInstr &MI) const override
RISCVLegalizerInfo(const RISCVSubtarget &ST)
RISCVMachineFunctionInfo - This class is derived from MachineFunctionInfo and contains private RISCV-...
static std::pair< unsigned, unsigned > decomposeSubvectorInsertExtractToSubRegs(MVT VecVT, MVT SubVecVT, unsigned InsertExtractIdx, const RISCVRegisterInfo *TRI)
static RISCVVType::VLMUL getLMUL(MVT VT)
Wrapper class representing virtual and physical registers.
Definition Register.h:20
Register getReg() const
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
self_iterator getIterator()
Definition ilist_node.h:123
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
constexpr char Align[]
Key for Kernel::Arg::Metadata::mAlign.
constexpr std::underlying_type_t< E > Mask()
Get a bitmask with 1s in all places up to the high-order bit of E's largest value.
@ BasicBlock
Various leaf nodes.
Definition ISDOpcodes.h:81
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
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
constexpr bool isInt(int64_t x)
Checks if an integer fits into the given bit width.
Definition MathExtras.h:166
LLVM_ABI bool isAllOnesOrAllOnesSplat(const MachineInstr &MI, const MachineRegisterInfo &MRI, bool AllowUndefs=false)
Return true if the value is a constant -1 integer or a splatted vector of a constant -1 integer (with...
Definition Utils.cpp: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:332
unsigned Log2_32(uint32_t Value)
Return the floor log base 2 of the specified value, -1 if the value is zero.
Definition MathExtras.h:326
std::function< bool(const LegalityQuery &)> LegalityPredicate
constexpr bool isPowerOf2_32(uint32_t Value)
Return true if the argument is a power of two > 0.
Definition MathExtras.h:280
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
Definition Casting.h:547
@ And
Bitwise or logical AND of integers.
DWARFExpression::Operation Op
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:559
LLVM_ABI std::optional< ValueAndVReg > getIConstantVRegValWithLookThrough(Register VReg, const MachineRegisterInfo &MRI, bool LookThroughInstrs=true)
If VReg is defined by a statically evaluable chain of instructions rooted on a G_CONSTANT returns its...
Definition Utils.cpp: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.