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