LLVM 20.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"
23#include "llvm/IR/Type.h"
24
25using namespace llvm;
26using namespace TargetOpcode;
27using namespace LegalizeActions;
28using namespace LegalityPredicates;
29
31 const X86TargetMachine &TM)
32 : Subtarget(STI) {
33
34 bool Is64Bit = Subtarget.is64Bit();
35 bool HasCMOV = Subtarget.canUseCMOV();
36 bool HasSSE1 = Subtarget.hasSSE1();
37 bool HasSSE2 = Subtarget.hasSSE2();
38 bool HasSSE41 = Subtarget.hasSSE41();
39 bool HasAVX = Subtarget.hasAVX();
40 bool HasAVX2 = Subtarget.hasAVX2();
41 bool HasAVX512 = Subtarget.hasAVX512();
42 bool HasVLX = Subtarget.hasVLX();
43 bool HasDQI = Subtarget.hasAVX512() && Subtarget.hasDQI();
44 bool HasBWI = Subtarget.hasAVX512() && Subtarget.hasBWI();
45 bool UseX87 = !Subtarget.useSoftFloat() && Subtarget.hasX87();
46
47 const LLT p0 = LLT::pointer(0, TM.getPointerSizeInBits(0));
48 const LLT s1 = LLT::scalar(1);
49 const LLT s8 = LLT::scalar(8);
50 const LLT s16 = LLT::scalar(16);
51 const LLT s32 = LLT::scalar(32);
52 const LLT s64 = LLT::scalar(64);
53 const LLT s80 = LLT::scalar(80);
54 const LLT s128 = LLT::scalar(128);
55 const LLT sMaxScalar = Subtarget.is64Bit() ? s64 : s32;
56 const LLT v2s32 = LLT::fixed_vector(2, 32);
57 const LLT v4s8 = LLT::fixed_vector(4, 8);
58
59
60 const LLT v16s8 = LLT::fixed_vector(16, 8);
61 const LLT v8s16 = LLT::fixed_vector(8, 16);
62 const LLT v4s32 = LLT::fixed_vector(4, 32);
63 const LLT v2s64 = LLT::fixed_vector(2, 64);
64 const LLT v2p0 = LLT::fixed_vector(2, p0);
65
66 const LLT v32s8 = LLT::fixed_vector(32, 8);
67 const LLT v16s16 = LLT::fixed_vector(16, 16);
68 const LLT v8s32 = LLT::fixed_vector(8, 32);
69 const LLT v4s64 = LLT::fixed_vector(4, 64);
70 const LLT v4p0 = LLT::fixed_vector(4, p0);
71
72 const LLT v64s8 = LLT::fixed_vector(64, 8);
73 const LLT v32s16 = LLT::fixed_vector(32, 16);
74 const LLT v16s32 = LLT::fixed_vector(16, 32);
75 const LLT v8s64 = LLT::fixed_vector(8, 64);
76
77 const LLT s8MaxVector = HasAVX512 ? v64s8 : HasAVX ? v32s8 : v16s8;
78 const LLT s16MaxVector = HasAVX512 ? v32s16 : HasAVX ? v16s16 : v8s16;
79 const LLT s32MaxVector = HasAVX512 ? v16s32 : HasAVX ? v8s32 : v4s32;
80 const LLT s64MaxVector = HasAVX512 ? v8s64 : HasAVX ? v4s64 : v2s64;
81
82 // todo: AVX512 bool vector predicate types
83
84 // implicit/constants
85 getActionDefinitionsBuilder(G_IMPLICIT_DEF)
86 .legalIf([=](const LegalityQuery &Query) -> bool {
87 // 32/64-bits needs support for s64/s128 to handle cases:
88 // s64 = EXTEND (G_IMPLICIT_DEF s32) -> s64 = G_IMPLICIT_DEF
89 // s128 = EXTEND (G_IMPLICIT_DEF s32/s64) -> s128 = G_IMPLICIT_DEF
90 return typeInSet(0, {p0, s1, s8, s16, s32, s64})(Query) ||
91 (Is64Bit && typeInSet(0, {s128})(Query));
92 });
93
95 .legalIf([=](const LegalityQuery &Query) -> bool {
96 return typeInSet(0, {p0, s8, s16, s32})(Query) ||
97 (Is64Bit && typeInSet(0, {s64})(Query));
98 })
99 .widenScalarToNextPow2(0, /*Min=*/8)
100 .clampScalar(0, s8, sMaxScalar);
101
102 // merge/unmerge
103 for (unsigned Op : {G_MERGE_VALUES, G_UNMERGE_VALUES}) {
104 unsigned BigTyIdx = Op == G_MERGE_VALUES ? 0 : 1;
105 unsigned LitTyIdx = Op == G_MERGE_VALUES ? 1 : 0;
107 .widenScalarToNextPow2(LitTyIdx, /*Min=*/8)
108 .widenScalarToNextPow2(BigTyIdx, /*Min=*/16)
109 .minScalar(LitTyIdx, s8)
110 .minScalar(BigTyIdx, s32)
111 .legalIf([=](const LegalityQuery &Q) {
112 switch (Q.Types[BigTyIdx].getSizeInBits()) {
113 case 16:
114 case 32:
115 case 64:
116 case 128:
117 case 256:
118 case 512:
119 break;
120 default:
121 return false;
122 }
123 switch (Q.Types[LitTyIdx].getSizeInBits()) {
124 case 8:
125 case 16:
126 case 32:
127 case 64:
128 case 128:
129 case 256:
130 return true;
131 default:
132 return false;
133 }
134 });
135 }
136
137 // integer addition/subtraction
138 getActionDefinitionsBuilder({G_ADD, G_SUB})
139 .legalIf([=](const LegalityQuery &Query) -> bool {
140 if (typeInSet(0, {s8, s16, s32})(Query))
141 return true;
142 if (Is64Bit && typeInSet(0, {s64})(Query))
143 return true;
144 if (HasSSE2 && typeInSet(0, {v16s8, v8s16, v4s32, v2s64})(Query))
145 return true;
146 if (HasAVX2 && typeInSet(0, {v32s8, v16s16, v8s32, v4s64})(Query))
147 return true;
148 if (HasAVX512 && typeInSet(0, {v16s32, v8s64})(Query))
149 return true;
150 if (HasBWI && typeInSet(0, {v64s8, v32s16})(Query))
151 return true;
152 return false;
153 })
154 .clampMinNumElements(0, s8, 16)
155 .clampMinNumElements(0, s16, 8)
156 .clampMinNumElements(0, s32, 4)
157 .clampMinNumElements(0, s64, 2)
158 .clampMaxNumElements(0, s8, HasBWI ? 64 : (HasAVX2 ? 32 : 16))
159 .clampMaxNumElements(0, s16, HasBWI ? 32 : (HasAVX2 ? 16 : 8))
160 .clampMaxNumElements(0, s32, HasAVX512 ? 16 : (HasAVX2 ? 8 : 4))
161 .clampMaxNumElements(0, s64, HasAVX512 ? 8 : (HasAVX2 ? 4 : 2))
162 .widenScalarToNextPow2(0, /*Min=*/32)
163 .clampScalar(0, s8, sMaxScalar)
164 .scalarize(0);
165
166 getActionDefinitionsBuilder({G_UADDE, G_UADDO, G_USUBE, G_USUBO})
167 .legalIf([=](const LegalityQuery &Query) -> bool {
168 return typePairInSet(0, 1, {{s8, s1}, {s16, s1}, {s32, s1}})(Query) ||
169 (Is64Bit && typePairInSet(0, 1, {{s64, s1}})(Query));
170 })
171 .widenScalarToNextPow2(0, /*Min=*/32)
172 .clampScalar(0, s8, sMaxScalar)
173 .clampScalar(1, s1, s1)
174 .scalarize(0);
175
176 // integer multiply
178 .legalIf([=](const LegalityQuery &Query) -> bool {
179 if (typeInSet(0, {s8, s16, s32})(Query))
180 return true;
181 if (Is64Bit && typeInSet(0, {s64})(Query))
182 return true;
183 if (HasSSE2 && typeInSet(0, {v8s16})(Query))
184 return true;
185 if (HasSSE41 && typeInSet(0, {v4s32})(Query))
186 return true;
187 if (HasAVX2 && typeInSet(0, {v16s16, v8s32})(Query))
188 return true;
189 if (HasAVX512 && typeInSet(0, {v16s32})(Query))
190 return true;
191 if (HasDQI && typeInSet(0, {v8s64})(Query))
192 return true;
193 if (HasDQI && HasVLX && typeInSet(0, {v2s64, v4s64})(Query))
194 return true;
195 if (HasBWI && typeInSet(0, {v32s16})(Query))
196 return true;
197 return false;
198 })
199 .clampMinNumElements(0, s16, 8)
200 .clampMinNumElements(0, s32, 4)
201 .clampMinNumElements(0, s64, HasVLX ? 2 : 8)
202 .clampMaxNumElements(0, s16, HasBWI ? 32 : (HasAVX2 ? 16 : 8))
203 .clampMaxNumElements(0, s32, HasAVX512 ? 16 : (HasAVX2 ? 8 : 4))
204 .clampMaxNumElements(0, s64, 8)
205 .widenScalarToNextPow2(0, /*Min=*/32)
206 .clampScalar(0, s8, sMaxScalar)
207 .scalarize(0);
208
209 getActionDefinitionsBuilder({G_SMULH, G_UMULH})
210 .legalIf([=](const LegalityQuery &Query) -> bool {
211 return typeInSet(0, {s8, s16, s32})(Query) ||
212 (Is64Bit && typeInSet(0, {s64})(Query));
213 })
214 .widenScalarToNextPow2(0, /*Min=*/32)
215 .clampScalar(0, s8, sMaxScalar)
216 .scalarize(0);
217
218 // integer divisions
219 getActionDefinitionsBuilder({G_SDIV, G_SREM, G_UDIV, G_UREM})
220 .legalIf([=](const LegalityQuery &Query) -> bool {
221 return typeInSet(0, {s8, s16, s32})(Query) ||
222 (Is64Bit && typeInSet(0, {s64})(Query));
223 })
224 .libcallFor({s64})
225 .clampScalar(0, s8, sMaxScalar);
226
227 // integer shifts
228 getActionDefinitionsBuilder({G_SHL, G_LSHR, G_ASHR})
229 .legalIf([=](const LegalityQuery &Query) -> bool {
230 return typePairInSet(0, 1, {{s8, s8}, {s16, s8}, {s32, s8}})(Query) ||
231 (Is64Bit && typePairInSet(0, 1, {{s64, s8}})(Query));
232 })
233 .clampScalar(0, s8, sMaxScalar)
234 .clampScalar(1, s8, s8);
235
236 // integer logic
237 getActionDefinitionsBuilder({G_AND, G_OR, G_XOR})
238 .legalIf([=](const LegalityQuery &Query) -> bool {
239 if (typeInSet(0, {s8, s16, s32})(Query))
240 return true;
241 if (Is64Bit && typeInSet(0, {s64})(Query))
242 return true;
243 if (HasSSE2 && typeInSet(0, {v16s8, v8s16, v4s32, v2s64})(Query))
244 return true;
245 if (HasAVX && typeInSet(0, {v32s8, v16s16, v8s32, v4s64})(Query))
246 return true;
247 if (HasAVX512 && typeInSet(0, {v64s8, v32s16, v16s32, v8s64})(Query))
248 return true;
249 return false;
250 })
251 .clampMinNumElements(0, s8, 16)
252 .clampMinNumElements(0, s16, 8)
253 .clampMinNumElements(0, s32, 4)
254 .clampMinNumElements(0, s64, 2)
255 .clampMaxNumElements(0, s8, HasAVX512 ? 64 : (HasAVX ? 32 : 16))
256 .clampMaxNumElements(0, s16, HasAVX512 ? 32 : (HasAVX ? 16 : 8))
257 .clampMaxNumElements(0, s32, HasAVX512 ? 16 : (HasAVX ? 8 : 4))
258 .clampMaxNumElements(0, s64, HasAVX512 ? 8 : (HasAVX ? 4 : 2))
259 .widenScalarToNextPow2(0, /*Min=*/32)
260 .clampScalar(0, s8, sMaxScalar)
261 .scalarize(0);
262
263 // integer comparison
264 const std::initializer_list<LLT> IntTypes32 = {s8, s16, s32, p0};
265 const std::initializer_list<LLT> IntTypes64 = {s8, s16, s32, s64, p0};
266
268 .legalForCartesianProduct({s8}, Is64Bit ? IntTypes64 : IntTypes32)
269 .clampScalar(0, s8, s8)
270 .clampScalar(1, s8, sMaxScalar);
271
272 // bswap
274 .legalIf([=](const LegalityQuery &Query) {
275 return Query.Types[0] == s32 ||
276 (Subtarget.is64Bit() && Query.Types[0] == s64);
277 })
278 .widenScalarToNextPow2(0, /*Min=*/32)
279 .clampScalar(0, s32, sMaxScalar);
280
281 // popcount
283 .legalIf([=](const LegalityQuery &Query) -> bool {
284 return Subtarget.hasPOPCNT() &&
285 (typePairInSet(0, 1, {{s16, s16}, {s32, s32}})(Query) ||
286 (Is64Bit && typePairInSet(0, 1, {{s64, s64}})(Query)));
287 })
288 .widenScalarToNextPow2(1, /*Min=*/16)
289 .clampScalar(1, s16, sMaxScalar)
290 .scalarSameSizeAs(0, 1);
291
292 // count leading zeros (LZCNT)
294 .legalIf([=](const LegalityQuery &Query) -> bool {
295 return Subtarget.hasLZCNT() &&
296 (typePairInSet(0, 1, {{s16, s16}, {s32, s32}})(Query) ||
297 (Is64Bit && typePairInSet(0, 1, {{s64, s64}})(Query)));
298 })
299 .widenScalarToNextPow2(1, /*Min=*/16)
300 .clampScalar(1, s16, sMaxScalar)
301 .scalarSameSizeAs(0, 1);
302
303 // count trailing zeros
304 getActionDefinitionsBuilder({G_CTTZ_ZERO_UNDEF, G_CTTZ})
305 .legalIf([=](const LegalityQuery &Query) -> bool {
306 return (Query.Opcode == G_CTTZ_ZERO_UNDEF || Subtarget.hasBMI()) &&
307 (typePairInSet(0, 1, {{s16, s16}, {s32, s32}})(Query) ||
308 (Is64Bit && typePairInSet(0, 1, {{s64, s64}})(Query)));
309 })
310 .widenScalarToNextPow2(1, /*Min=*/16)
311 .clampScalar(1, s16, sMaxScalar)
312 .scalarSameSizeAs(0, 1);
313
314 // control flow
316 .legalIf([=](const LegalityQuery &Query) -> bool {
317 return typeInSet(0, {s8, s16, s32, p0})(Query) ||
318 (UseX87 && typeIs(0, s80)(Query)) ||
319 (Is64Bit && typeIs(0, s64)(Query)) ||
320 (HasSSE1 && typeInSet(0, {v16s8, v8s16, v4s32, v2s64})(Query)) ||
321 (HasAVX && typeInSet(0, {v32s8, v16s16, v8s32, v4s64})(Query)) ||
322 (HasAVX512 &&
323 typeInSet(0, {v64s8, v32s16, v16s32, v8s64})(Query));
324 })
325 .clampMinNumElements(0, s8, 16)
326 .clampMinNumElements(0, s16, 8)
327 .clampMinNumElements(0, s32, 4)
328 .clampMinNumElements(0, s64, 2)
329 .clampMaxNumElements(0, s8, HasAVX512 ? 64 : (HasAVX ? 32 : 16))
330 .clampMaxNumElements(0, s16, HasAVX512 ? 32 : (HasAVX ? 16 : 8))
331 .clampMaxNumElements(0, s32, HasAVX512 ? 16 : (HasAVX ? 8 : 4))
332 .clampMaxNumElements(0, s64, HasAVX512 ? 8 : (HasAVX ? 4 : 2))
333 .widenScalarToNextPow2(0, /*Min=*/32)
334 .clampScalar(0, s8, sMaxScalar)
335 .scalarize(0);
336
338
339 // pointer handling
340 const std::initializer_list<LLT> PtrTypes32 = {s1, s8, s16, s32};
341 const std::initializer_list<LLT> PtrTypes64 = {s1, s8, s16, s32, s64};
342
344 .legalForCartesianProduct(Is64Bit ? PtrTypes64 : PtrTypes32, {p0})
345 .maxScalar(0, sMaxScalar)
346 .widenScalarToNextPow2(0, /*Min*/ 8);
347
348 getActionDefinitionsBuilder(G_INTTOPTR).legalFor({{p0, sMaxScalar}});
349
350 getActionDefinitionsBuilder(G_CONSTANT_POOL).legalFor({p0});
351
353 .legalIf([=](const LegalityQuery &Query) -> bool {
354 return typePairInSet(0, 1, {{p0, s32}})(Query) ||
355 (Is64Bit && typePairInSet(0, 1, {{p0, s64}})(Query));
356 })
357 .widenScalarToNextPow2(1, /*Min*/ 32)
358 .clampScalar(1, s32, sMaxScalar);
359
360 getActionDefinitionsBuilder({G_FRAME_INDEX, G_GLOBAL_VALUE}).legalFor({p0});
361
362 // load/store: add more corner cases
363 for (unsigned Op : {G_LOAD, G_STORE}) {
364 auto &Action = getActionDefinitionsBuilder(Op);
365 Action.legalForTypesWithMemDesc({{s8, p0, s1, 1},
366 {s8, p0, s8, 1},
367 {s16, p0, s8, 1},
368 {s16, p0, s16, 1},
369 {s32, p0, s8, 1},
370 {s32, p0, s16, 1},
371 {s32, p0, s32, 1},
372 {s80, p0, s80, 1},
373 {p0, p0, p0, 1},
374 {v4s8, p0, v4s8, 1}});
375 if (Is64Bit)
376 Action.legalForTypesWithMemDesc({{s64, p0, s8, 1},
377 {s64, p0, s16, 1},
378 {s64, p0, s32, 1},
379 {s64, p0, s64, 1},
380 {v2s32, p0, v2s32, 1}});
381 if (HasSSE1)
382 Action.legalForTypesWithMemDesc({{v4s32, p0, v4s32, 1}});
383 if (HasSSE2)
384 Action.legalForTypesWithMemDesc({{v16s8, p0, v16s8, 1},
385 {v8s16, p0, v8s16, 1},
386 {v2s64, p0, v2s64, 1},
387 {v2p0, p0, v2p0, 1}});
388 if (HasAVX)
389 Action.legalForTypesWithMemDesc({{v32s8, p0, v32s8, 1},
390 {v16s16, p0, v16s16, 1},
391 {v8s32, p0, v8s32, 1},
392 {v4s64, p0, v4s64, 1},
393 {v4p0, p0, v4p0, 1}});
394 if (HasAVX512)
395 Action.legalForTypesWithMemDesc({{v64s8, p0, v64s8, 1},
396 {v32s16, p0, v32s16, 1},
397 {v16s32, p0, v16s32, 1},
398 {v8s64, p0, v8s64, 1}});
399 Action.widenScalarToNextPow2(0, /*Min=*/8)
400 .clampScalar(0, s8, sMaxScalar)
401 .scalarize(0);
402 }
403
404 for (unsigned Op : {G_SEXTLOAD, G_ZEXTLOAD}) {
405 auto &Action = getActionDefinitionsBuilder(Op);
406 Action.legalForTypesWithMemDesc({{s16, p0, s8, 1},
407 {s32, p0, s8, 1},
408 {s32, p0, s16, 1}});
409 if (Is64Bit)
410 Action.legalForTypesWithMemDesc({{s64, p0, s8, 1},
411 {s64, p0, s16, 1},
412 {s64, p0, s32, 1}});
413 // TODO - SSE41/AVX2/AVX512F/AVX512BW vector extensions
414 }
415
416 // sext, zext, and anyext
417 getActionDefinitionsBuilder({G_SEXT, G_ZEXT, G_ANYEXT})
418 .legalIf([=](const LegalityQuery &Query) {
419 return typeInSet(0, {s8, s16, s32})(Query) ||
420 (Query.Opcode == G_ANYEXT && Query.Types[0] == s128) ||
421 (Is64Bit && Query.Types[0] == s64);
422 })
423 .widenScalarToNextPow2(0, /*Min=*/8)
424 .clampScalar(0, s8, sMaxScalar)
425 .widenScalarToNextPow2(1, /*Min=*/8)
426 .clampScalar(1, s8, sMaxScalar)
427 .scalarize(0);
428
429 getActionDefinitionsBuilder(G_SEXT_INREG).lower();
430
431 // fp constants
432 getActionDefinitionsBuilder(G_FCONSTANT)
433 .legalIf([=](const LegalityQuery &Query) -> bool {
434 return (typeInSet(0, {s32, s64})(Query)) ||
435 (UseX87 && typeInSet(0, {s80})(Query));
436 });
437
438 // fp arithmetic
439 getActionDefinitionsBuilder({G_FADD, G_FSUB, G_FMUL, G_FDIV})
440 .legalIf([=](const LegalityQuery &Query) {
441 return (typeInSet(0, {s32, s64})(Query)) ||
442 (HasSSE1 && typeInSet(0, {v4s32})(Query)) ||
443 (HasSSE2 && typeInSet(0, {v2s64})(Query)) ||
444 (HasAVX && typeInSet(0, {v8s32, v4s64})(Query)) ||
445 (HasAVX512 && typeInSet(0, {v16s32, v8s64})(Query)) ||
446 (UseX87 && typeInSet(0, {s80})(Query));
447 });
448
449 // fp comparison
451 .legalIf([=](const LegalityQuery &Query) {
452 return (HasSSE1 && typePairInSet(0, 1, {{s8, s32}})(Query)) ||
453 (HasSSE2 && typePairInSet(0, 1, {{s8, s64}})(Query));
454 })
455 .clampScalar(0, s8, s8)
456 .clampScalar(1, s32, HasSSE2 ? s64 : s32)
458
459 // fp conversions
460 getActionDefinitionsBuilder(G_FPEXT).legalIf([=](const LegalityQuery &Query) {
461 return (HasSSE2 && typePairInSet(0, 1, {{s64, s32}})(Query)) ||
462 (HasAVX && typePairInSet(0, 1, {{v4s64, v4s32}})(Query)) ||
463 (HasAVX512 && typePairInSet(0, 1, {{v8s64, v8s32}})(Query));
464 });
465
467 [=](const LegalityQuery &Query) {
468 return (HasSSE2 && typePairInSet(0, 1, {{s32, s64}})(Query)) ||
469 (HasAVX && typePairInSet(0, 1, {{v4s32, v4s64}})(Query)) ||
470 (HasAVX512 && typePairInSet(0, 1, {{v8s32, v8s64}})(Query));
471 });
472
474 .legalIf([=](const LegalityQuery &Query) {
475 return (HasSSE1 &&
476 (typePairInSet(0, 1, {{s32, s32}})(Query) ||
477 (Is64Bit && typePairInSet(0, 1, {{s32, s64}})(Query)))) ||
478 (HasSSE2 &&
479 (typePairInSet(0, 1, {{s64, s32}})(Query) ||
480 (Is64Bit && typePairInSet(0, 1, {{s64, s64}})(Query))));
481 })
482 .clampScalar(1, s32, sMaxScalar)
484 .clampScalar(0, s32, HasSSE2 ? s64 : s32)
486
488 .legalIf([=](const LegalityQuery &Query) {
489 return (HasSSE1 &&
490 (typePairInSet(0, 1, {{s32, s32}})(Query) ||
491 (Is64Bit && typePairInSet(0, 1, {{s64, s32}})(Query)))) ||
492 (HasSSE2 &&
493 (typePairInSet(0, 1, {{s32, s64}})(Query) ||
494 (Is64Bit && typePairInSet(0, 1, {{s64, s64}})(Query))));
495 })
496 .clampScalar(1, s32, HasSSE2 ? s64 : s32)
498 .clampScalar(0, s32, sMaxScalar)
500
501 // vector ops
502 getActionDefinitionsBuilder(G_BUILD_VECTOR)
503 .customIf([=](const LegalityQuery &Query) {
504 return (HasSSE1 && typeInSet(0, {v4s32})(Query)) ||
505 (HasSSE2 && typeInSet(0, {v2s64, v8s16, v16s8})(Query)) ||
506 (HasAVX && typeInSet(0, {v4s64, v8s32, v16s16, v32s8})(Query)) ||
507 (HasAVX512 && typeInSet(0, {v8s64, v16s32, v32s16, v64s8}));
508 })
509 .clampNumElements(0, v16s8, s8MaxVector)
510 .clampNumElements(0, v8s16, s16MaxVector)
511 .clampNumElements(0, v4s32, s32MaxVector)
512 .clampNumElements(0, v2s64, s64MaxVector)
514
515 getActionDefinitionsBuilder({G_EXTRACT, G_INSERT})
516 .legalIf([=](const LegalityQuery &Query) {
517 unsigned SubIdx = Query.Opcode == G_EXTRACT ? 0 : 1;
518 unsigned FullIdx = Query.Opcode == G_EXTRACT ? 1 : 0;
519 return (HasAVX && typePairInSet(SubIdx, FullIdx,
520 {{v16s8, v32s8},
521 {v8s16, v16s16},
522 {v4s32, v8s32},
523 {v2s64, v4s64}})(Query)) ||
524 (HasAVX512 && typePairInSet(SubIdx, FullIdx,
525 {{v16s8, v64s8},
526 {v32s8, v64s8},
527 {v8s16, v32s16},
528 {v16s16, v32s16},
529 {v4s32, v16s32},
530 {v8s32, v16s32},
531 {v2s64, v8s64},
532 {v4s64, v8s64}})(Query));
533 });
534
535 // todo: only permit dst types up to max legal vector register size?
536 getActionDefinitionsBuilder(G_CONCAT_VECTORS)
537 .legalIf([=](const LegalityQuery &Query) {
538 return (HasSSE1 && typePairInSet(1, 0,
539 {{v16s8, v32s8},
540 {v8s16, v16s16},
541 {v4s32, v8s32},
542 {v2s64, v4s64}})(Query)) ||
543 (HasAVX && typePairInSet(1, 0,
544 {{v16s8, v64s8},
545 {v32s8, v64s8},
546 {v8s16, v32s16},
547 {v16s16, v32s16},
548 {v4s32, v16s32},
549 {v8s32, v16s32},
550 {v2s64, v8s64},
551 {v4s64, v8s64}})(Query));
552 });
553
554 // todo: vectors and address spaces
556 .legalFor({{s8, s32}, {s16, s32}, {s32, s32}, {s64, s32}, {p0, s32}})
557 .widenScalarToNextPow2(0, /*Min=*/8)
558 .clampScalar(0, HasCMOV ? s16 : s8, sMaxScalar)
559 .clampScalar(1, s32, s32);
560
561 // memory intrinsics
562 getActionDefinitionsBuilder({G_MEMCPY, G_MEMMOVE, G_MEMSET}).libcall();
563
564 getActionDefinitionsBuilder({G_DYN_STACKALLOC,
565 G_STACKSAVE,
566 G_STACKRESTORE}).lower();
567
568 // fp intrinsics
569 getActionDefinitionsBuilder(G_INTRINSIC_ROUNDEVEN)
570 .scalarize(0)
571 .minScalar(0, LLT::scalar(32))
572 .libcall();
573
574 getActionDefinitionsBuilder({G_FREEZE, G_CONSTANT_FOLD_BARRIER})
575 .legalFor({s8, s16, s32, s64, p0})
576 .widenScalarToNextPow2(0, /*Min=*/8)
577 .clampScalar(0, s8, sMaxScalar);
578
580 verify(*STI.getInstrInfo());
581}
582
584 LostDebugLocObserver &LocObserver) const {
585 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
586 MachineRegisterInfo &MRI = *MIRBuilder.getMRI();
587 switch (MI.getOpcode()) {
588 default:
589 // No idea what to do.
590 return false;
591 case TargetOpcode::G_BUILD_VECTOR:
592 return legalizeBuildVector(MI, MRI, Helper);
593 }
594 llvm_unreachable("expected switch to return");
595}
596
597bool X86LegalizerInfo::legalizeBuildVector(MachineInstr &MI,
599 LegalizerHelper &Helper) const {
600 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
601 const auto &BuildVector = cast<GBuildVector>(MI);
602 Register Dst = BuildVector.getReg(0);
603 LLT DstTy = MRI.getType(Dst);
604 MachineFunction &MF = MIRBuilder.getMF();
605 LLVMContext &Ctx = MF.getFunction().getContext();
606 uint64_t DstTySize = DstTy.getScalarSizeInBits();
607
609 for (unsigned i = 0; i < BuildVector.getNumSources(); ++i) {
610 Register Source = BuildVector.getSourceReg(i);
611
612 auto ValueAndReg = getIConstantVRegValWithLookThrough(Source, MRI);
613 if (ValueAndReg) {
614 CstIdxs.emplace_back(ConstantInt::get(Ctx, ValueAndReg->Value));
615 continue;
616 }
617
618 auto FPValueAndReg = getFConstantVRegValWithLookThrough(Source, MRI);
619 if (FPValueAndReg) {
620 CstIdxs.emplace_back(ConstantFP::get(Ctx, FPValueAndReg->Value));
621 continue;
622 }
623
624 if (getOpcodeDef<GImplicitDef>(Source, MRI)) {
625 CstIdxs.emplace_back(UndefValue::get(Type::getIntNTy(Ctx, DstTySize)));
626 continue;
627 }
628 return false;
629 }
630
631 Constant *ConstVal = ConstantVector::get(CstIdxs);
632
633 const DataLayout &DL = MIRBuilder.getDataLayout();
634 unsigned AddrSpace = DL.getDefaultGlobalsAddressSpace();
635 Align Alignment(DL.getABITypeAlign(ConstVal->getType()));
636 auto Addr = MIRBuilder.buildConstantPool(
637 LLT::pointer(AddrSpace, DL.getPointerSizeInBits(AddrSpace)),
638 MF.getConstantPool()->getConstantPoolIndex(ConstVal, Alignment));
639 MachineMemOperand *MMO =
641 MachineMemOperand::MOLoad, DstTy, Alignment);
642
643 MIRBuilder.buildLoad(Dst, Addr, *MMO);
644 MI.eraseFromParent();
645 return true;
646}
647
649 MachineInstr &MI) const {
650 return true;
651}
unsigned const MachineRegisterInfo * MRI
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
uint64_t Addr
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.
ppc ctr loops verify
This file declares the targeting of the Machinelegalizer class for X86.
static Constant * get(ArrayRef< Constant * > V)
Definition: Constants.cpp:1399
This is an important base class in LLVM.
Definition: Constant.h:42
This class represents an Operation in the Expression.
A parsed version of the target data layout string in and methods for querying it.
Definition: DataLayout.h:63
LLVMContext & getContext() const
getContext - Return a reference to the LLVMContext associated with this function.
Definition: Function.cpp:380
constexpr unsigned getScalarSizeInBits() const
Definition: LowLevelType.h:267
static constexpr LLT scalar(unsigned SizeInBits)
Get a low-level scalar or aggregate "bag of bits".
Definition: LowLevelType.h:42
static constexpr LLT pointer(unsigned AddressSpace, unsigned SizeInBits)
Get a low-level pointer in the given address space.
Definition: LowLevelType.h:57
static constexpr LLT fixed_vector(unsigned NumElements, unsigned ScalarSizeInBits)
Get a low-level fixed-width vector of some number of elements and element width.
Definition: LowLevelType.h:100
This is an important class for using LLVM in a threaded context.
Definition: LLVMContext.h:67
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 & 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.
MachineIRBuilder & MIRBuilder
Expose MIRBuilder so clients can set their own RecordInsertInstruction functions.
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 buildConstantPool(const DstOp &Res, unsigned Idx)
Build and insert Res = G_CONSTANT_POOL Idx.
MachineInstrBuilder buildLoad(const DstOp &Res, const SrcOp &Addr, MachineMemOperand &MMO)
Build and insert Res = G_LOAD Addr, MMO.
MachineFunction & getMF()
Getter for the function we currently build.
MachineRegisterInfo * getMRI()
Getter for MRI.
const DataLayout & getDataLayout() const
Representation of each machine instruction.
Definition: MachineInstr.h:69
A description of a memory reference used in the backend.
@ MOLoad
The memory access reads data.
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
Wrapper class representing virtual and physical registers.
Definition: Register.h:19
reference emplace_back(ArgTypes &&... Args)
Definition: SmallVector.h:950
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1209
static IntegerType * getIntNTy(LLVMContext &C, unsigned N)
static UndefValue * get(Type *T)
Static factory methods - Return an 'undef' object of the specified type.
Definition: Constants.cpp:1833
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)
bool hasSSE1() const
Definition: X86Subtarget.h:193
bool canUseCMOV() const
Definition: X86Subtarget.h:192
const X86InstrInfo * getInstrInfo() const override
Definition: X86Subtarget.h:122
bool hasAVX512() const
Definition: X86Subtarget.h:201
bool hasSSE41() const
Definition: X86Subtarget.h:197
bool hasSSE2() const
Definition: X86Subtarget.h:194
bool hasAVX() const
Definition: X86Subtarget.h:199
bool hasAVX2() const
Definition: X86Subtarget.h:200
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
LegalityPredicate typeInSet(unsigned TypeIdx, std::initializer_list< LLT > TypesInit)
True iff the given type index is one of the specified types.
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.
LegalityPredicate typeIs(unsigned TypeIdx, LLT TypesInit)
True iff the given type index is the specified type.
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
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
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< LLT > Types
static MachinePointerInfo getConstantPool(MachineFunction &MF)
Return a MachinePointerInfo record that refers to the constant pool.