LLVM 24.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"
25#include "llvm/IR/IntrinsicsX86.h"
26#include "llvm/IR/Type.h"
27
28using namespace llvm;
29using namespace MIPatternMatch;
30using namespace TargetOpcode;
31using namespace LegalizeActions;
32using namespace LegalityPredicates;
33
35 const X86TargetMachine &TM)
36 : Subtarget(STI) {
37
38 bool Is64Bit = Subtarget.is64Bit();
39 bool HasCMOV = Subtarget.canUseCMOV();
40 bool HasSSE1 = Subtarget.hasSSE1();
41 bool HasSSE2 = Subtarget.hasSSE2();
42 bool HasSSE41 = Subtarget.hasSSE41();
43 bool HasAVX = Subtarget.hasAVX();
44 bool HasAVX2 = Subtarget.hasAVX2();
45 bool HasAVX512 = Subtarget.hasAVX512();
46 bool HasVLX = Subtarget.hasVLX();
47 bool HasDQI = Subtarget.hasAVX512() && Subtarget.hasDQI();
48 bool HasBWI = Subtarget.hasAVX512() && Subtarget.hasBWI();
49 bool UseX87 = !Subtarget.useSoftFloat() && Subtarget.hasX87();
50 bool HasPOPCNT = Subtarget.hasPOPCNT();
51 bool HasLZCNT = Subtarget.hasLZCNT();
52 bool HasBMI = Subtarget.hasBMI();
53
54 const LLT p0 = LLT::pointer(0, TM.getPointerSizeInBits(0));
55 const LLT s1 = LLT::scalar(1);
56 const LLT s8 = LLT::scalar(8);
57 const LLT s16 = LLT::scalar(16);
58 const LLT s32 = LLT::scalar(32);
59 const LLT s64 = LLT::scalar(64);
60 const LLT s80 = LLT::scalar(80);
61 const LLT s128 = LLT::scalar(128);
62 const LLT sMaxScalar = Subtarget.is64Bit() ? s64 : s32;
63 const LLT v2s32 = LLT::fixed_vector(2, 32);
64 const LLT v4s8 = LLT::fixed_vector(4, 8);
65
66 const LLT v16s8 = LLT::fixed_vector(16, 8);
67 const LLT v8s16 = LLT::fixed_vector(8, 16);
68 const LLT v4s32 = LLT::fixed_vector(4, 32);
69 const LLT v2s64 = LLT::fixed_vector(2, 64);
70 const LLT v2p0 = LLT::fixed_vector(2, p0);
71
72 const LLT v32s8 = LLT::fixed_vector(32, 8);
73 const LLT v16s16 = LLT::fixed_vector(16, 16);
74 const LLT v8s32 = LLT::fixed_vector(8, 32);
75 const LLT v4s64 = LLT::fixed_vector(4, 64);
76 const LLT v4p0 = LLT::fixed_vector(4, p0);
77
78 const LLT v64s8 = LLT::fixed_vector(64, 8);
79 const LLT v32s16 = LLT::fixed_vector(32, 16);
80 const LLT v16s32 = LLT::fixed_vector(16, 32);
81 const LLT v8s64 = LLT::fixed_vector(8, 64);
82
83 const LLT s8MaxVector = HasAVX512 ? v64s8 : HasAVX ? v32s8 : v16s8;
84 const LLT s16MaxVector = HasAVX512 ? v32s16 : HasAVX ? v16s16 : v8s16;
85 const LLT s32MaxVector = HasAVX512 ? v16s32 : HasAVX ? v8s32 : v4s32;
86 const LLT s64MaxVector = HasAVX512 ? v8s64 : HasAVX ? v4s64 : v2s64;
87
88 // todo: AVX512 bool vector predicate types
89
90 // implicit/constants
91 // 32/64-bits needs support for s64/s128 to handle cases:
92 // s64 = EXTEND (G_IMPLICIT_DEF s32) -> s64 = G_IMPLICIT_DEF
93 // s128 = EXTEND (G_IMPLICIT_DEF s32/s64) -> s128 = G_IMPLICIT_DEF
95 {G_IMPLICIT_DEF, G_PHI, G_FREEZE, G_CONSTANT_FOLD_BARRIER})
96 .legalFor({p0, s1, s8, s16, s32, s64})
97 .legalFor(UseX87, {s80})
98 .legalFor(Is64Bit, {s128})
99 .legalFor(HasSSE2, {v16s8, v8s16, v4s32, v2s64})
100 .legalFor(HasAVX, {v32s8, v16s16, v8s32, v4s64})
101 .legalFor(HasAVX512, {v64s8, v32s16, v16s32, v8s64})
102 .widenScalarOrEltToNextPow2(0, /*Min=*/8)
103 .clampScalarOrElt(0, s8, sMaxScalar)
104 .moreElementsToNextPow2(0)
105 .clampNumElements(0, v16s8, s8MaxVector)
106 .clampNumElements(0, v8s16, s16MaxVector)
107 .clampNumElements(0, v4s32, s32MaxVector)
108 .clampNumElements(0, v2s64, s64MaxVector)
109 .clampMaxNumElements(0, p0,
110 Is64Bit ? s64MaxVector.getNumElements()
111 : s32MaxVector.getNumElements())
112 .scalarizeIf(scalarOrEltWiderThan(0, 64), 0);
113
115 .legalFor({p0, s8, s16, s32})
116 .legalFor(Is64Bit, {s64})
117 .widenScalarToNextPow2(0, /*Min=*/8)
118 .clampScalar(0, s8, sMaxScalar);
119
120 getActionDefinitionsBuilder({G_LROUND, G_LLROUND})
121 .widenScalarIf(typeIs(1, s16),
122 [=](const LegalityQuery &) {
123 return std::pair<unsigned, LLT>(1, s32);
124 })
125 .libcall();
126
128 {G_FCOS, G_FCOSH, G_FACOS, G_FSIN, G_FSINH, G_FASIN, G_FTAN,
129 G_FTANH, G_FATAN, G_FATAN2, G_FPOW, G_FEXP, G_FEXP2, G_FEXP10,
130 G_FLOG, G_FLOG2, G_FLOG10, G_FPOWI, G_FSINCOS, G_FCEIL, G_FFLOOR})
131 .libcall();
132
134 .legalFor(UseX87 && !HasSSE1, {s32})
135 .legalFor(UseX87 && !HasSSE2, {s64})
136 .legalFor(UseX87, {s80})
137 .lower();
138
140 .legalFor(HasSSE1 || UseX87, {s32})
141 .legalFor(HasSSE2 || UseX87, {s64})
142 .legalFor(UseX87, {s80});
143
144 getActionDefinitionsBuilder({G_GET_ROUNDING, G_SET_ROUNDING})
145 .customFor({s32});
146
147 // merge/unmerge
148 for (unsigned Op : {G_MERGE_VALUES, G_UNMERGE_VALUES}) {
149 unsigned BigTyIdx = Op == G_MERGE_VALUES ? 0 : 1;
150 unsigned LitTyIdx = Op == G_MERGE_VALUES ? 1 : 0;
152 .widenScalarToNextPow2(LitTyIdx, /*Min=*/8)
153 .widenScalarToNextPow2(BigTyIdx, /*Min=*/16)
154 .minScalar(LitTyIdx, s8)
155 .minScalar(BigTyIdx, s32)
156 .legalIf([=](const LegalityQuery &Q) {
157 switch (Q.Types[BigTyIdx].getSizeInBits()) {
158 case 16:
159 case 32:
160 case 64:
161 case 128:
162 case 256:
163 case 512:
164 break;
165 default:
166 return false;
167 }
168 switch (Q.Types[LitTyIdx].getSizeInBits()) {
169 case 8:
170 case 16:
171 case 32:
172 case 64:
173 case 128:
174 case 256:
175 return true;
176 default:
177 return false;
178 }
179 });
180 }
181
182 getActionDefinitionsBuilder({G_UMIN, G_UMAX, G_SMIN, G_SMAX})
183 .widenScalarToNextPow2(0, /*Min=*/32)
184 .lower();
185
186 // integer addition/subtraction
187 getActionDefinitionsBuilder({G_ADD, G_SUB})
188 .legalFor({s8, s16, s32})
189 .legalFor(Is64Bit, {s64})
190 .legalFor(HasSSE2, {v16s8, v8s16, v4s32, v2s64})
191 .legalFor(HasAVX2, {v32s8, v16s16, v8s32, v4s64})
192 .legalFor(HasAVX512, {v16s32, v8s64})
193 .legalFor(HasBWI, {v64s8, v32s16})
194 .clampMinNumElements(0, s8, 16)
195 .clampMinNumElements(0, s16, 8)
196 .clampMinNumElements(0, s32, 4)
197 .clampMinNumElements(0, s64, 2)
198 .clampMaxNumElements(0, s8, HasBWI ? 64 : (HasAVX2 ? 32 : 16))
199 .clampMaxNumElements(0, s16, HasBWI ? 32 : (HasAVX2 ? 16 : 8))
200 .clampMaxNumElements(0, s32, HasAVX512 ? 16 : (HasAVX2 ? 8 : 4))
201 .clampMaxNumElements(0, s64, HasAVX512 ? 8 : (HasAVX2 ? 4 : 2))
202 .widenScalarToNextPow2(0, /*Min=*/32)
203 .clampScalar(0, s8, sMaxScalar)
204 .scalarize(0);
205
206 getActionDefinitionsBuilder({G_UADDE, G_UADDO, G_USUBE, G_USUBO})
207 .legalFor({{s8, s8}, {s16, s8}, {s32, s8}})
208 .legalFor(Is64Bit, {{s64, s8}})
209 .widenScalarToNextPow2(0, /*Min=*/32)
210 .clampScalar(0, s8, sMaxScalar)
211 .clampScalar(1, s8, s8)
212 .scalarize(0);
213
214 // integer multiply
216 .legalFor({s8, s16, s32})
217 .legalFor(Is64Bit, {s64})
218 .legalFor(HasSSE2, {v8s16})
219 .legalFor(HasSSE41, {v4s32})
220 .legalFor(HasAVX2, {v16s16, v8s32})
221 .legalFor(HasAVX512, {v16s32})
222 .legalFor(HasDQI, {v8s64})
223 .legalFor(HasDQI && HasVLX, {v2s64, v4s64})
224 .legalFor(HasBWI, {v32s16})
225 .clampMinNumElements(0, s16, 8)
226 .clampMinNumElements(0, s32, 4)
227 .clampMinNumElements(0, s64, HasVLX ? 2 : 8)
228 .clampMaxNumElements(0, s16, HasBWI ? 32 : (HasAVX2 ? 16 : 8))
229 .clampMaxNumElements(0, s32, HasAVX512 ? 16 : (HasAVX2 ? 8 : 4))
230 .clampMaxNumElements(0, s64, 8)
231 .widenScalarToNextPow2(0, /*Min=*/32)
232 .clampScalar(0, s8, sMaxScalar)
233 .scalarize(0);
234
235 getActionDefinitionsBuilder({G_SMULH, G_UMULH})
236 .legalFor({s8, s16, s32})
237 .legalFor(Is64Bit, {s64})
238 .widenScalarToNextPow2(0, /*Min=*/32)
239 .clampScalar(0, s8, sMaxScalar)
240 .scalarize(0);
241
242 // integer divisions
243 getActionDefinitionsBuilder({G_SDIV, G_SREM, G_UDIV, G_UREM})
244 .legalFor({s8, s16, s32})
245 .legalFor(Is64Bit, {s64})
246 .libcallFor({s64})
247 .clampScalar(0, s8, sMaxScalar);
248
249 // integer shifts
250 getActionDefinitionsBuilder({G_SHL, G_LSHR, G_ASHR})
251 .legalFor({{s8, s8}, {s16, s8}, {s32, s8}})
252 .legalFor(Is64Bit, {{s64, s8}})
253 .clampScalar(0, s8, sMaxScalar)
254 .clampScalar(1, s8, s8);
255
256 // integer logic
257 getActionDefinitionsBuilder({G_AND, G_OR, G_XOR})
258 .legalFor({s8, s16, s32})
259 .legalFor(Is64Bit, {s64})
260 .legalFor(HasSSE2, {v16s8, v8s16, v4s32, v2s64})
261 .legalFor(HasAVX, {v32s8, v16s16, v8s32, v4s64})
262 .legalFor(HasAVX512, {v64s8, v32s16, v16s32, v8s64})
263 .clampNumElements(0, v16s8, s8MaxVector)
264 .clampNumElements(0, v8s16, s16MaxVector)
265 .clampNumElements(0, v4s32, s32MaxVector)
266 .clampNumElements(0, v2s64, s64MaxVector)
267 .widenScalarToNextPow2(0, /*Min=*/32)
268 .clampScalar(0, s8, sMaxScalar)
269 .scalarize(0);
270
271 // integer comparison
272 const std::initializer_list<LLT> IntTypes32 = {s8, s16, s32, p0};
273 const std::initializer_list<LLT> IntTypes64 = {s8, s16, s32, s64, p0};
274
276 .legalForCartesianProduct({s8}, Is64Bit ? IntTypes64 : IntTypes32)
277 .clampScalar(0, s8, s8)
278 .widenScalarToNextPow2(1, /*Min=*/8)
279 .clampScalar(1, s8, sMaxScalar);
280
281 // bswap
283 .legalFor({s32})
284 .legalFor(Is64Bit, {s64})
285 .widenScalarToNextPow2(0, /*Min=*/32)
286 .clampScalar(0, s32, sMaxScalar);
287
288 // popcount
290 .legalFor(HasPOPCNT, {{s16, s16}, {s32, s32}})
291 .legalFor(HasPOPCNT && Is64Bit, {{s64, s64}})
292 .widenScalarToNextPow2(1, /*Min=*/16)
293 .clampScalar(1, s16, sMaxScalar)
294 .scalarSameSizeAs(0, 1);
295
296 // count leading zeros (LZCNT)
298 .legalFor(HasLZCNT, {{s16, s16}, {s32, s32}})
299 .legalFor(HasLZCNT && Is64Bit, {{s64, s64}})
300 .widenScalarToNextPow2(1, /*Min=*/16)
301 .clampScalar(1, s16, sMaxScalar)
302 .scalarSameSizeAs(0, 1);
303
304 // count trailing zeros
305 getActionDefinitionsBuilder(G_CTTZ_ZERO_POISON)
306 .legalFor({{s16, s16}, {s32, s32}})
307 .legalFor(Is64Bit, {{s64, s64}})
308 .widenScalarToNextPow2(1, /*Min=*/16)
309 .clampScalar(1, s16, sMaxScalar)
310 .scalarSameSizeAs(0, 1);
311
313 .legalFor(HasBMI, {{s16, s16}, {s32, s32}})
314 .legalFor(HasBMI && Is64Bit, {{s64, s64}})
315 .widenScalarToNextPow2(1, /*Min=*/16)
316 .clampScalar(1, s16, sMaxScalar)
317 .scalarSameSizeAs(0, 1);
318
321
322 // pointer handling
323 const std::initializer_list<LLT> PtrTypes32 = {s1, s8, s16, s32};
324 const std::initializer_list<LLT> PtrTypes64 = {s1, s8, s16, s32, s64};
325
327 .legalForCartesianProduct(Is64Bit ? PtrTypes64 : PtrTypes32, {p0})
328 .maxScalar(0, sMaxScalar)
329 .widenScalarToNextPow2(0, /*Min*/ 8);
330
331 getActionDefinitionsBuilder(G_INTTOPTR).legalFor({{p0, sMaxScalar}});
332
333 getActionDefinitionsBuilder(G_CONSTANT_POOL).legalFor({p0});
334
336 .legalFor({{p0, s32}})
337 .legalFor(Is64Bit, {{p0, s64}})
338 .widenScalarToNextPow2(1, /*Min*/ 32)
339 .clampScalar(1, s32, sMaxScalar);
340
341 getActionDefinitionsBuilder(G_FRAME_INDEX).legalFor({p0});
342
343 getActionDefinitionsBuilder(G_GLOBAL_VALUE).customFor({p0});
344
345 // load/store: add more corner cases
346 for (unsigned Op : {G_LOAD, G_STORE}) {
347 auto &Action = getActionDefinitionsBuilder(Op);
348 Action.legalForTypesWithMemDesc({{s8, p0, s8, 1},
349 {s16, p0, s16, 1},
350 {s32, p0, s32, 1},
351 {s80, p0, s80, 1},
352 {p0, p0, p0, 1},
353 {v4s8, p0, v4s8, 1}});
354 if (Is64Bit)
355 Action.legalForTypesWithMemDesc(
356 {{s64, p0, s64, 1}, {v2s32, p0, v2s32, 1}});
357
358 if (HasSSE1)
359 Action.legalForTypesWithMemDesc({{v4s32, p0, v4s32, 1}});
360 if (HasSSE2)
361 Action.legalForTypesWithMemDesc({{v16s8, p0, v16s8, 1},
362 {v8s16, p0, v8s16, 1},
363 {v2s64, p0, v2s64, 1},
364 {v2p0, p0, v2p0, 1}});
365 if (HasAVX)
366 Action.legalForTypesWithMemDesc({{v32s8, p0, v32s8, 1},
367 {v16s16, p0, v16s16, 1},
368 {v8s32, p0, v8s32, 1},
369 {v4s64, p0, v4s64, 1},
370 {v4p0, p0, v4p0, 1}});
371 if (HasAVX512)
372 Action.legalForTypesWithMemDesc({{v64s8, p0, v64s8, 1},
373 {v32s16, p0, v32s16, 1},
374 {v16s32, p0, v16s32, 1},
375 {v8s64, p0, v8s64, 1}});
376
377 // X86 supports extending loads but not stores for GPRs
378 if (Op == G_LOAD) {
379 Action.legalForTypesWithMemDesc({{s8, p0, s1, 1},
380 {s16, p0, s8, 1},
381 {s32, p0, s8, 1},
382 {s32, p0, s16, 1}});
383 if (Is64Bit)
384 Action.legalForTypesWithMemDesc(
385 {{s64, p0, s8, 1}, {s64, p0, s16, 1}, {s64, p0, s32, 1}});
386 } else {
387 Action.customIf([=](const LegalityQuery &Query) {
388 return Query.Types[0] != Query.MMODescrs[0].MemoryTy;
389 });
390 }
391 Action.widenScalarToNextPow2(0, /*Min=*/8)
392 .clampScalar(0, s8, sMaxScalar)
393 .scalarize(0);
394 }
395
396 for (unsigned Op : {G_SEXTLOAD, G_ZEXTLOAD}) {
397 auto &Action = getActionDefinitionsBuilder(Op);
398 Action.legalForTypesWithMemDesc(
399 {{s16, p0, s8, 1}, {s32, p0, s8, 1}, {s32, p0, s16, 1}});
400 if (Is64Bit)
401 Action.legalForTypesWithMemDesc(
402 {{s64, p0, s8, 1}, {s64, p0, s16, 1}, {s64, p0, s32, 1}});
403 // TODO - SSE41/AVX2/AVX512F/AVX512BW vector extensions
404 }
405
406 for (unsigned Op : {G_FPEXTLOAD, G_FPTRUNCSTORE}) {
407 auto &Action = getActionDefinitionsBuilder(Op);
408 Action.legalForTypesWithMemDesc(
409 UseX87, {{s80, p0, s32, 1}, {s80, p0, s64, 1}, {s64, p0, s32, 1}});
410 }
411
412 // sext, zext, and anyext
414 .legalFor({s8, s16, s32, s128})
415 .legalFor(Is64Bit, {s64})
416 .widenScalarToNextPow2(0, /*Min=*/8)
417 .clampScalar(0, s8, sMaxScalar)
418 .widenScalarToNextPow2(1, /*Min=*/8)
419 .clampScalar(1, s8, sMaxScalar)
420 .scalarize(0);
421
422 getActionDefinitionsBuilder({G_SEXT, G_ZEXT})
423 .legalFor({s8, s16, s32})
424 .legalFor(Is64Bit, {s64})
425 .widenScalarToNextPow2(0, /*Min=*/8)
426 .clampScalar(0, s8, sMaxScalar)
427 .widenScalarToNextPow2(1, /*Min=*/8)
428 .clampScalar(1, s8, sMaxScalar)
429 .scalarize(0);
430
432 {s1, s8, s16, s32, s64}, {s8, s16, s32, s64, s128});
433
434 getActionDefinitionsBuilder(G_SEXT_INREG).lower();
435
436 // fp constants
437 getActionDefinitionsBuilder(G_FCONSTANT)
438 .legalFor({s32, s64})
439 .legalFor(UseX87, {s80});
440
441 // fp arithmetic
442 getActionDefinitionsBuilder({G_FADD, G_FSUB, G_FMUL, G_FDIV})
443 .legalFor({s32, s64})
444 .legalFor(HasSSE1, {v4s32})
445 .legalFor(HasSSE2, {v2s64})
446 .legalFor(HasAVX, {v8s32, v4s64})
447 .legalFor(HasAVX512, {v16s32, v8s64})
448 .legalFor(UseX87, {s80});
449
451 .legalFor(UseX87, {s80})
452 .legalFor(UseX87 && !Is64Bit, {s64})
453 .lower();
454
455 // fp comparison
457 .legalFor(HasSSE1 || UseX87, {s8, s32})
458 .legalFor(HasSSE2 || UseX87, {s8, s64})
459 .legalFor(UseX87, {s8, s80})
460 .clampScalar(0, s8, s8)
461 .clampScalar(1, s32, HasSSE2 ? s64 : s32)
463
464 // fp conversions
466 .legalFor(HasSSE2, {{s64, s32}})
467 .legalFor(HasAVX, {{v4s64, v4s32}})
468 .legalFor(HasAVX512, {{v8s64, v8s32}})
469 .lowerFor(UseX87, {{s64, s32}, {s80, s32}, {s80, s64}})
470 .libcall();
471
473 .legalFor(HasSSE2, {{s32, s64}})
474 .legalFor(HasAVX, {{v4s32, v4s64}})
475 .legalFor(HasAVX512, {{v8s32, v8s64}})
476 .lowerFor(UseX87, {{s32, s64}, {s32, s80}, {s64, s80}});
477
479 .legalFor(HasSSE1, {{s32, s32}})
480 .legalFor(HasSSE1 && Is64Bit, {{s32, s64}})
481 .legalFor(HasSSE2, {{s64, s32}})
482 .legalFor(HasSSE2 && Is64Bit, {{s64, s64}})
483 .clampScalar(1, (UseX87 && !HasSSE1) ? s16 : s32, sMaxScalar)
485 .customForCartesianProduct(UseX87, {s32, s64, s80}, {s16, s32, s64})
486 .clampScalar(0, s32, HasSSE2 ? s64 : s32)
488
490 .legalFor(HasSSE1, {{s32, s32}})
491 .legalFor(HasSSE1 && Is64Bit, {{s64, s32}})
492 .legalFor(HasSSE2, {{s32, s64}})
493 .legalFor(HasSSE2 && Is64Bit, {{s64, s64}})
494 .clampScalar(0, (UseX87 && !HasSSE1) ? s16 : s32, sMaxScalar)
496 .customForCartesianProduct(UseX87, {s16, s32, s64}, {s32, s64, s80})
497 .clampScalar(1, s32, HasSSE2 ? s64 : s32)
499
500 // For G_UITOFP and G_FPTOUI without AVX512, we have to custom legalize types
501 // <= s32 manually. Otherwise, in custom handler there is no way to
502 // understand whether s32 is an original type and we need to promote it to
503 // s64 or s32 is obtained after widening and we shouldn't widen it to s64.
504 //
505 // For AVX512 we simply widen types as there is direct mapping from opcodes
506 // to asm instructions.
508 .legalFor(HasAVX512, {{s32, s32}, {s32, s64}, {s64, s32}, {s64, s64}})
509 .customIf([=](const LegalityQuery &Query) {
510 return !HasAVX512 &&
511 ((HasSSE1 && typeIs(0, s32)(Query)) ||
512 (HasSSE2 && typeIs(0, s64)(Query))) &&
513 scalarNarrowerThan(1, Is64Bit ? 64 : 32)(Query);
514 })
515 .lowerIf([=](const LegalityQuery &Query) {
516 // Lower conversions from s64
517 return !HasAVX512 &&
518 ((HasSSE1 && typeIs(0, s32)(Query)) ||
519 (HasSSE2 && typeIs(0, s64)(Query))) &&
520 (Is64Bit && typeIs(1, s64)(Query));
521 })
522 .clampScalar(0, s32, HasSSE2 ? s64 : s32)
524 .clampScalar(1, s32, sMaxScalar)
526
528 .legalFor(HasAVX512, {{s32, s32}, {s32, s64}, {s64, s32}, {s64, s64}})
529 .customIf([=](const LegalityQuery &Query) {
530 return !HasAVX512 &&
531 ((HasSSE1 && typeIs(1, s32)(Query)) ||
532 (HasSSE2 && typeIs(1, s64)(Query))) &&
533 scalarNarrowerThan(0, Is64Bit ? 64 : 32)(Query);
534 })
535 // TODO: replace with customized legalization using
536 // specifics of cvttsd2si. The selection of this node requires
537 // a vector type. Either G_SCALAR_TO_VECTOR is needed or more advanced
538 // support of G_BUILD_VECTOR/G_INSERT_VECTOR_ELT is required beforehand.
539 .lowerIf([=](const LegalityQuery &Query) {
540 return !HasAVX512 &&
541 ((HasSSE1 && typeIs(1, s32)(Query)) ||
542 (HasSSE2 && typeIs(1, s64)(Query))) &&
543 (Is64Bit && typeIs(0, s64)(Query));
544 })
545 .clampScalar(0, s32, sMaxScalar)
547 .clampScalar(1, s32, HasSSE2 ? s64 : s32)
549
550 // vector ops
551 getActionDefinitionsBuilder(G_BUILD_VECTOR)
552 .customIf([=](const LegalityQuery &Query) {
553 return (HasSSE1 && typeInSet(0, {v4s32})(Query)) ||
554 (HasSSE2 && typeInSet(0, {v2s64, v8s16, v16s8})(Query)) ||
555 (HasAVX && typeInSet(0, {v4s64, v8s32, v16s16, v32s8})(Query)) ||
556 (HasAVX512 &&
557 typeInSet(0, {v8s64, v16s32, v32s16, v64s8})(Query));
558 })
559 .clampNumElements(0, v16s8, s8MaxVector)
560 .clampNumElements(0, v8s16, s16MaxVector)
561 .clampNumElements(0, v4s32, s32MaxVector)
562 .clampNumElements(0, v2s64, s64MaxVector)
564
565 getActionDefinitionsBuilder({G_EXTRACT, G_INSERT})
566 .legalIf([=](const LegalityQuery &Query) {
567 unsigned SubIdx = Query.Opcode == G_EXTRACT ? 0 : 1;
568 unsigned FullIdx = Query.Opcode == G_EXTRACT ? 1 : 0;
569 return (HasAVX && typePairInSet(SubIdx, FullIdx,
570 {{v16s8, v32s8},
571 {v8s16, v16s16},
572 {v4s32, v8s32},
573 {v2s64, v4s64}})(Query)) ||
574 (HasAVX512 && typePairInSet(SubIdx, FullIdx,
575 {{v16s8, v64s8},
576 {v32s8, v64s8},
577 {v8s16, v32s16},
578 {v16s16, v32s16},
579 {v4s32, v16s32},
580 {v8s32, v16s32},
581 {v2s64, v8s64},
582 {v4s64, v8s64}})(Query));
583 });
584
585 // todo: only permit dst types up to max legal vector register size?
586 getActionDefinitionsBuilder(G_CONCAT_VECTORS)
587 .legalFor(
588 HasSSE1,
589 {{v32s8, v16s8}, {v16s16, v8s16}, {v8s32, v4s32}, {v4s64, v2s64}})
590 .legalFor(HasAVX, {{v64s8, v16s8},
591 {v64s8, v32s8},
592 {v32s16, v8s16},
593 {v32s16, v16s16},
594 {v16s32, v4s32},
595 {v16s32, v8s32},
596 {v8s64, v2s64},
597 {v8s64, v4s64}});
598
599 // todo: vectors and address spaces
601 .legalFor({{s16, s32}, {s32, s32}, {p0, s32}})
602 .legalFor(!HasCMOV, {{s8, s32}})
603 .legalFor(Is64Bit, {{s64, s32}})
604 .legalFor(UseX87, {{s80, s32}})
605 .clampScalar(1, s32, s32)
606 .widenScalarToNextPow2(0, /*Min=*/8)
607 .clampScalar(0, HasCMOV ? s16 : s8, sMaxScalar);
608
609 // memory intrinsics
610 getActionDefinitionsBuilder({G_MEMCPY, G_MEMMOVE, G_MEMSET}).libcall();
611
612 getActionDefinitionsBuilder({G_DYN_STACKALLOC, G_STACKSAVE, G_STACKRESTORE})
613 .lower();
614
615 // fp intrinsics
616 // fpclass for i686 is disabled for llvm issue #171992
617 getActionDefinitionsBuilder(G_IS_FPCLASS)
618 .lowerFor(Is64Bit, {{s1, s32}, {s1, s64}, {s1, s80}});
619
620 getActionDefinitionsBuilder({G_INTRINSIC_ROUNDEVEN, G_INTRINSIC_TRUNC})
621 .scalarize(0)
622 .minScalar(0, LLT::scalar(32))
623 .libcall();
624
625 getActionDefinitionsBuilder({G_INTRINSIC, G_INTRINSIC_W_SIDE_EFFECTS})
626 .alwaysLegal();
627 getActionDefinitionsBuilder({G_TRAP, G_DEBUGTRAP, G_UBSANTRAP}).alwaysLegal();
628 getActionDefinitionsBuilder(G_INVOKE_REGION_START).alwaysLegal();
629
630 verify(*STI.getInstrInfo());
631}
632
634 LostDebugLocObserver &LocObserver) const {
635 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
636 MachineRegisterInfo &MRI = *MIRBuilder.getMRI();
637 switch (MI.getOpcode()) {
638 default:
639 // No idea what to do.
640 return false;
641 case TargetOpcode::G_BUILD_VECTOR:
642 return legalizeBuildVector(MI, MRI, Helper);
643 case TargetOpcode::G_FPTOUI:
644 return legalizeFPTOUI(MI, MRI, Helper);
645 case TargetOpcode::G_UITOFP:
646 return legalizeUITOFP(MI, MRI, Helper);
647 case TargetOpcode::G_STORE:
648 return legalizeNarrowingStore(MI, MRI, Helper);
649 case TargetOpcode::G_SITOFP:
650 return legalizeSITOFP(MI, MRI, Helper);
651 case TargetOpcode::G_FPTOSI:
652 return legalizeFPTOSI(MI, MRI, Helper);
653 case TargetOpcode::G_GET_ROUNDING:
654 return legalizeGETROUNDING(MI, MRI, Helper);
655 case TargetOpcode::G_SET_ROUNDING:
656 return legalizeSETROUNDING(MI, MRI, Helper);
657 case TargetOpcode::G_GLOBAL_VALUE:
658 return legalizeGLOBAL_VALUE(MI, MRI, Helper);
659 }
660 llvm_unreachable("expected switch to return");
661}
662
663bool X86LegalizerInfo::legalizeSITOFP(MachineInstr &MI,
665 LegalizerHelper &Helper) const {
666 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
667 MachineFunction &MF = *MI.getMF();
668 auto [Dst, DstTy, Src, SrcTy] = MI.getFirst2RegLLTs();
669
670 assert((SrcTy.getSizeInBits() == 16 || SrcTy.getSizeInBits() == 32 ||
671 SrcTy.getSizeInBits() == 64) &&
672 "Unexpected source type for SITOFP in X87 mode.");
673
674 TypeSize MemSize = SrcTy.getSizeInBytes();
675 MachinePointerInfo PtrInfo;
676 Align Alignmt = Helper.getStackTemporaryAlignment(SrcTy);
677 auto SlotPointer = Helper.createStackTemporary(MemSize, Alignmt, PtrInfo);
679 PtrInfo, MachineMemOperand::MOStore, MemSize, Align(MemSize));
680
681 // Store the integer value on the FPU stack.
682 MIRBuilder.buildStore(Src, SlotPointer, *StoreMMO);
683
685 PtrInfo, MachineMemOperand::MOLoad, MemSize, Align(MemSize));
686 MIRBuilder.buildInstr(X86::G_FILD)
687 .addDef(Dst)
688 .addUse(SlotPointer.getReg(0))
689 .addMemOperand(LoadMMO);
690
691 MI.eraseFromParent();
692 return true;
693}
694
695bool X86LegalizerInfo::legalizeFPTOSI(MachineInstr &MI,
697 LegalizerHelper &Helper) const {
698 MachineFunction &MF = *MI.getMF();
699 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
700 auto [Dst, DstTy, Src, SrcTy] = MI.getFirst2RegLLTs();
701
702 TypeSize MemSize = DstTy.getSizeInBytes();
703 MachinePointerInfo PtrInfo;
704 Align Alignmt = Helper.getStackTemporaryAlignment(DstTy);
705 auto SlotPointer = Helper.createStackTemporary(MemSize, Alignmt, PtrInfo);
707 PtrInfo, MachineMemOperand::MOStore, MemSize, Align(MemSize));
708
709 MIRBuilder.buildInstr(X86::G_FIST)
710 .addUse(Src)
711 .addUse(SlotPointer.getReg(0))
712 .addMemOperand(StoreMMO);
713
714 MIRBuilder.buildLoad(Dst, SlotPointer, PtrInfo, Align(MemSize));
715 MI.eraseFromParent();
716 return true;
717}
718
719bool X86LegalizerInfo::legalizeBuildVector(MachineInstr &MI,
721 LegalizerHelper &Helper) const {
722 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
723 const auto &BuildVector = cast<GBuildVector>(MI);
724 Register Dst = BuildVector.getReg(0);
725 LLT DstTy = MRI.getType(Dst);
726 MachineFunction &MF = MIRBuilder.getMF();
727 LLVMContext &Ctx = MF.getFunction().getContext();
728 uint64_t DstTySize = DstTy.getScalarSizeInBits();
729
730 SmallVector<Constant *, 4> CstIdxs;
731 for (unsigned i = 0; i < BuildVector.getNumSources(); ++i) {
732 Register Source = BuildVector.getSourceReg(i);
733
734 auto ValueAndReg = getIConstantVRegValWithLookThrough(Source, MRI);
735 if (ValueAndReg) {
736 CstIdxs.emplace_back(ConstantInt::get(Ctx, ValueAndReg->Value));
737 continue;
738 }
739
740 auto FPValueAndReg = getFConstantVRegValWithLookThrough(Source, MRI);
741 if (FPValueAndReg) {
742 CstIdxs.emplace_back(ConstantFP::get(Ctx, FPValueAndReg->Value));
743 continue;
744 }
745
746 if (getOpcodeDef<GImplicitDef>(Source, MRI)) {
747 CstIdxs.emplace_back(UndefValue::get(Type::getIntNTy(Ctx, DstTySize)));
748 continue;
749 }
750 return false;
751 }
752
753 Constant *ConstVal = ConstantVector::get(CstIdxs);
754
755 const DataLayout &DL = MIRBuilder.getDataLayout();
756 unsigned AddrSpace = DL.getDefaultGlobalsAddressSpace();
757 Align Alignment(DL.getABITypeAlign(ConstVal->getType()));
758 auto Addr = MIRBuilder.buildConstantPool(
759 LLT::pointer(AddrSpace, DL.getPointerSizeInBits(AddrSpace)),
760 MF.getConstantPool()->getConstantPoolIndex(ConstVal, Alignment));
761 MachineMemOperand *MMO =
763 MachineMemOperand::MOLoad, DstTy, Alignment);
764
765 MIRBuilder.buildLoad(Dst, Addr, *MMO);
766 MI.eraseFromParent();
767 return true;
768}
769
770bool X86LegalizerInfo::legalizeFPTOUI(MachineInstr &MI,
772 LegalizerHelper &Helper) const {
773 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
774 auto [Dst, DstTy, Src, SrcTy] = MI.getFirst2RegLLTs();
775 unsigned DstSizeInBits = DstTy.getScalarSizeInBits();
776 const LLT s32 = LLT::scalar(32);
777 const LLT s64 = LLT::scalar(64);
778
779 // Simply reuse FPTOSI when it is possible to widen the type
780 if (DstSizeInBits <= 32) {
781 auto Casted = MIRBuilder.buildFPTOSI(DstTy == s32 ? s64 : s32, Src);
782 MIRBuilder.buildTrunc(Dst, Casted);
783 MI.eraseFromParent();
784 return true;
785 }
786
787 return false;
788}
789
790bool X86LegalizerInfo::legalizeUITOFP(MachineInstr &MI,
792 LegalizerHelper &Helper) const {
793 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
794 auto [Dst, DstTy, Src, SrcTy] = MI.getFirst2RegLLTs();
795 const LLT s32 = LLT::scalar(32);
796 const LLT s64 = LLT::scalar(64);
797
798 // Simply reuse SITOFP when it is possible to widen the type
799 if (SrcTy.getSizeInBits() <= 32) {
800 auto Ext = MIRBuilder.buildZExt(SrcTy == s32 ? s64 : s32, Src);
801 MIRBuilder.buildSITOFP(Dst, Ext);
802 MI.eraseFromParent();
803 return true;
804 }
805
806 return false;
807}
808
809bool X86LegalizerInfo::legalizeNarrowingStore(MachineInstr &MI,
811 LegalizerHelper &Helper) const {
812 auto &Store = cast<GStore>(MI);
813 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
814 MachineMemOperand &MMO = **Store.memoperands_begin();
815 MachineFunction &MF = MIRBuilder.getMF();
816 LLT ValTy = MRI.getType(Store.getValueReg());
817 auto *NewMMO = MF.getMachineMemOperand(&MMO, MMO.getPointerInfo(), ValTy);
818
820 Store.setMemRefs(MF, {NewMMO});
822 return true;
823}
824
825bool X86LegalizerInfo::legalizeGETROUNDING(MachineInstr &MI,
827 LegalizerHelper &Helper) const {
828 /*
829 The rounding mode is in bits 11:10 of FPSR, and has the following
830 settings:
831 00 Round to nearest
832 01 Round to -inf
833 10 Round to +inf
834 11 Round to 0
835
836 GET_ROUNDING, on the other hand, expects the following:
837 -1 Undefined
838 0 Round to 0
839 1 Round to nearest
840 2 Round to +inf
841 3 Round to -inf
842
843 To perform the conversion, we use a packed lookup table of the four 2-bit
844 values that we can index by FPSP[11:10]
845 0x2d --> (0b00,10,11,01) --> (0,2,3,1) >> FPSR[11:10]
846
847 (0x2d >> ((FPSR >> 9) & 6)) & 3
848 */
849
850 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
851 MachineFunction &MF = MIRBuilder.getMF();
852 Register Dst = MI.getOperand(0).getReg();
853 LLT DstTy = MRI.getType(Dst);
854 const LLT s8 = LLT::scalar(8);
855 const LLT s16 = LLT::scalar(16);
856 const LLT s32 = LLT::scalar(32);
857
858 // Save FP Control Word to stack slot
859 int MemSize = 2;
860 Align Alignment = Align(2);
861 MachinePointerInfo PtrInfo;
862 auto StackTemp = Helper.createStackTemporary(TypeSize::getFixed(MemSize),
863 Alignment, PtrInfo);
864 Register StackPtr = StackTemp.getReg(0);
865
866 auto StoreMMO = MF.getMachineMemOperand(PtrInfo, MachineMemOperand::MOStore,
867 MemSize, Alignment);
868
869 // Store FP Control Word to stack slot using G_FNSTCW16
870 MIRBuilder.buildInstr(X86::G_FNSTCW16)
871 .addUse(StackPtr)
872 .addMemOperand(StoreMMO);
873
874 // Load FP Control Word from stack slot
875 auto LoadMMO = MF.getMachineMemOperand(PtrInfo, MachineMemOperand::MOLoad,
876 MemSize, Alignment);
877
878 auto CWD32 =
879 MIRBuilder.buildZExt(s32, MIRBuilder.buildLoad(s16, StackPtr, *LoadMMO));
880 auto Shifted8 = MIRBuilder.buildTrunc(
881 s8, MIRBuilder.buildLShr(s32, CWD32, MIRBuilder.buildConstant(s8, 9)));
882 auto Masked32 = MIRBuilder.buildZExt(
883 s32, MIRBuilder.buildAnd(s8, Shifted8, MIRBuilder.buildConstant(s8, 6)));
884
885 // LUT is a packed lookup table (0x2d) used to map the 2-bit x87 FPU rounding
886 // mode (from bits 11:10 of the control word) to the values expected by
887 // GET_ROUNDING. The mapping is performed by shifting LUT right by the
888 // extracted rounding mode and masking the result with 3 to obtain the final
889 auto LUT = MIRBuilder.buildConstant(s32, 0x2d);
890 auto LUTShifted = MIRBuilder.buildLShr(s32, LUT, Masked32);
891 auto RetVal =
892 MIRBuilder.buildAnd(s32, LUTShifted, MIRBuilder.buildConstant(s32, 3));
893 auto RetValTrunc = MIRBuilder.buildZExtOrTrunc(DstTy, RetVal);
894
895 MIRBuilder.buildCopy(Dst, RetValTrunc);
896
897 MI.eraseFromParent();
898 return true;
899}
900
901bool X86LegalizerInfo::legalizeSETROUNDING(MachineInstr &MI,
903 LegalizerHelper &Helper) const {
904 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
905 MachineFunction &MF = MIRBuilder.getMF();
906 Register Src = MI.getOperand(0).getReg();
907 const LLT s8 = LLT::scalar(8);
908 const LLT s16 = LLT::scalar(16);
909 const LLT s32 = LLT::scalar(32);
910
911 // Allocate stack slot for control word and MXCSR (4 bytes).
912 int MemSize = 4;
913 Align Alignment = Align(4);
914 MachinePointerInfo PtrInfo;
915 auto StackTemp = Helper.createStackTemporary(TypeSize::getFixed(MemSize),
916 Alignment, PtrInfo);
917 Register StackPtr = StackTemp.getReg(0);
918
919 auto StoreMMO =
921 MIRBuilder.buildInstr(X86::G_FNSTCW16)
922 .addUse(StackPtr)
923 .addMemOperand(StoreMMO);
924
925 auto LoadMMO =
927 auto CWD16 = MIRBuilder.buildLoad(s16, StackPtr, *LoadMMO);
928
929 // Clear RM field (bits 11:10)
930 auto ClearedCWD =
931 MIRBuilder.buildAnd(s16, CWD16, MIRBuilder.buildConstant(s16, 0xf3ff));
932
933 // Check if Src is a constant
934 Register RMBits;
935 Register MXCSRRMBits;
936
937 APInt SrcCst;
938 if (mi_match(Src, MRI, m_ICst(SrcCst))) {
939 uint64_t RM = SrcCst.getZExtValue();
940 int FieldVal = X86::getRoundingModeX86(RM);
941
942 if (FieldVal == X86::rmInvalid) {
943 FieldVal = X86::rmToNearest;
944 LLVMContext &C = MF.getFunction().getContext();
945 C.diagnose(DiagnosticInfoUnsupported(
946 MF.getFunction(), "rounding mode is not supported by X86 hardware",
947 DiagnosticLocation(MI.getDebugLoc()), DS_Error));
948 return false;
949 }
950
951 FieldVal = FieldVal << 3;
952 RMBits = MIRBuilder.buildConstant(s16, FieldVal).getReg(0);
953 MXCSRRMBits = MIRBuilder.buildConstant(s32, FieldVal).getReg(0);
954 } else {
955 // Convert Src (rounding mode) to bits for control word
956 // (0xc9 << (2 * Src + 4)) & 0xc00
957 auto Src32 = MIRBuilder.buildZExtOrTrunc(s32, Src);
958 auto ShiftAmt = MIRBuilder.buildAdd(
959 s32, MIRBuilder.buildShl(s32, Src32, MIRBuilder.buildConstant(s32, 1)),
960 MIRBuilder.buildConstant(s32, 4));
961 auto ShiftAmt8 = MIRBuilder.buildTrunc(s8, ShiftAmt);
962 auto Shifted = MIRBuilder.buildShl(s16, MIRBuilder.buildConstant(s16, 0xc9),
963 ShiftAmt8);
964 RMBits =
965 MIRBuilder.buildAnd(s16, Shifted, MIRBuilder.buildConstant(s16, 0xc00))
966 .getReg(0);
967
968 // For non-constant case, we still need to compute MXCSR bits dynamically
969 auto RMBits32 = MIRBuilder.buildZExt(s32, RMBits);
970 MXCSRRMBits =
971 MIRBuilder.buildShl(s32, RMBits32, MIRBuilder.buildConstant(s32, 3))
972 .getReg(0);
973 }
974 // Update rounding mode bits
975 auto NewCWD =
976 MIRBuilder.buildOr(s16, ClearedCWD, RMBits, MachineInstr::Disjoint);
977
978 // Store new FP Control Word to stack
979 auto StoreNewMMO =
981 MIRBuilder.buildStore(NewCWD, StackPtr, *StoreNewMMO);
982
983 // Load FP control word from the slot using G_FLDCW16
984 auto LoadNewMMO =
986 MIRBuilder.buildInstr(X86::G_FLDCW16)
987 .addUse(StackPtr)
988 .addMemOperand(LoadNewMMO);
989
990 if (Subtarget.hasSSE1()) {
991 // Store MXCSR to stack (use STMXCSR)
992 auto StoreMXCSRMMO = MF.getMachineMemOperand(
993 PtrInfo, MachineMemOperand::MOStore, 4, Align(4));
994 MIRBuilder.buildInstr(TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS)
995 .addIntrinsicID(Intrinsic::x86_sse_stmxcsr)
996 .addUse(StackPtr)
997 .addMemOperand(StoreMXCSRMMO);
998
999 // Load MXCSR from stack
1000 auto LoadMXCSRMMO = MF.getMachineMemOperand(
1001 PtrInfo, MachineMemOperand::MOLoad, 4, Align(4));
1002 auto MXCSR = MIRBuilder.buildLoad(s32, StackPtr, *LoadMXCSRMMO);
1003
1004 // Clear RM field (bits 14:13)
1005 auto ClearedMXCSR = MIRBuilder.buildAnd(
1006 s32, MXCSR, MIRBuilder.buildConstant(s32, 0xffff9fff));
1007
1008 // Update rounding mode bits
1009 auto NewMXCSR = MIRBuilder.buildOr(s32, ClearedMXCSR, MXCSRRMBits);
1010
1011 // Store new MXCSR to stack
1012 auto StoreNewMXCSRMMO = MF.getMachineMemOperand(
1013 PtrInfo, MachineMemOperand::MOStore, 4, Align(4));
1014 MIRBuilder.buildStore(NewMXCSR, StackPtr, *StoreNewMXCSRMMO);
1015
1016 // Load MXCSR from stack (use LDMXCSR)
1017 auto LoadNewMXCSRMMO = MF.getMachineMemOperand(
1018 PtrInfo, MachineMemOperand::MOLoad, 4, Align(4));
1019 MIRBuilder.buildInstr(TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS)
1020 .addIntrinsicID(Intrinsic::x86_sse_ldmxcsr)
1021 .addUse(StackPtr)
1022 .addMemOperand(LoadNewMXCSRMMO);
1023 }
1024
1025 MI.eraseFromParent();
1026 return true;
1027}
1028
1029bool X86LegalizerInfo::legalizeGLOBAL_VALUE(MachineInstr &MI,
1031 LegalizerHelper &Helper) const {
1032 const GlobalValue *GV = MI.getOperand(1).getGlobal();
1033 Register Dst = MI.getOperand(0).getReg();
1034 LLT DstTy = MRI.getType(Dst);
1035 unsigned GVOpFlags = Subtarget.classifyGlobalReference(GV);
1036
1037 // For stub references (GOT/PLT), we need G_WRAPPER_RIP + load
1038 if (isGlobalStubReference(GVOpFlags)) {
1039 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
1040 MachineFunction &MF = MIRBuilder.getMF();
1041
1042 Register StubAddr = MRI.createGenericVirtualRegister(DstTy);
1043 MIRBuilder.buildInstr(X86::G_WRAPPER_RIP)
1044 .addDef(StubAddr)
1045 .addGlobalAddress(GV);
1046
1047 MachineMemOperand *MMO = MF.getMachineMemOperand(
1049 Align(DstTy.getSizeInBytes()));
1050 MIRBuilder.buildLoad(Dst, StubAddr, *MMO);
1051 MI.eraseFromParent();
1052 }
1053 return true;
1054}
1055
1057 MachineInstr &MI) const {
1058 return true;
1059}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
unsigned uint64_t
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
static GCRegistry::Add< ShadowStackGC > C("shadow-stack", "Very portable GC for uncooperative code generators")
static void scalarize(Instruction *I, SmallVectorImpl< Instruction * > &Worklist)
Declares convenience wrapper classes for interpreting MachineInstr instances as specific generic oper...
IRTranslator LLVM IR MI
Contains matchers for matching SSA Machine Instructions.
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:1561
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:353
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.
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.
LLVM_ABI unsigned getConstantPoolIndex(const Constant *C, Align Alignment)
getConstantPoolIndex - Create a new entry in the constant pool or return an existing one.
Function & getFunction()
Return the LLVM function that this machine code represents.
MachineConstantPool * getConstantPool()
getConstantPool - Return the constant pool object for the current function.
MachineMemOperand * getMachineMemOperand(MachinePointerInfo PtrInfo, MachineMemOperand::Flags F, LLT MemTy, Align BaseAlignment, const MMOMetadata &Metadata=MMOMetadata(), SyncScope::ID SSID=SyncScope::System, AtomicOrdering Ordering=AtomicOrdering::NotAtomic, AtomicOrdering FailureOrdering=AtomicOrdering::NotAtomic)
getMachineMemOperand - Allocate a new MachineMemOperand.
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,...
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.
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.
ConstantMatch< APInt > m_ICst(APInt &Cst)
bool mi_match(Reg R, const MachineRegisterInfo &MRI, Pattern &&P)
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
@ Store
The extracted value is stored (ExtractElement only).
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.