1 //===- X86LegalizerInfo.cpp --------------------------------------*- C++ -*-==//
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
7 //===----------------------------------------------------------------------===//
9 /// This file implements the targeting of the Machinelegalizer class for X86.
10 /// \todo This should be generated by TableGen.
11 //===----------------------------------------------------------------------===//
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"
23 using namespace TargetOpcode
;
24 using namespace LegalizeActions
;
25 using namespace LegalityPredicates
;
27 X86LegalizerInfo::X86LegalizerInfo(const X86Subtarget
&STI
,
28 const X86TargetMachine
&TM
)
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();
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);
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
);
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
);
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);
73 // todo: AVX512 bool vector predicate types
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
));
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
));
90 .widenScalarToNextPow2(0, /*Min=*/8)
91 .clampScalar(0, s8
, sMaxScalar
);
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()) {
114 switch (Q
.Types
[LitTyIdx
].getSizeInBits()) {
128 // integer addition/subtraction
129 getActionDefinitionsBuilder({G_ADD
, G_SUB
})
130 .legalIf([=](const LegalityQuery
&Query
) -> bool {
131 if (typeInSet(0, {s8
, s16
, s32
})(Query
))
133 if (Is64Bit
&& typeInSet(0, {s64
})(Query
))
135 if (HasSSE2
&& typeInSet(0, {v16s8
, v8s16
, v4s32
, v2s64
})(Query
))
137 if (HasAVX2
&& typeInSet(0, {v32s8
, v16s16
, v8s32
, v4s64
})(Query
))
139 if (HasAVX512
&& typeInSet(0, {v16s32
, v8s64
})(Query
))
141 if (HasBWI
&& typeInSet(0, {v64s8
, v32s16
})(Query
))
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
)
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
));
162 .widenScalarToNextPow2(0, /*Min=*/32)
163 .clampScalar(0, s8
, sMaxScalar
)
164 .clampScalar(1, s1
, s1
)
168 getActionDefinitionsBuilder(G_MUL
)
169 .legalIf([=](const LegalityQuery
&Query
) -> bool {
170 if (typeInSet(0, {s8
, s16
, s32
})(Query
))
172 if (Is64Bit
&& typeInSet(0, {s64
})(Query
))
174 if (HasSSE2
&& typeInSet(0, {v8s16
})(Query
))
176 if (HasSSE41
&& typeInSet(0, {v4s32
})(Query
))
178 if (HasAVX2
&& typeInSet(0, {v16s16
, v8s32
})(Query
))
180 if (HasAVX512
&& typeInSet(0, {v16s32
})(Query
))
182 if (HasDQI
&& typeInSet(0, {v8s64
})(Query
))
184 if (HasDQI
&& HasVLX
&& typeInSet(0, {v2s64
, v4s64
})(Query
))
186 if (HasBWI
&& typeInSet(0, {v32s16
})(Query
))
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
)
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
));
205 .widenScalarToNextPow2(0, /*Min=*/32)
206 .clampScalar(0, s8
, sMaxScalar
)
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
));
215 .clampScalar(0, s8
, sMaxScalar
);
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
));
223 .clampScalar(0, s8
, sMaxScalar
)
224 .clampScalar(1, s8
, s8
);
227 getActionDefinitionsBuilder({G_AND
, G_OR
, G_XOR
})
228 .legalIf([=](const LegalityQuery
&Query
) -> bool {
229 if (typeInSet(0, {s8
, s16
, s32
})(Query
))
231 if (Is64Bit
&& typeInSet(0, {s64
})(Query
))
233 if (HasSSE2
&& typeInSet(0, {v16s8
, v8s16
, v4s32
, v2s64
})(Query
))
235 if (HasAVX
&& typeInSet(0, {v32s8
, v16s16
, v8s32
, v4s64
})(Query
))
237 if (HasAVX512
&& typeInSet(0, {v64s8
, v32s16
, v16s32
, v8s64
})(Query
))
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
)
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
};
257 getActionDefinitionsBuilder(G_ICMP
)
258 .legalForCartesianProduct({s8
}, Is64Bit
? IntTypes64
: IntTypes32
)
259 .clampScalar(0, s8
, s8
)
260 .clampScalar(1, s8
, sMaxScalar
)
261 .scalarSameSizeAs(2, 1);
264 getActionDefinitionsBuilder(G_BSWAP
)
265 .legalIf([=](const LegalityQuery
&Query
) {
266 return Query
.Types
[0] == s32
||
267 (Subtarget
.is64Bit() && Query
.Types
[0] == s64
);
269 .widenScalarToNextPow2(0, /*Min=*/32)
270 .clampScalar(0, s32
, sMaxScalar
);
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
)));
279 .widenScalarToNextPow2(1, /*Min=*/16)
280 .clampScalar(1, s16
, sMaxScalar
)
281 .scalarSameSizeAs(0, 1);
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
)));
290 .widenScalarToNextPow2(1, /*Min=*/16)
291 .clampScalar(1, s16
, sMaxScalar
)
292 .scalarSameSizeAs(0, 1);
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
)));
301 .widenScalarToNextPow2(1, /*Min=*/16)
302 .clampScalar(1, s16
, sMaxScalar
)
303 .scalarSameSizeAs(0, 1);
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
)) ||
313 typeInSet(0, {v64s8
, v32s16
, v16s32
, v8s64
})(Query
));
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
)
327 getActionDefinitionsBuilder(G_BRCOND
).legalFor({s1
});
330 const std::initializer_list
<LLT
> PtrTypes32
= {s1
, s8
, s16
, s32
};
331 const std::initializer_list
<LLT
> PtrTypes64
= {s1
, s8
, s16
, s32
, s64
};
333 getActionDefinitionsBuilder(G_PTRTOINT
)
334 .legalForCartesianProduct(Is64Bit
? PtrTypes64
: PtrTypes32
, {p0
})
335 .maxScalar(0, sMaxScalar
)
336 .widenScalarToNextPow2(0, /*Min*/ 8);
338 getActionDefinitionsBuilder(G_INTTOPTR
).legalFor({{p0
, sMaxScalar
}});
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
));
345 .widenScalarToNextPow2(1, /*Min*/ 32)
346 .clampScalar(1, s32
, sMaxScalar
);
348 getActionDefinitionsBuilder({G_FRAME_INDEX
, G_GLOBAL_VALUE
}).legalFor({p0
});
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},
362 {v4s8
, p0
, v4s8
, 1}});
364 Action
.legalForTypesWithMemDesc({{s64
, p0
, s8
, 1},
368 {v2s32
, p0
, v2s32
, 1}});
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}});
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}});
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
);
389 for (unsigned Op
: {G_SEXTLOAD
, G_ZEXTLOAD
}) {
390 auto &Action
= getActionDefinitionsBuilder(Op
);
391 Action
.legalForTypesWithMemDesc({{s16
, p0
, s8
, 1},
395 Action
.legalForTypesWithMemDesc({{s64
, p0
, s8
, 1},
398 // TODO - SSE41/AVX2/AVX512F/AVX512BW vector extensions
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
);
408 .widenScalarToNextPow2(0, /*Min=*/8)
409 .clampScalar(0, s8
, sMaxScalar
)
410 .widenScalarToNextPow2(1, /*Min=*/8)
411 .clampScalar(1, s8
, sMaxScalar
);
413 getActionDefinitionsBuilder(G_SEXT_INREG
).lower();
416 getActionDefinitionsBuilder(G_FCONSTANT
)
417 .legalIf([=](const LegalityQuery
&Query
) -> bool {
418 return (HasSSE1
&& typeInSet(0, {s32
})(Query
)) ||
419 (HasSSE2
&& typeInSet(0, {s64
})(Query
));
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
));
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
));
437 .clampScalar(0, s8
, s8
)
438 .clampScalar(1, s32
, HasSSE2
? s64
: s32
)
439 .widenScalarToNextPow2(1);
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
));
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
));
455 getActionDefinitionsBuilder(G_SITOFP
)
456 .legalIf([=](const LegalityQuery
&Query
) {
458 (typePairInSet(0, 1, {{s32
, s32
}})(Query
) ||
459 (Is64Bit
&& typePairInSet(0, 1, {{s32
, s64
}})(Query
)))) ||
461 (typePairInSet(0, 1, {{s64
, s32
}})(Query
) ||
462 (Is64Bit
&& typePairInSet(0, 1, {{s64
, s64
}})(Query
))));
464 .clampScalar(1, s32
, sMaxScalar
)
465 .widenScalarToNextPow2(1)
466 .clampScalar(0, s32
, HasSSE2
? s64
: s32
)
467 .widenScalarToNextPow2(0);
469 getActionDefinitionsBuilder(G_FPTOSI
)
470 .legalIf([=](const LegalityQuery
&Query
) {
472 (typePairInSet(0, 1, {{s32
, s32
}})(Query
) ||
473 (Is64Bit
&& typePairInSet(0, 1, {{s64
, s32
}})(Query
)))) ||
475 (typePairInSet(0, 1, {{s32
, s64
}})(Query
) ||
476 (Is64Bit
&& typePairInSet(0, 1, {{s64
, s64
}})(Query
))));
478 .clampScalar(1, s32
, HasSSE2
? s64
: s32
)
479 .widenScalarToNextPow2(0)
480 .clampScalar(0, s32
, sMaxScalar
)
481 .widenScalarToNextPow2(1);
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
,
492 {v2s64
, v4s64
}})(Query
)) ||
493 (HasAVX512
&& typePairInSet(SubIdx
, FullIdx
,
501 {v4s64
, v8s64
}})(Query
));
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,
511 {v2s64
, v4s64
}})(Query
)) ||
512 (HasAVX
&& typePairInSet(1, 0,
520 {v4s64
, v8s64
}})(Query
));
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
);
531 getActionDefinitionsBuilder({G_MEMCPY
, G_MEMMOVE
, G_MEMSET
}).libcall();
533 getActionDefinitionsBuilder({G_DYN_STACKALLOC
,
535 G_STACKRESTORE
}).lower();
538 getActionDefinitionsBuilder(G_INTRINSIC_ROUNDEVEN
)
540 .minScalar(0, LLT::scalar(32))
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
);
548 getLegacyLegalizerInfo().computeTables();
549 verify(*STI
.getInstrInfo());
552 bool X86LegalizerInfo::legalizeIntrinsic(LegalizerHelper
&Helper
,
553 MachineInstr
&MI
) const {