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 getActionDefinitionsBuilder(G_CLMUL)
237 .legalFor(ST.hasStdExtZbkc(), {sXLen})
238 .unsupported();
239
240 auto &CountZerosActions = getActionDefinitionsBuilder({G_CTLZ, G_CTTZ});
241 auto &CountZerosPoisonActions =
242 getActionDefinitionsBuilder({G_CTLZ_ZERO_POISON, G_CTTZ_ZERO_POISON});
243 if (ST.hasStdExtZbb()) {
244 CountZerosActions.legalFor({{sXLen, sXLen}})
245 .customFor({{s32, s32}})
246 .clampScalar(0, s32, sXLen)
247 .widenScalarToNextPow2(0)
248 .scalarSameSizeAs(1, 0);
249 } else {
250 CountZerosActions.maxScalar(0, sXLen).scalarSameSizeAs(1, 0).lower();
251 CountZerosPoisonActions.maxScalar(0, sXLen).scalarSameSizeAs(1, 0);
252 }
253 CountZerosPoisonActions.lower();
254
255 auto &CountSignActions = getActionDefinitionsBuilder(G_CTLS);
256 if (ST.hasStdExtP()) {
257 CountSignActions.legalFor({{sXLen, sXLen}})
258 .customFor({{s32, s32}})
259 .clampScalar(0, s32, sXLen)
260 .widenScalarToNextPow2(0)
261 .scalarSameSizeAs(1, 0);
262 } else {
263 CountSignActions.maxScalar(0, sXLen).scalarSameSizeAs(1, 0).lower();
264 }
265
266 auto &CTPOPActions = getActionDefinitionsBuilder(G_CTPOP);
267 if (ST.hasStdExtZbb()) {
268 CTPOPActions.legalFor({{sXLen, sXLen}})
269 .clampScalar(0, sXLen, sXLen)
270 .scalarSameSizeAs(1, 0);
271 } else {
272 CTPOPActions.widenScalarToNextPow2(0, /*Min*/ 8)
273 .clampScalar(0, s8, sXLen)
274 .scalarSameSizeAs(1, 0)
275 .lower();
276 }
277
278 getActionDefinitionsBuilder(G_CONSTANT)
279 .legalFor({p0})
280 .legalFor(!ST.is64Bit(), {s32})
281 .customFor(ST.is64Bit(), {s64})
282 .widenScalarToNextPow2(0)
283 .clampScalar(0, sXLen, sXLen);
284
285 // TODO: transform illegal vector types into legal vector type
286 getActionDefinitionsBuilder(G_FREEZE)
287 .legalFor({s16, s32, p0})
288 .legalFor(ST.is64Bit(), {s64})
289 .legalIf(typeIsLegalBoolVec(0, BoolVecTys, ST))
290 .legalIf(typeIsLegalIntOrFPVec(0, IntOrFPVecTys, ST))
291 .widenScalarToNextPow2(0)
292 .clampScalar(0, s16, sXLen);
293
294 // TODO: transform illegal vector types into legal vector type
295 // TODO: Merge with G_FREEZE?
296 getActionDefinitionsBuilder(
297 {G_IMPLICIT_DEF, G_CONSTANT_FOLD_BARRIER})
298 .legalFor({s32, sXLen, p0})
299 .legalIf(typeIsLegalBoolVec(0, BoolVecTys, ST))
300 .legalIf(typeIsLegalIntOrFPVec(0, IntOrFPVecTys, ST))
301 .widenScalarToNextPow2(0)
302 .clampScalar(0, s32, sXLen);
303
304 getActionDefinitionsBuilder(G_ICMP)
305 .legalFor({{sXLen, sXLen}, {sXLen, p0}})
306 .legalIf(all(typeIsLegalBoolVec(0, BoolVecTys, ST),
307 typeIsLegalIntOrFPVec(1, IntOrFPVecTys, ST)))
308 .widenScalarOrEltToNextPow2OrMinSize(1, 8)
309 .clampScalar(1, sXLen, sXLen)
310 .clampScalar(0, sXLen, sXLen);
311
312 getActionDefinitionsBuilder(G_SELECT)
313 .legalFor({{s32, sXLen}, {p0, sXLen}})
314 .legalIf(all(typeIsLegalIntOrFPVec(0, IntOrFPVecTys, ST),
315 typeIsLegalBoolVec(1, BoolVecTys, ST)))
316 .legalFor(XLen == 64 || ST.hasStdExtD(), {{s64, sXLen}})
317 .widenScalarToNextPow2(0)
318 .clampScalar(0, s32, (XLen == 64 || ST.hasStdExtD()) ? s64 : s32)
319 .clampScalar(1, sXLen, sXLen);
320
321 auto &LoadActions = getActionDefinitionsBuilder(G_LOAD);
322 auto &StoreActions = getActionDefinitionsBuilder(G_STORE);
323 auto &ExtLoadActions = getActionDefinitionsBuilder({G_SEXTLOAD, G_ZEXTLOAD});
324
325 // Return the alignment needed for scalar memory ops. If unaligned scalar mem
326 // is supported, we only require byte alignment. Otherwise, we need the memory
327 // op to be natively aligned.
328 auto getScalarMemAlign = [&ST](unsigned Size) {
329 return ST.enableUnalignedScalarMem() ? 8 : Size;
330 };
331
332 LoadActions.legalForTypesWithMemDesc(
333 {{s16, p0, s8, getScalarMemAlign(8)},
334 {s32, p0, s8, getScalarMemAlign(8)},
335 {s16, p0, s16, getScalarMemAlign(16)},
336 {s32, p0, s16, getScalarMemAlign(16)},
337 {s32, p0, s32, getScalarMemAlign(32)},
338 {p0, p0, sXLen, getScalarMemAlign(XLen)}});
339 StoreActions.legalForTypesWithMemDesc(
340 {{s16, p0, s8, getScalarMemAlign(8)},
341 {s32, p0, s8, getScalarMemAlign(8)},
342 {s16, p0, s16, getScalarMemAlign(16)},
343 {s32, p0, s16, getScalarMemAlign(16)},
344 {s32, p0, s32, getScalarMemAlign(32)},
345 {p0, p0, sXLen, getScalarMemAlign(XLen)}});
346 ExtLoadActions.legalForTypesWithMemDesc(
347 {{sXLen, p0, s8, getScalarMemAlign(8)},
348 {sXLen, p0, s16, getScalarMemAlign(16)}});
349 if (XLen == 64) {
350 LoadActions.legalForTypesWithMemDesc(
351 {{s64, p0, s8, getScalarMemAlign(8)},
352 {s64, p0, s16, getScalarMemAlign(16)},
353 {s64, p0, s32, getScalarMemAlign(32)},
354 {s64, p0, s64, getScalarMemAlign(64)}});
355 StoreActions.legalForTypesWithMemDesc(
356 {{s64, p0, s8, getScalarMemAlign(8)},
357 {s64, p0, s16, getScalarMemAlign(16)},
358 {s64, p0, s32, getScalarMemAlign(32)},
359 {s64, p0, s64, getScalarMemAlign(64)}});
360 ExtLoadActions.legalForTypesWithMemDesc(
361 {{s64, p0, s32, getScalarMemAlign(32)}});
362 } else if (ST.hasStdExtD()) {
363 LoadActions.legalForTypesWithMemDesc(
364 {{s64, p0, s64, getScalarMemAlign(64)}});
365 StoreActions.legalForTypesWithMemDesc(
366 {{s64, p0, s64, getScalarMemAlign(64)}});
367 }
368
369 // Vector loads/stores.
370 if (ST.hasVInstructions()) {
371 LoadActions.legalForTypesWithMemDesc({{nxv2s8, p0, nxv2s8, 8},
372 {nxv4s8, p0, nxv4s8, 8},
373 {nxv8s8, p0, nxv8s8, 8},
374 {nxv16s8, p0, nxv16s8, 8},
375 {nxv32s8, p0, nxv32s8, 8},
376 {nxv64s8, p0, nxv64s8, 8},
377 {nxv2s16, p0, nxv2s16, 16},
378 {nxv4s16, p0, nxv4s16, 16},
379 {nxv8s16, p0, nxv8s16, 16},
380 {nxv16s16, p0, nxv16s16, 16},
381 {nxv32s16, p0, nxv32s16, 16},
382 {nxv2s32, p0, nxv2s32, 32},
383 {nxv4s32, p0, nxv4s32, 32},
384 {nxv8s32, p0, nxv8s32, 32},
385 {nxv16s32, p0, nxv16s32, 32}});
386 StoreActions.legalForTypesWithMemDesc({{nxv2s8, p0, nxv2s8, 8},
387 {nxv4s8, p0, nxv4s8, 8},
388 {nxv8s8, p0, nxv8s8, 8},
389 {nxv16s8, p0, nxv16s8, 8},
390 {nxv32s8, p0, nxv32s8, 8},
391 {nxv64s8, p0, nxv64s8, 8},
392 {nxv2s16, p0, nxv2s16, 16},
393 {nxv4s16, p0, nxv4s16, 16},
394 {nxv8s16, p0, nxv8s16, 16},
395 {nxv16s16, p0, nxv16s16, 16},
396 {nxv32s16, p0, nxv32s16, 16},
397 {nxv2s32, p0, nxv2s32, 32},
398 {nxv4s32, p0, nxv4s32, 32},
399 {nxv8s32, p0, nxv8s32, 32},
400 {nxv16s32, p0, nxv16s32, 32}});
401
402 if (ST.getELen() == 64) {
403 LoadActions.legalForTypesWithMemDesc({{nxv1s8, p0, nxv1s8, 8},
404 {nxv1s16, p0, nxv1s16, 16},
405 {nxv1s32, p0, nxv1s32, 32}});
406 StoreActions.legalForTypesWithMemDesc({{nxv1s8, p0, nxv1s8, 8},
407 {nxv1s16, p0, nxv1s16, 16},
408 {nxv1s32, p0, nxv1s32, 32}});
409 }
410
411 if (ST.hasVInstructionsI64()) {
412 LoadActions.legalForTypesWithMemDesc({{nxv1s64, p0, nxv1s64, 64},
413 {nxv2s64, p0, nxv2s64, 64},
414 {nxv4s64, p0, nxv4s64, 64},
415 {nxv8s64, p0, nxv8s64, 64}});
416 StoreActions.legalForTypesWithMemDesc({{nxv1s64, p0, nxv1s64, 64},
417 {nxv2s64, p0, nxv2s64, 64},
418 {nxv4s64, p0, nxv4s64, 64},
419 {nxv8s64, p0, nxv8s64, 64}});
420 }
421
422 // we will take the custom lowering logic if we have scalable vector types
423 // with non-standard alignments
424 LoadActions.customIf(typeIsLegalIntOrFPVec(0, IntOrFPVecTys, ST));
425 StoreActions.customIf(typeIsLegalIntOrFPVec(0, IntOrFPVecTys, ST));
426
427 // Pointers require that XLen sized elements are legal.
428 if (XLen <= ST.getELen()) {
429 LoadActions.customIf(typeIsLegalPtrVec(0, PtrVecTys, ST));
430 StoreActions.customIf(typeIsLegalPtrVec(0, PtrVecTys, ST));
431 }
432 }
433
434 LoadActions.widenScalarToNextPow2(0, /* MinSize = */ 8)
435 .lowerIfMemSizeNotByteSizePow2()
436 .clampScalar(0, s16, sXLen)
437 .lower();
438 StoreActions
439 .clampScalar(0, s16, sXLen)
440 .lowerIfMemSizeNotByteSizePow2()
441 .lower();
442
443 ExtLoadActions.widenScalarToNextPow2(0).clampScalar(0, sXLen, sXLen).lower();
444
445 getActionDefinitionsBuilder({G_PTR_ADD, G_PTRMASK}).legalFor({{p0, sXLen}});
446
447 getActionDefinitionsBuilder(G_PTRTOINT)
448 .legalFor({{sXLen, p0}})
449 .clampScalar(0, sXLen, sXLen);
450
451 getActionDefinitionsBuilder(G_INTTOPTR)
452 .legalFor({{p0, sXLen}})
453 .clampScalar(1, sXLen, sXLen);
454
455 getActionDefinitionsBuilder(G_BR).alwaysLegal();
456
457 getActionDefinitionsBuilder(G_BRCOND).legalFor({sXLen}).minScalar(0, sXLen);
458
459 getActionDefinitionsBuilder(G_BRJT).customFor({{p0, sXLen}});
460
461 getActionDefinitionsBuilder(G_BRINDIRECT).legalFor({p0});
462
463 getActionDefinitionsBuilder(G_PHI)
464 .legalFor({p0, s32, sXLen})
465 .widenScalarToNextPow2(0)
466 .clampScalar(0, s32, sXLen);
467
468 getActionDefinitionsBuilder({G_GLOBAL_VALUE, G_JUMP_TABLE, G_CONSTANT_POOL})
469 .legalFor({p0});
470
471 if (ST.hasStdExtZmmul()) {
472 getActionDefinitionsBuilder(G_MUL)
473 .legalFor({sXLen})
474 .widenScalarToNextPow2(0)
475 .clampScalar(0, sXLen, sXLen);
476
477 // clang-format off
478 getActionDefinitionsBuilder({G_SMULH, G_UMULH})
479 .legalFor({sXLen})
480 .lower();
481 // clang-format on
482
483 getActionDefinitionsBuilder({G_SMULO, G_UMULO}).minScalar(0, sXLen).lower();
484 } else {
485 getActionDefinitionsBuilder(G_MUL)
486 .libcallFor({sXLen, sDoubleXLen})
487 .widenScalarToNextPow2(0)
488 .clampScalar(0, sXLen, sDoubleXLen);
489
490 getActionDefinitionsBuilder({G_SMULH, G_UMULH}).lowerFor({sXLen});
491
492 getActionDefinitionsBuilder({G_SMULO, G_UMULO})
493 .minScalar(0, sXLen)
494 // Widen sXLen to sDoubleXLen so we can use a single libcall to get
495 // the low bits for the mul result and high bits to do the overflow
496 // check.
497 .widenScalarIf(typeIs(0, sXLen),
498 LegalizeMutations::changeTo(0, sDoubleXLen))
499 .lower();
500 }
501
502 if (ST.hasStdExtM()) {
503 getActionDefinitionsBuilder({G_SDIV, G_UDIV, G_UREM})
504 .legalFor({sXLen})
505 .customFor({s32})
506 .libcallFor({sDoubleXLen})
507 .clampScalar(0, s32, sDoubleXLen)
508 .widenScalarToNextPow2(0);
509 getActionDefinitionsBuilder(G_SREM)
510 .legalFor({sXLen})
511 .libcallFor({sDoubleXLen})
512 .clampScalar(0, sXLen, sDoubleXLen)
513 .widenScalarToNextPow2(0);
514 } else {
515 getActionDefinitionsBuilder({G_UDIV, G_SDIV, G_UREM, G_SREM})
516 .libcallFor({sXLen, sDoubleXLen})
517 .clampScalar(0, sXLen, sDoubleXLen)
518 .widenScalarToNextPow2(0);
519 }
520
521 // TODO: Use libcall for sDoubleXLen.
522 getActionDefinitionsBuilder({G_SDIVREM, G_UDIVREM}).lower();
523
524 getActionDefinitionsBuilder(G_ABS)
525 .customFor(ST.hasStdExtZbb(), {sXLen})
526 .minScalar(ST.hasStdExtZbb(), 0, sXLen)
527 .lower();
528
529 getActionDefinitionsBuilder({G_ABDS, G_ABDU})
530 .minScalar(ST.hasStdExtZbb(), 0, sXLen)
531 .lower();
532
533 getActionDefinitionsBuilder({G_UMAX, G_UMIN, G_SMAX, G_SMIN})
534 .legalFor(ST.hasStdExtZbb(), {sXLen})
535 .minScalar(ST.hasStdExtZbb(), 0, sXLen)
536 .lower();
537
538 getActionDefinitionsBuilder({G_SCMP, G_UCMP}).lower();
539
540 getActionDefinitionsBuilder(G_FRAME_INDEX).legalFor({p0});
541
542 getActionDefinitionsBuilder({G_MEMCPY, G_MEMMOVE, G_MEMSET}).libcall();
543
544 getActionDefinitionsBuilder({G_MEMCPY_INLINE, G_MEMSET_INLINE}).lower();
545
546 getActionDefinitionsBuilder({G_DYN_STACKALLOC, G_STACKSAVE, G_STACKRESTORE})
547 .lower();
548
549 // On RV64 the 64-bit counter CSRs (cycle/time) are read directly. On RV32
550 // they are custom-legally lowered to a re-read-the-high-half loop (see
551 // legalizeReadCounter).
552 getActionDefinitionsBuilder({G_READCYCLECOUNTER, G_READSTEADYCOUNTER})
553 .legalFor(ST.is64Bit(), {s64})
554 .customFor(!ST.is64Bit(), {s64});
555
556 // FP Operations
557
558 // FIXME: Support s128 for rv32 when libcall handling is able to use sret.
559 getActionDefinitionsBuilder({G_FADD, G_FSUB, G_FMUL, G_FDIV, G_FMA, G_FSQRT,
560 G_FMAXNUM, G_FMINNUM, G_FMAXIMUMNUM,
561 G_FMINIMUMNUM})
562 .legalFor(ST.hasStdExtF(), {s32})
563 .legalFor(ST.hasStdExtD(), {s64})
564 .legalFor(ST.hasStdExtZfh(), {s16})
565 .libcallFor({s32, s64})
566 .libcallFor(ST.is64Bit(), {s128});
567
568 getActionDefinitionsBuilder({G_FNEG, G_FABS})
569 .legalFor(ST.hasStdExtF(), {s32})
570 .legalFor(ST.hasStdExtD(), {s64})
571 .legalFor(ST.hasStdExtZfh(), {s16})
572 .lowerFor({s32, s64, s128});
573
574 getActionDefinitionsBuilder(G_FREM)
575 .libcallFor({s32, s64})
576 .libcallFor(ST.is64Bit(), {s128})
577 .minScalar(0, s32)
578 .scalarize(0);
579
580 getActionDefinitionsBuilder(G_FCOPYSIGN)
581 .legalFor(ST.hasStdExtF(), {{s32, s32}})
582 .legalFor(ST.hasStdExtD(), {{s64, s64}, {s32, s64}, {s64, s32}})
583 .legalFor(ST.hasStdExtZfh(), {{s16, s16}, {s16, s32}, {s32, s16}})
584 .legalFor(ST.hasStdExtZfh() && ST.hasStdExtD(), {{s16, s64}, {s64, s16}})
585 .lower();
586
587 // FIXME: Use Zfhmin.
588 getActionDefinitionsBuilder(G_FPTRUNC)
589 .legalFor(ST.hasStdExtD(), {{s32, s64}})
590 .legalFor(ST.hasStdExtZfh(), {{s16, s32}})
591 .legalFor(ST.hasStdExtZfh() && ST.hasStdExtD(), {{s16, s64}})
592 .libcallFor({{s32, s64}})
593 .libcallFor(ST.is64Bit(), {{s32, s128}, {s64, s128}});
594 getActionDefinitionsBuilder(G_FPEXT)
595 .legalFor(ST.hasStdExtD(), {{s64, s32}})
596 .legalFor(ST.hasStdExtZfh(), {{s32, s16}})
597 .legalFor(ST.hasStdExtZfh() && ST.hasStdExtD(), {{s64, s16}})
598 .libcallFor({{s64, s32}})
599 .libcallFor(ST.is64Bit(), {{s128, s32}, {s128, s64}});
600
601 getActionDefinitionsBuilder(G_FCMP)
602 .legalFor(ST.hasStdExtF(), {{sXLen, s32}})
603 .legalFor(ST.hasStdExtD(), {{sXLen, s64}})
604 .legalFor(ST.hasStdExtZfh(), {{sXLen, s16}})
605 .clampScalar(0, sXLen, sXLen)
606 .libcallFor({{sXLen, s32}, {sXLen, s64}})
607 .libcallFor(ST.is64Bit(), {{sXLen, s128}});
608
609 // TODO: Support vector version of G_IS_FPCLASS.
610 getActionDefinitionsBuilder(G_IS_FPCLASS)
611 .customFor(ST.hasStdExtF(), {{s1, s32}})
612 .customFor(ST.hasStdExtD(), {{s1, s64}})
613 .customFor(ST.hasStdExtZfh(), {{s1, s16}})
614 .lower();
615
616 getActionDefinitionsBuilder(G_FCONSTANT)
617 .legalFor(ST.hasStdExtF(), {s32})
618 .legalFor(ST.hasStdExtD(), {s64})
619 .legalFor(ST.hasStdExtZfh(), {s16})
620 .customFor(!ST.is64Bit(), {s32})
621 .customFor(ST.is64Bit(), {s32, s64})
622 .lowerFor({s64, s128});
623
624 getActionDefinitionsBuilder({G_FPTOSI, G_FPTOUI})
625 .legalFor(ST.hasStdExtF(), {{sXLen, s32}})
626 .legalFor(ST.hasStdExtD(), {{sXLen, s64}})
627 .legalFor(ST.hasStdExtZfh(), {{sXLen, s16}})
628 .customFor(ST.is64Bit() && ST.hasStdExtF(), {{s32, s32}})
629 .customFor(ST.is64Bit() && ST.hasStdExtD(), {{s32, s64}})
630 .customFor(ST.is64Bit() && ST.hasStdExtZfh(), {{s32, s16}})
631 .widenScalarToNextPow2(0)
632 .minScalar(0, s32)
633 .libcallFor({{s32, s32}, {s64, s32}, {s32, s64}, {s64, s64}})
634 .libcallFor(ST.is64Bit(), {{s32, s128}, {s64, s128}}) // FIXME RV32.
635 .libcallFor(ST.is64Bit(), {{s128, s32}, {s128, s64}, {s128, s128}});
636
637 getActionDefinitionsBuilder({G_LROUND, G_LLROUND})
638 .legalFor(ST.hasStdExtF(), {{sXLen, s32}})
639 .legalFor(ST.hasStdExtD(), {{sXLen, s64}})
640 .legalFor(ST.hasStdExtZfh(), {{sXLen, s16}})
641 .customFor(ST.is64Bit() && ST.hasStdExtF(), {{s32, s32}})
642 .customFor(ST.is64Bit() && ST.hasStdExtD(), {{s32, s64}})
643 .customFor(ST.is64Bit() && ST.hasStdExtZfh(), {{s32, s16}})
644 .widenScalarIf(typeIs(1, s16), LegalizeMutations::changeTo(1, s32))
645 .libcallFor({{s32, s32},
646 {s64, s32},
647 {s32, s64},
648 {s64, s64},
649 {s32, s128},
650 {s64, s128}});
651
652 getActionDefinitionsBuilder({G_SITOFP, G_UITOFP})
653 .legalFor(ST.hasStdExtF(), {{s32, sXLen}})
654 .legalFor(ST.hasStdExtD(), {{s64, sXLen}})
655 .legalFor(ST.hasStdExtZfh(), {{s16, sXLen}})
656 .widenScalarToNextPow2(1)
657 // Promote to XLen if the operation is legal.
658 .widenScalarIf(
659 [=, &ST](const LegalityQuery &Query) {
660 return Query.Types[0].isScalar() && Query.Types[1].isScalar() &&
661 (Query.Types[1].getSizeInBits() < ST.getXLen()) &&
662 ((ST.hasStdExtF() && Query.Types[0].getSizeInBits() == 32) ||
663 (ST.hasStdExtD() && Query.Types[0].getSizeInBits() == 64) ||
664 (ST.hasStdExtZfh() &&
665 Query.Types[0].getSizeInBits() == 16));
666 },
668 // Otherwise only promote to s32 since we have si libcalls.
669 .minScalar(1, s32)
670 .libcallFor({{s32, s32}, {s64, s32}, {s32, s64}, {s64, s64}})
671 .libcallFor(ST.is64Bit(), {{s128, s32}, {s128, s64}}) // FIXME RV32.
672 .libcallFor(ST.is64Bit(), {{s32, s128}, {s64, s128}, {s128, s128}});
673
674 // FIXME: We can do custom inline expansion like SelectionDAG.
675 getActionDefinitionsBuilder({G_FCEIL, G_FFLOOR, G_FRINT, G_FNEARBYINT,
676 G_INTRINSIC_TRUNC, G_INTRINSIC_ROUND,
677 G_INTRINSIC_ROUNDEVEN})
678 .legalFor(ST.hasStdExtZfa(), {s32})
679 .legalFor(ST.hasStdExtZfa() && ST.hasStdExtD(), {s64})
680 .legalFor(ST.hasStdExtZfa() && ST.hasStdExtZfh(), {s16})
681 .libcallFor({s32, s64})
682 .libcallFor(ST.is64Bit(), {s128});
683
684 getActionDefinitionsBuilder({G_FMAXIMUM, G_FMINIMUM})
685 .legalFor(ST.hasStdExtZfa(), {s32})
686 .legalFor(ST.hasStdExtZfa() && ST.hasStdExtD(), {s64})
687 .legalFor(ST.hasStdExtZfa() && ST.hasStdExtZfh(), {s16});
688
689 getActionDefinitionsBuilder({G_FCOS, G_FSIN, G_FTAN, G_FPOW, G_FLOG, G_FLOG2,
690 G_FLOG10, G_FEXP, G_FEXP2, G_FEXP10, G_FACOS,
691 G_FASIN, G_FATAN, G_FATAN2, G_FCOSH, G_FSINH,
692 G_FTANH, G_FMODF})
693 .libcallFor({s32, s64})
694 .libcallFor(ST.is64Bit(), {s128});
695 getActionDefinitionsBuilder({G_FPOWI, G_FLDEXP})
696 .libcallFor({{s32, s32}, {s64, s32}})
697 .libcallFor(ST.is64Bit(), {s128, s32});
698
699 getActionDefinitionsBuilder(G_FCANONICALIZE)
700 .legalFor(ST.hasStdExtF(), {s32})
701 .legalFor(ST.hasStdExtD(), {s64})
702 .legalFor(ST.hasStdExtZfh(), {s16});
703
704 getActionDefinitionsBuilder(G_VASTART).customFor({p0});
705
706 // va_list must be a pointer, but most sized types are pretty easy to handle
707 // as the destination.
708 getActionDefinitionsBuilder(G_VAARG)
709 // TODO: Implement narrowScalar and widenScalar for G_VAARG for types
710 // other than sXLen.
711 .clampScalar(0, sXLen, sXLen)
712 .lowerForCartesianProduct({sXLen, p0}, {p0});
713
714 getActionDefinitionsBuilder(G_VSCALE)
715 .clampScalar(0, sXLen, sXLen)
716 .customFor({sXLen});
717
718 auto &SplatActions =
719 getActionDefinitionsBuilder(G_SPLAT_VECTOR)
720 .legalIf(all(typeIsLegalIntOrFPVec(0, IntOrFPVecTys, ST),
721 typeIs(1, sXLen)))
722 .customIf(all(typeIsLegalBoolVec(0, BoolVecTys, ST), typeIs(1, s1)));
723 // Handle case of s64 element vectors on RV32. If the subtarget does not have
724 // f64, then try to lower it to G_SPLAT_VECTOR_SPLIT_64_VL. If the subtarget
725 // does have f64, then we don't know whether the type is an f64 or an i64,
726 // so mark the G_SPLAT_VECTOR as legal and decide later what to do with it,
727 // depending on how the instructions it consumes are legalized. They are not
728 // legalized yet since legalization is in reverse postorder, so we cannot
729 // make the decision at this moment.
730 if (XLen == 32) {
731 if (ST.hasVInstructionsF64() && ST.hasStdExtD())
732 SplatActions.legalIf(all(
733 typeInSet(0, {nxv1s64, nxv2s64, nxv4s64, nxv8s64}), typeIs(1, s64)));
734 else if (ST.hasVInstructionsI64())
735 SplatActions.customIf(all(
736 typeInSet(0, {nxv1s64, nxv2s64, nxv4s64, nxv8s64}), typeIs(1, s64)));
737 }
738
739 SplatActions.clampScalar(1, sXLen, sXLen);
740
741 LegalityPredicate ExtractSubvecBitcastPred = [=](const LegalityQuery &Query) {
742 LLT DstTy = Query.Types[0];
743 LLT SrcTy = Query.Types[1];
744 return DstTy.getElementType() == LLT::scalar(1) &&
745 DstTy.getElementCount().getKnownMinValue() >= 8 &&
746 SrcTy.getElementCount().getKnownMinValue() >= 8;
747 };
748 getActionDefinitionsBuilder(G_EXTRACT_SUBVECTOR)
749 // We don't have the ability to slide mask vectors down indexed by their
750 // i1 elements; the smallest we can do is i8. Often we are able to bitcast
751 // to equivalent i8 vectors.
752 .bitcastIf(
753 all(typeIsLegalBoolVec(0, BoolVecTys, ST),
754 typeIsLegalBoolVec(1, BoolVecTys, ST), ExtractSubvecBitcastPred),
755 [=](const LegalityQuery &Query) {
756 LLT CastTy = LLT::vector(
757 Query.Types[0].getElementCount().divideCoefficientBy(8), 8);
758 return std::pair(0, CastTy);
759 })
760 .customIf(LegalityPredicates::any(
761 all(typeIsLegalBoolVec(0, BoolVecTys, ST),
762 typeIsLegalBoolVec(1, BoolVecTys, ST)),
763 all(typeIsLegalIntOrFPVec(0, IntOrFPVecTys, ST),
764 typeIsLegalIntOrFPVec(1, IntOrFPVecTys, ST))));
765
766 getActionDefinitionsBuilder(G_INSERT_SUBVECTOR)
767 .customIf(all(typeIsLegalBoolVec(0, BoolVecTys, ST),
768 typeIsLegalBoolVec(1, BoolVecTys, ST)))
769 .customIf(all(typeIsLegalIntOrFPVec(0, IntOrFPVecTys, ST),
770 typeIsLegalIntOrFPVec(1, IntOrFPVecTys, ST)));
771
772 getActionDefinitionsBuilder(G_ATOMIC_CMPXCHG_WITH_SUCCESS)
773 .lowerIf(all(typeInSet(0, {s8, s16, s32, s64}), typeIs(2, p0)));
774
775 getActionDefinitionsBuilder({G_ATOMIC_CMPXCHG, G_ATOMICRMW_ADD,
776 G_ATOMICRMW_XCHG, G_ATOMICRMW_AND,
777 G_ATOMICRMW_OR, G_ATOMICRMW_XOR})
778 .legalFor(ST.hasStdExtA(), {{sXLen, p0}})
779 .libcallFor(!ST.hasStdExtA(), {{s8, p0}, {s16, p0}, {s32, p0}, {s64, p0}})
780 .clampScalar(0, sXLen, sXLen);
781
782 getActionDefinitionsBuilder(G_ATOMICRMW_SUB)
783 .libcallFor(!ST.hasStdExtA(), {{s8, p0}, {s16, p0}, {s32, p0}, {s64, p0}})
784 .clampScalar(0, sXLen, sXLen)
785 .lower();
786
787 getActionDefinitionsBuilder(
788 {G_ATOMICRMW_MAX, G_ATOMICRMW_MIN, G_ATOMICRMW_UMAX, G_ATOMICRMW_UMIN})
789 .legalFor(ST.hasStdExtA(), {{sXLen, p0}})
790 .clampScalar(0, sXLen, sXLen)
791 .unsupported();
792
793 getActionDefinitionsBuilder(G_PREFETCH).legalIf(typeIs(0, p0));
794
795 LegalityPredicate InsertVectorEltPred = [=](const LegalityQuery &Query) {
796 LLT VecTy = Query.Types[0];
797 LLT EltTy = Query.Types[1];
798 return VecTy.getElementType() == EltTy;
799 };
800
801 getActionDefinitionsBuilder(G_INSERT_VECTOR_ELT)
802 .legalIf(all(typeIsLegalIntOrFPVec(0, IntOrFPVecTys, ST),
803 InsertVectorEltPred, typeIs(2, sXLen)))
804 .legalIf(all(typeIsLegalBoolVec(0, BoolVecTys, ST), InsertVectorEltPred,
805 typeIs(2, sXLen)));
806
807 getActionDefinitionsBuilder({G_INTRINSIC, G_INTRINSIC_W_SIDE_EFFECTS})
808 .alwaysLegal();
809
810 getActionDefinitionsBuilder(G_FENCE).alwaysLegal();
811
812 getActionDefinitionsBuilder({G_TRAP, G_DEBUGTRAP, G_UBSANTRAP}).alwaysLegal();
813
814 verify(*ST.getInstrInfo());
815}
816
818 MachineInstr &MI) const {
819 Intrinsic::ID IntrinsicID = cast<GIntrinsic>(MI).getIntrinsicID();
820
822 RISCVVIntrinsicsTable::getRISCVVIntrinsicInfo(IntrinsicID)) {
823 if (II->hasScalarOperand() && !II->IsFPIntrinsic) {
824 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
825 MachineRegisterInfo &MRI = *MIRBuilder.getMRI();
826
827 auto OldScalar = MI.getOperand(II->ScalarOperand + 2).getReg();
828 // Legalize integer vx form intrinsic.
829 if (MRI.getType(OldScalar).isScalar()) {
830 if (MRI.getType(OldScalar).getSizeInBits() < sXLen.getSizeInBits()) {
831 Helper.Observer.changingInstr(MI);
832 Helper.widenScalarSrc(MI, sXLen, II->ScalarOperand + 2,
833 TargetOpcode::G_ANYEXT);
834 Helper.Observer.changedInstr(MI);
835 } else if (MRI.getType(OldScalar).getSizeInBits() >
836 sXLen.getSizeInBits()) {
837 // TODO: i64 in riscv32.
838 return false;
839 }
840 }
841 }
842 return true;
843 }
844
845 switch (IntrinsicID) {
846 default:
847 return false;
848 case Intrinsic::vacopy: {
849 // vacopy arguments must be legal because of the intrinsic signature.
850 // No need to check here.
851
852 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
853 MachineRegisterInfo &MRI = *MIRBuilder.getMRI();
854 MachineFunction &MF = *MI.getMF();
855 const DataLayout &DL = MIRBuilder.getDataLayout();
856 LLVMContext &Ctx = MF.getFunction().getContext();
857
858 Register DstLst = MI.getOperand(1).getReg();
859 LLT PtrTy = MRI.getType(DstLst);
860
861 // Load the source va_list
862 Align Alignment = DL.getABITypeAlign(getTypeForLLT(PtrTy, Ctx));
864 MachinePointerInfo(), MachineMemOperand::MOLoad, PtrTy, Alignment);
865 auto Tmp = MIRBuilder.buildLoad(PtrTy, MI.getOperand(2), *LoadMMO);
866
867 // Store the result in the destination va_list
870 MIRBuilder.buildStore(Tmp, DstLst, *StoreMMO);
871
872 MI.eraseFromParent();
873 return true;
874 }
875 case Intrinsic::riscv_vsetvli:
876 case Intrinsic::riscv_vsetvlimax:
877 case Intrinsic::riscv_masked_atomicrmw_add:
878 case Intrinsic::riscv_masked_atomicrmw_sub:
879 case Intrinsic::riscv_masked_atomicrmw_xchg:
880 case Intrinsic::riscv_masked_atomicrmw_max:
881 case Intrinsic::riscv_masked_atomicrmw_min:
882 case Intrinsic::riscv_masked_atomicrmw_umax:
883 case Intrinsic::riscv_masked_atomicrmw_umin:
884 case Intrinsic::riscv_masked_cmpxchg:
885 return true;
886 }
887}
888
889bool RISCVLegalizerInfo::legalizeVAStart(MachineInstr &MI,
890 MachineIRBuilder &MIRBuilder) const {
891 // Stores the address of the VarArgsFrameIndex slot into the memory location
892 assert(MI.getOpcode() == TargetOpcode::G_VASTART);
893 MachineFunction *MF = MI.getParent()->getParent();
895 int FI = FuncInfo->getVarArgsFrameIndex();
896 LLT AddrTy = MIRBuilder.getMRI()->getType(MI.getOperand(0).getReg());
897 auto FINAddr = MIRBuilder.buildFrameIndex(AddrTy, FI);
898 assert(MI.hasOneMemOperand());
899 MIRBuilder.buildStore(FINAddr, MI.getOperand(0).getReg(),
900 *MI.memoperands()[0]);
901 MI.eraseFromParent();
902 return true;
903}
904
905bool RISCVLegalizerInfo::legalizeReadCounter(
906 MachineInstr &MI, MachineIRBuilder &MIRBuilder,
907 GISelChangeObserver &Observer) const {
908 assert((MI.getOpcode() == TargetOpcode::G_READCYCLECOUNTER ||
909 MI.getOpcode() == TargetOpcode::G_READSTEADYCOUNTER) &&
910 "Unexpected opcode");
911 assert(!STI.is64Bit() && "READCYCLECOUNTER/READSTEADYCOUNTER only "
912 "has custom type legalization on riscv32");
913
914 // On RV32 a 64-bit counter CSR must be read as two 32-bit halves. Because
915 // the count may wrap between the two reads, re-read the high half and loop
916 // until the two high reads agree.
917 int64_t LoCounter, HiCounter;
918 if (MI.getOpcode() == TargetOpcode::G_READCYCLECOUNTER) {
919 LoCounter = RISCVSysReg::cycle;
920 HiCounter = RISCVSysReg::cycleh;
921 } else {
922 LoCounter = RISCVSysReg::time;
923 HiCounter = RISCVSysReg::timeh;
924 }
925
926 MachineBasicBlock *BB = MI.getParent();
927 MachineFunction &MF = *BB->getParent();
928 const BasicBlock *LLVMBB = BB->getBasicBlock();
929 DebugLoc DL = MI.getDebugLoc();
930 MachineRegisterInfo &MRI = *MIRBuilder.getMRI();
931
932 // Split BB into an entry that falls through into a loop block, and a done
933 // block that receives the remainder of BB and its original successors.
934 MachineFunction::iterator It = std::next(BB->getIterator());
935 MachineBasicBlock *LoopMBB = MF.CreateMachineBasicBlock(LLVMBB);
936 MachineBasicBlock *DoneMBB = MF.CreateMachineBasicBlock(LLVMBB);
937 MF.insert(It, LoopMBB);
938 MF.insert(It, DoneMBB);
939
940 // Splice the instructions after the readcyclecounter into DoneMBB, notifying
941 // the observer about each moved instruction so CSEInfo stays consistent.
942 for (MachineBasicBlock::iterator I = std::next(MI.getIterator()),
943 E = BB->end();
944 I != E; ++I)
945 Observer.changingInstr(*I);
946 DoneMBB->splice(DoneMBB->begin(), BB,
947 std::next(MachineBasicBlock::iterator(MI)), BB->end());
948 for (MachineInstr &MovedMI : DoneMBB->instrs())
949 Observer.changedInstr(MovedMI);
951 BB->addSuccessor(LoopMBB);
952
953 LLT S32 = LLT::scalar(32);
954 // Generic vregs carry the s32 type for G_MERGE_VALUES below, but are also
955 // constrained to GPR so the target CSRRS/BNE instructions satisfy the
956 // verifier's register-class constraints.
957 auto CreateGPR = [&]() {
959 MRI.setRegClass(R, &RISCV::GPRRegClass);
960 return R;
961 };
962 Register LoReg = CreateGPR();
963 Register HiReg = CreateGPR();
964 Register ReadAgainReg = CreateGPR();
965
966 // read:
967 // csrrs HiReg, counterh # high word
968 // csrrs LoReg, counter # low word
969 // csrrs ReadAgainReg, counterh
970 // bne HiReg, ReadAgainReg, read
971 // Emit the target instructions directly with BuildMI.
972 const RISCVInstrInfo *TII = STI.getInstrInfo();
973 BuildMI(LoopMBB, DL, TII->get(RISCV::CSRRS), HiReg)
974 .addImm(HiCounter)
975 .addReg(RISCV::X0);
976 BuildMI(LoopMBB, DL, TII->get(RISCV::CSRRS), LoReg)
977 .addImm(LoCounter)
978 .addReg(RISCV::X0);
979 BuildMI(LoopMBB, DL, TII->get(RISCV::CSRRS), ReadAgainReg)
980 .addImm(HiCounter)
981 .addReg(RISCV::X0);
982
983 BuildMI(LoopMBB, DL, TII->get(RISCV::BNE))
984 .addReg(HiReg)
985 .addReg(ReadAgainReg)
986 .addMBB(LoopMBB);
987
988 LoopMBB->addSuccessor(LoopMBB);
989 LoopMBB->addSuccessor(DoneMBB);
990
991 // Re-pair the two halves into the 64-bit result.
992 Register DstReg = MI.getOperand(0).getReg();
993 Observer.erasingInstr(MI);
994 MI.eraseFromParent();
995
996 MIRBuilder.setInsertPt(*DoneMBB, DoneMBB->begin());
997 MIRBuilder.setDebugLoc(DL);
998 MIRBuilder.buildMergeValues(DstReg, {LoReg, HiReg});
999 return true;
1000}
1001
1002bool RISCVLegalizerInfo::legalizeBRJT(MachineInstr &MI,
1003 MachineIRBuilder &MIRBuilder) const {
1004 MachineRegisterInfo &MRI = *MIRBuilder.getMRI();
1005 auto &MF = *MI.getParent()->getParent();
1006 const MachineJumpTableInfo *MJTI = MF.getJumpTableInfo();
1007 unsigned EntrySize = MJTI->getEntrySize(MF.getDataLayout());
1008
1009 Register PtrReg = MI.getOperand(0).getReg();
1010 LLT PtrTy = MRI.getType(PtrReg);
1011 Register IndexReg = MI.getOperand(2).getReg();
1012 LLT IndexTy = MRI.getType(IndexReg);
1013
1014 if (!isPowerOf2_32(EntrySize))
1015 return false;
1016
1017 auto ShiftAmt = MIRBuilder.buildConstant(IndexTy, Log2_32(EntrySize));
1018 IndexReg = MIRBuilder.buildShl(IndexTy, IndexReg, ShiftAmt).getReg(0);
1019
1020 auto Addr = MIRBuilder.buildPtrAdd(PtrTy, PtrReg, IndexReg);
1021
1022 MachineMemOperand *MMO = MF.getMachineMemOperand(
1024 EntrySize, Align(MJTI->getEntryAlignment(MF.getDataLayout())));
1025
1026 Register TargetReg;
1027 switch (MJTI->getEntryKind()) {
1028 default:
1029 return false;
1031 // For PIC, the sequence is:
1032 // BRIND(load(Jumptable + index) + RelocBase)
1033 // RelocBase can be JumpTable, GOT or some sort of global base.
1034 unsigned LoadOpc =
1035 STI.is64Bit() ? TargetOpcode::G_SEXTLOAD : TargetOpcode::G_LOAD;
1036 auto Load = MIRBuilder.buildLoadInstr(LoadOpc, IndexTy, Addr, *MMO);
1037 TargetReg = MIRBuilder.buildPtrAdd(PtrTy, PtrReg, Load).getReg(0);
1038 break;
1039 }
1041 auto Load = MIRBuilder.buildLoadInstr(TargetOpcode::G_SEXTLOAD, IndexTy,
1042 Addr, *MMO);
1043 TargetReg = MIRBuilder.buildIntToPtr(PtrTy, Load).getReg(0);
1044 break;
1045 }
1047 TargetReg = MIRBuilder.buildLoad(PtrTy, Addr, *MMO).getReg(0);
1048 break;
1049 }
1050
1051 MIRBuilder.buildBrIndirect(TargetReg);
1052
1053 MI.eraseFromParent();
1054 return true;
1055}
1056
1057bool RISCVLegalizerInfo::shouldBeInConstantPool(const APInt &APImm,
1058 bool ShouldOptForSize) const {
1059 assert(APImm.getBitWidth() == 32 || APImm.getBitWidth() == 64);
1060 int64_t Imm = APImm.getSExtValue();
1061 // All simm32 constants should be handled by isel.
1062 // NOTE: The getMaxBuildIntsCost call below should return a value >= 2 making
1063 // this check redundant, but small immediates are common so this check
1064 // should have better compile time.
1065 if (isInt<32>(Imm))
1066 return false;
1067
1068 // We only need to cost the immediate, if constant pool lowering is enabled.
1069 if (!STI.useConstantPoolForLargeInts())
1070 return false;
1071
1073 if (Seq.size() <= STI.getMaxBuildIntsCost())
1074 return false;
1075
1076 // Optimizations below are disabled for opt size. If we're optimizing for
1077 // size, use a constant pool.
1078 if (ShouldOptForSize)
1079 return true;
1080 //
1081 // Special case. See if we can build the constant as (ADD (SLLI X, C), X) do
1082 // that if it will avoid a constant pool.
1083 // It will require an extra temporary register though.
1084 // If we have Zba we can use (ADD_UW X, (SLLI X, 32)) to handle cases where
1085 // low and high 32 bits are the same and bit 31 and 63 are set.
1086 unsigned ShiftAmt, AddOpc;
1087 RISCVMatInt::InstSeq SeqLo =
1088 RISCVMatInt::generateTwoRegInstSeq(Imm, STI, ShiftAmt, AddOpc);
1089 return !(!SeqLo.empty() && (SeqLo.size() + 2) <= STI.getMaxBuildIntsCost());
1090}
1091
1092bool RISCVLegalizerInfo::legalizeVScale(MachineInstr &MI,
1093 MachineIRBuilder &MIB) const {
1094 Register Dst = MI.getOperand(0).getReg();
1095
1096 // We define our scalable vector types for lmul=1 to use a 64 bit known
1097 // minimum size. e.g. <vscale x 2 x i32>. VLENB is in bytes so we calculate
1098 // vscale as VLENB / 8.
1099 static_assert(RISCV::RVVBitsPerBlock == 64, "Unexpected bits per block!");
1100 if (STI.getRealMinVLen() < RISCV::RVVBitsPerBlock)
1101 // Support for VLEN==32 is incomplete.
1102 return false;
1103
1104 // We assume VLENB is a multiple of 8. We manually choose the best shift
1105 // here because SimplifyDemandedBits isn't always able to simplify it.
1106 uint64_t Val = MI.getOperand(1).getCImm()->getZExtValue();
1107 if (isPowerOf2_64(Val)) {
1108 uint64_t Log2 = Log2_64(Val);
1109 if (Log2 < 3) {
1110 auto VLENB = MIB.buildInstr(RISCV::G_READ_VLENB, {sXLen}, {});
1111 MIB.buildLShr(Dst, VLENB, MIB.buildConstant(sXLen, 3 - Log2),
1113 } else if (Log2 > 3) {
1114 auto VLENB = MIB.buildInstr(RISCV::G_READ_VLENB, {sXLen}, {});
1115 MIB.buildShl(Dst, VLENB, MIB.buildConstant(sXLen, Log2 - 3));
1116 } else {
1117 MIB.buildInstr(RISCV::G_READ_VLENB, {Dst}, {});
1118 }
1119 } else if ((Val % 8) == 0) {
1120 // If the multiplier is a multiple of 8, scale it down to avoid needing
1121 // to shift the VLENB value.
1122 auto VLENB = MIB.buildInstr(RISCV::G_READ_VLENB, {sXLen}, {});
1123 MIB.buildMul(Dst, VLENB, MIB.buildConstant(sXLen, Val / 8));
1124 } else {
1125 auto VLENB = MIB.buildInstr(RISCV::G_READ_VLENB, {sXLen}, {});
1126 auto VScale = MIB.buildLShr(sXLen, VLENB, MIB.buildConstant(sXLen, 3),
1128 MIB.buildMul(Dst, VScale, MIB.buildConstant(sXLen, Val));
1129 }
1130 MI.eraseFromParent();
1131 return true;
1132}
1133
1134// Custom-lower extensions from mask vectors by using a vselect either with 1
1135// for zero/any-extension or -1 for sign-extension:
1136// (vXiN = (s|z)ext vXi1:vmask) -> (vXiN = vselect vmask, (-1 or 1), 0)
1137// Note that any-extension is lowered identically to zero-extension.
1138bool RISCVLegalizerInfo::legalizeExt(MachineInstr &MI,
1139 MachineIRBuilder &MIB) const {
1140
1141 unsigned Opc = MI.getOpcode();
1142 assert(Opc == TargetOpcode::G_ZEXT || Opc == TargetOpcode::G_SEXT ||
1143 Opc == TargetOpcode::G_ANYEXT);
1144
1145 MachineRegisterInfo &MRI = *MIB.getMRI();
1146 Register Dst = MI.getOperand(0).getReg();
1147 Register Src = MI.getOperand(1).getReg();
1148
1149 LLT DstTy = MRI.getType(Dst);
1150 int64_t ExtTrueVal = Opc == TargetOpcode::G_SEXT ? -1 : 1;
1151 LLT DstEltTy = DstTy.getElementType();
1152 auto SplatZero = MIB.buildSplatVector(DstTy, MIB.buildConstant(DstEltTy, 0));
1153 auto SplatTrue =
1154 MIB.buildSplatVector(DstTy, MIB.buildConstant(DstEltTy, ExtTrueVal));
1155 MIB.buildSelect(Dst, Src, SplatTrue, SplatZero);
1156
1157 MI.eraseFromParent();
1158 return true;
1159}
1160
1161bool RISCVLegalizerInfo::legalizeLoadStore(MachineInstr &MI,
1162 LegalizerHelper &Helper,
1163 MachineIRBuilder &MIB) const {
1165 "Machine instructions must be Load/Store.");
1166 MachineRegisterInfo &MRI = *MIB.getMRI();
1167 MachineFunction *MF = MI.getMF();
1168 const DataLayout &DL = MIB.getDataLayout();
1169 LLVMContext &Ctx = MF->getFunction().getContext();
1170
1171 Register DstReg = MI.getOperand(0).getReg();
1172 LLT DataTy = MRI.getType(DstReg);
1173 if (!DataTy.isVector())
1174 return false;
1175
1176 if (!MI.hasOneMemOperand())
1177 return false;
1178
1179 MachineMemOperand *MMO = *MI.memoperands_begin();
1180
1181 const auto *TLI = STI.getTargetLowering();
1182 EVT VT = EVT::getEVT(getTypeForLLT(DataTy, Ctx));
1183
1184 if (TLI->allowsMemoryAccessForAlignment(Ctx, DL, VT, *MMO))
1185 return true;
1186
1187 unsigned EltSizeBits = DataTy.getScalarSizeInBits();
1188 assert((EltSizeBits == 16 || EltSizeBits == 32 || EltSizeBits == 64) &&
1189 "Unexpected unaligned RVV load type");
1190
1191 // Calculate the new vector type with i8 elements
1192 unsigned NumElements =
1193 DataTy.getElementCount().getKnownMinValue() * (EltSizeBits / 8);
1194 LLT NewDataTy = LLT::scalable_vector(NumElements, 8);
1195
1196 Helper.bitcast(MI, 0, NewDataTy);
1197
1198 return true;
1199}
1200
1201/// Return the type of the mask type suitable for masking the provided
1202/// vector type. This is simply an i1 element type vector of the same
1203/// (possibly scalable) length.
1204static LLT getMaskTypeFor(LLT VecTy) {
1205 assert(VecTy.isVector());
1206 ElementCount EC = VecTy.getElementCount();
1207 return LLT::vector(EC, LLT::scalar(1));
1208}
1209
1210/// Creates an all ones mask suitable for masking a vector of type VecTy with
1211/// vector length VL.
1213 MachineIRBuilder &MIB,
1214 MachineRegisterInfo &MRI) {
1215 LLT MaskTy = getMaskTypeFor(VecTy);
1216 return MIB.buildInstr(RISCV::G_VMSET_VL, {MaskTy}, {VL});
1217}
1218
1219/// Gets the two common "VL" operands: an all-ones mask and the vector length.
1220/// VecTy is a scalable vector type.
1221static std::pair<MachineInstrBuilder, MachineInstrBuilder>
1223 assert(VecTy.isScalableVector() && "Expecting scalable container type");
1224 const RISCVSubtarget &STI = MIB.getMF().getSubtarget<RISCVSubtarget>();
1225 LLT XLenTy(STI.getXLenVT());
1226 auto VL = MIB.buildConstant(XLenTy, -1);
1227 auto Mask = buildAllOnesMask(VecTy, VL, MIB, MRI);
1228 return {Mask, VL};
1229}
1230
1232buildSplatPartsS64WithVL(const DstOp &Dst, const SrcOp &Passthru, Register Lo,
1233 Register Hi, const SrcOp &VL, MachineIRBuilder &MIB,
1234 MachineRegisterInfo &MRI) {
1235 // TODO: If the Hi bits of the splat are undefined, then it's fine to just
1236 // splat Lo even if it might be sign extended. I don't think we have
1237 // introduced a case where we're build a s64 where the upper bits are undef
1238 // yet.
1239
1240 // Fall back to a stack store and stride x0 vector load.
1241 // TODO: need to lower G_SPLAT_VECTOR_SPLIT_I64. This is done in
1242 // preprocessDAG in SDAG.
1243 return MIB.buildInstr(RISCV::G_SPLAT_VECTOR_SPLIT_I64_VL, {Dst},
1244 {Passthru, Lo, Hi, VL});
1245}
1246
1248buildSplatSplitS64WithVL(const DstOp &Dst, const SrcOp &Passthru,
1249 const SrcOp &Scalar, const SrcOp &VL,
1251 assert(Scalar.getLLTTy(MRI) == LLT::scalar(64) && "Unexpected VecTy!");
1252 auto Unmerge = MIB.buildUnmerge(LLT::scalar(32), Scalar);
1253 return buildSplatPartsS64WithVL(Dst, Passthru, Unmerge.getReg(0),
1254 Unmerge.getReg(1), VL, MIB, MRI);
1255}
1256
1257// Lower splats of s1 types to G_ICMP. For each mask vector type, we have a
1258// legal equivalently-sized i8 type, so we can use that as a go-between.
1259// Splats of s1 types that have constant value can be legalized as VMSET_VL or
1260// VMCLR_VL.
1261bool RISCVLegalizerInfo::legalizeSplatVector(MachineInstr &MI,
1262 MachineIRBuilder &MIB) const {
1263 assert(MI.getOpcode() == TargetOpcode::G_SPLAT_VECTOR);
1264
1265 MachineRegisterInfo &MRI = *MIB.getMRI();
1266
1267 Register Dst = MI.getOperand(0).getReg();
1268 Register SplatVal = MI.getOperand(1).getReg();
1269
1270 LLT VecTy = MRI.getType(Dst);
1271 LLT XLenTy(STI.getXLenVT());
1272
1273 // Handle case of s64 element vectors on rv32
1274 if (XLenTy.getSizeInBits() == 32 &&
1275 VecTy.getElementType().getSizeInBits() == 64) {
1276 auto [_, VL] = buildDefaultVLOps(MRI.getType(Dst), MIB, MRI);
1277 buildSplatSplitS64WithVL(Dst, MIB.buildUndef(VecTy), SplatVal, VL, MIB,
1278 MRI);
1279 MI.eraseFromParent();
1280 return true;
1281 }
1282
1283 // All-zeros or all-ones splats are handled specially.
1284 MachineInstr &SplatValMI = *MRI.getVRegDef(SplatVal);
1285 if (isAllOnesOrAllOnesSplat(SplatValMI, MRI)) {
1286 auto VL = buildDefaultVLOps(VecTy, MIB, MRI).second;
1287 MIB.buildInstr(RISCV::G_VMSET_VL, {Dst}, {VL});
1288 MI.eraseFromParent();
1289 return true;
1290 }
1291 if (isNullOrNullSplat(SplatValMI, MRI)) {
1292 auto VL = buildDefaultVLOps(VecTy, MIB, MRI).second;
1293 MIB.buildInstr(RISCV::G_VMCLR_VL, {Dst}, {VL});
1294 MI.eraseFromParent();
1295 return true;
1296 }
1297
1298 // Handle non-constant mask splat (i.e. not sure if it's all zeros or all
1299 // ones) by promoting it to an s8 splat.
1300 LLT InterEltTy = LLT::scalar(8);
1301 LLT InterTy = VecTy.changeElementType(InterEltTy);
1302 auto ZExtSplatVal = MIB.buildZExt(InterEltTy, SplatVal);
1303 auto And =
1304 MIB.buildAnd(InterEltTy, ZExtSplatVal, MIB.buildConstant(InterEltTy, 1));
1305 auto LHS = MIB.buildSplatVector(InterTy, And);
1306 auto ZeroSplat =
1307 MIB.buildSplatVector(InterTy, MIB.buildConstant(InterEltTy, 0));
1308 MIB.buildICmp(CmpInst::Predicate::ICMP_NE, Dst, LHS, ZeroSplat);
1309 MI.eraseFromParent();
1310 return true;
1311}
1312
1313static LLT getLMUL1Ty(LLT VecTy) {
1314 assert(VecTy.getElementType().getSizeInBits() <= 64 &&
1315 "Unexpected vector LLT");
1317 VecTy.getElementType().getSizeInBits(),
1318 VecTy.getElementType());
1319}
1320
1321bool RISCVLegalizerInfo::legalizeExtractSubvector(MachineInstr &MI,
1322 MachineIRBuilder &MIB) const {
1323 GExtractSubvector &ES = cast<GExtractSubvector>(MI);
1324
1325 MachineRegisterInfo &MRI = *MIB.getMRI();
1326
1327 Register Dst = ES.getReg(0);
1328 Register Src = ES.getSrcVec();
1329 uint64_t Idx = ES.getIndexImm();
1330
1331 // With an index of 0 this is a cast-like subvector, which can be performed
1332 // with subregister operations.
1333 if (Idx == 0)
1334 return true;
1335
1336 LLT LitTy = MRI.getType(Dst);
1337 LLT BigTy = MRI.getType(Src);
1338
1339 if (LitTy.getElementType() == LLT::scalar(1)) {
1340 // We can't slide this mask vector up indexed by its i1 elements.
1341 // This poses a problem when we wish to insert a scalable vector which
1342 // can't be re-expressed as a larger type. Just choose the slow path and
1343 // extend to a larger type, then truncate back down.
1344 LLT ExtBigTy = BigTy.changeElementType(LLT::scalar(8));
1345 LLT ExtLitTy = LitTy.changeElementType(LLT::scalar(8));
1346 auto BigZExt = MIB.buildZExt(ExtBigTy, Src);
1347 auto ExtractZExt = MIB.buildExtractSubvector(ExtLitTy, BigZExt, Idx);
1348 auto SplatZero = MIB.buildSplatVector(
1349 ExtLitTy, MIB.buildConstant(ExtLitTy.getElementType(), 0));
1350 MIB.buildICmp(CmpInst::Predicate::ICMP_NE, Dst, ExtractZExt, SplatZero);
1351 MI.eraseFromParent();
1352 return true;
1353 }
1354
1355 // extract_subvector scales the index by vscale if the subvector is scalable,
1356 // and decomposeSubvectorInsertExtractToSubRegs takes this into account.
1357 const RISCVRegisterInfo *TRI = STI.getRegisterInfo();
1358 MVT LitTyMVT = getMVTForLLT(LitTy);
1359 auto Decompose =
1361 getMVTForLLT(BigTy), LitTyMVT, Idx, TRI);
1362 unsigned RemIdx = Decompose.second;
1363
1364 // If the Idx has been completely eliminated then this is a subvector extract
1365 // which naturally aligns to a vector register. These can easily be handled
1366 // using subregister manipulation.
1367 if (RemIdx == 0)
1368 return true;
1369
1370 // Else LitTy is M1 or smaller and may need to be slid down: if LitTy
1371 // was > M1 then the index would need to be a multiple of VLMAX, and so would
1372 // divide exactly.
1373 assert(
1376
1377 // If the vector type is an LMUL-group type, extract a subvector equal to the
1378 // nearest full vector register type.
1379 LLT InterLitTy = BigTy;
1380 Register Vec = Src;
1382 getLMUL1Ty(BigTy).getSizeInBits())) {
1383 // If BigTy has an LMUL > 1, then LitTy should have a smaller LMUL, and
1384 // we should have successfully decomposed the extract into a subregister.
1385 assert(Decompose.first != RISCV::NoSubRegister);
1386 InterLitTy = getLMUL1Ty(BigTy);
1387 // SDAG builds a TargetExtractSubreg. We cannot create a a Copy with SubReg
1388 // specified on the source Register (the equivalent) since generic virtual
1389 // register does not allow subregister index.
1390 Vec = MIB.buildExtractSubvector(InterLitTy, Src, Idx - RemIdx).getReg(0);
1391 }
1392
1393 // Slide this vector register down by the desired number of elements in order
1394 // to place the desired subvector starting at element 0.
1395 const LLT XLenTy(STI.getXLenVT());
1396 auto SlidedownAmt = MIB.buildVScale(XLenTy, RemIdx);
1397 auto [Mask, VL] = buildDefaultVLOps(InterLitTy, MIB, MRI);
1399 auto Slidedown = MIB.buildInstr(
1400 RISCV::G_VSLIDEDOWN_VL, {InterLitTy},
1401 {MIB.buildUndef(InterLitTy), Vec, SlidedownAmt, Mask, VL, Policy});
1402
1403 // Now the vector is in the right position, extract our final subvector. This
1404 // should resolve to a COPY.
1405 MIB.buildExtractSubvector(Dst, Slidedown, 0);
1406
1407 MI.eraseFromParent();
1408 return true;
1409}
1410
1411bool RISCVLegalizerInfo::legalizeInsertSubvector(MachineInstr &MI,
1412 LegalizerHelper &Helper,
1413 MachineIRBuilder &MIB) const {
1414 GInsertSubvector &IS = cast<GInsertSubvector>(MI);
1415
1416 MachineRegisterInfo &MRI = *MIB.getMRI();
1417
1418 Register Dst = IS.getReg(0);
1419 Register BigVec = IS.getBigVec();
1420 Register LitVec = IS.getSubVec();
1421 uint64_t Idx = IS.getIndexImm();
1422
1423 LLT BigTy = MRI.getType(BigVec);
1424 LLT LitTy = MRI.getType(LitVec);
1425
1426 if (Idx == 0 && mi_match(BigVec, MRI, m_GImplicitDef()))
1427 return true;
1428
1429 // We don't have the ability to slide mask vectors up indexed by their i1
1430 // elements; the smallest we can do is i8. Often we are able to bitcast to
1431 // equivalent i8 vectors. Otherwise, we can must zeroextend to equivalent i8
1432 // vectors and truncate down after the insert.
1433 if (LitTy.getElementType() == LLT::scalar(1)) {
1434 auto BigTyMinElts = BigTy.getElementCount().getKnownMinValue();
1435 auto LitTyMinElts = LitTy.getElementCount().getKnownMinValue();
1436 if (BigTyMinElts >= 8 && LitTyMinElts >= 8)
1437 return Helper.bitcast(
1438 IS, 0,
1440
1441 // We can't slide this mask vector up indexed by its i1 elements.
1442 // This poses a problem when we wish to insert a scalable vector which
1443 // can't be re-expressed as a larger type. Just choose the slow path and
1444 // extend to a larger type, then truncate back down.
1445 LLT ExtBigTy = BigTy.changeElementType(LLT::scalar(8));
1446 return Helper.widenScalar(IS, 0, ExtBigTy);
1447 }
1448
1449 const RISCVRegisterInfo *TRI = STI.getRegisterInfo();
1450 unsigned SubRegIdx, RemIdx;
1451 std::tie(SubRegIdx, RemIdx) =
1453 getMVTForLLT(BigTy), getMVTForLLT(LitTy), Idx, TRI);
1454
1455 TypeSize VecRegSize = TypeSize::getScalable(RISCV::RVVBitsPerBlock);
1457 STI.expandVScale(LitTy.getSizeInBits()).getKnownMinValue()));
1458 bool ExactlyVecRegSized =
1459 STI.expandVScale(LitTy.getSizeInBits())
1460 .isKnownMultipleOf(STI.expandVScale(VecRegSize));
1461
1462 // If the Idx has been completely eliminated and this subvector's size is a
1463 // vector register or a multiple thereof, or the surrounding elements are
1464 // undef, then this is a subvector insert which naturally aligns to a vector
1465 // register. These can easily be handled using subregister manipulation.
1466 if (RemIdx == 0 && ExactlyVecRegSized)
1467 return true;
1468
1469 // If the subvector is smaller than a vector register, then the insertion
1470 // must preserve the undisturbed elements of the register. We do this by
1471 // lowering to an EXTRACT_SUBVECTOR grabbing the nearest LMUL=1 vector type
1472 // (which resolves to a subregister copy), performing a VSLIDEUP to place the
1473 // subvector within the vector register, and an INSERT_SUBVECTOR of that
1474 // LMUL=1 type back into the larger vector (resolving to another subregister
1475 // operation). See below for how our VSLIDEUP works. We go via a LMUL=1 type
1476 // to avoid allocating a large register group to hold our subvector.
1477
1478 // VSLIDEUP works by leaving elements 0<i<OFFSET undisturbed, elements
1479 // OFFSET<=i<VL set to the "subvector" and vl<=i<VLMAX set to the tail policy
1480 // (in our case undisturbed). This means we can set up a subvector insertion
1481 // where OFFSET is the insertion offset, and the VL is the OFFSET plus the
1482 // size of the subvector.
1483 const LLT XLenTy(STI.getXLenVT());
1484 LLT InterLitTy = BigTy;
1485 Register AlignedExtract = BigVec;
1486 unsigned AlignedIdx = Idx - RemIdx;
1488 getLMUL1Ty(BigTy).getSizeInBits())) {
1489 InterLitTy = getLMUL1Ty(BigTy);
1490 // Extract a subvector equal to the nearest full vector register type. This
1491 // should resolve to a G_EXTRACT on a subreg.
1492 AlignedExtract =
1493 MIB.buildExtractSubvector(InterLitTy, BigVec, AlignedIdx).getReg(0);
1494 }
1495
1496 auto Insert = MIB.buildInsertSubvector(InterLitTy, MIB.buildUndef(InterLitTy),
1497 LitVec, 0);
1498
1499 auto [Mask, _] = buildDefaultVLOps(InterLitTy, MIB, MRI);
1500 auto VL = MIB.buildVScale(XLenTy, LitTy.getElementCount().getKnownMinValue());
1501
1502 // If we're inserting into the lowest elements, use a tail undisturbed
1503 // vmv.v.v.
1504 MachineInstrBuilder Inserted;
1505 bool NeedInsertSubvec =
1506 TypeSize::isKnownGT(BigTy.getSizeInBits(), InterLitTy.getSizeInBits());
1507 Register InsertedDst =
1508 NeedInsertSubvec ? MRI.createGenericVirtualRegister(InterLitTy) : Dst;
1509 if (RemIdx == 0) {
1510 Inserted = MIB.buildInstr(RISCV::G_VMV_V_V_VL, {InsertedDst},
1511 {AlignedExtract, Insert, VL});
1512 } else {
1513 auto SlideupAmt = MIB.buildVScale(XLenTy, RemIdx);
1514 // Construct the vector length corresponding to RemIdx + length(LitTy).
1515 VL = MIB.buildAdd(XLenTy, SlideupAmt, VL);
1516 // Use tail agnostic policy if we're inserting over InterLitTy's tail.
1517 ElementCount EndIndex =
1520 if (STI.expandVScale(EndIndex) ==
1521 STI.expandVScale(InterLitTy.getElementCount()))
1523
1524 Inserted =
1525 MIB.buildInstr(RISCV::G_VSLIDEUP_VL, {InsertedDst},
1526 {AlignedExtract, Insert, SlideupAmt, Mask, VL, Policy});
1527 }
1528
1529 // If required, insert this subvector back into the correct vector register.
1530 // This should resolve to an INSERT_SUBREG instruction.
1531 if (NeedInsertSubvec)
1532 MIB.buildInsertSubvector(Dst, BigVec, Inserted, AlignedIdx);
1533
1534 MI.eraseFromParent();
1535 return true;
1536}
1537
1538bool RISCVLegalizerInfo::legalizeBitreverse(MachineInstr &MI,
1539 MachineIRBuilder &MIB) const {
1540 assert(MI.getOpcode() == TargetOpcode::G_BITREVERSE && "Unexpected opcode");
1541
1542 if (!STI.hasStdExtZbkb())
1543 return false;
1544
1545 MachineRegisterInfo &MRI = *MIB.getMRI();
1546
1547 Register Dst = MI.getOperand(0).getReg();
1548 Register Src = MI.getOperand(1).getReg();
1549
1550 if (!MRI.getType(Dst).isScalar(8))
1551 return false;
1552
1553 auto WideSrc = MIB.buildAnyExt(sXLen, Src);
1554 auto Brev = MIB.buildInstr(RISCV::G_BREV8, {sXLen}, {WideSrc.getReg(0)});
1555 MIB.buildTrunc(Dst, Brev.getReg(0));
1556
1557 MI.eraseFromParent();
1558 return true;
1559}
1560
1561static unsigned getRISCVWOpcode(unsigned Opcode) {
1562 switch (Opcode) {
1563 default:
1564 llvm_unreachable("Unexpected opcode");
1565 case TargetOpcode::G_ASHR:
1566 return RISCV::G_SRAW;
1567 case TargetOpcode::G_LSHR:
1568 return RISCV::G_SRLW;
1569 case TargetOpcode::G_SHL:
1570 return RISCV::G_SLLW;
1571 case TargetOpcode::G_SDIV:
1572 return RISCV::G_DIVW;
1573 case TargetOpcode::G_UDIV:
1574 return RISCV::G_DIVUW;
1575 case TargetOpcode::G_UREM:
1576 return RISCV::G_REMUW;
1577 case TargetOpcode::G_ROTL:
1578 return RISCV::G_ROLW;
1579 case TargetOpcode::G_ROTR:
1580 return RISCV::G_RORW;
1581 case TargetOpcode::G_CTLZ:
1582 return RISCV::G_CLZW;
1583 case TargetOpcode::G_CTTZ:
1584 return RISCV::G_CTZW;
1585 case TargetOpcode::G_CTLS:
1586 return RISCV::G_CLSW;
1587 case TargetOpcode::G_FPTOSI:
1588 return RISCV::G_FCVT_W_RV64;
1589 case TargetOpcode::G_FPTOUI:
1590 return RISCV::G_FCVT_WU_RV64;
1591 }
1592}
1593
1596 LostDebugLocObserver &LocObserver) const {
1597 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
1598 MachineRegisterInfo &MRI = *MIRBuilder.getMRI();
1599 MachineFunction &MF = *MI.getParent()->getParent();
1600 switch (MI.getOpcode()) {
1601 default:
1602 // No idea what to do.
1603 return false;
1604 case TargetOpcode::G_ABS:
1605 return Helper.lowerAbsToMaxNeg(MI);
1606 case TargetOpcode::G_FCONSTANT: {
1607 const APFloat &FVal = MI.getOperand(1).getFPImm()->getValueAPF();
1608
1609 // Convert G_FCONSTANT to G_CONSTANT.
1610 Register DstReg = MI.getOperand(0).getReg();
1611 MIRBuilder.buildConstant(DstReg, FVal.bitcastToAPInt());
1612
1613 MI.eraseFromParent();
1614 return true;
1615 }
1616 case TargetOpcode::G_CONSTANT: {
1617 const Function &F = MF.getFunction();
1618 // TODO: if PSI and BFI are present, add " ||
1619 // llvm::shouldOptForSize(*CurMBB, PSI, BFI)".
1620 bool ShouldOptForSize = F.hasOptSize();
1621 const ConstantInt *ConstVal = MI.getOperand(1).getCImm();
1622 if (!shouldBeInConstantPool(ConstVal->getValue(), ShouldOptForSize))
1623 return true;
1624 return Helper.lowerConstant(MI);
1625 }
1626 case TargetOpcode::G_SUB:
1627 case TargetOpcode::G_ADD: {
1628 Helper.Observer.changingInstr(MI);
1629 Helper.widenScalarSrc(MI, sXLen, 1, TargetOpcode::G_ANYEXT);
1630 Helper.widenScalarSrc(MI, sXLen, 2, TargetOpcode::G_ANYEXT);
1631
1632 Register DstALU = MRI.createGenericVirtualRegister(sXLen);
1633
1634 MachineOperand &MO = MI.getOperand(0);
1635 MIRBuilder.setInsertPt(MIRBuilder.getMBB(), ++MIRBuilder.getInsertPt());
1636 auto DstSext = MIRBuilder.buildSExtInReg(sXLen, DstALU, 32);
1637
1638 MIRBuilder.buildInstr(TargetOpcode::G_TRUNC, {MO}, {DstSext});
1639 MO.setReg(DstALU);
1640
1641 Helper.Observer.changedInstr(MI);
1642 return true;
1643 }
1644 case TargetOpcode::G_ASHR:
1645 case TargetOpcode::G_LSHR:
1646 case TargetOpcode::G_SHL: {
1647 if (getIConstantVRegValWithLookThrough(MI.getOperand(2).getReg(), MRI)) {
1648 // We don't need a custom node for shift by constant. Just widen the
1649 // source and the shift amount.
1650 unsigned ExtOpc = TargetOpcode::G_ANYEXT;
1651 if (MI.getOpcode() == TargetOpcode::G_ASHR)
1652 ExtOpc = TargetOpcode::G_SEXT;
1653 else if (MI.getOpcode() == TargetOpcode::G_LSHR)
1654 ExtOpc = TargetOpcode::G_ZEXT;
1655
1656 Helper.Observer.changingInstr(MI);
1657 Helper.widenScalarSrc(MI, sXLen, 1, ExtOpc);
1658 Helper.widenScalarSrc(MI, sXLen, 2, TargetOpcode::G_ZEXT);
1659 Helper.widenScalarDst(MI, sXLen);
1660 Helper.Observer.changedInstr(MI);
1661 return true;
1662 }
1663
1664 Helper.Observer.changingInstr(MI);
1665 Helper.widenScalarSrc(MI, sXLen, 1, TargetOpcode::G_ANYEXT);
1666 Helper.widenScalarSrc(MI, sXLen, 2, TargetOpcode::G_ANYEXT);
1667 Helper.widenScalarDst(MI, sXLen);
1668 MI.setDesc(MIRBuilder.getTII().get(getRISCVWOpcode(MI.getOpcode())));
1669 Helper.Observer.changedInstr(MI);
1670 return true;
1671 }
1672 case TargetOpcode::G_SDIV:
1673 case TargetOpcode::G_UDIV:
1674 case TargetOpcode::G_UREM:
1675 case TargetOpcode::G_ROTL:
1676 case TargetOpcode::G_ROTR: {
1677 Helper.Observer.changingInstr(MI);
1678 Helper.widenScalarSrc(MI, sXLen, 1, TargetOpcode::G_ANYEXT);
1679 Helper.widenScalarSrc(MI, sXLen, 2, TargetOpcode::G_ANYEXT);
1680 Helper.widenScalarDst(MI, sXLen);
1681 MI.setDesc(MIRBuilder.getTII().get(getRISCVWOpcode(MI.getOpcode())));
1682 Helper.Observer.changedInstr(MI);
1683 return true;
1684 }
1685 case TargetOpcode::G_CTLZ:
1686 case TargetOpcode::G_CTTZ:
1687 case TargetOpcode::G_CTLS: {
1688 Helper.Observer.changingInstr(MI);
1689 Helper.widenScalarSrc(MI, sXLen, 1, TargetOpcode::G_ANYEXT);
1690 Helper.widenScalarDst(MI, sXLen);
1691 MI.setDesc(MIRBuilder.getTII().get(getRISCVWOpcode(MI.getOpcode())));
1692 Helper.Observer.changedInstr(MI);
1693 return true;
1694 }
1695 case TargetOpcode::G_FPTOSI:
1696 case TargetOpcode::G_FPTOUI: {
1697 Helper.Observer.changingInstr(MI);
1698 Helper.widenScalarDst(MI, sXLen);
1699 MI.setDesc(MIRBuilder.getTII().get(getRISCVWOpcode(MI.getOpcode())));
1701 Helper.Observer.changedInstr(MI);
1702 return true;
1703 }
1704 case TargetOpcode::G_LROUND: {
1705 // The (i32 any_lround) Pat is IsRV32-only; on RV64 lower to
1706 // riscv_fcvt_w_rv64 with FRM_RMM.
1707 Helper.Observer.changingInstr(MI);
1708 Helper.widenScalarDst(MI, sXLen);
1709 MI.setDesc(MIRBuilder.getTII().get(RISCV::G_FCVT_W_RV64));
1711 Helper.Observer.changedInstr(MI);
1712 return true;
1713 }
1714 case TargetOpcode::G_READCYCLECOUNTER:
1715 case TargetOpcode::G_READSTEADYCOUNTER:
1716 return legalizeReadCounter(MI, MIRBuilder, Helper.Observer);
1717 case TargetOpcode::G_IS_FPCLASS: {
1718 Register GISFPCLASS = MI.getOperand(0).getReg();
1719 Register Src = MI.getOperand(1).getReg();
1720 const MachineOperand &ImmOp = MI.getOperand(2);
1721 MachineIRBuilder MIB(MI);
1722
1723 // Turn LLVM IR's floating point classes to that in RISC-V,
1724 // by simply rotating the 10-bit immediate right by two bits.
1725 APInt GFpClassImm(10, static_cast<uint64_t>(ImmOp.getImm()));
1726 auto FClassMask = MIB.buildConstant(sXLen, GFpClassImm.rotr(2).zext(XLen));
1727 auto ConstZero = MIB.buildConstant(sXLen, 0);
1728
1729 auto GFClass = MIB.buildInstr(RISCV::G_FCLASS, {sXLen}, {Src});
1730 auto And = MIB.buildAnd(sXLen, GFClass, FClassMask);
1731 MIB.buildICmp(CmpInst::ICMP_NE, GISFPCLASS, And, ConstZero);
1732
1733 MI.eraseFromParent();
1734 return true;
1735 }
1736 case TargetOpcode::G_BRJT:
1737 return legalizeBRJT(MI, MIRBuilder);
1738 case TargetOpcode::G_VASTART:
1739 return legalizeVAStart(MI, MIRBuilder);
1740 case TargetOpcode::G_VSCALE:
1741 return legalizeVScale(MI, MIRBuilder);
1742 case TargetOpcode::G_ZEXT:
1743 case TargetOpcode::G_SEXT:
1744 case TargetOpcode::G_ANYEXT:
1745 return legalizeExt(MI, MIRBuilder);
1746 case TargetOpcode::G_SPLAT_VECTOR:
1747 return legalizeSplatVector(MI, MIRBuilder);
1748 case TargetOpcode::G_EXTRACT_SUBVECTOR:
1749 return legalizeExtractSubvector(MI, MIRBuilder);
1750 case TargetOpcode::G_INSERT_SUBVECTOR:
1751 return legalizeInsertSubvector(MI, Helper, MIRBuilder);
1752 case TargetOpcode::G_BITREVERSE:
1753 return legalizeBitreverse(MI, MIRBuilder);
1754 case TargetOpcode::G_LOAD:
1755 case TargetOpcode::G_STORE:
1756 return legalizeLoadStore(MI, Helper, MIRBuilder);
1757 }
1758
1759 llvm_unreachable("expected switch to return");
1760}
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:1475
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:1057
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:1199
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:308
LLVMContext & getContext() const
getContext - Return a reference to the LLVMContext associated with this function.
Definition Function.cpp:356
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:342
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.