LLVM 23.0.0git
X86LegalizerInfo.cpp
Go to the documentation of this file.
1//===- X86LegalizerInfo.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 X86.
10/// \todo This should be generated by TableGen.
11//===----------------------------------------------------------------------===//
12
13#include "X86LegalizerInfo.h"
14#include "X86Subtarget.h"
15#include "X86TargetMachine.h"
24#include "llvm/IR/IntrinsicsX86.h"
25#include "llvm/IR/Type.h"
26
27using namespace llvm;
28using namespace TargetOpcode;
29using namespace LegalizeActions;
30using namespace LegalityPredicates;
31
33 const X86TargetMachine &TM)
34 : Subtarget(STI) {
35
36 bool Is64Bit = Subtarget.is64Bit();
37 bool HasCMOV = Subtarget.canUseCMOV();
38 bool HasSSE1 = Subtarget.hasSSE1();
39 bool HasSSE2 = Subtarget.hasSSE2();
40 bool HasSSE41 = Subtarget.hasSSE41();
41 bool HasAVX = Subtarget.hasAVX();
42 bool HasAVX2 = Subtarget.hasAVX2();
43 bool HasAVX512 = Subtarget.hasAVX512();
44 bool HasVLX = Subtarget.hasVLX();
45 bool HasDQI = Subtarget.hasAVX512() && Subtarget.hasDQI();
46 bool HasBWI = Subtarget.hasAVX512() && Subtarget.hasBWI();
47 bool UseX87 = !Subtarget.useSoftFloat() && Subtarget.hasX87();
48 bool HasPOPCNT = Subtarget.hasPOPCNT();
49 bool HasLZCNT = Subtarget.hasLZCNT();
50 bool HasBMI = Subtarget.hasBMI();
51
52 const LLT p0 = LLT::pointer(0, TM.getPointerSizeInBits(0));
53 const LLT s1 = LLT::scalar(1);
54 const LLT s8 = LLT::scalar(8);
55 const LLT s16 = LLT::scalar(16);
56 const LLT s32 = LLT::scalar(32);
57 const LLT s64 = LLT::scalar(64);
58 const LLT s80 = LLT::scalar(80);
59 const LLT s128 = LLT::scalar(128);
60 const LLT sMaxScalar = Subtarget.is64Bit() ? s64 : s32;
61 const LLT v2s32 = LLT::fixed_vector(2, 32);
62 const LLT v4s8 = LLT::fixed_vector(4, 8);
63
64 const LLT v16s8 = LLT::fixed_vector(16, 8);
65 const LLT v8s16 = LLT::fixed_vector(8, 16);
66 const LLT v4s32 = LLT::fixed_vector(4, 32);
67 const LLT v2s64 = LLT::fixed_vector(2, 64);
68 const LLT v2p0 = LLT::fixed_vector(2, p0);
69
70 const LLT v32s8 = LLT::fixed_vector(32, 8);
71 const LLT v16s16 = LLT::fixed_vector(16, 16);
72 const LLT v8s32 = LLT::fixed_vector(8, 32);
73 const LLT v4s64 = LLT::fixed_vector(4, 64);
74 const LLT v4p0 = LLT::fixed_vector(4, p0);
75
76 const LLT v64s8 = LLT::fixed_vector(64, 8);
77 const LLT v32s16 = LLT::fixed_vector(32, 16);
78 const LLT v16s32 = LLT::fixed_vector(16, 32);
79 const LLT v8s64 = LLT::fixed_vector(8, 64);
80
81 const LLT s8MaxVector = HasAVX512 ? v64s8 : HasAVX ? v32s8 : v16s8;
82 const LLT s16MaxVector = HasAVX512 ? v32s16 : HasAVX ? v16s16 : v8s16;
83 const LLT s32MaxVector = HasAVX512 ? v16s32 : HasAVX ? v8s32 : v4s32;
84 const LLT s64MaxVector = HasAVX512 ? v8s64 : HasAVX ? v4s64 : v2s64;
85
86 // todo: AVX512 bool vector predicate types
87
88 // implicit/constants
89 // 32/64-bits needs support for s64/s128 to handle cases:
90 // s64 = EXTEND (G_IMPLICIT_DEF s32) -> s64 = G_IMPLICIT_DEF
91 // s128 = EXTEND (G_IMPLICIT_DEF s32/s64) -> s128 = G_IMPLICIT_DEF
93 {G_IMPLICIT_DEF, G_PHI, G_FREEZE, G_CONSTANT_FOLD_BARRIER})
94 .legalFor({p0, s1, s8, s16, s32, s64})
95 .legalFor(UseX87, {s80})
96 .legalFor(Is64Bit, {s128})
97 .legalFor(HasSSE2, {v16s8, v8s16, v4s32, v2s64})
98 .legalFor(HasAVX, {v32s8, v16s16, v8s32, v4s64})
99 .legalFor(HasAVX512, {v64s8, v32s16, v16s32, v8s64})
100 .widenScalarOrEltToNextPow2(0, /*Min=*/8)
101 .clampScalarOrElt(0, s8, sMaxScalar)
102 .moreElementsToNextPow2(0)
103 .clampNumElements(0, v16s8, s8MaxVector)
104 .clampNumElements(0, v8s16, s16MaxVector)
105 .clampNumElements(0, v4s32, s32MaxVector)
106 .clampNumElements(0, v2s64, s64MaxVector)
107 .clampMaxNumElements(0, p0,
108 Is64Bit ? s64MaxVector.getNumElements()
109 : s32MaxVector.getNumElements())
110 .scalarizeIf(scalarOrEltWiderThan(0, 64), 0);
111
113 .legalFor({p0, s8, s16, s32})
114 .legalFor(Is64Bit, {s64})
115 .widenScalarToNextPow2(0, /*Min=*/8)
116 .clampScalar(0, s8, sMaxScalar);
117
118 getActionDefinitionsBuilder({G_LROUND, G_LLROUND})
119 .widenScalarIf(typeIs(1, s16),
120 [=](const LegalityQuery &) {
121 return std::pair<unsigned, LLT>(1, s32);
122 })
123 .libcall();
124
126 {G_FCOS, G_FCOSH, G_FACOS, G_FSIN, G_FSINH, G_FASIN, G_FTAN,
127 G_FTANH, G_FATAN, G_FATAN2, G_FPOW, G_FEXP, G_FEXP2, G_FEXP10,
128 G_FLOG, G_FLOG2, G_FLOG10, G_FPOWI, G_FSINCOS, G_FCEIL, G_FFLOOR})
129 .libcall();
130
132 .legalFor(HasSSE1 || UseX87, {s32})
133 .legalFor(HasSSE2 || UseX87, {s64})
134 .legalFor(UseX87, {s80});
135
136 getActionDefinitionsBuilder({G_GET_ROUNDING, G_SET_ROUNDING})
137 .customFor({s32});
138
139 // merge/unmerge
140 for (unsigned Op : {G_MERGE_VALUES, G_UNMERGE_VALUES}) {
141 unsigned BigTyIdx = Op == G_MERGE_VALUES ? 0 : 1;
142 unsigned LitTyIdx = Op == G_MERGE_VALUES ? 1 : 0;
144 .widenScalarToNextPow2(LitTyIdx, /*Min=*/8)
145 .widenScalarToNextPow2(BigTyIdx, /*Min=*/16)
146 .minScalar(LitTyIdx, s8)
147 .minScalar(BigTyIdx, s32)
148 .legalIf([=](const LegalityQuery &Q) {
149 switch (Q.Types[BigTyIdx].getSizeInBits()) {
150 case 16:
151 case 32:
152 case 64:
153 case 128:
154 case 256:
155 case 512:
156 break;
157 default:
158 return false;
159 }
160 switch (Q.Types[LitTyIdx].getSizeInBits()) {
161 case 8:
162 case 16:
163 case 32:
164 case 64:
165 case 128:
166 case 256:
167 return true;
168 default:
169 return false;
170 }
171 });
172 }
173
174 getActionDefinitionsBuilder({G_UMIN, G_UMAX, G_SMIN, G_SMAX})
175 .widenScalarToNextPow2(0, /*Min=*/32)
176 .lower();
177
178 // integer addition/subtraction
179 getActionDefinitionsBuilder({G_ADD, G_SUB})
180 .legalFor({s8, s16, s32})
181 .legalFor(Is64Bit, {s64})
182 .legalFor(HasSSE2, {v16s8, v8s16, v4s32, v2s64})
183 .legalFor(HasAVX2, {v32s8, v16s16, v8s32, v4s64})
184 .legalFor(HasAVX512, {v16s32, v8s64})
185 .legalFor(HasBWI, {v64s8, v32s16})
186 .clampMinNumElements(0, s8, 16)
187 .clampMinNumElements(0, s16, 8)
188 .clampMinNumElements(0, s32, 4)
189 .clampMinNumElements(0, s64, 2)
190 .clampMaxNumElements(0, s8, HasBWI ? 64 : (HasAVX2 ? 32 : 16))
191 .clampMaxNumElements(0, s16, HasBWI ? 32 : (HasAVX2 ? 16 : 8))
192 .clampMaxNumElements(0, s32, HasAVX512 ? 16 : (HasAVX2 ? 8 : 4))
193 .clampMaxNumElements(0, s64, HasAVX512 ? 8 : (HasAVX2 ? 4 : 2))
194 .widenScalarToNextPow2(0, /*Min=*/32)
195 .clampScalar(0, s8, sMaxScalar)
196 .scalarize(0);
197
198 getActionDefinitionsBuilder({G_UADDE, G_UADDO, G_USUBE, G_USUBO})
199 .legalFor({{s8, s8}, {s16, s8}, {s32, s8}})
200 .legalFor(Is64Bit, {{s64, s8}})
201 .widenScalarToNextPow2(0, /*Min=*/32)
202 .clampScalar(0, s8, sMaxScalar)
203 .clampScalar(1, s8, s8)
204 .scalarize(0);
205
206 // integer multiply
208 .legalFor({s8, s16, s32})
209 .legalFor(Is64Bit, {s64})
210 .legalFor(HasSSE2, {v8s16})
211 .legalFor(HasSSE41, {v4s32})
212 .legalFor(HasAVX2, {v16s16, v8s32})
213 .legalFor(HasAVX512, {v16s32})
214 .legalFor(HasDQI, {v8s64})
215 .legalFor(HasDQI && HasVLX, {v2s64, v4s64})
216 .legalFor(HasBWI, {v32s16})
217 .clampMinNumElements(0, s16, 8)
218 .clampMinNumElements(0, s32, 4)
219 .clampMinNumElements(0, s64, HasVLX ? 2 : 8)
220 .clampMaxNumElements(0, s16, HasBWI ? 32 : (HasAVX2 ? 16 : 8))
221 .clampMaxNumElements(0, s32, HasAVX512 ? 16 : (HasAVX2 ? 8 : 4))
222 .clampMaxNumElements(0, s64, 8)
223 .widenScalarToNextPow2(0, /*Min=*/32)
224 .clampScalar(0, s8, sMaxScalar)
225 .scalarize(0);
226
227 getActionDefinitionsBuilder({G_SMULH, G_UMULH})
228 .legalFor({s8, s16, s32})
229 .legalFor(Is64Bit, {s64})
230 .widenScalarToNextPow2(0, /*Min=*/32)
231 .clampScalar(0, s8, sMaxScalar)
232 .scalarize(0);
233
234 // integer divisions
235 getActionDefinitionsBuilder({G_SDIV, G_SREM, G_UDIV, G_UREM})
236 .legalFor({s8, s16, s32})
237 .legalFor(Is64Bit, {s64})
238 .libcallFor({s64})
239 .clampScalar(0, s8, sMaxScalar);
240
241 // integer shifts
242 getActionDefinitionsBuilder({G_SHL, G_LSHR, G_ASHR})
243 .legalFor({{s8, s8}, {s16, s8}, {s32, s8}})
244 .legalFor(Is64Bit, {{s64, s8}})
245 .clampScalar(0, s8, sMaxScalar)
246 .clampScalar(1, s8, s8);
247
248 // integer logic
249 getActionDefinitionsBuilder({G_AND, G_OR, G_XOR})
250 .legalFor({s8, s16, s32})
251 .legalFor(Is64Bit, {s64})
252 .legalFor(HasSSE2, {v16s8, v8s16, v4s32, v2s64})
253 .legalFor(HasAVX, {v32s8, v16s16, v8s32, v4s64})
254 .legalFor(HasAVX512, {v64s8, v32s16, v16s32, v8s64})
255 .clampNumElements(0, v16s8, s8MaxVector)
256 .clampNumElements(0, v8s16, s16MaxVector)
257 .clampNumElements(0, v4s32, s32MaxVector)
258 .clampNumElements(0, v2s64, s64MaxVector)
259 .widenScalarToNextPow2(0, /*Min=*/32)
260 .clampScalar(0, s8, sMaxScalar)
261 .scalarize(0);
262
263 // integer comparison
264 const std::initializer_list<LLT> IntTypes32 = {s8, s16, s32, p0};
265 const std::initializer_list<LLT> IntTypes64 = {s8, s16, s32, s64, p0};
266
268 .legalForCartesianProduct({s8}, Is64Bit ? IntTypes64 : IntTypes32)
269 .clampScalar(0, s8, s8)
270 .widenScalarToNextPow2(1, /*Min=*/8)
271 .clampScalar(1, s8, sMaxScalar);
272
273 // bswap
275 .legalFor({s32})
276 .legalFor(Is64Bit, {s64})
277 .widenScalarToNextPow2(0, /*Min=*/32)
278 .clampScalar(0, s32, sMaxScalar);
279
280 // popcount
282 .legalFor(HasPOPCNT, {{s16, s16}, {s32, s32}})
283 .legalFor(HasPOPCNT && Is64Bit, {{s64, s64}})
284 .widenScalarToNextPow2(1, /*Min=*/16)
285 .clampScalar(1, s16, sMaxScalar)
286 .scalarSameSizeAs(0, 1);
287
288 // count leading zeros (LZCNT)
290 .legalFor(HasLZCNT, {{s16, s16}, {s32, s32}})
291 .legalFor(HasLZCNT && Is64Bit, {{s64, s64}})
292 .widenScalarToNextPow2(1, /*Min=*/16)
293 .clampScalar(1, s16, sMaxScalar)
294 .scalarSameSizeAs(0, 1);
295
296 // count trailing zeros
297 getActionDefinitionsBuilder(G_CTTZ_ZERO_UNDEF)
298 .legalFor({{s16, s16}, {s32, s32}})
299 .legalFor(Is64Bit, {{s64, s64}})
300 .widenScalarToNextPow2(1, /*Min=*/16)
301 .clampScalar(1, s16, sMaxScalar)
302 .scalarSameSizeAs(0, 1);
303
305 .legalFor(HasBMI, {{s16, s16}, {s32, s32}})
306 .legalFor(HasBMI && Is64Bit, {{s64, s64}})
307 .widenScalarToNextPow2(1, /*Min=*/16)
308 .clampScalar(1, s16, sMaxScalar)
309 .scalarSameSizeAs(0, 1);
310
312
313 // pointer handling
314 const std::initializer_list<LLT> PtrTypes32 = {s1, s8, s16, s32};
315 const std::initializer_list<LLT> PtrTypes64 = {s1, s8, s16, s32, s64};
316
318 .legalForCartesianProduct(Is64Bit ? PtrTypes64 : PtrTypes32, {p0})
319 .maxScalar(0, sMaxScalar)
320 .widenScalarToNextPow2(0, /*Min*/ 8);
321
322 getActionDefinitionsBuilder(G_INTTOPTR).legalFor({{p0, sMaxScalar}});
323
324 getActionDefinitionsBuilder(G_CONSTANT_POOL).legalFor({p0});
325
327 .legalFor({{p0, s32}})
328 .legalFor(Is64Bit, {{p0, s64}})
329 .widenScalarToNextPow2(1, /*Min*/ 32)
330 .clampScalar(1, s32, sMaxScalar);
331
332 getActionDefinitionsBuilder({G_FRAME_INDEX, G_GLOBAL_VALUE}).legalFor({p0});
333
334 // load/store: add more corner cases
335 for (unsigned Op : {G_LOAD, G_STORE}) {
336 auto &Action = getActionDefinitionsBuilder(Op);
337 Action.legalForTypesWithMemDesc({{s8, p0, s8, 1},
338 {s16, p0, s16, 1},
339 {s32, p0, s32, 1},
340 {s80, p0, s80, 1},
341 {p0, p0, p0, 1},
342 {v4s8, p0, v4s8, 1}});
343 if (Is64Bit)
344 Action.legalForTypesWithMemDesc(
345 {{s64, p0, s64, 1}, {v2s32, p0, v2s32, 1}});
346
347 if (HasSSE1)
348 Action.legalForTypesWithMemDesc({{v4s32, p0, v4s32, 1}});
349 if (HasSSE2)
350 Action.legalForTypesWithMemDesc({{v16s8, p0, v16s8, 1},
351 {v8s16, p0, v8s16, 1},
352 {v2s64, p0, v2s64, 1},
353 {v2p0, p0, v2p0, 1}});
354 if (HasAVX)
355 Action.legalForTypesWithMemDesc({{v32s8, p0, v32s8, 1},
356 {v16s16, p0, v16s16, 1},
357 {v8s32, p0, v8s32, 1},
358 {v4s64, p0, v4s64, 1},
359 {v4p0, p0, v4p0, 1}});
360 if (HasAVX512)
361 Action.legalForTypesWithMemDesc({{v64s8, p0, v64s8, 1},
362 {v32s16, p0, v32s16, 1},
363 {v16s32, p0, v16s32, 1},
364 {v8s64, p0, v8s64, 1}});
365
366 // X86 supports extending loads but not stores for GPRs
367 if (Op == G_LOAD) {
368 Action.legalForTypesWithMemDesc({{s8, p0, s1, 1},
369 {s16, p0, s8, 1},
370 {s32, p0, s8, 1},
371 {s32, p0, s16, 1}});
372 if (Is64Bit)
373 Action.legalForTypesWithMemDesc(
374 {{s64, p0, s8, 1}, {s64, p0, s16, 1}, {s64, p0, s32, 1}});
375 } else {
376 Action.customIf([=](const LegalityQuery &Query) {
377 return Query.Types[0] != Query.MMODescrs[0].MemoryTy;
378 });
379 }
380 Action.widenScalarToNextPow2(0, /*Min=*/8)
381 .clampScalar(0, s8, sMaxScalar)
382 .scalarize(0);
383 }
384
385 for (unsigned Op : {G_SEXTLOAD, G_ZEXTLOAD}) {
386 auto &Action = getActionDefinitionsBuilder(Op);
387 Action.legalForTypesWithMemDesc(
388 {{s16, p0, s8, 1}, {s32, p0, s8, 1}, {s32, p0, s16, 1}});
389 if (Is64Bit)
390 Action.legalForTypesWithMemDesc(
391 {{s64, p0, s8, 1}, {s64, p0, s16, 1}, {s64, p0, s32, 1}});
392 // TODO - SSE41/AVX2/AVX512F/AVX512BW vector extensions
393 }
394
395 // sext, zext, and anyext
397 .legalFor({s8, s16, s32, s128})
398 .legalFor(Is64Bit, {s64})
399 .widenScalarToNextPow2(0, /*Min=*/8)
400 .clampScalar(0, s8, sMaxScalar)
401 .widenScalarToNextPow2(1, /*Min=*/8)
402 .clampScalar(1, s8, sMaxScalar)
403 .scalarize(0);
404
405 getActionDefinitionsBuilder({G_SEXT, G_ZEXT})
406 .legalFor({s8, s16, s32})
407 .legalFor(Is64Bit, {s64})
408 .widenScalarToNextPow2(0, /*Min=*/8)
409 .clampScalar(0, s8, sMaxScalar)
410 .widenScalarToNextPow2(1, /*Min=*/8)
411 .clampScalar(1, s8, sMaxScalar)
412 .scalarize(0);
413
414 getActionDefinitionsBuilder(G_SEXT_INREG).lower();
415
416 // fp constants
417 getActionDefinitionsBuilder(G_FCONSTANT)
418 .legalFor({s32, s64})
419 .legalFor(UseX87, {s80});
420
421 // fp arithmetic
422 getActionDefinitionsBuilder({G_FADD, G_FSUB, G_FMUL, G_FDIV})
423 .legalFor({s32, s64})
424 .legalFor(HasSSE1, {v4s32})
425 .legalFor(HasSSE2, {v2s64})
426 .legalFor(HasAVX, {v8s32, v4s64})
427 .legalFor(HasAVX512, {v16s32, v8s64})
428 .legalFor(UseX87, {s80});
429
431 .legalFor(UseX87, {s80})
432 .legalFor(UseX87 && !Is64Bit, {s64})
433 .lower();
434
435 // fp comparison
437 .legalFor(HasSSE1 || UseX87, {s8, s32})
438 .legalFor(HasSSE2 || UseX87, {s8, s64})
439 .legalFor(UseX87, {s8, s80})
440 .clampScalar(0, s8, s8)
441 .clampScalar(1, s32, HasSSE2 ? s64 : s32)
443
444 // fp conversions
446 .legalFor(HasSSE2, {{s64, s32}})
447 .legalFor(HasAVX, {{v4s64, v4s32}})
448 .legalFor(HasAVX512, {{v8s64, v8s32}})
449 .libcall();
450
452 .legalFor(HasSSE2, {{s32, s64}})
453 .legalFor(HasAVX, {{v4s32, v4s64}})
454 .legalFor(HasAVX512, {{v8s32, v8s64}});
455
457 .legalFor(HasSSE1, {{s32, s32}})
458 .legalFor(HasSSE1 && Is64Bit, {{s32, s64}})
459 .legalFor(HasSSE2, {{s64, s32}})
460 .legalFor(HasSSE2 && Is64Bit, {{s64, s64}})
461 .clampScalar(1, (UseX87 && !HasSSE1) ? s16 : s32, sMaxScalar)
463 .customForCartesianProduct(UseX87, {s32, s64, s80}, {s16, s32, s64})
464 .clampScalar(0, s32, HasSSE2 ? s64 : s32)
466
468 .legalFor(HasSSE1, {{s32, s32}})
469 .legalFor(HasSSE1 && Is64Bit, {{s64, s32}})
470 .legalFor(HasSSE2, {{s32, s64}})
471 .legalFor(HasSSE2 && Is64Bit, {{s64, s64}})
472 .clampScalar(0, (UseX87 && !HasSSE1) ? s16 : s32, sMaxScalar)
474 .customForCartesianProduct(UseX87, {s16, s32, s64}, {s32, s64, s80})
475 .clampScalar(1, s32, HasSSE2 ? s64 : s32)
477
478 // For G_UITOFP and G_FPTOUI without AVX512, we have to custom legalize types
479 // <= s32 manually. Otherwise, in custom handler there is no way to
480 // understand whether s32 is an original type and we need to promote it to
481 // s64 or s32 is obtained after widening and we shouldn't widen it to s64.
482 //
483 // For AVX512 we simply widen types as there is direct mapping from opcodes
484 // to asm instructions.
486 .legalFor(HasAVX512, {{s32, s32}, {s32, s64}, {s64, s32}, {s64, s64}})
487 .customIf([=](const LegalityQuery &Query) {
488 return !HasAVX512 &&
489 ((HasSSE1 && typeIs(0, s32)(Query)) ||
490 (HasSSE2 && typeIs(0, s64)(Query))) &&
491 scalarNarrowerThan(1, Is64Bit ? 64 : 32)(Query);
492 })
493 .lowerIf([=](const LegalityQuery &Query) {
494 // Lower conversions from s64
495 return !HasAVX512 &&
496 ((HasSSE1 && typeIs(0, s32)(Query)) ||
497 (HasSSE2 && typeIs(0, s64)(Query))) &&
498 (Is64Bit && typeIs(1, s64)(Query));
499 })
500 .clampScalar(0, s32, HasSSE2 ? s64 : s32)
502 .clampScalar(1, s32, sMaxScalar)
504
506 .legalFor(HasAVX512, {{s32, s32}, {s32, s64}, {s64, s32}, {s64, s64}})
507 .customIf([=](const LegalityQuery &Query) {
508 return !HasAVX512 &&
509 ((HasSSE1 && typeIs(1, s32)(Query)) ||
510 (HasSSE2 && typeIs(1, s64)(Query))) &&
511 scalarNarrowerThan(0, Is64Bit ? 64 : 32)(Query);
512 })
513 // TODO: replace with customized legalization using
514 // specifics of cvttsd2si. The selection of this node requires
515 // a vector type. Either G_SCALAR_TO_VECTOR is needed or more advanced
516 // support of G_BUILD_VECTOR/G_INSERT_VECTOR_ELT is required beforehand.
517 .lowerIf([=](const LegalityQuery &Query) {
518 return !HasAVX512 &&
519 ((HasSSE1 && typeIs(1, s32)(Query)) ||
520 (HasSSE2 && typeIs(1, s64)(Query))) &&
521 (Is64Bit && typeIs(0, s64)(Query));
522 })
523 .clampScalar(0, s32, sMaxScalar)
525 .clampScalar(1, s32, HasSSE2 ? s64 : s32)
527
528 // vector ops
529 getActionDefinitionsBuilder(G_BUILD_VECTOR)
530 .customIf([=](const LegalityQuery &Query) {
531 return (HasSSE1 && typeInSet(0, {v4s32})(Query)) ||
532 (HasSSE2 && typeInSet(0, {v2s64, v8s16, v16s8})(Query)) ||
533 (HasAVX && typeInSet(0, {v4s64, v8s32, v16s16, v32s8})(Query)) ||
534 (HasAVX512 && typeInSet(0, {v8s64, v16s32, v32s16, v64s8}));
535 })
536 .clampNumElements(0, v16s8, s8MaxVector)
537 .clampNumElements(0, v8s16, s16MaxVector)
538 .clampNumElements(0, v4s32, s32MaxVector)
539 .clampNumElements(0, v2s64, s64MaxVector)
541
542 getActionDefinitionsBuilder({G_EXTRACT, G_INSERT})
543 .legalIf([=](const LegalityQuery &Query) {
544 unsigned SubIdx = Query.Opcode == G_EXTRACT ? 0 : 1;
545 unsigned FullIdx = Query.Opcode == G_EXTRACT ? 1 : 0;
546 return (HasAVX && typePairInSet(SubIdx, FullIdx,
547 {{v16s8, v32s8},
548 {v8s16, v16s16},
549 {v4s32, v8s32},
550 {v2s64, v4s64}})(Query)) ||
551 (HasAVX512 && typePairInSet(SubIdx, FullIdx,
552 {{v16s8, v64s8},
553 {v32s8, v64s8},
554 {v8s16, v32s16},
555 {v16s16, v32s16},
556 {v4s32, v16s32},
557 {v8s32, v16s32},
558 {v2s64, v8s64},
559 {v4s64, v8s64}})(Query));
560 });
561
562 // todo: only permit dst types up to max legal vector register size?
563 getActionDefinitionsBuilder(G_CONCAT_VECTORS)
564 .legalFor(
565 HasSSE1,
566 {{v32s8, v16s8}, {v16s16, v8s16}, {v8s32, v4s32}, {v4s64, v2s64}})
567 .legalFor(HasAVX, {{v64s8, v16s8},
568 {v64s8, v32s8},
569 {v32s16, v8s16},
570 {v32s16, v16s16},
571 {v16s32, v4s32},
572 {v16s32, v8s32},
573 {v8s64, v2s64},
574 {v8s64, v4s64}});
575
576 // todo: vectors and address spaces
578 .legalFor({{s16, s32}, {s32, s32}, {p0, s32}})
579 .legalFor(!HasCMOV, {{s8, s32}})
580 .legalFor(Is64Bit, {{s64, s32}})
581 .legalFor(UseX87, {{s80, s32}})
582 .clampScalar(1, s32, s32)
583 .widenScalarToNextPow2(0, /*Min=*/8)
584 .clampScalar(0, HasCMOV ? s16 : s8, sMaxScalar);
585
586 // memory intrinsics
587 getActionDefinitionsBuilder({G_MEMCPY, G_MEMMOVE, G_MEMSET}).libcall();
588
589 getActionDefinitionsBuilder({G_DYN_STACKALLOC, G_STACKSAVE, G_STACKRESTORE})
590 .lower();
591
592 // fp intrinsics
593 // fpclass for i686 is disabled for llvm issue #171992
594 getActionDefinitionsBuilder(G_IS_FPCLASS)
595 .lowerFor(Is64Bit, {{s1, s32}, {s1, s64}, {s1, s80}});
596
597 getActionDefinitionsBuilder({G_INTRINSIC_ROUNDEVEN, G_INTRINSIC_TRUNC})
598 .scalarize(0)
599 .minScalar(0, LLT::scalar(32))
600 .libcall();
601
603 verify(*STI.getInstrInfo());
604}
605
607 LostDebugLocObserver &LocObserver) const {
608 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
609 MachineRegisterInfo &MRI = *MIRBuilder.getMRI();
610 switch (MI.getOpcode()) {
611 default:
612 // No idea what to do.
613 return false;
614 case TargetOpcode::G_BUILD_VECTOR:
615 return legalizeBuildVector(MI, MRI, Helper);
616 case TargetOpcode::G_FPTOUI:
617 return legalizeFPTOUI(MI, MRI, Helper);
618 case TargetOpcode::G_UITOFP:
619 return legalizeUITOFP(MI, MRI, Helper);
620 case TargetOpcode::G_STORE:
621 return legalizeNarrowingStore(MI, MRI, Helper);
622 case TargetOpcode::G_SITOFP:
623 return legalizeSITOFP(MI, MRI, Helper);
624 case TargetOpcode::G_FPTOSI:
625 return legalizeFPTOSI(MI, MRI, Helper);
626 case TargetOpcode::G_GET_ROUNDING:
627 return legalizeGETROUNDING(MI, MRI, Helper);
628 case TargetOpcode::G_SET_ROUNDING:
629 return legalizeSETROUNDING(MI, MRI, Helper);
630 }
631 llvm_unreachable("expected switch to return");
632}
633
634bool X86LegalizerInfo::legalizeSITOFP(MachineInstr &MI,
636 LegalizerHelper &Helper) const {
637 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
638 MachineFunction &MF = *MI.getMF();
639 auto [Dst, DstTy, Src, SrcTy] = MI.getFirst2RegLLTs();
640
641 assert((SrcTy.getSizeInBits() == 16 || SrcTy.getSizeInBits() == 32 ||
642 SrcTy.getSizeInBits() == 64) &&
643 "Unexpected source type for SITOFP in X87 mode.");
644
645 TypeSize MemSize = SrcTy.getSizeInBytes();
646 MachinePointerInfo PtrInfo;
647 Align Alignmt = Helper.getStackTemporaryAlignment(SrcTy);
648 auto SlotPointer = Helper.createStackTemporary(MemSize, Alignmt, PtrInfo);
650 PtrInfo, MachineMemOperand::MOStore, MemSize, Align(MemSize));
651
652 // Store the integer value on the FPU stack.
653 MIRBuilder.buildStore(Src, SlotPointer, *StoreMMO);
654
656 PtrInfo, MachineMemOperand::MOLoad, MemSize, Align(MemSize));
657 MIRBuilder.buildInstr(X86::G_FILD)
658 .addDef(Dst)
659 .addUse(SlotPointer.getReg(0))
660 .addMemOperand(LoadMMO);
661
662 MI.eraseFromParent();
663 return true;
664}
665
666bool X86LegalizerInfo::legalizeFPTOSI(MachineInstr &MI,
668 LegalizerHelper &Helper) const {
669 MachineFunction &MF = *MI.getMF();
670 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
671 auto [Dst, DstTy, Src, SrcTy] = MI.getFirst2RegLLTs();
672
673 TypeSize MemSize = DstTy.getSizeInBytes();
674 MachinePointerInfo PtrInfo;
675 Align Alignmt = Helper.getStackTemporaryAlignment(DstTy);
676 auto SlotPointer = Helper.createStackTemporary(MemSize, Alignmt, PtrInfo);
678 PtrInfo, MachineMemOperand::MOStore, MemSize, Align(MemSize));
679
680 MIRBuilder.buildInstr(X86::G_FIST)
681 .addUse(Src)
682 .addUse(SlotPointer.getReg(0))
683 .addMemOperand(StoreMMO);
684
685 MIRBuilder.buildLoad(Dst, SlotPointer, PtrInfo, Align(MemSize));
686 MI.eraseFromParent();
687 return true;
688}
689
690bool X86LegalizerInfo::legalizeBuildVector(MachineInstr &MI,
692 LegalizerHelper &Helper) const {
693 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
694 const auto &BuildVector = cast<GBuildVector>(MI);
695 Register Dst = BuildVector.getReg(0);
696 LLT DstTy = MRI.getType(Dst);
697 MachineFunction &MF = MIRBuilder.getMF();
698 LLVMContext &Ctx = MF.getFunction().getContext();
699 uint64_t DstTySize = DstTy.getScalarSizeInBits();
700
701 SmallVector<Constant *, 4> CstIdxs;
702 for (unsigned i = 0; i < BuildVector.getNumSources(); ++i) {
703 Register Source = BuildVector.getSourceReg(i);
704
705 auto ValueAndReg = getIConstantVRegValWithLookThrough(Source, MRI);
706 if (ValueAndReg) {
707 CstIdxs.emplace_back(ConstantInt::get(Ctx, ValueAndReg->Value));
708 continue;
709 }
710
711 auto FPValueAndReg = getFConstantVRegValWithLookThrough(Source, MRI);
712 if (FPValueAndReg) {
713 CstIdxs.emplace_back(ConstantFP::get(Ctx, FPValueAndReg->Value));
714 continue;
715 }
716
717 if (getOpcodeDef<GImplicitDef>(Source, MRI)) {
718 CstIdxs.emplace_back(UndefValue::get(Type::getIntNTy(Ctx, DstTySize)));
719 continue;
720 }
721 return false;
722 }
723
724 Constant *ConstVal = ConstantVector::get(CstIdxs);
725
726 const DataLayout &DL = MIRBuilder.getDataLayout();
727 unsigned AddrSpace = DL.getDefaultGlobalsAddressSpace();
728 Align Alignment(DL.getABITypeAlign(ConstVal->getType()));
729 auto Addr = MIRBuilder.buildConstantPool(
730 LLT::pointer(AddrSpace, DL.getPointerSizeInBits(AddrSpace)),
731 MF.getConstantPool()->getConstantPoolIndex(ConstVal, Alignment));
732 MachineMemOperand *MMO =
734 MachineMemOperand::MOLoad, DstTy, Alignment);
735
736 MIRBuilder.buildLoad(Dst, Addr, *MMO);
737 MI.eraseFromParent();
738 return true;
739}
740
741bool X86LegalizerInfo::legalizeFPTOUI(MachineInstr &MI,
743 LegalizerHelper &Helper) const {
744 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
745 auto [Dst, DstTy, Src, SrcTy] = MI.getFirst2RegLLTs();
746 unsigned DstSizeInBits = DstTy.getScalarSizeInBits();
747 const LLT s32 = LLT::scalar(32);
748 const LLT s64 = LLT::scalar(64);
749
750 // Simply reuse FPTOSI when it is possible to widen the type
751 if (DstSizeInBits <= 32) {
752 auto Casted = MIRBuilder.buildFPTOSI(DstTy == s32 ? s64 : s32, Src);
753 MIRBuilder.buildTrunc(Dst, Casted);
754 MI.eraseFromParent();
755 return true;
756 }
757
758 return false;
759}
760
761bool X86LegalizerInfo::legalizeUITOFP(MachineInstr &MI,
763 LegalizerHelper &Helper) const {
764 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
765 auto [Dst, DstTy, Src, SrcTy] = MI.getFirst2RegLLTs();
766 const LLT s32 = LLT::scalar(32);
767 const LLT s64 = LLT::scalar(64);
768
769 // Simply reuse SITOFP when it is possible to widen the type
770 if (SrcTy.getSizeInBits() <= 32) {
771 auto Ext = MIRBuilder.buildZExt(SrcTy == s32 ? s64 : s32, Src);
772 MIRBuilder.buildSITOFP(Dst, Ext);
773 MI.eraseFromParent();
774 return true;
775 }
776
777 return false;
778}
779
780bool X86LegalizerInfo::legalizeNarrowingStore(MachineInstr &MI,
782 LegalizerHelper &Helper) const {
783 auto &Store = cast<GStore>(MI);
784 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
785 MachineMemOperand &MMO = **Store.memoperands_begin();
786 MachineFunction &MF = MIRBuilder.getMF();
787 LLT ValTy = MRI.getType(Store.getValueReg());
788 auto *NewMMO = MF.getMachineMemOperand(&MMO, MMO.getPointerInfo(), ValTy);
789
790 Helper.Observer.changingInstr(Store);
791 Store.setMemRefs(MF, {NewMMO});
792 Helper.Observer.changedInstr(Store);
793 return true;
794}
795
796bool X86LegalizerInfo::legalizeGETROUNDING(MachineInstr &MI,
798 LegalizerHelper &Helper) const {
799 /*
800 The rounding mode is in bits 11:10 of FPSR, and has the following
801 settings:
802 00 Round to nearest
803 01 Round to -inf
804 10 Round to +inf
805 11 Round to 0
806
807 GET_ROUNDING, on the other hand, expects the following:
808 -1 Undefined
809 0 Round to 0
810 1 Round to nearest
811 2 Round to +inf
812 3 Round to -inf
813
814 To perform the conversion, we use a packed lookup table of the four 2-bit
815 values that we can index by FPSP[11:10]
816 0x2d --> (0b00,10,11,01) --> (0,2,3,1) >> FPSR[11:10]
817
818 (0x2d >> ((FPSR >> 9) & 6)) & 3
819 */
820
821 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
822 MachineFunction &MF = MIRBuilder.getMF();
823 Register Dst = MI.getOperand(0).getReg();
824 LLT DstTy = MRI.getType(Dst);
825 const LLT s8 = LLT::scalar(8);
826 const LLT s16 = LLT::scalar(16);
827 const LLT s32 = LLT::scalar(32);
828
829 // Save FP Control Word to stack slot
830 int MemSize = 2;
831 Align Alignment = Align(2);
832 MachinePointerInfo PtrInfo;
833 auto StackTemp = Helper.createStackTemporary(TypeSize::getFixed(MemSize),
834 Alignment, PtrInfo);
835 Register StackPtr = StackTemp.getReg(0);
836
837 auto StoreMMO = MF.getMachineMemOperand(PtrInfo, MachineMemOperand::MOStore,
838 MemSize, Alignment);
839
840 // Store FP Control Word to stack slot using G_FNSTCW16
841 MIRBuilder.buildInstr(X86::G_FNSTCW16)
842 .addUse(StackPtr)
843 .addMemOperand(StoreMMO);
844
845 // Load FP Control Word from stack slot
846 auto LoadMMO = MF.getMachineMemOperand(PtrInfo, MachineMemOperand::MOLoad,
847 MemSize, Alignment);
848
849 auto CWD32 =
850 MIRBuilder.buildZExt(s32, MIRBuilder.buildLoad(s16, StackPtr, *LoadMMO));
851 auto Shifted8 = MIRBuilder.buildTrunc(
852 s8, MIRBuilder.buildLShr(s32, CWD32, MIRBuilder.buildConstant(s8, 9)));
853 auto Masked32 = MIRBuilder.buildZExt(
854 s32, MIRBuilder.buildAnd(s8, Shifted8, MIRBuilder.buildConstant(s8, 6)));
855
856 // LUT is a packed lookup table (0x2d) used to map the 2-bit x87 FPU rounding
857 // mode (from bits 11:10 of the control word) to the values expected by
858 // GET_ROUNDING. The mapping is performed by shifting LUT right by the
859 // extracted rounding mode and masking the result with 3 to obtain the final
860 auto LUT = MIRBuilder.buildConstant(s32, 0x2d);
861 auto LUTShifted = MIRBuilder.buildLShr(s32, LUT, Masked32);
862 auto RetVal =
863 MIRBuilder.buildAnd(s32, LUTShifted, MIRBuilder.buildConstant(s32, 3));
864 auto RetValTrunc = MIRBuilder.buildZExtOrTrunc(DstTy, RetVal);
865
866 MIRBuilder.buildCopy(Dst, RetValTrunc);
867
868 MI.eraseFromParent();
869 return true;
870}
871
872bool X86LegalizerInfo::legalizeSETROUNDING(MachineInstr &MI,
874 LegalizerHelper &Helper) const {
875 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
876 MachineFunction &MF = MIRBuilder.getMF();
877 Register Src = MI.getOperand(0).getReg();
878 const LLT s8 = LLT::scalar(8);
879 const LLT s16 = LLT::scalar(16);
880 const LLT s32 = LLT::scalar(32);
881
882 // Allocate stack slot for control word and MXCSR (4 bytes).
883 int MemSize = 4;
884 Align Alignment = Align(4);
885 MachinePointerInfo PtrInfo;
886 auto StackTemp = Helper.createStackTemporary(TypeSize::getFixed(MemSize),
887 Alignment, PtrInfo);
888 Register StackPtr = StackTemp.getReg(0);
889
890 auto StoreMMO =
892 MIRBuilder.buildInstr(X86::G_FNSTCW16)
893 .addUse(StackPtr)
894 .addMemOperand(StoreMMO);
895
896 auto LoadMMO =
898 auto CWD16 = MIRBuilder.buildLoad(s16, StackPtr, *LoadMMO);
899
900 // Clear RM field (bits 11:10)
901 auto ClearedCWD =
902 MIRBuilder.buildAnd(s16, CWD16, MIRBuilder.buildConstant(s16, 0xf3ff));
903
904 // Check if Src is a constant
905 auto *SrcDef = MRI.getVRegDef(Src);
906 Register RMBits;
907 Register MXCSRRMBits;
908
909 if (SrcDef && SrcDef->getOpcode() == TargetOpcode::G_CONSTANT) {
910 uint64_t RM = getIConstantFromReg(Src, MRI).getZExtValue();
911 int FieldVal = X86::getRoundingModeX86(RM);
912
913 if (FieldVal == X86::rmInvalid) {
914 FieldVal = X86::rmToNearest;
915 LLVMContext &C = MF.getFunction().getContext();
916 C.diagnose(DiagnosticInfoUnsupported(
917 MF.getFunction(), "rounding mode is not supported by X86 hardware",
918 DiagnosticLocation(MI.getDebugLoc()), DS_Error));
919 return false;
920 }
921
922 FieldVal = FieldVal << 3;
923 RMBits = MIRBuilder.buildConstant(s16, FieldVal).getReg(0);
924 MXCSRRMBits = MIRBuilder.buildConstant(s32, FieldVal).getReg(0);
925 } else {
926 // Convert Src (rounding mode) to bits for control word
927 // (0xc9 << (2 * Src + 4)) & 0xc00
928 auto Src32 = MIRBuilder.buildZExtOrTrunc(s32, Src);
929 auto ShiftAmt = MIRBuilder.buildAdd(
930 s32, MIRBuilder.buildShl(s32, Src32, MIRBuilder.buildConstant(s32, 1)),
931 MIRBuilder.buildConstant(s32, 4));
932 auto ShiftAmt8 = MIRBuilder.buildTrunc(s8, ShiftAmt);
933 auto Shifted = MIRBuilder.buildShl(s16, MIRBuilder.buildConstant(s16, 0xc9),
934 ShiftAmt8);
935 RMBits =
936 MIRBuilder.buildAnd(s16, Shifted, MIRBuilder.buildConstant(s16, 0xc00))
937 .getReg(0);
938
939 // For non-constant case, we still need to compute MXCSR bits dynamically
940 auto RMBits32 = MIRBuilder.buildZExt(s32, RMBits);
941 MXCSRRMBits =
942 MIRBuilder.buildShl(s32, RMBits32, MIRBuilder.buildConstant(s32, 3))
943 .getReg(0);
944 }
945 // Update rounding mode bits
946 auto NewCWD =
947 MIRBuilder.buildOr(s16, ClearedCWD, RMBits, MachineInstr::Disjoint);
948
949 // Store new FP Control Word to stack
950 auto StoreNewMMO =
952 MIRBuilder.buildStore(NewCWD, StackPtr, *StoreNewMMO);
953
954 // Load FP control word from the slot using G_FLDCW16
955 auto LoadNewMMO =
957 MIRBuilder.buildInstr(X86::G_FLDCW16)
958 .addUse(StackPtr)
959 .addMemOperand(LoadNewMMO);
960
961 if (Subtarget.hasSSE1()) {
962 // Store MXCSR to stack (use STMXCSR)
963 auto StoreMXCSRMMO = MF.getMachineMemOperand(
964 PtrInfo, MachineMemOperand::MOStore, 4, Align(4));
965 MIRBuilder.buildInstr(TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS)
966 .addIntrinsicID(Intrinsic::x86_sse_stmxcsr)
967 .addUse(StackPtr)
968 .addMemOperand(StoreMXCSRMMO);
969
970 // Load MXCSR from stack
971 auto LoadMXCSRMMO = MF.getMachineMemOperand(
972 PtrInfo, MachineMemOperand::MOLoad, 4, Align(4));
973 auto MXCSR = MIRBuilder.buildLoad(s32, StackPtr, *LoadMXCSRMMO);
974
975 // Clear RM field (bits 14:13)
976 auto ClearedMXCSR = MIRBuilder.buildAnd(
977 s32, MXCSR, MIRBuilder.buildConstant(s32, 0xffff9fff));
978
979 // Update rounding mode bits
980 auto NewMXCSR = MIRBuilder.buildOr(s32, ClearedMXCSR, MXCSRRMBits);
981
982 // Store new MXCSR to stack
983 auto StoreNewMXCSRMMO = MF.getMachineMemOperand(
984 PtrInfo, MachineMemOperand::MOStore, 4, Align(4));
985 MIRBuilder.buildStore(NewMXCSR, StackPtr, *StoreNewMXCSRMMO);
986
987 // Load MXCSR from stack (use LDMXCSR)
988 auto LoadNewMXCSRMMO = MF.getMachineMemOperand(
989 PtrInfo, MachineMemOperand::MOLoad, 4, Align(4));
990 MIRBuilder.buildInstr(TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS)
991 .addIntrinsicID(Intrinsic::x86_sse_ldmxcsr)
992 .addUse(StackPtr)
993 .addMemOperand(LoadNewMXCSRMMO);
994 }
995
996 MI.eraseFromParent();
997 return true;
998}
999
1001 MachineInstr &MI) const {
1002 return true;
1003}
unsigned const MachineRegisterInfo * MRI
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
static void scalarize(Instruction *I, SmallVectorImpl< Instruction * > &Worklist)
Declares convenience wrapper classes for interpreting MachineInstr instances as specific generic oper...
IRTranslator LLVM IR MI
This file declares the MachineConstantPool class which is an abstract constant pool to keep track of ...
This file declares the MachineIRBuilder class.
Promote Memory to Register
Definition Mem2Reg.cpp:110
ppc ctr loops verify
static const char LUT[]
This file declares the targeting of the Machinelegalizer class for X86.
uint64_t getZExtValue() const
Get zero extended value.
Definition APInt.h:1555
static LLVM_ABI Constant * get(ArrayRef< Constant * > V)
LLVMContext & getContext() const
getContext - Return a reference to the LLVMContext associated with this function.
Definition Function.cpp:358
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.
constexpr unsigned getScalarSizeInBits() const
static constexpr LLT scalar(unsigned SizeInBits)
Get a low-level scalar or aggregate "bag of bits".
static constexpr LLT pointer(unsigned AddressSpace, unsigned SizeInBits)
Get a low-level pointer in the given address space.
static constexpr LLT fixed_vector(unsigned NumElements, unsigned ScalarSizeInBits)
Get a low-level fixed-width vector of some number of elements and element width.
LLVM_ABI void diagnose(const DiagnosticInfo &DI)
Report a message to the currently installed diagnostic handler.
LLVM_ABI void computeTables()
Compute any ancillary tables needed to quickly decide how an operation should be handled.
LegalizeRuleSet & minScalar(unsigned TypeIdx, const LLT Ty)
Ensure the scalar is at least as wide as Ty.
LegalizeRuleSet & legalFor(std::initializer_list< LLT > Types)
The instruction is legal when type index 0 is any type in the given list.
LegalizeRuleSet & scalarSameSizeAs(unsigned TypeIdx, unsigned SameSizeIdx)
Change the type TypeIdx to have the same scalar size as type SameSizeIdx.
LegalizeRuleSet & libcall()
The instruction is emitted as a library call.
LegalizeRuleSet & clampMaxNumElements(unsigned TypeIdx, const LLT EltTy, unsigned MaxElements)
Limit the number of elements in EltTy vectors to at most MaxElements.
LegalizeRuleSet & clampMinNumElements(unsigned TypeIdx, const LLT EltTy, unsigned MinElements)
Limit the number of elements in EltTy vectors to at least MinElements.
LegalizeRuleSet & customForCartesianProduct(std::initializer_list< LLT > Types)
LegalizeRuleSet & moreElementsToNextPow2(unsigned TypeIdx)
Add more elements to the vector to reach the next power of two.
LegalizeRuleSet & lower()
The instruction is lowered.
LegalizeRuleSet & lowerFor(std::initializer_list< LLT > Types)
The instruction is lowered when type index 0 is any type in the given list.
LegalizeRuleSet & clampScalar(unsigned TypeIdx, const LLT MinTy, const LLT MaxTy)
Limit the range of scalar sizes to MinTy and MaxTy.
LegalizeRuleSet & clampNumElements(unsigned TypeIdx, const LLT MinTy, const LLT MaxTy)
Limit the number of elements for the given vectors to at least MinTy's number of elements and at most...
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 & scalarize(unsigned TypeIdx)
LegalizeRuleSet & legalForCartesianProduct(std::initializer_list< LLT > Types)
The instruction is legal when type indexes 0 and 1 are both in the given list.
LegalizeRuleSet & legalIf(LegalityPredicate Predicate)
The instruction is legal if predicate is true.
LLVM_ABI MachineInstrBuilder createStackTemporary(TypeSize Bytes, Align Alignment, MachinePointerInfo &PtrInfo)
Create a stack temporary based on the size in bytes and the alignment.
GISelChangeObserver & Observer
To keep track of changes made by the LegalizerHelper.
MachineIRBuilder & MIRBuilder
Expose MIRBuilder so clients can set their own RecordInsertInstruction functions.
LLVM_ABI Align getStackTemporaryAlignment(LLT Type, Align MinAlign=Align()) const
Return the alignment to use for a stack temporary object with the given type.
LegalizeRuleSet & getActionDefinitionsBuilder(unsigned Opcode)
Get the action definition builder for the given opcode.
const LegacyLegalizerInfo & getLegacyLegalizerInfo() const
unsigned getConstantPoolIndex(const Constant *C, Align Alignment)
getConstantPoolIndex - Create a new entry in the constant pool or return an existing one.
MachineMemOperand * getMachineMemOperand(MachinePointerInfo PtrInfo, MachineMemOperand::Flags f, LLT MemTy, Align base_alignment, const AAMDNodes &AAInfo=AAMDNodes(), const MDNode *Ranges=nullptr, SyncScope::ID SSID=SyncScope::System, AtomicOrdering Ordering=AtomicOrdering::NotAtomic, AtomicOrdering FailureOrdering=AtomicOrdering::NotAtomic)
getMachineMemOperand - Allocate a new MachineMemOperand.
Function & getFunction()
Return the LLVM function that this machine code represents.
MachineConstantPool * getConstantPool()
getConstantPool - Return the constant pool object for the current function.
Helper class to build MachineInstr.
MachineInstrBuilder buildFPTOSI(const DstOp &Dst, const SrcOp &Src0)
Build and insert Res = G_FPTOSI Src0.
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 buildConstantPool(const DstOp &Res, unsigned Idx)
Build and insert Res = G_CONSTANT_POOL Idx.
MachineInstrBuilder buildAnd(const DstOp &Dst, const SrcOp &Src0, const SrcOp &Src1)
Build and insert Res = G_AND Op0, Op1.
MachineInstrBuilder buildLShr(const DstOp &Dst, const SrcOp &Src0, const SrcOp &Src1, std::optional< unsigned > Flags=std::nullopt)
MachineInstrBuilder buildZExt(const DstOp &Res, const SrcOp &Op, std::optional< unsigned > Flags=std::nullopt)
Build and insert Res = G_ZEXT Op.
MachineInstrBuilder buildLoad(const DstOp &Res, const SrcOp &Addr, MachineMemOperand &MMO)
Build and insert Res = G_LOAD Addr, MMO.
MachineInstrBuilder buildZExtOrTrunc(const DstOp &Res, const SrcOp &Op)
Build and insert Res = G_ZEXT Op, Res = G_TRUNC Op, or Res = COPY Op depending on the differing sizes...
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 buildSITOFP(const DstOp &Dst, const SrcOp &Src0)
Build and insert Res = G_SITOFP Src0.
MachineFunction & getMF()
Getter for the function we currently build.
MachineInstrBuilder buildTrunc(const DstOp &Res, const SrcOp &Op, std::optional< unsigned > Flags=std::nullopt)
Build and insert Res = G_TRUNC Op.
MachineRegisterInfo * getMRI()
Getter for MRI.
MachineInstrBuilder buildOr(const DstOp &Dst, const SrcOp &Src0, const SrcOp &Src1, std::optional< unsigned > Flags=std::nullopt)
Build and insert Res = G_OR Op0, Op1.
MachineInstrBuilder buildCopy(const DstOp &Res, const SrcOp &Op)
Build and insert Res = COPY Op.
const DataLayout & getDataLayout() const
virtual MachineInstrBuilder buildConstant(const DstOp &Res, const ConstantInt &Val)
Build and insert Res = G_CONSTANT Val.
Register getReg(unsigned Idx) const
Get the register for the operand index.
const MachineInstrBuilder & addUse(Register RegNo, RegState Flags={}, unsigned SubReg=0) const
Add a virtual register use operand.
const MachineInstrBuilder & addIntrinsicID(Intrinsic::ID ID) const
const MachineInstrBuilder & addDef(Register RegNo, RegState Flags={}, unsigned SubReg=0) const
Add a virtual register definition operand.
const MachineInstrBuilder & addMemOperand(MachineMemOperand *MMO) const
Representation of each machine instruction.
A description of a memory reference used in the backend.
@ MOLoad
The memory access reads data.
@ MOStore
The memory access writes data.
const MachinePointerInfo & getPointerInfo() const
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
reference emplace_back(ArgTypes &&... Args)
unsigned getPointerSizeInBits(unsigned AS) const
static constexpr TypeSize getFixed(ScalarTy ExactSize)
Definition TypeSize.h:343
static LLVM_ABI IntegerType * getIntNTy(LLVMContext &C, unsigned N)
Definition Type.cpp:300
static LLVM_ABI UndefValue * get(Type *T)
Static factory methods - Return an 'undef' object of the specified type.
Type * getType() const
All values are typed, get the type of this value.
Definition Value.h:256
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
X86LegalizerInfo(const X86Subtarget &STI, const X86TargetMachine &TM)
const X86InstrInfo * getInstrInfo() const override
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
constexpr char Align[]
Key for Kernel::Arg::Metadata::mAlign.
@ C
The default llvm calling convention, compatible with C.
Definition CallingConv.h:34
LLVM_ABI LegalityPredicate scalarOrEltWiderThan(unsigned TypeIdx, unsigned Size)
True iff the specified type index is a scalar or a vector with an element type that's wider than the ...
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 typePairInSet(unsigned TypeIdx0, unsigned TypeIdx1, std::initializer_list< std::pair< LLT, LLT > > TypesInit)
True iff the given types for the given pair of type indexes is one of the specified type pairs.
LLVM_ABI LegalityPredicate typeIs(unsigned TypeIdx, LLT TypesInit)
True iff the given type index is the specified type.
LLVM_ABI LegalityPredicate scalarNarrowerThan(unsigned TypeIdx, unsigned Size)
True iff the specified type index is a scalar that's narrower than the given size.
Invariant opcodes: All instruction sets have these as their low opcodes.
int getRoundingModeX86(unsigned RM)
Convert LLVM rounding mode to X86 rounding mode.
This is an optimization pass for GlobalISel generic memory operations.
Definition Types.h:26
LLVM_ABI MachineInstr * getOpcodeDef(unsigned Opcode, Register Reg, const MachineRegisterInfo &MRI)
See if Reg is defined by an single def instruction that is Opcode.
Definition Utils.cpp:653
LLVM_ABI const APInt & getIConstantFromReg(Register VReg, const MachineRegisterInfo &MRI)
VReg is defined by a G_CONSTANT, return the corresponding value.
Definition Utils.cpp:305
DWARFExpression::Operation Op
LLVM_ABI std::optional< FPValueAndVReg > getFConstantVRegValWithLookThrough(Register VReg, const MachineRegisterInfo &MRI, bool LookThroughInstrs=true)
If VReg is defined by a statically evaluable chain of instructions rooted on a G_FCONSTANT returns it...
Definition Utils.cpp:447
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:433
This struct is a compact representation of a valid (non-zero power of two) alignment.
Definition Alignment.h:39
The LegalityQuery object bundles together all the information that's needed to decide whether a given...
ArrayRef< MemDesc > MMODescrs
Operations which require memory can use this to place requirements on the memory type for each MMO.
ArrayRef< LLT > Types
This class contains a discriminated union of information about pointers in memory operands,...
static LLVM_ABI MachinePointerInfo getConstantPool(MachineFunction &MF)
Return a MachinePointerInfo record that refers to the constant pool.