1 //===- X86LegalizerInfo.cpp --------------------------------------*- C++ -*-==// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 /// \file 9 /// This file implements the targeting of the Machinelegalizer class for X86. 10 /// \todo This should be generated by TableGen. 11 //===----------------------------------------------------------------------===// 12 13 #include "X86LegalizerInfo.h" 14 #include "X86Subtarget.h" 15 #include "X86TargetMachine.h" 16 #include "llvm/CodeGen/GlobalISel/LegalizerHelper.h" 17 #include "llvm/CodeGen/TargetOpcodes.h" 18 #include "llvm/CodeGen/ValueTypes.h" 19 #include "llvm/IR/DerivedTypes.h" 20 #include "llvm/IR/Type.h" 21 22 using namespace llvm; 23 using namespace TargetOpcode; 24 using namespace LegalizeActions; 25 using namespace LegalityPredicates; 26 27 X86LegalizerInfo::X86LegalizerInfo(const X86Subtarget &STI, 28 const X86TargetMachine &TM) 29 : Subtarget(STI) { 30 31 bool Is64Bit = Subtarget.is64Bit(); 32 bool HasCMOV = Subtarget.canUseCMOV(); 33 bool HasSSE1 = Subtarget.hasSSE1(); 34 bool HasSSE2 = Subtarget.hasSSE2(); 35 bool HasSSE41 = Subtarget.hasSSE41(); 36 bool HasAVX = Subtarget.hasAVX(); 37 bool HasAVX2 = Subtarget.hasAVX2(); 38 bool HasAVX512 = Subtarget.hasAVX512(); 39 bool HasVLX = Subtarget.hasVLX(); 40 bool HasDQI = Subtarget.hasAVX512() && Subtarget.hasDQI(); 41 bool HasBWI = Subtarget.hasAVX512() && Subtarget.hasBWI(); 42 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); 54 55 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); 61 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); 67 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); 72 73 // todo: AVX512 bool vector predicate types 74 75 // implicit/constants 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)); 83 }); 84 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)); 89 }) 90 .widenScalarToNextPow2(0, /*Min=*/8) 91 .clampScalar(0, s8, sMaxScalar); 92 93 // merge/unmerge 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()) { 104 case 16: 105 case 32: 106 case 64: 107 case 128: 108 case 256: 109 case 512: 110 break; 111 default: 112 return false; 113 } 114 switch (Q.Types[LitTyIdx].getSizeInBits()) { 115 case 8: 116 case 16: 117 case 32: 118 case 64: 119 case 128: 120 case 256: 121 return true; 122 default: 123 return false; 124 } 125 }); 126 } 127 128 // integer addition/subtraction 129 getActionDefinitionsBuilder({G_ADD, G_SUB}) 130 .legalIf([=](const LegalityQuery &Query) -> bool { 131 if (typeInSet(0, {s8, s16, s32})(Query)) 132 return true; 133 if (Is64Bit && typeInSet(0, {s64})(Query)) 134 return true; 135 if (HasSSE2 && typeInSet(0, {v16s8, v8s16, v4s32, v2s64})(Query)) 136 return true; 137 if (HasAVX2 && typeInSet(0, {v32s8, v16s16, v8s32, v4s64})(Query)) 138 return true; 139 if (HasAVX512 && typeInSet(0, {v16s32, v8s64})(Query)) 140 return true; 141 if (HasBWI && typeInSet(0, {v64s8, v32s16})(Query)) 142 return true; 143 return false; 144 }) 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) 155 .scalarize(0); 156 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)); 161 }) 162 .widenScalarToNextPow2(0, /*Min=*/32) 163 .clampScalar(0, s8, sMaxScalar) 164 .clampScalar(1, s1, s1) 165 .scalarize(0); 166 167 // integer multiply 168 getActionDefinitionsBuilder(G_MUL) 169 .legalIf([=](const LegalityQuery &Query) -> bool { 170 if (typeInSet(0, {s8, s16, s32})(Query)) 171 return true; 172 if (Is64Bit && typeInSet(0, {s64})(Query)) 173 return true; 174 if (HasSSE2 && typeInSet(0, {v8s16})(Query)) 175 return true; 176 if (HasSSE41 && typeInSet(0, {v4s32})(Query)) 177 return true; 178 if (HasAVX2 && typeInSet(0, {v16s16, v8s32})(Query)) 179 return true; 180 if (HasAVX512 && typeInSet(0, {v16s32})(Query)) 181 return true; 182 if (HasDQI && typeInSet(0, {v8s64})(Query)) 183 return true; 184 if (HasDQI && HasVLX && typeInSet(0, {v2s64, v4s64})(Query)) 185 return true; 186 if (HasBWI && typeInSet(0, {v32s16})(Query)) 187 return true; 188 return false; 189 }) 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) 198 .scalarize(0); 199 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)); 204 }) 205 .widenScalarToNextPow2(0, /*Min=*/32) 206 .clampScalar(0, s8, sMaxScalar) 207 .scalarize(0); 208 209 // integer divisions 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)); 214 }) 215 .clampScalar(0, s8, sMaxScalar); 216 217 // integer shifts 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)); 222 }) 223 .clampScalar(0, s8, sMaxScalar) 224 .clampScalar(1, s8, s8); 225 226 // integer logic 227 getActionDefinitionsBuilder({G_AND, G_OR, G_XOR}) 228 .legalIf([=](const LegalityQuery &Query) -> bool { 229 if (typeInSet(0, {s8, s16, s32})(Query)) 230 return true; 231 if (Is64Bit && typeInSet(0, {s64})(Query)) 232 return true; 233 if (HasSSE2 && typeInSet(0, {v16s8, v8s16, v4s32, v2s64})(Query)) 234 return true; 235 if (HasAVX && typeInSet(0, {v32s8, v16s16, v8s32, v4s64})(Query)) 236 return true; 237 if (HasAVX512 && typeInSet(0, {v64s8, v32s16, v16s32, v8s64})(Query)) 238 return true; 239 return false; 240 }) 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) 251 .scalarize(0); 252 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}; 256 257 getActionDefinitionsBuilder(G_ICMP) 258 .legalForCartesianProduct({s8}, Is64Bit ? IntTypes64 : IntTypes32) 259 .clampScalar(0, s8, s8) 260 .clampScalar(1, s8, sMaxScalar) 261 .scalarSameSizeAs(2, 1); 262 263 // bswap 264 getActionDefinitionsBuilder(G_BSWAP) 265 .legalIf([=](const LegalityQuery &Query) { 266 return Query.Types[0] == s32 || 267 (Subtarget.is64Bit() && Query.Types[0] == s64); 268 }) 269 .widenScalarToNextPow2(0, /*Min=*/32) 270 .clampScalar(0, s32, sMaxScalar); 271 272 // popcount 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))); 278 }) 279 .widenScalarToNextPow2(1, /*Min=*/16) 280 .clampScalar(1, s16, sMaxScalar) 281 .scalarSameSizeAs(0, 1); 282 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))); 289 }) 290 .widenScalarToNextPow2(1, /*Min=*/16) 291 .clampScalar(1, s16, sMaxScalar) 292 .scalarSameSizeAs(0, 1); 293 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))); 300 }) 301 .widenScalarToNextPow2(1, /*Min=*/16) 302 .clampScalar(1, s16, sMaxScalar) 303 .scalarSameSizeAs(0, 1); 304 305 // control flow 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)) || 312 (HasAVX512 && 313 typeInSet(0, {v64s8, v32s16, v16s32, v8s64})(Query)); 314 }) 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) 325 .scalarize(0); 326 327 getActionDefinitionsBuilder(G_BRCOND).legalFor({s1}); 328 329 // pointer handling 330 const std::initializer_list<LLT> PtrTypes32 = {s1, s8, s16, s32}; 331 const std::initializer_list<LLT> PtrTypes64 = {s1, s8, s16, s32, s64}; 332 333 getActionDefinitionsBuilder(G_PTRTOINT) 334 .legalForCartesianProduct(Is64Bit ? PtrTypes64 : PtrTypes32, {p0}) 335 .maxScalar(0, sMaxScalar) 336 .widenScalarToNextPow2(0, /*Min*/ 8); 337 338 getActionDefinitionsBuilder(G_INTTOPTR).legalFor({{p0, sMaxScalar}}); 339 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)); 344 }) 345 .widenScalarToNextPow2(1, /*Min*/ 32) 346 .clampScalar(1, s32, sMaxScalar); 347 348 getActionDefinitionsBuilder({G_FRAME_INDEX, G_GLOBAL_VALUE}).legalFor({p0}); 349 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}, 354 {s8, p0, s8, 1}, 355 {s16, p0, s8, 1}, 356 {s16, p0, s16, 1}, 357 {s32, p0, s8, 1}, 358 {s32, p0, s16, 1}, 359 {s32, p0, s32, 1}, 360 {s80, p0, s80, 1}, 361 {p0, p0, p0, 1}, 362 {v4s8, p0, v4s8, 1}}); 363 if (Is64Bit) 364 Action.legalForTypesWithMemDesc({{s64, p0, s8, 1}, 365 {s64, p0, s16, 1}, 366 {s64, p0, s32, 1}, 367 {s64, p0, s64, 1}, 368 {v2s32, p0, v2s32, 1}}); 369 if (HasSSE1) 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}}); 375 if (HasAVX) 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}}); 381 if (HasAVX512) 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); 387 } 388 389 for (unsigned Op : {G_SEXTLOAD, G_ZEXTLOAD}) { 390 auto &Action = getActionDefinitionsBuilder(Op); 391 Action.legalForTypesWithMemDesc({{s16, p0, s8, 1}, 392 {s32, p0, s8, 1}, 393 {s32, p0, s16, 1}}); 394 if (Is64Bit) 395 Action.legalForTypesWithMemDesc({{s64, p0, s8, 1}, 396 {s64, p0, s16, 1}, 397 {s64, p0, s32, 1}}); 398 // TODO - SSE41/AVX2/AVX512F/AVX512BW vector extensions 399 } 400 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); 407 }) 408 .widenScalarToNextPow2(0, /*Min=*/8) 409 .clampScalar(0, s8, sMaxScalar) 410 .widenScalarToNextPow2(1, /*Min=*/8) 411 .clampScalar(1, s8, sMaxScalar); 412 413 getActionDefinitionsBuilder(G_SEXT_INREG).lower(); 414 415 // fp constants 416 getActionDefinitionsBuilder(G_FCONSTANT) 417 .legalIf([=](const LegalityQuery &Query) -> bool { 418 return (HasSSE1 && typeInSet(0, {s32})(Query)) || 419 (HasSSE2 && typeInSet(0, {s64})(Query)); 420 }); 421 422 // fp arithmetic 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)); 429 }); 430 431 // fp comparison 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)); 436 }) 437 .clampScalar(0, s8, s8) 438 .clampScalar(1, s32, HasSSE2 ? s64 : s32) 439 .widenScalarToNextPow2(1); 440 441 // fp conversions 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)); 446 }); 447 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)); 453 }); 454 455 getActionDefinitionsBuilder(G_SITOFP) 456 .legalIf([=](const LegalityQuery &Query) { 457 return (HasSSE1 && 458 (typePairInSet(0, 1, {{s32, s32}})(Query) || 459 (Is64Bit && typePairInSet(0, 1, {{s32, s64}})(Query)))) || 460 (HasSSE2 && 461 (typePairInSet(0, 1, {{s64, s32}})(Query) || 462 (Is64Bit && typePairInSet(0, 1, {{s64, s64}})(Query)))); 463 }) 464 .clampScalar(1, s32, sMaxScalar) 465 .widenScalarToNextPow2(1) 466 .clampScalar(0, s32, HasSSE2 ? s64 : s32) 467 .widenScalarToNextPow2(0); 468 469 getActionDefinitionsBuilder(G_FPTOSI) 470 .legalIf([=](const LegalityQuery &Query) { 471 return (HasSSE1 && 472 (typePairInSet(0, 1, {{s32, s32}})(Query) || 473 (Is64Bit && typePairInSet(0, 1, {{s64, s32}})(Query)))) || 474 (HasSSE2 && 475 (typePairInSet(0, 1, {{s32, s64}})(Query) || 476 (Is64Bit && typePairInSet(0, 1, {{s64, s64}})(Query)))); 477 }) 478 .clampScalar(1, s32, HasSSE2 ? s64 : s32) 479 .widenScalarToNextPow2(0) 480 .clampScalar(0, s32, sMaxScalar) 481 .widenScalarToNextPow2(1); 482 483 // vector ops 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, 489 {{v16s8, v32s8}, 490 {v8s16, v16s16}, 491 {v4s32, v8s32}, 492 {v2s64, v4s64}})(Query)) || 493 (HasAVX512 && typePairInSet(SubIdx, FullIdx, 494 {{v16s8, v64s8}, 495 {v32s8, v64s8}, 496 {v8s16, v32s16}, 497 {v16s16, v32s16}, 498 {v4s32, v16s32}, 499 {v8s32, v16s32}, 500 {v2s64, v8s64}, 501 {v4s64, v8s64}})(Query)); 502 }); 503 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, 508 {{v16s8, v32s8}, 509 {v8s16, v16s16}, 510 {v4s32, v8s32}, 511 {v2s64, v4s64}})(Query)) || 512 (HasAVX && typePairInSet(1, 0, 513 {{v16s8, v64s8}, 514 {v32s8, v64s8}, 515 {v8s16, v32s16}, 516 {v16s16, v32s16}, 517 {v4s32, v16s32}, 518 {v8s32, v16s32}, 519 {v2s64, v8s64}, 520 {v4s64, v8s64}})(Query)); 521 }); 522 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); 529 530 // memory intrinsics 531 getActionDefinitionsBuilder({G_MEMCPY, G_MEMMOVE, G_MEMSET}).libcall(); 532 533 getActionDefinitionsBuilder({G_DYN_STACKALLOC, 534 G_STACKSAVE, 535 G_STACKRESTORE}).lower(); 536 537 // fp intrinsics 538 getActionDefinitionsBuilder(G_INTRINSIC_ROUNDEVEN) 539 .scalarize(0) 540 .minScalar(0, LLT::scalar(32)) 541 .libcall(); 542 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); 547 548 getLegacyLegalizerInfo().computeTables(); 549 verify(*STI.getInstrInfo()); 550 } 551 552 bool X86LegalizerInfo::legalizeIntrinsic(LegalizerHelper &Helper, 553 MachineInstr &MI) const { 554 return true; 555 } 556