LLVM 22.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 .clampMinNumElements(0, s8, 16)
104 .clampMinNumElements(0, s16, 8)
105 .clampMinNumElements(0, s32, 4)
106 .clampMinNumElements(0, s64, 2)
107 .clampMaxNumElements(0, s8, HasAVX512 ? 64 : (HasAVX ? 32 : 16))
108 .clampMaxNumElements(0, s16, HasAVX512 ? 32 : (HasAVX ? 16 : 8))
109 .clampMaxNumElements(0, s32, HasAVX512 ? 16 : (HasAVX ? 8 : 4))
110 .clampMaxNumElements(0, s64, HasAVX512 ? 8 : (HasAVX ? 4 : 2))
111 .clampMaxNumElements(0, p0,
112 Is64Bit ? s64MaxVector.getNumElements()
113 : s32MaxVector.getNumElements())
114 .scalarizeIf(scalarOrEltWiderThan(0, 64), 0);
115
117 .legalFor({p0, s8, s16, s32})
118 .legalFor(Is64Bit, {s64})
119 .widenScalarToNextPow2(0, /*Min=*/8)
120 .clampScalar(0, s8, sMaxScalar);
121
122 getActionDefinitionsBuilder({G_LROUND, G_LLROUND, G_FCOS, G_FCOSH, G_FACOS,
123 G_FSIN, G_FSINH, G_FASIN, G_FTAN, G_FTANH,
124 G_FATAN, G_FATAN2, G_FPOW, G_FEXP, G_FEXP2,
125 G_FEXP10, G_FLOG, G_FLOG2, G_FLOG10, G_FPOWI,
126 G_FSINCOS, G_FCEIL, G_FFLOOR})
127 .libcall();
128
130 .legalFor(HasSSE1 || UseX87, {s32})
131 .legalFor(HasSSE2 || UseX87, {s64})
132 .legalFor(UseX87, {s80});
133
134 getActionDefinitionsBuilder({G_GET_ROUNDING, G_SET_ROUNDING})
135 .customFor({s32});
136
137 // merge/unmerge
138 for (unsigned Op : {G_MERGE_VALUES, G_UNMERGE_VALUES}) {
139 unsigned BigTyIdx = Op == G_MERGE_VALUES ? 0 : 1;
140 unsigned LitTyIdx = Op == G_MERGE_VALUES ? 1 : 0;
142 .widenScalarToNextPow2(LitTyIdx, /*Min=*/8)
143 .widenScalarToNextPow2(BigTyIdx, /*Min=*/16)
144 .minScalar(LitTyIdx, s8)
145 .minScalar(BigTyIdx, s32)
146 .legalIf([=](const LegalityQuery &Q) {
147 switch (Q.Types[BigTyIdx].getSizeInBits()) {
148 case 16:
149 case 32:
150 case 64:
151 case 128:
152 case 256:
153 case 512:
154 break;
155 default:
156 return false;
157 }
158 switch (Q.Types[LitTyIdx].getSizeInBits()) {
159 case 8:
160 case 16:
161 case 32:
162 case 64:
163 case 128:
164 case 256:
165 return true;
166 default:
167 return false;
168 }
169 });
170 }
171
172 getActionDefinitionsBuilder({G_UMIN, G_UMAX, G_SMIN, G_SMAX})
173 .widenScalarToNextPow2(0, /*Min=*/32)
174 .lower();
175
176 // integer addition/subtraction
177 getActionDefinitionsBuilder({G_ADD, G_SUB})
178 .legalFor({s8, s16, s32})
179 .legalFor(Is64Bit, {s64})
180 .legalFor(HasSSE2, {v16s8, v8s16, v4s32, v2s64})
181 .legalFor(HasAVX2, {v32s8, v16s16, v8s32, v4s64})
182 .legalFor(HasAVX512, {v16s32, v8s64})
183 .legalFor(HasBWI, {v64s8, v32s16})
184 .clampMinNumElements(0, s8, 16)
185 .clampMinNumElements(0, s16, 8)
186 .clampMinNumElements(0, s32, 4)
187 .clampMinNumElements(0, s64, 2)
188 .clampMaxNumElements(0, s8, HasBWI ? 64 : (HasAVX2 ? 32 : 16))
189 .clampMaxNumElements(0, s16, HasBWI ? 32 : (HasAVX2 ? 16 : 8))
190 .clampMaxNumElements(0, s32, HasAVX512 ? 16 : (HasAVX2 ? 8 : 4))
191 .clampMaxNumElements(0, s64, HasAVX512 ? 8 : (HasAVX2 ? 4 : 2))
192 .widenScalarToNextPow2(0, /*Min=*/32)
193 .clampScalar(0, s8, sMaxScalar)
194 .scalarize(0);
195
196 getActionDefinitionsBuilder({G_UADDE, G_UADDO, G_USUBE, G_USUBO})
197 .legalFor({{s8, s1}, {s16, s1}, {s32, s1}})
198 .legalFor(Is64Bit, {{s64, s1}})
199 .widenScalarToNextPow2(0, /*Min=*/32)
200 .clampScalar(0, s8, sMaxScalar)
201 .clampScalar(1, s1, s1)
202 .scalarize(0);
203
204 // integer multiply
206 .legalFor({s8, s16, s32})
207 .legalFor(Is64Bit, {s64})
208 .legalFor(HasSSE2, {v8s16})
209 .legalFor(HasSSE41, {v4s32})
210 .legalFor(HasAVX2, {v16s16, v8s32})
211 .legalFor(HasAVX512, {v16s32})
212 .legalFor(HasDQI, {v8s64})
213 .legalFor(HasDQI && HasVLX, {v2s64, v4s64})
214 .legalFor(HasBWI, {v32s16})
215 .clampMinNumElements(0, s16, 8)
216 .clampMinNumElements(0, s32, 4)
217 .clampMinNumElements(0, s64, HasVLX ? 2 : 8)
218 .clampMaxNumElements(0, s16, HasBWI ? 32 : (HasAVX2 ? 16 : 8))
219 .clampMaxNumElements(0, s32, HasAVX512 ? 16 : (HasAVX2 ? 8 : 4))
220 .clampMaxNumElements(0, s64, 8)
221 .widenScalarToNextPow2(0, /*Min=*/32)
222 .clampScalar(0, s8, sMaxScalar)
223 .scalarize(0);
224
225 getActionDefinitionsBuilder({G_SMULH, G_UMULH})
226 .legalFor({s8, s16, s32})
227 .legalFor(Is64Bit, {s64})
228 .widenScalarToNextPow2(0, /*Min=*/32)
229 .clampScalar(0, s8, sMaxScalar)
230 .scalarize(0);
231
232 // integer divisions
233 getActionDefinitionsBuilder({G_SDIV, G_SREM, G_UDIV, G_UREM})
234 .legalFor({s8, s16, s32})
235 .legalFor(Is64Bit, {s64})
236 .libcallFor({s64})
237 .clampScalar(0, s8, sMaxScalar);
238
239 // integer shifts
240 getActionDefinitionsBuilder({G_SHL, G_LSHR, G_ASHR})
241 .legalFor({{s8, s8}, {s16, s8}, {s32, s8}})
242 .legalFor(Is64Bit, {{s64, s8}})
243 .clampScalar(0, s8, sMaxScalar)
244 .clampScalar(1, s8, s8);
245
246 // integer logic
247 getActionDefinitionsBuilder({G_AND, G_OR, G_XOR})
248 .legalFor({s8, s16, s32})
249 .legalFor(Is64Bit, {s64})
250 .legalFor(HasSSE2, {v16s8, v8s16, v4s32, v2s64})
251 .legalFor(HasAVX, {v32s8, v16s16, v8s32, v4s64})
252 .legalFor(HasAVX512, {v64s8, v32s16, v16s32, v8s64})
253 .clampMinNumElements(0, s8, 16)
254 .clampMinNumElements(0, s16, 8)
255 .clampMinNumElements(0, s32, 4)
256 .clampMinNumElements(0, s64, 2)
257 .clampMaxNumElements(0, s8, HasAVX512 ? 64 : (HasAVX ? 32 : 16))
258 .clampMaxNumElements(0, s16, HasAVX512 ? 32 : (HasAVX ? 16 : 8))
259 .clampMaxNumElements(0, s32, HasAVX512 ? 16 : (HasAVX ? 8 : 4))
260 .clampMaxNumElements(0, s64, HasAVX512 ? 8 : (HasAVX ? 4 : 2))
261 .widenScalarToNextPow2(0, /*Min=*/32)
262 .clampScalar(0, s8, sMaxScalar)
263 .scalarize(0);
264
265 // integer comparison
266 const std::initializer_list<LLT> IntTypes32 = {s8, s16, s32, p0};
267 const std::initializer_list<LLT> IntTypes64 = {s8, s16, s32, s64, p0};
268
270 .legalForCartesianProduct({s8}, Is64Bit ? IntTypes64 : IntTypes32)
271 .clampScalar(0, s8, s8)
272 .clampScalar(1, s8, sMaxScalar);
273
274 // bswap
276 .legalFor({s32})
277 .legalFor(Is64Bit, {s64})
278 .widenScalarToNextPow2(0, /*Min=*/32)
279 .clampScalar(0, s32, sMaxScalar);
280
281 // popcount
283 .legalFor(HasPOPCNT, {{s16, s16}, {s32, s32}})
284 .legalFor(HasPOPCNT && Is64Bit, {{s64, s64}})
285 .widenScalarToNextPow2(1, /*Min=*/16)
286 .clampScalar(1, s16, sMaxScalar)
287 .scalarSameSizeAs(0, 1);
288
289 // count leading zeros (LZCNT)
291 .legalFor(HasLZCNT, {{s16, s16}, {s32, s32}})
292 .legalFor(HasLZCNT && Is64Bit, {{s64, s64}})
293 .widenScalarToNextPow2(1, /*Min=*/16)
294 .clampScalar(1, s16, sMaxScalar)
295 .scalarSameSizeAs(0, 1);
296
297 // count trailing zeros
298 getActionDefinitionsBuilder(G_CTTZ_ZERO_UNDEF)
299 .legalFor({{s16, s16}, {s32, s32}})
300 .legalFor(Is64Bit, {{s64, s64}})
301 .widenScalarToNextPow2(1, /*Min=*/16)
302 .clampScalar(1, s16, sMaxScalar)
303 .scalarSameSizeAs(0, 1);
304
306 .legalFor(HasBMI, {{s16, s16}, {s32, s32}})
307 .legalFor(HasBMI && Is64Bit, {{s64, s64}})
308 .widenScalarToNextPow2(1, /*Min=*/16)
309 .clampScalar(1, s16, sMaxScalar)
310 .scalarSameSizeAs(0, 1);
311
313
314 // pointer handling
315 const std::initializer_list<LLT> PtrTypes32 = {s1, s8, s16, s32};
316 const std::initializer_list<LLT> PtrTypes64 = {s1, s8, s16, s32, s64};
317
319 .legalForCartesianProduct(Is64Bit ? PtrTypes64 : PtrTypes32, {p0})
320 .maxScalar(0, sMaxScalar)
321 .widenScalarToNextPow2(0, /*Min*/ 8);
322
323 getActionDefinitionsBuilder(G_INTTOPTR).legalFor({{p0, sMaxScalar}});
324
325 getActionDefinitionsBuilder(G_CONSTANT_POOL).legalFor({p0});
326
328 .legalFor({{p0, s32}})
329 .legalFor(Is64Bit, {{p0, s64}})
330 .widenScalarToNextPow2(1, /*Min*/ 32)
331 .clampScalar(1, s32, sMaxScalar);
332
333 getActionDefinitionsBuilder({G_FRAME_INDEX, G_GLOBAL_VALUE}).legalFor({p0});
334
335 // load/store: add more corner cases
336 for (unsigned Op : {G_LOAD, G_STORE}) {
337 auto &Action = getActionDefinitionsBuilder(Op);
338 Action.legalForTypesWithMemDesc({{s8, p0, s8, 1},
339 {s16, p0, s16, 1},
340 {s32, p0, s32, 1},
341 {s80, p0, s80, 1},
342 {p0, p0, p0, 1},
343 {v4s8, p0, v4s8, 1}});
344 if (Is64Bit)
345 Action.legalForTypesWithMemDesc(
346 {{s64, p0, s64, 1}, {v2s32, p0, v2s32, 1}});
347
348 if (HasSSE1)
349 Action.legalForTypesWithMemDesc({{v4s32, p0, v4s32, 1}});
350 if (HasSSE2)
351 Action.legalForTypesWithMemDesc({{v16s8, p0, v16s8, 1},
352 {v8s16, p0, v8s16, 1},
353 {v2s64, p0, v2s64, 1},
354 {v2p0, p0, v2p0, 1}});
355 if (HasAVX)
356 Action.legalForTypesWithMemDesc({{v32s8, p0, v32s8, 1},
357 {v16s16, p0, v16s16, 1},
358 {v8s32, p0, v8s32, 1},
359 {v4s64, p0, v4s64, 1},
360 {v4p0, p0, v4p0, 1}});
361 if (HasAVX512)
362 Action.legalForTypesWithMemDesc({{v64s8, p0, v64s8, 1},
363 {v32s16, p0, v32s16, 1},
364 {v16s32, p0, v16s32, 1},
365 {v8s64, p0, v8s64, 1}});
366
367 // X86 supports extending loads but not stores for GPRs
368 if (Op == G_LOAD) {
369 Action.legalForTypesWithMemDesc({{s8, p0, s1, 1},
370 {s16, p0, s8, 1},
371 {s32, p0, s8, 1},
372 {s32, p0, s16, 1}});
373 if (Is64Bit)
374 Action.legalForTypesWithMemDesc(
375 {{s64, p0, s8, 1}, {s64, p0, s16, 1}, {s64, p0, s32, 1}});
376 } else {
377 Action.customIf([=](const LegalityQuery &Query) {
378 return Query.Types[0] != Query.MMODescrs[0].MemoryTy;
379 });
380 }
381 Action.widenScalarToNextPow2(0, /*Min=*/8)
382 .clampScalar(0, s8, sMaxScalar)
383 .scalarize(0);
384 }
385
386 for (unsigned Op : {G_SEXTLOAD, G_ZEXTLOAD}) {
387 auto &Action = getActionDefinitionsBuilder(Op);
388 Action.legalForTypesWithMemDesc(
389 {{s16, p0, s8, 1}, {s32, p0, s8, 1}, {s32, p0, s16, 1}});
390 if (Is64Bit)
391 Action.legalForTypesWithMemDesc(
392 {{s64, p0, s8, 1}, {s64, p0, s16, 1}, {s64, p0, s32, 1}});
393 // TODO - SSE41/AVX2/AVX512F/AVX512BW vector extensions
394 }
395
396 // sext, zext, and anyext
398 .legalFor({s8, s16, s32, s128})
399 .legalFor(Is64Bit, {s64})
400 .widenScalarToNextPow2(0, /*Min=*/8)
401 .clampScalar(0, s8, sMaxScalar)
402 .widenScalarToNextPow2(1, /*Min=*/8)
403 .clampScalar(1, s8, sMaxScalar)
404 .scalarize(0);
405
406 getActionDefinitionsBuilder({G_SEXT, G_ZEXT})
407 .legalFor({s8, s16, s32})
408 .legalFor(Is64Bit, {s64})
409 .widenScalarToNextPow2(0, /*Min=*/8)
410 .clampScalar(0, s8, sMaxScalar)
411 .widenScalarToNextPow2(1, /*Min=*/8)
412 .clampScalar(1, s8, sMaxScalar)
413 .scalarize(0);
414
415 getActionDefinitionsBuilder(G_SEXT_INREG).lower();
416
417 // fp constants
418 getActionDefinitionsBuilder(G_FCONSTANT)
419 .legalFor({s32, s64})
420 .legalFor(UseX87, {s80});
421
422 // fp arithmetic
423 getActionDefinitionsBuilder({G_FADD, G_FSUB, G_FMUL, G_FDIV})
424 .legalFor({s32, s64})
425 .legalFor(HasSSE1, {v4s32})
426 .legalFor(HasSSE2, {v2s64})
427 .legalFor(HasAVX, {v8s32, v4s64})
428 .legalFor(HasAVX512, {v16s32, v8s64})
429 .legalFor(UseX87, {s80});
430
432 .legalFor(UseX87, {s80})
433 .legalFor(UseX87 && !Is64Bit, {s64})
434 .lower();
435
436 // fp comparison
438 .legalFor(HasSSE1 || UseX87, {s8, s32})
439 .legalFor(HasSSE2 || UseX87, {s8, s64})
440 .legalFor(UseX87, {s8, s80})
441 .clampScalar(0, s8, s8)
442 .clampScalar(1, s32, HasSSE2 ? s64 : s32)
444
445 // fp conversions
447 .legalFor(HasSSE2, {{s64, s32}})
448 .legalFor(HasAVX, {{v4s64, v4s32}})
449 .legalFor(HasAVX512, {{v8s64, v8s32}});
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({{s8, s32}, {s16, s32}, {s32, s32}, {s64, s32}, {p0, s32}})
579 .widenScalarToNextPow2(0, /*Min=*/8)
580 .clampScalar(0, HasCMOV ? s16 : s8, sMaxScalar)
581 .clampScalar(1, s32, s32);
582
583 // memory intrinsics
584 getActionDefinitionsBuilder({G_MEMCPY, G_MEMMOVE, G_MEMSET}).libcall();
585
586 getActionDefinitionsBuilder({G_DYN_STACKALLOC, G_STACKSAVE, G_STACKRESTORE})
587 .lower();
588
589 // fp intrinsics
590 getActionDefinitionsBuilder({G_INTRINSIC_ROUNDEVEN, G_INTRINSIC_TRUNC})
591 .scalarize(0)
592 .minScalar(0, LLT::scalar(32))
593 .libcall();
594
596 verify(*STI.getInstrInfo());
597}
598
600 LostDebugLocObserver &LocObserver) const {
601 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
602 MachineRegisterInfo &MRI = *MIRBuilder.getMRI();
603 switch (MI.getOpcode()) {
604 default:
605 // No idea what to do.
606 return false;
607 case TargetOpcode::G_BUILD_VECTOR:
608 return legalizeBuildVector(MI, MRI, Helper);
609 case TargetOpcode::G_FPTOUI:
610 return legalizeFPTOUI(MI, MRI, Helper);
611 case TargetOpcode::G_UITOFP:
612 return legalizeUITOFP(MI, MRI, Helper);
613 case TargetOpcode::G_STORE:
614 return legalizeNarrowingStore(MI, MRI, Helper);
615 case TargetOpcode::G_SITOFP:
616 return legalizeSITOFP(MI, MRI, Helper);
617 case TargetOpcode::G_FPTOSI:
618 return legalizeFPTOSI(MI, MRI, Helper);
619 case TargetOpcode::G_GET_ROUNDING:
620 return legalizeGETROUNDING(MI, MRI, Helper);
621 case TargetOpcode::G_SET_ROUNDING:
622 return legalizeSETROUNDING(MI, MRI, Helper);
623 }
624 llvm_unreachable("expected switch to return");
625}
626
627bool X86LegalizerInfo::legalizeSITOFP(MachineInstr &MI,
629 LegalizerHelper &Helper) const {
630 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
631 MachineFunction &MF = *MI.getMF();
632 auto [Dst, DstTy, Src, SrcTy] = MI.getFirst2RegLLTs();
633
634 assert((SrcTy.getSizeInBits() == 16 || SrcTy.getSizeInBits() == 32 ||
635 SrcTy.getSizeInBits() == 64) &&
636 "Unexpected source type for SITOFP in X87 mode.");
637
638 TypeSize MemSize = SrcTy.getSizeInBytes();
639 MachinePointerInfo PtrInfo;
640 Align Alignmt = Helper.getStackTemporaryAlignment(SrcTy);
641 auto SlotPointer = Helper.createStackTemporary(MemSize, Alignmt, PtrInfo);
643 PtrInfo, MachineMemOperand::MOStore, MemSize, Align(MemSize));
644
645 // Store the integer value on the FPU stack.
646 MIRBuilder.buildStore(Src, SlotPointer, *StoreMMO);
647
649 PtrInfo, MachineMemOperand::MOLoad, MemSize, Align(MemSize));
650 MIRBuilder.buildInstr(X86::G_FILD)
651 .addDef(Dst)
652 .addUse(SlotPointer.getReg(0))
653 .addMemOperand(LoadMMO);
654
655 MI.eraseFromParent();
656 return true;
657}
658
659bool X86LegalizerInfo::legalizeFPTOSI(MachineInstr &MI,
661 LegalizerHelper &Helper) const {
662 MachineFunction &MF = *MI.getMF();
663 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
664 auto [Dst, DstTy, Src, SrcTy] = MI.getFirst2RegLLTs();
665
666 TypeSize MemSize = DstTy.getSizeInBytes();
667 MachinePointerInfo PtrInfo;
668 Align Alignmt = Helper.getStackTemporaryAlignment(DstTy);
669 auto SlotPointer = Helper.createStackTemporary(MemSize, Alignmt, PtrInfo);
671 PtrInfo, MachineMemOperand::MOStore, MemSize, Align(MemSize));
672
673 MIRBuilder.buildInstr(X86::G_FIST)
674 .addUse(Src)
675 .addUse(SlotPointer.getReg(0))
676 .addMemOperand(StoreMMO);
677
678 MIRBuilder.buildLoad(Dst, SlotPointer, PtrInfo, Align(MemSize));
679 MI.eraseFromParent();
680 return true;
681}
682
683bool X86LegalizerInfo::legalizeBuildVector(MachineInstr &MI,
685 LegalizerHelper &Helper) const {
686 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
687 const auto &BuildVector = cast<GBuildVector>(MI);
688 Register Dst = BuildVector.getReg(0);
689 LLT DstTy = MRI.getType(Dst);
690 MachineFunction &MF = MIRBuilder.getMF();
691 LLVMContext &Ctx = MF.getFunction().getContext();
692 uint64_t DstTySize = DstTy.getScalarSizeInBits();
693
695 for (unsigned i = 0; i < BuildVector.getNumSources(); ++i) {
696 Register Source = BuildVector.getSourceReg(i);
697
698 auto ValueAndReg = getIConstantVRegValWithLookThrough(Source, MRI);
699 if (ValueAndReg) {
700 CstIdxs.emplace_back(ConstantInt::get(Ctx, ValueAndReg->Value));
701 continue;
702 }
703
704 auto FPValueAndReg = getFConstantVRegValWithLookThrough(Source, MRI);
705 if (FPValueAndReg) {
706 CstIdxs.emplace_back(ConstantFP::get(Ctx, FPValueAndReg->Value));
707 continue;
708 }
709
710 if (getOpcodeDef<GImplicitDef>(Source, MRI)) {
711 CstIdxs.emplace_back(UndefValue::get(Type::getIntNTy(Ctx, DstTySize)));
712 continue;
713 }
714 return false;
715 }
716
717 Constant *ConstVal = ConstantVector::get(CstIdxs);
718
719 const DataLayout &DL = MIRBuilder.getDataLayout();
720 unsigned AddrSpace = DL.getDefaultGlobalsAddressSpace();
721 Align Alignment(DL.getABITypeAlign(ConstVal->getType()));
722 auto Addr = MIRBuilder.buildConstantPool(
723 LLT::pointer(AddrSpace, DL.getPointerSizeInBits(AddrSpace)),
724 MF.getConstantPool()->getConstantPoolIndex(ConstVal, Alignment));
725 MachineMemOperand *MMO =
727 MachineMemOperand::MOLoad, DstTy, Alignment);
728
729 MIRBuilder.buildLoad(Dst, Addr, *MMO);
730 MI.eraseFromParent();
731 return true;
732}
733
734bool X86LegalizerInfo::legalizeFPTOUI(MachineInstr &MI,
736 LegalizerHelper &Helper) const {
737 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
738 auto [Dst, DstTy, Src, SrcTy] = MI.getFirst2RegLLTs();
739 unsigned DstSizeInBits = DstTy.getScalarSizeInBits();
740 const LLT s32 = LLT::scalar(32);
741 const LLT s64 = LLT::scalar(64);
742
743 // Simply reuse FPTOSI when it is possible to widen the type
744 if (DstSizeInBits <= 32) {
745 auto Casted = MIRBuilder.buildFPTOSI(DstTy == s32 ? s64 : s32, Src);
746 MIRBuilder.buildTrunc(Dst, Casted);
747 MI.eraseFromParent();
748 return true;
749 }
750
751 return false;
752}
753
754bool X86LegalizerInfo::legalizeUITOFP(MachineInstr &MI,
756 LegalizerHelper &Helper) const {
757 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
758 auto [Dst, DstTy, Src, SrcTy] = MI.getFirst2RegLLTs();
759 const LLT s32 = LLT::scalar(32);
760 const LLT s64 = LLT::scalar(64);
761
762 // Simply reuse SITOFP when it is possible to widen the type
763 if (SrcTy.getSizeInBits() <= 32) {
764 auto Ext = MIRBuilder.buildZExt(SrcTy == s32 ? s64 : s32, Src);
765 MIRBuilder.buildSITOFP(Dst, Ext);
766 MI.eraseFromParent();
767 return true;
768 }
769
770 return false;
771}
772
773bool X86LegalizerInfo::legalizeNarrowingStore(MachineInstr &MI,
775 LegalizerHelper &Helper) const {
776 auto &Store = cast<GStore>(MI);
777 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
778 MachineMemOperand &MMO = **Store.memoperands_begin();
779 MachineFunction &MF = MIRBuilder.getMF();
780 LLT ValTy = MRI.getType(Store.getValueReg());
781 auto *NewMMO = MF.getMachineMemOperand(&MMO, MMO.getPointerInfo(), ValTy);
782
783 Helper.Observer.changingInstr(Store);
784 Store.setMemRefs(MF, {NewMMO});
785 Helper.Observer.changedInstr(Store);
786 return true;
787}
788
789bool X86LegalizerInfo::legalizeGETROUNDING(MachineInstr &MI,
791 LegalizerHelper &Helper) const {
792 /*
793 The rounding mode is in bits 11:10 of FPSR, and has the following
794 settings:
795 00 Round to nearest
796 01 Round to -inf
797 10 Round to +inf
798 11 Round to 0
799
800 GET_ROUNDING, on the other hand, expects the following:
801 -1 Undefined
802 0 Round to 0
803 1 Round to nearest
804 2 Round to +inf
805 3 Round to -inf
806
807 To perform the conversion, we use a packed lookup table of the four 2-bit
808 values that we can index by FPSP[11:10]
809 0x2d --> (0b00,10,11,01) --> (0,2,3,1) >> FPSR[11:10]
810
811 (0x2d >> ((FPSR >> 9) & 6)) & 3
812 */
813
814 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
815 MachineFunction &MF = MIRBuilder.getMF();
816 Register Dst = MI.getOperand(0).getReg();
817 LLT DstTy = MRI.getType(Dst);
818 const LLT s8 = LLT::scalar(8);
819 const LLT s16 = LLT::scalar(16);
820 const LLT s32 = LLT::scalar(32);
821
822 // Save FP Control Word to stack slot
823 int MemSize = 2;
824 Align Alignment = Align(2);
825 MachinePointerInfo PtrInfo;
826 auto StackTemp = Helper.createStackTemporary(TypeSize::getFixed(MemSize),
827 Alignment, PtrInfo);
828 Register StackPtr = StackTemp.getReg(0);
829
830 auto StoreMMO = MF.getMachineMemOperand(PtrInfo, MachineMemOperand::MOStore,
831 MemSize, Alignment);
832
833 // Store FP Control Word to stack slot using G_FNSTCW16
834 MIRBuilder.buildInstr(X86::G_FNSTCW16)
835 .addUse(StackPtr)
836 .addMemOperand(StoreMMO);
837
838 // Load FP Control Word from stack slot
839 auto LoadMMO = MF.getMachineMemOperand(PtrInfo, MachineMemOperand::MOLoad,
840 MemSize, Alignment);
841
842 auto CWD32 =
843 MIRBuilder.buildZExt(s32, MIRBuilder.buildLoad(s16, StackPtr, *LoadMMO));
844 auto Shifted8 = MIRBuilder.buildTrunc(
845 s8, MIRBuilder.buildLShr(s32, CWD32, MIRBuilder.buildConstant(s8, 9)));
846 auto Masked32 = MIRBuilder.buildZExt(
847 s32, MIRBuilder.buildAnd(s8, Shifted8, MIRBuilder.buildConstant(s8, 6)));
848
849 // LUT is a packed lookup table (0x2d) used to map the 2-bit x87 FPU rounding
850 // mode (from bits 11:10 of the control word) to the values expected by
851 // GET_ROUNDING. The mapping is performed by shifting LUT right by the
852 // extracted rounding mode and masking the result with 3 to obtain the final
853 auto LUT = MIRBuilder.buildConstant(s32, 0x2d);
854 auto LUTShifted = MIRBuilder.buildLShr(s32, LUT, Masked32);
855 auto RetVal =
856 MIRBuilder.buildAnd(s32, LUTShifted, MIRBuilder.buildConstant(s32, 3));
857 auto RetValTrunc = MIRBuilder.buildZExtOrTrunc(DstTy, RetVal);
858
859 MIRBuilder.buildCopy(Dst, RetValTrunc);
860
861 MI.eraseFromParent();
862 return true;
863}
864
865bool X86LegalizerInfo::legalizeSETROUNDING(MachineInstr &MI,
867 LegalizerHelper &Helper) const {
868 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
869 MachineFunction &MF = MIRBuilder.getMF();
870 Register Src = MI.getOperand(0).getReg();
871 const LLT s8 = LLT::scalar(8);
872 const LLT s16 = LLT::scalar(16);
873 const LLT s32 = LLT::scalar(32);
874
875 // Allocate stack slot for control word and MXCSR (4 bytes).
876 int MemSize = 4;
877 Align Alignment = Align(4);
878 MachinePointerInfo PtrInfo;
879 auto StackTemp = Helper.createStackTemporary(TypeSize::getFixed(MemSize),
880 Alignment, PtrInfo);
881 Register StackPtr = StackTemp.getReg(0);
882
883 auto StoreMMO =
885 MIRBuilder.buildInstr(X86::G_FNSTCW16)
886 .addUse(StackPtr)
887 .addMemOperand(StoreMMO);
888
889 auto LoadMMO =
891 auto CWD16 = MIRBuilder.buildLoad(s16, StackPtr, *LoadMMO);
892
893 // Clear RM field (bits 11:10)
894 auto ClearedCWD =
895 MIRBuilder.buildAnd(s16, CWD16, MIRBuilder.buildConstant(s16, 0xf3ff));
896
897 // Check if Src is a constant
898 auto *SrcDef = MRI.getVRegDef(Src);
899 Register RMBits;
900 Register MXCSRRMBits;
901
902 if (SrcDef && SrcDef->getOpcode() == TargetOpcode::G_CONSTANT) {
903 uint64_t RM = getIConstantFromReg(Src, MRI).getZExtValue();
904 int FieldVal = X86::getRoundingModeX86(RM);
905
906 if (FieldVal == X86::rmInvalid) {
907 FieldVal = X86::rmToNearest;
908 LLVMContext &C = MF.getFunction().getContext();
909 C.diagnose(DiagnosticInfoUnsupported(
910 MF.getFunction(), "rounding mode is not supported by X86 hardware",
911 DiagnosticLocation(MI.getDebugLoc()), DS_Error));
912 return false;
913 }
914
915 FieldVal = FieldVal << 3;
916 RMBits = MIRBuilder.buildConstant(s16, FieldVal).getReg(0);
917 MXCSRRMBits = MIRBuilder.buildConstant(s32, FieldVal).getReg(0);
918 } else {
919 // Convert Src (rounding mode) to bits for control word
920 // (0xc9 << (2 * Src + 4)) & 0xc00
921 auto Src32 = MIRBuilder.buildZExtOrTrunc(s32, Src);
922 auto ShiftAmt = MIRBuilder.buildAdd(
923 s32, MIRBuilder.buildShl(s32, Src32, MIRBuilder.buildConstant(s32, 1)),
924 MIRBuilder.buildConstant(s32, 4));
925 auto ShiftAmt8 = MIRBuilder.buildTrunc(s8, ShiftAmt);
926 auto Shifted = MIRBuilder.buildShl(s16, MIRBuilder.buildConstant(s16, 0xc9),
927 ShiftAmt8);
928 RMBits =
929 MIRBuilder.buildAnd(s16, Shifted, MIRBuilder.buildConstant(s16, 0xc00))
930 .getReg(0);
931
932 // For non-constant case, we still need to compute MXCSR bits dynamically
933 auto RMBits32 = MIRBuilder.buildZExt(s32, RMBits);
934 MXCSRRMBits =
935 MIRBuilder.buildShl(s32, RMBits32, MIRBuilder.buildConstant(s32, 3))
936 .getReg(0);
937 }
938 // Update rounding mode bits
939 auto NewCWD =
940 MIRBuilder.buildOr(s16, ClearedCWD, RMBits, MachineInstr::Disjoint);
941
942 // Store new FP Control Word to stack
943 auto StoreNewMMO =
945 MIRBuilder.buildStore(NewCWD, StackPtr, *StoreNewMMO);
946
947 // Load FP control word from the slot using G_FLDCW16
948 auto LoadNewMMO =
950 MIRBuilder.buildInstr(X86::G_FLDCW16)
951 .addUse(StackPtr)
952 .addMemOperand(LoadNewMMO);
953
954 if (Subtarget.hasSSE1()) {
955 // Store MXCSR to stack (use STMXCSR)
956 auto StoreMXCSRMMO = MF.getMachineMemOperand(
957 PtrInfo, MachineMemOperand::MOStore, 4, Align(4));
958 MIRBuilder.buildInstr(TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS)
959 .addIntrinsicID(Intrinsic::x86_sse_stmxcsr)
960 .addUse(StackPtr)
961 .addMemOperand(StoreMXCSRMMO);
962
963 // Load MXCSR from stack
964 auto LoadMXCSRMMO = MF.getMachineMemOperand(
965 PtrInfo, MachineMemOperand::MOLoad, 4, Align(4));
966 auto MXCSR = MIRBuilder.buildLoad(s32, StackPtr, *LoadMXCSRMMO);
967
968 // Clear RM field (bits 14:13)
969 auto ClearedMXCSR = MIRBuilder.buildAnd(
970 s32, MXCSR, MIRBuilder.buildConstant(s32, 0xffff9fff));
971
972 // Update rounding mode bits
973 auto NewMXCSR = MIRBuilder.buildOr(s32, ClearedMXCSR, MXCSRRMBits);
974
975 // Store new MXCSR to stack
976 auto StoreNewMXCSRMMO = MF.getMachineMemOperand(
977 PtrInfo, MachineMemOperand::MOStore, 4, Align(4));
978 MIRBuilder.buildStore(NewMXCSR, StackPtr, *StoreNewMXCSRMMO);
979
980 // Load MXCSR from stack (use LDMXCSR)
981 auto LoadNewMXCSRMMO = MF.getMachineMemOperand(
982 PtrInfo, MachineMemOperand::MOLoad, 4, Align(4));
983 MIRBuilder.buildInstr(TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS)
984 .addIntrinsicID(Intrinsic::x86_sse_ldmxcsr)
985 .addUse(StackPtr)
986 .addMemOperand(LoadNewMXCSRMMO);
987 }
988
989 MI.eraseFromParent();
990 return true;
991}
992
994 MachineInstr &MI) const {
995 return true;
996}
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 * > &Replace)
Definition ExpandFp.cpp:942
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:1540
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:359
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 & 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 & addIntrinsicID(Intrinsic::ID ID) const
const MachineInstrBuilder & addUse(Register RegNo, unsigned Flags=0, unsigned SubReg=0) const
Add a virtual register use operand.
const MachineInstrBuilder & addMemOperand(MachineMemOperand *MMO) const
const MachineInstrBuilder & addDef(Register RegNo, unsigned Flags=0, unsigned SubReg=0) const
Add a virtual register definition operand.
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)
static constexpr TypeSize getFixed(ScalarTy ExactSize)
Definition TypeSize.h:344
static LLVM_ABI IntegerType * getIntNTy(LLVMContext &C, unsigned N)
Definition Type.cpp:301
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.
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:651
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
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
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:560
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.