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