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