LLVM 23.0.0git
X86LegalizerInfo.cpp
Go to the documentation of this file.
1//===- X86LegalizerInfo.cpp --------------------------------------*- C++ -*-==//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8/// \file
9/// This file implements the targeting of the Machinelegalizer class for X86.
10/// \todo This should be generated by TableGen.
11//===----------------------------------------------------------------------===//
12
13#include "X86LegalizerInfo.h"
14#include "X86Subtarget.h"
15#include "X86TargetMachine.h"
24#include "llvm/IR/IntrinsicsX86.h"
25#include "llvm/IR/Type.h"
26
27using namespace llvm;
28using namespace TargetOpcode;
29using namespace LegalizeActions;
30using namespace LegalityPredicates;
31
33 const X86TargetMachine &TM)
34 : Subtarget(STI) {
35
36 bool Is64Bit = Subtarget.is64Bit();
37 bool HasCMOV = Subtarget.canUseCMOV();
38 bool HasSSE1 = Subtarget.hasSSE1();
39 bool HasSSE2 = Subtarget.hasSSE2();
40 bool HasSSE41 = Subtarget.hasSSE41();
41 bool HasAVX = Subtarget.hasAVX();
42 bool HasAVX2 = Subtarget.hasAVX2();
43 bool HasAVX512 = Subtarget.hasAVX512();
44 bool HasVLX = Subtarget.hasVLX();
45 bool HasDQI = Subtarget.hasAVX512() && Subtarget.hasDQI();
46 bool HasBWI = Subtarget.hasAVX512() && Subtarget.hasBWI();
47 bool UseX87 = !Subtarget.useSoftFloat() && Subtarget.hasX87();
48 bool HasPOPCNT = Subtarget.hasPOPCNT();
49 bool HasLZCNT = Subtarget.hasLZCNT();
50 bool HasBMI = Subtarget.hasBMI();
51
52 const LLT p0 = LLT::pointer(0, TM.getPointerSizeInBits(0));
53 const LLT s1 = LLT::scalar(1);
54 const LLT s8 = LLT::scalar(8);
55 const LLT s16 = LLT::scalar(16);
56 const LLT s32 = LLT::scalar(32);
57 const LLT s64 = LLT::scalar(64);
58 const LLT s80 = LLT::scalar(80);
59 const LLT s128 = LLT::scalar(128);
60 const LLT sMaxScalar = Subtarget.is64Bit() ? s64 : s32;
61 const LLT v2s32 = LLT::fixed_vector(2, 32);
62 const LLT v4s8 = LLT::fixed_vector(4, 8);
63
64 const LLT v16s8 = LLT::fixed_vector(16, 8);
65 const LLT v8s16 = LLT::fixed_vector(8, 16);
66 const LLT v4s32 = LLT::fixed_vector(4, 32);
67 const LLT v2s64 = LLT::fixed_vector(2, 64);
68 const LLT v2p0 = LLT::fixed_vector(2, p0);
69
70 const LLT v32s8 = LLT::fixed_vector(32, 8);
71 const LLT v16s16 = LLT::fixed_vector(16, 16);
72 const LLT v8s32 = LLT::fixed_vector(8, 32);
73 const LLT v4s64 = LLT::fixed_vector(4, 64);
74 const LLT v4p0 = LLT::fixed_vector(4, p0);
75
76 const LLT v64s8 = LLT::fixed_vector(64, 8);
77 const LLT v32s16 = LLT::fixed_vector(32, 16);
78 const LLT v16s32 = LLT::fixed_vector(16, 32);
79 const LLT v8s64 = LLT::fixed_vector(8, 64);
80
81 const LLT s8MaxVector = HasAVX512 ? v64s8 : HasAVX ? v32s8 : v16s8;
82 const LLT s16MaxVector = HasAVX512 ? v32s16 : HasAVX ? v16s16 : v8s16;
83 const LLT s32MaxVector = HasAVX512 ? v16s32 : HasAVX ? v8s32 : v4s32;
84 const LLT s64MaxVector = HasAVX512 ? v8s64 : HasAVX ? v4s64 : v2s64;
85
86 // todo: AVX512 bool vector predicate types
87
88 // implicit/constants
89 // 32/64-bits needs support for s64/s128 to handle cases:
90 // s64 = EXTEND (G_IMPLICIT_DEF s32) -> s64 = G_IMPLICIT_DEF
91 // s128 = EXTEND (G_IMPLICIT_DEF s32/s64) -> s128 = G_IMPLICIT_DEF
93 {G_IMPLICIT_DEF, G_PHI, G_FREEZE, G_CONSTANT_FOLD_BARRIER})
94 .legalFor({p0, s1, s8, s16, s32, s64})
95 .legalFor(UseX87, {s80})
96 .legalFor(Is64Bit, {s128})
97 .legalFor(HasSSE2, {v16s8, v8s16, v4s32, v2s64})
98 .legalFor(HasAVX, {v32s8, v16s16, v8s32, v4s64})
99 .legalFor(HasAVX512, {v64s8, v32s16, v16s32, v8s64})
100 .widenScalarOrEltToNextPow2(0, /*Min=*/8)
101 .clampScalarOrElt(0, s8, sMaxScalar)
102 .moreElementsToNextPow2(0)
103 .clampNumElements(0, v16s8, s8MaxVector)
104 .clampNumElements(0, v8s16, s16MaxVector)
105 .clampNumElements(0, v4s32, s32MaxVector)
106 .clampNumElements(0, v2s64, s64MaxVector)
107 .clampMaxNumElements(0, p0,
108 Is64Bit ? s64MaxVector.getNumElements()
109 : s32MaxVector.getNumElements())
110 .scalarizeIf(scalarOrEltWiderThan(0, 64), 0);
111
113 .legalFor({p0, s8, s16, s32})
114 .legalFor(Is64Bit, {s64})
115 .widenScalarToNextPow2(0, /*Min=*/8)
116 .clampScalar(0, s8, sMaxScalar);
117
118 getActionDefinitionsBuilder({G_LROUND, G_LLROUND})
119 .widenScalarIf(typeIs(1, s16),
120 [=](const LegalityQuery &) {
121 return std::pair<unsigned, LLT>(1, s32);
122 })
123 .libcall();
124
126 {G_FCOS, G_FCOSH, G_FACOS, G_FSIN, G_FSINH, G_FASIN, G_FTAN,
127 G_FTANH, G_FATAN, G_FATAN2, G_FPOW, G_FEXP, G_FEXP2, G_FEXP10,
128 G_FLOG, G_FLOG2, G_FLOG10, G_FPOWI, G_FSINCOS, G_FCEIL, G_FFLOOR})
129 .libcall();
130
132 .legalFor(UseX87 && !HasSSE1, {s32})
133 .legalFor(UseX87 && !HasSSE2, {s64})
134 .legalFor(UseX87, {s80})
135 .lower();
136
138 .legalFor(HasSSE1 || UseX87, {s32})
139 .legalFor(HasSSE2 || UseX87, {s64})
140 .legalFor(UseX87, {s80});
141
142 getActionDefinitionsBuilder({G_GET_ROUNDING, G_SET_ROUNDING})
143 .customFor({s32});
144
145 // merge/unmerge
146 for (unsigned Op : {G_MERGE_VALUES, G_UNMERGE_VALUES}) {
147 unsigned BigTyIdx = Op == G_MERGE_VALUES ? 0 : 1;
148 unsigned LitTyIdx = Op == G_MERGE_VALUES ? 1 : 0;
150 .widenScalarToNextPow2(LitTyIdx, /*Min=*/8)
151 .widenScalarToNextPow2(BigTyIdx, /*Min=*/16)
152 .minScalar(LitTyIdx, s8)
153 .minScalar(BigTyIdx, s32)
154 .legalIf([=](const LegalityQuery &Q) {
155 switch (Q.Types[BigTyIdx].getSizeInBits()) {
156 case 16:
157 case 32:
158 case 64:
159 case 128:
160 case 256:
161 case 512:
162 break;
163 default:
164 return false;
165 }
166 switch (Q.Types[LitTyIdx].getSizeInBits()) {
167 case 8:
168 case 16:
169 case 32:
170 case 64:
171 case 128:
172 case 256:
173 return true;
174 default:
175 return false;
176 }
177 });
178 }
179
180 getActionDefinitionsBuilder({G_UMIN, G_UMAX, G_SMIN, G_SMAX})
181 .widenScalarToNextPow2(0, /*Min=*/32)
182 .lower();
183
184 // integer addition/subtraction
185 getActionDefinitionsBuilder({G_ADD, G_SUB})
186 .legalFor({s8, s16, s32})
187 .legalFor(Is64Bit, {s64})
188 .legalFor(HasSSE2, {v16s8, v8s16, v4s32, v2s64})
189 .legalFor(HasAVX2, {v32s8, v16s16, v8s32, v4s64})
190 .legalFor(HasAVX512, {v16s32, v8s64})
191 .legalFor(HasBWI, {v64s8, v32s16})
192 .clampMinNumElements(0, s8, 16)
193 .clampMinNumElements(0, s16, 8)
194 .clampMinNumElements(0, s32, 4)
195 .clampMinNumElements(0, s64, 2)
196 .clampMaxNumElements(0, s8, HasBWI ? 64 : (HasAVX2 ? 32 : 16))
197 .clampMaxNumElements(0, s16, HasBWI ? 32 : (HasAVX2 ? 16 : 8))
198 .clampMaxNumElements(0, s32, HasAVX512 ? 16 : (HasAVX2 ? 8 : 4))
199 .clampMaxNumElements(0, s64, HasAVX512 ? 8 : (HasAVX2 ? 4 : 2))
200 .widenScalarToNextPow2(0, /*Min=*/32)
201 .clampScalar(0, s8, sMaxScalar)
202 .scalarize(0);
203
204 getActionDefinitionsBuilder({G_UADDE, G_UADDO, G_USUBE, G_USUBO})
205 .legalFor({{s8, s8}, {s16, s8}, {s32, s8}})
206 .legalFor(Is64Bit, {{s64, s8}})
207 .widenScalarToNextPow2(0, /*Min=*/32)
208 .clampScalar(0, s8, sMaxScalar)
209 .clampScalar(1, s8, s8)
210 .scalarize(0);
211
212 // integer multiply
214 .legalFor({s8, s16, s32})
215 .legalFor(Is64Bit, {s64})
216 .legalFor(HasSSE2, {v8s16})
217 .legalFor(HasSSE41, {v4s32})
218 .legalFor(HasAVX2, {v16s16, v8s32})
219 .legalFor(HasAVX512, {v16s32})
220 .legalFor(HasDQI, {v8s64})
221 .legalFor(HasDQI && HasVLX, {v2s64, v4s64})
222 .legalFor(HasBWI, {v32s16})
223 .clampMinNumElements(0, s16, 8)
224 .clampMinNumElements(0, s32, 4)
225 .clampMinNumElements(0, s64, HasVLX ? 2 : 8)
226 .clampMaxNumElements(0, s16, HasBWI ? 32 : (HasAVX2 ? 16 : 8))
227 .clampMaxNumElements(0, s32, HasAVX512 ? 16 : (HasAVX2 ? 8 : 4))
228 .clampMaxNumElements(0, s64, 8)
229 .widenScalarToNextPow2(0, /*Min=*/32)
230 .clampScalar(0, s8, sMaxScalar)
231 .scalarize(0);
232
233 getActionDefinitionsBuilder({G_SMULH, G_UMULH})
234 .legalFor({s8, s16, s32})
235 .legalFor(Is64Bit, {s64})
236 .widenScalarToNextPow2(0, /*Min=*/32)
237 .clampScalar(0, s8, sMaxScalar)
238 .scalarize(0);
239
240 // integer divisions
241 getActionDefinitionsBuilder({G_SDIV, G_SREM, G_UDIV, G_UREM})
242 .legalFor({s8, s16, s32})
243 .legalFor(Is64Bit, {s64})
244 .libcallFor({s64})
245 .clampScalar(0, s8, sMaxScalar);
246
247 // integer shifts
248 getActionDefinitionsBuilder({G_SHL, G_LSHR, G_ASHR})
249 .legalFor({{s8, s8}, {s16, s8}, {s32, s8}})
250 .legalFor(Is64Bit, {{s64, s8}})
251 .clampScalar(0, s8, sMaxScalar)
252 .clampScalar(1, s8, s8);
253
254 // integer logic
255 getActionDefinitionsBuilder({G_AND, G_OR, G_XOR})
256 .legalFor({s8, s16, s32})
257 .legalFor(Is64Bit, {s64})
258 .legalFor(HasSSE2, {v16s8, v8s16, v4s32, v2s64})
259 .legalFor(HasAVX, {v32s8, v16s16, v8s32, v4s64})
260 .legalFor(HasAVX512, {v64s8, v32s16, v16s32, v8s64})
261 .clampNumElements(0, v16s8, s8MaxVector)
262 .clampNumElements(0, v8s16, s16MaxVector)
263 .clampNumElements(0, v4s32, s32MaxVector)
264 .clampNumElements(0, v2s64, s64MaxVector)
265 .widenScalarToNextPow2(0, /*Min=*/32)
266 .clampScalar(0, s8, sMaxScalar)
267 .scalarize(0);
268
269 // integer comparison
270 const std::initializer_list<LLT> IntTypes32 = {s8, s16, s32, p0};
271 const std::initializer_list<LLT> IntTypes64 = {s8, s16, s32, s64, p0};
272
274 .legalForCartesianProduct({s8}, Is64Bit ? IntTypes64 : IntTypes32)
275 .clampScalar(0, s8, s8)
276 .widenScalarToNextPow2(1, /*Min=*/8)
277 .clampScalar(1, s8, sMaxScalar);
278
279 // bswap
281 .legalFor({s32})
282 .legalFor(Is64Bit, {s64})
283 .widenScalarToNextPow2(0, /*Min=*/32)
284 .clampScalar(0, s32, sMaxScalar);
285
286 // popcount
288 .legalFor(HasPOPCNT, {{s16, s16}, {s32, s32}})
289 .legalFor(HasPOPCNT && Is64Bit, {{s64, s64}})
290 .widenScalarToNextPow2(1, /*Min=*/16)
291 .clampScalar(1, s16, sMaxScalar)
292 .scalarSameSizeAs(0, 1);
293
294 // count leading zeros (LZCNT)
296 .legalFor(HasLZCNT, {{s16, s16}, {s32, s32}})
297 .legalFor(HasLZCNT && Is64Bit, {{s64, s64}})
298 .widenScalarToNextPow2(1, /*Min=*/16)
299 .clampScalar(1, s16, sMaxScalar)
300 .scalarSameSizeAs(0, 1);
301
302 // count trailing zeros
303 getActionDefinitionsBuilder(G_CTTZ_ZERO_POISON)
304 .legalFor({{s16, s16}, {s32, s32}})
305 .legalFor(Is64Bit, {{s64, s64}})
306 .widenScalarToNextPow2(1, /*Min=*/16)
307 .clampScalar(1, s16, sMaxScalar)
308 .scalarSameSizeAs(0, 1);
309
311 .legalFor(HasBMI, {{s16, s16}, {s32, s32}})
312 .legalFor(HasBMI && Is64Bit, {{s64, s64}})
313 .widenScalarToNextPow2(1, /*Min=*/16)
314 .clampScalar(1, s16, sMaxScalar)
315 .scalarSameSizeAs(0, 1);
316
318
319 // pointer handling
320 const std::initializer_list<LLT> PtrTypes32 = {s1, s8, s16, s32};
321 const std::initializer_list<LLT> PtrTypes64 = {s1, s8, s16, s32, s64};
322
324 .legalForCartesianProduct(Is64Bit ? PtrTypes64 : PtrTypes32, {p0})
325 .maxScalar(0, sMaxScalar)
326 .widenScalarToNextPow2(0, /*Min*/ 8);
327
328 getActionDefinitionsBuilder(G_INTTOPTR).legalFor({{p0, sMaxScalar}});
329
330 getActionDefinitionsBuilder(G_CONSTANT_POOL).legalFor({p0});
331
333 .legalFor({{p0, s32}})
334 .legalFor(Is64Bit, {{p0, s64}})
335 .widenScalarToNextPow2(1, /*Min*/ 32)
336 .clampScalar(1, s32, sMaxScalar);
337
338 getActionDefinitionsBuilder(G_FRAME_INDEX).legalFor({p0});
339
340 getActionDefinitionsBuilder(G_GLOBAL_VALUE).customFor({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 for (unsigned Op : {G_FPEXTLOAD, G_FPTRUNCSTORE}) {
404 auto &Action = getActionDefinitionsBuilder(Op);
405 Action.legalForTypesWithMemDesc(
406 UseX87, {{s80, p0, s32, 1}, {s80, p0, s64, 1}, {s64, p0, s32, 1}});
407 }
408
409 // sext, zext, and anyext
411 .legalFor({s8, s16, s32, s128})
412 .legalFor(Is64Bit, {s64})
413 .widenScalarToNextPow2(0, /*Min=*/8)
414 .clampScalar(0, s8, sMaxScalar)
415 .widenScalarToNextPow2(1, /*Min=*/8)
416 .clampScalar(1, s8, sMaxScalar)
417 .scalarize(0);
418
419 getActionDefinitionsBuilder({G_SEXT, G_ZEXT})
420 .legalFor({s8, s16, s32})
421 .legalFor(Is64Bit, {s64})
422 .widenScalarToNextPow2(0, /*Min=*/8)
423 .clampScalar(0, s8, sMaxScalar)
424 .widenScalarToNextPow2(1, /*Min=*/8)
425 .clampScalar(1, s8, sMaxScalar)
426 .scalarize(0);
427
428 getActionDefinitionsBuilder(G_SEXT_INREG).lower();
429
430 // fp constants
431 getActionDefinitionsBuilder(G_FCONSTANT)
432 .legalFor({s32, s64})
433 .legalFor(UseX87, {s80});
434
435 // fp arithmetic
436 getActionDefinitionsBuilder({G_FADD, G_FSUB, G_FMUL, G_FDIV})
437 .legalFor({s32, s64})
438 .legalFor(HasSSE1, {v4s32})
439 .legalFor(HasSSE2, {v2s64})
440 .legalFor(HasAVX, {v8s32, v4s64})
441 .legalFor(HasAVX512, {v16s32, v8s64})
442 .legalFor(UseX87, {s80});
443
445 .legalFor(UseX87, {s80})
446 .legalFor(UseX87 && !Is64Bit, {s64})
447 .lower();
448
449 // fp comparison
451 .legalFor(HasSSE1 || UseX87, {s8, s32})
452 .legalFor(HasSSE2 || UseX87, {s8, s64})
453 .legalFor(UseX87, {s8, s80})
454 .clampScalar(0, s8, s8)
455 .clampScalar(1, s32, HasSSE2 ? s64 : s32)
457
458 // fp conversions
460 .legalFor(HasSSE2, {{s64, s32}})
461 .legalFor(HasAVX, {{v4s64, v4s32}})
462 .legalFor(HasAVX512, {{v8s64, v8s32}})
463 .lowerFor(UseX87, {{s64, s32}, {s80, s32}, {s80, s64}})
464 .libcall();
465
467 .legalFor(HasSSE2, {{s32, s64}})
468 .legalFor(HasAVX, {{v4s32, v4s64}})
469 .legalFor(HasAVX512, {{v8s32, v8s64}})
470 .lowerFor(UseX87, {{s32, s64}, {s32, s80}, {s64, s80}});
471
473 .legalFor(HasSSE1, {{s32, s32}})
474 .legalFor(HasSSE1 && Is64Bit, {{s32, s64}})
475 .legalFor(HasSSE2, {{s64, s32}})
476 .legalFor(HasSSE2 && Is64Bit, {{s64, s64}})
477 .clampScalar(1, (UseX87 && !HasSSE1) ? s16 : s32, sMaxScalar)
479 .customForCartesianProduct(UseX87, {s32, s64, s80}, {s16, s32, s64})
480 .clampScalar(0, s32, HasSSE2 ? s64 : s32)
482
484 .legalFor(HasSSE1, {{s32, s32}})
485 .legalFor(HasSSE1 && Is64Bit, {{s64, s32}})
486 .legalFor(HasSSE2, {{s32, s64}})
487 .legalFor(HasSSE2 && Is64Bit, {{s64, s64}})
488 .clampScalar(0, (UseX87 && !HasSSE1) ? s16 : s32, sMaxScalar)
490 .customForCartesianProduct(UseX87, {s16, s32, s64}, {s32, s64, s80})
491 .clampScalar(1, s32, HasSSE2 ? s64 : s32)
493
494 // For G_UITOFP and G_FPTOUI without AVX512, we have to custom legalize types
495 // <= s32 manually. Otherwise, in custom handler there is no way to
496 // understand whether s32 is an original type and we need to promote it to
497 // s64 or s32 is obtained after widening and we shouldn't widen it to s64.
498 //
499 // For AVX512 we simply widen types as there is direct mapping from opcodes
500 // to asm instructions.
502 .legalFor(HasAVX512, {{s32, s32}, {s32, s64}, {s64, s32}, {s64, s64}})
503 .customIf([=](const LegalityQuery &Query) {
504 return !HasAVX512 &&
505 ((HasSSE1 && typeIs(0, s32)(Query)) ||
506 (HasSSE2 && typeIs(0, s64)(Query))) &&
507 scalarNarrowerThan(1, Is64Bit ? 64 : 32)(Query);
508 })
509 .lowerIf([=](const LegalityQuery &Query) {
510 // Lower conversions from s64
511 return !HasAVX512 &&
512 ((HasSSE1 && typeIs(0, s32)(Query)) ||
513 (HasSSE2 && typeIs(0, s64)(Query))) &&
514 (Is64Bit && typeIs(1, s64)(Query));
515 })
516 .clampScalar(0, s32, HasSSE2 ? s64 : s32)
518 .clampScalar(1, s32, sMaxScalar)
520
522 .legalFor(HasAVX512, {{s32, s32}, {s32, s64}, {s64, s32}, {s64, s64}})
523 .customIf([=](const LegalityQuery &Query) {
524 return !HasAVX512 &&
525 ((HasSSE1 && typeIs(1, s32)(Query)) ||
526 (HasSSE2 && typeIs(1, s64)(Query))) &&
527 scalarNarrowerThan(0, Is64Bit ? 64 : 32)(Query);
528 })
529 // TODO: replace with customized legalization using
530 // specifics of cvttsd2si. The selection of this node requires
531 // a vector type. Either G_SCALAR_TO_VECTOR is needed or more advanced
532 // support of G_BUILD_VECTOR/G_INSERT_VECTOR_ELT is required beforehand.
533 .lowerIf([=](const LegalityQuery &Query) {
534 return !HasAVX512 &&
535 ((HasSSE1 && typeIs(1, s32)(Query)) ||
536 (HasSSE2 && typeIs(1, s64)(Query))) &&
537 (Is64Bit && typeIs(0, s64)(Query));
538 })
539 .clampScalar(0, s32, sMaxScalar)
541 .clampScalar(1, s32, HasSSE2 ? s64 : s32)
543
544 // vector ops
545 getActionDefinitionsBuilder(G_BUILD_VECTOR)
546 .customIf([=](const LegalityQuery &Query) {
547 return (HasSSE1 && typeInSet(0, {v4s32})(Query)) ||
548 (HasSSE2 && typeInSet(0, {v2s64, v8s16, v16s8})(Query)) ||
549 (HasAVX && typeInSet(0, {v4s64, v8s32, v16s16, v32s8})(Query)) ||
550 (HasAVX512 && typeInSet(0, {v8s64, v16s32, v32s16, v64s8}));
551 })
552 .clampNumElements(0, v16s8, s8MaxVector)
553 .clampNumElements(0, v8s16, s16MaxVector)
554 .clampNumElements(0, v4s32, s32MaxVector)
555 .clampNumElements(0, v2s64, s64MaxVector)
557
558 getActionDefinitionsBuilder({G_EXTRACT, G_INSERT})
559 .legalIf([=](const LegalityQuery &Query) {
560 unsigned SubIdx = Query.Opcode == G_EXTRACT ? 0 : 1;
561 unsigned FullIdx = Query.Opcode == G_EXTRACT ? 1 : 0;
562 return (HasAVX && typePairInSet(SubIdx, FullIdx,
563 {{v16s8, v32s8},
564 {v8s16, v16s16},
565 {v4s32, v8s32},
566 {v2s64, v4s64}})(Query)) ||
567 (HasAVX512 && typePairInSet(SubIdx, FullIdx,
568 {{v16s8, v64s8},
569 {v32s8, v64s8},
570 {v8s16, v32s16},
571 {v16s16, v32s16},
572 {v4s32, v16s32},
573 {v8s32, v16s32},
574 {v2s64, v8s64},
575 {v4s64, v8s64}})(Query));
576 });
577
578 // todo: only permit dst types up to max legal vector register size?
579 getActionDefinitionsBuilder(G_CONCAT_VECTORS)
580 .legalFor(
581 HasSSE1,
582 {{v32s8, v16s8}, {v16s16, v8s16}, {v8s32, v4s32}, {v4s64, v2s64}})
583 .legalFor(HasAVX, {{v64s8, v16s8},
584 {v64s8, v32s8},
585 {v32s16, v8s16},
586 {v32s16, v16s16},
587 {v16s32, v4s32},
588 {v16s32, v8s32},
589 {v8s64, v2s64},
590 {v8s64, v4s64}});
591
592 // todo: vectors and address spaces
594 .legalFor({{s16, s32}, {s32, s32}, {p0, s32}})
595 .legalFor(!HasCMOV, {{s8, s32}})
596 .legalFor(Is64Bit, {{s64, s32}})
597 .legalFor(UseX87, {{s80, s32}})
598 .clampScalar(1, s32, s32)
599 .widenScalarToNextPow2(0, /*Min=*/8)
600 .clampScalar(0, HasCMOV ? s16 : s8, sMaxScalar);
601
602 // memory intrinsics
603 getActionDefinitionsBuilder({G_MEMCPY, G_MEMMOVE, G_MEMSET}).libcall();
604
605 getActionDefinitionsBuilder({G_DYN_STACKALLOC, G_STACKSAVE, G_STACKRESTORE})
606 .lower();
607
608 // fp intrinsics
609 // fpclass for i686 is disabled for llvm issue #171992
610 getActionDefinitionsBuilder(G_IS_FPCLASS)
611 .lowerFor(Is64Bit, {{s1, s32}, {s1, s64}, {s1, s80}});
612
613 getActionDefinitionsBuilder({G_INTRINSIC_ROUNDEVEN, G_INTRINSIC_TRUNC})
614 .scalarize(0)
615 .minScalar(0, LLT::scalar(32))
616 .libcall();
617
619 verify(*STI.getInstrInfo());
620}
621
623 LostDebugLocObserver &LocObserver) const {
624 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
625 MachineRegisterInfo &MRI = *MIRBuilder.getMRI();
626 switch (MI.getOpcode()) {
627 default:
628 // No idea what to do.
629 return false;
630 case TargetOpcode::G_BUILD_VECTOR:
631 return legalizeBuildVector(MI, MRI, Helper);
632 case TargetOpcode::G_FPTOUI:
633 return legalizeFPTOUI(MI, MRI, Helper);
634 case TargetOpcode::G_UITOFP:
635 return legalizeUITOFP(MI, MRI, Helper);
636 case TargetOpcode::G_STORE:
637 return legalizeNarrowingStore(MI, MRI, Helper);
638 case TargetOpcode::G_SITOFP:
639 return legalizeSITOFP(MI, MRI, Helper);
640 case TargetOpcode::G_FPTOSI:
641 return legalizeFPTOSI(MI, MRI, Helper);
642 case TargetOpcode::G_GET_ROUNDING:
643 return legalizeGETROUNDING(MI, MRI, Helper);
644 case TargetOpcode::G_SET_ROUNDING:
645 return legalizeSETROUNDING(MI, MRI, Helper);
646 case TargetOpcode::G_GLOBAL_VALUE:
647 return legalizeGLOBAL_VALUE(MI, MRI, Helper);
648 }
649 llvm_unreachable("expected switch to return");
650}
651
652bool X86LegalizerInfo::legalizeSITOFP(MachineInstr &MI,
654 LegalizerHelper &Helper) const {
655 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
656 MachineFunction &MF = *MI.getMF();
657 auto [Dst, DstTy, Src, SrcTy] = MI.getFirst2RegLLTs();
658
659 assert((SrcTy.getSizeInBits() == 16 || SrcTy.getSizeInBits() == 32 ||
660 SrcTy.getSizeInBits() == 64) &&
661 "Unexpected source type for SITOFP in X87 mode.");
662
663 TypeSize MemSize = SrcTy.getSizeInBytes();
664 MachinePointerInfo PtrInfo;
665 Align Alignmt = Helper.getStackTemporaryAlignment(SrcTy);
666 auto SlotPointer = Helper.createStackTemporary(MemSize, Alignmt, PtrInfo);
668 PtrInfo, MachineMemOperand::MOStore, MemSize, Align(MemSize));
669
670 // Store the integer value on the FPU stack.
671 MIRBuilder.buildStore(Src, SlotPointer, *StoreMMO);
672
674 PtrInfo, MachineMemOperand::MOLoad, MemSize, Align(MemSize));
675 MIRBuilder.buildInstr(X86::G_FILD)
676 .addDef(Dst)
677 .addUse(SlotPointer.getReg(0))
678 .addMemOperand(LoadMMO);
679
680 MI.eraseFromParent();
681 return true;
682}
683
684bool X86LegalizerInfo::legalizeFPTOSI(MachineInstr &MI,
686 LegalizerHelper &Helper) const {
687 MachineFunction &MF = *MI.getMF();
688 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
689 auto [Dst, DstTy, Src, SrcTy] = MI.getFirst2RegLLTs();
690
691 TypeSize MemSize = DstTy.getSizeInBytes();
692 MachinePointerInfo PtrInfo;
693 Align Alignmt = Helper.getStackTemporaryAlignment(DstTy);
694 auto SlotPointer = Helper.createStackTemporary(MemSize, Alignmt, PtrInfo);
696 PtrInfo, MachineMemOperand::MOStore, MemSize, Align(MemSize));
697
698 MIRBuilder.buildInstr(X86::G_FIST)
699 .addUse(Src)
700 .addUse(SlotPointer.getReg(0))
701 .addMemOperand(StoreMMO);
702
703 MIRBuilder.buildLoad(Dst, SlotPointer, PtrInfo, Align(MemSize));
704 MI.eraseFromParent();
705 return true;
706}
707
708bool X86LegalizerInfo::legalizeBuildVector(MachineInstr &MI,
710 LegalizerHelper &Helper) const {
711 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
712 const auto &BuildVector = cast<GBuildVector>(MI);
713 Register Dst = BuildVector.getReg(0);
714 LLT DstTy = MRI.getType(Dst);
715 MachineFunction &MF = MIRBuilder.getMF();
716 LLVMContext &Ctx = MF.getFunction().getContext();
717 uint64_t DstTySize = DstTy.getScalarSizeInBits();
718
719 SmallVector<Constant *, 4> CstIdxs;
720 for (unsigned i = 0; i < BuildVector.getNumSources(); ++i) {
721 Register Source = BuildVector.getSourceReg(i);
722
723 auto ValueAndReg = getIConstantVRegValWithLookThrough(Source, MRI);
724 if (ValueAndReg) {
725 CstIdxs.emplace_back(ConstantInt::get(Ctx, ValueAndReg->Value));
726 continue;
727 }
728
729 auto FPValueAndReg = getFConstantVRegValWithLookThrough(Source, MRI);
730 if (FPValueAndReg) {
731 CstIdxs.emplace_back(ConstantFP::get(Ctx, FPValueAndReg->Value));
732 continue;
733 }
734
735 if (getOpcodeDef<GImplicitDef>(Source, MRI)) {
736 CstIdxs.emplace_back(UndefValue::get(Type::getIntNTy(Ctx, DstTySize)));
737 continue;
738 }
739 return false;
740 }
741
742 Constant *ConstVal = ConstantVector::get(CstIdxs);
743
744 const DataLayout &DL = MIRBuilder.getDataLayout();
745 unsigned AddrSpace = DL.getDefaultGlobalsAddressSpace();
746 Align Alignment(DL.getABITypeAlign(ConstVal->getType()));
747 auto Addr = MIRBuilder.buildConstantPool(
748 LLT::pointer(AddrSpace, DL.getPointerSizeInBits(AddrSpace)),
749 MF.getConstantPool()->getConstantPoolIndex(ConstVal, Alignment));
750 MachineMemOperand *MMO =
752 MachineMemOperand::MOLoad, DstTy, Alignment);
753
754 MIRBuilder.buildLoad(Dst, Addr, *MMO);
755 MI.eraseFromParent();
756 return true;
757}
758
759bool X86LegalizerInfo::legalizeFPTOUI(MachineInstr &MI,
761 LegalizerHelper &Helper) const {
762 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
763 auto [Dst, DstTy, Src, SrcTy] = MI.getFirst2RegLLTs();
764 unsigned DstSizeInBits = DstTy.getScalarSizeInBits();
765 const LLT s32 = LLT::scalar(32);
766 const LLT s64 = LLT::scalar(64);
767
768 // Simply reuse FPTOSI when it is possible to widen the type
769 if (DstSizeInBits <= 32) {
770 auto Casted = MIRBuilder.buildFPTOSI(DstTy == s32 ? s64 : s32, Src);
771 MIRBuilder.buildTrunc(Dst, Casted);
772 MI.eraseFromParent();
773 return true;
774 }
775
776 return false;
777}
778
779bool X86LegalizerInfo::legalizeUITOFP(MachineInstr &MI,
781 LegalizerHelper &Helper) const {
782 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
783 auto [Dst, DstTy, Src, SrcTy] = MI.getFirst2RegLLTs();
784 const LLT s32 = LLT::scalar(32);
785 const LLT s64 = LLT::scalar(64);
786
787 // Simply reuse SITOFP when it is possible to widen the type
788 if (SrcTy.getSizeInBits() <= 32) {
789 auto Ext = MIRBuilder.buildZExt(SrcTy == s32 ? s64 : s32, Src);
790 MIRBuilder.buildSITOFP(Dst, Ext);
791 MI.eraseFromParent();
792 return true;
793 }
794
795 return false;
796}
797
798bool X86LegalizerInfo::legalizeNarrowingStore(MachineInstr &MI,
800 LegalizerHelper &Helper) const {
801 auto &Store = cast<GStore>(MI);
802 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
803 MachineMemOperand &MMO = **Store.memoperands_begin();
804 MachineFunction &MF = MIRBuilder.getMF();
805 LLT ValTy = MRI.getType(Store.getValueReg());
806 auto *NewMMO = MF.getMachineMemOperand(&MMO, MMO.getPointerInfo(), ValTy);
807
808 Helper.Observer.changingInstr(Store);
809 Store.setMemRefs(MF, {NewMMO});
810 Helper.Observer.changedInstr(Store);
811 return true;
812}
813
814bool X86LegalizerInfo::legalizeGETROUNDING(MachineInstr &MI,
816 LegalizerHelper &Helper) const {
817 /*
818 The rounding mode is in bits 11:10 of FPSR, and has the following
819 settings:
820 00 Round to nearest
821 01 Round to -inf
822 10 Round to +inf
823 11 Round to 0
824
825 GET_ROUNDING, on the other hand, expects the following:
826 -1 Undefined
827 0 Round to 0
828 1 Round to nearest
829 2 Round to +inf
830 3 Round to -inf
831
832 To perform the conversion, we use a packed lookup table of the four 2-bit
833 values that we can index by FPSP[11:10]
834 0x2d --> (0b00,10,11,01) --> (0,2,3,1) >> FPSR[11:10]
835
836 (0x2d >> ((FPSR >> 9) & 6)) & 3
837 */
838
839 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
840 MachineFunction &MF = MIRBuilder.getMF();
841 Register Dst = MI.getOperand(0).getReg();
842 LLT DstTy = MRI.getType(Dst);
843 const LLT s8 = LLT::scalar(8);
844 const LLT s16 = LLT::scalar(16);
845 const LLT s32 = LLT::scalar(32);
846
847 // Save FP Control Word to stack slot
848 int MemSize = 2;
849 Align Alignment = Align(2);
850 MachinePointerInfo PtrInfo;
851 auto StackTemp = Helper.createStackTemporary(TypeSize::getFixed(MemSize),
852 Alignment, PtrInfo);
853 Register StackPtr = StackTemp.getReg(0);
854
855 auto StoreMMO = MF.getMachineMemOperand(PtrInfo, MachineMemOperand::MOStore,
856 MemSize, Alignment);
857
858 // Store FP Control Word to stack slot using G_FNSTCW16
859 MIRBuilder.buildInstr(X86::G_FNSTCW16)
860 .addUse(StackPtr)
861 .addMemOperand(StoreMMO);
862
863 // Load FP Control Word from stack slot
864 auto LoadMMO = MF.getMachineMemOperand(PtrInfo, MachineMemOperand::MOLoad,
865 MemSize, Alignment);
866
867 auto CWD32 =
868 MIRBuilder.buildZExt(s32, MIRBuilder.buildLoad(s16, StackPtr, *LoadMMO));
869 auto Shifted8 = MIRBuilder.buildTrunc(
870 s8, MIRBuilder.buildLShr(s32, CWD32, MIRBuilder.buildConstant(s8, 9)));
871 auto Masked32 = MIRBuilder.buildZExt(
872 s32, MIRBuilder.buildAnd(s8, Shifted8, MIRBuilder.buildConstant(s8, 6)));
873
874 // LUT is a packed lookup table (0x2d) used to map the 2-bit x87 FPU rounding
875 // mode (from bits 11:10 of the control word) to the values expected by
876 // GET_ROUNDING. The mapping is performed by shifting LUT right by the
877 // extracted rounding mode and masking the result with 3 to obtain the final
878 auto LUT = MIRBuilder.buildConstant(s32, 0x2d);
879 auto LUTShifted = MIRBuilder.buildLShr(s32, LUT, Masked32);
880 auto RetVal =
881 MIRBuilder.buildAnd(s32, LUTShifted, MIRBuilder.buildConstant(s32, 3));
882 auto RetValTrunc = MIRBuilder.buildZExtOrTrunc(DstTy, RetVal);
883
884 MIRBuilder.buildCopy(Dst, RetValTrunc);
885
886 MI.eraseFromParent();
887 return true;
888}
889
890bool X86LegalizerInfo::legalizeSETROUNDING(MachineInstr &MI,
892 LegalizerHelper &Helper) const {
893 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
894 MachineFunction &MF = MIRBuilder.getMF();
895 Register Src = MI.getOperand(0).getReg();
896 const LLT s8 = LLT::scalar(8);
897 const LLT s16 = LLT::scalar(16);
898 const LLT s32 = LLT::scalar(32);
899
900 // Allocate stack slot for control word and MXCSR (4 bytes).
901 int MemSize = 4;
902 Align Alignment = Align(4);
903 MachinePointerInfo PtrInfo;
904 auto StackTemp = Helper.createStackTemporary(TypeSize::getFixed(MemSize),
905 Alignment, PtrInfo);
906 Register StackPtr = StackTemp.getReg(0);
907
908 auto StoreMMO =
910 MIRBuilder.buildInstr(X86::G_FNSTCW16)
911 .addUse(StackPtr)
912 .addMemOperand(StoreMMO);
913
914 auto LoadMMO =
916 auto CWD16 = MIRBuilder.buildLoad(s16, StackPtr, *LoadMMO);
917
918 // Clear RM field (bits 11:10)
919 auto ClearedCWD =
920 MIRBuilder.buildAnd(s16, CWD16, MIRBuilder.buildConstant(s16, 0xf3ff));
921
922 // Check if Src is a constant
923 auto *SrcDef = MRI.getVRegDef(Src);
924 Register RMBits;
925 Register MXCSRRMBits;
926
927 if (SrcDef && SrcDef->getOpcode() == TargetOpcode::G_CONSTANT) {
928 uint64_t RM = getIConstantFromReg(Src, MRI).getZExtValue();
929 int FieldVal = X86::getRoundingModeX86(RM);
930
931 if (FieldVal == X86::rmInvalid) {
932 FieldVal = X86::rmToNearest;
933 LLVMContext &C = MF.getFunction().getContext();
934 C.diagnose(DiagnosticInfoUnsupported(
935 MF.getFunction(), "rounding mode is not supported by X86 hardware",
936 DiagnosticLocation(MI.getDebugLoc()), DS_Error));
937 return false;
938 }
939
940 FieldVal = FieldVal << 3;
941 RMBits = MIRBuilder.buildConstant(s16, FieldVal).getReg(0);
942 MXCSRRMBits = MIRBuilder.buildConstant(s32, FieldVal).getReg(0);
943 } else {
944 // Convert Src (rounding mode) to bits for control word
945 // (0xc9 << (2 * Src + 4)) & 0xc00
946 auto Src32 = MIRBuilder.buildZExtOrTrunc(s32, Src);
947 auto ShiftAmt = MIRBuilder.buildAdd(
948 s32, MIRBuilder.buildShl(s32, Src32, MIRBuilder.buildConstant(s32, 1)),
949 MIRBuilder.buildConstant(s32, 4));
950 auto ShiftAmt8 = MIRBuilder.buildTrunc(s8, ShiftAmt);
951 auto Shifted = MIRBuilder.buildShl(s16, MIRBuilder.buildConstant(s16, 0xc9),
952 ShiftAmt8);
953 RMBits =
954 MIRBuilder.buildAnd(s16, Shifted, MIRBuilder.buildConstant(s16, 0xc00))
955 .getReg(0);
956
957 // For non-constant case, we still need to compute MXCSR bits dynamically
958 auto RMBits32 = MIRBuilder.buildZExt(s32, RMBits);
959 MXCSRRMBits =
960 MIRBuilder.buildShl(s32, RMBits32, MIRBuilder.buildConstant(s32, 3))
961 .getReg(0);
962 }
963 // Update rounding mode bits
964 auto NewCWD =
965 MIRBuilder.buildOr(s16, ClearedCWD, RMBits, MachineInstr::Disjoint);
966
967 // Store new FP Control Word to stack
968 auto StoreNewMMO =
970 MIRBuilder.buildStore(NewCWD, StackPtr, *StoreNewMMO);
971
972 // Load FP control word from the slot using G_FLDCW16
973 auto LoadNewMMO =
975 MIRBuilder.buildInstr(X86::G_FLDCW16)
976 .addUse(StackPtr)
977 .addMemOperand(LoadNewMMO);
978
979 if (Subtarget.hasSSE1()) {
980 // Store MXCSR to stack (use STMXCSR)
981 auto StoreMXCSRMMO = MF.getMachineMemOperand(
982 PtrInfo, MachineMemOperand::MOStore, 4, Align(4));
983 MIRBuilder.buildInstr(TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS)
984 .addIntrinsicID(Intrinsic::x86_sse_stmxcsr)
985 .addUse(StackPtr)
986 .addMemOperand(StoreMXCSRMMO);
987
988 // Load MXCSR from stack
989 auto LoadMXCSRMMO = MF.getMachineMemOperand(
990 PtrInfo, MachineMemOperand::MOLoad, 4, Align(4));
991 auto MXCSR = MIRBuilder.buildLoad(s32, StackPtr, *LoadMXCSRMMO);
992
993 // Clear RM field (bits 14:13)
994 auto ClearedMXCSR = MIRBuilder.buildAnd(
995 s32, MXCSR, MIRBuilder.buildConstant(s32, 0xffff9fff));
996
997 // Update rounding mode bits
998 auto NewMXCSR = MIRBuilder.buildOr(s32, ClearedMXCSR, MXCSRRMBits);
999
1000 // Store new MXCSR to stack
1001 auto StoreNewMXCSRMMO = MF.getMachineMemOperand(
1002 PtrInfo, MachineMemOperand::MOStore, 4, Align(4));
1003 MIRBuilder.buildStore(NewMXCSR, StackPtr, *StoreNewMXCSRMMO);
1004
1005 // Load MXCSR from stack (use LDMXCSR)
1006 auto LoadNewMXCSRMMO = MF.getMachineMemOperand(
1007 PtrInfo, MachineMemOperand::MOLoad, 4, Align(4));
1008 MIRBuilder.buildInstr(TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS)
1009 .addIntrinsicID(Intrinsic::x86_sse_ldmxcsr)
1010 .addUse(StackPtr)
1011 .addMemOperand(LoadNewMXCSRMMO);
1012 }
1013
1014 MI.eraseFromParent();
1015 return true;
1016}
1017
1018bool X86LegalizerInfo::legalizeGLOBAL_VALUE(MachineInstr &MI,
1020 LegalizerHelper &Helper) const {
1021 const GlobalValue *GV = MI.getOperand(1).getGlobal();
1022 Register Dst = MI.getOperand(0).getReg();
1023 LLT DstTy = MRI.getType(Dst);
1024 unsigned GVOpFlags = Subtarget.classifyGlobalReference(GV);
1025
1026 // For stub references (GOT/PLT), we need G_WRAPPER_RIP + load
1027 if (isGlobalStubReference(GVOpFlags)) {
1028 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
1029 MachineFunction &MF = MIRBuilder.getMF();
1030
1031 Register StubAddr = MRI.createGenericVirtualRegister(DstTy);
1032 MIRBuilder.buildInstr(X86::G_WRAPPER_RIP)
1033 .addDef(StubAddr)
1034 .addGlobalAddress(GV);
1035
1036 MachineMemOperand *MMO = MF.getMachineMemOperand(
1038 Align(DstTy.getSizeInBytes()));
1039 MIRBuilder.buildLoad(Dst, StubAddr, *MMO);
1040 MI.eraseFromParent();
1041 }
1042 return true;
1043}
1044
1046 MachineInstr &MI) const {
1047 return true;
1048}
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:1563
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:358
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.
constexpr TypeSize getSizeInBytes() const
Returns the total size of the type in bytes, i.e.
LLVM_ABI void diagnose(const DiagnosticInfo &DI)
Report a message to the currently installed diagnostic handler.
LLVM_ABI void computeTables()
Compute any ancillary tables needed to quickly decide how an operation should be handled.
LegalizeRuleSet & minScalar(unsigned TypeIdx, const LLT Ty)
Ensure the scalar is at least as wide as Ty.
LegalizeRuleSet & legalFor(std::initializer_list< LLT > Types)
The instruction is legal when type index 0 is any type in the given list.
LegalizeRuleSet & scalarSameSizeAs(unsigned TypeIdx, unsigned SameSizeIdx)
Change the type TypeIdx to have the same scalar size as type SameSizeIdx.
LegalizeRuleSet & libcall()
The instruction is emitted as a library call.
LegalizeRuleSet & clampMaxNumElements(unsigned TypeIdx, const LLT EltTy, unsigned MaxElements)
Limit the number of elements in EltTy vectors to at most MaxElements.
LegalizeRuleSet & clampMinNumElements(unsigned TypeIdx, const LLT EltTy, unsigned MinElements)
Limit the number of elements in EltTy vectors to at least MinElements.
LegalizeRuleSet & customForCartesianProduct(std::initializer_list< LLT > Types)
LegalizeRuleSet & moreElementsToNextPow2(unsigned TypeIdx)
Add more elements to the vector to reach the next power of two.
LegalizeRuleSet & lower()
The instruction is lowered.
LegalizeRuleSet & lowerFor(std::initializer_list< LLT > Types)
The instruction is lowered when type index 0 is any type in the given list.
LegalizeRuleSet & clampScalar(unsigned TypeIdx, const LLT MinTy, const LLT MaxTy)
Limit the range of scalar sizes to MinTy and MaxTy.
LegalizeRuleSet & clampNumElements(unsigned TypeIdx, const LLT MinTy, const LLT MaxTy)
Limit the number of elements for the given vectors to at least MinTy's number of elements and at most...
LegalizeRuleSet & customIf(LegalityPredicate Predicate)
LegalizeRuleSet & widenScalarToNextPow2(unsigned TypeIdx, unsigned MinSize=0)
Widen the scalar to the next power of two that is at least MinSize.
LegalizeRuleSet & scalarize(unsigned TypeIdx)
LegalizeRuleSet & legalForCartesianProduct(std::initializer_list< LLT > Types)
The instruction is legal when type indexes 0 and 1 are both in the given list.
LegalizeRuleSet & legalIf(LegalityPredicate Predicate)
The instruction is legal if predicate is true.
LegalizeRuleSet & customFor(std::initializer_list< LLT > Types)
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 & addUse(Register RegNo, RegState Flags={}, unsigned SubReg=0) const
Add a virtual register use operand.
const MachineInstrBuilder & addIntrinsicID(Intrinsic::ID ID) const
const MachineInstrBuilder & addGlobalAddress(const GlobalValue *GV, int64_t Offset=0, unsigned TargetFlags=0) const
const MachineInstrBuilder & addDef(Register RegNo, RegState Flags={}, unsigned SubReg=0) const
Add a virtual register definition operand.
const MachineInstrBuilder & addMemOperand(MachineMemOperand *MMO) const
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,...
LLVM_ABI MachineInstr * getVRegDef(Register Reg) const
getVRegDef - Return the machine instr that defines the specified virtual register or null if none is ...
LLT getType(Register Reg) const
Get the low-level type of Reg or LLT{} if Reg is not a generic (target independent) virtual register.
LLVM_ABI Register createGenericVirtualRegister(LLT Ty, StringRef Name="")
Create and return a new generic virtual register with low-level type Ty.
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:317
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:255
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.
static bool isGlobalStubReference(unsigned char TargetFlag)
isGlobalStubReference - Return true if the specified TargetFlag operand is a reference to a stub for ...
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:653
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
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.
static LLVM_ABI MachinePointerInfo getGOT(MachineFunction &MF)
Return a MachinePointerInfo record that refers to a GOT entry.