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"
20#include "llvm/IR/Type.h"
21
22using namespace llvm;
23using namespace TargetOpcode;
24using namespace LegalizeActions;
25using namespace LegalityPredicates;
26
28 const X86TargetMachine &TM)
29 : Subtarget(STI) {
30
31 bool Is64Bit = Subtarget.is64Bit();
32 bool HasCMOV = Subtarget.canUseCMOV();
33 bool HasSSE1 = Subtarget.hasSSE1();
34 bool HasSSE2 = Subtarget.hasSSE2();
35 bool HasSSE41 = Subtarget.hasSSE41();
36 bool HasAVX = Subtarget.hasAVX();
37 bool HasAVX2 = Subtarget.hasAVX2();
38 bool HasAVX512 = Subtarget.hasAVX512();
39 bool HasVLX = Subtarget.hasVLX();
40 bool HasDQI = Subtarget.hasAVX512() && Subtarget.hasDQI();
41 bool HasBWI = Subtarget.hasAVX512() && Subtarget.hasBWI();
42 bool UseX87 = !Subtarget.useSoftFloat() && Subtarget.hasX87();
43
44 const LLT p0 = LLT::pointer(0, TM.getPointerSizeInBits(0));
45 const LLT s1 = LLT::scalar(1);
46 const LLT s8 = LLT::scalar(8);
47 const LLT s16 = LLT::scalar(16);
48 const LLT s32 = LLT::scalar(32);
49 const LLT s64 = LLT::scalar(64);
50 const LLT s80 = LLT::scalar(80);
51 const LLT s128 = LLT::scalar(128);
52 const LLT sMaxScalar = Subtarget.is64Bit() ? s64 : s32;
53 const LLT v2s32 = LLT::fixed_vector(2, 32);
54 const LLT v4s8 = LLT::fixed_vector(4, 8);
55
56
57 const LLT v16s8 = LLT::fixed_vector(16, 8);
58 const LLT v8s16 = LLT::fixed_vector(8, 16);
59 const LLT v4s32 = LLT::fixed_vector(4, 32);
60 const LLT v2s64 = LLT::fixed_vector(2, 64);
61 const LLT v2p0 = LLT::fixed_vector(2, p0);
62
63 const LLT v32s8 = LLT::fixed_vector(32, 8);
64 const LLT v16s16 = LLT::fixed_vector(16, 16);
65 const LLT v8s32 = LLT::fixed_vector(8, 32);
66 const LLT v4s64 = LLT::fixed_vector(4, 64);
67 const LLT v4p0 = LLT::fixed_vector(4, p0);
68
69 const LLT v64s8 = LLT::fixed_vector(64, 8);
70 const LLT v32s16 = LLT::fixed_vector(32, 16);
71 const LLT v16s32 = LLT::fixed_vector(16, 32);
72 const LLT v8s64 = LLT::fixed_vector(8, 64);
73
74 // todo: AVX512 bool vector predicate types
75
76 // implicit/constants
77 getActionDefinitionsBuilder(G_IMPLICIT_DEF)
78 .legalIf([=](const LegalityQuery &Query) -> bool {
79 // 32/64-bits needs support for s64/s128 to handle cases:
80 // s64 = EXTEND (G_IMPLICIT_DEF s32) -> s64 = G_IMPLICIT_DEF
81 // s128 = EXTEND (G_IMPLICIT_DEF s32/s64) -> s128 = G_IMPLICIT_DEF
82 return typeInSet(0, {p0, s1, s8, s16, s32, s64})(Query) ||
83 (Is64Bit && typeInSet(0, {s128})(Query));
84 });
85
87 .legalIf([=](const LegalityQuery &Query) -> bool {
88 return typeInSet(0, {p0, s8, s16, s32})(Query) ||
89 (Is64Bit && typeInSet(0, {s64})(Query));
90 })
91 .widenScalarToNextPow2(0, /*Min=*/8)
92 .clampScalar(0, s8, sMaxScalar);
93
94 // merge/unmerge
95 for (unsigned Op : {G_MERGE_VALUES, G_UNMERGE_VALUES}) {
96 unsigned BigTyIdx = Op == G_MERGE_VALUES ? 0 : 1;
97 unsigned LitTyIdx = Op == G_MERGE_VALUES ? 1 : 0;
99 .widenScalarToNextPow2(LitTyIdx, /*Min=*/8)
100 .widenScalarToNextPow2(BigTyIdx, /*Min=*/16)
101 .minScalar(LitTyIdx, s8)
102 .minScalar(BigTyIdx, s32)
103 .legalIf([=](const LegalityQuery &Q) {
104 switch (Q.Types[BigTyIdx].getSizeInBits()) {
105 case 16:
106 case 32:
107 case 64:
108 case 128:
109 case 256:
110 case 512:
111 break;
112 default:
113 return false;
114 }
115 switch (Q.Types[LitTyIdx].getSizeInBits()) {
116 case 8:
117 case 16:
118 case 32:
119 case 64:
120 case 128:
121 case 256:
122 return true;
123 default:
124 return false;
125 }
126 });
127 }
128
129 // integer addition/subtraction
130 getActionDefinitionsBuilder({G_ADD, G_SUB})
131 .legalIf([=](const LegalityQuery &Query) -> bool {
132 if (typeInSet(0, {s8, s16, s32})(Query))
133 return true;
134 if (Is64Bit && typeInSet(0, {s64})(Query))
135 return true;
136 if (HasSSE2 && typeInSet(0, {v16s8, v8s16, v4s32, v2s64})(Query))
137 return true;
138 if (HasAVX2 && typeInSet(0, {v32s8, v16s16, v8s32, v4s64})(Query))
139 return true;
140 if (HasAVX512 && typeInSet(0, {v16s32, v8s64})(Query))
141 return true;
142 if (HasBWI && typeInSet(0, {v64s8, v32s16})(Query))
143 return true;
144 return false;
145 })
146 .clampMinNumElements(0, s8, 16)
147 .clampMinNumElements(0, s16, 8)
148 .clampMinNumElements(0, s32, 4)
149 .clampMinNumElements(0, s64, 2)
150 .clampMaxNumElements(0, s8, HasBWI ? 64 : (HasAVX2 ? 32 : 16))
151 .clampMaxNumElements(0, s16, HasBWI ? 32 : (HasAVX2 ? 16 : 8))
152 .clampMaxNumElements(0, s32, HasAVX512 ? 16 : (HasAVX2 ? 8 : 4))
153 .clampMaxNumElements(0, s64, HasAVX512 ? 8 : (HasAVX2 ? 4 : 2))
154 .widenScalarToNextPow2(0, /*Min=*/32)
155 .clampScalar(0, s8, sMaxScalar)
156 .scalarize(0);
157
158 getActionDefinitionsBuilder({G_UADDE, G_UADDO, G_USUBE, G_USUBO})
159 .legalIf([=](const LegalityQuery &Query) -> bool {
160 return typePairInSet(0, 1, {{s8, s1}, {s16, s1}, {s32, s1}})(Query) ||
161 (Is64Bit && typePairInSet(0, 1, {{s64, s1}})(Query));
162 })
163 .widenScalarToNextPow2(0, /*Min=*/32)
164 .clampScalar(0, s8, sMaxScalar)
165 .clampScalar(1, s1, s1)
166 .scalarize(0);
167
168 // integer multiply
170 .legalIf([=](const LegalityQuery &Query) -> bool {
171 if (typeInSet(0, {s8, s16, s32})(Query))
172 return true;
173 if (Is64Bit && typeInSet(0, {s64})(Query))
174 return true;
175 if (HasSSE2 && typeInSet(0, {v8s16})(Query))
176 return true;
177 if (HasSSE41 && typeInSet(0, {v4s32})(Query))
178 return true;
179 if (HasAVX2 && typeInSet(0, {v16s16, v8s32})(Query))
180 return true;
181 if (HasAVX512 && typeInSet(0, {v16s32})(Query))
182 return true;
183 if (HasDQI && typeInSet(0, {v8s64})(Query))
184 return true;
185 if (HasDQI && HasVLX && typeInSet(0, {v2s64, v4s64})(Query))
186 return true;
187 if (HasBWI && typeInSet(0, {v32s16})(Query))
188 return true;
189 return false;
190 })
191 .clampMinNumElements(0, s16, 8)
192 .clampMinNumElements(0, s32, 4)
193 .clampMinNumElements(0, s64, HasVLX ? 2 : 8)
194 .clampMaxNumElements(0, s16, HasBWI ? 32 : (HasAVX2 ? 16 : 8))
195 .clampMaxNumElements(0, s32, HasAVX512 ? 16 : (HasAVX2 ? 8 : 4))
196 .clampMaxNumElements(0, s64, 8)
197 .widenScalarToNextPow2(0, /*Min=*/32)
198 .clampScalar(0, s8, sMaxScalar)
199 .scalarize(0);
200
201 getActionDefinitionsBuilder({G_SMULH, G_UMULH})
202 .legalIf([=](const LegalityQuery &Query) -> bool {
203 return typeInSet(0, {s8, s16, s32})(Query) ||
204 (Is64Bit && typeInSet(0, {s64})(Query));
205 })
206 .widenScalarToNextPow2(0, /*Min=*/32)
207 .clampScalar(0, s8, sMaxScalar)
208 .scalarize(0);
209
210 // integer divisions
211 getActionDefinitionsBuilder({G_SDIV, G_SREM, G_UDIV, G_UREM})
212 .legalIf([=](const LegalityQuery &Query) -> bool {
213 return typeInSet(0, {s8, s16, s32})(Query) ||
214 (Is64Bit && typeInSet(0, {s64})(Query));
215 })
216 .libcallFor({s64})
217 .clampScalar(0, s8, sMaxScalar);
218
219 // integer shifts
220 getActionDefinitionsBuilder({G_SHL, G_LSHR, G_ASHR})
221 .legalIf([=](const LegalityQuery &Query) -> bool {
222 return typePairInSet(0, 1, {{s8, s8}, {s16, s8}, {s32, s8}})(Query) ||
223 (Is64Bit && typePairInSet(0, 1, {{s64, s8}})(Query));
224 })
225 .clampScalar(0, s8, sMaxScalar)
226 .clampScalar(1, s8, s8);
227
228 // integer logic
229 getActionDefinitionsBuilder({G_AND, G_OR, G_XOR})
230 .legalIf([=](const LegalityQuery &Query) -> bool {
231 if (typeInSet(0, {s8, s16, s32})(Query))
232 return true;
233 if (Is64Bit && typeInSet(0, {s64})(Query))
234 return true;
235 if (HasSSE2 && typeInSet(0, {v16s8, v8s16, v4s32, v2s64})(Query))
236 return true;
237 if (HasAVX && typeInSet(0, {v32s8, v16s16, v8s32, v4s64})(Query))
238 return true;
239 if (HasAVX512 && typeInSet(0, {v64s8, v32s16, v16s32, v8s64})(Query))
240 return true;
241 return false;
242 })
243 .clampMinNumElements(0, s8, 16)
244 .clampMinNumElements(0, s16, 8)
245 .clampMinNumElements(0, s32, 4)
246 .clampMinNumElements(0, s64, 2)
247 .clampMaxNumElements(0, s8, HasAVX512 ? 64 : (HasAVX ? 32 : 16))
248 .clampMaxNumElements(0, s16, HasAVX512 ? 32 : (HasAVX ? 16 : 8))
249 .clampMaxNumElements(0, s32, HasAVX512 ? 16 : (HasAVX ? 8 : 4))
250 .clampMaxNumElements(0, s64, HasAVX512 ? 8 : (HasAVX ? 4 : 2))
251 .widenScalarToNextPow2(0, /*Min=*/32)
252 .clampScalar(0, s8, sMaxScalar)
253 .scalarize(0);
254
255 // integer comparison
256 const std::initializer_list<LLT> IntTypes32 = {s8, s16, s32, p0};
257 const std::initializer_list<LLT> IntTypes64 = {s8, s16, s32, s64, p0};
258
260 .legalForCartesianProduct({s8}, Is64Bit ? IntTypes64 : IntTypes32)
261 .clampScalar(0, s8, s8)
262 .clampScalar(1, s8, sMaxScalar);
263
264 // bswap
266 .legalIf([=](const LegalityQuery &Query) {
267 return Query.Types[0] == s32 ||
268 (Subtarget.is64Bit() && Query.Types[0] == s64);
269 })
270 .widenScalarToNextPow2(0, /*Min=*/32)
271 .clampScalar(0, s32, sMaxScalar);
272
273 // popcount
275 .legalIf([=](const LegalityQuery &Query) -> bool {
276 return Subtarget.hasPOPCNT() &&
277 (typePairInSet(0, 1, {{s16, s16}, {s32, s32}})(Query) ||
278 (Is64Bit && typePairInSet(0, 1, {{s64, s64}})(Query)));
279 })
280 .widenScalarToNextPow2(1, /*Min=*/16)
281 .clampScalar(1, s16, sMaxScalar)
282 .scalarSameSizeAs(0, 1);
283
284 // count leading zeros (LZCNT)
286 .legalIf([=](const LegalityQuery &Query) -> bool {
287 return Subtarget.hasLZCNT() &&
288 (typePairInSet(0, 1, {{s16, s16}, {s32, s32}})(Query) ||
289 (Is64Bit && typePairInSet(0, 1, {{s64, s64}})(Query)));
290 })
291 .widenScalarToNextPow2(1, /*Min=*/16)
292 .clampScalar(1, s16, sMaxScalar)
293 .scalarSameSizeAs(0, 1);
294
295 // count trailing zeros
296 getActionDefinitionsBuilder({G_CTTZ_ZERO_UNDEF, G_CTTZ})
297 .legalIf([=](const LegalityQuery &Query) -> bool {
298 return (Query.Opcode == G_CTTZ_ZERO_UNDEF || Subtarget.hasBMI()) &&
299 (typePairInSet(0, 1, {{s16, s16}, {s32, s32}})(Query) ||
300 (Is64Bit && typePairInSet(0, 1, {{s64, s64}})(Query)));
301 })
302 .widenScalarToNextPow2(1, /*Min=*/16)
303 .clampScalar(1, s16, sMaxScalar)
304 .scalarSameSizeAs(0, 1);
305
306 // control flow
308 .legalIf([=](const LegalityQuery &Query) -> bool {
309 return typeInSet(0, {s8, s16, s32, p0})(Query) ||
310 (Is64Bit && typeInSet(0, {s64})(Query)) ||
311 (HasSSE1 && typeInSet(0, {v16s8, v8s16, v4s32, v2s64})(Query)) ||
312 (HasAVX && typeInSet(0, {v32s8, v16s16, v8s32, v4s64})(Query)) ||
313 (HasAVX512 &&
314 typeInSet(0, {v64s8, v32s16, v16s32, v8s64})(Query));
315 })
316 .clampMinNumElements(0, s8, 16)
317 .clampMinNumElements(0, s16, 8)
318 .clampMinNumElements(0, s32, 4)
319 .clampMinNumElements(0, s64, 2)
320 .clampMaxNumElements(0, s8, HasAVX512 ? 64 : (HasAVX ? 32 : 16))
321 .clampMaxNumElements(0, s16, HasAVX512 ? 32 : (HasAVX ? 16 : 8))
322 .clampMaxNumElements(0, s32, HasAVX512 ? 16 : (HasAVX ? 8 : 4))
323 .clampMaxNumElements(0, s64, HasAVX512 ? 8 : (HasAVX ? 4 : 2))
324 .widenScalarToNextPow2(0, /*Min=*/32)
325 .clampScalar(0, s8, sMaxScalar)
326 .scalarize(0);
327
329
330 // pointer handling
331 const std::initializer_list<LLT> PtrTypes32 = {s1, s8, s16, s32};
332 const std::initializer_list<LLT> PtrTypes64 = {s1, s8, s16, s32, s64};
333
335 .legalForCartesianProduct(Is64Bit ? PtrTypes64 : PtrTypes32, {p0})
336 .maxScalar(0, sMaxScalar)
337 .widenScalarToNextPow2(0, /*Min*/ 8);
338
339 getActionDefinitionsBuilder(G_INTTOPTR).legalFor({{p0, sMaxScalar}});
340
342 .legalIf([=](const LegalityQuery &Query) -> bool {
343 return typePairInSet(0, 1, {{p0, s32}})(Query) ||
344 (Is64Bit && typePairInSet(0, 1, {{p0, s64}})(Query));
345 })
346 .widenScalarToNextPow2(1, /*Min*/ 32)
347 .clampScalar(1, s32, sMaxScalar);
348
349 getActionDefinitionsBuilder({G_FRAME_INDEX, G_GLOBAL_VALUE}).legalFor({p0});
350
351 // load/store: add more corner cases
352 for (unsigned Op : {G_LOAD, G_STORE}) {
353 auto &Action = getActionDefinitionsBuilder(Op);
354 Action.legalForTypesWithMemDesc({{s8, p0, s1, 1},
355 {s8, p0, s8, 1},
356 {s16, p0, s8, 1},
357 {s16, p0, s16, 1},
358 {s32, p0, s8, 1},
359 {s32, p0, s16, 1},
360 {s32, p0, s32, 1},
361 {s80, p0, s80, 1},
362 {p0, p0, p0, 1},
363 {v4s8, p0, v4s8, 1}});
364 if (Is64Bit)
365 Action.legalForTypesWithMemDesc({{s64, p0, s8, 1},
366 {s64, p0, s16, 1},
367 {s64, p0, s32, 1},
368 {s64, p0, s64, 1},
369 {v2s32, p0, v2s32, 1}});
370 if (HasSSE1)
371 Action.legalForTypesWithMemDesc({{v16s8, p0, v16s8, 1},
372 {v8s16, p0, v8s16, 1},
373 {v4s32, p0, v4s32, 1},
374 {v2s64, p0, v2s64, 1},
375 {v2p0, p0, v2p0, 1}});
376 if (HasAVX)
377 Action.legalForTypesWithMemDesc({{v32s8, p0, v32s8, 1},
378 {v16s16, p0, v16s16, 1},
379 {v8s32, p0, v8s32, 1},
380 {v4s64, p0, v4s64, 1},
381 {v4p0, p0, v4p0, 1}});
382 if (HasAVX512)
383 Action.legalForTypesWithMemDesc({{v64s8, p0, v64s8, 1},
384 {v32s16, p0, v32s16, 1},
385 {v16s32, p0, v16s32, 1},
386 {v8s64, p0, v8s64, 1}});
387 Action.widenScalarToNextPow2(0, /*Min=*/8).clampScalar(0, s8, sMaxScalar);
388 }
389
390 for (unsigned Op : {G_SEXTLOAD, G_ZEXTLOAD}) {
391 auto &Action = getActionDefinitionsBuilder(Op);
392 Action.legalForTypesWithMemDesc({{s16, p0, s8, 1},
393 {s32, p0, s8, 1},
394 {s32, p0, s16, 1}});
395 if (Is64Bit)
396 Action.legalForTypesWithMemDesc({{s64, p0, s8, 1},
397 {s64, p0, s16, 1},
398 {s64, p0, s32, 1}});
399 // TODO - SSE41/AVX2/AVX512F/AVX512BW vector extensions
400 }
401
402 // sext, zext, and anyext
403 getActionDefinitionsBuilder({G_SEXT, G_ZEXT, G_ANYEXT})
404 .legalIf([=](const LegalityQuery &Query) {
405 return typeInSet(0, {s8, s16, s32})(Query) ||
406 (Query.Opcode == G_ANYEXT && Query.Types[0] == s128) ||
407 (Is64Bit && Query.Types[0] == s64);
408 })
409 .widenScalarToNextPow2(0, /*Min=*/8)
410 .clampScalar(0, s8, sMaxScalar)
411 .widenScalarToNextPow2(1, /*Min=*/8)
412 .clampScalar(1, s8, sMaxScalar);
413
414 getActionDefinitionsBuilder(G_SEXT_INREG).lower();
415
416 // fp constants
417 getActionDefinitionsBuilder(G_FCONSTANT)
418 .legalIf([=](const LegalityQuery &Query) -> bool {
419 return (typeInSet(0, {s32, s64})(Query)) ||
420 (UseX87 && typeInSet(0, {s80})(Query));
421 });
422
423 // fp arithmetic
424 getActionDefinitionsBuilder({G_FADD, G_FSUB, G_FMUL, G_FDIV})
425 .legalIf([=](const LegalityQuery &Query) {
426 return (typeInSet(0, {s32, s64})(Query)) ||
427 (HasSSE1 && typeInSet(0, {v4s32})(Query)) ||
428 (HasSSE2 && typeInSet(0, {v2s64})(Query)) ||
429 (HasAVX && typeInSet(0, {v8s32, v4s64})(Query)) ||
430 (HasAVX512 && typeInSet(0, {v16s32, v8s64})(Query)) ||
431 (UseX87 && typeInSet(0, {s80})(Query));
432 });
433
434 // fp comparison
436 .legalIf([=](const LegalityQuery &Query) {
437 return (HasSSE1 && typePairInSet(0, 1, {{s8, s32}})(Query)) ||
438 (HasSSE2 && typePairInSet(0, 1, {{s8, s64}})(Query));
439 })
440 .clampScalar(0, s8, s8)
441 .clampScalar(1, s32, HasSSE2 ? s64 : s32)
443
444 // fp conversions
445 getActionDefinitionsBuilder(G_FPEXT).legalIf([=](const LegalityQuery &Query) {
446 return (HasSSE2 && typePairInSet(0, 1, {{s64, s32}})(Query)) ||
447 (HasAVX && typePairInSet(0, 1, {{v4s64, v4s32}})(Query)) ||
448 (HasAVX512 && typePairInSet(0, 1, {{v8s64, v8s32}})(Query));
449 });
450
452 [=](const LegalityQuery &Query) {
453 return (HasSSE2 && typePairInSet(0, 1, {{s32, s64}})(Query)) ||
454 (HasAVX && typePairInSet(0, 1, {{v4s32, v4s64}})(Query)) ||
455 (HasAVX512 && typePairInSet(0, 1, {{v8s32, v8s64}})(Query));
456 });
457
459 .legalIf([=](const LegalityQuery &Query) {
460 return (HasSSE1 &&
461 (typePairInSet(0, 1, {{s32, s32}})(Query) ||
462 (Is64Bit && typePairInSet(0, 1, {{s32, s64}})(Query)))) ||
463 (HasSSE2 &&
464 (typePairInSet(0, 1, {{s64, s32}})(Query) ||
465 (Is64Bit && typePairInSet(0, 1, {{s64, s64}})(Query))));
466 })
467 .clampScalar(1, s32, sMaxScalar)
469 .clampScalar(0, s32, HasSSE2 ? s64 : s32)
471
473 .legalIf([=](const LegalityQuery &Query) {
474 return (HasSSE1 &&
475 (typePairInSet(0, 1, {{s32, s32}})(Query) ||
476 (Is64Bit && typePairInSet(0, 1, {{s64, s32}})(Query)))) ||
477 (HasSSE2 &&
478 (typePairInSet(0, 1, {{s32, s64}})(Query) ||
479 (Is64Bit && typePairInSet(0, 1, {{s64, s64}})(Query))));
480 })
481 .clampScalar(1, s32, HasSSE2 ? s64 : s32)
483 .clampScalar(0, s32, sMaxScalar)
485
486 // vector ops
487 getActionDefinitionsBuilder({G_EXTRACT, G_INSERT})
488 .legalIf([=](const LegalityQuery &Query) {
489 unsigned SubIdx = Query.Opcode == G_EXTRACT ? 0 : 1;
490 unsigned FullIdx = Query.Opcode == G_EXTRACT ? 1 : 0;
491 return (HasAVX && typePairInSet(SubIdx, FullIdx,
492 {{v16s8, v32s8},
493 {v8s16, v16s16},
494 {v4s32, v8s32},
495 {v2s64, v4s64}})(Query)) ||
496 (HasAVX512 && typePairInSet(SubIdx, FullIdx,
497 {{v16s8, v64s8},
498 {v32s8, v64s8},
499 {v8s16, v32s16},
500 {v16s16, v32s16},
501 {v4s32, v16s32},
502 {v8s32, v16s32},
503 {v2s64, v8s64},
504 {v4s64, v8s64}})(Query));
505 });
506
507 // todo: only permit dst types up to max legal vector register size?
508 getActionDefinitionsBuilder(G_CONCAT_VECTORS)
509 .legalIf([=](const LegalityQuery &Query) {
510 return (HasSSE1 && typePairInSet(1, 0,
511 {{v16s8, v32s8},
512 {v8s16, v16s16},
513 {v4s32, v8s32},
514 {v2s64, v4s64}})(Query)) ||
515 (HasAVX && typePairInSet(1, 0,
516 {{v16s8, v64s8},
517 {v32s8, v64s8},
518 {v8s16, v32s16},
519 {v16s16, v32s16},
520 {v4s32, v16s32},
521 {v8s32, v16s32},
522 {v2s64, v8s64},
523 {v4s64, v8s64}})(Query));
524 });
525
526 // todo: vectors and address spaces
528 .legalFor({{s8, s32}, {s16, s32}, {s32, s32}, {s64, s32}, {p0, s32}})
529 .widenScalarToNextPow2(0, /*Min=*/8)
530 .clampScalar(0, HasCMOV ? s16 : s8, sMaxScalar)
531 .clampScalar(1, s32, s32);
532
533 // memory intrinsics
534 getActionDefinitionsBuilder({G_MEMCPY, G_MEMMOVE, G_MEMSET}).libcall();
535
536 getActionDefinitionsBuilder({G_DYN_STACKALLOC,
537 G_STACKSAVE,
538 G_STACKRESTORE}).lower();
539
540 // fp intrinsics
541 getActionDefinitionsBuilder(G_INTRINSIC_ROUNDEVEN)
542 .scalarize(0)
543 .minScalar(0, LLT::scalar(32))
544 .libcall();
545
546 getActionDefinitionsBuilder({G_FREEZE, G_CONSTANT_FOLD_BARRIER})
547 .legalFor({s8, s16, s32, s64, p0})
548 .widenScalarToNextPow2(0, /*Min=*/8)
549 .clampScalar(0, s8, sMaxScalar);
550
552 verify(*STI.getInstrInfo());
553}
554
556 MachineInstr &MI) const {
557 return true;
558}
IRTranslator LLVM IR MI
ppc ctr loops verify
const char LLVMTargetMachineRef TM
This file declares the targeting of the Machinelegalizer class for X86.
This class represents an Operation in the Expression.
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
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 & 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 & widenScalarToNextPow2(unsigned TypeIdx, unsigned MinSize=0)
Widen the scalar to the next power of two that is at least MinSize.
LegalizeRuleSet & scalarize(unsigned TypeIdx)
LegalizeRuleSet & legalForCartesianProduct(std::initializer_list< LLT > Types)
The instruction is legal when type indexes 0 and 1 are both in the given list.
LegalizeRuleSet & legalIf(LegalityPredicate Predicate)
The instruction is legal if predicate is true.
LegalizeRuleSet & getActionDefinitionsBuilder(unsigned Opcode)
Get the action definition builder for the given opcode.
const LegacyLegalizerInfo & getLegacyLegalizerInfo() const
Representation of each machine instruction.
Definition: MachineInstr.h:69
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
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
The LegalityQuery object bundles together all the information that's needed to decide whether a given...
ArrayRef< LLT > Types