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
22using namespace llvm;
23using namespace TargetOpcode;
24using namespace LegalizeActions;
25using namespace LegalityPredicates;
26
27X86LegalizerInfo::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 bool UseX87 = !Subtarget.useSoftFloat() && Subtarget.hasX87();
43
44 const LLT p0 = LLT::pointer(AddressSpace: 0, SizeInBits: TM.getPointerSizeInBits(AS: 0));
45 const LLT s1 = LLT::scalar(SizeInBits: 1);
46 const LLT s8 = LLT::scalar(SizeInBits: 8);
47 const LLT s16 = LLT::scalar(SizeInBits: 16);
48 const LLT s32 = LLT::scalar(SizeInBits: 32);
49 const LLT s64 = LLT::scalar(SizeInBits: 64);
50 const LLT s80 = LLT::scalar(SizeInBits: 80);
51 const LLT s128 = LLT::scalar(SizeInBits: 128);
52 const LLT sMaxScalar = Subtarget.is64Bit() ? s64 : s32;
53 const LLT v2s32 = LLT::fixed_vector(NumElements: 2, ScalarSizeInBits: 32);
54 const LLT v4s8 = LLT::fixed_vector(NumElements: 4, ScalarSizeInBits: 8);
55
56
57 const LLT v16s8 = LLT::fixed_vector(NumElements: 16, ScalarSizeInBits: 8);
58 const LLT v8s16 = LLT::fixed_vector(NumElements: 8, ScalarSizeInBits: 16);
59 const LLT v4s32 = LLT::fixed_vector(NumElements: 4, ScalarSizeInBits: 32);
60 const LLT v2s64 = LLT::fixed_vector(NumElements: 2, ScalarSizeInBits: 64);
61 const LLT v2p0 = LLT::fixed_vector(NumElements: 2, ScalarTy: p0);
62
63 const LLT v32s8 = LLT::fixed_vector(NumElements: 32, ScalarSizeInBits: 8);
64 const LLT v16s16 = LLT::fixed_vector(NumElements: 16, ScalarSizeInBits: 16);
65 const LLT v8s32 = LLT::fixed_vector(NumElements: 8, ScalarSizeInBits: 32);
66 const LLT v4s64 = LLT::fixed_vector(NumElements: 4, ScalarSizeInBits: 64);
67 const LLT v4p0 = LLT::fixed_vector(NumElements: 4, ScalarTy: p0);
68
69 const LLT v64s8 = LLT::fixed_vector(NumElements: 64, ScalarSizeInBits: 8);
70 const LLT v32s16 = LLT::fixed_vector(NumElements: 32, ScalarSizeInBits: 16);
71 const LLT v16s32 = LLT::fixed_vector(NumElements: 16, ScalarSizeInBits: 32);
72 const LLT v8s64 = LLT::fixed_vector(NumElements: 8, ScalarSizeInBits: 64);
73
74 // todo: AVX512 bool vector predicate types
75
76 // implicit/constants
77 getActionDefinitionsBuilder(Opcode: G_IMPLICIT_DEF)
78 .legalIf(Predicate: [=](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(TypeIdx: 0, TypesInit: {p0, s1, s8, s16, s32, s64})(Query) ||
83 (Is64Bit && typeInSet(TypeIdx: 0, TypesInit: {s128})(Query));
84 });
85
86 getActionDefinitionsBuilder(Opcode: G_CONSTANT)
87 .legalIf(Predicate: [=](const LegalityQuery &Query) -> bool {
88 return typeInSet(TypeIdx: 0, TypesInit: {p0, s8, s16, s32})(Query) ||
89 (Is64Bit && typeInSet(TypeIdx: 0, TypesInit: {s64})(Query));
90 })
91 .widenScalarToNextPow2(TypeIdx: 0, /*Min=*/MinSize: 8)
92 .clampScalar(TypeIdx: 0, MinTy: s8, MaxTy: 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;
98 getActionDefinitionsBuilder(Opcode: Op)
99 .widenScalarToNextPow2(TypeIdx: LitTyIdx, /*Min=*/MinSize: 8)
100 .widenScalarToNextPow2(TypeIdx: BigTyIdx, /*Min=*/MinSize: 16)
101 .minScalar(TypeIdx: LitTyIdx, Ty: s8)
102 .minScalar(TypeIdx: BigTyIdx, Ty: s32)
103 .legalIf(Predicate: [=](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(Opcodes: {G_ADD, G_SUB})
131 .legalIf(Predicate: [=](const LegalityQuery &Query) -> bool {
132 if (typeInSet(TypeIdx: 0, TypesInit: {s8, s16, s32})(Query))
133 return true;
134 if (Is64Bit && typeInSet(TypeIdx: 0, TypesInit: {s64})(Query))
135 return true;
136 if (HasSSE2 && typeInSet(TypeIdx: 0, TypesInit: {v16s8, v8s16, v4s32, v2s64})(Query))
137 return true;
138 if (HasAVX2 && typeInSet(TypeIdx: 0, TypesInit: {v32s8, v16s16, v8s32, v4s64})(Query))
139 return true;
140 if (HasAVX512 && typeInSet(TypeIdx: 0, TypesInit: {v16s32, v8s64})(Query))
141 return true;
142 if (HasBWI && typeInSet(TypeIdx: 0, TypesInit: {v64s8, v32s16})(Query))
143 return true;
144 return false;
145 })
146 .clampMinNumElements(TypeIdx: 0, EltTy: s8, MinElements: 16)
147 .clampMinNumElements(TypeIdx: 0, EltTy: s16, MinElements: 8)
148 .clampMinNumElements(TypeIdx: 0, EltTy: s32, MinElements: 4)
149 .clampMinNumElements(TypeIdx: 0, EltTy: s64, MinElements: 2)
150 .clampMaxNumElements(TypeIdx: 0, EltTy: s8, MaxElements: HasBWI ? 64 : (HasAVX2 ? 32 : 16))
151 .clampMaxNumElements(TypeIdx: 0, EltTy: s16, MaxElements: HasBWI ? 32 : (HasAVX2 ? 16 : 8))
152 .clampMaxNumElements(TypeIdx: 0, EltTy: s32, MaxElements: HasAVX512 ? 16 : (HasAVX2 ? 8 : 4))
153 .clampMaxNumElements(TypeIdx: 0, EltTy: s64, MaxElements: HasAVX512 ? 8 : (HasAVX2 ? 4 : 2))
154 .widenScalarToNextPow2(TypeIdx: 0, /*Min=*/MinSize: 32)
155 .clampScalar(TypeIdx: 0, MinTy: s8, MaxTy: sMaxScalar)
156 .scalarize(TypeIdx: 0);
157
158 getActionDefinitionsBuilder(Opcodes: {G_UADDE, G_UADDO, G_USUBE, G_USUBO})
159 .legalIf(Predicate: [=](const LegalityQuery &Query) -> bool {
160 return typePairInSet(TypeIdx0: 0, TypeIdx1: 1, TypesInit: {{s8, s1}, {s16, s1}, {s32, s1}})(Query) ||
161 (Is64Bit && typePairInSet(TypeIdx0: 0, TypeIdx1: 1, TypesInit: {{s64, s1}})(Query));
162 })
163 .widenScalarToNextPow2(TypeIdx: 0, /*Min=*/MinSize: 32)
164 .clampScalar(TypeIdx: 0, MinTy: s8, MaxTy: sMaxScalar)
165 .clampScalar(TypeIdx: 1, MinTy: s1, MaxTy: s1)
166 .scalarize(TypeIdx: 0);
167
168 // integer multiply
169 getActionDefinitionsBuilder(Opcode: G_MUL)
170 .legalIf(Predicate: [=](const LegalityQuery &Query) -> bool {
171 if (typeInSet(TypeIdx: 0, TypesInit: {s8, s16, s32})(Query))
172 return true;
173 if (Is64Bit && typeInSet(TypeIdx: 0, TypesInit: {s64})(Query))
174 return true;
175 if (HasSSE2 && typeInSet(TypeIdx: 0, TypesInit: {v8s16})(Query))
176 return true;
177 if (HasSSE41 && typeInSet(TypeIdx: 0, TypesInit: {v4s32})(Query))
178 return true;
179 if (HasAVX2 && typeInSet(TypeIdx: 0, TypesInit: {v16s16, v8s32})(Query))
180 return true;
181 if (HasAVX512 && typeInSet(TypeIdx: 0, TypesInit: {v16s32})(Query))
182 return true;
183 if (HasDQI && typeInSet(TypeIdx: 0, TypesInit: {v8s64})(Query))
184 return true;
185 if (HasDQI && HasVLX && typeInSet(TypeIdx: 0, TypesInit: {v2s64, v4s64})(Query))
186 return true;
187 if (HasBWI && typeInSet(TypeIdx: 0, TypesInit: {v32s16})(Query))
188 return true;
189 return false;
190 })
191 .clampMinNumElements(TypeIdx: 0, EltTy: s16, MinElements: 8)
192 .clampMinNumElements(TypeIdx: 0, EltTy: s32, MinElements: 4)
193 .clampMinNumElements(TypeIdx: 0, EltTy: s64, MinElements: HasVLX ? 2 : 8)
194 .clampMaxNumElements(TypeIdx: 0, EltTy: s16, MaxElements: HasBWI ? 32 : (HasAVX2 ? 16 : 8))
195 .clampMaxNumElements(TypeIdx: 0, EltTy: s32, MaxElements: HasAVX512 ? 16 : (HasAVX2 ? 8 : 4))
196 .clampMaxNumElements(TypeIdx: 0, EltTy: s64, MaxElements: 8)
197 .widenScalarToNextPow2(TypeIdx: 0, /*Min=*/MinSize: 32)
198 .clampScalar(TypeIdx: 0, MinTy: s8, MaxTy: sMaxScalar)
199 .scalarize(TypeIdx: 0);
200
201 getActionDefinitionsBuilder(Opcodes: {G_SMULH, G_UMULH})
202 .legalIf(Predicate: [=](const LegalityQuery &Query) -> bool {
203 return typeInSet(TypeIdx: 0, TypesInit: {s8, s16, s32})(Query) ||
204 (Is64Bit && typeInSet(TypeIdx: 0, TypesInit: {s64})(Query));
205 })
206 .widenScalarToNextPow2(TypeIdx: 0, /*Min=*/MinSize: 32)
207 .clampScalar(TypeIdx: 0, MinTy: s8, MaxTy: sMaxScalar)
208 .scalarize(TypeIdx: 0);
209
210 // integer divisions
211 getActionDefinitionsBuilder(Opcodes: {G_SDIV, G_SREM, G_UDIV, G_UREM})
212 .legalIf(Predicate: [=](const LegalityQuery &Query) -> bool {
213 return typeInSet(TypeIdx: 0, TypesInit: {s8, s16, s32})(Query) ||
214 (Is64Bit && typeInSet(TypeIdx: 0, TypesInit: {s64})(Query));
215 })
216 .libcallFor(Types: {s64})
217 .clampScalar(TypeIdx: 0, MinTy: s8, MaxTy: sMaxScalar);
218
219 // integer shifts
220 getActionDefinitionsBuilder(Opcodes: {G_SHL, G_LSHR, G_ASHR})
221 .legalIf(Predicate: [=](const LegalityQuery &Query) -> bool {
222 return typePairInSet(TypeIdx0: 0, TypeIdx1: 1, TypesInit: {{s8, s8}, {s16, s8}, {s32, s8}})(Query) ||
223 (Is64Bit && typePairInSet(TypeIdx0: 0, TypeIdx1: 1, TypesInit: {{s64, s8}})(Query));
224 })
225 .clampScalar(TypeIdx: 0, MinTy: s8, MaxTy: sMaxScalar)
226 .clampScalar(TypeIdx: 1, MinTy: s8, MaxTy: s8);
227
228 // integer logic
229 getActionDefinitionsBuilder(Opcodes: {G_AND, G_OR, G_XOR})
230 .legalIf(Predicate: [=](const LegalityQuery &Query) -> bool {
231 if (typeInSet(TypeIdx: 0, TypesInit: {s8, s16, s32})(Query))
232 return true;
233 if (Is64Bit && typeInSet(TypeIdx: 0, TypesInit: {s64})(Query))
234 return true;
235 if (HasSSE2 && typeInSet(TypeIdx: 0, TypesInit: {v16s8, v8s16, v4s32, v2s64})(Query))
236 return true;
237 if (HasAVX && typeInSet(TypeIdx: 0, TypesInit: {v32s8, v16s16, v8s32, v4s64})(Query))
238 return true;
239 if (HasAVX512 && typeInSet(TypeIdx: 0, TypesInit: {v64s8, v32s16, v16s32, v8s64})(Query))
240 return true;
241 return false;
242 })
243 .clampMinNumElements(TypeIdx: 0, EltTy: s8, MinElements: 16)
244 .clampMinNumElements(TypeIdx: 0, EltTy: s16, MinElements: 8)
245 .clampMinNumElements(TypeIdx: 0, EltTy: s32, MinElements: 4)
246 .clampMinNumElements(TypeIdx: 0, EltTy: s64, MinElements: 2)
247 .clampMaxNumElements(TypeIdx: 0, EltTy: s8, MaxElements: HasAVX512 ? 64 : (HasAVX ? 32 : 16))
248 .clampMaxNumElements(TypeIdx: 0, EltTy: s16, MaxElements: HasAVX512 ? 32 : (HasAVX ? 16 : 8))
249 .clampMaxNumElements(TypeIdx: 0, EltTy: s32, MaxElements: HasAVX512 ? 16 : (HasAVX ? 8 : 4))
250 .clampMaxNumElements(TypeIdx: 0, EltTy: s64, MaxElements: HasAVX512 ? 8 : (HasAVX ? 4 : 2))
251 .widenScalarToNextPow2(TypeIdx: 0, /*Min=*/MinSize: 32)
252 .clampScalar(TypeIdx: 0, MinTy: s8, MaxTy: sMaxScalar)
253 .scalarize(TypeIdx: 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
259 getActionDefinitionsBuilder(Opcode: G_ICMP)
260 .legalForCartesianProduct(Types0: {s8}, Types1: Is64Bit ? IntTypes64 : IntTypes32)
261 .clampScalar(TypeIdx: 0, MinTy: s8, MaxTy: s8)
262 .clampScalar(TypeIdx: 1, MinTy: s8, MaxTy: sMaxScalar);
263
264 // bswap
265 getActionDefinitionsBuilder(Opcode: G_BSWAP)
266 .legalIf([=](const LegalityQuery &Query) {
267 return Query.Types[0] == s32 ||
268 (Subtarget.is64Bit() && Query.Types[0] == s64);
269 })
270 .widenScalarToNextPow2(TypeIdx: 0, /*Min=*/MinSize: 32)
271 .clampScalar(TypeIdx: 0, MinTy: s32, MaxTy: sMaxScalar);
272
273 // popcount
274 getActionDefinitionsBuilder(Opcode: G_CTPOP)
275 .legalIf(Predicate: [=](const LegalityQuery &Query) -> bool {
276 return Subtarget.hasPOPCNT() &&
277 (typePairInSet(TypeIdx0: 0, TypeIdx1: 1, TypesInit: {{s16, s16}, {s32, s32}})(Query) ||
278 (Is64Bit && typePairInSet(TypeIdx0: 0, TypeIdx1: 1, TypesInit: {{s64, s64}})(Query)));
279 })
280 .widenScalarToNextPow2(TypeIdx: 1, /*Min=*/MinSize: 16)
281 .clampScalar(TypeIdx: 1, MinTy: s16, MaxTy: sMaxScalar)
282 .scalarSameSizeAs(TypeIdx: 0, SameSizeIdx: 1);
283
284 // count leading zeros (LZCNT)
285 getActionDefinitionsBuilder(Opcode: G_CTLZ)
286 .legalIf(Predicate: [=](const LegalityQuery &Query) -> bool {
287 return Subtarget.hasLZCNT() &&
288 (typePairInSet(TypeIdx0: 0, TypeIdx1: 1, TypesInit: {{s16, s16}, {s32, s32}})(Query) ||
289 (Is64Bit && typePairInSet(TypeIdx0: 0, TypeIdx1: 1, TypesInit: {{s64, s64}})(Query)));
290 })
291 .widenScalarToNextPow2(TypeIdx: 1, /*Min=*/MinSize: 16)
292 .clampScalar(TypeIdx: 1, MinTy: s16, MaxTy: sMaxScalar)
293 .scalarSameSizeAs(TypeIdx: 0, SameSizeIdx: 1);
294
295 // count trailing zeros
296 getActionDefinitionsBuilder(Opcodes: {G_CTTZ_ZERO_UNDEF, G_CTTZ})
297 .legalIf(Predicate: [=](const LegalityQuery &Query) -> bool {
298 return (Query.Opcode == G_CTTZ_ZERO_UNDEF || Subtarget.hasBMI()) &&
299 (typePairInSet(TypeIdx0: 0, TypeIdx1: 1, TypesInit: {{s16, s16}, {s32, s32}})(Query) ||
300 (Is64Bit && typePairInSet(TypeIdx0: 0, TypeIdx1: 1, TypesInit: {{s64, s64}})(Query)));
301 })
302 .widenScalarToNextPow2(TypeIdx: 1, /*Min=*/MinSize: 16)
303 .clampScalar(TypeIdx: 1, MinTy: s16, MaxTy: sMaxScalar)
304 .scalarSameSizeAs(TypeIdx: 0, SameSizeIdx: 1);
305
306 // control flow
307 getActionDefinitionsBuilder(Opcode: G_PHI)
308 .legalIf(Predicate: [=](const LegalityQuery &Query) -> bool {
309 return typeInSet(TypeIdx: 0, TypesInit: {s8, s16, s32, p0})(Query) ||
310 (Is64Bit && typeInSet(TypeIdx: 0, TypesInit: {s64})(Query)) ||
311 (HasSSE1 && typeInSet(TypeIdx: 0, TypesInit: {v16s8, v8s16, v4s32, v2s64})(Query)) ||
312 (HasAVX && typeInSet(TypeIdx: 0, TypesInit: {v32s8, v16s16, v8s32, v4s64})(Query)) ||
313 (HasAVX512 &&
314 typeInSet(TypeIdx: 0, TypesInit: {v64s8, v32s16, v16s32, v8s64})(Query));
315 })
316 .clampMinNumElements(TypeIdx: 0, EltTy: s8, MinElements: 16)
317 .clampMinNumElements(TypeIdx: 0, EltTy: s16, MinElements: 8)
318 .clampMinNumElements(TypeIdx: 0, EltTy: s32, MinElements: 4)
319 .clampMinNumElements(TypeIdx: 0, EltTy: s64, MinElements: 2)
320 .clampMaxNumElements(TypeIdx: 0, EltTy: s8, MaxElements: HasAVX512 ? 64 : (HasAVX ? 32 : 16))
321 .clampMaxNumElements(TypeIdx: 0, EltTy: s16, MaxElements: HasAVX512 ? 32 : (HasAVX ? 16 : 8))
322 .clampMaxNumElements(TypeIdx: 0, EltTy: s32, MaxElements: HasAVX512 ? 16 : (HasAVX ? 8 : 4))
323 .clampMaxNumElements(TypeIdx: 0, EltTy: s64, MaxElements: HasAVX512 ? 8 : (HasAVX ? 4 : 2))
324 .widenScalarToNextPow2(TypeIdx: 0, /*Min=*/MinSize: 32)
325 .clampScalar(TypeIdx: 0, MinTy: s8, MaxTy: sMaxScalar)
326 .scalarize(TypeIdx: 0);
327
328 getActionDefinitionsBuilder(Opcode: G_BRCOND).legalFor(Types: {s1});
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
334 getActionDefinitionsBuilder(Opcode: G_PTRTOINT)
335 .legalForCartesianProduct(Types0: Is64Bit ? PtrTypes64 : PtrTypes32, Types1: {p0})
336 .maxScalar(TypeIdx: 0, Ty: sMaxScalar)
337 .widenScalarToNextPow2(TypeIdx: 0, /*Min*/ MinSize: 8);
338
339 getActionDefinitionsBuilder(Opcode: G_INTTOPTR).legalFor(Types: {{p0, sMaxScalar}});
340
341 getActionDefinitionsBuilder(Opcode: G_PTR_ADD)
342 .legalIf(Predicate: [=](const LegalityQuery &Query) -> bool {
343 return typePairInSet(TypeIdx0: 0, TypeIdx1: 1, TypesInit: {{p0, s32}})(Query) ||
344 (Is64Bit && typePairInSet(TypeIdx0: 0, TypeIdx1: 1, TypesInit: {{p0, s64}})(Query));
345 })
346 .widenScalarToNextPow2(TypeIdx: 1, /*Min*/ MinSize: 32)
347 .clampScalar(TypeIdx: 1, MinTy: s32, MaxTy: sMaxScalar);
348
349 getActionDefinitionsBuilder(Opcodes: {G_FRAME_INDEX, G_GLOBAL_VALUE}).legalFor(Types: {p0});
350
351 // load/store: add more corner cases
352 for (unsigned Op : {G_LOAD, G_STORE}) {
353 auto &Action = getActionDefinitionsBuilder(Opcode: Op);
354 Action.legalForTypesWithMemDesc(TypesAndMemDesc: {{.Type0: s8, .Type1: p0, .MemTy: s1, .Align: 1},
355 {.Type0: s8, .Type1: p0, .MemTy: s8, .Align: 1},
356 {.Type0: s16, .Type1: p0, .MemTy: s8, .Align: 1},
357 {.Type0: s16, .Type1: p0, .MemTy: s16, .Align: 1},
358 {.Type0: s32, .Type1: p0, .MemTy: s8, .Align: 1},
359 {.Type0: s32, .Type1: p0, .MemTy: s16, .Align: 1},
360 {.Type0: s32, .Type1: p0, .MemTy: s32, .Align: 1},
361 {.Type0: s80, .Type1: p0, .MemTy: s80, .Align: 1},
362 {.Type0: p0, .Type1: p0, .MemTy: p0, .Align: 1},
363 {.Type0: v4s8, .Type1: p0, .MemTy: v4s8, .Align: 1}});
364 if (Is64Bit)
365 Action.legalForTypesWithMemDesc(TypesAndMemDesc: {{.Type0: s64, .Type1: p0, .MemTy: s8, .Align: 1},
366 {.Type0: s64, .Type1: p0, .MemTy: s16, .Align: 1},
367 {.Type0: s64, .Type1: p0, .MemTy: s32, .Align: 1},
368 {.Type0: s64, .Type1: p0, .MemTy: s64, .Align: 1},
369 {.Type0: v2s32, .Type1: p0, .MemTy: v2s32, .Align: 1}});
370 if (HasSSE1)
371 Action.legalForTypesWithMemDesc(TypesAndMemDesc: {{.Type0: v16s8, .Type1: p0, .MemTy: v16s8, .Align: 1},
372 {.Type0: v8s16, .Type1: p0, .MemTy: v8s16, .Align: 1},
373 {.Type0: v4s32, .Type1: p0, .MemTy: v4s32, .Align: 1},
374 {.Type0: v2s64, .Type1: p0, .MemTy: v2s64, .Align: 1},
375 {.Type0: v2p0, .Type1: p0, .MemTy: v2p0, .Align: 1}});
376 if (HasAVX)
377 Action.legalForTypesWithMemDesc(TypesAndMemDesc: {{.Type0: v32s8, .Type1: p0, .MemTy: v32s8, .Align: 1},
378 {.Type0: v16s16, .Type1: p0, .MemTy: v16s16, .Align: 1},
379 {.Type0: v8s32, .Type1: p0, .MemTy: v8s32, .Align: 1},
380 {.Type0: v4s64, .Type1: p0, .MemTy: v4s64, .Align: 1},
381 {.Type0: v4p0, .Type1: p0, .MemTy: v4p0, .Align: 1}});
382 if (HasAVX512)
383 Action.legalForTypesWithMemDesc(TypesAndMemDesc: {{.Type0: v64s8, .Type1: p0, .MemTy: v64s8, .Align: 1},
384 {.Type0: v32s16, .Type1: p0, .MemTy: v32s16, .Align: 1},
385 {.Type0: v16s32, .Type1: p0, .MemTy: v16s32, .Align: 1},
386 {.Type0: v8s64, .Type1: p0, .MemTy: v8s64, .Align: 1}});
387 Action.widenScalarToNextPow2(TypeIdx: 0, /*Min=*/MinSize: 8).clampScalar(TypeIdx: 0, MinTy: s8, MaxTy: sMaxScalar);
388 }
389
390 for (unsigned Op : {G_SEXTLOAD, G_ZEXTLOAD}) {
391 auto &Action = getActionDefinitionsBuilder(Opcode: Op);
392 Action.legalForTypesWithMemDesc(TypesAndMemDesc: {{.Type0: s16, .Type1: p0, .MemTy: s8, .Align: 1},
393 {.Type0: s32, .Type1: p0, .MemTy: s8, .Align: 1},
394 {.Type0: s32, .Type1: p0, .MemTy: s16, .Align: 1}});
395 if (Is64Bit)
396 Action.legalForTypesWithMemDesc(TypesAndMemDesc: {{.Type0: s64, .Type1: p0, .MemTy: s8, .Align: 1},
397 {.Type0: s64, .Type1: p0, .MemTy: s16, .Align: 1},
398 {.Type0: s64, .Type1: p0, .MemTy: s32, .Align: 1}});
399 // TODO - SSE41/AVX2/AVX512F/AVX512BW vector extensions
400 }
401
402 // sext, zext, and anyext
403 getActionDefinitionsBuilder(Opcodes: {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(TypeIdx: 0, /*Min=*/MinSize: 8)
410 .clampScalar(TypeIdx: 0, MinTy: s8, MaxTy: sMaxScalar)
411 .widenScalarToNextPow2(TypeIdx: 1, /*Min=*/MinSize: 8)
412 .clampScalar(TypeIdx: 1, MinTy: s8, MaxTy: sMaxScalar);
413
414 getActionDefinitionsBuilder(Opcode: G_SEXT_INREG).lower();
415
416 // fp constants
417 getActionDefinitionsBuilder(Opcode: G_FCONSTANT)
418 .legalIf(Predicate: [=](const LegalityQuery &Query) -> bool {
419 return (typeInSet(TypeIdx: 0, TypesInit: {s32, s64})(Query)) ||
420 (UseX87 && typeInSet(TypeIdx: 0, TypesInit: {s80})(Query));
421 });
422
423 // fp arithmetic
424 getActionDefinitionsBuilder(Opcodes: {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
435 getActionDefinitionsBuilder(Opcode: G_FCMP)
436 .legalIf(Predicate: [=](const LegalityQuery &Query) {
437 return (HasSSE1 && typePairInSet(TypeIdx0: 0, TypeIdx1: 1, TypesInit: {{s8, s32}})(Query)) ||
438 (HasSSE2 && typePairInSet(TypeIdx0: 0, TypeIdx1: 1, TypesInit: {{s8, s64}})(Query));
439 })
440 .clampScalar(TypeIdx: 0, MinTy: s8, MaxTy: s8)
441 .clampScalar(TypeIdx: 1, MinTy: s32, MaxTy: HasSSE2 ? s64 : s32)
442 .widenScalarToNextPow2(TypeIdx: 1);
443
444 // fp conversions
445 getActionDefinitionsBuilder(Opcode: G_FPEXT).legalIf(Predicate: [=](const LegalityQuery &Query) {
446 return (HasSSE2 && typePairInSet(TypeIdx0: 0, TypeIdx1: 1, TypesInit: {{s64, s32}})(Query)) ||
447 (HasAVX && typePairInSet(TypeIdx0: 0, TypeIdx1: 1, TypesInit: {{v4s64, v4s32}})(Query)) ||
448 (HasAVX512 && typePairInSet(TypeIdx0: 0, TypeIdx1: 1, TypesInit: {{v8s64, v8s32}})(Query));
449 });
450
451 getActionDefinitionsBuilder(Opcode: G_FPTRUNC).legalIf(
452 Predicate: [=](const LegalityQuery &Query) {
453 return (HasSSE2 && typePairInSet(TypeIdx0: 0, TypeIdx1: 1, TypesInit: {{s32, s64}})(Query)) ||
454 (HasAVX && typePairInSet(TypeIdx0: 0, TypeIdx1: 1, TypesInit: {{v4s32, v4s64}})(Query)) ||
455 (HasAVX512 && typePairInSet(TypeIdx0: 0, TypeIdx1: 1, TypesInit: {{v8s32, v8s64}})(Query));
456 });
457
458 getActionDefinitionsBuilder(Opcode: G_SITOFP)
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(TypeIdx: 1, MinTy: s32, MaxTy: sMaxScalar)
468 .widenScalarToNextPow2(TypeIdx: 1)
469 .clampScalar(TypeIdx: 0, MinTy: s32, MaxTy: HasSSE2 ? s64 : s32)
470 .widenScalarToNextPow2(TypeIdx: 0);
471
472 getActionDefinitionsBuilder(Opcode: G_FPTOSI)
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(TypeIdx: 1, MinTy: s32, MaxTy: HasSSE2 ? s64 : s32)
482 .widenScalarToNextPow2(TypeIdx: 0)
483 .clampScalar(TypeIdx: 0, MinTy: s32, MaxTy: sMaxScalar)
484 .widenScalarToNextPow2(TypeIdx: 1);
485
486 // vector ops
487 getActionDefinitionsBuilder(Opcodes: {G_EXTRACT, G_INSERT})
488 .legalIf(Predicate: [=](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(TypeIdx0: SubIdx, TypeIdx1: FullIdx,
492 TypesInit: {{v16s8, v32s8},
493 {v8s16, v16s16},
494 {v4s32, v8s32},
495 {v2s64, v4s64}})(Query)) ||
496 (HasAVX512 && typePairInSet(TypeIdx0: SubIdx, TypeIdx1: FullIdx,
497 TypesInit: {{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(Opcode: G_CONCAT_VECTORS)
509 .legalIf(Predicate: [=](const LegalityQuery &Query) {
510 return (HasSSE1 && typePairInSet(TypeIdx0: 1, TypeIdx1: 0,
511 TypesInit: {{v16s8, v32s8},
512 {v8s16, v16s16},
513 {v4s32, v8s32},
514 {v2s64, v4s64}})(Query)) ||
515 (HasAVX && typePairInSet(TypeIdx0: 1, TypeIdx1: 0,
516 TypesInit: {{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
527 getActionDefinitionsBuilder(Opcode: G_SELECT)
528 .legalFor(Types: {{s8, s32}, {s16, s32}, {s32, s32}, {s64, s32}, {p0, s32}})
529 .widenScalarToNextPow2(TypeIdx: 0, /*Min=*/MinSize: 8)
530 .clampScalar(TypeIdx: 0, MinTy: HasCMOV ? s16 : s8, MaxTy: sMaxScalar)
531 .clampScalar(TypeIdx: 1, MinTy: s32, MaxTy: s32);
532
533 // memory intrinsics
534 getActionDefinitionsBuilder(Opcodes: {G_MEMCPY, G_MEMMOVE, G_MEMSET}).libcall();
535
536 getActionDefinitionsBuilder(Opcodes: {G_DYN_STACKALLOC,
537 G_STACKSAVE,
538 G_STACKRESTORE}).lower();
539
540 // fp intrinsics
541 getActionDefinitionsBuilder(Opcode: G_INTRINSIC_ROUNDEVEN)
542 .scalarize(TypeIdx: 0)
543 .minScalar(TypeIdx: 0, Ty: LLT::scalar(SizeInBits: 32))
544 .libcall();
545
546 getActionDefinitionsBuilder(Opcodes: {G_FREEZE, G_CONSTANT_FOLD_BARRIER})
547 .legalFor(Types: {s8, s16, s32, s64, p0})
548 .widenScalarToNextPow2(TypeIdx: 0, /*Min=*/MinSize: 8)
549 .clampScalar(TypeIdx: 0, MinTy: s8, MaxTy: sMaxScalar);
550
551 getLegacyLegalizerInfo().computeTables();
552 verify(*STI.getInstrInfo());
553}
554
555bool X86LegalizerInfo::legalizeIntrinsic(LegalizerHelper &Helper,
556 MachineInstr &MI) const {
557 return true;
558}
559

Provided by KDAB

Privacy Policy
Improve your Profiling and Debugging skills
Find out more

source code of llvm/lib/Target/X86/GISel/X86LegalizerInfo.cpp