LLVM 22.0.0git
X86LegalizerInfo.cpp
Go to the documentation of this file.
1//===- X86LegalizerInfo.cpp --------------------------------------*- C++ -*-==//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8/// \file
9/// This file implements the targeting of the Machinelegalizer class for X86.
10/// \todo This should be generated by TableGen.
11//===----------------------------------------------------------------------===//
12
13#include "X86LegalizerInfo.h"
14#include "X86Subtarget.h"
15#include "X86TargetMachine.h"
24#include "llvm/IR/IntrinsicsX86.h"
25#include "llvm/IR/Type.h"
26
27using namespace llvm;
28using namespace TargetOpcode;
29using namespace LegalizeActions;
30using namespace LegalityPredicates;
31
33 const X86TargetMachine &TM)
34 : Subtarget(STI) {
35
36 bool Is64Bit = Subtarget.is64Bit();
37 bool HasCMOV = Subtarget.canUseCMOV();
38 bool HasSSE1 = Subtarget.hasSSE1();
39 bool HasSSE2 = Subtarget.hasSSE2();
40 bool HasSSE41 = Subtarget.hasSSE41();
41 bool HasAVX = Subtarget.hasAVX();
42 bool HasAVX2 = Subtarget.hasAVX2();
43 bool HasAVX512 = Subtarget.hasAVX512();
44 bool HasVLX = Subtarget.hasVLX();
45 bool HasDQI = Subtarget.hasAVX512() && Subtarget.hasDQI();
46 bool HasBWI = Subtarget.hasAVX512() && Subtarget.hasBWI();
47 bool UseX87 = !Subtarget.useSoftFloat() && Subtarget.hasX87();
48 bool HasPOPCNT = Subtarget.hasPOPCNT();
49 bool HasLZCNT = Subtarget.hasLZCNT();
50 bool HasBMI = Subtarget.hasBMI();
51
52 const LLT p0 = LLT::pointer(0, TM.getPointerSizeInBits(0));
53 const LLT s1 = LLT::scalar(1);
54 const LLT s8 = LLT::scalar(8);
55 const LLT s16 = LLT::scalar(16);
56 const LLT s32 = LLT::scalar(32);
57 const LLT s64 = LLT::scalar(64);
58 const LLT s80 = LLT::scalar(80);
59 const LLT s128 = LLT::scalar(128);
60 const LLT sMaxScalar = Subtarget.is64Bit() ? s64 : s32;
61 const LLT v2s32 = LLT::fixed_vector(2, 32);
62 const LLT v4s8 = LLT::fixed_vector(4, 8);
63
64 const LLT v16s8 = LLT::fixed_vector(16, 8);
65 const LLT v8s16 = LLT::fixed_vector(8, 16);
66 const LLT v4s32 = LLT::fixed_vector(4, 32);
67 const LLT v2s64 = LLT::fixed_vector(2, 64);
68 const LLT v2p0 = LLT::fixed_vector(2, p0);
69
70 const LLT v32s8 = LLT::fixed_vector(32, 8);
71 const LLT v16s16 = LLT::fixed_vector(16, 16);
72 const LLT v8s32 = LLT::fixed_vector(8, 32);
73 const LLT v4s64 = LLT::fixed_vector(4, 64);
74 const LLT v4p0 = LLT::fixed_vector(4, p0);
75
76 const LLT v64s8 = LLT::fixed_vector(64, 8);
77 const LLT v32s16 = LLT::fixed_vector(32, 16);
78 const LLT v16s32 = LLT::fixed_vector(16, 32);
79 const LLT v8s64 = LLT::fixed_vector(8, 64);
80
81 const LLT s8MaxVector = HasAVX512 ? v64s8 : HasAVX ? v32s8 : v16s8;
82 const LLT s16MaxVector = HasAVX512 ? v32s16 : HasAVX ? v16s16 : v8s16;
83 const LLT s32MaxVector = HasAVX512 ? v16s32 : HasAVX ? v8s32 : v4s32;
84 const LLT s64MaxVector = HasAVX512 ? v8s64 : HasAVX ? v4s64 : v2s64;
85
86 // todo: AVX512 bool vector predicate types
87
88 // implicit/constants
89 // 32/64-bits needs support for s64/s128 to handle cases:
90 // s64 = EXTEND (G_IMPLICIT_DEF s32) -> s64 = G_IMPLICIT_DEF
91 // s128 = EXTEND (G_IMPLICIT_DEF s32/s64) -> s128 = G_IMPLICIT_DEF
92 getActionDefinitionsBuilder(G_IMPLICIT_DEF)
93 .legalFor({p0, s1, s8, s16, s32, s64})
94 .legalFor(Is64Bit, {s128});
95
97 .legalFor({p0, s8, s16, s32})
98 .legalFor(Is64Bit, {s64})
99 .widenScalarToNextPow2(0, /*Min=*/8)
100 .clampScalar(0, s8, sMaxScalar);
101
102 getActionDefinitionsBuilder({G_LROUND, G_LLROUND, G_FCOS, G_FCOSH, G_FACOS,
103 G_FSIN, G_FSINH, G_FASIN, G_FTAN, G_FTANH,
104 G_FATAN, G_FATAN2, G_FPOW, G_FEXP, G_FEXP2,
105 G_FEXP10, G_FLOG, G_FLOG2, G_FLOG10, G_FPOWI,
106 G_FSINCOS, G_FCEIL, G_FFLOOR})
107 .libcall();
108
110 .legalFor(HasSSE1 || UseX87, {s32})
111 .legalFor(HasSSE2 || UseX87, {s64})
112 .legalFor(UseX87, {s80});
113
114 getActionDefinitionsBuilder({G_GET_ROUNDING, G_SET_ROUNDING})
115 .customFor({s32});
116
117 // merge/unmerge
118 for (unsigned Op : {G_MERGE_VALUES, G_UNMERGE_VALUES}) {
119 unsigned BigTyIdx = Op == G_MERGE_VALUES ? 0 : 1;
120 unsigned LitTyIdx = Op == G_MERGE_VALUES ? 1 : 0;
122 .widenScalarToNextPow2(LitTyIdx, /*Min=*/8)
123 .widenScalarToNextPow2(BigTyIdx, /*Min=*/16)
124 .minScalar(LitTyIdx, s8)
125 .minScalar(BigTyIdx, s32)
126 .legalIf([=](const LegalityQuery &Q) {
127 switch (Q.Types[BigTyIdx].getSizeInBits()) {
128 case 16:
129 case 32:
130 case 64:
131 case 128:
132 case 256:
133 case 512:
134 break;
135 default:
136 return false;
137 }
138 switch (Q.Types[LitTyIdx].getSizeInBits()) {
139 case 8:
140 case 16:
141 case 32:
142 case 64:
143 case 128:
144 case 256:
145 return true;
146 default:
147 return false;
148 }
149 });
150 }
151
152 // integer addition/subtraction
153 getActionDefinitionsBuilder({G_ADD, G_SUB})
154 .legalFor({s8, s16, s32})
155 .legalFor(Is64Bit, {s64})
156 .legalFor(HasSSE2, {v16s8, v8s16, v4s32, v2s64})
157 .legalFor(HasAVX2, {v32s8, v16s16, v8s32, v4s64})
158 .legalFor(HasAVX512, {v16s32, v8s64})
159 .legalFor(HasBWI, {v64s8, v32s16})
160 .clampMinNumElements(0, s8, 16)
161 .clampMinNumElements(0, s16, 8)
162 .clampMinNumElements(0, s32, 4)
163 .clampMinNumElements(0, s64, 2)
164 .clampMaxNumElements(0, s8, HasBWI ? 64 : (HasAVX2 ? 32 : 16))
165 .clampMaxNumElements(0, s16, HasBWI ? 32 : (HasAVX2 ? 16 : 8))
166 .clampMaxNumElements(0, s32, HasAVX512 ? 16 : (HasAVX2 ? 8 : 4))
167 .clampMaxNumElements(0, s64, HasAVX512 ? 8 : (HasAVX2 ? 4 : 2))
168 .widenScalarToNextPow2(0, /*Min=*/32)
169 .clampScalar(0, s8, sMaxScalar)
170 .scalarize(0);
171
172 getActionDefinitionsBuilder({G_UADDE, G_UADDO, G_USUBE, G_USUBO})
173 .legalFor({{s8, s1}, {s16, s1}, {s32, s1}})
174 .legalFor(Is64Bit, {{s64, s1}})
175 .widenScalarToNextPow2(0, /*Min=*/32)
176 .clampScalar(0, s8, sMaxScalar)
177 .clampScalar(1, s1, s1)
178 .scalarize(0);
179
180 // integer multiply
182 .legalFor({s8, s16, s32})
183 .legalFor(Is64Bit, {s64})
184 .legalFor(HasSSE2, {v8s16})
185 .legalFor(HasSSE41, {v4s32})
186 .legalFor(HasAVX2, {v16s16, v8s32})
187 .legalFor(HasAVX512, {v16s32})
188 .legalFor(HasDQI, {v8s64})
189 .legalFor(HasDQI && HasVLX, {v2s64, v4s64})
190 .legalFor(HasBWI, {v32s16})
191 .clampMinNumElements(0, s16, 8)
192 .clampMinNumElements(0, s32, 4)
193 .clampMinNumElements(0, s64, HasVLX ? 2 : 8)
194 .clampMaxNumElements(0, s16, HasBWI ? 32 : (HasAVX2 ? 16 : 8))
195 .clampMaxNumElements(0, s32, HasAVX512 ? 16 : (HasAVX2 ? 8 : 4))
196 .clampMaxNumElements(0, s64, 8)
197 .widenScalarToNextPow2(0, /*Min=*/32)
198 .clampScalar(0, s8, sMaxScalar)
199 .scalarize(0);
200
201 getActionDefinitionsBuilder({G_SMULH, G_UMULH})
202 .legalFor({s8, s16, s32})
203 .legalFor(Is64Bit, {s64})
204 .widenScalarToNextPow2(0, /*Min=*/32)
205 .clampScalar(0, s8, sMaxScalar)
206 .scalarize(0);
207
208 // integer divisions
209 getActionDefinitionsBuilder({G_SDIV, G_SREM, G_UDIV, G_UREM})
210 .legalFor({s8, s16, s32})
211 .legalFor(Is64Bit, {s64})
212 .libcallFor({s64})
213 .clampScalar(0, s8, sMaxScalar);
214
215 // integer shifts
216 getActionDefinitionsBuilder({G_SHL, G_LSHR, G_ASHR})
217 .legalFor({{s8, s8}, {s16, s8}, {s32, s8}})
218 .legalFor(Is64Bit, {{s64, s8}})
219 .clampScalar(0, s8, sMaxScalar)
220 .clampScalar(1, s8, s8);
221
222 // integer logic
223 getActionDefinitionsBuilder({G_AND, G_OR, G_XOR})
224 .legalFor({s8, s16, s32})
225 .legalFor(Is64Bit, {s64})
226 .legalFor(HasSSE2, {v16s8, v8s16, v4s32, v2s64})
227 .legalFor(HasAVX, {v32s8, v16s16, v8s32, v4s64})
228 .legalFor(HasAVX512, {v64s8, v32s16, v16s32, v8s64})
229 .clampMinNumElements(0, s8, 16)
230 .clampMinNumElements(0, s16, 8)
231 .clampMinNumElements(0, s32, 4)
232 .clampMinNumElements(0, s64, 2)
233 .clampMaxNumElements(0, s8, HasAVX512 ? 64 : (HasAVX ? 32 : 16))
234 .clampMaxNumElements(0, s16, HasAVX512 ? 32 : (HasAVX ? 16 : 8))
235 .clampMaxNumElements(0, s32, HasAVX512 ? 16 : (HasAVX ? 8 : 4))
236 .clampMaxNumElements(0, s64, HasAVX512 ? 8 : (HasAVX ? 4 : 2))
237 .widenScalarToNextPow2(0, /*Min=*/32)
238 .clampScalar(0, s8, sMaxScalar)
239 .scalarize(0);
240
241 // integer comparison
242 const std::initializer_list<LLT> IntTypes32 = {s8, s16, s32, p0};
243 const std::initializer_list<LLT> IntTypes64 = {s8, s16, s32, s64, p0};
244
246 .legalForCartesianProduct({s8}, Is64Bit ? IntTypes64 : IntTypes32)
247 .clampScalar(0, s8, s8)
248 .clampScalar(1, s8, sMaxScalar);
249
250 // bswap
252 .legalFor({s32})
253 .legalFor(Is64Bit, {s64})
254 .widenScalarToNextPow2(0, /*Min=*/32)
255 .clampScalar(0, s32, sMaxScalar);
256
257 // popcount
259 .legalFor(HasPOPCNT, {{s16, s16}, {s32, s32}})
260 .legalFor(HasPOPCNT && Is64Bit, {{s64, s64}})
261 .widenScalarToNextPow2(1, /*Min=*/16)
262 .clampScalar(1, s16, sMaxScalar)
263 .scalarSameSizeAs(0, 1);
264
265 // count leading zeros (LZCNT)
267 .legalFor(HasLZCNT, {{s16, s16}, {s32, s32}})
268 .legalFor(HasLZCNT && Is64Bit, {{s64, s64}})
269 .widenScalarToNextPow2(1, /*Min=*/16)
270 .clampScalar(1, s16, sMaxScalar)
271 .scalarSameSizeAs(0, 1);
272
273 // count trailing zeros
274 getActionDefinitionsBuilder(G_CTTZ_ZERO_UNDEF)
275 .legalFor({{s16, s16}, {s32, s32}})
276 .legalFor(Is64Bit, {{s64, s64}})
277 .widenScalarToNextPow2(1, /*Min=*/16)
278 .clampScalar(1, s16, sMaxScalar)
279 .scalarSameSizeAs(0, 1);
280
282 .legalFor(HasBMI, {{s16, s16}, {s32, s32}})
283 .legalFor(HasBMI && Is64Bit, {{s64, s64}})
284 .widenScalarToNextPow2(1, /*Min=*/16)
285 .clampScalar(1, s16, sMaxScalar)
286 .scalarSameSizeAs(0, 1);
287
288 // control flow
290 .legalFor({s8, s16, s32, p0})
291 .legalFor(UseX87, {s80})
292 .legalFor(Is64Bit, {s64})
293 .legalFor(HasSSE1, {v16s8, v8s16, v4s32, v2s64})
294 .legalFor(HasAVX, {v32s8, v16s16, v8s32, v4s64})
295 .legalFor(HasAVX512, {v64s8, v32s16, v16s32, v8s64})
296 .clampMinNumElements(0, s8, 16)
297 .clampMinNumElements(0, s16, 8)
298 .clampMinNumElements(0, s32, 4)
299 .clampMinNumElements(0, s64, 2)
300 .clampMaxNumElements(0, s8, HasAVX512 ? 64 : (HasAVX ? 32 : 16))
301 .clampMaxNumElements(0, s16, HasAVX512 ? 32 : (HasAVX ? 16 : 8))
302 .clampMaxNumElements(0, s32, HasAVX512 ? 16 : (HasAVX ? 8 : 4))
303 .clampMaxNumElements(0, s64, HasAVX512 ? 8 : (HasAVX ? 4 : 2))
304 .widenScalarToNextPow2(0, /*Min=*/32)
305 .clampScalar(0, s8, sMaxScalar)
306 .scalarize(0);
307
309
310 // pointer handling
311 const std::initializer_list<LLT> PtrTypes32 = {s1, s8, s16, s32};
312 const std::initializer_list<LLT> PtrTypes64 = {s1, s8, s16, s32, s64};
313
315 .legalForCartesianProduct(Is64Bit ? PtrTypes64 : PtrTypes32, {p0})
316 .maxScalar(0, sMaxScalar)
317 .widenScalarToNextPow2(0, /*Min*/ 8);
318
319 getActionDefinitionsBuilder(G_INTTOPTR).legalFor({{p0, sMaxScalar}});
320
321 getActionDefinitionsBuilder(G_CONSTANT_POOL).legalFor({p0});
322
324 .legalFor({{p0, s32}})
325 .legalFor(Is64Bit, {{p0, s64}})
326 .widenScalarToNextPow2(1, /*Min*/ 32)
327 .clampScalar(1, s32, sMaxScalar);
328
329 getActionDefinitionsBuilder({G_FRAME_INDEX, G_GLOBAL_VALUE}).legalFor({p0});
330
331 // load/store: add more corner cases
332 for (unsigned Op : {G_LOAD, G_STORE}) {
333 auto &Action = getActionDefinitionsBuilder(Op);
334 Action.legalForTypesWithMemDesc({{s8, p0, s8, 1},
335 {s16, p0, s16, 1},
336 {s32, p0, s32, 1},
337 {s80, p0, s80, 1},
338 {p0, p0, p0, 1},
339 {v4s8, p0, v4s8, 1}});
340 if (Is64Bit)
341 Action.legalForTypesWithMemDesc(
342 {{s64, p0, s64, 1}, {v2s32, p0, v2s32, 1}});
343
344 if (HasSSE1)
345 Action.legalForTypesWithMemDesc({{v4s32, p0, v4s32, 1}});
346 if (HasSSE2)
347 Action.legalForTypesWithMemDesc({{v16s8, p0, v16s8, 1},
348 {v8s16, p0, v8s16, 1},
349 {v2s64, p0, v2s64, 1},
350 {v2p0, p0, v2p0, 1}});
351 if (HasAVX)
352 Action.legalForTypesWithMemDesc({{v32s8, p0, v32s8, 1},
353 {v16s16, p0, v16s16, 1},
354 {v8s32, p0, v8s32, 1},
355 {v4s64, p0, v4s64, 1},
356 {v4p0, p0, v4p0, 1}});
357 if (HasAVX512)
358 Action.legalForTypesWithMemDesc({{v64s8, p0, v64s8, 1},
359 {v32s16, p0, v32s16, 1},
360 {v16s32, p0, v16s32, 1},
361 {v8s64, p0, v8s64, 1}});
362
363 // X86 supports extending loads but not stores for GPRs
364 if (Op == G_LOAD) {
365 Action.legalForTypesWithMemDesc({{s8, p0, s1, 1},
366 {s16, p0, s8, 1},
367 {s32, p0, s8, 1},
368 {s32, p0, s16, 1}});
369 if (Is64Bit)
370 Action.legalForTypesWithMemDesc(
371 {{s64, p0, s8, 1}, {s64, p0, s16, 1}, {s64, p0, s32, 1}});
372 } else {
373 Action.customIf([=](const LegalityQuery &Query) {
374 return Query.Types[0] != Query.MMODescrs[0].MemoryTy;
375 });
376 }
377 Action.widenScalarToNextPow2(0, /*Min=*/8)
378 .clampScalar(0, s8, sMaxScalar)
379 .scalarize(0);
380 }
381
382 for (unsigned Op : {G_SEXTLOAD, G_ZEXTLOAD}) {
383 auto &Action = getActionDefinitionsBuilder(Op);
384 Action.legalForTypesWithMemDesc(
385 {{s16, p0, s8, 1}, {s32, p0, s8, 1}, {s32, p0, s16, 1}});
386 if (Is64Bit)
387 Action.legalForTypesWithMemDesc(
388 {{s64, p0, s8, 1}, {s64, p0, s16, 1}, {s64, p0, s32, 1}});
389 // TODO - SSE41/AVX2/AVX512F/AVX512BW vector extensions
390 }
391
392 // sext, zext, and anyext
394 .legalFor({s8, s16, s32, s128})
395 .legalFor(Is64Bit, {s64})
396 .widenScalarToNextPow2(0, /*Min=*/8)
397 .clampScalar(0, s8, sMaxScalar)
398 .widenScalarToNextPow2(1, /*Min=*/8)
399 .clampScalar(1, s8, sMaxScalar)
400 .scalarize(0);
401
402 getActionDefinitionsBuilder({G_SEXT, G_ZEXT})
403 .legalFor({s8, s16, s32})
404 .legalFor(Is64Bit, {s64})
405 .widenScalarToNextPow2(0, /*Min=*/8)
406 .clampScalar(0, s8, sMaxScalar)
407 .widenScalarToNextPow2(1, /*Min=*/8)
408 .clampScalar(1, s8, sMaxScalar)
409 .scalarize(0);
410
411 getActionDefinitionsBuilder(G_SEXT_INREG).lower();
412
413 // fp constants
414 getActionDefinitionsBuilder(G_FCONSTANT)
415 .legalFor({s32, s64})
416 .legalFor(UseX87, {s80});
417
418 // fp arithmetic
419 getActionDefinitionsBuilder({G_FADD, G_FSUB, G_FMUL, G_FDIV})
420 .legalFor({s32, s64})
421 .legalFor(HasSSE1, {v4s32})
422 .legalFor(HasSSE2, {v2s64})
423 .legalFor(HasAVX, {v8s32, v4s64})
424 .legalFor(HasAVX512, {v16s32, v8s64})
425 .legalFor(UseX87, {s80});
426
428 .legalFor(UseX87, {s80})
429 .legalFor(UseX87 && !Is64Bit, {s64})
430 .lower();
431
432 // fp comparison
434 .legalFor(HasSSE1 || UseX87, {s8, s32})
435 .legalFor(HasSSE2 || UseX87, {s8, s64})
436 .legalFor(UseX87, {s8, s80})
437 .clampScalar(0, s8, s8)
438 .clampScalar(1, s32, HasSSE2 ? s64 : s32)
440
441 // fp conversions
443 .legalFor(HasSSE2, {{s64, s32}})
444 .legalFor(HasAVX, {{v4s64, v4s32}})
445 .legalFor(HasAVX512, {{v8s64, v8s32}});
446
448 .legalFor(HasSSE2, {{s32, s64}})
449 .legalFor(HasAVX, {{v4s32, v4s64}})
450 .legalFor(HasAVX512, {{v8s32, v8s64}});
451
453 .legalFor(HasSSE1, {{s32, s32}})
454 .legalFor(HasSSE1 && Is64Bit, {{s32, s64}})
455 .legalFor(HasSSE2, {{s64, s32}})
456 .legalFor(HasSSE2 && Is64Bit, {{s64, s64}})
457 .clampScalar(1, (UseX87 && !HasSSE1) ? s16 : s32, sMaxScalar)
459 .customForCartesianProduct(UseX87, {s32, s64, s80}, {s16, s32, s64})
460 .clampScalar(0, s32, HasSSE2 ? s64 : s32)
462
464 .legalFor(HasSSE1, {{s32, s32}})
465 .legalFor(HasSSE1 && Is64Bit, {{s64, s32}})
466 .legalFor(HasSSE2, {{s32, s64}})
467 .legalFor(HasSSE2 && Is64Bit, {{s64, s64}})
468 .clampScalar(0, (UseX87 && !HasSSE1) ? s16 : s32, sMaxScalar)
470 .customForCartesianProduct(UseX87, {s16, s32, s64}, {s32, s64, s80})
471 .clampScalar(1, s32, HasSSE2 ? s64 : s32)
473
474 // For G_UITOFP and G_FPTOUI without AVX512, we have to custom legalize types
475 // <= s32 manually. Otherwise, in custom handler there is no way to
476 // understand whether s32 is an original type and we need to promote it to
477 // s64 or s32 is obtained after widening and we shouldn't widen it to s64.
478 //
479 // For AVX512 we simply widen types as there is direct mapping from opcodes
480 // to asm instructions.
482 .legalFor(HasAVX512, {{s32, s32}, {s32, s64}, {s64, s32}, {s64, s64}})
483 .customIf([=](const LegalityQuery &Query) {
484 return !HasAVX512 &&
485 ((HasSSE1 && typeIs(0, s32)(Query)) ||
486 (HasSSE2 && typeIs(0, s64)(Query))) &&
487 scalarNarrowerThan(1, Is64Bit ? 64 : 32)(Query);
488 })
489 .lowerIf([=](const LegalityQuery &Query) {
490 // Lower conversions from s64
491 return !HasAVX512 &&
492 ((HasSSE1 && typeIs(0, s32)(Query)) ||
493 (HasSSE2 && typeIs(0, s64)(Query))) &&
494 (Is64Bit && typeIs(1, s64)(Query));
495 })
496 .clampScalar(0, s32, HasSSE2 ? s64 : s32)
498 .clampScalar(1, s32, sMaxScalar)
500
502 .legalFor(HasAVX512, {{s32, s32}, {s32, s64}, {s64, s32}, {s64, s64}})
503 .customIf([=](const LegalityQuery &Query) {
504 return !HasAVX512 &&
505 ((HasSSE1 && typeIs(1, s32)(Query)) ||
506 (HasSSE2 && typeIs(1, s64)(Query))) &&
507 scalarNarrowerThan(0, Is64Bit ? 64 : 32)(Query);
508 })
509 // TODO: replace with customized legalization using
510 // specifics of cvttsd2si. The selection of this node requires
511 // a vector type. Either G_SCALAR_TO_VECTOR is needed or more advanced
512 // support of G_BUILD_VECTOR/G_INSERT_VECTOR_ELT is required beforehand.
513 .lowerIf([=](const LegalityQuery &Query) {
514 return !HasAVX512 &&
515 ((HasSSE1 && typeIs(1, s32)(Query)) ||
516 (HasSSE2 && typeIs(1, s64)(Query))) &&
517 (Is64Bit && typeIs(0, s64)(Query));
518 })
519 .clampScalar(0, s32, sMaxScalar)
521 .clampScalar(1, s32, HasSSE2 ? s64 : s32)
523
524 // vector ops
525 getActionDefinitionsBuilder(G_BUILD_VECTOR)
526 .customIf([=](const LegalityQuery &Query) {
527 return (HasSSE1 && typeInSet(0, {v4s32})(Query)) ||
528 (HasSSE2 && typeInSet(0, {v2s64, v8s16, v16s8})(Query)) ||
529 (HasAVX && typeInSet(0, {v4s64, v8s32, v16s16, v32s8})(Query)) ||
530 (HasAVX512 && typeInSet(0, {v8s64, v16s32, v32s16, v64s8}));
531 })
532 .clampNumElements(0, v16s8, s8MaxVector)
533 .clampNumElements(0, v8s16, s16MaxVector)
534 .clampNumElements(0, v4s32, s32MaxVector)
535 .clampNumElements(0, v2s64, s64MaxVector)
537
538 getActionDefinitionsBuilder({G_EXTRACT, G_INSERT})
539 .legalIf([=](const LegalityQuery &Query) {
540 unsigned SubIdx = Query.Opcode == G_EXTRACT ? 0 : 1;
541 unsigned FullIdx = Query.Opcode == G_EXTRACT ? 1 : 0;
542 return (HasAVX && typePairInSet(SubIdx, FullIdx,
543 {{v16s8, v32s8},
544 {v8s16, v16s16},
545 {v4s32, v8s32},
546 {v2s64, v4s64}})(Query)) ||
547 (HasAVX512 && typePairInSet(SubIdx, FullIdx,
548 {{v16s8, v64s8},
549 {v32s8, v64s8},
550 {v8s16, v32s16},
551 {v16s16, v32s16},
552 {v4s32, v16s32},
553 {v8s32, v16s32},
554 {v2s64, v8s64},
555 {v4s64, v8s64}})(Query));
556 });
557
558 // todo: only permit dst types up to max legal vector register size?
559 getActionDefinitionsBuilder(G_CONCAT_VECTORS)
560 .legalFor(
561 HasSSE1,
562 {{v32s8, v16s8}, {v16s16, v8s16}, {v8s32, v4s32}, {v4s64, v2s64}})
563 .legalFor(HasAVX, {{v64s8, v16s8},
564 {v64s8, v32s8},
565 {v32s16, v8s16},
566 {v32s16, v16s16},
567 {v16s32, v4s32},
568 {v16s32, v8s32},
569 {v8s64, v2s64},
570 {v8s64, v4s64}});
571
572 // todo: vectors and address spaces
574 .legalFor({{s8, s32}, {s16, s32}, {s32, s32}, {s64, s32}, {p0, s32}})
575 .widenScalarToNextPow2(0, /*Min=*/8)
576 .clampScalar(0, HasCMOV ? s16 : s8, sMaxScalar)
577 .clampScalar(1, s32, s32);
578
579 // memory intrinsics
580 getActionDefinitionsBuilder({G_MEMCPY, G_MEMMOVE, G_MEMSET}).libcall();
581
582 getActionDefinitionsBuilder({G_DYN_STACKALLOC, G_STACKSAVE, G_STACKRESTORE})
583 .lower();
584
585 // fp intrinsics
586 getActionDefinitionsBuilder({G_INTRINSIC_ROUNDEVEN, G_INTRINSIC_TRUNC})
587 .scalarize(0)
588 .minScalar(0, LLT::scalar(32))
589 .libcall();
590
591 getActionDefinitionsBuilder({G_FREEZE, G_CONSTANT_FOLD_BARRIER})
592 .legalFor({s8, s16, s32, s64, p0})
593 .widenScalarToNextPow2(0, /*Min=*/8)
594 .clampScalar(0, s8, sMaxScalar);
595
597 verify(*STI.getInstrInfo());
598}
599
601 LostDebugLocObserver &LocObserver) const {
602 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
603 MachineRegisterInfo &MRI = *MIRBuilder.getMRI();
604 switch (MI.getOpcode()) {
605 default:
606 // No idea what to do.
607 return false;
608 case TargetOpcode::G_BUILD_VECTOR:
609 return legalizeBuildVector(MI, MRI, Helper);
610 case TargetOpcode::G_FPTOUI:
611 return legalizeFPTOUI(MI, MRI, Helper);
612 case TargetOpcode::G_UITOFP:
613 return legalizeUITOFP(MI, MRI, Helper);
614 case TargetOpcode::G_STORE:
615 return legalizeNarrowingStore(MI, MRI, Helper);
616 case TargetOpcode::G_SITOFP:
617 return legalizeSITOFP(MI, MRI, Helper);
618 case TargetOpcode::G_FPTOSI:
619 return legalizeFPTOSI(MI, MRI, Helper);
620 case TargetOpcode::G_GET_ROUNDING:
621 return legalizeGETROUNDING(MI, MRI, Helper);
622 case TargetOpcode::G_SET_ROUNDING:
623 return legalizeSETROUNDING(MI, MRI, Helper);
624 }
625 llvm_unreachable("expected switch to return");
626}
627
628bool X86LegalizerInfo::legalizeSITOFP(MachineInstr &MI,
630 LegalizerHelper &Helper) const {
631 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
632 MachineFunction &MF = *MI.getMF();
633 auto [Dst, DstTy, Src, SrcTy] = MI.getFirst2RegLLTs();
634
635 assert((SrcTy.getSizeInBits() == 16 || SrcTy.getSizeInBits() == 32 ||
636 SrcTy.getSizeInBits() == 64) &&
637 "Unexpected source type for SITOFP in X87 mode.");
638
639 TypeSize MemSize = SrcTy.getSizeInBytes();
640 MachinePointerInfo PtrInfo;
641 Align Alignmt = Helper.getStackTemporaryAlignment(SrcTy);
642 auto SlotPointer = Helper.createStackTemporary(MemSize, Alignmt, PtrInfo);
644 PtrInfo, MachineMemOperand::MOStore, MemSize, Align(MemSize));
645
646 // Store the integer value on the FPU stack.
647 MIRBuilder.buildStore(Src, SlotPointer, *StoreMMO);
648
650 PtrInfo, MachineMemOperand::MOLoad, MemSize, Align(MemSize));
651 MIRBuilder.buildInstr(X86::G_FILD)
652 .addDef(Dst)
653 .addUse(SlotPointer.getReg(0))
654 .addMemOperand(LoadMMO);
655
656 MI.eraseFromParent();
657 return true;
658}
659
660bool X86LegalizerInfo::legalizeFPTOSI(MachineInstr &MI,
662 LegalizerHelper &Helper) const {
663 MachineFunction &MF = *MI.getMF();
664 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
665 auto [Dst, DstTy, Src, SrcTy] = MI.getFirst2RegLLTs();
666
667 TypeSize MemSize = DstTy.getSizeInBytes();
668 MachinePointerInfo PtrInfo;
669 Align Alignmt = Helper.getStackTemporaryAlignment(DstTy);
670 auto SlotPointer = Helper.createStackTemporary(MemSize, Alignmt, PtrInfo);
672 PtrInfo, MachineMemOperand::MOStore, MemSize, Align(MemSize));
673
674 MIRBuilder.buildInstr(X86::G_FIST)
675 .addUse(Src)
676 .addUse(SlotPointer.getReg(0))
677 .addMemOperand(StoreMMO);
678
679 MIRBuilder.buildLoad(Dst, SlotPointer, PtrInfo, Align(MemSize));
680 MI.eraseFromParent();
681 return true;
682}
683
684bool X86LegalizerInfo::legalizeBuildVector(MachineInstr &MI,
686 LegalizerHelper &Helper) const {
687 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
688 const auto &BuildVector = cast<GBuildVector>(MI);
689 Register Dst = BuildVector.getReg(0);
690 LLT DstTy = MRI.getType(Dst);
691 MachineFunction &MF = MIRBuilder.getMF();
692 LLVMContext &Ctx = MF.getFunction().getContext();
693 uint64_t DstTySize = DstTy.getScalarSizeInBits();
694
696 for (unsigned i = 0; i < BuildVector.getNumSources(); ++i) {
697 Register Source = BuildVector.getSourceReg(i);
698
699 auto ValueAndReg = getIConstantVRegValWithLookThrough(Source, MRI);
700 if (ValueAndReg) {
701 CstIdxs.emplace_back(ConstantInt::get(Ctx, ValueAndReg->Value));
702 continue;
703 }
704
705 auto FPValueAndReg = getFConstantVRegValWithLookThrough(Source, MRI);
706 if (FPValueAndReg) {
707 CstIdxs.emplace_back(ConstantFP::get(Ctx, FPValueAndReg->Value));
708 continue;
709 }
710
711 if (getOpcodeDef<GImplicitDef>(Source, MRI)) {
712 CstIdxs.emplace_back(UndefValue::get(Type::getIntNTy(Ctx, DstTySize)));
713 continue;
714 }
715 return false;
716 }
717
718 Constant *ConstVal = ConstantVector::get(CstIdxs);
719
720 const DataLayout &DL = MIRBuilder.getDataLayout();
721 unsigned AddrSpace = DL.getDefaultGlobalsAddressSpace();
722 Align Alignment(DL.getABITypeAlign(ConstVal->getType()));
723 auto Addr = MIRBuilder.buildConstantPool(
724 LLT::pointer(AddrSpace, DL.getPointerSizeInBits(AddrSpace)),
725 MF.getConstantPool()->getConstantPoolIndex(ConstVal, Alignment));
726 MachineMemOperand *MMO =
728 MachineMemOperand::MOLoad, DstTy, Alignment);
729
730 MIRBuilder.buildLoad(Dst, Addr, *MMO);
731 MI.eraseFromParent();
732 return true;
733}
734
735bool X86LegalizerInfo::legalizeFPTOUI(MachineInstr &MI,
737 LegalizerHelper &Helper) const {
738 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
739 auto [Dst, DstTy, Src, SrcTy] = MI.getFirst2RegLLTs();
740 unsigned DstSizeInBits = DstTy.getScalarSizeInBits();
741 const LLT s32 = LLT::scalar(32);
742 const LLT s64 = LLT::scalar(64);
743
744 // Simply reuse FPTOSI when it is possible to widen the type
745 if (DstSizeInBits <= 32) {
746 auto Casted = MIRBuilder.buildFPTOSI(DstTy == s32 ? s64 : s32, Src);
747 MIRBuilder.buildTrunc(Dst, Casted);
748 MI.eraseFromParent();
749 return true;
750 }
751
752 return false;
753}
754
755bool X86LegalizerInfo::legalizeUITOFP(MachineInstr &MI,
757 LegalizerHelper &Helper) const {
758 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
759 auto [Dst, DstTy, Src, SrcTy] = MI.getFirst2RegLLTs();
760 const LLT s32 = LLT::scalar(32);
761 const LLT s64 = LLT::scalar(64);
762
763 // Simply reuse SITOFP when it is possible to widen the type
764 if (SrcTy.getSizeInBits() <= 32) {
765 auto Ext = MIRBuilder.buildZExt(SrcTy == s32 ? s64 : s32, Src);
766 MIRBuilder.buildSITOFP(Dst, Ext);
767 MI.eraseFromParent();
768 return true;
769 }
770
771 return false;
772}
773
774bool X86LegalizerInfo::legalizeNarrowingStore(MachineInstr &MI,
776 LegalizerHelper &Helper) const {
777 auto &Store = cast<GStore>(MI);
778 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
779 MachineMemOperand &MMO = **Store.memoperands_begin();
780 MachineFunction &MF = MIRBuilder.getMF();
781 LLT ValTy = MRI.getType(Store.getValueReg());
782 auto *NewMMO = MF.getMachineMemOperand(&MMO, MMO.getPointerInfo(), ValTy);
783
784 Helper.Observer.changingInstr(Store);
785 Store.setMemRefs(MF, {NewMMO});
786 Helper.Observer.changedInstr(Store);
787 return true;
788}
789
790bool X86LegalizerInfo::legalizeGETROUNDING(MachineInstr &MI,
792 LegalizerHelper &Helper) const {
793 /*
794 The rounding mode is in bits 11:10 of FPSR, and has the following
795 settings:
796 00 Round to nearest
797 01 Round to -inf
798 10 Round to +inf
799 11 Round to 0
800
801 GET_ROUNDING, on the other hand, expects the following:
802 -1 Undefined
803 0 Round to 0
804 1 Round to nearest
805 2 Round to +inf
806 3 Round to -inf
807
808 To perform the conversion, we use a packed lookup table of the four 2-bit
809 values that we can index by FPSP[11:10]
810 0x2d --> (0b00,10,11,01) --> (0,2,3,1) >> FPSR[11:10]
811
812 (0x2d >> ((FPSR >> 9) & 6)) & 3
813 */
814
815 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
816 MachineFunction &MF = MIRBuilder.getMF();
817 Register Dst = MI.getOperand(0).getReg();
818 LLT DstTy = MRI.getType(Dst);
819 const LLT s8 = LLT::scalar(8);
820 const LLT s16 = LLT::scalar(16);
821 const LLT s32 = LLT::scalar(32);
822
823 // Save FP Control Word to stack slot
824 int MemSize = 2;
825 Align Alignment = Align(2);
826 MachinePointerInfo PtrInfo;
827 auto StackTemp = Helper.createStackTemporary(TypeSize::getFixed(MemSize),
828 Alignment, PtrInfo);
829 Register StackPtr = StackTemp.getReg(0);
830
831 auto StoreMMO = MF.getMachineMemOperand(PtrInfo, MachineMemOperand::MOStore,
832 MemSize, Alignment);
833
834 // Store FP Control Word to stack slot using G_FNSTCW16
835 MIRBuilder.buildInstr(X86::G_FNSTCW16)
836 .addUse(StackPtr)
837 .addMemOperand(StoreMMO);
838
839 // Load FP Control Word from stack slot
840 auto LoadMMO = MF.getMachineMemOperand(PtrInfo, MachineMemOperand::MOLoad,
841 MemSize, Alignment);
842
843 auto CWD32 =
844 MIRBuilder.buildZExt(s32, MIRBuilder.buildLoad(s16, StackPtr, *LoadMMO));
845 auto Shifted8 = MIRBuilder.buildTrunc(
846 s8, MIRBuilder.buildLShr(s32, CWD32, MIRBuilder.buildConstant(s8, 9)));
847 auto Masked32 = MIRBuilder.buildZExt(
848 s32, MIRBuilder.buildAnd(s8, Shifted8, MIRBuilder.buildConstant(s8, 6)));
849
850 // LUT is a packed lookup table (0x2d) used to map the 2-bit x87 FPU rounding
851 // mode (from bits 11:10 of the control word) to the values expected by
852 // GET_ROUNDING. The mapping is performed by shifting LUT right by the
853 // extracted rounding mode and masking the result with 3 to obtain the final
854 auto LUT = MIRBuilder.buildConstant(s32, 0x2d);
855 auto LUTShifted = MIRBuilder.buildLShr(s32, LUT, Masked32);
856 auto RetVal =
857 MIRBuilder.buildAnd(s32, LUTShifted, MIRBuilder.buildConstant(s32, 3));
858 auto RetValTrunc = MIRBuilder.buildZExtOrTrunc(DstTy, RetVal);
859
860 MIRBuilder.buildCopy(Dst, RetValTrunc);
861
862 MI.eraseFromParent();
863 return true;
864}
865
866bool X86LegalizerInfo::legalizeSETROUNDING(MachineInstr &MI,
868 LegalizerHelper &Helper) const {
869 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
870 MachineFunction &MF = MIRBuilder.getMF();
871 Register Src = MI.getOperand(0).getReg();
872 const LLT s8 = LLT::scalar(8);
873 const LLT s16 = LLT::scalar(16);
874 const LLT s32 = LLT::scalar(32);
875
876 // Allocate stack slot for control word and MXCSR (4 bytes).
877 int MemSize = 4;
878 Align Alignment = Align(4);
879 MachinePointerInfo PtrInfo;
880 auto StackTemp = Helper.createStackTemporary(TypeSize::getFixed(MemSize),
881 Alignment, PtrInfo);
882 Register StackPtr = StackTemp.getReg(0);
883
884 auto StoreMMO =
886 MIRBuilder.buildInstr(X86::G_FNSTCW16)
887 .addUse(StackPtr)
888 .addMemOperand(StoreMMO);
889
890 auto LoadMMO =
892 auto CWD16 = MIRBuilder.buildLoad(s16, StackPtr, *LoadMMO);
893
894 // Clear RM field (bits 11:10)
895 auto ClearedCWD =
896 MIRBuilder.buildAnd(s16, CWD16, MIRBuilder.buildConstant(s16, 0xf3ff));
897
898 // Check if Src is a constant
899 auto *SrcDef = MRI.getVRegDef(Src);
900 Register RMBits;
901 Register MXCSRRMBits;
902
903 if (SrcDef && SrcDef->getOpcode() == TargetOpcode::G_CONSTANT) {
904 uint64_t RM = getIConstantFromReg(Src, MRI).getZExtValue();
905 int FieldVal = X86::getRoundingModeX86(RM);
906
907 if (FieldVal == X86::rmInvalid) {
908 FieldVal = X86::rmToNearest;
909 LLVMContext &C = MF.getFunction().getContext();
910 C.diagnose(DiagnosticInfoUnsupported(
911 MF.getFunction(), "rounding mode is not supported by X86 hardware",
912 DiagnosticLocation(MI.getDebugLoc()), DS_Error));
913 return false;
914 }
915
916 FieldVal = FieldVal << 3;
917 RMBits = MIRBuilder.buildConstant(s16, FieldVal).getReg(0);
918 MXCSRRMBits = MIRBuilder.buildConstant(s32, FieldVal).getReg(0);
919 } else {
920 // Convert Src (rounding mode) to bits for control word
921 // (0xc9 << (2 * Src + 4)) & 0xc00
922 auto Src32 = MIRBuilder.buildZExtOrTrunc(s32, Src);
923 auto ShiftAmt = MIRBuilder.buildAdd(
924 s32, MIRBuilder.buildShl(s32, Src32, MIRBuilder.buildConstant(s32, 1)),
925 MIRBuilder.buildConstant(s32, 4));
926 auto ShiftAmt8 = MIRBuilder.buildTrunc(s8, ShiftAmt);
927 auto Shifted = MIRBuilder.buildShl(s16, MIRBuilder.buildConstant(s16, 0xc9),
928 ShiftAmt8);
929 RMBits =
930 MIRBuilder.buildAnd(s16, Shifted, MIRBuilder.buildConstant(s16, 0xc00))
931 .getReg(0);
932
933 // For non-constant case, we still need to compute MXCSR bits dynamically
934 auto RMBits32 = MIRBuilder.buildZExt(s32, RMBits);
935 MXCSRRMBits =
936 MIRBuilder.buildShl(s32, RMBits32, MIRBuilder.buildConstant(s32, 3))
937 .getReg(0);
938 }
939 // Update rounding mode bits
940 auto NewCWD =
941 MIRBuilder.buildOr(s16, ClearedCWD, RMBits, MachineInstr::Disjoint);
942
943 // Store new FP Control Word to stack
944 auto StoreNewMMO =
946 MIRBuilder.buildStore(NewCWD, StackPtr, *StoreNewMMO);
947
948 // Load FP control word from the slot using G_FLDCW16
949 auto LoadNewMMO =
951 MIRBuilder.buildInstr(X86::G_FLDCW16)
952 .addUse(StackPtr)
953 .addMemOperand(LoadNewMMO);
954
955 if (Subtarget.hasSSE1()) {
956 // Store MXCSR to stack (use STMXCSR)
957 auto StoreMXCSRMMO = MF.getMachineMemOperand(
958 PtrInfo, MachineMemOperand::MOStore, 4, Align(4));
959 MIRBuilder.buildInstr(TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS)
960 .addIntrinsicID(Intrinsic::x86_sse_stmxcsr)
961 .addUse(StackPtr)
962 .addMemOperand(StoreMXCSRMMO);
963
964 // Load MXCSR from stack
965 auto LoadMXCSRMMO = MF.getMachineMemOperand(
966 PtrInfo, MachineMemOperand::MOLoad, 4, Align(4));
967 auto MXCSR = MIRBuilder.buildLoad(s32, StackPtr, *LoadMXCSRMMO);
968
969 // Clear RM field (bits 14:13)
970 auto ClearedMXCSR = MIRBuilder.buildAnd(
971 s32, MXCSR, MIRBuilder.buildConstant(s32, 0xffff9fff));
972
973 // Update rounding mode bits
974 auto NewMXCSR = MIRBuilder.buildOr(s32, ClearedMXCSR, MXCSRRMBits);
975
976 // Store new MXCSR to stack
977 auto StoreNewMXCSRMMO = MF.getMachineMemOperand(
978 PtrInfo, MachineMemOperand::MOStore, 4, Align(4));
979 MIRBuilder.buildStore(NewMXCSR, StackPtr, *StoreNewMXCSRMMO);
980
981 // Load MXCSR from stack (use LDMXCSR)
982 auto LoadNewMXCSRMMO = MF.getMachineMemOperand(
983 PtrInfo, MachineMemOperand::MOLoad, 4, Align(4));
984 MIRBuilder.buildInstr(TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS)
985 .addIntrinsicID(Intrinsic::x86_sse_ldmxcsr)
986 .addUse(StackPtr)
987 .addMemOperand(LoadNewMXCSRMMO);
988 }
989
990 MI.eraseFromParent();
991 return true;
992}
993
995 MachineInstr &MI) const {
996 return true;
997}
unsigned const MachineRegisterInfo * MRI
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
static void scalarize(Instruction *I, SmallVectorImpl< Instruction * > &Replace)
Definition ExpandFp.cpp:942
Declares convenience wrapper classes for interpreting MachineInstr instances as specific generic oper...
IRTranslator LLVM IR MI
This file declares the MachineConstantPool class which is an abstract constant pool to keep track of ...
This file declares the MachineIRBuilder class.
Promote Memory to Register
Definition Mem2Reg.cpp:110
ppc ctr loops verify
static const char LUT[]
This file declares the targeting of the Machinelegalizer class for X86.
uint64_t getZExtValue() const
Get zero extended value.
Definition APInt.h:1540
static LLVM_ABI Constant * get(ArrayRef< Constant * > V)
LLVMContext & getContext() const
getContext - Return a reference to the LLVMContext associated with this function.
Definition Function.cpp:359
virtual void changingInstr(MachineInstr &MI)=0
This instruction is about to be mutated in some way.
virtual void changedInstr(MachineInstr &MI)=0
This instruction was mutated in some way.
constexpr unsigned getScalarSizeInBits() const
static constexpr LLT scalar(unsigned SizeInBits)
Get a low-level scalar or aggregate "bag of bits".
static constexpr LLT pointer(unsigned AddressSpace, unsigned SizeInBits)
Get a low-level pointer in the given address space.
static constexpr LLT fixed_vector(unsigned NumElements, unsigned ScalarSizeInBits)
Get a low-level fixed-width vector of some number of elements and element width.
LLVM_ABI void diagnose(const DiagnosticInfo &DI)
Report a message to the currently installed diagnostic handler.
LLVM_ABI void computeTables()
Compute any ancillary tables needed to quickly decide how an operation should be handled.
LegalizeRuleSet & minScalar(unsigned TypeIdx, const LLT Ty)
Ensure the scalar is at least as wide as Ty.
LegalizeRuleSet & legalFor(std::initializer_list< LLT > Types)
The instruction is legal when type index 0 is any type in the given list.
LegalizeRuleSet & scalarSameSizeAs(unsigned TypeIdx, unsigned SameSizeIdx)
Change the type TypeIdx to have the same scalar size as type SameSizeIdx.
LegalizeRuleSet & libcall()
The instruction is emitted as a library call.
LegalizeRuleSet & clampMaxNumElements(unsigned TypeIdx, const LLT EltTy, unsigned MaxElements)
Limit the number of elements in EltTy vectors to at most MaxElements.
LegalizeRuleSet & clampMinNumElements(unsigned TypeIdx, const LLT EltTy, unsigned MinElements)
Limit the number of elements in EltTy vectors to at least MinElements.
LegalizeRuleSet & customForCartesianProduct(std::initializer_list< LLT > Types)
LegalizeRuleSet & moreElementsToNextPow2(unsigned TypeIdx)
Add more elements to the vector to reach the next power of two.
LegalizeRuleSet & lower()
The instruction is lowered.
LegalizeRuleSet & clampScalar(unsigned TypeIdx, const LLT MinTy, const LLT MaxTy)
Limit the range of scalar sizes to MinTy and MaxTy.
LegalizeRuleSet & clampNumElements(unsigned TypeIdx, const LLT MinTy, const LLT MaxTy)
Limit the number of elements for the given vectors to at least MinTy's number of elements and at most...
LegalizeRuleSet & customIf(LegalityPredicate Predicate)
LegalizeRuleSet & widenScalarToNextPow2(unsigned TypeIdx, unsigned MinSize=0)
Widen the scalar to the next power of two that is at least MinSize.
LegalizeRuleSet & scalarize(unsigned TypeIdx)
LegalizeRuleSet & legalForCartesianProduct(std::initializer_list< LLT > Types)
The instruction is legal when type indexes 0 and 1 are both in the given list.
LegalizeRuleSet & legalIf(LegalityPredicate Predicate)
The instruction is legal if predicate is true.
LLVM_ABI MachineInstrBuilder createStackTemporary(TypeSize Bytes, Align Alignment, MachinePointerInfo &PtrInfo)
Create a stack temporary based on the size in bytes and the alignment.
GISelChangeObserver & Observer
To keep track of changes made by the LegalizerHelper.
MachineIRBuilder & MIRBuilder
Expose MIRBuilder so clients can set their own RecordInsertInstruction functions.
LLVM_ABI Align getStackTemporaryAlignment(LLT Type, Align MinAlign=Align()) const
Return the alignment to use for a stack temporary object with the given type.
LegalizeRuleSet & getActionDefinitionsBuilder(unsigned Opcode)
Get the action definition builder for the given opcode.
const LegacyLegalizerInfo & getLegacyLegalizerInfo() const
unsigned getConstantPoolIndex(const Constant *C, Align Alignment)
getConstantPoolIndex - Create a new entry in the constant pool or return an existing one.
MachineMemOperand * getMachineMemOperand(MachinePointerInfo PtrInfo, MachineMemOperand::Flags f, LLT MemTy, Align base_alignment, const AAMDNodes &AAInfo=AAMDNodes(), const MDNode *Ranges=nullptr, SyncScope::ID SSID=SyncScope::System, AtomicOrdering Ordering=AtomicOrdering::NotAtomic, AtomicOrdering FailureOrdering=AtomicOrdering::NotAtomic)
getMachineMemOperand - Allocate a new MachineMemOperand.
Function & getFunction()
Return the LLVM function that this machine code represents.
MachineConstantPool * getConstantPool()
getConstantPool - Return the constant pool object for the current function.
Helper class to build MachineInstr.
MachineInstrBuilder buildFPTOSI(const DstOp &Dst, const SrcOp &Src0)
Build and insert Res = G_FPTOSI Src0.
MachineInstrBuilder buildAdd(const DstOp &Dst, const SrcOp &Src0, const SrcOp &Src1, std::optional< unsigned > Flags=std::nullopt)
Build and insert Res = G_ADD Op0, Op1.
MachineInstrBuilder buildConstantPool(const DstOp &Res, unsigned Idx)
Build and insert Res = G_CONSTANT_POOL Idx.
MachineInstrBuilder buildAnd(const DstOp &Dst, const SrcOp &Src0, const SrcOp &Src1)
Build and insert Res = G_AND Op0, Op1.
MachineInstrBuilder buildLShr(const DstOp &Dst, const SrcOp &Src0, const SrcOp &Src1, std::optional< unsigned > Flags=std::nullopt)
MachineInstrBuilder buildZExt(const DstOp &Res, const SrcOp &Op, std::optional< unsigned > Flags=std::nullopt)
Build and insert Res = G_ZEXT Op.
MachineInstrBuilder buildLoad(const DstOp &Res, const SrcOp &Addr, MachineMemOperand &MMO)
Build and insert Res = G_LOAD Addr, MMO.
MachineInstrBuilder buildZExtOrTrunc(const DstOp &Res, const SrcOp &Op)
Build and insert Res = G_ZEXT Op, Res = G_TRUNC Op, or Res = COPY Op depending on the differing sizes...
MachineInstrBuilder buildShl(const DstOp &Dst, const SrcOp &Src0, const SrcOp &Src1, std::optional< unsigned > Flags=std::nullopt)
MachineInstrBuilder buildStore(const SrcOp &Val, const SrcOp &Addr, MachineMemOperand &MMO)
Build and insert G_STORE Val, Addr, MMO.
MachineInstrBuilder buildInstr(unsigned Opcode)
Build and insert <empty> = Opcode <empty>.
MachineInstrBuilder buildSITOFP(const DstOp &Dst, const SrcOp &Src0)
Build and insert Res = G_SITOFP Src0.
MachineFunction & getMF()
Getter for the function we currently build.
MachineInstrBuilder buildTrunc(const DstOp &Res, const SrcOp &Op, std::optional< unsigned > Flags=std::nullopt)
Build and insert Res = G_TRUNC Op.
MachineRegisterInfo * getMRI()
Getter for MRI.
MachineInstrBuilder buildOr(const DstOp &Dst, const SrcOp &Src0, const SrcOp &Src1, std::optional< unsigned > Flags=std::nullopt)
Build and insert Res = G_OR Op0, Op1.
MachineInstrBuilder buildCopy(const DstOp &Res, const SrcOp &Op)
Build and insert Res = COPY Op.
const DataLayout & getDataLayout() const
virtual MachineInstrBuilder buildConstant(const DstOp &Res, const ConstantInt &Val)
Build and insert Res = G_CONSTANT Val.
Register getReg(unsigned Idx) const
Get the register for the operand index.
const MachineInstrBuilder & addIntrinsicID(Intrinsic::ID ID) const
const MachineInstrBuilder & addUse(Register RegNo, unsigned Flags=0, unsigned SubReg=0) const
Add a virtual register use operand.
const MachineInstrBuilder & addMemOperand(MachineMemOperand *MMO) const
const MachineInstrBuilder & addDef(Register RegNo, unsigned Flags=0, unsigned SubReg=0) const
Add a virtual register definition operand.
Representation of each machine instruction.
A description of a memory reference used in the backend.
@ MOLoad
The memory access reads data.
@ MOStore
The memory access writes data.
const MachinePointerInfo & getPointerInfo() const
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
reference emplace_back(ArgTypes &&... Args)
static constexpr TypeSize getFixed(ScalarTy ExactSize)
Definition TypeSize.h:343
static LLVM_ABI IntegerType * getIntNTy(LLVMContext &C, unsigned N)
Definition Type.cpp:301
static LLVM_ABI UndefValue * get(Type *T)
Static factory methods - Return an 'undef' object of the specified type.
Type * getType() const
All values are typed, get the type of this value.
Definition Value.h:256
bool legalizeCustom(LegalizerHelper &Helper, MachineInstr &MI, LostDebugLocObserver &LocObserver) const override
Called for instructions with the Custom LegalizationAction.
bool legalizeIntrinsic(LegalizerHelper &Helper, MachineInstr &MI) const override
X86LegalizerInfo(const X86Subtarget &STI, const X86TargetMachine &TM)
const X86InstrInfo * getInstrInfo() const override
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
constexpr char Align[]
Key for Kernel::Arg::Metadata::mAlign.
@ C
The default llvm calling convention, compatible with C.
Definition CallingConv.h:34
LLVM_ABI LegalityPredicate typeInSet(unsigned TypeIdx, std::initializer_list< LLT > TypesInit)
True iff the given type index is one of the specified types.
LLVM_ABI LegalityPredicate typePairInSet(unsigned TypeIdx0, unsigned TypeIdx1, std::initializer_list< std::pair< LLT, LLT > > TypesInit)
True iff the given types for the given pair of type indexes is one of the specified type pairs.
LLVM_ABI LegalityPredicate typeIs(unsigned TypeIdx, LLT TypesInit)
True iff the given type index is the specified type.
LLVM_ABI LegalityPredicate scalarNarrowerThan(unsigned TypeIdx, unsigned Size)
True iff the specified type index is a scalar that's narrower than the given size.
Invariant opcodes: All instruction sets have these as their low opcodes.
int getRoundingModeX86(unsigned RM)
Convert LLVM rounding mode to X86 rounding mode.
This is an optimization pass for GlobalISel generic memory operations.
LLVM_ABI MachineInstr * getOpcodeDef(unsigned Opcode, Register Reg, const MachineRegisterInfo &MRI)
See if Reg is defined by an single def instruction that is Opcode.
Definition Utils.cpp:651
LLVM_ABI const APInt & getIConstantFromReg(Register VReg, const MachineRegisterInfo &MRI)
VReg is defined by a G_CONSTANT, return the corresponding value.
Definition Utils.cpp:305
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
DWARFExpression::Operation Op
LLVM_ABI std::optional< FPValueAndVReg > getFConstantVRegValWithLookThrough(Register VReg, const MachineRegisterInfo &MRI, bool LookThroughInstrs=true)
If VReg is defined by a statically evaluable chain of instructions rooted on a G_FCONSTANT returns it...
Definition Utils.cpp:447
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:565
LLVM_ABI std::optional< ValueAndVReg > getIConstantVRegValWithLookThrough(Register VReg, const MachineRegisterInfo &MRI, bool LookThroughInstrs=true)
If VReg is defined by a statically evaluable chain of instructions rooted on a G_CONSTANT returns its...
Definition Utils.cpp:433
This struct is a compact representation of a valid (non-zero power of two) alignment.
Definition Alignment.h:39
The LegalityQuery object bundles together all the information that's needed to decide whether a given...
ArrayRef< MemDesc > MMODescrs
Operations which require memory can use this to place requirements on the memory type for each MMO.
ArrayRef< LLT > Types
This class contains a discriminated union of information about pointers in memory operands,...
static LLVM_ABI MachinePointerInfo getConstantPool(MachineFunction &MF)
Return a MachinePointerInfo record that refers to the constant pool.