xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/X86/GISel/X86LegalizerInfo.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
15f757f3fSDimitry Andric //===- X86LegalizerInfo.cpp --------------------------------------*- C++ -*-==//
25f757f3fSDimitry Andric //
35f757f3fSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
45f757f3fSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
55f757f3fSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
65f757f3fSDimitry Andric //
75f757f3fSDimitry Andric //===----------------------------------------------------------------------===//
85f757f3fSDimitry Andric /// \file
95f757f3fSDimitry Andric /// This file implements the targeting of the Machinelegalizer class for X86.
105f757f3fSDimitry Andric /// \todo This should be generated by TableGen.
115f757f3fSDimitry Andric //===----------------------------------------------------------------------===//
125f757f3fSDimitry Andric 
135f757f3fSDimitry Andric #include "X86LegalizerInfo.h"
145f757f3fSDimitry Andric #include "X86Subtarget.h"
155f757f3fSDimitry Andric #include "X86TargetMachine.h"
16*0fca6ea1SDimitry Andric #include "llvm/CodeGen/GlobalISel/GenericMachineInstrs.h"
175f757f3fSDimitry Andric #include "llvm/CodeGen/GlobalISel/LegalizerHelper.h"
18*0fca6ea1SDimitry Andric #include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h"
19*0fca6ea1SDimitry Andric #include "llvm/CodeGen/MachineConstantPool.h"
205f757f3fSDimitry Andric #include "llvm/CodeGen/TargetOpcodes.h"
215f757f3fSDimitry Andric #include "llvm/CodeGen/ValueTypes.h"
225f757f3fSDimitry Andric #include "llvm/IR/DerivedTypes.h"
235f757f3fSDimitry Andric #include "llvm/IR/Type.h"
245f757f3fSDimitry Andric 
255f757f3fSDimitry Andric using namespace llvm;
265f757f3fSDimitry Andric using namespace TargetOpcode;
275f757f3fSDimitry Andric using namespace LegalizeActions;
285f757f3fSDimitry Andric using namespace LegalityPredicates;
295f757f3fSDimitry Andric 
305f757f3fSDimitry Andric X86LegalizerInfo::X86LegalizerInfo(const X86Subtarget &STI,
315f757f3fSDimitry Andric                                    const X86TargetMachine &TM)
325f757f3fSDimitry Andric     : Subtarget(STI) {
335f757f3fSDimitry Andric 
345f757f3fSDimitry Andric   bool Is64Bit = Subtarget.is64Bit();
355f757f3fSDimitry Andric   bool HasCMOV = Subtarget.canUseCMOV();
365f757f3fSDimitry Andric   bool HasSSE1 = Subtarget.hasSSE1();
375f757f3fSDimitry Andric   bool HasSSE2 = Subtarget.hasSSE2();
385f757f3fSDimitry Andric   bool HasSSE41 = Subtarget.hasSSE41();
395f757f3fSDimitry Andric   bool HasAVX = Subtarget.hasAVX();
405f757f3fSDimitry Andric   bool HasAVX2 = Subtarget.hasAVX2();
415f757f3fSDimitry Andric   bool HasAVX512 = Subtarget.hasAVX512();
425f757f3fSDimitry Andric   bool HasVLX = Subtarget.hasVLX();
435f757f3fSDimitry Andric   bool HasDQI = Subtarget.hasAVX512() && Subtarget.hasDQI();
445f757f3fSDimitry Andric   bool HasBWI = Subtarget.hasAVX512() && Subtarget.hasBWI();
45*0fca6ea1SDimitry Andric   bool UseX87 = !Subtarget.useSoftFloat() && Subtarget.hasX87();
465f757f3fSDimitry Andric 
475f757f3fSDimitry Andric   const LLT p0 = LLT::pointer(0, TM.getPointerSizeInBits(0));
485f757f3fSDimitry Andric   const LLT s1 = LLT::scalar(1);
495f757f3fSDimitry Andric   const LLT s8 = LLT::scalar(8);
505f757f3fSDimitry Andric   const LLT s16 = LLT::scalar(16);
515f757f3fSDimitry Andric   const LLT s32 = LLT::scalar(32);
525f757f3fSDimitry Andric   const LLT s64 = LLT::scalar(64);
535f757f3fSDimitry Andric   const LLT s80 = LLT::scalar(80);
545f757f3fSDimitry Andric   const LLT s128 = LLT::scalar(128);
555f757f3fSDimitry Andric   const LLT sMaxScalar = Subtarget.is64Bit() ? s64 : s32;
565f757f3fSDimitry Andric   const LLT v2s32 = LLT::fixed_vector(2, 32);
575f757f3fSDimitry Andric   const LLT v4s8 = LLT::fixed_vector(4, 8);
585f757f3fSDimitry Andric 
595f757f3fSDimitry Andric 
605f757f3fSDimitry Andric   const LLT v16s8 = LLT::fixed_vector(16, 8);
615f757f3fSDimitry Andric   const LLT v8s16 = LLT::fixed_vector(8, 16);
625f757f3fSDimitry Andric   const LLT v4s32 = LLT::fixed_vector(4, 32);
635f757f3fSDimitry Andric   const LLT v2s64 = LLT::fixed_vector(2, 64);
645f757f3fSDimitry Andric   const LLT v2p0 = LLT::fixed_vector(2, p0);
655f757f3fSDimitry Andric 
665f757f3fSDimitry Andric   const LLT v32s8 = LLT::fixed_vector(32, 8);
675f757f3fSDimitry Andric   const LLT v16s16 = LLT::fixed_vector(16, 16);
685f757f3fSDimitry Andric   const LLT v8s32 = LLT::fixed_vector(8, 32);
695f757f3fSDimitry Andric   const LLT v4s64 = LLT::fixed_vector(4, 64);
705f757f3fSDimitry Andric   const LLT v4p0 = LLT::fixed_vector(4, p0);
715f757f3fSDimitry Andric 
725f757f3fSDimitry Andric   const LLT v64s8 = LLT::fixed_vector(64, 8);
735f757f3fSDimitry Andric   const LLT v32s16 = LLT::fixed_vector(32, 16);
745f757f3fSDimitry Andric   const LLT v16s32 = LLT::fixed_vector(16, 32);
755f757f3fSDimitry Andric   const LLT v8s64 = LLT::fixed_vector(8, 64);
765f757f3fSDimitry Andric 
77*0fca6ea1SDimitry Andric   const LLT s8MaxVector = HasAVX512 ? v64s8 : HasAVX ? v32s8 : v16s8;
78*0fca6ea1SDimitry Andric   const LLT s16MaxVector = HasAVX512 ? v32s16 : HasAVX ? v16s16 : v8s16;
79*0fca6ea1SDimitry Andric   const LLT s32MaxVector = HasAVX512 ? v16s32 : HasAVX ? v8s32 : v4s32;
80*0fca6ea1SDimitry Andric   const LLT s64MaxVector = HasAVX512 ? v8s64 : HasAVX ? v4s64 : v2s64;
81*0fca6ea1SDimitry Andric 
825f757f3fSDimitry Andric   // todo: AVX512 bool vector predicate types
835f757f3fSDimitry Andric 
845f757f3fSDimitry Andric   // implicit/constants
855f757f3fSDimitry Andric   getActionDefinitionsBuilder(G_IMPLICIT_DEF)
865f757f3fSDimitry Andric       .legalIf([=](const LegalityQuery &Query) -> bool {
875f757f3fSDimitry Andric         // 32/64-bits needs support for s64/s128 to handle cases:
885f757f3fSDimitry Andric         // s64 = EXTEND (G_IMPLICIT_DEF s32) -> s64 = G_IMPLICIT_DEF
895f757f3fSDimitry Andric         // s128 = EXTEND (G_IMPLICIT_DEF s32/s64) -> s128 = G_IMPLICIT_DEF
905f757f3fSDimitry Andric         return typeInSet(0, {p0, s1, s8, s16, s32, s64})(Query) ||
915f757f3fSDimitry Andric                (Is64Bit && typeInSet(0, {s128})(Query));
925f757f3fSDimitry Andric       });
935f757f3fSDimitry Andric 
945f757f3fSDimitry Andric   getActionDefinitionsBuilder(G_CONSTANT)
955f757f3fSDimitry Andric       .legalIf([=](const LegalityQuery &Query) -> bool {
965f757f3fSDimitry Andric         return typeInSet(0, {p0, s8, s16, s32})(Query) ||
975f757f3fSDimitry Andric                (Is64Bit && typeInSet(0, {s64})(Query));
985f757f3fSDimitry Andric       })
995f757f3fSDimitry Andric       .widenScalarToNextPow2(0, /*Min=*/8)
1005f757f3fSDimitry Andric       .clampScalar(0, s8, sMaxScalar);
1015f757f3fSDimitry Andric 
1025f757f3fSDimitry Andric   // merge/unmerge
1035f757f3fSDimitry Andric   for (unsigned Op : {G_MERGE_VALUES, G_UNMERGE_VALUES}) {
1045f757f3fSDimitry Andric     unsigned BigTyIdx = Op == G_MERGE_VALUES ? 0 : 1;
1055f757f3fSDimitry Andric     unsigned LitTyIdx = Op == G_MERGE_VALUES ? 1 : 0;
1065f757f3fSDimitry Andric     getActionDefinitionsBuilder(Op)
1075f757f3fSDimitry Andric         .widenScalarToNextPow2(LitTyIdx, /*Min=*/8)
1085f757f3fSDimitry Andric         .widenScalarToNextPow2(BigTyIdx, /*Min=*/16)
1095f757f3fSDimitry Andric         .minScalar(LitTyIdx, s8)
1105f757f3fSDimitry Andric         .minScalar(BigTyIdx, s32)
1115f757f3fSDimitry Andric         .legalIf([=](const LegalityQuery &Q) {
1125f757f3fSDimitry Andric           switch (Q.Types[BigTyIdx].getSizeInBits()) {
1135f757f3fSDimitry Andric           case 16:
1145f757f3fSDimitry Andric           case 32:
1155f757f3fSDimitry Andric           case 64:
1165f757f3fSDimitry Andric           case 128:
1175f757f3fSDimitry Andric           case 256:
1185f757f3fSDimitry Andric           case 512:
1195f757f3fSDimitry Andric             break;
1205f757f3fSDimitry Andric           default:
1215f757f3fSDimitry Andric             return false;
1225f757f3fSDimitry Andric           }
1235f757f3fSDimitry Andric           switch (Q.Types[LitTyIdx].getSizeInBits()) {
1245f757f3fSDimitry Andric           case 8:
1255f757f3fSDimitry Andric           case 16:
1265f757f3fSDimitry Andric           case 32:
1275f757f3fSDimitry Andric           case 64:
1285f757f3fSDimitry Andric           case 128:
1295f757f3fSDimitry Andric           case 256:
1305f757f3fSDimitry Andric             return true;
1315f757f3fSDimitry Andric           default:
1325f757f3fSDimitry Andric             return false;
1335f757f3fSDimitry Andric           }
1345f757f3fSDimitry Andric         });
1355f757f3fSDimitry Andric   }
1365f757f3fSDimitry Andric 
1375f757f3fSDimitry Andric   // integer addition/subtraction
1385f757f3fSDimitry Andric   getActionDefinitionsBuilder({G_ADD, G_SUB})
1395f757f3fSDimitry Andric       .legalIf([=](const LegalityQuery &Query) -> bool {
1405f757f3fSDimitry Andric         if (typeInSet(0, {s8, s16, s32})(Query))
1415f757f3fSDimitry Andric           return true;
1425f757f3fSDimitry Andric         if (Is64Bit && typeInSet(0, {s64})(Query))
1435f757f3fSDimitry Andric           return true;
1445f757f3fSDimitry Andric         if (HasSSE2 && typeInSet(0, {v16s8, v8s16, v4s32, v2s64})(Query))
1455f757f3fSDimitry Andric           return true;
1465f757f3fSDimitry Andric         if (HasAVX2 && typeInSet(0, {v32s8, v16s16, v8s32, v4s64})(Query))
1475f757f3fSDimitry Andric           return true;
1485f757f3fSDimitry Andric         if (HasAVX512 && typeInSet(0, {v16s32, v8s64})(Query))
1495f757f3fSDimitry Andric           return true;
1505f757f3fSDimitry Andric         if (HasBWI && typeInSet(0, {v64s8, v32s16})(Query))
1515f757f3fSDimitry Andric           return true;
1525f757f3fSDimitry Andric         return false;
1535f757f3fSDimitry Andric       })
1545f757f3fSDimitry Andric       .clampMinNumElements(0, s8, 16)
1555f757f3fSDimitry Andric       .clampMinNumElements(0, s16, 8)
1565f757f3fSDimitry Andric       .clampMinNumElements(0, s32, 4)
1575f757f3fSDimitry Andric       .clampMinNumElements(0, s64, 2)
1585f757f3fSDimitry Andric       .clampMaxNumElements(0, s8, HasBWI ? 64 : (HasAVX2 ? 32 : 16))
1595f757f3fSDimitry Andric       .clampMaxNumElements(0, s16, HasBWI ? 32 : (HasAVX2 ? 16 : 8))
1605f757f3fSDimitry Andric       .clampMaxNumElements(0, s32, HasAVX512 ? 16 : (HasAVX2 ? 8 : 4))
1615f757f3fSDimitry Andric       .clampMaxNumElements(0, s64, HasAVX512 ? 8 : (HasAVX2 ? 4 : 2))
1625f757f3fSDimitry Andric       .widenScalarToNextPow2(0, /*Min=*/32)
1635f757f3fSDimitry Andric       .clampScalar(0, s8, sMaxScalar)
1645f757f3fSDimitry Andric       .scalarize(0);
1655f757f3fSDimitry Andric 
1665f757f3fSDimitry Andric   getActionDefinitionsBuilder({G_UADDE, G_UADDO, G_USUBE, G_USUBO})
1675f757f3fSDimitry Andric       .legalIf([=](const LegalityQuery &Query) -> bool {
1685f757f3fSDimitry Andric         return typePairInSet(0, 1, {{s8, s1}, {s16, s1}, {s32, s1}})(Query) ||
1695f757f3fSDimitry Andric                (Is64Bit && typePairInSet(0, 1, {{s64, s1}})(Query));
1705f757f3fSDimitry Andric       })
1715f757f3fSDimitry Andric       .widenScalarToNextPow2(0, /*Min=*/32)
1725f757f3fSDimitry Andric       .clampScalar(0, s8, sMaxScalar)
1735f757f3fSDimitry Andric       .clampScalar(1, s1, s1)
1745f757f3fSDimitry Andric       .scalarize(0);
1755f757f3fSDimitry Andric 
1765f757f3fSDimitry Andric   // integer multiply
1775f757f3fSDimitry Andric   getActionDefinitionsBuilder(G_MUL)
1785f757f3fSDimitry Andric       .legalIf([=](const LegalityQuery &Query) -> bool {
1795f757f3fSDimitry Andric         if (typeInSet(0, {s8, s16, s32})(Query))
1805f757f3fSDimitry Andric           return true;
1815f757f3fSDimitry Andric         if (Is64Bit && typeInSet(0, {s64})(Query))
1825f757f3fSDimitry Andric           return true;
1835f757f3fSDimitry Andric         if (HasSSE2 && typeInSet(0, {v8s16})(Query))
1845f757f3fSDimitry Andric           return true;
1855f757f3fSDimitry Andric         if (HasSSE41 && typeInSet(0, {v4s32})(Query))
1865f757f3fSDimitry Andric           return true;
1875f757f3fSDimitry Andric         if (HasAVX2 && typeInSet(0, {v16s16, v8s32})(Query))
1885f757f3fSDimitry Andric           return true;
1895f757f3fSDimitry Andric         if (HasAVX512 && typeInSet(0, {v16s32})(Query))
1905f757f3fSDimitry Andric           return true;
1915f757f3fSDimitry Andric         if (HasDQI && typeInSet(0, {v8s64})(Query))
1925f757f3fSDimitry Andric           return true;
1935f757f3fSDimitry Andric         if (HasDQI && HasVLX && typeInSet(0, {v2s64, v4s64})(Query))
1945f757f3fSDimitry Andric           return true;
1955f757f3fSDimitry Andric         if (HasBWI && typeInSet(0, {v32s16})(Query))
1965f757f3fSDimitry Andric           return true;
1975f757f3fSDimitry Andric         return false;
1985f757f3fSDimitry Andric       })
1995f757f3fSDimitry Andric       .clampMinNumElements(0, s16, 8)
2005f757f3fSDimitry Andric       .clampMinNumElements(0, s32, 4)
2015f757f3fSDimitry Andric       .clampMinNumElements(0, s64, HasVLX ? 2 : 8)
2025f757f3fSDimitry Andric       .clampMaxNumElements(0, s16, HasBWI ? 32 : (HasAVX2 ? 16 : 8))
2035f757f3fSDimitry Andric       .clampMaxNumElements(0, s32, HasAVX512 ? 16 : (HasAVX2 ? 8 : 4))
2045f757f3fSDimitry Andric       .clampMaxNumElements(0, s64, 8)
2055f757f3fSDimitry Andric       .widenScalarToNextPow2(0, /*Min=*/32)
2065f757f3fSDimitry Andric       .clampScalar(0, s8, sMaxScalar)
2075f757f3fSDimitry Andric       .scalarize(0);
2085f757f3fSDimitry Andric 
2095f757f3fSDimitry Andric   getActionDefinitionsBuilder({G_SMULH, G_UMULH})
2105f757f3fSDimitry Andric       .legalIf([=](const LegalityQuery &Query) -> bool {
2115f757f3fSDimitry Andric         return typeInSet(0, {s8, s16, s32})(Query) ||
2125f757f3fSDimitry Andric                (Is64Bit && typeInSet(0, {s64})(Query));
2135f757f3fSDimitry Andric       })
2145f757f3fSDimitry Andric       .widenScalarToNextPow2(0, /*Min=*/32)
2155f757f3fSDimitry Andric       .clampScalar(0, s8, sMaxScalar)
2165f757f3fSDimitry Andric       .scalarize(0);
2175f757f3fSDimitry Andric 
2185f757f3fSDimitry Andric   // integer divisions
2195f757f3fSDimitry Andric   getActionDefinitionsBuilder({G_SDIV, G_SREM, G_UDIV, G_UREM})
2205f757f3fSDimitry Andric       .legalIf([=](const LegalityQuery &Query) -> bool {
2215f757f3fSDimitry Andric         return typeInSet(0, {s8, s16, s32})(Query) ||
2225f757f3fSDimitry Andric                (Is64Bit && typeInSet(0, {s64})(Query));
2235f757f3fSDimitry Andric       })
224*0fca6ea1SDimitry Andric       .libcallFor({s64})
2255f757f3fSDimitry Andric       .clampScalar(0, s8, sMaxScalar);
2265f757f3fSDimitry Andric 
2275f757f3fSDimitry Andric   // integer shifts
2285f757f3fSDimitry Andric   getActionDefinitionsBuilder({G_SHL, G_LSHR, G_ASHR})
2295f757f3fSDimitry Andric       .legalIf([=](const LegalityQuery &Query) -> bool {
2305f757f3fSDimitry Andric         return typePairInSet(0, 1, {{s8, s8}, {s16, s8}, {s32, s8}})(Query) ||
2315f757f3fSDimitry Andric                (Is64Bit && typePairInSet(0, 1, {{s64, s8}})(Query));
2325f757f3fSDimitry Andric       })
2335f757f3fSDimitry Andric       .clampScalar(0, s8, sMaxScalar)
2345f757f3fSDimitry Andric       .clampScalar(1, s8, s8);
2355f757f3fSDimitry Andric 
2365f757f3fSDimitry Andric   // integer logic
2375f757f3fSDimitry Andric   getActionDefinitionsBuilder({G_AND, G_OR, G_XOR})
2385f757f3fSDimitry Andric       .legalIf([=](const LegalityQuery &Query) -> bool {
2395f757f3fSDimitry Andric         if (typeInSet(0, {s8, s16, s32})(Query))
2405f757f3fSDimitry Andric           return true;
2415f757f3fSDimitry Andric         if (Is64Bit && typeInSet(0, {s64})(Query))
2425f757f3fSDimitry Andric           return true;
2435f757f3fSDimitry Andric         if (HasSSE2 && typeInSet(0, {v16s8, v8s16, v4s32, v2s64})(Query))
2445f757f3fSDimitry Andric           return true;
2455f757f3fSDimitry Andric         if (HasAVX && typeInSet(0, {v32s8, v16s16, v8s32, v4s64})(Query))
2465f757f3fSDimitry Andric           return true;
2475f757f3fSDimitry Andric         if (HasAVX512 && typeInSet(0, {v64s8, v32s16, v16s32, v8s64})(Query))
2485f757f3fSDimitry Andric           return true;
2495f757f3fSDimitry Andric         return false;
2505f757f3fSDimitry Andric       })
2515f757f3fSDimitry Andric       .clampMinNumElements(0, s8, 16)
2525f757f3fSDimitry Andric       .clampMinNumElements(0, s16, 8)
2535f757f3fSDimitry Andric       .clampMinNumElements(0, s32, 4)
2545f757f3fSDimitry Andric       .clampMinNumElements(0, s64, 2)
2555f757f3fSDimitry Andric       .clampMaxNumElements(0, s8, HasAVX512 ? 64 : (HasAVX ? 32 : 16))
2565f757f3fSDimitry Andric       .clampMaxNumElements(0, s16, HasAVX512 ? 32 : (HasAVX ? 16 : 8))
2575f757f3fSDimitry Andric       .clampMaxNumElements(0, s32, HasAVX512 ? 16 : (HasAVX ? 8 : 4))
2585f757f3fSDimitry Andric       .clampMaxNumElements(0, s64, HasAVX512 ? 8 : (HasAVX ? 4 : 2))
2595f757f3fSDimitry Andric       .widenScalarToNextPow2(0, /*Min=*/32)
2605f757f3fSDimitry Andric       .clampScalar(0, s8, sMaxScalar)
2615f757f3fSDimitry Andric       .scalarize(0);
2625f757f3fSDimitry Andric 
2635f757f3fSDimitry Andric   // integer comparison
2645f757f3fSDimitry Andric   const std::initializer_list<LLT> IntTypes32 = {s8, s16, s32, p0};
2655f757f3fSDimitry Andric   const std::initializer_list<LLT> IntTypes64 = {s8, s16, s32, s64, p0};
2665f757f3fSDimitry Andric 
2675f757f3fSDimitry Andric   getActionDefinitionsBuilder(G_ICMP)
2685f757f3fSDimitry Andric       .legalForCartesianProduct({s8}, Is64Bit ? IntTypes64 : IntTypes32)
2695f757f3fSDimitry Andric       .clampScalar(0, s8, s8)
270*0fca6ea1SDimitry Andric       .clampScalar(1, s8, sMaxScalar);
2715f757f3fSDimitry Andric 
2725f757f3fSDimitry Andric   // bswap
2735f757f3fSDimitry Andric   getActionDefinitionsBuilder(G_BSWAP)
2745f757f3fSDimitry Andric       .legalIf([=](const LegalityQuery &Query) {
2755f757f3fSDimitry Andric         return Query.Types[0] == s32 ||
2765f757f3fSDimitry Andric                (Subtarget.is64Bit() && Query.Types[0] == s64);
2775f757f3fSDimitry Andric       })
2785f757f3fSDimitry Andric       .widenScalarToNextPow2(0, /*Min=*/32)
2795f757f3fSDimitry Andric       .clampScalar(0, s32, sMaxScalar);
2805f757f3fSDimitry Andric 
2815f757f3fSDimitry Andric   // popcount
2825f757f3fSDimitry Andric   getActionDefinitionsBuilder(G_CTPOP)
2835f757f3fSDimitry Andric       .legalIf([=](const LegalityQuery &Query) -> bool {
2845f757f3fSDimitry Andric         return Subtarget.hasPOPCNT() &&
2855f757f3fSDimitry Andric                (typePairInSet(0, 1, {{s16, s16}, {s32, s32}})(Query) ||
2865f757f3fSDimitry Andric                 (Is64Bit && typePairInSet(0, 1, {{s64, s64}})(Query)));
2875f757f3fSDimitry Andric       })
2885f757f3fSDimitry Andric       .widenScalarToNextPow2(1, /*Min=*/16)
2895f757f3fSDimitry Andric       .clampScalar(1, s16, sMaxScalar)
2905f757f3fSDimitry Andric       .scalarSameSizeAs(0, 1);
2915f757f3fSDimitry Andric 
2925f757f3fSDimitry Andric   // count leading zeros (LZCNT)
2935f757f3fSDimitry Andric   getActionDefinitionsBuilder(G_CTLZ)
2945f757f3fSDimitry Andric       .legalIf([=](const LegalityQuery &Query) -> bool {
2955f757f3fSDimitry Andric         return Subtarget.hasLZCNT() &&
2965f757f3fSDimitry Andric                (typePairInSet(0, 1, {{s16, s16}, {s32, s32}})(Query) ||
2975f757f3fSDimitry Andric                 (Is64Bit && typePairInSet(0, 1, {{s64, s64}})(Query)));
2985f757f3fSDimitry Andric       })
2995f757f3fSDimitry Andric       .widenScalarToNextPow2(1, /*Min=*/16)
3005f757f3fSDimitry Andric       .clampScalar(1, s16, sMaxScalar)
3015f757f3fSDimitry Andric       .scalarSameSizeAs(0, 1);
3025f757f3fSDimitry Andric 
3035f757f3fSDimitry Andric   // count trailing zeros
3045f757f3fSDimitry Andric   getActionDefinitionsBuilder({G_CTTZ_ZERO_UNDEF, G_CTTZ})
3055f757f3fSDimitry Andric       .legalIf([=](const LegalityQuery &Query) -> bool {
3065f757f3fSDimitry Andric         return (Query.Opcode == G_CTTZ_ZERO_UNDEF || Subtarget.hasBMI()) &&
3075f757f3fSDimitry Andric                (typePairInSet(0, 1, {{s16, s16}, {s32, s32}})(Query) ||
3085f757f3fSDimitry Andric                 (Is64Bit && typePairInSet(0, 1, {{s64, s64}})(Query)));
3095f757f3fSDimitry Andric       })
3105f757f3fSDimitry Andric       .widenScalarToNextPow2(1, /*Min=*/16)
3115f757f3fSDimitry Andric       .clampScalar(1, s16, sMaxScalar)
3125f757f3fSDimitry Andric       .scalarSameSizeAs(0, 1);
3135f757f3fSDimitry Andric 
3145f757f3fSDimitry Andric   // control flow
3155f757f3fSDimitry Andric   getActionDefinitionsBuilder(G_PHI)
3165f757f3fSDimitry Andric       .legalIf([=](const LegalityQuery &Query) -> bool {
3175f757f3fSDimitry Andric         return typeInSet(0, {s8, s16, s32, p0})(Query) ||
3185f757f3fSDimitry Andric                (Is64Bit && typeInSet(0, {s64})(Query)) ||
3195f757f3fSDimitry Andric                (HasSSE1 && typeInSet(0, {v16s8, v8s16, v4s32, v2s64})(Query)) ||
3205f757f3fSDimitry Andric                (HasAVX && typeInSet(0, {v32s8, v16s16, v8s32, v4s64})(Query)) ||
3215f757f3fSDimitry Andric                (HasAVX512 &&
3225f757f3fSDimitry Andric                 typeInSet(0, {v64s8, v32s16, v16s32, v8s64})(Query));
3235f757f3fSDimitry Andric       })
3245f757f3fSDimitry Andric       .clampMinNumElements(0, s8, 16)
3255f757f3fSDimitry Andric       .clampMinNumElements(0, s16, 8)
3265f757f3fSDimitry Andric       .clampMinNumElements(0, s32, 4)
3275f757f3fSDimitry Andric       .clampMinNumElements(0, s64, 2)
3285f757f3fSDimitry Andric       .clampMaxNumElements(0, s8, HasAVX512 ? 64 : (HasAVX ? 32 : 16))
3295f757f3fSDimitry Andric       .clampMaxNumElements(0, s16, HasAVX512 ? 32 : (HasAVX ? 16 : 8))
3305f757f3fSDimitry Andric       .clampMaxNumElements(0, s32, HasAVX512 ? 16 : (HasAVX ? 8 : 4))
3315f757f3fSDimitry Andric       .clampMaxNumElements(0, s64, HasAVX512 ? 8 : (HasAVX ? 4 : 2))
3325f757f3fSDimitry Andric       .widenScalarToNextPow2(0, /*Min=*/32)
3335f757f3fSDimitry Andric       .clampScalar(0, s8, sMaxScalar)
3345f757f3fSDimitry Andric       .scalarize(0);
3355f757f3fSDimitry Andric 
3365f757f3fSDimitry Andric   getActionDefinitionsBuilder(G_BRCOND).legalFor({s1});
3375f757f3fSDimitry Andric 
3385f757f3fSDimitry Andric   // pointer handling
3395f757f3fSDimitry Andric   const std::initializer_list<LLT> PtrTypes32 = {s1, s8, s16, s32};
3405f757f3fSDimitry Andric   const std::initializer_list<LLT> PtrTypes64 = {s1, s8, s16, s32, s64};
3415f757f3fSDimitry Andric 
3425f757f3fSDimitry Andric   getActionDefinitionsBuilder(G_PTRTOINT)
3435f757f3fSDimitry Andric       .legalForCartesianProduct(Is64Bit ? PtrTypes64 : PtrTypes32, {p0})
3445f757f3fSDimitry Andric       .maxScalar(0, sMaxScalar)
3455f757f3fSDimitry Andric       .widenScalarToNextPow2(0, /*Min*/ 8);
3465f757f3fSDimitry Andric 
3475f757f3fSDimitry Andric   getActionDefinitionsBuilder(G_INTTOPTR).legalFor({{p0, sMaxScalar}});
3485f757f3fSDimitry Andric 
349*0fca6ea1SDimitry Andric   getActionDefinitionsBuilder(G_CONSTANT_POOL).legalFor({p0});
350*0fca6ea1SDimitry Andric 
3515f757f3fSDimitry Andric   getActionDefinitionsBuilder(G_PTR_ADD)
3525f757f3fSDimitry Andric       .legalIf([=](const LegalityQuery &Query) -> bool {
3535f757f3fSDimitry Andric         return typePairInSet(0, 1, {{p0, s32}})(Query) ||
3545f757f3fSDimitry Andric                (Is64Bit && typePairInSet(0, 1, {{p0, s64}})(Query));
3555f757f3fSDimitry Andric       })
3565f757f3fSDimitry Andric       .widenScalarToNextPow2(1, /*Min*/ 32)
3575f757f3fSDimitry Andric       .clampScalar(1, s32, sMaxScalar);
3585f757f3fSDimitry Andric 
3595f757f3fSDimitry Andric   getActionDefinitionsBuilder({G_FRAME_INDEX, G_GLOBAL_VALUE}).legalFor({p0});
3605f757f3fSDimitry Andric 
3615f757f3fSDimitry Andric   // load/store: add more corner cases
3625f757f3fSDimitry Andric   for (unsigned Op : {G_LOAD, G_STORE}) {
3635f757f3fSDimitry Andric     auto &Action = getActionDefinitionsBuilder(Op);
3645f757f3fSDimitry Andric     Action.legalForTypesWithMemDesc({{s8, p0, s1, 1},
3655f757f3fSDimitry Andric                                      {s8, p0, s8, 1},
3665f757f3fSDimitry Andric                                      {s16, p0, s8, 1},
3675f757f3fSDimitry Andric                                      {s16, p0, s16, 1},
3685f757f3fSDimitry Andric                                      {s32, p0, s8, 1},
3695f757f3fSDimitry Andric                                      {s32, p0, s16, 1},
3705f757f3fSDimitry Andric                                      {s32, p0, s32, 1},
3715f757f3fSDimitry Andric                                      {s80, p0, s80, 1},
3725f757f3fSDimitry Andric                                      {p0, p0, p0, 1},
3735f757f3fSDimitry Andric                                      {v4s8, p0, v4s8, 1}});
3745f757f3fSDimitry Andric     if (Is64Bit)
3755f757f3fSDimitry Andric       Action.legalForTypesWithMemDesc({{s64, p0, s8, 1},
3765f757f3fSDimitry Andric                                        {s64, p0, s16, 1},
3775f757f3fSDimitry Andric                                        {s64, p0, s32, 1},
3785f757f3fSDimitry Andric                                        {s64, p0, s64, 1},
3795f757f3fSDimitry Andric                                        {v2s32, p0, v2s32, 1}});
3805f757f3fSDimitry Andric     if (HasSSE1)
381*0fca6ea1SDimitry Andric       Action.legalForTypesWithMemDesc({{v4s32, p0, v4s32, 1}});
382*0fca6ea1SDimitry Andric     if (HasSSE2)
3835f757f3fSDimitry Andric       Action.legalForTypesWithMemDesc({{v16s8, p0, v16s8, 1},
3845f757f3fSDimitry Andric                                        {v8s16, p0, v8s16, 1},
3855f757f3fSDimitry Andric                                        {v2s64, p0, v2s64, 1},
3865f757f3fSDimitry Andric                                        {v2p0, p0, v2p0, 1}});
3875f757f3fSDimitry Andric     if (HasAVX)
3885f757f3fSDimitry Andric       Action.legalForTypesWithMemDesc({{v32s8, p0, v32s8, 1},
3895f757f3fSDimitry Andric                                        {v16s16, p0, v16s16, 1},
3905f757f3fSDimitry Andric                                        {v8s32, p0, v8s32, 1},
3915f757f3fSDimitry Andric                                        {v4s64, p0, v4s64, 1},
3925f757f3fSDimitry Andric                                        {v4p0, p0, v4p0, 1}});
3935f757f3fSDimitry Andric     if (HasAVX512)
3945f757f3fSDimitry Andric       Action.legalForTypesWithMemDesc({{v64s8, p0, v64s8, 1},
3955f757f3fSDimitry Andric                                        {v32s16, p0, v32s16, 1},
3965f757f3fSDimitry Andric                                        {v16s32, p0, v16s32, 1},
3975f757f3fSDimitry Andric                                        {v8s64, p0, v8s64, 1}});
398*0fca6ea1SDimitry Andric     Action.widenScalarToNextPow2(0, /*Min=*/8)
399*0fca6ea1SDimitry Andric         .clampScalar(0, s8, sMaxScalar)
400*0fca6ea1SDimitry Andric         .scalarize(0);
4015f757f3fSDimitry Andric   }
4025f757f3fSDimitry Andric 
4035f757f3fSDimitry Andric   for (unsigned Op : {G_SEXTLOAD, G_ZEXTLOAD}) {
4045f757f3fSDimitry Andric     auto &Action = getActionDefinitionsBuilder(Op);
4055f757f3fSDimitry Andric     Action.legalForTypesWithMemDesc({{s16, p0, s8, 1},
4065f757f3fSDimitry Andric                                      {s32, p0, s8, 1},
4075f757f3fSDimitry Andric                                      {s32, p0, s16, 1}});
4085f757f3fSDimitry Andric     if (Is64Bit)
4095f757f3fSDimitry Andric       Action.legalForTypesWithMemDesc({{s64, p0, s8, 1},
4105f757f3fSDimitry Andric                                        {s64, p0, s16, 1},
4115f757f3fSDimitry Andric                                        {s64, p0, s32, 1}});
4125f757f3fSDimitry Andric     // TODO - SSE41/AVX2/AVX512F/AVX512BW vector extensions
4135f757f3fSDimitry Andric   }
4145f757f3fSDimitry Andric 
4155f757f3fSDimitry Andric   // sext, zext, and anyext
4165f757f3fSDimitry Andric   getActionDefinitionsBuilder({G_SEXT, G_ZEXT, G_ANYEXT})
4175f757f3fSDimitry Andric       .legalIf([=](const LegalityQuery &Query) {
4185f757f3fSDimitry Andric         return typeInSet(0, {s8, s16, s32})(Query) ||
4195f757f3fSDimitry Andric           (Query.Opcode == G_ANYEXT && Query.Types[0] == s128) ||
4205f757f3fSDimitry Andric           (Is64Bit && Query.Types[0] == s64);
4215f757f3fSDimitry Andric       })
4225f757f3fSDimitry Andric       .widenScalarToNextPow2(0, /*Min=*/8)
4235f757f3fSDimitry Andric       .clampScalar(0, s8, sMaxScalar)
4245f757f3fSDimitry Andric       .widenScalarToNextPow2(1, /*Min=*/8)
425*0fca6ea1SDimitry Andric       .clampScalar(1, s8, sMaxScalar)
426*0fca6ea1SDimitry Andric       .scalarize(0);
4275f757f3fSDimitry Andric 
4285f757f3fSDimitry Andric   getActionDefinitionsBuilder(G_SEXT_INREG).lower();
4295f757f3fSDimitry Andric 
4305f757f3fSDimitry Andric   // fp constants
4315f757f3fSDimitry Andric   getActionDefinitionsBuilder(G_FCONSTANT)
4325f757f3fSDimitry Andric       .legalIf([=](const LegalityQuery &Query) -> bool {
433*0fca6ea1SDimitry Andric         return (typeInSet(0, {s32, s64})(Query)) ||
434*0fca6ea1SDimitry Andric                (UseX87 && typeInSet(0, {s80})(Query));
4355f757f3fSDimitry Andric       });
4365f757f3fSDimitry Andric 
4375f757f3fSDimitry Andric   // fp arithmetic
4385f757f3fSDimitry Andric   getActionDefinitionsBuilder({G_FADD, G_FSUB, G_FMUL, G_FDIV})
4395f757f3fSDimitry Andric       .legalIf([=](const LegalityQuery &Query) {
440*0fca6ea1SDimitry Andric         return (typeInSet(0, {s32, s64})(Query)) ||
441*0fca6ea1SDimitry Andric                (HasSSE1 && typeInSet(0, {v4s32})(Query)) ||
442*0fca6ea1SDimitry Andric                (HasSSE2 && typeInSet(0, {v2s64})(Query)) ||
4435f757f3fSDimitry Andric                (HasAVX && typeInSet(0, {v8s32, v4s64})(Query)) ||
444*0fca6ea1SDimitry Andric                (HasAVX512 && typeInSet(0, {v16s32, v8s64})(Query)) ||
445*0fca6ea1SDimitry Andric                (UseX87 && typeInSet(0, {s80})(Query));
4465f757f3fSDimitry Andric       });
4475f757f3fSDimitry Andric 
4485f757f3fSDimitry Andric   // fp comparison
4495f757f3fSDimitry Andric   getActionDefinitionsBuilder(G_FCMP)
4505f757f3fSDimitry Andric       .legalIf([=](const LegalityQuery &Query) {
4515f757f3fSDimitry Andric         return (HasSSE1 && typePairInSet(0, 1, {{s8, s32}})(Query)) ||
4525f757f3fSDimitry Andric                (HasSSE2 && typePairInSet(0, 1, {{s8, s64}})(Query));
4535f757f3fSDimitry Andric       })
4545f757f3fSDimitry Andric       .clampScalar(0, s8, s8)
4555f757f3fSDimitry Andric       .clampScalar(1, s32, HasSSE2 ? s64 : s32)
4565f757f3fSDimitry Andric       .widenScalarToNextPow2(1);
4575f757f3fSDimitry Andric 
4585f757f3fSDimitry Andric   // fp conversions
4595f757f3fSDimitry Andric   getActionDefinitionsBuilder(G_FPEXT).legalIf([=](const LegalityQuery &Query) {
4605f757f3fSDimitry Andric     return (HasSSE2 && typePairInSet(0, 1, {{s64, s32}})(Query)) ||
4615f757f3fSDimitry Andric            (HasAVX && typePairInSet(0, 1, {{v4s64, v4s32}})(Query)) ||
4625f757f3fSDimitry Andric            (HasAVX512 && typePairInSet(0, 1, {{v8s64, v8s32}})(Query));
4635f757f3fSDimitry Andric   });
4645f757f3fSDimitry Andric 
4655f757f3fSDimitry Andric   getActionDefinitionsBuilder(G_FPTRUNC).legalIf(
4665f757f3fSDimitry Andric       [=](const LegalityQuery &Query) {
4675f757f3fSDimitry Andric         return (HasSSE2 && typePairInSet(0, 1, {{s32, s64}})(Query)) ||
4685f757f3fSDimitry Andric                (HasAVX && typePairInSet(0, 1, {{v4s32, v4s64}})(Query)) ||
4695f757f3fSDimitry Andric                (HasAVX512 && typePairInSet(0, 1, {{v8s32, v8s64}})(Query));
4705f757f3fSDimitry Andric       });
4715f757f3fSDimitry Andric 
4725f757f3fSDimitry Andric   getActionDefinitionsBuilder(G_SITOFP)
4735f757f3fSDimitry Andric       .legalIf([=](const LegalityQuery &Query) {
4745f757f3fSDimitry Andric         return (HasSSE1 &&
4755f757f3fSDimitry Andric                 (typePairInSet(0, 1, {{s32, s32}})(Query) ||
4765f757f3fSDimitry Andric                  (Is64Bit && typePairInSet(0, 1, {{s32, s64}})(Query)))) ||
4775f757f3fSDimitry Andric                (HasSSE2 &&
4785f757f3fSDimitry Andric                 (typePairInSet(0, 1, {{s64, s32}})(Query) ||
4795f757f3fSDimitry Andric                  (Is64Bit && typePairInSet(0, 1, {{s64, s64}})(Query))));
4805f757f3fSDimitry Andric       })
4815f757f3fSDimitry Andric       .clampScalar(1, s32, sMaxScalar)
4825f757f3fSDimitry Andric       .widenScalarToNextPow2(1)
4835f757f3fSDimitry Andric       .clampScalar(0, s32, HasSSE2 ? s64 : s32)
4845f757f3fSDimitry Andric       .widenScalarToNextPow2(0);
4855f757f3fSDimitry Andric 
4865f757f3fSDimitry Andric   getActionDefinitionsBuilder(G_FPTOSI)
4875f757f3fSDimitry Andric       .legalIf([=](const LegalityQuery &Query) {
4885f757f3fSDimitry Andric         return (HasSSE1 &&
4895f757f3fSDimitry Andric                 (typePairInSet(0, 1, {{s32, s32}})(Query) ||
4905f757f3fSDimitry Andric                  (Is64Bit && typePairInSet(0, 1, {{s64, s32}})(Query)))) ||
4915f757f3fSDimitry Andric                (HasSSE2 &&
4925f757f3fSDimitry Andric                 (typePairInSet(0, 1, {{s32, s64}})(Query) ||
4935f757f3fSDimitry Andric                  (Is64Bit && typePairInSet(0, 1, {{s64, s64}})(Query))));
4945f757f3fSDimitry Andric       })
4955f757f3fSDimitry Andric       .clampScalar(1, s32, HasSSE2 ? s64 : s32)
4965f757f3fSDimitry Andric       .widenScalarToNextPow2(0)
4975f757f3fSDimitry Andric       .clampScalar(0, s32, sMaxScalar)
4985f757f3fSDimitry Andric       .widenScalarToNextPow2(1);
4995f757f3fSDimitry Andric 
5005f757f3fSDimitry Andric   // vector ops
501*0fca6ea1SDimitry Andric   getActionDefinitionsBuilder(G_BUILD_VECTOR)
502*0fca6ea1SDimitry Andric       .customIf([=](const LegalityQuery &Query) {
503*0fca6ea1SDimitry Andric         return (HasSSE1 && typeInSet(0, {v4s32})(Query)) ||
504*0fca6ea1SDimitry Andric                (HasSSE2 && typeInSet(0, {v2s64, v8s16, v16s8})(Query)) ||
505*0fca6ea1SDimitry Andric                (HasAVX && typeInSet(0, {v4s64, v8s32, v16s16, v32s8})(Query)) ||
506*0fca6ea1SDimitry Andric                (HasAVX512 && typeInSet(0, {v8s64, v16s32, v32s16, v64s8}));
507*0fca6ea1SDimitry Andric       })
508*0fca6ea1SDimitry Andric       .clampNumElements(0, v16s8, s8MaxVector)
509*0fca6ea1SDimitry Andric       .clampNumElements(0, v8s16, s16MaxVector)
510*0fca6ea1SDimitry Andric       .clampNumElements(0, v4s32, s32MaxVector)
511*0fca6ea1SDimitry Andric       .clampNumElements(0, v2s64, s64MaxVector)
512*0fca6ea1SDimitry Andric       .moreElementsToNextPow2(0);
513*0fca6ea1SDimitry Andric 
5145f757f3fSDimitry Andric   getActionDefinitionsBuilder({G_EXTRACT, G_INSERT})
5155f757f3fSDimitry Andric       .legalIf([=](const LegalityQuery &Query) {
5165f757f3fSDimitry Andric         unsigned SubIdx = Query.Opcode == G_EXTRACT ? 0 : 1;
5175f757f3fSDimitry Andric         unsigned FullIdx = Query.Opcode == G_EXTRACT ? 1 : 0;
5185f757f3fSDimitry Andric         return (HasAVX && typePairInSet(SubIdx, FullIdx,
5195f757f3fSDimitry Andric                                         {{v16s8, v32s8},
5205f757f3fSDimitry Andric                                          {v8s16, v16s16},
5215f757f3fSDimitry Andric                                          {v4s32, v8s32},
5225f757f3fSDimitry Andric                                          {v2s64, v4s64}})(Query)) ||
5235f757f3fSDimitry Andric                (HasAVX512 && typePairInSet(SubIdx, FullIdx,
5245f757f3fSDimitry Andric                                            {{v16s8, v64s8},
5255f757f3fSDimitry Andric                                             {v32s8, v64s8},
5265f757f3fSDimitry Andric                                             {v8s16, v32s16},
5275f757f3fSDimitry Andric                                             {v16s16, v32s16},
5285f757f3fSDimitry Andric                                             {v4s32, v16s32},
5295f757f3fSDimitry Andric                                             {v8s32, v16s32},
5305f757f3fSDimitry Andric                                             {v2s64, v8s64},
5315f757f3fSDimitry Andric                                             {v4s64, v8s64}})(Query));
5325f757f3fSDimitry Andric       });
5335f757f3fSDimitry Andric 
5345f757f3fSDimitry Andric   // todo: only permit dst types up to max legal vector register size?
5355f757f3fSDimitry Andric   getActionDefinitionsBuilder(G_CONCAT_VECTORS)
5365f757f3fSDimitry Andric       .legalIf([=](const LegalityQuery &Query) {
5375f757f3fSDimitry Andric         return (HasSSE1 && typePairInSet(1, 0,
5385f757f3fSDimitry Andric                                          {{v16s8, v32s8},
5395f757f3fSDimitry Andric                                           {v8s16, v16s16},
5405f757f3fSDimitry Andric                                           {v4s32, v8s32},
5415f757f3fSDimitry Andric                                           {v2s64, v4s64}})(Query)) ||
5425f757f3fSDimitry Andric                (HasAVX && typePairInSet(1, 0,
5435f757f3fSDimitry Andric                                         {{v16s8, v64s8},
5445f757f3fSDimitry Andric                                          {v32s8, v64s8},
5455f757f3fSDimitry Andric                                          {v8s16, v32s16},
5465f757f3fSDimitry Andric                                          {v16s16, v32s16},
5475f757f3fSDimitry Andric                                          {v4s32, v16s32},
5485f757f3fSDimitry Andric                                          {v8s32, v16s32},
5495f757f3fSDimitry Andric                                          {v2s64, v8s64},
5505f757f3fSDimitry Andric                                          {v4s64, v8s64}})(Query));
5515f757f3fSDimitry Andric       });
5525f757f3fSDimitry Andric 
5535f757f3fSDimitry Andric   // todo: vectors and address spaces
5545f757f3fSDimitry Andric   getActionDefinitionsBuilder(G_SELECT)
5555f757f3fSDimitry Andric       .legalFor({{s8, s32}, {s16, s32}, {s32, s32}, {s64, s32}, {p0, s32}})
5565f757f3fSDimitry Andric       .widenScalarToNextPow2(0, /*Min=*/8)
5575f757f3fSDimitry Andric       .clampScalar(0, HasCMOV ? s16 : s8, sMaxScalar)
5585f757f3fSDimitry Andric       .clampScalar(1, s32, s32);
5595f757f3fSDimitry Andric 
5605f757f3fSDimitry Andric   // memory intrinsics
5615f757f3fSDimitry Andric   getActionDefinitionsBuilder({G_MEMCPY, G_MEMMOVE, G_MEMSET}).libcall();
5625f757f3fSDimitry Andric 
5635f757f3fSDimitry Andric   getActionDefinitionsBuilder({G_DYN_STACKALLOC,
5645f757f3fSDimitry Andric                                G_STACKSAVE,
5655f757f3fSDimitry Andric                                G_STACKRESTORE}).lower();
5665f757f3fSDimitry Andric 
5675f757f3fSDimitry Andric   // fp intrinsics
5685f757f3fSDimitry Andric   getActionDefinitionsBuilder(G_INTRINSIC_ROUNDEVEN)
5695f757f3fSDimitry Andric       .scalarize(0)
5705f757f3fSDimitry Andric       .minScalar(0, LLT::scalar(32))
5715f757f3fSDimitry Andric       .libcall();
5725f757f3fSDimitry Andric 
5735f757f3fSDimitry Andric   getActionDefinitionsBuilder({G_FREEZE, G_CONSTANT_FOLD_BARRIER})
5745f757f3fSDimitry Andric     .legalFor({s8, s16, s32, s64, p0})
5755f757f3fSDimitry Andric     .widenScalarToNextPow2(0, /*Min=*/8)
5765f757f3fSDimitry Andric     .clampScalar(0, s8, sMaxScalar);
5775f757f3fSDimitry Andric 
5785f757f3fSDimitry Andric   getLegacyLegalizerInfo().computeTables();
5795f757f3fSDimitry Andric   verify(*STI.getInstrInfo());
5805f757f3fSDimitry Andric }
5815f757f3fSDimitry Andric 
582*0fca6ea1SDimitry Andric bool X86LegalizerInfo::legalizeCustom(LegalizerHelper &Helper, MachineInstr &MI,
583*0fca6ea1SDimitry Andric                                       LostDebugLocObserver &LocObserver) const {
584*0fca6ea1SDimitry Andric   MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
585*0fca6ea1SDimitry Andric   MachineRegisterInfo &MRI = *MIRBuilder.getMRI();
586*0fca6ea1SDimitry Andric   switch (MI.getOpcode()) {
587*0fca6ea1SDimitry Andric   default:
588*0fca6ea1SDimitry Andric     // No idea what to do.
589*0fca6ea1SDimitry Andric     return false;
590*0fca6ea1SDimitry Andric   case TargetOpcode::G_BUILD_VECTOR:
591*0fca6ea1SDimitry Andric     return legalizeBuildVector(MI, MRI, Helper);
592*0fca6ea1SDimitry Andric   }
593*0fca6ea1SDimitry Andric   llvm_unreachable("expected switch to return");
594*0fca6ea1SDimitry Andric }
595*0fca6ea1SDimitry Andric 
596*0fca6ea1SDimitry Andric bool X86LegalizerInfo::legalizeBuildVector(MachineInstr &MI,
597*0fca6ea1SDimitry Andric                                            MachineRegisterInfo &MRI,
598*0fca6ea1SDimitry Andric                                            LegalizerHelper &Helper) const {
599*0fca6ea1SDimitry Andric   MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
600*0fca6ea1SDimitry Andric   const auto &BuildVector = cast<GBuildVector>(MI);
601*0fca6ea1SDimitry Andric   Register Dst = BuildVector.getReg(0);
602*0fca6ea1SDimitry Andric   LLT DstTy = MRI.getType(Dst);
603*0fca6ea1SDimitry Andric   MachineFunction &MF = MIRBuilder.getMF();
604*0fca6ea1SDimitry Andric   LLVMContext &Ctx = MF.getFunction().getContext();
605*0fca6ea1SDimitry Andric   uint64_t DstTySize = DstTy.getScalarSizeInBits();
606*0fca6ea1SDimitry Andric 
607*0fca6ea1SDimitry Andric   SmallVector<Constant *, 4> CstIdxs;
608*0fca6ea1SDimitry Andric   for (unsigned i = 0; i < BuildVector.getNumSources(); ++i) {
609*0fca6ea1SDimitry Andric     Register Source = BuildVector.getSourceReg(i);
610*0fca6ea1SDimitry Andric 
611*0fca6ea1SDimitry Andric     auto ValueAndReg = getIConstantVRegValWithLookThrough(Source, MRI);
612*0fca6ea1SDimitry Andric     if (ValueAndReg) {
613*0fca6ea1SDimitry Andric       CstIdxs.emplace_back(ConstantInt::get(Ctx, ValueAndReg->Value));
614*0fca6ea1SDimitry Andric       continue;
615*0fca6ea1SDimitry Andric     }
616*0fca6ea1SDimitry Andric 
617*0fca6ea1SDimitry Andric     auto FPValueAndReg = getFConstantVRegValWithLookThrough(Source, MRI);
618*0fca6ea1SDimitry Andric     if (FPValueAndReg) {
619*0fca6ea1SDimitry Andric       CstIdxs.emplace_back(ConstantFP::get(Ctx, FPValueAndReg->Value));
620*0fca6ea1SDimitry Andric       continue;
621*0fca6ea1SDimitry Andric     }
622*0fca6ea1SDimitry Andric 
623*0fca6ea1SDimitry Andric     if (getOpcodeDef<GImplicitDef>(Source, MRI)) {
624*0fca6ea1SDimitry Andric       CstIdxs.emplace_back(UndefValue::get(Type::getIntNTy(Ctx, DstTySize)));
625*0fca6ea1SDimitry Andric       continue;
626*0fca6ea1SDimitry Andric     }
627*0fca6ea1SDimitry Andric     return false;
628*0fca6ea1SDimitry Andric   }
629*0fca6ea1SDimitry Andric 
630*0fca6ea1SDimitry Andric   Constant *ConstVal = ConstantVector::get(CstIdxs);
631*0fca6ea1SDimitry Andric 
632*0fca6ea1SDimitry Andric   const DataLayout &DL = MIRBuilder.getDataLayout();
633*0fca6ea1SDimitry Andric   unsigned AddrSpace = DL.getDefaultGlobalsAddressSpace();
634*0fca6ea1SDimitry Andric   Align Alignment(DL.getABITypeAlign(ConstVal->getType()));
635*0fca6ea1SDimitry Andric   auto Addr = MIRBuilder.buildConstantPool(
636*0fca6ea1SDimitry Andric       LLT::pointer(AddrSpace, DL.getPointerSizeInBits(AddrSpace)),
637*0fca6ea1SDimitry Andric       MF.getConstantPool()->getConstantPoolIndex(ConstVal, Alignment));
638*0fca6ea1SDimitry Andric   MachineMemOperand *MMO =
639*0fca6ea1SDimitry Andric       MF.getMachineMemOperand(MachinePointerInfo::getConstantPool(MF),
640*0fca6ea1SDimitry Andric                               MachineMemOperand::MOLoad, DstTy, Alignment);
641*0fca6ea1SDimitry Andric 
642*0fca6ea1SDimitry Andric   MIRBuilder.buildLoad(Dst, Addr, *MMO);
643*0fca6ea1SDimitry Andric   MI.eraseFromParent();
644*0fca6ea1SDimitry Andric   return true;
645*0fca6ea1SDimitry Andric }
646*0fca6ea1SDimitry Andric 
6475f757f3fSDimitry Andric bool X86LegalizerInfo::legalizeIntrinsic(LegalizerHelper &Helper,
6485f757f3fSDimitry Andric                                          MachineInstr &MI) const {
6495f757f3fSDimitry Andric   return true;
6505f757f3fSDimitry Andric }
651