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