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