Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/llvm/lib/Target/X86/GISel/X86LegalizerInfo.cpp
35294 views
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/GenericMachineInstrs.h"
17
#include "llvm/CodeGen/GlobalISel/LegalizerHelper.h"
18
#include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h"
19
#include "llvm/CodeGen/MachineConstantPool.h"
20
#include "llvm/CodeGen/TargetOpcodes.h"
21
#include "llvm/CodeGen/ValueTypes.h"
22
#include "llvm/IR/DerivedTypes.h"
23
#include "llvm/IR/Type.h"
24
25
using namespace llvm;
26
using namespace TargetOpcode;
27
using namespace LegalizeActions;
28
using namespace LegalityPredicates;
29
30
X86LegalizerInfo::X86LegalizerInfo(const X86Subtarget &STI,
31
const X86TargetMachine &TM)
32
: Subtarget(STI) {
33
34
bool Is64Bit = Subtarget.is64Bit();
35
bool HasCMOV = Subtarget.canUseCMOV();
36
bool HasSSE1 = Subtarget.hasSSE1();
37
bool HasSSE2 = Subtarget.hasSSE2();
38
bool HasSSE41 = Subtarget.hasSSE41();
39
bool HasAVX = Subtarget.hasAVX();
40
bool HasAVX2 = Subtarget.hasAVX2();
41
bool HasAVX512 = Subtarget.hasAVX512();
42
bool HasVLX = Subtarget.hasVLX();
43
bool HasDQI = Subtarget.hasAVX512() && Subtarget.hasDQI();
44
bool HasBWI = Subtarget.hasAVX512() && Subtarget.hasBWI();
45
bool UseX87 = !Subtarget.useSoftFloat() && Subtarget.hasX87();
46
47
const LLT p0 = LLT::pointer(0, TM.getPointerSizeInBits(0));
48
const LLT s1 = LLT::scalar(1);
49
const LLT s8 = LLT::scalar(8);
50
const LLT s16 = LLT::scalar(16);
51
const LLT s32 = LLT::scalar(32);
52
const LLT s64 = LLT::scalar(64);
53
const LLT s80 = LLT::scalar(80);
54
const LLT s128 = LLT::scalar(128);
55
const LLT sMaxScalar = Subtarget.is64Bit() ? s64 : s32;
56
const LLT v2s32 = LLT::fixed_vector(2, 32);
57
const LLT v4s8 = LLT::fixed_vector(4, 8);
58
59
60
const LLT v16s8 = LLT::fixed_vector(16, 8);
61
const LLT v8s16 = LLT::fixed_vector(8, 16);
62
const LLT v4s32 = LLT::fixed_vector(4, 32);
63
const LLT v2s64 = LLT::fixed_vector(2, 64);
64
const LLT v2p0 = LLT::fixed_vector(2, p0);
65
66
const LLT v32s8 = LLT::fixed_vector(32, 8);
67
const LLT v16s16 = LLT::fixed_vector(16, 16);
68
const LLT v8s32 = LLT::fixed_vector(8, 32);
69
const LLT v4s64 = LLT::fixed_vector(4, 64);
70
const LLT v4p0 = LLT::fixed_vector(4, p0);
71
72
const LLT v64s8 = LLT::fixed_vector(64, 8);
73
const LLT v32s16 = LLT::fixed_vector(32, 16);
74
const LLT v16s32 = LLT::fixed_vector(16, 32);
75
const LLT v8s64 = LLT::fixed_vector(8, 64);
76
77
const LLT s8MaxVector = HasAVX512 ? v64s8 : HasAVX ? v32s8 : v16s8;
78
const LLT s16MaxVector = HasAVX512 ? v32s16 : HasAVX ? v16s16 : v8s16;
79
const LLT s32MaxVector = HasAVX512 ? v16s32 : HasAVX ? v8s32 : v4s32;
80
const LLT s64MaxVector = HasAVX512 ? v8s64 : HasAVX ? v4s64 : v2s64;
81
82
// todo: AVX512 bool vector predicate types
83
84
// implicit/constants
85
getActionDefinitionsBuilder(G_IMPLICIT_DEF)
86
.legalIf([=](const LegalityQuery &Query) -> bool {
87
// 32/64-bits needs support for s64/s128 to handle cases:
88
// s64 = EXTEND (G_IMPLICIT_DEF s32) -> s64 = G_IMPLICIT_DEF
89
// s128 = EXTEND (G_IMPLICIT_DEF s32/s64) -> s128 = G_IMPLICIT_DEF
90
return typeInSet(0, {p0, s1, s8, s16, s32, s64})(Query) ||
91
(Is64Bit && typeInSet(0, {s128})(Query));
92
});
93
94
getActionDefinitionsBuilder(G_CONSTANT)
95
.legalIf([=](const LegalityQuery &Query) -> bool {
96
return typeInSet(0, {p0, s8, s16, s32})(Query) ||
97
(Is64Bit && typeInSet(0, {s64})(Query));
98
})
99
.widenScalarToNextPow2(0, /*Min=*/8)
100
.clampScalar(0, s8, sMaxScalar);
101
102
// merge/unmerge
103
for (unsigned Op : {G_MERGE_VALUES, G_UNMERGE_VALUES}) {
104
unsigned BigTyIdx = Op == G_MERGE_VALUES ? 0 : 1;
105
unsigned LitTyIdx = Op == G_MERGE_VALUES ? 1 : 0;
106
getActionDefinitionsBuilder(Op)
107
.widenScalarToNextPow2(LitTyIdx, /*Min=*/8)
108
.widenScalarToNextPow2(BigTyIdx, /*Min=*/16)
109
.minScalar(LitTyIdx, s8)
110
.minScalar(BigTyIdx, s32)
111
.legalIf([=](const LegalityQuery &Q) {
112
switch (Q.Types[BigTyIdx].getSizeInBits()) {
113
case 16:
114
case 32:
115
case 64:
116
case 128:
117
case 256:
118
case 512:
119
break;
120
default:
121
return false;
122
}
123
switch (Q.Types[LitTyIdx].getSizeInBits()) {
124
case 8:
125
case 16:
126
case 32:
127
case 64:
128
case 128:
129
case 256:
130
return true;
131
default:
132
return false;
133
}
134
});
135
}
136
137
// integer addition/subtraction
138
getActionDefinitionsBuilder({G_ADD, G_SUB})
139
.legalIf([=](const LegalityQuery &Query) -> bool {
140
if (typeInSet(0, {s8, s16, s32})(Query))
141
return true;
142
if (Is64Bit && typeInSet(0, {s64})(Query))
143
return true;
144
if (HasSSE2 && typeInSet(0, {v16s8, v8s16, v4s32, v2s64})(Query))
145
return true;
146
if (HasAVX2 && typeInSet(0, {v32s8, v16s16, v8s32, v4s64})(Query))
147
return true;
148
if (HasAVX512 && typeInSet(0, {v16s32, v8s64})(Query))
149
return true;
150
if (HasBWI && typeInSet(0, {v64s8, v32s16})(Query))
151
return true;
152
return false;
153
})
154
.clampMinNumElements(0, s8, 16)
155
.clampMinNumElements(0, s16, 8)
156
.clampMinNumElements(0, s32, 4)
157
.clampMinNumElements(0, s64, 2)
158
.clampMaxNumElements(0, s8, HasBWI ? 64 : (HasAVX2 ? 32 : 16))
159
.clampMaxNumElements(0, s16, HasBWI ? 32 : (HasAVX2 ? 16 : 8))
160
.clampMaxNumElements(0, s32, HasAVX512 ? 16 : (HasAVX2 ? 8 : 4))
161
.clampMaxNumElements(0, s64, HasAVX512 ? 8 : (HasAVX2 ? 4 : 2))
162
.widenScalarToNextPow2(0, /*Min=*/32)
163
.clampScalar(0, s8, sMaxScalar)
164
.scalarize(0);
165
166
getActionDefinitionsBuilder({G_UADDE, G_UADDO, G_USUBE, G_USUBO})
167
.legalIf([=](const LegalityQuery &Query) -> bool {
168
return typePairInSet(0, 1, {{s8, s1}, {s16, s1}, {s32, s1}})(Query) ||
169
(Is64Bit && typePairInSet(0, 1, {{s64, s1}})(Query));
170
})
171
.widenScalarToNextPow2(0, /*Min=*/32)
172
.clampScalar(0, s8, sMaxScalar)
173
.clampScalar(1, s1, s1)
174
.scalarize(0);
175
176
// integer multiply
177
getActionDefinitionsBuilder(G_MUL)
178
.legalIf([=](const LegalityQuery &Query) -> bool {
179
if (typeInSet(0, {s8, s16, s32})(Query))
180
return true;
181
if (Is64Bit && typeInSet(0, {s64})(Query))
182
return true;
183
if (HasSSE2 && typeInSet(0, {v8s16})(Query))
184
return true;
185
if (HasSSE41 && typeInSet(0, {v4s32})(Query))
186
return true;
187
if (HasAVX2 && typeInSet(0, {v16s16, v8s32})(Query))
188
return true;
189
if (HasAVX512 && typeInSet(0, {v16s32})(Query))
190
return true;
191
if (HasDQI && typeInSet(0, {v8s64})(Query))
192
return true;
193
if (HasDQI && HasVLX && typeInSet(0, {v2s64, v4s64})(Query))
194
return true;
195
if (HasBWI && typeInSet(0, {v32s16})(Query))
196
return true;
197
return false;
198
})
199
.clampMinNumElements(0, s16, 8)
200
.clampMinNumElements(0, s32, 4)
201
.clampMinNumElements(0, s64, HasVLX ? 2 : 8)
202
.clampMaxNumElements(0, s16, HasBWI ? 32 : (HasAVX2 ? 16 : 8))
203
.clampMaxNumElements(0, s32, HasAVX512 ? 16 : (HasAVX2 ? 8 : 4))
204
.clampMaxNumElements(0, s64, 8)
205
.widenScalarToNextPow2(0, /*Min=*/32)
206
.clampScalar(0, s8, sMaxScalar)
207
.scalarize(0);
208
209
getActionDefinitionsBuilder({G_SMULH, G_UMULH})
210
.legalIf([=](const LegalityQuery &Query) -> bool {
211
return typeInSet(0, {s8, s16, s32})(Query) ||
212
(Is64Bit && typeInSet(0, {s64})(Query));
213
})
214
.widenScalarToNextPow2(0, /*Min=*/32)
215
.clampScalar(0, s8, sMaxScalar)
216
.scalarize(0);
217
218
// integer divisions
219
getActionDefinitionsBuilder({G_SDIV, G_SREM, G_UDIV, G_UREM})
220
.legalIf([=](const LegalityQuery &Query) -> bool {
221
return typeInSet(0, {s8, s16, s32})(Query) ||
222
(Is64Bit && typeInSet(0, {s64})(Query));
223
})
224
.libcallFor({s64})
225
.clampScalar(0, s8, sMaxScalar);
226
227
// integer shifts
228
getActionDefinitionsBuilder({G_SHL, G_LSHR, G_ASHR})
229
.legalIf([=](const LegalityQuery &Query) -> bool {
230
return typePairInSet(0, 1, {{s8, s8}, {s16, s8}, {s32, s8}})(Query) ||
231
(Is64Bit && typePairInSet(0, 1, {{s64, s8}})(Query));
232
})
233
.clampScalar(0, s8, sMaxScalar)
234
.clampScalar(1, s8, s8);
235
236
// integer logic
237
getActionDefinitionsBuilder({G_AND, G_OR, G_XOR})
238
.legalIf([=](const LegalityQuery &Query) -> bool {
239
if (typeInSet(0, {s8, s16, s32})(Query))
240
return true;
241
if (Is64Bit && typeInSet(0, {s64})(Query))
242
return true;
243
if (HasSSE2 && typeInSet(0, {v16s8, v8s16, v4s32, v2s64})(Query))
244
return true;
245
if (HasAVX && typeInSet(0, {v32s8, v16s16, v8s32, v4s64})(Query))
246
return true;
247
if (HasAVX512 && typeInSet(0, {v64s8, v32s16, v16s32, v8s64})(Query))
248
return true;
249
return false;
250
})
251
.clampMinNumElements(0, s8, 16)
252
.clampMinNumElements(0, s16, 8)
253
.clampMinNumElements(0, s32, 4)
254
.clampMinNumElements(0, s64, 2)
255
.clampMaxNumElements(0, s8, HasAVX512 ? 64 : (HasAVX ? 32 : 16))
256
.clampMaxNumElements(0, s16, HasAVX512 ? 32 : (HasAVX ? 16 : 8))
257
.clampMaxNumElements(0, s32, HasAVX512 ? 16 : (HasAVX ? 8 : 4))
258
.clampMaxNumElements(0, s64, HasAVX512 ? 8 : (HasAVX ? 4 : 2))
259
.widenScalarToNextPow2(0, /*Min=*/32)
260
.clampScalar(0, s8, sMaxScalar)
261
.scalarize(0);
262
263
// integer comparison
264
const std::initializer_list<LLT> IntTypes32 = {s8, s16, s32, p0};
265
const std::initializer_list<LLT> IntTypes64 = {s8, s16, s32, s64, p0};
266
267
getActionDefinitionsBuilder(G_ICMP)
268
.legalForCartesianProduct({s8}, Is64Bit ? IntTypes64 : IntTypes32)
269
.clampScalar(0, s8, s8)
270
.clampScalar(1, s8, sMaxScalar);
271
272
// bswap
273
getActionDefinitionsBuilder(G_BSWAP)
274
.legalIf([=](const LegalityQuery &Query) {
275
return Query.Types[0] == s32 ||
276
(Subtarget.is64Bit() && Query.Types[0] == s64);
277
})
278
.widenScalarToNextPow2(0, /*Min=*/32)
279
.clampScalar(0, s32, sMaxScalar);
280
281
// popcount
282
getActionDefinitionsBuilder(G_CTPOP)
283
.legalIf([=](const LegalityQuery &Query) -> bool {
284
return Subtarget.hasPOPCNT() &&
285
(typePairInSet(0, 1, {{s16, s16}, {s32, s32}})(Query) ||
286
(Is64Bit && typePairInSet(0, 1, {{s64, s64}})(Query)));
287
})
288
.widenScalarToNextPow2(1, /*Min=*/16)
289
.clampScalar(1, s16, sMaxScalar)
290
.scalarSameSizeAs(0, 1);
291
292
// count leading zeros (LZCNT)
293
getActionDefinitionsBuilder(G_CTLZ)
294
.legalIf([=](const LegalityQuery &Query) -> bool {
295
return Subtarget.hasLZCNT() &&
296
(typePairInSet(0, 1, {{s16, s16}, {s32, s32}})(Query) ||
297
(Is64Bit && typePairInSet(0, 1, {{s64, s64}})(Query)));
298
})
299
.widenScalarToNextPow2(1, /*Min=*/16)
300
.clampScalar(1, s16, sMaxScalar)
301
.scalarSameSizeAs(0, 1);
302
303
// count trailing zeros
304
getActionDefinitionsBuilder({G_CTTZ_ZERO_UNDEF, G_CTTZ})
305
.legalIf([=](const LegalityQuery &Query) -> bool {
306
return (Query.Opcode == G_CTTZ_ZERO_UNDEF || Subtarget.hasBMI()) &&
307
(typePairInSet(0, 1, {{s16, s16}, {s32, s32}})(Query) ||
308
(Is64Bit && typePairInSet(0, 1, {{s64, s64}})(Query)));
309
})
310
.widenScalarToNextPow2(1, /*Min=*/16)
311
.clampScalar(1, s16, sMaxScalar)
312
.scalarSameSizeAs(0, 1);
313
314
// control flow
315
getActionDefinitionsBuilder(G_PHI)
316
.legalIf([=](const LegalityQuery &Query) -> bool {
317
return typeInSet(0, {s8, s16, s32, p0})(Query) ||
318
(Is64Bit && typeInSet(0, {s64})(Query)) ||
319
(HasSSE1 && typeInSet(0, {v16s8, v8s16, v4s32, v2s64})(Query)) ||
320
(HasAVX && typeInSet(0, {v32s8, v16s16, v8s32, v4s64})(Query)) ||
321
(HasAVX512 &&
322
typeInSet(0, {v64s8, v32s16, v16s32, v8s64})(Query));
323
})
324
.clampMinNumElements(0, s8, 16)
325
.clampMinNumElements(0, s16, 8)
326
.clampMinNumElements(0, s32, 4)
327
.clampMinNumElements(0, s64, 2)
328
.clampMaxNumElements(0, s8, HasAVX512 ? 64 : (HasAVX ? 32 : 16))
329
.clampMaxNumElements(0, s16, HasAVX512 ? 32 : (HasAVX ? 16 : 8))
330
.clampMaxNumElements(0, s32, HasAVX512 ? 16 : (HasAVX ? 8 : 4))
331
.clampMaxNumElements(0, s64, HasAVX512 ? 8 : (HasAVX ? 4 : 2))
332
.widenScalarToNextPow2(0, /*Min=*/32)
333
.clampScalar(0, s8, sMaxScalar)
334
.scalarize(0);
335
336
getActionDefinitionsBuilder(G_BRCOND).legalFor({s1});
337
338
// pointer handling
339
const std::initializer_list<LLT> PtrTypes32 = {s1, s8, s16, s32};
340
const std::initializer_list<LLT> PtrTypes64 = {s1, s8, s16, s32, s64};
341
342
getActionDefinitionsBuilder(G_PTRTOINT)
343
.legalForCartesianProduct(Is64Bit ? PtrTypes64 : PtrTypes32, {p0})
344
.maxScalar(0, sMaxScalar)
345
.widenScalarToNextPow2(0, /*Min*/ 8);
346
347
getActionDefinitionsBuilder(G_INTTOPTR).legalFor({{p0, sMaxScalar}});
348
349
getActionDefinitionsBuilder(G_CONSTANT_POOL).legalFor({p0});
350
351
getActionDefinitionsBuilder(G_PTR_ADD)
352
.legalIf([=](const LegalityQuery &Query) -> bool {
353
return typePairInSet(0, 1, {{p0, s32}})(Query) ||
354
(Is64Bit && typePairInSet(0, 1, {{p0, s64}})(Query));
355
})
356
.widenScalarToNextPow2(1, /*Min*/ 32)
357
.clampScalar(1, s32, sMaxScalar);
358
359
getActionDefinitionsBuilder({G_FRAME_INDEX, G_GLOBAL_VALUE}).legalFor({p0});
360
361
// load/store: add more corner cases
362
for (unsigned Op : {G_LOAD, G_STORE}) {
363
auto &Action = getActionDefinitionsBuilder(Op);
364
Action.legalForTypesWithMemDesc({{s8, p0, s1, 1},
365
{s8, p0, s8, 1},
366
{s16, p0, s8, 1},
367
{s16, p0, s16, 1},
368
{s32, p0, s8, 1},
369
{s32, p0, s16, 1},
370
{s32, p0, s32, 1},
371
{s80, p0, s80, 1},
372
{p0, p0, p0, 1},
373
{v4s8, p0, v4s8, 1}});
374
if (Is64Bit)
375
Action.legalForTypesWithMemDesc({{s64, p0, s8, 1},
376
{s64, p0, s16, 1},
377
{s64, p0, s32, 1},
378
{s64, p0, s64, 1},
379
{v2s32, p0, v2s32, 1}});
380
if (HasSSE1)
381
Action.legalForTypesWithMemDesc({{v4s32, p0, v4s32, 1}});
382
if (HasSSE2)
383
Action.legalForTypesWithMemDesc({{v16s8, p0, v16s8, 1},
384
{v8s16, p0, v8s16, 1},
385
{v2s64, p0, v2s64, 1},
386
{v2p0, p0, v2p0, 1}});
387
if (HasAVX)
388
Action.legalForTypesWithMemDesc({{v32s8, p0, v32s8, 1},
389
{v16s16, p0, v16s16, 1},
390
{v8s32, p0, v8s32, 1},
391
{v4s64, p0, v4s64, 1},
392
{v4p0, p0, v4p0, 1}});
393
if (HasAVX512)
394
Action.legalForTypesWithMemDesc({{v64s8, p0, v64s8, 1},
395
{v32s16, p0, v32s16, 1},
396
{v16s32, p0, v16s32, 1},
397
{v8s64, p0, v8s64, 1}});
398
Action.widenScalarToNextPow2(0, /*Min=*/8)
399
.clampScalar(0, s8, sMaxScalar)
400
.scalarize(0);
401
}
402
403
for (unsigned Op : {G_SEXTLOAD, G_ZEXTLOAD}) {
404
auto &Action = getActionDefinitionsBuilder(Op);
405
Action.legalForTypesWithMemDesc({{s16, p0, s8, 1},
406
{s32, p0, s8, 1},
407
{s32, p0, s16, 1}});
408
if (Is64Bit)
409
Action.legalForTypesWithMemDesc({{s64, p0, s8, 1},
410
{s64, p0, s16, 1},
411
{s64, p0, s32, 1}});
412
// TODO - SSE41/AVX2/AVX512F/AVX512BW vector extensions
413
}
414
415
// sext, zext, and anyext
416
getActionDefinitionsBuilder({G_SEXT, G_ZEXT, G_ANYEXT})
417
.legalIf([=](const LegalityQuery &Query) {
418
return typeInSet(0, {s8, s16, s32})(Query) ||
419
(Query.Opcode == G_ANYEXT && Query.Types[0] == s128) ||
420
(Is64Bit && Query.Types[0] == s64);
421
})
422
.widenScalarToNextPow2(0, /*Min=*/8)
423
.clampScalar(0, s8, sMaxScalar)
424
.widenScalarToNextPow2(1, /*Min=*/8)
425
.clampScalar(1, s8, sMaxScalar)
426
.scalarize(0);
427
428
getActionDefinitionsBuilder(G_SEXT_INREG).lower();
429
430
// fp constants
431
getActionDefinitionsBuilder(G_FCONSTANT)
432
.legalIf([=](const LegalityQuery &Query) -> bool {
433
return (typeInSet(0, {s32, s64})(Query)) ||
434
(UseX87 && typeInSet(0, {s80})(Query));
435
});
436
437
// fp arithmetic
438
getActionDefinitionsBuilder({G_FADD, G_FSUB, G_FMUL, G_FDIV})
439
.legalIf([=](const LegalityQuery &Query) {
440
return (typeInSet(0, {s32, s64})(Query)) ||
441
(HasSSE1 && typeInSet(0, {v4s32})(Query)) ||
442
(HasSSE2 && typeInSet(0, {v2s64})(Query)) ||
443
(HasAVX && typeInSet(0, {v8s32, v4s64})(Query)) ||
444
(HasAVX512 && typeInSet(0, {v16s32, v8s64})(Query)) ||
445
(UseX87 && typeInSet(0, {s80})(Query));
446
});
447
448
// fp comparison
449
getActionDefinitionsBuilder(G_FCMP)
450
.legalIf([=](const LegalityQuery &Query) {
451
return (HasSSE1 && typePairInSet(0, 1, {{s8, s32}})(Query)) ||
452
(HasSSE2 && typePairInSet(0, 1, {{s8, s64}})(Query));
453
})
454
.clampScalar(0, s8, s8)
455
.clampScalar(1, s32, HasSSE2 ? s64 : s32)
456
.widenScalarToNextPow2(1);
457
458
// fp conversions
459
getActionDefinitionsBuilder(G_FPEXT).legalIf([=](const LegalityQuery &Query) {
460
return (HasSSE2 && typePairInSet(0, 1, {{s64, s32}})(Query)) ||
461
(HasAVX && typePairInSet(0, 1, {{v4s64, v4s32}})(Query)) ||
462
(HasAVX512 && typePairInSet(0, 1, {{v8s64, v8s32}})(Query));
463
});
464
465
getActionDefinitionsBuilder(G_FPTRUNC).legalIf(
466
[=](const LegalityQuery &Query) {
467
return (HasSSE2 && typePairInSet(0, 1, {{s32, s64}})(Query)) ||
468
(HasAVX && typePairInSet(0, 1, {{v4s32, v4s64}})(Query)) ||
469
(HasAVX512 && typePairInSet(0, 1, {{v8s32, v8s64}})(Query));
470
});
471
472
getActionDefinitionsBuilder(G_SITOFP)
473
.legalIf([=](const LegalityQuery &Query) {
474
return (HasSSE1 &&
475
(typePairInSet(0, 1, {{s32, s32}})(Query) ||
476
(Is64Bit && typePairInSet(0, 1, {{s32, s64}})(Query)))) ||
477
(HasSSE2 &&
478
(typePairInSet(0, 1, {{s64, s32}})(Query) ||
479
(Is64Bit && typePairInSet(0, 1, {{s64, s64}})(Query))));
480
})
481
.clampScalar(1, s32, sMaxScalar)
482
.widenScalarToNextPow2(1)
483
.clampScalar(0, s32, HasSSE2 ? s64 : s32)
484
.widenScalarToNextPow2(0);
485
486
getActionDefinitionsBuilder(G_FPTOSI)
487
.legalIf([=](const LegalityQuery &Query) {
488
return (HasSSE1 &&
489
(typePairInSet(0, 1, {{s32, s32}})(Query) ||
490
(Is64Bit && typePairInSet(0, 1, {{s64, s32}})(Query)))) ||
491
(HasSSE2 &&
492
(typePairInSet(0, 1, {{s32, s64}})(Query) ||
493
(Is64Bit && typePairInSet(0, 1, {{s64, s64}})(Query))));
494
})
495
.clampScalar(1, s32, HasSSE2 ? s64 : s32)
496
.widenScalarToNextPow2(0)
497
.clampScalar(0, s32, sMaxScalar)
498
.widenScalarToNextPow2(1);
499
500
// vector ops
501
getActionDefinitionsBuilder(G_BUILD_VECTOR)
502
.customIf([=](const LegalityQuery &Query) {
503
return (HasSSE1 && typeInSet(0, {v4s32})(Query)) ||
504
(HasSSE2 && typeInSet(0, {v2s64, v8s16, v16s8})(Query)) ||
505
(HasAVX && typeInSet(0, {v4s64, v8s32, v16s16, v32s8})(Query)) ||
506
(HasAVX512 && typeInSet(0, {v8s64, v16s32, v32s16, v64s8}));
507
})
508
.clampNumElements(0, v16s8, s8MaxVector)
509
.clampNumElements(0, v8s16, s16MaxVector)
510
.clampNumElements(0, v4s32, s32MaxVector)
511
.clampNumElements(0, v2s64, s64MaxVector)
512
.moreElementsToNextPow2(0);
513
514
getActionDefinitionsBuilder({G_EXTRACT, G_INSERT})
515
.legalIf([=](const LegalityQuery &Query) {
516
unsigned SubIdx = Query.Opcode == G_EXTRACT ? 0 : 1;
517
unsigned FullIdx = Query.Opcode == G_EXTRACT ? 1 : 0;
518
return (HasAVX && typePairInSet(SubIdx, FullIdx,
519
{{v16s8, v32s8},
520
{v8s16, v16s16},
521
{v4s32, v8s32},
522
{v2s64, v4s64}})(Query)) ||
523
(HasAVX512 && typePairInSet(SubIdx, FullIdx,
524
{{v16s8, v64s8},
525
{v32s8, v64s8},
526
{v8s16, v32s16},
527
{v16s16, v32s16},
528
{v4s32, v16s32},
529
{v8s32, v16s32},
530
{v2s64, v8s64},
531
{v4s64, v8s64}})(Query));
532
});
533
534
// todo: only permit dst types up to max legal vector register size?
535
getActionDefinitionsBuilder(G_CONCAT_VECTORS)
536
.legalIf([=](const LegalityQuery &Query) {
537
return (HasSSE1 && typePairInSet(1, 0,
538
{{v16s8, v32s8},
539
{v8s16, v16s16},
540
{v4s32, v8s32},
541
{v2s64, v4s64}})(Query)) ||
542
(HasAVX && typePairInSet(1, 0,
543
{{v16s8, v64s8},
544
{v32s8, v64s8},
545
{v8s16, v32s16},
546
{v16s16, v32s16},
547
{v4s32, v16s32},
548
{v8s32, v16s32},
549
{v2s64, v8s64},
550
{v4s64, v8s64}})(Query));
551
});
552
553
// todo: vectors and address spaces
554
getActionDefinitionsBuilder(G_SELECT)
555
.legalFor({{s8, s32}, {s16, s32}, {s32, s32}, {s64, s32}, {p0, s32}})
556
.widenScalarToNextPow2(0, /*Min=*/8)
557
.clampScalar(0, HasCMOV ? s16 : s8, sMaxScalar)
558
.clampScalar(1, s32, s32);
559
560
// memory intrinsics
561
getActionDefinitionsBuilder({G_MEMCPY, G_MEMMOVE, G_MEMSET}).libcall();
562
563
getActionDefinitionsBuilder({G_DYN_STACKALLOC,
564
G_STACKSAVE,
565
G_STACKRESTORE}).lower();
566
567
// fp intrinsics
568
getActionDefinitionsBuilder(G_INTRINSIC_ROUNDEVEN)
569
.scalarize(0)
570
.minScalar(0, LLT::scalar(32))
571
.libcall();
572
573
getActionDefinitionsBuilder({G_FREEZE, G_CONSTANT_FOLD_BARRIER})
574
.legalFor({s8, s16, s32, s64, p0})
575
.widenScalarToNextPow2(0, /*Min=*/8)
576
.clampScalar(0, s8, sMaxScalar);
577
578
getLegacyLegalizerInfo().computeTables();
579
verify(*STI.getInstrInfo());
580
}
581
582
bool X86LegalizerInfo::legalizeCustom(LegalizerHelper &Helper, MachineInstr &MI,
583
LostDebugLocObserver &LocObserver) const {
584
MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
585
MachineRegisterInfo &MRI = *MIRBuilder.getMRI();
586
switch (MI.getOpcode()) {
587
default:
588
// No idea what to do.
589
return false;
590
case TargetOpcode::G_BUILD_VECTOR:
591
return legalizeBuildVector(MI, MRI, Helper);
592
}
593
llvm_unreachable("expected switch to return");
594
}
595
596
bool X86LegalizerInfo::legalizeBuildVector(MachineInstr &MI,
597
MachineRegisterInfo &MRI,
598
LegalizerHelper &Helper) const {
599
MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
600
const auto &BuildVector = cast<GBuildVector>(MI);
601
Register Dst = BuildVector.getReg(0);
602
LLT DstTy = MRI.getType(Dst);
603
MachineFunction &MF = MIRBuilder.getMF();
604
LLVMContext &Ctx = MF.getFunction().getContext();
605
uint64_t DstTySize = DstTy.getScalarSizeInBits();
606
607
SmallVector<Constant *, 4> CstIdxs;
608
for (unsigned i = 0; i < BuildVector.getNumSources(); ++i) {
609
Register Source = BuildVector.getSourceReg(i);
610
611
auto ValueAndReg = getIConstantVRegValWithLookThrough(Source, MRI);
612
if (ValueAndReg) {
613
CstIdxs.emplace_back(ConstantInt::get(Ctx, ValueAndReg->Value));
614
continue;
615
}
616
617
auto FPValueAndReg = getFConstantVRegValWithLookThrough(Source, MRI);
618
if (FPValueAndReg) {
619
CstIdxs.emplace_back(ConstantFP::get(Ctx, FPValueAndReg->Value));
620
continue;
621
}
622
623
if (getOpcodeDef<GImplicitDef>(Source, MRI)) {
624
CstIdxs.emplace_back(UndefValue::get(Type::getIntNTy(Ctx, DstTySize)));
625
continue;
626
}
627
return false;
628
}
629
630
Constant *ConstVal = ConstantVector::get(CstIdxs);
631
632
const DataLayout &DL = MIRBuilder.getDataLayout();
633
unsigned AddrSpace = DL.getDefaultGlobalsAddressSpace();
634
Align Alignment(DL.getABITypeAlign(ConstVal->getType()));
635
auto Addr = MIRBuilder.buildConstantPool(
636
LLT::pointer(AddrSpace, DL.getPointerSizeInBits(AddrSpace)),
637
MF.getConstantPool()->getConstantPoolIndex(ConstVal, Alignment));
638
MachineMemOperand *MMO =
639
MF.getMachineMemOperand(MachinePointerInfo::getConstantPool(MF),
640
MachineMemOperand::MOLoad, DstTy, Alignment);
641
642
MIRBuilder.buildLoad(Dst, Addr, *MMO);
643
MI.eraseFromParent();
644
return true;
645
}
646
647
bool X86LegalizerInfo::legalizeIntrinsic(LegalizerHelper &Helper,
648
MachineInstr &MI) const {
649
return true;
650
}
651
652