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