LLVM 19.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 (Is64Bit && typeInSet(0, {s64})(Query)) ||
319 (HasSSE1 && typeInSet(0, {v16s8, v8s16, v4s32, v2s64})(Query)) ||
320 (HasAVX && typeInSet(0, {v32s8, v16s16, v8s32, v4s64})(Query)) ||
321 (HasAVX512 &&
322 typeInSet(0, {v64s8, v32s16, v16s32, v8s64})(Query));
323 })
324 .clampMinNumElements(0, s8, 16)
325 .clampMinNumElements(0, s16, 8)
326 .clampMinNumElements(0, s32, 4)
327 .clampMinNumElements(0, s64, 2)
328 .clampMaxNumElements(0, s8, HasAVX512 ? 64 : (HasAVX ? 32 : 16))
329 .clampMaxNumElements(0, s16, HasAVX512 ? 32 : (HasAVX ? 16 : 8))
330 .clampMaxNumElements(0, s32, HasAVX512 ? 16 : (HasAVX ? 8 : 4))
331 .clampMaxNumElements(0, s64, HasAVX512 ? 8 : (HasAVX ? 4 : 2))
332 .widenScalarToNextPow2(0, /*Min=*/32)
333 .clampScalar(0, s8, sMaxScalar)
334 .scalarize(0);
335
337
338 // pointer handling
339 const std::initializer_list<LLT> PtrTypes32 = {s1, s8, s16, s32};
340 const std::initializer_list<LLT> PtrTypes64 = {s1, s8, s16, s32, s64};
341
343 .legalForCartesianProduct(Is64Bit ? PtrTypes64 : PtrTypes32, {p0})
344 .maxScalar(0, sMaxScalar)
345 .widenScalarToNextPow2(0, /*Min*/ 8);
346
347 getActionDefinitionsBuilder(G_INTTOPTR).legalFor({{p0, sMaxScalar}});
348
349 getActionDefinitionsBuilder(G_CONSTANT_POOL).legalFor({p0});
350
352 .legalIf([=](const LegalityQuery &Query) -> bool {
353 return typePairInSet(0, 1, {{p0, s32}})(Query) ||
354 (Is64Bit && typePairInSet(0, 1, {{p0, s64}})(Query));
355 })
356 .widenScalarToNextPow2(1, /*Min*/ 32)
357 .clampScalar(1, s32, sMaxScalar);
358
359 getActionDefinitionsBuilder({G_FRAME_INDEX, G_GLOBAL_VALUE}).legalFor({p0});
360
361 // load/store: add more corner cases
362 for (unsigned Op : {G_LOAD, G_STORE}) {
363 auto &Action = getActionDefinitionsBuilder(Op);
364 Action.legalForTypesWithMemDesc({{s8, p0, s1, 1},
365 {s8, p0, s8, 1},
366 {s16, p0, s8, 1},
367 {s16, p0, s16, 1},
368 {s32, p0, s8, 1},
369 {s32, p0, s16, 1},
370 {s32, p0, s32, 1},
371 {s80, p0, s80, 1},
372 {p0, p0, p0, 1},
373 {v4s8, p0, v4s8, 1}});
374 if (Is64Bit)
375 Action.legalForTypesWithMemDesc({{s64, p0, s8, 1},
376 {s64, p0, s16, 1},
377 {s64, p0, s32, 1},
378 {s64, p0, s64, 1},
379 {v2s32, p0, v2s32, 1}});
380 if (HasSSE1)
381 Action.legalForTypesWithMemDesc({{v4s32, p0, v4s32, 1}});
382 if (HasSSE2)
383 Action.legalForTypesWithMemDesc({{v16s8, p0, v16s8, 1},
384 {v8s16, p0, v8s16, 1},
385 {v2s64, p0, v2s64, 1},
386 {v2p0, p0, v2p0, 1}});
387 if (HasAVX)
388 Action.legalForTypesWithMemDesc({{v32s8, p0, v32s8, 1},
389 {v16s16, p0, v16s16, 1},
390 {v8s32, p0, v8s32, 1},
391 {v4s64, p0, v4s64, 1},
392 {v4p0, p0, v4p0, 1}});
393 if (HasAVX512)
394 Action.legalForTypesWithMemDesc({{v64s8, p0, v64s8, 1},
395 {v32s16, p0, v32s16, 1},
396 {v16s32, p0, v16s32, 1},
397 {v8s64, p0, v8s64, 1}});
398 Action.widenScalarToNextPow2(0, /*Min=*/8)
399 .clampScalar(0, s8, sMaxScalar)
400 .scalarize(0);
401 }
402
403 for (unsigned Op : {G_SEXTLOAD, G_ZEXTLOAD}) {
404 auto &Action = getActionDefinitionsBuilder(Op);
405 Action.legalForTypesWithMemDesc({{s16, p0, s8, 1},
406 {s32, p0, s8, 1},
407 {s32, p0, s16, 1}});
408 if (Is64Bit)
409 Action.legalForTypesWithMemDesc({{s64, p0, s8, 1},
410 {s64, p0, s16, 1},
411 {s64, p0, s32, 1}});
412 // TODO - SSE41/AVX2/AVX512F/AVX512BW vector extensions
413 }
414
415 // sext, zext, and anyext
416 getActionDefinitionsBuilder({G_SEXT, G_ZEXT, G_ANYEXT})
417 .legalIf([=](const LegalityQuery &Query) {
418 return typeInSet(0, {s8, s16, s32})(Query) ||
419 (Query.Opcode == G_ANYEXT && Query.Types[0] == s128) ||
420 (Is64Bit && Query.Types[0] == s64);
421 })
422 .widenScalarToNextPow2(0, /*Min=*/8)
423 .clampScalar(0, s8, sMaxScalar)
424 .widenScalarToNextPow2(1, /*Min=*/8)
425 .clampScalar(1, s8, sMaxScalar)
426 .scalarize(0);
427
428 getActionDefinitionsBuilder(G_SEXT_INREG).lower();
429
430 // fp constants
431 getActionDefinitionsBuilder(G_FCONSTANT)
432 .legalIf([=](const LegalityQuery &Query) -> bool {
433 return (typeInSet(0, {s32, s64})(Query)) ||
434 (UseX87 && typeInSet(0, {s80})(Query));
435 });
436
437 // fp arithmetic
438 getActionDefinitionsBuilder({G_FADD, G_FSUB, G_FMUL, G_FDIV})
439 .legalIf([=](const LegalityQuery &Query) {
440 return (typeInSet(0, {s32, s64})(Query)) ||
441 (HasSSE1 && typeInSet(0, {v4s32})(Query)) ||
442 (HasSSE2 && typeInSet(0, {v2s64})(Query)) ||
443 (HasAVX && typeInSet(0, {v8s32, v4s64})(Query)) ||
444 (HasAVX512 && typeInSet(0, {v16s32, v8s64})(Query)) ||
445 (UseX87 && typeInSet(0, {s80})(Query));
446 });
447
448 // fp comparison
450 .legalIf([=](const LegalityQuery &Query) {
451 return (HasSSE1 && typePairInSet(0, 1, {{s8, s32}})(Query)) ||
452 (HasSSE2 && typePairInSet(0, 1, {{s8, s64}})(Query));
453 })
454 .clampScalar(0, s8, s8)
455 .clampScalar(1, s32, HasSSE2 ? s64 : s32)
457
458 // fp conversions
459 getActionDefinitionsBuilder(G_FPEXT).legalIf([=](const LegalityQuery &Query) {
460 return (HasSSE2 && typePairInSet(0, 1, {{s64, s32}})(Query)) ||
461 (HasAVX && typePairInSet(0, 1, {{v4s64, v4s32}})(Query)) ||
462 (HasAVX512 && typePairInSet(0, 1, {{v8s64, v8s32}})(Query));
463 });
464
466 [=](const LegalityQuery &Query) {
467 return (HasSSE2 && typePairInSet(0, 1, {{s32, s64}})(Query)) ||
468 (HasAVX && typePairInSet(0, 1, {{v4s32, v4s64}})(Query)) ||
469 (HasAVX512 && typePairInSet(0, 1, {{v8s32, v8s64}})(Query));
470 });
471
473 .legalIf([=](const LegalityQuery &Query) {
474 return (HasSSE1 &&
475 (typePairInSet(0, 1, {{s32, s32}})(Query) ||
476 (Is64Bit && typePairInSet(0, 1, {{s32, s64}})(Query)))) ||
477 (HasSSE2 &&
478 (typePairInSet(0, 1, {{s64, s32}})(Query) ||
479 (Is64Bit && typePairInSet(0, 1, {{s64, s64}})(Query))));
480 })
481 .clampScalar(1, s32, sMaxScalar)
483 .clampScalar(0, s32, HasSSE2 ? s64 : s32)
485
487 .legalIf([=](const LegalityQuery &Query) {
488 return (HasSSE1 &&
489 (typePairInSet(0, 1, {{s32, s32}})(Query) ||
490 (Is64Bit && typePairInSet(0, 1, {{s64, s32}})(Query)))) ||
491 (HasSSE2 &&
492 (typePairInSet(0, 1, {{s32, s64}})(Query) ||
493 (Is64Bit && typePairInSet(0, 1, {{s64, s64}})(Query))));
494 })
495 .clampScalar(1, s32, HasSSE2 ? s64 : s32)
497 .clampScalar(0, s32, sMaxScalar)
499
500 // vector ops
501 getActionDefinitionsBuilder(G_BUILD_VECTOR)
502 .customIf([=](const LegalityQuery &Query) {
503 return (HasSSE1 && typeInSet(0, {v4s32})(Query)) ||
504 (HasSSE2 && typeInSet(0, {v2s64, v8s16, v16s8})(Query)) ||
505 (HasAVX && typeInSet(0, {v4s64, v8s32, v16s16, v32s8})(Query)) ||
506 (HasAVX512 && typeInSet(0, {v8s64, v16s32, v32s16, v64s8}));
507 })
508 .clampNumElements(0, v16s8, s8MaxVector)
509 .clampNumElements(0, v8s16, s16MaxVector)
510 .clampNumElements(0, v4s32, s32MaxVector)
511 .clampNumElements(0, v2s64, s64MaxVector)
513
514 getActionDefinitionsBuilder({G_EXTRACT, G_INSERT})
515 .legalIf([=](const LegalityQuery &Query) {
516 unsigned SubIdx = Query.Opcode == G_EXTRACT ? 0 : 1;
517 unsigned FullIdx = Query.Opcode == G_EXTRACT ? 1 : 0;
518 return (HasAVX && typePairInSet(SubIdx, FullIdx,
519 {{v16s8, v32s8},
520 {v8s16, v16s16},
521 {v4s32, v8s32},
522 {v2s64, v4s64}})(Query)) ||
523 (HasAVX512 && typePairInSet(SubIdx, FullIdx,
524 {{v16s8, v64s8},
525 {v32s8, v64s8},
526 {v8s16, v32s16},
527 {v16s16, v32s16},
528 {v4s32, v16s32},
529 {v8s32, v16s32},
530 {v2s64, v8s64},
531 {v4s64, v8s64}})(Query));
532 });
533
534 // todo: only permit dst types up to max legal vector register size?
535 getActionDefinitionsBuilder(G_CONCAT_VECTORS)
536 .legalIf([=](const LegalityQuery &Query) {
537 return (HasSSE1 && typePairInSet(1, 0,
538 {{v16s8, v32s8},
539 {v8s16, v16s16},
540 {v4s32, v8s32},
541 {v2s64, v4s64}})(Query)) ||
542 (HasAVX && typePairInSet(1, 0,
543 {{v16s8, v64s8},
544 {v32s8, v64s8},
545 {v8s16, v32s16},
546 {v16s16, v32s16},
547 {v4s32, v16s32},
548 {v8s32, v16s32},
549 {v2s64, v8s64},
550 {v4s64, v8s64}})(Query));
551 });
552
553 // todo: vectors and address spaces
555 .legalFor({{s8, s32}, {s16, s32}, {s32, s32}, {s64, s32}, {p0, s32}})
556 .widenScalarToNextPow2(0, /*Min=*/8)
557 .clampScalar(0, HasCMOV ? s16 : s8, sMaxScalar)
558 .clampScalar(1, s32, s32);
559
560 // memory intrinsics
561 getActionDefinitionsBuilder({G_MEMCPY, G_MEMMOVE, G_MEMSET}).libcall();
562
563 getActionDefinitionsBuilder({G_DYN_STACKALLOC,
564 G_STACKSAVE,
565 G_STACKRESTORE}).lower();
566
567 // fp intrinsics
568 getActionDefinitionsBuilder(G_INTRINSIC_ROUNDEVEN)
569 .scalarize(0)
570 .minScalar(0, LLT::scalar(32))
571 .libcall();
572
573 getActionDefinitionsBuilder({G_FREEZE, G_CONSTANT_FOLD_BARRIER})
574 .legalFor({s8, s16, s32, s64, p0})
575 .widenScalarToNextPow2(0, /*Min=*/8)
576 .clampScalar(0, s8, sMaxScalar);
577
579 verify(*STI.getInstrInfo());
580}
581
583 LostDebugLocObserver &LocObserver) const {
584 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
585 MachineRegisterInfo &MRI = *MIRBuilder.getMRI();
586 switch (MI.getOpcode()) {
587 default:
588 // No idea what to do.
589 return false;
590 case TargetOpcode::G_BUILD_VECTOR:
591 return legalizeBuildVector(MI, MRI, Helper);
592 }
593 llvm_unreachable("expected switch to return");
594}
595
596bool X86LegalizerInfo::legalizeBuildVector(MachineInstr &MI,
598 LegalizerHelper &Helper) const {
599 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
600 const auto &BuildVector = cast<GBuildVector>(MI);
601 Register Dst = BuildVector.getReg(0);
602 LLT DstTy = MRI.getType(Dst);
603 MachineFunction &MF = MIRBuilder.getMF();
604 LLVMContext &Ctx = MF.getFunction().getContext();
605 uint64_t DstTySize = DstTy.getScalarSizeInBits();
606
608 for (unsigned i = 0; i < BuildVector.getNumSources(); ++i) {
609 Register Source = BuildVector.getSourceReg(i);
610
611 auto ValueAndReg = getIConstantVRegValWithLookThrough(Source, MRI);
612 if (ValueAndReg) {
613 CstIdxs.emplace_back(ConstantInt::get(Ctx, ValueAndReg->Value));
614 continue;
615 }
616
617 auto FPValueAndReg = getFConstantVRegValWithLookThrough(Source, MRI);
618 if (FPValueAndReg) {
619 CstIdxs.emplace_back(ConstantFP::get(Ctx, FPValueAndReg->Value));
620 continue;
621 }
622
623 if (getOpcodeDef<GImplicitDef>(Source, MRI)) {
624 CstIdxs.emplace_back(UndefValue::get(Type::getIntNTy(Ctx, DstTySize)));
625 continue;
626 }
627 return false;
628 }
629
630 Constant *ConstVal = ConstantVector::get(CstIdxs);
631
632 const DataLayout &DL = MIRBuilder.getDataLayout();
633 unsigned AddrSpace = DL.getDefaultGlobalsAddressSpace();
634 Align Alignment(DL.getABITypeAlign(ConstVal->getType()));
635 auto Addr = MIRBuilder.buildConstantPool(
636 LLT::pointer(AddrSpace, DL.getPointerSizeInBits(AddrSpace)),
637 MF.getConstantPool()->getConstantPoolIndex(ConstVal, Alignment));
638 MachineMemOperand *MMO =
640 MachineMemOperand::MOLoad, DstTy, Alignment);
641
642 MIRBuilder.buildLoad(Dst, Addr, *MMO);
643 MI.eraseFromParent();
644 return true;
645}
646
648 MachineInstr &MI) const {
649 return true;
650}
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
const char LLVMTargetMachineRef TM
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:41
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:110
LLVMContext & getContext() const
getContext - Return a reference to the LLVMContext associated with this function.
Definition: Function.cpp:358
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:1795
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:200
bool canUseCMOV() const
Definition: X86Subtarget.h:199
const X86InstrInfo * getInstrInfo() const override
Definition: X86Subtarget.h:129
bool hasAVX512() const
Definition: X86Subtarget.h:208
bool hasSSE41() const
Definition: X86Subtarget.h:204
bool hasSSE2() const
Definition: X86Subtarget.h:201
bool hasAVX() const
Definition: X86Subtarget.h:206
bool hasAVX2() const
Definition: X86Subtarget.h:207
#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.
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:440
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:426
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.