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