LLVM 21.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
103
105
106 // merge/unmerge
107 for (unsigned Op : {G_MERGE_VALUES, G_UNMERGE_VALUES}) {
108 unsigned BigTyIdx = Op == G_MERGE_VALUES ? 0 : 1;
109 unsigned LitTyIdx = Op == G_MERGE_VALUES ? 1 : 0;
111 .widenScalarToNextPow2(LitTyIdx, /*Min=*/8)
112 .widenScalarToNextPow2(BigTyIdx, /*Min=*/16)
113 .minScalar(LitTyIdx, s8)
114 .minScalar(BigTyIdx, s32)
115 .legalIf([=](const LegalityQuery &Q) {
116 switch (Q.Types[BigTyIdx].getSizeInBits()) {
117 case 16:
118 case 32:
119 case 64:
120 case 128:
121 case 256:
122 case 512:
123 break;
124 default:
125 return false;
126 }
127 switch (Q.Types[LitTyIdx].getSizeInBits()) {
128 case 8:
129 case 16:
130 case 32:
131 case 64:
132 case 128:
133 case 256:
134 return true;
135 default:
136 return false;
137 }
138 });
139 }
140
141 // integer addition/subtraction
142 getActionDefinitionsBuilder({G_ADD, G_SUB})
143 .legalIf([=](const LegalityQuery &Query) -> bool {
144 if (typeInSet(0, {s8, s16, s32})(Query))
145 return true;
146 if (Is64Bit && typeInSet(0, {s64})(Query))
147 return true;
148 if (HasSSE2 && typeInSet(0, {v16s8, v8s16, v4s32, v2s64})(Query))
149 return true;
150 if (HasAVX2 && typeInSet(0, {v32s8, v16s16, v8s32, v4s64})(Query))
151 return true;
152 if (HasAVX512 && typeInSet(0, {v16s32, v8s64})(Query))
153 return true;
154 if (HasBWI && typeInSet(0, {v64s8, v32s16})(Query))
155 return true;
156 return false;
157 })
158 .clampMinNumElements(0, s8, 16)
159 .clampMinNumElements(0, s16, 8)
160 .clampMinNumElements(0, s32, 4)
161 .clampMinNumElements(0, s64, 2)
162 .clampMaxNumElements(0, s8, HasBWI ? 64 : (HasAVX2 ? 32 : 16))
163 .clampMaxNumElements(0, s16, HasBWI ? 32 : (HasAVX2 ? 16 : 8))
164 .clampMaxNumElements(0, s32, HasAVX512 ? 16 : (HasAVX2 ? 8 : 4))
165 .clampMaxNumElements(0, s64, HasAVX512 ? 8 : (HasAVX2 ? 4 : 2))
166 .widenScalarToNextPow2(0, /*Min=*/32)
167 .clampScalar(0, s8, sMaxScalar)
168 .scalarize(0);
169
170 getActionDefinitionsBuilder({G_UADDE, G_UADDO, G_USUBE, G_USUBO})
171 .legalIf([=](const LegalityQuery &Query) -> bool {
172 return typePairInSet(0, 1, {{s8, s1}, {s16, s1}, {s32, s1}})(Query) ||
173 (Is64Bit && typePairInSet(0, 1, {{s64, s1}})(Query));
174 })
175 .widenScalarToNextPow2(0, /*Min=*/32)
176 .clampScalar(0, s8, sMaxScalar)
177 .clampScalar(1, s1, s1)
178 .scalarize(0);
179
180 // integer multiply
182 .legalIf([=](const LegalityQuery &Query) -> bool {
183 if (typeInSet(0, {s8, s16, s32})(Query))
184 return true;
185 if (Is64Bit && typeInSet(0, {s64})(Query))
186 return true;
187 if (HasSSE2 && typeInSet(0, {v8s16})(Query))
188 return true;
189 if (HasSSE41 && typeInSet(0, {v4s32})(Query))
190 return true;
191 if (HasAVX2 && typeInSet(0, {v16s16, v8s32})(Query))
192 return true;
193 if (HasAVX512 && typeInSet(0, {v16s32})(Query))
194 return true;
195 if (HasDQI && typeInSet(0, {v8s64})(Query))
196 return true;
197 if (HasDQI && HasVLX && typeInSet(0, {v2s64, v4s64})(Query))
198 return true;
199 if (HasBWI && typeInSet(0, {v32s16})(Query))
200 return true;
201 return false;
202 })
203 .clampMinNumElements(0, s16, 8)
204 .clampMinNumElements(0, s32, 4)
205 .clampMinNumElements(0, s64, HasVLX ? 2 : 8)
206 .clampMaxNumElements(0, s16, HasBWI ? 32 : (HasAVX2 ? 16 : 8))
207 .clampMaxNumElements(0, s32, HasAVX512 ? 16 : (HasAVX2 ? 8 : 4))
208 .clampMaxNumElements(0, s64, 8)
209 .widenScalarToNextPow2(0, /*Min=*/32)
210 .clampScalar(0, s8, sMaxScalar)
211 .scalarize(0);
212
213 getActionDefinitionsBuilder({G_SMULH, G_UMULH})
214 .legalIf([=](const LegalityQuery &Query) -> bool {
215 return typeInSet(0, {s8, s16, s32})(Query) ||
216 (Is64Bit && typeInSet(0, {s64})(Query));
217 })
218 .widenScalarToNextPow2(0, /*Min=*/32)
219 .clampScalar(0, s8, sMaxScalar)
220 .scalarize(0);
221
222 // integer divisions
223 getActionDefinitionsBuilder({G_SDIV, G_SREM, G_UDIV, G_UREM})
224 .legalIf([=](const LegalityQuery &Query) -> bool {
225 return typeInSet(0, {s8, s16, s32})(Query) ||
226 (Is64Bit && typeInSet(0, {s64})(Query));
227 })
228 .libcallFor({s64})
229 .clampScalar(0, s8, sMaxScalar);
230
231 // integer shifts
232 getActionDefinitionsBuilder({G_SHL, G_LSHR, G_ASHR})
233 .legalIf([=](const LegalityQuery &Query) -> bool {
234 return typePairInSet(0, 1, {{s8, s8}, {s16, s8}, {s32, s8}})(Query) ||
235 (Is64Bit && typePairInSet(0, 1, {{s64, s8}})(Query));
236 })
237 .clampScalar(0, s8, sMaxScalar)
238 .clampScalar(1, s8, s8);
239
240 // integer logic
241 getActionDefinitionsBuilder({G_AND, G_OR, G_XOR})
242 .legalIf([=](const LegalityQuery &Query) -> bool {
243 if (typeInSet(0, {s8, s16, s32})(Query))
244 return true;
245 if (Is64Bit && typeInSet(0, {s64})(Query))
246 return true;
247 if (HasSSE2 && typeInSet(0, {v16s8, v8s16, v4s32, v2s64})(Query))
248 return true;
249 if (HasAVX && typeInSet(0, {v32s8, v16s16, v8s32, v4s64})(Query))
250 return true;
251 if (HasAVX512 && typeInSet(0, {v64s8, v32s16, v16s32, v8s64})(Query))
252 return true;
253 return false;
254 })
255 .clampMinNumElements(0, s8, 16)
256 .clampMinNumElements(0, s16, 8)
257 .clampMinNumElements(0, s32, 4)
258 .clampMinNumElements(0, s64, 2)
259 .clampMaxNumElements(0, s8, HasAVX512 ? 64 : (HasAVX ? 32 : 16))
260 .clampMaxNumElements(0, s16, HasAVX512 ? 32 : (HasAVX ? 16 : 8))
261 .clampMaxNumElements(0, s32, HasAVX512 ? 16 : (HasAVX ? 8 : 4))
262 .clampMaxNumElements(0, s64, HasAVX512 ? 8 : (HasAVX ? 4 : 2))
263 .widenScalarToNextPow2(0, /*Min=*/32)
264 .clampScalar(0, s8, sMaxScalar)
265 .scalarize(0);
266
267 // integer comparison
268 const std::initializer_list<LLT> IntTypes32 = {s8, s16, s32, p0};
269 const std::initializer_list<LLT> IntTypes64 = {s8, s16, s32, s64, p0};
270
272 .legalForCartesianProduct({s8}, Is64Bit ? IntTypes64 : IntTypes32)
273 .clampScalar(0, s8, s8)
274 .clampScalar(1, s8, sMaxScalar);
275
276 // bswap
278 .legalIf([=](const LegalityQuery &Query) {
279 return Query.Types[0] == s32 ||
280 (Subtarget.is64Bit() && Query.Types[0] == s64);
281 })
282 .widenScalarToNextPow2(0, /*Min=*/32)
283 .clampScalar(0, s32, sMaxScalar);
284
285 // popcount
287 .legalIf([=](const LegalityQuery &Query) -> bool {
288 return Subtarget.hasPOPCNT() &&
289 (typePairInSet(0, 1, {{s16, s16}, {s32, s32}})(Query) ||
290 (Is64Bit && typePairInSet(0, 1, {{s64, s64}})(Query)));
291 })
292 .widenScalarToNextPow2(1, /*Min=*/16)
293 .clampScalar(1, s16, sMaxScalar)
294 .scalarSameSizeAs(0, 1);
295
296 // count leading zeros (LZCNT)
298 .legalIf([=](const LegalityQuery &Query) -> bool {
299 return Subtarget.hasLZCNT() &&
300 (typePairInSet(0, 1, {{s16, s16}, {s32, s32}})(Query) ||
301 (Is64Bit && typePairInSet(0, 1, {{s64, s64}})(Query)));
302 })
303 .widenScalarToNextPow2(1, /*Min=*/16)
304 .clampScalar(1, s16, sMaxScalar)
305 .scalarSameSizeAs(0, 1);
306
307 // count trailing zeros
308 getActionDefinitionsBuilder({G_CTTZ_ZERO_UNDEF, G_CTTZ})
309 .legalIf([=](const LegalityQuery &Query) -> bool {
310 return (Query.Opcode == G_CTTZ_ZERO_UNDEF || Subtarget.hasBMI()) &&
311 (typePairInSet(0, 1, {{s16, s16}, {s32, s32}})(Query) ||
312 (Is64Bit && typePairInSet(0, 1, {{s64, s64}})(Query)));
313 })
314 .widenScalarToNextPow2(1, /*Min=*/16)
315 .clampScalar(1, s16, sMaxScalar)
316 .scalarSameSizeAs(0, 1);
317
318 // control flow
320 .legalIf([=](const LegalityQuery &Query) -> bool {
321 return typeInSet(0, {s8, s16, s32, p0})(Query) ||
322 (UseX87 && typeIs(0, s80)(Query)) ||
323 (Is64Bit && typeIs(0, s64)(Query)) ||
324 (HasSSE1 && typeInSet(0, {v16s8, v8s16, v4s32, v2s64})(Query)) ||
325 (HasAVX && typeInSet(0, {v32s8, v16s16, v8s32, v4s64})(Query)) ||
326 (HasAVX512 &&
327 typeInSet(0, {v64s8, v32s16, v16s32, v8s64})(Query));
328 })
329 .clampMinNumElements(0, s8, 16)
330 .clampMinNumElements(0, s16, 8)
331 .clampMinNumElements(0, s32, 4)
332 .clampMinNumElements(0, s64, 2)
333 .clampMaxNumElements(0, s8, HasAVX512 ? 64 : (HasAVX ? 32 : 16))
334 .clampMaxNumElements(0, s16, HasAVX512 ? 32 : (HasAVX ? 16 : 8))
335 .clampMaxNumElements(0, s32, HasAVX512 ? 16 : (HasAVX ? 8 : 4))
336 .clampMaxNumElements(0, s64, HasAVX512 ? 8 : (HasAVX ? 4 : 2))
337 .widenScalarToNextPow2(0, /*Min=*/32)
338 .clampScalar(0, s8, sMaxScalar)
339 .scalarize(0);
340
342
343 // pointer handling
344 const std::initializer_list<LLT> PtrTypes32 = {s1, s8, s16, s32};
345 const std::initializer_list<LLT> PtrTypes64 = {s1, s8, s16, s32, s64};
346
348 .legalForCartesianProduct(Is64Bit ? PtrTypes64 : PtrTypes32, {p0})
349 .maxScalar(0, sMaxScalar)
350 .widenScalarToNextPow2(0, /*Min*/ 8);
351
352 getActionDefinitionsBuilder(G_INTTOPTR).legalFor({{p0, sMaxScalar}});
353
354 getActionDefinitionsBuilder(G_CONSTANT_POOL).legalFor({p0});
355
357 .legalIf([=](const LegalityQuery &Query) -> bool {
358 return typePairInSet(0, 1, {{p0, s32}})(Query) ||
359 (Is64Bit && typePairInSet(0, 1, {{p0, s64}})(Query));
360 })
361 .widenScalarToNextPow2(1, /*Min*/ 32)
362 .clampScalar(1, s32, sMaxScalar);
363
364 getActionDefinitionsBuilder({G_FRAME_INDEX, G_GLOBAL_VALUE}).legalFor({p0});
365
366 // load/store: add more corner cases
367 for (unsigned Op : {G_LOAD, G_STORE}) {
368 auto &Action = getActionDefinitionsBuilder(Op);
369 Action.legalForTypesWithMemDesc({{s8, p0, s1, 1},
370 {s8, p0, s8, 1},
371 {s16, p0, s8, 1},
372 {s16, p0, s16, 1},
373 {s32, p0, s8, 1},
374 {s32, p0, s16, 1},
375 {s32, p0, s32, 1},
376 {s80, p0, s80, 1},
377 {p0, p0, p0, 1},
378 {v4s8, p0, v4s8, 1}});
379 if (Is64Bit)
380 Action.legalForTypesWithMemDesc({{s64, p0, s8, 1},
381 {s64, p0, s16, 1},
382 {s64, p0, s32, 1},
383 {s64, p0, s64, 1},
384 {v2s32, p0, v2s32, 1}});
385 if (HasSSE1)
386 Action.legalForTypesWithMemDesc({{v4s32, p0, v4s32, 1}});
387 if (HasSSE2)
388 Action.legalForTypesWithMemDesc({{v16s8, p0, v16s8, 1},
389 {v8s16, p0, v8s16, 1},
390 {v2s64, p0, v2s64, 1},
391 {v2p0, p0, v2p0, 1}});
392 if (HasAVX)
393 Action.legalForTypesWithMemDesc({{v32s8, p0, v32s8, 1},
394 {v16s16, p0, v16s16, 1},
395 {v8s32, p0, v8s32, 1},
396 {v4s64, p0, v4s64, 1},
397 {v4p0, p0, v4p0, 1}});
398 if (HasAVX512)
399 Action.legalForTypesWithMemDesc({{v64s8, p0, v64s8, 1},
400 {v32s16, p0, v32s16, 1},
401 {v16s32, p0, v16s32, 1},
402 {v8s64, p0, v8s64, 1}});
403 Action.widenScalarToNextPow2(0, /*Min=*/8)
404 .clampScalar(0, s8, sMaxScalar)
405 .scalarize(0);
406 }
407
408 for (unsigned Op : {G_SEXTLOAD, G_ZEXTLOAD}) {
409 auto &Action = getActionDefinitionsBuilder(Op);
410 Action.legalForTypesWithMemDesc({{s16, p0, s8, 1},
411 {s32, p0, s8, 1},
412 {s32, p0, s16, 1}});
413 if (Is64Bit)
414 Action.legalForTypesWithMemDesc({{s64, p0, s8, 1},
415 {s64, p0, s16, 1},
416 {s64, p0, s32, 1}});
417 // TODO - SSE41/AVX2/AVX512F/AVX512BW vector extensions
418 }
419
420 // sext, zext, and anyext
421 getActionDefinitionsBuilder({G_SEXT, G_ZEXT, G_ANYEXT})
422 .legalIf([=](const LegalityQuery &Query) {
423 return typeInSet(0, {s8, s16, s32})(Query) ||
424 (Query.Opcode == G_ANYEXT && Query.Types[0] == s128) ||
425 (Is64Bit && Query.Types[0] == s64);
426 })
427 .widenScalarToNextPow2(0, /*Min=*/8)
428 .clampScalar(0, s8, sMaxScalar)
429 .widenScalarToNextPow2(1, /*Min=*/8)
430 .clampScalar(1, s8, sMaxScalar)
431 .scalarize(0);
432
433 getActionDefinitionsBuilder(G_SEXT_INREG).lower();
434
435 // fp constants
436 getActionDefinitionsBuilder(G_FCONSTANT)
437 .legalIf([=](const LegalityQuery &Query) -> bool {
438 return (typeInSet(0, {s32, s64})(Query)) ||
439 (UseX87 && typeInSet(0, {s80})(Query));
440 });
441
442 // fp arithmetic
443 getActionDefinitionsBuilder({G_FADD, G_FSUB, G_FMUL, G_FDIV})
444 .legalIf([=](const LegalityQuery &Query) {
445 return (typeInSet(0, {s32, s64})(Query)) ||
446 (HasSSE1 && typeInSet(0, {v4s32})(Query)) ||
447 (HasSSE2 && typeInSet(0, {v2s64})(Query)) ||
448 (HasAVX && typeInSet(0, {v8s32, v4s64})(Query)) ||
449 (HasAVX512 && typeInSet(0, {v16s32, v8s64})(Query)) ||
450 (UseX87 && typeInSet(0, {s80})(Query));
451 });
452
453 // fp comparison
455 .legalIf([=](const LegalityQuery &Query) {
456 return (HasSSE1 && typePairInSet(0, 1, {{s8, s32}})(Query)) ||
457 (HasSSE2 && typePairInSet(0, 1, {{s8, s64}})(Query));
458 })
459 .clampScalar(0, s8, s8)
460 .clampScalar(1, s32, HasSSE2 ? s64 : s32)
462
463 // fp conversions
464 getActionDefinitionsBuilder(G_FPEXT).legalIf([=](const LegalityQuery &Query) {
465 return (HasSSE2 && typePairInSet(0, 1, {{s64, s32}})(Query)) ||
466 (HasAVX && typePairInSet(0, 1, {{v4s64, v4s32}})(Query)) ||
467 (HasAVX512 && typePairInSet(0, 1, {{v8s64, v8s32}})(Query));
468 });
469
471 [=](const LegalityQuery &Query) {
472 return (HasSSE2 && typePairInSet(0, 1, {{s32, s64}})(Query)) ||
473 (HasAVX && typePairInSet(0, 1, {{v4s32, v4s64}})(Query)) ||
474 (HasAVX512 && typePairInSet(0, 1, {{v8s32, v8s64}})(Query));
475 });
476
478 .legalIf([=](const LegalityQuery &Query) {
479 return (HasSSE1 &&
480 (typePairInSet(0, 1, {{s32, s32}})(Query) ||
481 (Is64Bit && typePairInSet(0, 1, {{s32, s64}})(Query)))) ||
482 (HasSSE2 &&
483 (typePairInSet(0, 1, {{s64, s32}})(Query) ||
484 (Is64Bit && typePairInSet(0, 1, {{s64, s64}})(Query))));
485 })
486 .clampScalar(1, s32, sMaxScalar)
488 .clampScalar(0, s32, HasSSE2 ? s64 : s32)
490
492 .legalIf([=](const LegalityQuery &Query) {
493 return (HasSSE1 &&
494 (typePairInSet(0, 1, {{s32, s32}})(Query) ||
495 (Is64Bit && typePairInSet(0, 1, {{s64, s32}})(Query)))) ||
496 (HasSSE2 &&
497 (typePairInSet(0, 1, {{s32, s64}})(Query) ||
498 (Is64Bit && typePairInSet(0, 1, {{s64, s64}})(Query))));
499 })
500 .clampScalar(1, s32, HasSSE2 ? s64 : s32)
502 .clampScalar(0, s32, sMaxScalar)
504
505 // For G_UITOFP and G_FPTOUI without AVX512, we have to custom legalize types
506 // <= s32 manually. Otherwise, in custom handler there is no way to
507 // understand whether s32 is an original type and we need to promote it to
508 // s64 or s32 is obtained after widening and we shouldn't widen it to s64.
509 //
510 // For AVX512 we simply widen types as there is direct mapping from opcodes
511 // to asm instructions.
513 .legalIf([=](const LegalityQuery &Query) {
514 return HasAVX512 && typeInSet(0, {s32, s64})(Query) &&
515 typeInSet(1, {s32, s64})(Query);
516 })
517 .customIf([=](const LegalityQuery &Query) {
518 return !HasAVX512 &&
519 ((HasSSE1 && typeIs(0, s32)(Query)) ||
520 (HasSSE2 && typeIs(0, s64)(Query))) &&
521 scalarNarrowerThan(1, Is64Bit ? 64 : 32)(Query);
522 })
523 .lowerIf([=](const LegalityQuery &Query) {
524 // Lower conversions from s64
525 return !HasAVX512 &&
526 ((HasSSE1 && typeIs(0, s32)(Query)) ||
527 (HasSSE2 && typeIs(0, s64)(Query))) &&
528 (Is64Bit && typeIs(1, s64)(Query));
529 })
530 .clampScalar(0, s32, HasSSE2 ? s64 : s32)
532 .clampScalar(1, s32, sMaxScalar)
534
536 .legalIf([=](const LegalityQuery &Query) {
537 return HasAVX512 && typeInSet(0, {s32, s64})(Query) &&
538 typeInSet(1, {s32, s64})(Query);
539 })
540 .customIf([=](const LegalityQuery &Query) {
541 return !HasAVX512 &&
542 ((HasSSE1 && typeIs(1, s32)(Query)) ||
543 (HasSSE2 && typeIs(1, s64)(Query))) &&
544 scalarNarrowerThan(0, Is64Bit ? 64 : 32)(Query);
545 })
546 // TODO: replace with customized legalization using
547 // specifics of cvttsd2si. The selection of this node requires
548 // a vector type. Either G_SCALAR_TO_VECTOR is needed or more advanced
549 // support of G_BUILD_VECTOR/G_INSERT_VECTOR_ELT is required beforehand.
550 .lowerIf([=](const LegalityQuery &Query) {
551 return !HasAVX512 &&
552 ((HasSSE1 && typeIs(1, s32)(Query)) ||
553 (HasSSE2 && typeIs(1, s64)(Query))) &&
554 (Is64Bit && typeIs(0, s64)(Query));
555 })
556 .clampScalar(0, s32, sMaxScalar)
558 .clampScalar(1, s32, HasSSE2 ? s64 : s32)
560
561 // vector ops
562 getActionDefinitionsBuilder(G_BUILD_VECTOR)
563 .customIf([=](const LegalityQuery &Query) {
564 return (HasSSE1 && typeInSet(0, {v4s32})(Query)) ||
565 (HasSSE2 && typeInSet(0, {v2s64, v8s16, v16s8})(Query)) ||
566 (HasAVX && typeInSet(0, {v4s64, v8s32, v16s16, v32s8})(Query)) ||
567 (HasAVX512 && typeInSet(0, {v8s64, v16s32, v32s16, v64s8}));
568 })
569 .clampNumElements(0, v16s8, s8MaxVector)
570 .clampNumElements(0, v8s16, s16MaxVector)
571 .clampNumElements(0, v4s32, s32MaxVector)
572 .clampNumElements(0, v2s64, s64MaxVector)
574
575 getActionDefinitionsBuilder({G_EXTRACT, G_INSERT})
576 .legalIf([=](const LegalityQuery &Query) {
577 unsigned SubIdx = Query.Opcode == G_EXTRACT ? 0 : 1;
578 unsigned FullIdx = Query.Opcode == G_EXTRACT ? 1 : 0;
579 return (HasAVX && typePairInSet(SubIdx, FullIdx,
580 {{v16s8, v32s8},
581 {v8s16, v16s16},
582 {v4s32, v8s32},
583 {v2s64, v4s64}})(Query)) ||
584 (HasAVX512 && typePairInSet(SubIdx, FullIdx,
585 {{v16s8, v64s8},
586 {v32s8, v64s8},
587 {v8s16, v32s16},
588 {v16s16, v32s16},
589 {v4s32, v16s32},
590 {v8s32, v16s32},
591 {v2s64, v8s64},
592 {v4s64, v8s64}})(Query));
593 });
594
595 // todo: only permit dst types up to max legal vector register size?
596 getActionDefinitionsBuilder(G_CONCAT_VECTORS)
597 .legalIf([=](const LegalityQuery &Query) {
598 return (HasSSE1 && typePairInSet(1, 0,
599 {{v16s8, v32s8},
600 {v8s16, v16s16},
601 {v4s32, v8s32},
602 {v2s64, v4s64}})(Query)) ||
603 (HasAVX && typePairInSet(1, 0,
604 {{v16s8, v64s8},
605 {v32s8, v64s8},
606 {v8s16, v32s16},
607 {v16s16, v32s16},
608 {v4s32, v16s32},
609 {v8s32, v16s32},
610 {v2s64, v8s64},
611 {v4s64, v8s64}})(Query));
612 });
613
614 // todo: vectors and address spaces
616 .legalFor({{s8, s32}, {s16, s32}, {s32, s32}, {s64, s32}, {p0, s32}})
617 .widenScalarToNextPow2(0, /*Min=*/8)
618 .clampScalar(0, HasCMOV ? s16 : s8, sMaxScalar)
619 .clampScalar(1, s32, s32);
620
621 // memory intrinsics
622 getActionDefinitionsBuilder({G_MEMCPY, G_MEMMOVE, G_MEMSET}).libcall();
623
624 getActionDefinitionsBuilder({G_DYN_STACKALLOC,
625 G_STACKSAVE,
626 G_STACKRESTORE}).lower();
627
628 // fp intrinsics
629 getActionDefinitionsBuilder(G_INTRINSIC_ROUNDEVEN)
630 .scalarize(0)
631 .minScalar(0, LLT::scalar(32))
632 .libcall();
633
634 getActionDefinitionsBuilder({G_FREEZE, G_CONSTANT_FOLD_BARRIER})
635 .legalFor({s8, s16, s32, s64, p0})
636 .widenScalarToNextPow2(0, /*Min=*/8)
637 .clampScalar(0, s8, sMaxScalar);
638
640 verify(*STI.getInstrInfo());
641}
642
644 LostDebugLocObserver &LocObserver) const {
645 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
646 MachineRegisterInfo &MRI = *MIRBuilder.getMRI();
647 switch (MI.getOpcode()) {
648 default:
649 // No idea what to do.
650 return false;
651 case TargetOpcode::G_BUILD_VECTOR:
652 return legalizeBuildVector(MI, MRI, Helper);
653 case TargetOpcode::G_FPTOUI:
654 return legalizeFPTOUI(MI, MRI, Helper);
655 case TargetOpcode::G_UITOFP:
656 return legalizeUITOFP(MI, MRI, Helper);
657 }
658 llvm_unreachable("expected switch to return");
659}
660
661bool X86LegalizerInfo::legalizeBuildVector(MachineInstr &MI,
663 LegalizerHelper &Helper) const {
664 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
665 const auto &BuildVector = cast<GBuildVector>(MI);
666 Register Dst = BuildVector.getReg(0);
667 LLT DstTy = MRI.getType(Dst);
668 MachineFunction &MF = MIRBuilder.getMF();
669 LLVMContext &Ctx = MF.getFunction().getContext();
670 uint64_t DstTySize = DstTy.getScalarSizeInBits();
671
673 for (unsigned i = 0; i < BuildVector.getNumSources(); ++i) {
674 Register Source = BuildVector.getSourceReg(i);
675
676 auto ValueAndReg = getIConstantVRegValWithLookThrough(Source, MRI);
677 if (ValueAndReg) {
678 CstIdxs.emplace_back(ConstantInt::get(Ctx, ValueAndReg->Value));
679 continue;
680 }
681
682 auto FPValueAndReg = getFConstantVRegValWithLookThrough(Source, MRI);
683 if (FPValueAndReg) {
684 CstIdxs.emplace_back(ConstantFP::get(Ctx, FPValueAndReg->Value));
685 continue;
686 }
687
688 if (getOpcodeDef<GImplicitDef>(Source, MRI)) {
689 CstIdxs.emplace_back(UndefValue::get(Type::getIntNTy(Ctx, DstTySize)));
690 continue;
691 }
692 return false;
693 }
694
695 Constant *ConstVal = ConstantVector::get(CstIdxs);
696
697 const DataLayout &DL = MIRBuilder.getDataLayout();
698 unsigned AddrSpace = DL.getDefaultGlobalsAddressSpace();
699 Align Alignment(DL.getABITypeAlign(ConstVal->getType()));
700 auto Addr = MIRBuilder.buildConstantPool(
701 LLT::pointer(AddrSpace, DL.getPointerSizeInBits(AddrSpace)),
702 MF.getConstantPool()->getConstantPoolIndex(ConstVal, Alignment));
703 MachineMemOperand *MMO =
705 MachineMemOperand::MOLoad, DstTy, Alignment);
706
707 MIRBuilder.buildLoad(Dst, Addr, *MMO);
708 MI.eraseFromParent();
709 return true;
710}
711
712bool X86LegalizerInfo::legalizeFPTOUI(MachineInstr &MI,
714 LegalizerHelper &Helper) const {
715 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
716 auto [Dst, DstTy, Src, SrcTy] = MI.getFirst2RegLLTs();
717 unsigned DstSizeInBits = DstTy.getScalarSizeInBits();
718 const LLT s32 = LLT::scalar(32);
719 const LLT s64 = LLT::scalar(64);
720
721 // Simply reuse FPTOSI when it is possible to widen the type
722 if (DstSizeInBits <= 32) {
723 auto Casted = MIRBuilder.buildFPTOSI(DstTy == s32 ? s64 : s32, Src);
724 MIRBuilder.buildTrunc(Dst, Casted);
725 MI.eraseFromParent();
726 return true;
727 }
728
729 return false;
730}
731
732bool X86LegalizerInfo::legalizeUITOFP(MachineInstr &MI,
734 LegalizerHelper &Helper) const {
735 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
736 auto [Dst, DstTy, Src, SrcTy] = MI.getFirst2RegLLTs();
737 const LLT s32 = LLT::scalar(32);
738 const LLT s64 = LLT::scalar(64);
739
740 // Simply reuse SITOFP when it is possible to widen the type
741 if (SrcTy.getSizeInBits() <= 32) {
742 auto Ext = MIRBuilder.buildZExt(SrcTy == s32 ? s64 : s32, Src);
743 MIRBuilder.buildSITOFP(Dst, Ext);
744 MI.eraseFromParent();
745 return true;
746 }
747
748 return false;
749}
750
752 MachineInstr &MI) const {
753 return true;
754}
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:1421
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:369
constexpr unsigned getScalarSizeInBits() const
Definition: LowLevelType.h:264
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 buildFPTOSI(const DstOp &Dst, const SrcOp &Src0)
Build and insert Res = G_FPTOSI Src0.
MachineInstrBuilder buildConstantPool(const DstOp &Res, unsigned Idx)
Build and insert Res = G_CONSTANT_POOL Idx.
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 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.
const DataLayout & getDataLayout() const
Representation of each machine instruction.
Definition: MachineInstr.h:71
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:937
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1196
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:1859
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.
LegalityPredicate scalarNarrowerThan(unsigned TypeIdx, unsigned Size)
True iff the specified type index is a scalar that's narrower than the given size.
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.