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 .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})
123 .widenScalarIf(typeIs(1, s16),
124 [=](const LegalityQuery &) {
125 return std::pair<unsigned, LLT>(1, s32);
126 })
127 .libcall();
128
130 {G_FCOS, G_FCOSH, G_FACOS, G_FSIN, G_FSINH, G_FASIN, G_FTAN,
131 G_FTANH, G_FATAN, G_FATAN2, G_FPOW, G_FEXP, G_FEXP2, G_FEXP10,
132 G_FLOG, G_FLOG2, G_FLOG10, G_FPOWI, G_FSINCOS, G_FCEIL, G_FFLOOR})
133 .libcall();
134
136 .legalFor(HasSSE1 || UseX87, {s32})
137 .legalFor(HasSSE2 || UseX87, {s64})
138 .legalFor(UseX87, {s80});
139
140 getActionDefinitionsBuilder({G_GET_ROUNDING, G_SET_ROUNDING})
141 .customFor({s32});
142
143 // merge/unmerge
144 for (unsigned Op : {G_MERGE_VALUES, G_UNMERGE_VALUES}) {
145 unsigned BigTyIdx = Op == G_MERGE_VALUES ? 0 : 1;
146 unsigned LitTyIdx = Op == G_MERGE_VALUES ? 1 : 0;
148 .widenScalarToNextPow2(LitTyIdx, /*Min=*/8)
149 .widenScalarToNextPow2(BigTyIdx, /*Min=*/16)
150 .minScalar(LitTyIdx, s8)
151 .minScalar(BigTyIdx, s32)
152 .legalIf([=](const LegalityQuery &Q) {
153 switch (Q.Types[BigTyIdx].getSizeInBits()) {
154 case 16:
155 case 32:
156 case 64:
157 case 128:
158 case 256:
159 case 512:
160 break;
161 default:
162 return false;
163 }
164 switch (Q.Types[LitTyIdx].getSizeInBits()) {
165 case 8:
166 case 16:
167 case 32:
168 case 64:
169 case 128:
170 case 256:
171 return true;
172 default:
173 return false;
174 }
175 });
176 }
177
178 getActionDefinitionsBuilder({G_UMIN, G_UMAX, G_SMIN, G_SMAX})
179 .widenScalarToNextPow2(0, /*Min=*/32)
180 .lower();
181
182 // integer addition/subtraction
183 getActionDefinitionsBuilder({G_ADD, G_SUB})
184 .legalFor({s8, s16, s32})
185 .legalFor(Is64Bit, {s64})
186 .legalFor(HasSSE2, {v16s8, v8s16, v4s32, v2s64})
187 .legalFor(HasAVX2, {v32s8, v16s16, v8s32, v4s64})
188 .legalFor(HasAVX512, {v16s32, v8s64})
189 .legalFor(HasBWI, {v64s8, v32s16})
190 .clampMinNumElements(0, s8, 16)
191 .clampMinNumElements(0, s16, 8)
192 .clampMinNumElements(0, s32, 4)
193 .clampMinNumElements(0, s64, 2)
194 .clampMaxNumElements(0, s8, HasBWI ? 64 : (HasAVX2 ? 32 : 16))
195 .clampMaxNumElements(0, s16, HasBWI ? 32 : (HasAVX2 ? 16 : 8))
196 .clampMaxNumElements(0, s32, HasAVX512 ? 16 : (HasAVX2 ? 8 : 4))
197 .clampMaxNumElements(0, s64, HasAVX512 ? 8 : (HasAVX2 ? 4 : 2))
198 .widenScalarToNextPow2(0, /*Min=*/32)
199 .clampScalar(0, s8, sMaxScalar)
200 .scalarize(0);
201
202 getActionDefinitionsBuilder({G_UADDE, G_UADDO, G_USUBE, G_USUBO})
203 .legalFor({{s8, s8}, {s16, s8}, {s32, s8}})
204 .legalFor(Is64Bit, {{s64, s8}})
205 .widenScalarToNextPow2(0, /*Min=*/32)
206 .clampScalar(0, s8, sMaxScalar)
207 .clampScalar(1, s8, s8)
208 .scalarize(0);
209
210 // integer multiply
212 .legalFor({s8, s16, s32})
213 .legalFor(Is64Bit, {s64})
214 .legalFor(HasSSE2, {v8s16})
215 .legalFor(HasSSE41, {v4s32})
216 .legalFor(HasAVX2, {v16s16, v8s32})
217 .legalFor(HasAVX512, {v16s32})
218 .legalFor(HasDQI, {v8s64})
219 .legalFor(HasDQI && HasVLX, {v2s64, v4s64})
220 .legalFor(HasBWI, {v32s16})
221 .clampMinNumElements(0, s16, 8)
222 .clampMinNumElements(0, s32, 4)
223 .clampMinNumElements(0, s64, HasVLX ? 2 : 8)
224 .clampMaxNumElements(0, s16, HasBWI ? 32 : (HasAVX2 ? 16 : 8))
225 .clampMaxNumElements(0, s32, HasAVX512 ? 16 : (HasAVX2 ? 8 : 4))
226 .clampMaxNumElements(0, s64, 8)
227 .widenScalarToNextPow2(0, /*Min=*/32)
228 .clampScalar(0, s8, sMaxScalar)
229 .scalarize(0);
230
231 getActionDefinitionsBuilder({G_SMULH, G_UMULH})
232 .legalFor({s8, s16, s32})
233 .legalFor(Is64Bit, {s64})
234 .widenScalarToNextPow2(0, /*Min=*/32)
235 .clampScalar(0, s8, sMaxScalar)
236 .scalarize(0);
237
238 // integer divisions
239 getActionDefinitionsBuilder({G_SDIV, G_SREM, G_UDIV, G_UREM})
240 .legalFor({s8, s16, s32})
241 .legalFor(Is64Bit, {s64})
242 .libcallFor({s64})
243 .clampScalar(0, s8, sMaxScalar);
244
245 // integer shifts
246 getActionDefinitionsBuilder({G_SHL, G_LSHR, G_ASHR})
247 .legalFor({{s8, s8}, {s16, s8}, {s32, s8}})
248 .legalFor(Is64Bit, {{s64, s8}})
249 .clampScalar(0, s8, sMaxScalar)
250 .clampScalar(1, s8, s8);
251
252 // integer logic
253 getActionDefinitionsBuilder({G_AND, G_OR, G_XOR})
254 .legalFor({s8, s16, s32})
255 .legalFor(Is64Bit, {s64})
256 .legalFor(HasSSE2, {v16s8, v8s16, v4s32, v2s64})
257 .legalFor(HasAVX, {v32s8, v16s16, v8s32, v4s64})
258 .legalFor(HasAVX512, {v64s8, v32s16, v16s32, v8s64})
259 .clampMinNumElements(0, s8, 16)
260 .clampMinNumElements(0, s16, 8)
261 .clampMinNumElements(0, s32, 4)
262 .clampMinNumElements(0, s64, 2)
263 .clampMaxNumElements(0, s8, HasAVX512 ? 64 : (HasAVX ? 32 : 16))
264 .clampMaxNumElements(0, s16, HasAVX512 ? 32 : (HasAVX ? 16 : 8))
265 .clampMaxNumElements(0, s32, HasAVX512 ? 16 : (HasAVX ? 8 : 4))
266 .clampMaxNumElements(0, s64, HasAVX512 ? 8 : (HasAVX ? 4 : 2))
267 .widenScalarToNextPow2(0, /*Min=*/32)
268 .clampScalar(0, s8, sMaxScalar)
269 .scalarize(0);
270
271 // integer comparison
272 const std::initializer_list<LLT> IntTypes32 = {s8, s16, s32, p0};
273 const std::initializer_list<LLT> IntTypes64 = {s8, s16, s32, s64, p0};
274
276 .legalForCartesianProduct({s8}, Is64Bit ? IntTypes64 : IntTypes32)
277 .clampScalar(0, s8, s8)
278 .widenScalarToNextPow2(1, /*Min=*/8)
279 .clampScalar(1, s8, sMaxScalar);
280
281 // bswap
283 .legalFor({s32})
284 .legalFor(Is64Bit, {s64})
285 .widenScalarToNextPow2(0, /*Min=*/32)
286 .clampScalar(0, s32, sMaxScalar);
287
288 // popcount
290 .legalFor(HasPOPCNT, {{s16, s16}, {s32, s32}})
291 .legalFor(HasPOPCNT && Is64Bit, {{s64, s64}})
292 .widenScalarToNextPow2(1, /*Min=*/16)
293 .clampScalar(1, s16, sMaxScalar)
294 .scalarSameSizeAs(0, 1);
295
296 // count leading zeros (LZCNT)
298 .legalFor(HasLZCNT, {{s16, s16}, {s32, s32}})
299 .legalFor(HasLZCNT && Is64Bit, {{s64, s64}})
300 .widenScalarToNextPow2(1, /*Min=*/16)
301 .clampScalar(1, s16, sMaxScalar)
302 .scalarSameSizeAs(0, 1);
303
304 // count trailing zeros
305 getActionDefinitionsBuilder(G_CTTZ_ZERO_UNDEF)
306 .legalFor({{s16, s16}, {s32, s32}})
307 .legalFor(Is64Bit, {{s64, s64}})
308 .widenScalarToNextPow2(1, /*Min=*/16)
309 .clampScalar(1, s16, sMaxScalar)
310 .scalarSameSizeAs(0, 1);
311
313 .legalFor(HasBMI, {{s16, s16}, {s32, s32}})
314 .legalFor(HasBMI && Is64Bit, {{s64, s64}})
315 .widenScalarToNextPow2(1, /*Min=*/16)
316 .clampScalar(1, s16, sMaxScalar)
317 .scalarSameSizeAs(0, 1);
318
320
321 // pointer handling
322 const std::initializer_list<LLT> PtrTypes32 = {s1, s8, s16, s32};
323 const std::initializer_list<LLT> PtrTypes64 = {s1, s8, s16, s32, s64};
324
326 .legalForCartesianProduct(Is64Bit ? PtrTypes64 : PtrTypes32, {p0})
327 .maxScalar(0, sMaxScalar)
328 .widenScalarToNextPow2(0, /*Min*/ 8);
329
330 getActionDefinitionsBuilder(G_INTTOPTR).legalFor({{p0, sMaxScalar}});
331
332 getActionDefinitionsBuilder(G_CONSTANT_POOL).legalFor({p0});
333
335 .legalFor({{p0, s32}})
336 .legalFor(Is64Bit, {{p0, s64}})
337 .widenScalarToNextPow2(1, /*Min*/ 32)
338 .clampScalar(1, s32, sMaxScalar);
339
340 getActionDefinitionsBuilder({G_FRAME_INDEX, G_GLOBAL_VALUE}).legalFor({p0});
341
342 // load/store: add more corner cases
343 for (unsigned Op : {G_LOAD, G_STORE}) {
344 auto &Action = getActionDefinitionsBuilder(Op);
345 Action.legalForTypesWithMemDesc({{s8, p0, s8, 1},
346 {s16, p0, s16, 1},
347 {s32, p0, s32, 1},
348 {s80, p0, s80, 1},
349 {p0, p0, p0, 1},
350 {v4s8, p0, v4s8, 1}});
351 if (Is64Bit)
352 Action.legalForTypesWithMemDesc(
353 {{s64, p0, s64, 1}, {v2s32, p0, v2s32, 1}});
354
355 if (HasSSE1)
356 Action.legalForTypesWithMemDesc({{v4s32, p0, v4s32, 1}});
357 if (HasSSE2)
358 Action.legalForTypesWithMemDesc({{v16s8, p0, v16s8, 1},
359 {v8s16, p0, v8s16, 1},
360 {v2s64, p0, v2s64, 1},
361 {v2p0, p0, v2p0, 1}});
362 if (HasAVX)
363 Action.legalForTypesWithMemDesc({{v32s8, p0, v32s8, 1},
364 {v16s16, p0, v16s16, 1},
365 {v8s32, p0, v8s32, 1},
366 {v4s64, p0, v4s64, 1},
367 {v4p0, p0, v4p0, 1}});
368 if (HasAVX512)
369 Action.legalForTypesWithMemDesc({{v64s8, p0, v64s8, 1},
370 {v32s16, p0, v32s16, 1},
371 {v16s32, p0, v16s32, 1},
372 {v8s64, p0, v8s64, 1}});
373
374 // X86 supports extending loads but not stores for GPRs
375 if (Op == G_LOAD) {
376 Action.legalForTypesWithMemDesc({{s8, p0, s1, 1},
377 {s16, p0, s8, 1},
378 {s32, p0, s8, 1},
379 {s32, p0, s16, 1}});
380 if (Is64Bit)
381 Action.legalForTypesWithMemDesc(
382 {{s64, p0, s8, 1}, {s64, p0, s16, 1}, {s64, p0, s32, 1}});
383 } else {
384 Action.customIf([=](const LegalityQuery &Query) {
385 return Query.Types[0] != Query.MMODescrs[0].MemoryTy;
386 });
387 }
388 Action.widenScalarToNextPow2(0, /*Min=*/8)
389 .clampScalar(0, s8, sMaxScalar)
390 .scalarize(0);
391 }
392
393 for (unsigned Op : {G_SEXTLOAD, G_ZEXTLOAD}) {
394 auto &Action = getActionDefinitionsBuilder(Op);
395 Action.legalForTypesWithMemDesc(
396 {{s16, p0, s8, 1}, {s32, p0, s8, 1}, {s32, p0, s16, 1}});
397 if (Is64Bit)
398 Action.legalForTypesWithMemDesc(
399 {{s64, p0, s8, 1}, {s64, p0, s16, 1}, {s64, p0, s32, 1}});
400 // TODO - SSE41/AVX2/AVX512F/AVX512BW vector extensions
401 }
402
403 // sext, zext, and anyext
405 .legalFor({s8, s16, s32, s128})
406 .legalFor(Is64Bit, {s64})
407 .widenScalarToNextPow2(0, /*Min=*/8)
408 .clampScalar(0, s8, sMaxScalar)
409 .widenScalarToNextPow2(1, /*Min=*/8)
410 .clampScalar(1, s8, sMaxScalar)
411 .scalarize(0);
412
413 getActionDefinitionsBuilder({G_SEXT, G_ZEXT})
414 .legalFor({s8, s16, s32})
415 .legalFor(Is64Bit, {s64})
416 .widenScalarToNextPow2(0, /*Min=*/8)
417 .clampScalar(0, s8, sMaxScalar)
418 .widenScalarToNextPow2(1, /*Min=*/8)
419 .clampScalar(1, s8, sMaxScalar)
420 .scalarize(0);
421
422 getActionDefinitionsBuilder(G_SEXT_INREG).lower();
423
424 // fp constants
425 getActionDefinitionsBuilder(G_FCONSTANT)
426 .legalFor({s32, s64})
427 .legalFor(UseX87, {s80});
428
429 // fp arithmetic
430 getActionDefinitionsBuilder({G_FADD, G_FSUB, G_FMUL, G_FDIV})
431 .legalFor({s32, s64})
432 .legalFor(HasSSE1, {v4s32})
433 .legalFor(HasSSE2, {v2s64})
434 .legalFor(HasAVX, {v8s32, v4s64})
435 .legalFor(HasAVX512, {v16s32, v8s64})
436 .legalFor(UseX87, {s80});
437
439 .legalFor(UseX87, {s80})
440 .legalFor(UseX87 && !Is64Bit, {s64})
441 .lower();
442
443 // fp comparison
445 .legalFor(HasSSE1 || UseX87, {s8, s32})
446 .legalFor(HasSSE2 || UseX87, {s8, s64})
447 .legalFor(UseX87, {s8, s80})
448 .clampScalar(0, s8, s8)
449 .clampScalar(1, s32, HasSSE2 ? s64 : s32)
451
452 // fp conversions
454 .legalFor(HasSSE2, {{s64, s32}})
455 .legalFor(HasAVX, {{v4s64, v4s32}})
456 .legalFor(HasAVX512, {{v8s64, v8s32}})
457 .libcall();
458
460 .legalFor(HasSSE2, {{s32, s64}})
461 .legalFor(HasAVX, {{v4s32, v4s64}})
462 .legalFor(HasAVX512, {{v8s32, v8s64}});
463
465 .legalFor(HasSSE1, {{s32, s32}})
466 .legalFor(HasSSE1 && Is64Bit, {{s32, s64}})
467 .legalFor(HasSSE2, {{s64, s32}})
468 .legalFor(HasSSE2 && Is64Bit, {{s64, s64}})
469 .clampScalar(1, (UseX87 && !HasSSE1) ? s16 : s32, sMaxScalar)
471 .customForCartesianProduct(UseX87, {s32, s64, s80}, {s16, s32, s64})
472 .clampScalar(0, s32, HasSSE2 ? s64 : s32)
474
476 .legalFor(HasSSE1, {{s32, s32}})
477 .legalFor(HasSSE1 && Is64Bit, {{s64, s32}})
478 .legalFor(HasSSE2, {{s32, s64}})
479 .legalFor(HasSSE2 && Is64Bit, {{s64, s64}})
480 .clampScalar(0, (UseX87 && !HasSSE1) ? s16 : s32, sMaxScalar)
482 .customForCartesianProduct(UseX87, {s16, s32, s64}, {s32, s64, s80})
483 .clampScalar(1, s32, HasSSE2 ? s64 : s32)
485
486 // For G_UITOFP and G_FPTOUI without AVX512, we have to custom legalize types
487 // <= s32 manually. Otherwise, in custom handler there is no way to
488 // understand whether s32 is an original type and we need to promote it to
489 // s64 or s32 is obtained after widening and we shouldn't widen it to s64.
490 //
491 // For AVX512 we simply widen types as there is direct mapping from opcodes
492 // to asm instructions.
494 .legalFor(HasAVX512, {{s32, s32}, {s32, s64}, {s64, s32}, {s64, s64}})
495 .customIf([=](const LegalityQuery &Query) {
496 return !HasAVX512 &&
497 ((HasSSE1 && typeIs(0, s32)(Query)) ||
498 (HasSSE2 && typeIs(0, s64)(Query))) &&
499 scalarNarrowerThan(1, Is64Bit ? 64 : 32)(Query);
500 })
501 .lowerIf([=](const LegalityQuery &Query) {
502 // Lower conversions from s64
503 return !HasAVX512 &&
504 ((HasSSE1 && typeIs(0, s32)(Query)) ||
505 (HasSSE2 && typeIs(0, s64)(Query))) &&
506 (Is64Bit && typeIs(1, s64)(Query));
507 })
508 .clampScalar(0, s32, HasSSE2 ? s64 : s32)
510 .clampScalar(1, s32, sMaxScalar)
512
514 .legalFor(HasAVX512, {{s32, s32}, {s32, s64}, {s64, s32}, {s64, s64}})
515 .customIf([=](const LegalityQuery &Query) {
516 return !HasAVX512 &&
517 ((HasSSE1 && typeIs(1, s32)(Query)) ||
518 (HasSSE2 && typeIs(1, s64)(Query))) &&
519 scalarNarrowerThan(0, Is64Bit ? 64 : 32)(Query);
520 })
521 // TODO: replace with customized legalization using
522 // specifics of cvttsd2si. The selection of this node requires
523 // a vector type. Either G_SCALAR_TO_VECTOR is needed or more advanced
524 // support of G_BUILD_VECTOR/G_INSERT_VECTOR_ELT is required beforehand.
525 .lowerIf([=](const LegalityQuery &Query) {
526 return !HasAVX512 &&
527 ((HasSSE1 && typeIs(1, s32)(Query)) ||
528 (HasSSE2 && typeIs(1, s64)(Query))) &&
529 (Is64Bit && typeIs(0, s64)(Query));
530 })
531 .clampScalar(0, s32, sMaxScalar)
533 .clampScalar(1, s32, HasSSE2 ? s64 : s32)
535
536 // vector ops
537 getActionDefinitionsBuilder(G_BUILD_VECTOR)
538 .customIf([=](const LegalityQuery &Query) {
539 return (HasSSE1 && typeInSet(0, {v4s32})(Query)) ||
540 (HasSSE2 && typeInSet(0, {v2s64, v8s16, v16s8})(Query)) ||
541 (HasAVX && typeInSet(0, {v4s64, v8s32, v16s16, v32s8})(Query)) ||
542 (HasAVX512 && typeInSet(0, {v8s64, v16s32, v32s16, v64s8}));
543 })
544 .clampNumElements(0, v16s8, s8MaxVector)
545 .clampNumElements(0, v8s16, s16MaxVector)
546 .clampNumElements(0, v4s32, s32MaxVector)
547 .clampNumElements(0, v2s64, s64MaxVector)
549
550 getActionDefinitionsBuilder({G_EXTRACT, G_INSERT})
551 .legalIf([=](const LegalityQuery &Query) {
552 unsigned SubIdx = Query.Opcode == G_EXTRACT ? 0 : 1;
553 unsigned FullIdx = Query.Opcode == G_EXTRACT ? 1 : 0;
554 return (HasAVX && typePairInSet(SubIdx, FullIdx,
555 {{v16s8, v32s8},
556 {v8s16, v16s16},
557 {v4s32, v8s32},
558 {v2s64, v4s64}})(Query)) ||
559 (HasAVX512 && typePairInSet(SubIdx, FullIdx,
560 {{v16s8, v64s8},
561 {v32s8, v64s8},
562 {v8s16, v32s16},
563 {v16s16, v32s16},
564 {v4s32, v16s32},
565 {v8s32, v16s32},
566 {v2s64, v8s64},
567 {v4s64, v8s64}})(Query));
568 });
569
570 // todo: only permit dst types up to max legal vector register size?
571 getActionDefinitionsBuilder(G_CONCAT_VECTORS)
572 .legalFor(
573 HasSSE1,
574 {{v32s8, v16s8}, {v16s16, v8s16}, {v8s32, v4s32}, {v4s64, v2s64}})
575 .legalFor(HasAVX, {{v64s8, v16s8},
576 {v64s8, v32s8},
577 {v32s16, v8s16},
578 {v32s16, v16s16},
579 {v16s32, v4s32},
580 {v16s32, v8s32},
581 {v8s64, v2s64},
582 {v8s64, v4s64}});
583
584 // todo: vectors and address spaces
586 .legalFor({{s16, s32}, {s32, s32}, {p0, s32}})
587 .legalFor(!HasCMOV, {{s8, s32}})
588 .legalFor(Is64Bit, {{s64, s32}})
589 .legalFor(UseX87, {{s80, s32}})
590 .clampScalar(1, s32, s32)
591 .widenScalarToNextPow2(0, /*Min=*/8)
592 .clampScalar(0, HasCMOV ? s16 : s8, sMaxScalar);
593
594 // memory intrinsics
595 getActionDefinitionsBuilder({G_MEMCPY, G_MEMMOVE, G_MEMSET}).libcall();
596
597 getActionDefinitionsBuilder({G_DYN_STACKALLOC, G_STACKSAVE, G_STACKRESTORE})
598 .lower();
599
600 // fp intrinsics
601 // fpclass for i686 is disabled for llvm issue #171992
602 getActionDefinitionsBuilder(G_IS_FPCLASS)
603 .lowerFor(Is64Bit, {{s1, s32}, {s1, s64}, {s1, s80}});
604
605 getActionDefinitionsBuilder({G_INTRINSIC_ROUNDEVEN, G_INTRINSIC_TRUNC})
606 .scalarize(0)
607 .minScalar(0, LLT::scalar(32))
608 .libcall();
609
611 verify(*STI.getInstrInfo());
612}
613
615 LostDebugLocObserver &LocObserver) const {
616 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
617 MachineRegisterInfo &MRI = *MIRBuilder.getMRI();
618 switch (MI.getOpcode()) {
619 default:
620 // No idea what to do.
621 return false;
622 case TargetOpcode::G_BUILD_VECTOR:
623 return legalizeBuildVector(MI, MRI, Helper);
624 case TargetOpcode::G_FPTOUI:
625 return legalizeFPTOUI(MI, MRI, Helper);
626 case TargetOpcode::G_UITOFP:
627 return legalizeUITOFP(MI, MRI, Helper);
628 case TargetOpcode::G_STORE:
629 return legalizeNarrowingStore(MI, MRI, Helper);
630 case TargetOpcode::G_SITOFP:
631 return legalizeSITOFP(MI, MRI, Helper);
632 case TargetOpcode::G_FPTOSI:
633 return legalizeFPTOSI(MI, MRI, Helper);
634 case TargetOpcode::G_GET_ROUNDING:
635 return legalizeGETROUNDING(MI, MRI, Helper);
636 case TargetOpcode::G_SET_ROUNDING:
637 return legalizeSETROUNDING(MI, MRI, Helper);
638 }
639 llvm_unreachable("expected switch to return");
640}
641
642bool X86LegalizerInfo::legalizeSITOFP(MachineInstr &MI,
644 LegalizerHelper &Helper) const {
645 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
646 MachineFunction &MF = *MI.getMF();
647 auto [Dst, DstTy, Src, SrcTy] = MI.getFirst2RegLLTs();
648
649 assert((SrcTy.getSizeInBits() == 16 || SrcTy.getSizeInBits() == 32 ||
650 SrcTy.getSizeInBits() == 64) &&
651 "Unexpected source type for SITOFP in X87 mode.");
652
653 TypeSize MemSize = SrcTy.getSizeInBytes();
654 MachinePointerInfo PtrInfo;
655 Align Alignmt = Helper.getStackTemporaryAlignment(SrcTy);
656 auto SlotPointer = Helper.createStackTemporary(MemSize, Alignmt, PtrInfo);
658 PtrInfo, MachineMemOperand::MOStore, MemSize, Align(MemSize));
659
660 // Store the integer value on the FPU stack.
661 MIRBuilder.buildStore(Src, SlotPointer, *StoreMMO);
662
664 PtrInfo, MachineMemOperand::MOLoad, MemSize, Align(MemSize));
665 MIRBuilder.buildInstr(X86::G_FILD)
666 .addDef(Dst)
667 .addUse(SlotPointer.getReg(0))
668 .addMemOperand(LoadMMO);
669
670 MI.eraseFromParent();
671 return true;
672}
673
674bool X86LegalizerInfo::legalizeFPTOSI(MachineInstr &MI,
676 LegalizerHelper &Helper) const {
677 MachineFunction &MF = *MI.getMF();
678 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
679 auto [Dst, DstTy, Src, SrcTy] = MI.getFirst2RegLLTs();
680
681 TypeSize MemSize = DstTy.getSizeInBytes();
682 MachinePointerInfo PtrInfo;
683 Align Alignmt = Helper.getStackTemporaryAlignment(DstTy);
684 auto SlotPointer = Helper.createStackTemporary(MemSize, Alignmt, PtrInfo);
686 PtrInfo, MachineMemOperand::MOStore, MemSize, Align(MemSize));
687
688 MIRBuilder.buildInstr(X86::G_FIST)
689 .addUse(Src)
690 .addUse(SlotPointer.getReg(0))
691 .addMemOperand(StoreMMO);
692
693 MIRBuilder.buildLoad(Dst, SlotPointer, PtrInfo, Align(MemSize));
694 MI.eraseFromParent();
695 return true;
696}
697
698bool X86LegalizerInfo::legalizeBuildVector(MachineInstr &MI,
700 LegalizerHelper &Helper) const {
701 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
702 const auto &BuildVector = cast<GBuildVector>(MI);
703 Register Dst = BuildVector.getReg(0);
704 LLT DstTy = MRI.getType(Dst);
705 MachineFunction &MF = MIRBuilder.getMF();
706 LLVMContext &Ctx = MF.getFunction().getContext();
707 uint64_t DstTySize = DstTy.getScalarSizeInBits();
708
709 SmallVector<Constant *, 4> CstIdxs;
710 for (unsigned i = 0; i < BuildVector.getNumSources(); ++i) {
711 Register Source = BuildVector.getSourceReg(i);
712
713 auto ValueAndReg = getIConstantVRegValWithLookThrough(Source, MRI);
714 if (ValueAndReg) {
715 CstIdxs.emplace_back(ConstantInt::get(Ctx, ValueAndReg->Value));
716 continue;
717 }
718
719 auto FPValueAndReg = getFConstantVRegValWithLookThrough(Source, MRI);
720 if (FPValueAndReg) {
721 CstIdxs.emplace_back(ConstantFP::get(Ctx, FPValueAndReg->Value));
722 continue;
723 }
724
725 if (getOpcodeDef<GImplicitDef>(Source, MRI)) {
726 CstIdxs.emplace_back(UndefValue::get(Type::getIntNTy(Ctx, DstTySize)));
727 continue;
728 }
729 return false;
730 }
731
732 Constant *ConstVal = ConstantVector::get(CstIdxs);
733
734 const DataLayout &DL = MIRBuilder.getDataLayout();
735 unsigned AddrSpace = DL.getDefaultGlobalsAddressSpace();
736 Align Alignment(DL.getABITypeAlign(ConstVal->getType()));
737 auto Addr = MIRBuilder.buildConstantPool(
738 LLT::pointer(AddrSpace, DL.getPointerSizeInBits(AddrSpace)),
739 MF.getConstantPool()->getConstantPoolIndex(ConstVal, Alignment));
740 MachineMemOperand *MMO =
742 MachineMemOperand::MOLoad, DstTy, Alignment);
743
744 MIRBuilder.buildLoad(Dst, Addr, *MMO);
745 MI.eraseFromParent();
746 return true;
747}
748
749bool X86LegalizerInfo::legalizeFPTOUI(MachineInstr &MI,
751 LegalizerHelper &Helper) const {
752 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
753 auto [Dst, DstTy, Src, SrcTy] = MI.getFirst2RegLLTs();
754 unsigned DstSizeInBits = DstTy.getScalarSizeInBits();
755 const LLT s32 = LLT::scalar(32);
756 const LLT s64 = LLT::scalar(64);
757
758 // Simply reuse FPTOSI when it is possible to widen the type
759 if (DstSizeInBits <= 32) {
760 auto Casted = MIRBuilder.buildFPTOSI(DstTy == s32 ? s64 : s32, Src);
761 MIRBuilder.buildTrunc(Dst, Casted);
762 MI.eraseFromParent();
763 return true;
764 }
765
766 return false;
767}
768
769bool X86LegalizerInfo::legalizeUITOFP(MachineInstr &MI,
771 LegalizerHelper &Helper) const {
772 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
773 auto [Dst, DstTy, Src, SrcTy] = MI.getFirst2RegLLTs();
774 const LLT s32 = LLT::scalar(32);
775 const LLT s64 = LLT::scalar(64);
776
777 // Simply reuse SITOFP when it is possible to widen the type
778 if (SrcTy.getSizeInBits() <= 32) {
779 auto Ext = MIRBuilder.buildZExt(SrcTy == s32 ? s64 : s32, Src);
780 MIRBuilder.buildSITOFP(Dst, Ext);
781 MI.eraseFromParent();
782 return true;
783 }
784
785 return false;
786}
787
788bool X86LegalizerInfo::legalizeNarrowingStore(MachineInstr &MI,
790 LegalizerHelper &Helper) const {
791 auto &Store = cast<GStore>(MI);
792 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
793 MachineMemOperand &MMO = **Store.memoperands_begin();
794 MachineFunction &MF = MIRBuilder.getMF();
795 LLT ValTy = MRI.getType(Store.getValueReg());
796 auto *NewMMO = MF.getMachineMemOperand(&MMO, MMO.getPointerInfo(), ValTy);
797
798 Helper.Observer.changingInstr(Store);
799 Store.setMemRefs(MF, {NewMMO});
800 Helper.Observer.changedInstr(Store);
801 return true;
802}
803
804bool X86LegalizerInfo::legalizeGETROUNDING(MachineInstr &MI,
806 LegalizerHelper &Helper) const {
807 /*
808 The rounding mode is in bits 11:10 of FPSR, and has the following
809 settings:
810 00 Round to nearest
811 01 Round to -inf
812 10 Round to +inf
813 11 Round to 0
814
815 GET_ROUNDING, on the other hand, expects the following:
816 -1 Undefined
817 0 Round to 0
818 1 Round to nearest
819 2 Round to +inf
820 3 Round to -inf
821
822 To perform the conversion, we use a packed lookup table of the four 2-bit
823 values that we can index by FPSP[11:10]
824 0x2d --> (0b00,10,11,01) --> (0,2,3,1) >> FPSR[11:10]
825
826 (0x2d >> ((FPSR >> 9) & 6)) & 3
827 */
828
829 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
830 MachineFunction &MF = MIRBuilder.getMF();
831 Register Dst = MI.getOperand(0).getReg();
832 LLT DstTy = MRI.getType(Dst);
833 const LLT s8 = LLT::scalar(8);
834 const LLT s16 = LLT::scalar(16);
835 const LLT s32 = LLT::scalar(32);
836
837 // Save FP Control Word to stack slot
838 int MemSize = 2;
839 Align Alignment = Align(2);
840 MachinePointerInfo PtrInfo;
841 auto StackTemp = Helper.createStackTemporary(TypeSize::getFixed(MemSize),
842 Alignment, PtrInfo);
843 Register StackPtr = StackTemp.getReg(0);
844
845 auto StoreMMO = MF.getMachineMemOperand(PtrInfo, MachineMemOperand::MOStore,
846 MemSize, Alignment);
847
848 // Store FP Control Word to stack slot using G_FNSTCW16
849 MIRBuilder.buildInstr(X86::G_FNSTCW16)
850 .addUse(StackPtr)
851 .addMemOperand(StoreMMO);
852
853 // Load FP Control Word from stack slot
854 auto LoadMMO = MF.getMachineMemOperand(PtrInfo, MachineMemOperand::MOLoad,
855 MemSize, Alignment);
856
857 auto CWD32 =
858 MIRBuilder.buildZExt(s32, MIRBuilder.buildLoad(s16, StackPtr, *LoadMMO));
859 auto Shifted8 = MIRBuilder.buildTrunc(
860 s8, MIRBuilder.buildLShr(s32, CWD32, MIRBuilder.buildConstant(s8, 9)));
861 auto Masked32 = MIRBuilder.buildZExt(
862 s32, MIRBuilder.buildAnd(s8, Shifted8, MIRBuilder.buildConstant(s8, 6)));
863
864 // LUT is a packed lookup table (0x2d) used to map the 2-bit x87 FPU rounding
865 // mode (from bits 11:10 of the control word) to the values expected by
866 // GET_ROUNDING. The mapping is performed by shifting LUT right by the
867 // extracted rounding mode and masking the result with 3 to obtain the final
868 auto LUT = MIRBuilder.buildConstant(s32, 0x2d);
869 auto LUTShifted = MIRBuilder.buildLShr(s32, LUT, Masked32);
870 auto RetVal =
871 MIRBuilder.buildAnd(s32, LUTShifted, MIRBuilder.buildConstant(s32, 3));
872 auto RetValTrunc = MIRBuilder.buildZExtOrTrunc(DstTy, RetVal);
873
874 MIRBuilder.buildCopy(Dst, RetValTrunc);
875
876 MI.eraseFromParent();
877 return true;
878}
879
880bool X86LegalizerInfo::legalizeSETROUNDING(MachineInstr &MI,
882 LegalizerHelper &Helper) const {
883 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
884 MachineFunction &MF = MIRBuilder.getMF();
885 Register Src = MI.getOperand(0).getReg();
886 const LLT s8 = LLT::scalar(8);
887 const LLT s16 = LLT::scalar(16);
888 const LLT s32 = LLT::scalar(32);
889
890 // Allocate stack slot for control word and MXCSR (4 bytes).
891 int MemSize = 4;
892 Align Alignment = Align(4);
893 MachinePointerInfo PtrInfo;
894 auto StackTemp = Helper.createStackTemporary(TypeSize::getFixed(MemSize),
895 Alignment, PtrInfo);
896 Register StackPtr = StackTemp.getReg(0);
897
898 auto StoreMMO =
900 MIRBuilder.buildInstr(X86::G_FNSTCW16)
901 .addUse(StackPtr)
902 .addMemOperand(StoreMMO);
903
904 auto LoadMMO =
906 auto CWD16 = MIRBuilder.buildLoad(s16, StackPtr, *LoadMMO);
907
908 // Clear RM field (bits 11:10)
909 auto ClearedCWD =
910 MIRBuilder.buildAnd(s16, CWD16, MIRBuilder.buildConstant(s16, 0xf3ff));
911
912 // Check if Src is a constant
913 auto *SrcDef = MRI.getVRegDef(Src);
914 Register RMBits;
915 Register MXCSRRMBits;
916
917 if (SrcDef && SrcDef->getOpcode() == TargetOpcode::G_CONSTANT) {
918 uint64_t RM = getIConstantFromReg(Src, MRI).getZExtValue();
919 int FieldVal = X86::getRoundingModeX86(RM);
920
921 if (FieldVal == X86::rmInvalid) {
922 FieldVal = X86::rmToNearest;
923 LLVMContext &C = MF.getFunction().getContext();
924 C.diagnose(DiagnosticInfoUnsupported(
925 MF.getFunction(), "rounding mode is not supported by X86 hardware",
926 DiagnosticLocation(MI.getDebugLoc()), DS_Error));
927 return false;
928 }
929
930 FieldVal = FieldVal << 3;
931 RMBits = MIRBuilder.buildConstant(s16, FieldVal).getReg(0);
932 MXCSRRMBits = MIRBuilder.buildConstant(s32, FieldVal).getReg(0);
933 } else {
934 // Convert Src (rounding mode) to bits for control word
935 // (0xc9 << (2 * Src + 4)) & 0xc00
936 auto Src32 = MIRBuilder.buildZExtOrTrunc(s32, Src);
937 auto ShiftAmt = MIRBuilder.buildAdd(
938 s32, MIRBuilder.buildShl(s32, Src32, MIRBuilder.buildConstant(s32, 1)),
939 MIRBuilder.buildConstant(s32, 4));
940 auto ShiftAmt8 = MIRBuilder.buildTrunc(s8, ShiftAmt);
941 auto Shifted = MIRBuilder.buildShl(s16, MIRBuilder.buildConstant(s16, 0xc9),
942 ShiftAmt8);
943 RMBits =
944 MIRBuilder.buildAnd(s16, Shifted, MIRBuilder.buildConstant(s16, 0xc00))
945 .getReg(0);
946
947 // For non-constant case, we still need to compute MXCSR bits dynamically
948 auto RMBits32 = MIRBuilder.buildZExt(s32, RMBits);
949 MXCSRRMBits =
950 MIRBuilder.buildShl(s32, RMBits32, MIRBuilder.buildConstant(s32, 3))
951 .getReg(0);
952 }
953 // Update rounding mode bits
954 auto NewCWD =
955 MIRBuilder.buildOr(s16, ClearedCWD, RMBits, MachineInstr::Disjoint);
956
957 // Store new FP Control Word to stack
958 auto StoreNewMMO =
960 MIRBuilder.buildStore(NewCWD, StackPtr, *StoreNewMMO);
961
962 // Load FP control word from the slot using G_FLDCW16
963 auto LoadNewMMO =
965 MIRBuilder.buildInstr(X86::G_FLDCW16)
966 .addUse(StackPtr)
967 .addMemOperand(LoadNewMMO);
968
969 if (Subtarget.hasSSE1()) {
970 // Store MXCSR to stack (use STMXCSR)
971 auto StoreMXCSRMMO = MF.getMachineMemOperand(
972 PtrInfo, MachineMemOperand::MOStore, 4, Align(4));
973 MIRBuilder.buildInstr(TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS)
974 .addIntrinsicID(Intrinsic::x86_sse_stmxcsr)
975 .addUse(StackPtr)
976 .addMemOperand(StoreMXCSRMMO);
977
978 // Load MXCSR from stack
979 auto LoadMXCSRMMO = MF.getMachineMemOperand(
980 PtrInfo, MachineMemOperand::MOLoad, 4, Align(4));
981 auto MXCSR = MIRBuilder.buildLoad(s32, StackPtr, *LoadMXCSRMMO);
982
983 // Clear RM field (bits 14:13)
984 auto ClearedMXCSR = MIRBuilder.buildAnd(
985 s32, MXCSR, MIRBuilder.buildConstant(s32, 0xffff9fff));
986
987 // Update rounding mode bits
988 auto NewMXCSR = MIRBuilder.buildOr(s32, ClearedMXCSR, MXCSRRMBits);
989
990 // Store new MXCSR to stack
991 auto StoreNewMXCSRMMO = MF.getMachineMemOperand(
992 PtrInfo, MachineMemOperand::MOStore, 4, Align(4));
993 MIRBuilder.buildStore(NewMXCSR, StackPtr, *StoreNewMXCSRMMO);
994
995 // Load MXCSR from stack (use LDMXCSR)
996 auto LoadNewMXCSRMMO = MF.getMachineMemOperand(
997 PtrInfo, MachineMemOperand::MOLoad, 4, Align(4));
998 MIRBuilder.buildInstr(TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS)
999 .addIntrinsicID(Intrinsic::x86_sse_ldmxcsr)
1000 .addUse(StackPtr)
1001 .addMemOperand(LoadNewMXCSRMMO);
1002 }
1003
1004 MI.eraseFromParent();
1005 return true;
1006}
1007
1009 MachineInstr &MI) const {
1010 return true;
1011}
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:1549
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 & 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 & 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)
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:654
LLVM_ABI const APInt & getIConstantFromReg(Register VReg, const MachineRegisterInfo &MRI)
VReg is defined by a G_CONSTANT, return the corresponding value.
Definition Utils.cpp:306
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:448
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:434
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.