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 .widenScalarToNextPow2(1, /*Min=*/8)
273 .clampScalar(1, s8, sMaxScalar);
274
275 // bswap
277 .legalFor({s32})
278 .legalFor(Is64Bit, {s64})
279 .widenScalarToNextPow2(0, /*Min=*/32)
280 .clampScalar(0, s32, sMaxScalar);
281
282 // popcount
284 .legalFor(HasPOPCNT, {{s16, s16}, {s32, s32}})
285 .legalFor(HasPOPCNT && Is64Bit, {{s64, s64}})
286 .widenScalarToNextPow2(1, /*Min=*/16)
287 .clampScalar(1, s16, sMaxScalar)
288 .scalarSameSizeAs(0, 1);
289
290 // count leading zeros (LZCNT)
292 .legalFor(HasLZCNT, {{s16, s16}, {s32, s32}})
293 .legalFor(HasLZCNT && Is64Bit, {{s64, s64}})
294 .widenScalarToNextPow2(1, /*Min=*/16)
295 .clampScalar(1, s16, sMaxScalar)
296 .scalarSameSizeAs(0, 1);
297
298 // count trailing zeros
299 getActionDefinitionsBuilder(G_CTTZ_ZERO_UNDEF)
300 .legalFor({{s16, s16}, {s32, s32}})
301 .legalFor(Is64Bit, {{s64, s64}})
302 .widenScalarToNextPow2(1, /*Min=*/16)
303 .clampScalar(1, s16, sMaxScalar)
304 .scalarSameSizeAs(0, 1);
305
307 .legalFor(HasBMI, {{s16, s16}, {s32, s32}})
308 .legalFor(HasBMI && Is64Bit, {{s64, s64}})
309 .widenScalarToNextPow2(1, /*Min=*/16)
310 .clampScalar(1, s16, sMaxScalar)
311 .scalarSameSizeAs(0, 1);
312
314
315 // pointer handling
316 const std::initializer_list<LLT> PtrTypes32 = {s1, s8, s16, s32};
317 const std::initializer_list<LLT> PtrTypes64 = {s1, s8, s16, s32, s64};
318
320 .legalForCartesianProduct(Is64Bit ? PtrTypes64 : PtrTypes32, {p0})
321 .maxScalar(0, sMaxScalar)
322 .widenScalarToNextPow2(0, /*Min*/ 8);
323
324 getActionDefinitionsBuilder(G_INTTOPTR).legalFor({{p0, sMaxScalar}});
325
326 getActionDefinitionsBuilder(G_CONSTANT_POOL).legalFor({p0});
327
329 .legalFor({{p0, s32}})
330 .legalFor(Is64Bit, {{p0, s64}})
331 .widenScalarToNextPow2(1, /*Min*/ 32)
332 .clampScalar(1, s32, sMaxScalar);
333
334 getActionDefinitionsBuilder({G_FRAME_INDEX, G_GLOBAL_VALUE}).legalFor({p0});
335
336 // load/store: add more corner cases
337 for (unsigned Op : {G_LOAD, G_STORE}) {
338 auto &Action = getActionDefinitionsBuilder(Op);
339 Action.legalForTypesWithMemDesc({{s8, p0, s8, 1},
340 {s16, p0, s16, 1},
341 {s32, p0, s32, 1},
342 {s80, p0, s80, 1},
343 {p0, p0, p0, 1},
344 {v4s8, p0, v4s8, 1}});
345 if (Is64Bit)
346 Action.legalForTypesWithMemDesc(
347 {{s64, p0, s64, 1}, {v2s32, p0, v2s32, 1}});
348
349 if (HasSSE1)
350 Action.legalForTypesWithMemDesc({{v4s32, p0, v4s32, 1}});
351 if (HasSSE2)
352 Action.legalForTypesWithMemDesc({{v16s8, p0, v16s8, 1},
353 {v8s16, p0, v8s16, 1},
354 {v2s64, p0, v2s64, 1},
355 {v2p0, p0, v2p0, 1}});
356 if (HasAVX)
357 Action.legalForTypesWithMemDesc({{v32s8, p0, v32s8, 1},
358 {v16s16, p0, v16s16, 1},
359 {v8s32, p0, v8s32, 1},
360 {v4s64, p0, v4s64, 1},
361 {v4p0, p0, v4p0, 1}});
362 if (HasAVX512)
363 Action.legalForTypesWithMemDesc({{v64s8, p0, v64s8, 1},
364 {v32s16, p0, v32s16, 1},
365 {v16s32, p0, v16s32, 1},
366 {v8s64, p0, v8s64, 1}});
367
368 // X86 supports extending loads but not stores for GPRs
369 if (Op == G_LOAD) {
370 Action.legalForTypesWithMemDesc({{s8, p0, s1, 1},
371 {s16, p0, s8, 1},
372 {s32, p0, s8, 1},
373 {s32, p0, s16, 1}});
374 if (Is64Bit)
375 Action.legalForTypesWithMemDesc(
376 {{s64, p0, s8, 1}, {s64, p0, s16, 1}, {s64, p0, s32, 1}});
377 } else {
378 Action.customIf([=](const LegalityQuery &Query) {
379 return Query.Types[0] != Query.MMODescrs[0].MemoryTy;
380 });
381 }
382 Action.widenScalarToNextPow2(0, /*Min=*/8)
383 .clampScalar(0, s8, sMaxScalar)
384 .scalarize(0);
385 }
386
387 for (unsigned Op : {G_SEXTLOAD, G_ZEXTLOAD}) {
388 auto &Action = getActionDefinitionsBuilder(Op);
389 Action.legalForTypesWithMemDesc(
390 {{s16, p0, s8, 1}, {s32, p0, s8, 1}, {s32, p0, s16, 1}});
391 if (Is64Bit)
392 Action.legalForTypesWithMemDesc(
393 {{s64, p0, s8, 1}, {s64, p0, s16, 1}, {s64, p0, s32, 1}});
394 // TODO - SSE41/AVX2/AVX512F/AVX512BW vector extensions
395 }
396
397 // sext, zext, and anyext
399 .legalFor({s8, s16, s32, s128})
400 .legalFor(Is64Bit, {s64})
401 .widenScalarToNextPow2(0, /*Min=*/8)
402 .clampScalar(0, s8, sMaxScalar)
403 .widenScalarToNextPow2(1, /*Min=*/8)
404 .clampScalar(1, s8, sMaxScalar)
405 .scalarize(0);
406
407 getActionDefinitionsBuilder({G_SEXT, G_ZEXT})
408 .legalFor({s8, s16, s32})
409 .legalFor(Is64Bit, {s64})
410 .widenScalarToNextPow2(0, /*Min=*/8)
411 .clampScalar(0, s8, sMaxScalar)
412 .widenScalarToNextPow2(1, /*Min=*/8)
413 .clampScalar(1, s8, sMaxScalar)
414 .scalarize(0);
415
416 getActionDefinitionsBuilder(G_SEXT_INREG).lower();
417
418 // fp constants
419 getActionDefinitionsBuilder(G_FCONSTANT)
420 .legalFor({s32, s64})
421 .legalFor(UseX87, {s80});
422
423 // fp arithmetic
424 getActionDefinitionsBuilder({G_FADD, G_FSUB, G_FMUL, G_FDIV})
425 .legalFor({s32, s64})
426 .legalFor(HasSSE1, {v4s32})
427 .legalFor(HasSSE2, {v2s64})
428 .legalFor(HasAVX, {v8s32, v4s64})
429 .legalFor(HasAVX512, {v16s32, v8s64})
430 .legalFor(UseX87, {s80});
431
433 .legalFor(UseX87, {s80})
434 .legalFor(UseX87 && !Is64Bit, {s64})
435 .lower();
436
437 // fp comparison
439 .legalFor(HasSSE1 || UseX87, {s8, s32})
440 .legalFor(HasSSE2 || UseX87, {s8, s64})
441 .legalFor(UseX87, {s8, s80})
442 .clampScalar(0, s8, s8)
443 .clampScalar(1, s32, HasSSE2 ? s64 : s32)
445
446 // fp conversions
448 .legalFor(HasSSE2, {{s64, s32}})
449 .legalFor(HasAVX, {{v4s64, v4s32}})
450 .legalFor(HasAVX512, {{v8s64, v8s32}});
451
453 .legalFor(HasSSE2, {{s32, s64}})
454 .legalFor(HasAVX, {{v4s32, v4s64}})
455 .legalFor(HasAVX512, {{v8s32, v8s64}});
456
458 .legalFor(HasSSE1, {{s32, s32}})
459 .legalFor(HasSSE1 && Is64Bit, {{s32, s64}})
460 .legalFor(HasSSE2, {{s64, s32}})
461 .legalFor(HasSSE2 && Is64Bit, {{s64, s64}})
462 .clampScalar(1, (UseX87 && !HasSSE1) ? s16 : s32, sMaxScalar)
464 .customForCartesianProduct(UseX87, {s32, s64, s80}, {s16, s32, s64})
465 .clampScalar(0, s32, HasSSE2 ? s64 : s32)
467
469 .legalFor(HasSSE1, {{s32, s32}})
470 .legalFor(HasSSE1 && Is64Bit, {{s64, s32}})
471 .legalFor(HasSSE2, {{s32, s64}})
472 .legalFor(HasSSE2 && Is64Bit, {{s64, s64}})
473 .clampScalar(0, (UseX87 && !HasSSE1) ? s16 : s32, sMaxScalar)
475 .customForCartesianProduct(UseX87, {s16, s32, s64}, {s32, s64, s80})
476 .clampScalar(1, s32, HasSSE2 ? s64 : s32)
478
479 // For G_UITOFP and G_FPTOUI without AVX512, we have to custom legalize types
480 // <= s32 manually. Otherwise, in custom handler there is no way to
481 // understand whether s32 is an original type and we need to promote it to
482 // s64 or s32 is obtained after widening and we shouldn't widen it to s64.
483 //
484 // For AVX512 we simply widen types as there is direct mapping from opcodes
485 // to asm instructions.
487 .legalFor(HasAVX512, {{s32, s32}, {s32, s64}, {s64, s32}, {s64, s64}})
488 .customIf([=](const LegalityQuery &Query) {
489 return !HasAVX512 &&
490 ((HasSSE1 && typeIs(0, s32)(Query)) ||
491 (HasSSE2 && typeIs(0, s64)(Query))) &&
492 scalarNarrowerThan(1, Is64Bit ? 64 : 32)(Query);
493 })
494 .lowerIf([=](const LegalityQuery &Query) {
495 // Lower conversions from s64
496 return !HasAVX512 &&
497 ((HasSSE1 && typeIs(0, s32)(Query)) ||
498 (HasSSE2 && typeIs(0, s64)(Query))) &&
499 (Is64Bit && typeIs(1, s64)(Query));
500 })
501 .clampScalar(0, s32, HasSSE2 ? s64 : s32)
503 .clampScalar(1, s32, sMaxScalar)
505
507 .legalFor(HasAVX512, {{s32, s32}, {s32, s64}, {s64, s32}, {s64, s64}})
508 .customIf([=](const LegalityQuery &Query) {
509 return !HasAVX512 &&
510 ((HasSSE1 && typeIs(1, s32)(Query)) ||
511 (HasSSE2 && typeIs(1, s64)(Query))) &&
512 scalarNarrowerThan(0, Is64Bit ? 64 : 32)(Query);
513 })
514 // TODO: replace with customized legalization using
515 // specifics of cvttsd2si. The selection of this node requires
516 // a vector type. Either G_SCALAR_TO_VECTOR is needed or more advanced
517 // support of G_BUILD_VECTOR/G_INSERT_VECTOR_ELT is required beforehand.
518 .lowerIf([=](const LegalityQuery &Query) {
519 return !HasAVX512 &&
520 ((HasSSE1 && typeIs(1, s32)(Query)) ||
521 (HasSSE2 && typeIs(1, s64)(Query))) &&
522 (Is64Bit && typeIs(0, s64)(Query));
523 })
524 .clampScalar(0, s32, sMaxScalar)
526 .clampScalar(1, s32, HasSSE2 ? s64 : s32)
528
529 // vector ops
530 getActionDefinitionsBuilder(G_BUILD_VECTOR)
531 .customIf([=](const LegalityQuery &Query) {
532 return (HasSSE1 && typeInSet(0, {v4s32})(Query)) ||
533 (HasSSE2 && typeInSet(0, {v2s64, v8s16, v16s8})(Query)) ||
534 (HasAVX && typeInSet(0, {v4s64, v8s32, v16s16, v32s8})(Query)) ||
535 (HasAVX512 && typeInSet(0, {v8s64, v16s32, v32s16, v64s8}));
536 })
537 .clampNumElements(0, v16s8, s8MaxVector)
538 .clampNumElements(0, v8s16, s16MaxVector)
539 .clampNumElements(0, v4s32, s32MaxVector)
540 .clampNumElements(0, v2s64, s64MaxVector)
542
543 getActionDefinitionsBuilder({G_EXTRACT, G_INSERT})
544 .legalIf([=](const LegalityQuery &Query) {
545 unsigned SubIdx = Query.Opcode == G_EXTRACT ? 0 : 1;
546 unsigned FullIdx = Query.Opcode == G_EXTRACT ? 1 : 0;
547 return (HasAVX && typePairInSet(SubIdx, FullIdx,
548 {{v16s8, v32s8},
549 {v8s16, v16s16},
550 {v4s32, v8s32},
551 {v2s64, v4s64}})(Query)) ||
552 (HasAVX512 && typePairInSet(SubIdx, FullIdx,
553 {{v16s8, v64s8},
554 {v32s8, v64s8},
555 {v8s16, v32s16},
556 {v16s16, v32s16},
557 {v4s32, v16s32},
558 {v8s32, v16s32},
559 {v2s64, v8s64},
560 {v4s64, v8s64}})(Query));
561 });
562
563 // todo: only permit dst types up to max legal vector register size?
564 getActionDefinitionsBuilder(G_CONCAT_VECTORS)
565 .legalFor(
566 HasSSE1,
567 {{v32s8, v16s8}, {v16s16, v8s16}, {v8s32, v4s32}, {v4s64, v2s64}})
568 .legalFor(HasAVX, {{v64s8, v16s8},
569 {v64s8, v32s8},
570 {v32s16, v8s16},
571 {v32s16, v16s16},
572 {v16s32, v4s32},
573 {v16s32, v8s32},
574 {v8s64, v2s64},
575 {v8s64, v4s64}});
576
577 // todo: vectors and address spaces
579 .legalFor({{s16, s32}, {s32, s32}, {p0, s32}})
580 .legalFor(!HasCMOV, {{s8, s32}})
581 .legalFor(Is64Bit, {{s64, s32}})
582 .legalFor(UseX87, {{s80, s32}})
583 .clampScalar(1, s32, s32)
584 .widenScalarToNextPow2(0, /*Min=*/8)
585 .clampScalar(0, HasCMOV ? s16 : s8, sMaxScalar);
586
587 // memory intrinsics
588 getActionDefinitionsBuilder({G_MEMCPY, G_MEMMOVE, G_MEMSET}).libcall();
589
590 getActionDefinitionsBuilder({G_DYN_STACKALLOC, G_STACKSAVE, G_STACKRESTORE})
591 .lower();
592
593 // fp intrinsics
594 getActionDefinitionsBuilder({G_INTRINSIC_ROUNDEVEN, G_INTRINSIC_TRUNC})
595 .scalarize(0)
596 .minScalar(0, LLT::scalar(32))
597 .libcall();
598
600 verify(*STI.getInstrInfo());
601}
602
604 LostDebugLocObserver &LocObserver) const {
605 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
606 MachineRegisterInfo &MRI = *MIRBuilder.getMRI();
607 switch (MI.getOpcode()) {
608 default:
609 // No idea what to do.
610 return false;
611 case TargetOpcode::G_BUILD_VECTOR:
612 return legalizeBuildVector(MI, MRI, Helper);
613 case TargetOpcode::G_FPTOUI:
614 return legalizeFPTOUI(MI, MRI, Helper);
615 case TargetOpcode::G_UITOFP:
616 return legalizeUITOFP(MI, MRI, Helper);
617 case TargetOpcode::G_STORE:
618 return legalizeNarrowingStore(MI, MRI, Helper);
619 case TargetOpcode::G_SITOFP:
620 return legalizeSITOFP(MI, MRI, Helper);
621 case TargetOpcode::G_FPTOSI:
622 return legalizeFPTOSI(MI, MRI, Helper);
623 case TargetOpcode::G_GET_ROUNDING:
624 return legalizeGETROUNDING(MI, MRI, Helper);
625 case TargetOpcode::G_SET_ROUNDING:
626 return legalizeSETROUNDING(MI, MRI, Helper);
627 }
628 llvm_unreachable("expected switch to return");
629}
630
631bool X86LegalizerInfo::legalizeSITOFP(MachineInstr &MI,
633 LegalizerHelper &Helper) const {
634 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
635 MachineFunction &MF = *MI.getMF();
636 auto [Dst, DstTy, Src, SrcTy] = MI.getFirst2RegLLTs();
637
638 assert((SrcTy.getSizeInBits() == 16 || SrcTy.getSizeInBits() == 32 ||
639 SrcTy.getSizeInBits() == 64) &&
640 "Unexpected source type for SITOFP in X87 mode.");
641
642 TypeSize MemSize = SrcTy.getSizeInBytes();
643 MachinePointerInfo PtrInfo;
644 Align Alignmt = Helper.getStackTemporaryAlignment(SrcTy);
645 auto SlotPointer = Helper.createStackTemporary(MemSize, Alignmt, PtrInfo);
647 PtrInfo, MachineMemOperand::MOStore, MemSize, Align(MemSize));
648
649 // Store the integer value on the FPU stack.
650 MIRBuilder.buildStore(Src, SlotPointer, *StoreMMO);
651
653 PtrInfo, MachineMemOperand::MOLoad, MemSize, Align(MemSize));
654 MIRBuilder.buildInstr(X86::G_FILD)
655 .addDef(Dst)
656 .addUse(SlotPointer.getReg(0))
657 .addMemOperand(LoadMMO);
658
659 MI.eraseFromParent();
660 return true;
661}
662
663bool X86LegalizerInfo::legalizeFPTOSI(MachineInstr &MI,
665 LegalizerHelper &Helper) const {
666 MachineFunction &MF = *MI.getMF();
667 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
668 auto [Dst, DstTy, Src, SrcTy] = MI.getFirst2RegLLTs();
669
670 TypeSize MemSize = DstTy.getSizeInBytes();
671 MachinePointerInfo PtrInfo;
672 Align Alignmt = Helper.getStackTemporaryAlignment(DstTy);
673 auto SlotPointer = Helper.createStackTemporary(MemSize, Alignmt, PtrInfo);
675 PtrInfo, MachineMemOperand::MOStore, MemSize, Align(MemSize));
676
677 MIRBuilder.buildInstr(X86::G_FIST)
678 .addUse(Src)
679 .addUse(SlotPointer.getReg(0))
680 .addMemOperand(StoreMMO);
681
682 MIRBuilder.buildLoad(Dst, SlotPointer, PtrInfo, Align(MemSize));
683 MI.eraseFromParent();
684 return true;
685}
686
687bool X86LegalizerInfo::legalizeBuildVector(MachineInstr &MI,
689 LegalizerHelper &Helper) const {
690 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
691 const auto &BuildVector = cast<GBuildVector>(MI);
692 Register Dst = BuildVector.getReg(0);
693 LLT DstTy = MRI.getType(Dst);
694 MachineFunction &MF = MIRBuilder.getMF();
695 LLVMContext &Ctx = MF.getFunction().getContext();
696 uint64_t DstTySize = DstTy.getScalarSizeInBits();
697
699 for (unsigned i = 0; i < BuildVector.getNumSources(); ++i) {
700 Register Source = BuildVector.getSourceReg(i);
701
702 auto ValueAndReg = getIConstantVRegValWithLookThrough(Source, MRI);
703 if (ValueAndReg) {
704 CstIdxs.emplace_back(ConstantInt::get(Ctx, ValueAndReg->Value));
705 continue;
706 }
707
708 auto FPValueAndReg = getFConstantVRegValWithLookThrough(Source, MRI);
709 if (FPValueAndReg) {
710 CstIdxs.emplace_back(ConstantFP::get(Ctx, FPValueAndReg->Value));
711 continue;
712 }
713
714 if (getOpcodeDef<GImplicitDef>(Source, MRI)) {
715 CstIdxs.emplace_back(UndefValue::get(Type::getIntNTy(Ctx, DstTySize)));
716 continue;
717 }
718 return false;
719 }
720
721 Constant *ConstVal = ConstantVector::get(CstIdxs);
722
723 const DataLayout &DL = MIRBuilder.getDataLayout();
724 unsigned AddrSpace = DL.getDefaultGlobalsAddressSpace();
725 Align Alignment(DL.getABITypeAlign(ConstVal->getType()));
726 auto Addr = MIRBuilder.buildConstantPool(
727 LLT::pointer(AddrSpace, DL.getPointerSizeInBits(AddrSpace)),
728 MF.getConstantPool()->getConstantPoolIndex(ConstVal, Alignment));
729 MachineMemOperand *MMO =
731 MachineMemOperand::MOLoad, DstTy, Alignment);
732
733 MIRBuilder.buildLoad(Dst, Addr, *MMO);
734 MI.eraseFromParent();
735 return true;
736}
737
738bool X86LegalizerInfo::legalizeFPTOUI(MachineInstr &MI,
740 LegalizerHelper &Helper) const {
741 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
742 auto [Dst, DstTy, Src, SrcTy] = MI.getFirst2RegLLTs();
743 unsigned DstSizeInBits = DstTy.getScalarSizeInBits();
744 const LLT s32 = LLT::scalar(32);
745 const LLT s64 = LLT::scalar(64);
746
747 // Simply reuse FPTOSI when it is possible to widen the type
748 if (DstSizeInBits <= 32) {
749 auto Casted = MIRBuilder.buildFPTOSI(DstTy == s32 ? s64 : s32, Src);
750 MIRBuilder.buildTrunc(Dst, Casted);
751 MI.eraseFromParent();
752 return true;
753 }
754
755 return false;
756}
757
758bool X86LegalizerInfo::legalizeUITOFP(MachineInstr &MI,
760 LegalizerHelper &Helper) const {
761 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
762 auto [Dst, DstTy, Src, SrcTy] = MI.getFirst2RegLLTs();
763 const LLT s32 = LLT::scalar(32);
764 const LLT s64 = LLT::scalar(64);
765
766 // Simply reuse SITOFP when it is possible to widen the type
767 if (SrcTy.getSizeInBits() <= 32) {
768 auto Ext = MIRBuilder.buildZExt(SrcTy == s32 ? s64 : s32, Src);
769 MIRBuilder.buildSITOFP(Dst, Ext);
770 MI.eraseFromParent();
771 return true;
772 }
773
774 return false;
775}
776
777bool X86LegalizerInfo::legalizeNarrowingStore(MachineInstr &MI,
779 LegalizerHelper &Helper) const {
780 auto &Store = cast<GStore>(MI);
781 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
782 MachineMemOperand &MMO = **Store.memoperands_begin();
783 MachineFunction &MF = MIRBuilder.getMF();
784 LLT ValTy = MRI.getType(Store.getValueReg());
785 auto *NewMMO = MF.getMachineMemOperand(&MMO, MMO.getPointerInfo(), ValTy);
786
787 Helper.Observer.changingInstr(Store);
788 Store.setMemRefs(MF, {NewMMO});
789 Helper.Observer.changedInstr(Store);
790 return true;
791}
792
793bool X86LegalizerInfo::legalizeGETROUNDING(MachineInstr &MI,
795 LegalizerHelper &Helper) const {
796 /*
797 The rounding mode is in bits 11:10 of FPSR, and has the following
798 settings:
799 00 Round to nearest
800 01 Round to -inf
801 10 Round to +inf
802 11 Round to 0
803
804 GET_ROUNDING, on the other hand, expects the following:
805 -1 Undefined
806 0 Round to 0
807 1 Round to nearest
808 2 Round to +inf
809 3 Round to -inf
810
811 To perform the conversion, we use a packed lookup table of the four 2-bit
812 values that we can index by FPSP[11:10]
813 0x2d --> (0b00,10,11,01) --> (0,2,3,1) >> FPSR[11:10]
814
815 (0x2d >> ((FPSR >> 9) & 6)) & 3
816 */
817
818 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
819 MachineFunction &MF = MIRBuilder.getMF();
820 Register Dst = MI.getOperand(0).getReg();
821 LLT DstTy = MRI.getType(Dst);
822 const LLT s8 = LLT::scalar(8);
823 const LLT s16 = LLT::scalar(16);
824 const LLT s32 = LLT::scalar(32);
825
826 // Save FP Control Word to stack slot
827 int MemSize = 2;
828 Align Alignment = Align(2);
829 MachinePointerInfo PtrInfo;
830 auto StackTemp = Helper.createStackTemporary(TypeSize::getFixed(MemSize),
831 Alignment, PtrInfo);
832 Register StackPtr = StackTemp.getReg(0);
833
834 auto StoreMMO = MF.getMachineMemOperand(PtrInfo, MachineMemOperand::MOStore,
835 MemSize, Alignment);
836
837 // Store FP Control Word to stack slot using G_FNSTCW16
838 MIRBuilder.buildInstr(X86::G_FNSTCW16)
839 .addUse(StackPtr)
840 .addMemOperand(StoreMMO);
841
842 // Load FP Control Word from stack slot
843 auto LoadMMO = MF.getMachineMemOperand(PtrInfo, MachineMemOperand::MOLoad,
844 MemSize, Alignment);
845
846 auto CWD32 =
847 MIRBuilder.buildZExt(s32, MIRBuilder.buildLoad(s16, StackPtr, *LoadMMO));
848 auto Shifted8 = MIRBuilder.buildTrunc(
849 s8, MIRBuilder.buildLShr(s32, CWD32, MIRBuilder.buildConstant(s8, 9)));
850 auto Masked32 = MIRBuilder.buildZExt(
851 s32, MIRBuilder.buildAnd(s8, Shifted8, MIRBuilder.buildConstant(s8, 6)));
852
853 // LUT is a packed lookup table (0x2d) used to map the 2-bit x87 FPU rounding
854 // mode (from bits 11:10 of the control word) to the values expected by
855 // GET_ROUNDING. The mapping is performed by shifting LUT right by the
856 // extracted rounding mode and masking the result with 3 to obtain the final
857 auto LUT = MIRBuilder.buildConstant(s32, 0x2d);
858 auto LUTShifted = MIRBuilder.buildLShr(s32, LUT, Masked32);
859 auto RetVal =
860 MIRBuilder.buildAnd(s32, LUTShifted, MIRBuilder.buildConstant(s32, 3));
861 auto RetValTrunc = MIRBuilder.buildZExtOrTrunc(DstTy, RetVal);
862
863 MIRBuilder.buildCopy(Dst, RetValTrunc);
864
865 MI.eraseFromParent();
866 return true;
867}
868
869bool X86LegalizerInfo::legalizeSETROUNDING(MachineInstr &MI,
871 LegalizerHelper &Helper) const {
872 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
873 MachineFunction &MF = MIRBuilder.getMF();
874 Register Src = MI.getOperand(0).getReg();
875 const LLT s8 = LLT::scalar(8);
876 const LLT s16 = LLT::scalar(16);
877 const LLT s32 = LLT::scalar(32);
878
879 // Allocate stack slot for control word and MXCSR (4 bytes).
880 int MemSize = 4;
881 Align Alignment = Align(4);
882 MachinePointerInfo PtrInfo;
883 auto StackTemp = Helper.createStackTemporary(TypeSize::getFixed(MemSize),
884 Alignment, PtrInfo);
885 Register StackPtr = StackTemp.getReg(0);
886
887 auto StoreMMO =
889 MIRBuilder.buildInstr(X86::G_FNSTCW16)
890 .addUse(StackPtr)
891 .addMemOperand(StoreMMO);
892
893 auto LoadMMO =
895 auto CWD16 = MIRBuilder.buildLoad(s16, StackPtr, *LoadMMO);
896
897 // Clear RM field (bits 11:10)
898 auto ClearedCWD =
899 MIRBuilder.buildAnd(s16, CWD16, MIRBuilder.buildConstant(s16, 0xf3ff));
900
901 // Check if Src is a constant
902 auto *SrcDef = MRI.getVRegDef(Src);
903 Register RMBits;
904 Register MXCSRRMBits;
905
906 if (SrcDef && SrcDef->getOpcode() == TargetOpcode::G_CONSTANT) {
907 uint64_t RM = getIConstantFromReg(Src, MRI).getZExtValue();
908 int FieldVal = X86::getRoundingModeX86(RM);
909
910 if (FieldVal == X86::rmInvalid) {
911 FieldVal = X86::rmToNearest;
912 LLVMContext &C = MF.getFunction().getContext();
913 C.diagnose(DiagnosticInfoUnsupported(
914 MF.getFunction(), "rounding mode is not supported by X86 hardware",
915 DiagnosticLocation(MI.getDebugLoc()), DS_Error));
916 return false;
917 }
918
919 FieldVal = FieldVal << 3;
920 RMBits = MIRBuilder.buildConstant(s16, FieldVal).getReg(0);
921 MXCSRRMBits = MIRBuilder.buildConstant(s32, FieldVal).getReg(0);
922 } else {
923 // Convert Src (rounding mode) to bits for control word
924 // (0xc9 << (2 * Src + 4)) & 0xc00
925 auto Src32 = MIRBuilder.buildZExtOrTrunc(s32, Src);
926 auto ShiftAmt = MIRBuilder.buildAdd(
927 s32, MIRBuilder.buildShl(s32, Src32, MIRBuilder.buildConstant(s32, 1)),
928 MIRBuilder.buildConstant(s32, 4));
929 auto ShiftAmt8 = MIRBuilder.buildTrunc(s8, ShiftAmt);
930 auto Shifted = MIRBuilder.buildShl(s16, MIRBuilder.buildConstant(s16, 0xc9),
931 ShiftAmt8);
932 RMBits =
933 MIRBuilder.buildAnd(s16, Shifted, MIRBuilder.buildConstant(s16, 0xc00))
934 .getReg(0);
935
936 // For non-constant case, we still need to compute MXCSR bits dynamically
937 auto RMBits32 = MIRBuilder.buildZExt(s32, RMBits);
938 MXCSRRMBits =
939 MIRBuilder.buildShl(s32, RMBits32, MIRBuilder.buildConstant(s32, 3))
940 .getReg(0);
941 }
942 // Update rounding mode bits
943 auto NewCWD =
944 MIRBuilder.buildOr(s16, ClearedCWD, RMBits, MachineInstr::Disjoint);
945
946 // Store new FP Control Word to stack
947 auto StoreNewMMO =
949 MIRBuilder.buildStore(NewCWD, StackPtr, *StoreNewMMO);
950
951 // Load FP control word from the slot using G_FLDCW16
952 auto LoadNewMMO =
954 MIRBuilder.buildInstr(X86::G_FLDCW16)
955 .addUse(StackPtr)
956 .addMemOperand(LoadNewMMO);
957
958 if (Subtarget.hasSSE1()) {
959 // Store MXCSR to stack (use STMXCSR)
960 auto StoreMXCSRMMO = MF.getMachineMemOperand(
961 PtrInfo, MachineMemOperand::MOStore, 4, Align(4));
962 MIRBuilder.buildInstr(TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS)
963 .addIntrinsicID(Intrinsic::x86_sse_stmxcsr)
964 .addUse(StackPtr)
965 .addMemOperand(StoreMXCSRMMO);
966
967 // Load MXCSR from stack
968 auto LoadMXCSRMMO = MF.getMachineMemOperand(
969 PtrInfo, MachineMemOperand::MOLoad, 4, Align(4));
970 auto MXCSR = MIRBuilder.buildLoad(s32, StackPtr, *LoadMXCSRMMO);
971
972 // Clear RM field (bits 14:13)
973 auto ClearedMXCSR = MIRBuilder.buildAnd(
974 s32, MXCSR, MIRBuilder.buildConstant(s32, 0xffff9fff));
975
976 // Update rounding mode bits
977 auto NewMXCSR = MIRBuilder.buildOr(s32, ClearedMXCSR, MXCSRRMBits);
978
979 // Store new MXCSR to stack
980 auto StoreNewMXCSRMMO = MF.getMachineMemOperand(
981 PtrInfo, MachineMemOperand::MOStore, 4, Align(4));
982 MIRBuilder.buildStore(NewMXCSR, StackPtr, *StoreNewMXCSRMMO);
983
984 // Load MXCSR from stack (use LDMXCSR)
985 auto LoadNewMXCSRMMO = MF.getMachineMemOperand(
986 PtrInfo, MachineMemOperand::MOLoad, 4, Align(4));
987 MIRBuilder.buildInstr(TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS)
988 .addIntrinsicID(Intrinsic::x86_sse_ldmxcsr)
989 .addUse(StackPtr)
990 .addMemOperand(LoadNewMXCSRMMO);
991 }
992
993 MI.eraseFromParent();
994 return true;
995}
996
998 MachineInstr &MI) const {
999 return true;
1000}
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: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.
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:652
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
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: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.