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})
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 getActionDefinitionsBuilder({G_INTRINSIC_ROUNDEVEN, G_INTRINSIC_TRUNC})
602 .scalarize(0)
603 .minScalar(0, LLT::scalar(32))
604 .libcall();
605
607 verify(*STI.getInstrInfo());
608}
609
611 LostDebugLocObserver &LocObserver) const {
612 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
613 MachineRegisterInfo &MRI = *MIRBuilder.getMRI();
614 switch (MI.getOpcode()) {
615 default:
616 // No idea what to do.
617 return false;
618 case TargetOpcode::G_BUILD_VECTOR:
619 return legalizeBuildVector(MI, MRI, Helper);
620 case TargetOpcode::G_FPTOUI:
621 return legalizeFPTOUI(MI, MRI, Helper);
622 case TargetOpcode::G_UITOFP:
623 return legalizeUITOFP(MI, MRI, Helper);
624 case TargetOpcode::G_STORE:
625 return legalizeNarrowingStore(MI, MRI, Helper);
626 case TargetOpcode::G_SITOFP:
627 return legalizeSITOFP(MI, MRI, Helper);
628 case TargetOpcode::G_FPTOSI:
629 return legalizeFPTOSI(MI, MRI, Helper);
630 case TargetOpcode::G_GET_ROUNDING:
631 return legalizeGETROUNDING(MI, MRI, Helper);
632 case TargetOpcode::G_SET_ROUNDING:
633 return legalizeSETROUNDING(MI, MRI, Helper);
634 }
635 llvm_unreachable("expected switch to return");
636}
637
638bool X86LegalizerInfo::legalizeSITOFP(MachineInstr &MI,
640 LegalizerHelper &Helper) const {
641 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
642 MachineFunction &MF = *MI.getMF();
643 auto [Dst, DstTy, Src, SrcTy] = MI.getFirst2RegLLTs();
644
645 assert((SrcTy.getSizeInBits() == 16 || SrcTy.getSizeInBits() == 32 ||
646 SrcTy.getSizeInBits() == 64) &&
647 "Unexpected source type for SITOFP in X87 mode.");
648
649 TypeSize MemSize = SrcTy.getSizeInBytes();
650 MachinePointerInfo PtrInfo;
651 Align Alignmt = Helper.getStackTemporaryAlignment(SrcTy);
652 auto SlotPointer = Helper.createStackTemporary(MemSize, Alignmt, PtrInfo);
654 PtrInfo, MachineMemOperand::MOStore, MemSize, Align(MemSize));
655
656 // Store the integer value on the FPU stack.
657 MIRBuilder.buildStore(Src, SlotPointer, *StoreMMO);
658
660 PtrInfo, MachineMemOperand::MOLoad, MemSize, Align(MemSize));
661 MIRBuilder.buildInstr(X86::G_FILD)
662 .addDef(Dst)
663 .addUse(SlotPointer.getReg(0))
664 .addMemOperand(LoadMMO);
665
666 MI.eraseFromParent();
667 return true;
668}
669
670bool X86LegalizerInfo::legalizeFPTOSI(MachineInstr &MI,
672 LegalizerHelper &Helper) const {
673 MachineFunction &MF = *MI.getMF();
674 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
675 auto [Dst, DstTy, Src, SrcTy] = MI.getFirst2RegLLTs();
676
677 TypeSize MemSize = DstTy.getSizeInBytes();
678 MachinePointerInfo PtrInfo;
679 Align Alignmt = Helper.getStackTemporaryAlignment(DstTy);
680 auto SlotPointer = Helper.createStackTemporary(MemSize, Alignmt, PtrInfo);
682 PtrInfo, MachineMemOperand::MOStore, MemSize, Align(MemSize));
683
684 MIRBuilder.buildInstr(X86::G_FIST)
685 .addUse(Src)
686 .addUse(SlotPointer.getReg(0))
687 .addMemOperand(StoreMMO);
688
689 MIRBuilder.buildLoad(Dst, SlotPointer, PtrInfo, Align(MemSize));
690 MI.eraseFromParent();
691 return true;
692}
693
694bool X86LegalizerInfo::legalizeBuildVector(MachineInstr &MI,
696 LegalizerHelper &Helper) const {
697 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
698 const auto &BuildVector = cast<GBuildVector>(MI);
699 Register Dst = BuildVector.getReg(0);
700 LLT DstTy = MRI.getType(Dst);
701 MachineFunction &MF = MIRBuilder.getMF();
702 LLVMContext &Ctx = MF.getFunction().getContext();
703 uint64_t DstTySize = DstTy.getScalarSizeInBits();
704
705 SmallVector<Constant *, 4> CstIdxs;
706 for (unsigned i = 0; i < BuildVector.getNumSources(); ++i) {
707 Register Source = BuildVector.getSourceReg(i);
708
709 auto ValueAndReg = getIConstantVRegValWithLookThrough(Source, MRI);
710 if (ValueAndReg) {
711 CstIdxs.emplace_back(ConstantInt::get(Ctx, ValueAndReg->Value));
712 continue;
713 }
714
715 auto FPValueAndReg = getFConstantVRegValWithLookThrough(Source, MRI);
716 if (FPValueAndReg) {
717 CstIdxs.emplace_back(ConstantFP::get(Ctx, FPValueAndReg->Value));
718 continue;
719 }
720
721 if (getOpcodeDef<GImplicitDef>(Source, MRI)) {
722 CstIdxs.emplace_back(UndefValue::get(Type::getIntNTy(Ctx, DstTySize)));
723 continue;
724 }
725 return false;
726 }
727
728 Constant *ConstVal = ConstantVector::get(CstIdxs);
729
730 const DataLayout &DL = MIRBuilder.getDataLayout();
731 unsigned AddrSpace = DL.getDefaultGlobalsAddressSpace();
732 Align Alignment(DL.getABITypeAlign(ConstVal->getType()));
733 auto Addr = MIRBuilder.buildConstantPool(
734 LLT::pointer(AddrSpace, DL.getPointerSizeInBits(AddrSpace)),
735 MF.getConstantPool()->getConstantPoolIndex(ConstVal, Alignment));
736 MachineMemOperand *MMO =
738 MachineMemOperand::MOLoad, DstTy, Alignment);
739
740 MIRBuilder.buildLoad(Dst, Addr, *MMO);
741 MI.eraseFromParent();
742 return true;
743}
744
745bool X86LegalizerInfo::legalizeFPTOUI(MachineInstr &MI,
747 LegalizerHelper &Helper) const {
748 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
749 auto [Dst, DstTy, Src, SrcTy] = MI.getFirst2RegLLTs();
750 unsigned DstSizeInBits = DstTy.getScalarSizeInBits();
751 const LLT s32 = LLT::scalar(32);
752 const LLT s64 = LLT::scalar(64);
753
754 // Simply reuse FPTOSI when it is possible to widen the type
755 if (DstSizeInBits <= 32) {
756 auto Casted = MIRBuilder.buildFPTOSI(DstTy == s32 ? s64 : s32, Src);
757 MIRBuilder.buildTrunc(Dst, Casted);
758 MI.eraseFromParent();
759 return true;
760 }
761
762 return false;
763}
764
765bool X86LegalizerInfo::legalizeUITOFP(MachineInstr &MI,
767 LegalizerHelper &Helper) const {
768 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
769 auto [Dst, DstTy, Src, SrcTy] = MI.getFirst2RegLLTs();
770 const LLT s32 = LLT::scalar(32);
771 const LLT s64 = LLT::scalar(64);
772
773 // Simply reuse SITOFP when it is possible to widen the type
774 if (SrcTy.getSizeInBits() <= 32) {
775 auto Ext = MIRBuilder.buildZExt(SrcTy == s32 ? s64 : s32, Src);
776 MIRBuilder.buildSITOFP(Dst, Ext);
777 MI.eraseFromParent();
778 return true;
779 }
780
781 return false;
782}
783
784bool X86LegalizerInfo::legalizeNarrowingStore(MachineInstr &MI,
786 LegalizerHelper &Helper) const {
787 auto &Store = cast<GStore>(MI);
788 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
789 MachineMemOperand &MMO = **Store.memoperands_begin();
790 MachineFunction &MF = MIRBuilder.getMF();
791 LLT ValTy = MRI.getType(Store.getValueReg());
792 auto *NewMMO = MF.getMachineMemOperand(&MMO, MMO.getPointerInfo(), ValTy);
793
794 Helper.Observer.changingInstr(Store);
795 Store.setMemRefs(MF, {NewMMO});
796 Helper.Observer.changedInstr(Store);
797 return true;
798}
799
800bool X86LegalizerInfo::legalizeGETROUNDING(MachineInstr &MI,
802 LegalizerHelper &Helper) const {
803 /*
804 The rounding mode is in bits 11:10 of FPSR, and has the following
805 settings:
806 00 Round to nearest
807 01 Round to -inf
808 10 Round to +inf
809 11 Round to 0
810
811 GET_ROUNDING, on the other hand, expects the following:
812 -1 Undefined
813 0 Round to 0
814 1 Round to nearest
815 2 Round to +inf
816 3 Round to -inf
817
818 To perform the conversion, we use a packed lookup table of the four 2-bit
819 values that we can index by FPSP[11:10]
820 0x2d --> (0b00,10,11,01) --> (0,2,3,1) >> FPSR[11:10]
821
822 (0x2d >> ((FPSR >> 9) & 6)) & 3
823 */
824
825 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
826 MachineFunction &MF = MIRBuilder.getMF();
827 Register Dst = MI.getOperand(0).getReg();
828 LLT DstTy = MRI.getType(Dst);
829 const LLT s8 = LLT::scalar(8);
830 const LLT s16 = LLT::scalar(16);
831 const LLT s32 = LLT::scalar(32);
832
833 // Save FP Control Word to stack slot
834 int MemSize = 2;
835 Align Alignment = Align(2);
836 MachinePointerInfo PtrInfo;
837 auto StackTemp = Helper.createStackTemporary(TypeSize::getFixed(MemSize),
838 Alignment, PtrInfo);
839 Register StackPtr = StackTemp.getReg(0);
840
841 auto StoreMMO = MF.getMachineMemOperand(PtrInfo, MachineMemOperand::MOStore,
842 MemSize, Alignment);
843
844 // Store FP Control Word to stack slot using G_FNSTCW16
845 MIRBuilder.buildInstr(X86::G_FNSTCW16)
846 .addUse(StackPtr)
847 .addMemOperand(StoreMMO);
848
849 // Load FP Control Word from stack slot
850 auto LoadMMO = MF.getMachineMemOperand(PtrInfo, MachineMemOperand::MOLoad,
851 MemSize, Alignment);
852
853 auto CWD32 =
854 MIRBuilder.buildZExt(s32, MIRBuilder.buildLoad(s16, StackPtr, *LoadMMO));
855 auto Shifted8 = MIRBuilder.buildTrunc(
856 s8, MIRBuilder.buildLShr(s32, CWD32, MIRBuilder.buildConstant(s8, 9)));
857 auto Masked32 = MIRBuilder.buildZExt(
858 s32, MIRBuilder.buildAnd(s8, Shifted8, MIRBuilder.buildConstant(s8, 6)));
859
860 // LUT is a packed lookup table (0x2d) used to map the 2-bit x87 FPU rounding
861 // mode (from bits 11:10 of the control word) to the values expected by
862 // GET_ROUNDING. The mapping is performed by shifting LUT right by the
863 // extracted rounding mode and masking the result with 3 to obtain the final
864 auto LUT = MIRBuilder.buildConstant(s32, 0x2d);
865 auto LUTShifted = MIRBuilder.buildLShr(s32, LUT, Masked32);
866 auto RetVal =
867 MIRBuilder.buildAnd(s32, LUTShifted, MIRBuilder.buildConstant(s32, 3));
868 auto RetValTrunc = MIRBuilder.buildZExtOrTrunc(DstTy, RetVal);
869
870 MIRBuilder.buildCopy(Dst, RetValTrunc);
871
872 MI.eraseFromParent();
873 return true;
874}
875
876bool X86LegalizerInfo::legalizeSETROUNDING(MachineInstr &MI,
878 LegalizerHelper &Helper) const {
879 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
880 MachineFunction &MF = MIRBuilder.getMF();
881 Register Src = MI.getOperand(0).getReg();
882 const LLT s8 = LLT::scalar(8);
883 const LLT s16 = LLT::scalar(16);
884 const LLT s32 = LLT::scalar(32);
885
886 // Allocate stack slot for control word and MXCSR (4 bytes).
887 int MemSize = 4;
888 Align Alignment = Align(4);
889 MachinePointerInfo PtrInfo;
890 auto StackTemp = Helper.createStackTemporary(TypeSize::getFixed(MemSize),
891 Alignment, PtrInfo);
892 Register StackPtr = StackTemp.getReg(0);
893
894 auto StoreMMO =
896 MIRBuilder.buildInstr(X86::G_FNSTCW16)
897 .addUse(StackPtr)
898 .addMemOperand(StoreMMO);
899
900 auto LoadMMO =
902 auto CWD16 = MIRBuilder.buildLoad(s16, StackPtr, *LoadMMO);
903
904 // Clear RM field (bits 11:10)
905 auto ClearedCWD =
906 MIRBuilder.buildAnd(s16, CWD16, MIRBuilder.buildConstant(s16, 0xf3ff));
907
908 // Check if Src is a constant
909 auto *SrcDef = MRI.getVRegDef(Src);
910 Register RMBits;
911 Register MXCSRRMBits;
912
913 if (SrcDef && SrcDef->getOpcode() == TargetOpcode::G_CONSTANT) {
914 uint64_t RM = getIConstantFromReg(Src, MRI).getZExtValue();
915 int FieldVal = X86::getRoundingModeX86(RM);
916
917 if (FieldVal == X86::rmInvalid) {
918 FieldVal = X86::rmToNearest;
919 LLVMContext &C = MF.getFunction().getContext();
920 C.diagnose(DiagnosticInfoUnsupported(
921 MF.getFunction(), "rounding mode is not supported by X86 hardware",
922 DiagnosticLocation(MI.getDebugLoc()), DS_Error));
923 return false;
924 }
925
926 FieldVal = FieldVal << 3;
927 RMBits = MIRBuilder.buildConstant(s16, FieldVal).getReg(0);
928 MXCSRRMBits = MIRBuilder.buildConstant(s32, FieldVal).getReg(0);
929 } else {
930 // Convert Src (rounding mode) to bits for control word
931 // (0xc9 << (2 * Src + 4)) & 0xc00
932 auto Src32 = MIRBuilder.buildZExtOrTrunc(s32, Src);
933 auto ShiftAmt = MIRBuilder.buildAdd(
934 s32, MIRBuilder.buildShl(s32, Src32, MIRBuilder.buildConstant(s32, 1)),
935 MIRBuilder.buildConstant(s32, 4));
936 auto ShiftAmt8 = MIRBuilder.buildTrunc(s8, ShiftAmt);
937 auto Shifted = MIRBuilder.buildShl(s16, MIRBuilder.buildConstant(s16, 0xc9),
938 ShiftAmt8);
939 RMBits =
940 MIRBuilder.buildAnd(s16, Shifted, MIRBuilder.buildConstant(s16, 0xc00))
941 .getReg(0);
942
943 // For non-constant case, we still need to compute MXCSR bits dynamically
944 auto RMBits32 = MIRBuilder.buildZExt(s32, RMBits);
945 MXCSRRMBits =
946 MIRBuilder.buildShl(s32, RMBits32, MIRBuilder.buildConstant(s32, 3))
947 .getReg(0);
948 }
949 // Update rounding mode bits
950 auto NewCWD =
951 MIRBuilder.buildOr(s16, ClearedCWD, RMBits, MachineInstr::Disjoint);
952
953 // Store new FP Control Word to stack
954 auto StoreNewMMO =
956 MIRBuilder.buildStore(NewCWD, StackPtr, *StoreNewMMO);
957
958 // Load FP control word from the slot using G_FLDCW16
959 auto LoadNewMMO =
961 MIRBuilder.buildInstr(X86::G_FLDCW16)
962 .addUse(StackPtr)
963 .addMemOperand(LoadNewMMO);
964
965 if (Subtarget.hasSSE1()) {
966 // Store MXCSR to stack (use STMXCSR)
967 auto StoreMXCSRMMO = MF.getMachineMemOperand(
968 PtrInfo, MachineMemOperand::MOStore, 4, Align(4));
969 MIRBuilder.buildInstr(TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS)
970 .addIntrinsicID(Intrinsic::x86_sse_stmxcsr)
971 .addUse(StackPtr)
972 .addMemOperand(StoreMXCSRMMO);
973
974 // Load MXCSR from stack
975 auto LoadMXCSRMMO = MF.getMachineMemOperand(
976 PtrInfo, MachineMemOperand::MOLoad, 4, Align(4));
977 auto MXCSR = MIRBuilder.buildLoad(s32, StackPtr, *LoadMXCSRMMO);
978
979 // Clear RM field (bits 14:13)
980 auto ClearedMXCSR = MIRBuilder.buildAnd(
981 s32, MXCSR, MIRBuilder.buildConstant(s32, 0xffff9fff));
982
983 // Update rounding mode bits
984 auto NewMXCSR = MIRBuilder.buildOr(s32, ClearedMXCSR, MXCSRRMBits);
985
986 // Store new MXCSR to stack
987 auto StoreNewMXCSRMMO = MF.getMachineMemOperand(
988 PtrInfo, MachineMemOperand::MOStore, 4, Align(4));
989 MIRBuilder.buildStore(NewMXCSR, StackPtr, *StoreNewMXCSRMMO);
990
991 // Load MXCSR from stack (use LDMXCSR)
992 auto LoadNewMXCSRMMO = MF.getMachineMemOperand(
993 PtrInfo, MachineMemOperand::MOLoad, 4, Align(4));
994 MIRBuilder.buildInstr(TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS)
995 .addIntrinsicID(Intrinsic::x86_sse_ldmxcsr)
996 .addUse(StackPtr)
997 .addMemOperand(LoadNewMXCSRMMO);
998 }
999
1000 MI.eraseFromParent();
1001 return true;
1002}
1003
1005 MachineInstr &MI) const {
1006 return true;
1007}
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:1541
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)
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.