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