1 //===- AMDGPULegalizerInfo.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 10 /// AMDGPU. 11 /// \todo This should be generated by TableGen. 12 //===----------------------------------------------------------------------===// 13 14 #if defined(_MSC_VER) || defined(__MINGW32__) 15 // According to Microsoft, one must set _USE_MATH_DEFINES in order to get M_PI 16 // from the Visual C++ cmath / math.h headers: 17 // https://docs.microsoft.com/en-us/cpp/c-runtime-library/math-constants?view=vs-2019 18 #define _USE_MATH_DEFINES 19 #endif 20 21 #include "AMDGPULegalizerInfo.h" 22 23 #include "AMDGPU.h" 24 #include "AMDGPUGlobalISelUtils.h" 25 #include "AMDGPUTargetMachine.h" 26 #include "SIMachineFunctionInfo.h" 27 #include "llvm/CodeGen/GlobalISel/LegalizerHelper.h" 28 #include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h" 29 #include "llvm/CodeGen/GlobalISel/MIPatternMatch.h" 30 #include "llvm/CodeGen/TargetOpcodes.h" 31 #include "llvm/CodeGen/ValueTypes.h" 32 #include "llvm/IR/DerivedTypes.h" 33 #include "llvm/IR/DiagnosticInfo.h" 34 #include "llvm/IR/Type.h" 35 #include "llvm/Support/Debug.h" 36 37 #define DEBUG_TYPE "amdgpu-legalinfo" 38 39 using namespace llvm; 40 using namespace LegalizeActions; 41 using namespace LegalizeMutations; 42 using namespace LegalityPredicates; 43 using namespace MIPatternMatch; 44 45 static LegalityPredicate isMultiple32(unsigned TypeIdx, 46 unsigned MaxSize = 1024) { 47 return [=](const LegalityQuery &Query) { 48 const LLT Ty = Query.Types[TypeIdx]; 49 const LLT EltTy = Ty.getScalarType(); 50 return Ty.getSizeInBits() <= MaxSize && EltTy.getSizeInBits() % 32 == 0; 51 }; 52 } 53 54 static LegalityPredicate sizeIs(unsigned TypeIdx, unsigned Size) { 55 return [=](const LegalityQuery &Query) { 56 return Query.Types[TypeIdx].getSizeInBits() == Size; 57 }; 58 } 59 60 static LegalityPredicate isSmallOddVector(unsigned TypeIdx) { 61 return [=](const LegalityQuery &Query) { 62 const LLT Ty = Query.Types[TypeIdx]; 63 return Ty.isVector() && 64 Ty.getNumElements() % 2 != 0 && 65 Ty.getElementType().getSizeInBits() < 32 && 66 Ty.getSizeInBits() % 32 != 0; 67 }; 68 } 69 70 static LegalityPredicate isWideVec16(unsigned TypeIdx) { 71 return [=](const LegalityQuery &Query) { 72 const LLT Ty = Query.Types[TypeIdx]; 73 const LLT EltTy = Ty.getScalarType(); 74 return EltTy.getSizeInBits() == 16 && Ty.getNumElements() > 2; 75 }; 76 } 77 78 static LegalizeMutation oneMoreElement(unsigned TypeIdx) { 79 return [=](const LegalityQuery &Query) { 80 const LLT Ty = Query.Types[TypeIdx]; 81 const LLT EltTy = Ty.getElementType(); 82 return std::make_pair(TypeIdx, LLT::vector(Ty.getNumElements() + 1, EltTy)); 83 }; 84 } 85 86 static LegalizeMutation fewerEltsToSize64Vector(unsigned TypeIdx) { 87 return [=](const LegalityQuery &Query) { 88 const LLT Ty = Query.Types[TypeIdx]; 89 const LLT EltTy = Ty.getElementType(); 90 unsigned Size = Ty.getSizeInBits(); 91 unsigned Pieces = (Size + 63) / 64; 92 unsigned NewNumElts = (Ty.getNumElements() + 1) / Pieces; 93 return std::make_pair(TypeIdx, LLT::scalarOrVector(NewNumElts, EltTy)); 94 }; 95 } 96 97 // Increase the number of vector elements to reach the next multiple of 32-bit 98 // type. 99 static LegalizeMutation moreEltsToNext32Bit(unsigned TypeIdx) { 100 return [=](const LegalityQuery &Query) { 101 const LLT Ty = Query.Types[TypeIdx]; 102 103 const LLT EltTy = Ty.getElementType(); 104 const int Size = Ty.getSizeInBits(); 105 const int EltSize = EltTy.getSizeInBits(); 106 const int NextMul32 = (Size + 31) / 32; 107 108 assert(EltSize < 32); 109 110 const int NewNumElts = (32 * NextMul32 + EltSize - 1) / EltSize; 111 return std::make_pair(TypeIdx, LLT::vector(NewNumElts, EltTy)); 112 }; 113 } 114 115 static LegalityPredicate vectorSmallerThan(unsigned TypeIdx, unsigned Size) { 116 return [=](const LegalityQuery &Query) { 117 const LLT QueryTy = Query.Types[TypeIdx]; 118 return QueryTy.isVector() && QueryTy.getSizeInBits() < Size; 119 }; 120 } 121 122 static LegalityPredicate vectorWiderThan(unsigned TypeIdx, unsigned Size) { 123 return [=](const LegalityQuery &Query) { 124 const LLT QueryTy = Query.Types[TypeIdx]; 125 return QueryTy.isVector() && QueryTy.getSizeInBits() > Size; 126 }; 127 } 128 129 static LegalityPredicate numElementsNotEven(unsigned TypeIdx) { 130 return [=](const LegalityQuery &Query) { 131 const LLT QueryTy = Query.Types[TypeIdx]; 132 return QueryTy.isVector() && QueryTy.getNumElements() % 2 != 0; 133 }; 134 } 135 136 // Any combination of 32 or 64-bit elements up to 1024 bits, and multiples of 137 // v2s16. 138 static LegalityPredicate isRegisterType(unsigned TypeIdx) { 139 return [=](const LegalityQuery &Query) { 140 const LLT Ty = Query.Types[TypeIdx]; 141 if (Ty.isVector()) { 142 const int EltSize = Ty.getElementType().getSizeInBits(); 143 return EltSize == 32 || EltSize == 64 || 144 (EltSize == 16 && Ty.getNumElements() % 2 == 0) || 145 EltSize == 128 || EltSize == 256; 146 } 147 148 return Ty.getSizeInBits() % 32 == 0 && Ty.getSizeInBits() <= 1024; 149 }; 150 } 151 152 static LegalityPredicate elementTypeIs(unsigned TypeIdx, LLT Type) { 153 return [=](const LegalityQuery &Query) { 154 const LLT QueryTy = Query.Types[TypeIdx]; 155 return QueryTy.isVector() && QueryTy.getElementType() == Type; 156 }; 157 } 158 159 static LegalityPredicate isWideScalarTruncStore(unsigned TypeIdx) { 160 return [=](const LegalityQuery &Query) { 161 const LLT Ty = Query.Types[TypeIdx]; 162 return !Ty.isVector() && Ty.getSizeInBits() > 32 && 163 Query.MMODescrs[0].SizeInBits < Ty.getSizeInBits(); 164 }; 165 } 166 167 AMDGPULegalizerInfo::AMDGPULegalizerInfo(const GCNSubtarget &ST_, 168 const GCNTargetMachine &TM) 169 : ST(ST_) { 170 using namespace TargetOpcode; 171 172 auto GetAddrSpacePtr = [&TM](unsigned AS) { 173 return LLT::pointer(AS, TM.getPointerSizeInBits(AS)); 174 }; 175 176 const LLT S1 = LLT::scalar(1); 177 const LLT S8 = LLT::scalar(8); 178 const LLT S16 = LLT::scalar(16); 179 const LLT S32 = LLT::scalar(32); 180 const LLT S64 = LLT::scalar(64); 181 const LLT S96 = LLT::scalar(96); 182 const LLT S128 = LLT::scalar(128); 183 const LLT S256 = LLT::scalar(256); 184 const LLT S1024 = LLT::scalar(1024); 185 186 const LLT V2S16 = LLT::vector(2, 16); 187 const LLT V4S16 = LLT::vector(4, 16); 188 189 const LLT V2S32 = LLT::vector(2, 32); 190 const LLT V3S32 = LLT::vector(3, 32); 191 const LLT V4S32 = LLT::vector(4, 32); 192 const LLT V5S32 = LLT::vector(5, 32); 193 const LLT V6S32 = LLT::vector(6, 32); 194 const LLT V7S32 = LLT::vector(7, 32); 195 const LLT V8S32 = LLT::vector(8, 32); 196 const LLT V9S32 = LLT::vector(9, 32); 197 const LLT V10S32 = LLT::vector(10, 32); 198 const LLT V11S32 = LLT::vector(11, 32); 199 const LLT V12S32 = LLT::vector(12, 32); 200 const LLT V13S32 = LLT::vector(13, 32); 201 const LLT V14S32 = LLT::vector(14, 32); 202 const LLT V15S32 = LLT::vector(15, 32); 203 const LLT V16S32 = LLT::vector(16, 32); 204 const LLT V32S32 = LLT::vector(32, 32); 205 206 const LLT V2S64 = LLT::vector(2, 64); 207 const LLT V3S64 = LLT::vector(3, 64); 208 const LLT V4S64 = LLT::vector(4, 64); 209 const LLT V5S64 = LLT::vector(5, 64); 210 const LLT V6S64 = LLT::vector(6, 64); 211 const LLT V7S64 = LLT::vector(7, 64); 212 const LLT V8S64 = LLT::vector(8, 64); 213 const LLT V16S64 = LLT::vector(16, 64); 214 215 std::initializer_list<LLT> AllS32Vectors = 216 {V2S32, V3S32, V4S32, V5S32, V6S32, V7S32, V8S32, 217 V9S32, V10S32, V11S32, V12S32, V13S32, V14S32, V15S32, V16S32, V32S32}; 218 std::initializer_list<LLT> AllS64Vectors = 219 {V2S64, V3S64, V4S64, V5S64, V6S64, V7S64, V8S64, V16S64}; 220 221 const LLT GlobalPtr = GetAddrSpacePtr(AMDGPUAS::GLOBAL_ADDRESS); 222 const LLT ConstantPtr = GetAddrSpacePtr(AMDGPUAS::CONSTANT_ADDRESS); 223 const LLT Constant32Ptr = GetAddrSpacePtr(AMDGPUAS::CONSTANT_ADDRESS_32BIT); 224 const LLT LocalPtr = GetAddrSpacePtr(AMDGPUAS::LOCAL_ADDRESS); 225 const LLT RegionPtr = GetAddrSpacePtr(AMDGPUAS::REGION_ADDRESS); 226 const LLT FlatPtr = GetAddrSpacePtr(AMDGPUAS::FLAT_ADDRESS); 227 const LLT PrivatePtr = GetAddrSpacePtr(AMDGPUAS::PRIVATE_ADDRESS); 228 229 const LLT CodePtr = FlatPtr; 230 231 const std::initializer_list<LLT> AddrSpaces64 = { 232 GlobalPtr, ConstantPtr, FlatPtr 233 }; 234 235 const std::initializer_list<LLT> AddrSpaces32 = { 236 LocalPtr, PrivatePtr, Constant32Ptr, RegionPtr 237 }; 238 239 const std::initializer_list<LLT> FPTypesBase = { 240 S32, S64 241 }; 242 243 const std::initializer_list<LLT> FPTypes16 = { 244 S32, S64, S16 245 }; 246 247 const std::initializer_list<LLT> FPTypesPK16 = { 248 S32, S64, S16, V2S16 249 }; 250 251 const LLT MinLegalScalarShiftTy = ST.has16BitInsts() ? S16 : S32; 252 253 setAction({G_BRCOND, S1}, Legal); // VCC branches 254 setAction({G_BRCOND, S32}, Legal); // SCC branches 255 256 // TODO: All multiples of 32, vectors of pointers, all v2s16 pairs, more 257 // elements for v3s16 258 getActionDefinitionsBuilder(G_PHI) 259 .legalFor({S32, S64, V2S16, V4S16, S1, S128, S256}) 260 .legalFor(AllS32Vectors) 261 .legalFor(AllS64Vectors) 262 .legalFor(AddrSpaces64) 263 .legalFor(AddrSpaces32) 264 .clampScalar(0, S32, S256) 265 .widenScalarToNextPow2(0, 32) 266 .clampMaxNumElements(0, S32, 16) 267 .moreElementsIf(isSmallOddVector(0), oneMoreElement(0)) 268 .legalIf(isPointer(0)); 269 270 if (ST.has16BitInsts()) { 271 getActionDefinitionsBuilder({G_ADD, G_SUB, G_MUL}) 272 .legalFor({S32, S16}) 273 .clampScalar(0, S16, S32) 274 .scalarize(0); 275 } else { 276 getActionDefinitionsBuilder({G_ADD, G_SUB, G_MUL}) 277 .legalFor({S32}) 278 .clampScalar(0, S32, S32) 279 .scalarize(0); 280 } 281 282 // FIXME: Not really legal. Placeholder for custom lowering. 283 getActionDefinitionsBuilder({G_SDIV, G_UDIV, G_SREM, G_UREM}) 284 .legalFor({S32, S64}) 285 .clampScalar(0, S32, S64) 286 .widenScalarToNextPow2(0, 32) 287 .scalarize(0); 288 289 getActionDefinitionsBuilder({G_UMULH, G_SMULH}) 290 .legalFor({S32}) 291 .clampScalar(0, S32, S32) 292 .scalarize(0); 293 294 // Report legal for any types we can handle anywhere. For the cases only legal 295 // on the SALU, RegBankSelect will be able to re-legalize. 296 getActionDefinitionsBuilder({G_AND, G_OR, G_XOR}) 297 .legalFor({S32, S1, S64, V2S32, S16, V2S16, V4S16}) 298 .clampScalar(0, S32, S64) 299 .moreElementsIf(isSmallOddVector(0), oneMoreElement(0)) 300 .fewerElementsIf(vectorWiderThan(0, 64), fewerEltsToSize64Vector(0)) 301 .widenScalarToNextPow2(0) 302 .scalarize(0); 303 304 getActionDefinitionsBuilder({G_UADDO, G_USUBO, 305 G_UADDE, G_SADDE, G_USUBE, G_SSUBE}) 306 .legalFor({{S32, S1}, {S32, S32}}) 307 .clampScalar(0, S32, S32) 308 .scalarize(0); // TODO: Implement. 309 310 getActionDefinitionsBuilder(G_BITCAST) 311 // Don't worry about the size constraint. 312 .legalIf(all(isRegisterType(0), isRegisterType(1))) 313 // FIXME: Testing hack 314 .legalForCartesianProduct({S16, LLT::vector(2, 8), }) 315 .lower(); 316 317 318 getActionDefinitionsBuilder(G_CONSTANT) 319 .legalFor({S1, S32, S64, S16, GlobalPtr, 320 LocalPtr, ConstantPtr, PrivatePtr, FlatPtr }) 321 .clampScalar(0, S32, S64) 322 .widenScalarToNextPow2(0) 323 .legalIf(isPointer(0)); 324 325 getActionDefinitionsBuilder(G_FCONSTANT) 326 .legalFor({S32, S64, S16}) 327 .clampScalar(0, S16, S64); 328 329 getActionDefinitionsBuilder(G_IMPLICIT_DEF) 330 .legalFor({S1, S32, S64, S16, V2S32, V4S32, V2S16, V4S16, GlobalPtr, 331 ConstantPtr, LocalPtr, FlatPtr, PrivatePtr}) 332 .moreElementsIf(isSmallOddVector(0), oneMoreElement(0)) 333 .clampScalarOrElt(0, S32, S1024) 334 .legalIf(isMultiple32(0)) 335 .widenScalarToNextPow2(0, 32) 336 .clampMaxNumElements(0, S32, 16); 337 338 setAction({G_FRAME_INDEX, PrivatePtr}, Legal); 339 getActionDefinitionsBuilder(G_GLOBAL_VALUE) 340 .customFor({LocalPtr, GlobalPtr, ConstantPtr, Constant32Ptr}); 341 setAction({G_BLOCK_ADDR, CodePtr}, Legal); 342 343 auto &FPOpActions = getActionDefinitionsBuilder( 344 { G_FADD, G_FMUL, G_FMA, G_FCANONICALIZE}) 345 .legalFor({S32, S64}); 346 auto &TrigActions = getActionDefinitionsBuilder({G_FSIN, G_FCOS}) 347 .customFor({S32, S64}); 348 auto &FDIVActions = getActionDefinitionsBuilder(G_FDIV) 349 .customFor({S32, S64}); 350 351 if (ST.has16BitInsts()) { 352 if (ST.hasVOP3PInsts()) 353 FPOpActions.legalFor({S16, V2S16}); 354 else 355 FPOpActions.legalFor({S16}); 356 357 TrigActions.customFor({S16}); 358 FDIVActions.customFor({S16}); 359 } 360 361 auto &MinNumMaxNum = getActionDefinitionsBuilder({ 362 G_FMINNUM, G_FMAXNUM, G_FMINNUM_IEEE, G_FMAXNUM_IEEE}); 363 364 if (ST.hasVOP3PInsts()) { 365 MinNumMaxNum.customFor(FPTypesPK16) 366 .moreElementsIf(isSmallOddVector(0), oneMoreElement(0)) 367 .clampMaxNumElements(0, S16, 2) 368 .clampScalar(0, S16, S64) 369 .scalarize(0); 370 } else if (ST.has16BitInsts()) { 371 MinNumMaxNum.customFor(FPTypes16) 372 .clampScalar(0, S16, S64) 373 .scalarize(0); 374 } else { 375 MinNumMaxNum.customFor(FPTypesBase) 376 .clampScalar(0, S32, S64) 377 .scalarize(0); 378 } 379 380 if (ST.hasVOP3PInsts()) 381 FPOpActions.clampMaxNumElements(0, S16, 2); 382 383 FPOpActions 384 .scalarize(0) 385 .clampScalar(0, ST.has16BitInsts() ? S16 : S32, S64); 386 387 TrigActions 388 .scalarize(0) 389 .clampScalar(0, ST.has16BitInsts() ? S16 : S32, S64); 390 391 FDIVActions 392 .scalarize(0) 393 .clampScalar(0, ST.has16BitInsts() ? S16 : S32, S64); 394 395 getActionDefinitionsBuilder({G_FNEG, G_FABS}) 396 .legalFor(FPTypesPK16) 397 .clampMaxNumElements(0, S16, 2) 398 .scalarize(0) 399 .clampScalar(0, S16, S64); 400 401 if (ST.has16BitInsts()) { 402 getActionDefinitionsBuilder({G_FSQRT, G_FFLOOR}) 403 .legalFor({S32, S64, S16}) 404 .scalarize(0) 405 .clampScalar(0, S16, S64); 406 } else { 407 getActionDefinitionsBuilder({G_FSQRT, G_FFLOOR}) 408 .legalFor({S32, S64}) 409 .scalarize(0) 410 .clampScalar(0, S32, S64); 411 } 412 413 getActionDefinitionsBuilder(G_FPTRUNC) 414 .legalFor({{S32, S64}, {S16, S32}}) 415 .scalarize(0); 416 417 getActionDefinitionsBuilder(G_FPEXT) 418 .legalFor({{S64, S32}, {S32, S16}}) 419 .lowerFor({{S64, S16}}) // FIXME: Implement 420 .scalarize(0); 421 422 getActionDefinitionsBuilder(G_FSUB) 423 // Use actual fsub instruction 424 .legalFor({S32}) 425 // Must use fadd + fneg 426 .lowerFor({S64, S16, V2S16}) 427 .scalarize(0) 428 .clampScalar(0, S32, S64); 429 430 // Whether this is legal depends on the floating point mode for the function. 431 auto &FMad = getActionDefinitionsBuilder(G_FMAD); 432 if (ST.hasMadF16()) 433 FMad.customFor({S32, S16}); 434 else 435 FMad.customFor({S32}); 436 FMad.scalarize(0) 437 .lower(); 438 439 getActionDefinitionsBuilder({G_SEXT, G_ZEXT, G_ANYEXT}) 440 .legalFor({{S64, S32}, {S32, S16}, {S64, S16}, 441 {S32, S1}, {S64, S1}, {S16, S1}, 442 {S96, S32}, 443 // FIXME: Hack 444 {S64, LLT::scalar(33)}, 445 {S32, S8}, {S32, LLT::scalar(24)}}) 446 .scalarize(0) 447 .clampScalar(0, S32, S64); 448 449 // TODO: Split s1->s64 during regbankselect for VALU. 450 auto &IToFP = getActionDefinitionsBuilder({G_SITOFP, G_UITOFP}) 451 .legalFor({{S32, S32}, {S64, S32}, {S16, S32}}) 452 .lowerFor({{S32, S64}}) 453 .lowerIf(typeIs(1, S1)) 454 .customFor({{S64, S64}}); 455 if (ST.has16BitInsts()) 456 IToFP.legalFor({{S16, S16}}); 457 IToFP.clampScalar(1, S32, S64) 458 .scalarize(0); 459 460 auto &FPToI = getActionDefinitionsBuilder({G_FPTOSI, G_FPTOUI}) 461 .legalFor({{S32, S32}, {S32, S64}, {S32, S16}}) 462 .customFor({{S64, S64}}); 463 if (ST.has16BitInsts()) 464 FPToI.legalFor({{S16, S16}}); 465 else 466 FPToI.minScalar(1, S32); 467 468 FPToI.minScalar(0, S32) 469 .scalarize(0) 470 .lower(); 471 472 getActionDefinitionsBuilder(G_INTRINSIC_ROUND) 473 .scalarize(0) 474 .lower(); 475 476 if (ST.has16BitInsts()) { 477 getActionDefinitionsBuilder({G_INTRINSIC_TRUNC, G_FCEIL, G_FRINT}) 478 .legalFor({S16, S32, S64}) 479 .clampScalar(0, S16, S64) 480 .scalarize(0); 481 } else if (ST.getGeneration() >= AMDGPUSubtarget::SEA_ISLANDS) { 482 getActionDefinitionsBuilder({G_INTRINSIC_TRUNC, G_FCEIL, G_FRINT}) 483 .legalFor({S32, S64}) 484 .clampScalar(0, S32, S64) 485 .scalarize(0); 486 } else { 487 getActionDefinitionsBuilder({G_INTRINSIC_TRUNC, G_FCEIL, G_FRINT}) 488 .legalFor({S32}) 489 .customFor({S64}) 490 .clampScalar(0, S32, S64) 491 .scalarize(0); 492 } 493 494 getActionDefinitionsBuilder({G_PTR_ADD, G_PTR_MASK}) 495 .scalarize(0) 496 .alwaysLegal(); 497 498 auto &CmpBuilder = 499 getActionDefinitionsBuilder(G_ICMP) 500 // The compare output type differs based on the register bank of the output, 501 // so make both s1 and s32 legal. 502 // 503 // Scalar compares producing output in scc will be promoted to s32, as that 504 // is the allocatable register type that will be needed for the copy from 505 // scc. This will be promoted during RegBankSelect, and we assume something 506 // before that won't try to use s32 result types. 507 // 508 // Vector compares producing an output in vcc/SGPR will use s1 in VCC reg 509 // bank. 510 .legalForCartesianProduct( 511 {S1}, {S32, S64, GlobalPtr, LocalPtr, ConstantPtr, PrivatePtr, FlatPtr}) 512 .legalForCartesianProduct( 513 {S32}, {S32, S64, GlobalPtr, LocalPtr, ConstantPtr, PrivatePtr, FlatPtr}); 514 if (ST.has16BitInsts()) { 515 CmpBuilder.legalFor({{S1, S16}}); 516 } 517 518 CmpBuilder 519 .widenScalarToNextPow2(1) 520 .clampScalar(1, S32, S64) 521 .scalarize(0) 522 .legalIf(all(typeInSet(0, {S1, S32}), isPointer(1))); 523 524 getActionDefinitionsBuilder(G_FCMP) 525 .legalForCartesianProduct({S1}, ST.has16BitInsts() ? FPTypes16 : FPTypesBase) 526 .widenScalarToNextPow2(1) 527 .clampScalar(1, S32, S64) 528 .scalarize(0); 529 530 // FIXME: fexp, flog2, flog10 needs to be custom lowered. 531 getActionDefinitionsBuilder({G_FPOW, G_FEXP, G_FEXP2, 532 G_FLOG2}) 533 .legalFor({S32}) 534 .scalarize(0); 535 536 getActionDefinitionsBuilder({G_FLOG, G_FLOG10}) 537 .customFor({S32}) 538 .clampScalar(0, S32, S32) 539 .scalarize(0); 540 541 // The 64-bit versions produce 32-bit results, but only on the SALU. 542 getActionDefinitionsBuilder({G_CTLZ, G_CTLZ_ZERO_UNDEF, 543 G_CTTZ, G_CTTZ_ZERO_UNDEF, 544 G_CTPOP}) 545 .legalFor({{S32, S32}, {S32, S64}}) 546 .clampScalar(0, S32, S32) 547 .clampScalar(1, S32, S64) 548 .scalarize(0) 549 .widenScalarToNextPow2(0, 32) 550 .widenScalarToNextPow2(1, 32); 551 552 // TODO: Expand for > s32 553 getActionDefinitionsBuilder({G_BSWAP, G_BITREVERSE}) 554 .legalFor({S32}) 555 .clampScalar(0, S32, S32) 556 .scalarize(0); 557 558 if (ST.has16BitInsts()) { 559 if (ST.hasVOP3PInsts()) { 560 getActionDefinitionsBuilder({G_SMIN, G_SMAX, G_UMIN, G_UMAX}) 561 .legalFor({S32, S16, V2S16}) 562 .moreElementsIf(isSmallOddVector(0), oneMoreElement(0)) 563 .clampMaxNumElements(0, S16, 2) 564 .clampScalar(0, S16, S32) 565 .widenScalarToNextPow2(0) 566 .scalarize(0); 567 } else { 568 getActionDefinitionsBuilder({G_SMIN, G_SMAX, G_UMIN, G_UMAX}) 569 .legalFor({S32, S16}) 570 .widenScalarToNextPow2(0) 571 .clampScalar(0, S16, S32) 572 .scalarize(0); 573 } 574 } else { 575 getActionDefinitionsBuilder({G_SMIN, G_SMAX, G_UMIN, G_UMAX}) 576 .legalFor({S32}) 577 .clampScalar(0, S32, S32) 578 .widenScalarToNextPow2(0) 579 .scalarize(0); 580 } 581 582 auto smallerThan = [](unsigned TypeIdx0, unsigned TypeIdx1) { 583 return [=](const LegalityQuery &Query) { 584 return Query.Types[TypeIdx0].getSizeInBits() < 585 Query.Types[TypeIdx1].getSizeInBits(); 586 }; 587 }; 588 589 auto greaterThan = [](unsigned TypeIdx0, unsigned TypeIdx1) { 590 return [=](const LegalityQuery &Query) { 591 return Query.Types[TypeIdx0].getSizeInBits() > 592 Query.Types[TypeIdx1].getSizeInBits(); 593 }; 594 }; 595 596 getActionDefinitionsBuilder(G_INTTOPTR) 597 // List the common cases 598 .legalForCartesianProduct(AddrSpaces64, {S64}) 599 .legalForCartesianProduct(AddrSpaces32, {S32}) 600 .scalarize(0) 601 // Accept any address space as long as the size matches 602 .legalIf(sameSize(0, 1)) 603 .widenScalarIf(smallerThan(1, 0), 604 [](const LegalityQuery &Query) { 605 return std::make_pair(1, LLT::scalar(Query.Types[0].getSizeInBits())); 606 }) 607 .narrowScalarIf(greaterThan(1, 0), 608 [](const LegalityQuery &Query) { 609 return std::make_pair(1, LLT::scalar(Query.Types[0].getSizeInBits())); 610 }); 611 612 getActionDefinitionsBuilder(G_PTRTOINT) 613 // List the common cases 614 .legalForCartesianProduct(AddrSpaces64, {S64}) 615 .legalForCartesianProduct(AddrSpaces32, {S32}) 616 .scalarize(0) 617 // Accept any address space as long as the size matches 618 .legalIf(sameSize(0, 1)) 619 .widenScalarIf(smallerThan(0, 1), 620 [](const LegalityQuery &Query) { 621 return std::make_pair(0, LLT::scalar(Query.Types[1].getSizeInBits())); 622 }) 623 .narrowScalarIf( 624 greaterThan(0, 1), 625 [](const LegalityQuery &Query) { 626 return std::make_pair(0, LLT::scalar(Query.Types[1].getSizeInBits())); 627 }); 628 629 getActionDefinitionsBuilder(G_ADDRSPACE_CAST) 630 .scalarize(0) 631 .custom(); 632 633 // TODO: Should load to s16 be legal? Most loads extend to 32-bits, but we 634 // handle some operations by just promoting the register during 635 // selection. There are also d16 loads on GFX9+ which preserve the high bits. 636 auto maxSizeForAddrSpace = [this](unsigned AS, bool IsLoad) -> unsigned { 637 switch (AS) { 638 // FIXME: Private element size. 639 case AMDGPUAS::PRIVATE_ADDRESS: 640 return 32; 641 // FIXME: Check subtarget 642 case AMDGPUAS::LOCAL_ADDRESS: 643 return ST.useDS128() ? 128 : 64; 644 645 // Treat constant and global as identical. SMRD loads are sometimes usable 646 // for global loads (ideally constant address space should be eliminated) 647 // depending on the context. Legality cannot be context dependent, but 648 // RegBankSelect can split the load as necessary depending on the pointer 649 // register bank/uniformity and if the memory is invariant or not written in 650 // a kernel. 651 case AMDGPUAS::CONSTANT_ADDRESS: 652 case AMDGPUAS::GLOBAL_ADDRESS: 653 return IsLoad ? 512 : 128; 654 default: 655 return 128; 656 } 657 }; 658 659 const auto needToSplitMemOp = [=](const LegalityQuery &Query, bool IsLoad) -> bool { 660 const LLT DstTy = Query.Types[0]; 661 662 // Split vector extloads. 663 unsigned MemSize = Query.MMODescrs[0].SizeInBits; 664 unsigned Align = Query.MMODescrs[0].AlignInBits; 665 666 if (MemSize < DstTy.getSizeInBits()) 667 MemSize = std::max(MemSize, Align); 668 669 if (DstTy.isVector() && DstTy.getSizeInBits() > MemSize) 670 return true; 671 672 const LLT PtrTy = Query.Types[1]; 673 unsigned AS = PtrTy.getAddressSpace(); 674 if (MemSize > maxSizeForAddrSpace(AS, IsLoad)) 675 return true; 676 677 // Catch weird sized loads that don't evenly divide into the access sizes 678 // TODO: May be able to widen depending on alignment etc. 679 unsigned NumRegs = MemSize / 32; 680 if (NumRegs == 3 && !ST.hasDwordx3LoadStores()) 681 return true; 682 683 if (Align < MemSize) { 684 const SITargetLowering *TLI = ST.getTargetLowering(); 685 return !TLI->allowsMisalignedMemoryAccessesImpl(MemSize, AS, Align / 8); 686 } 687 688 return false; 689 }; 690 691 unsigned GlobalAlign32 = ST.hasUnalignedBufferAccess() ? 0 : 32; 692 unsigned GlobalAlign16 = ST.hasUnalignedBufferAccess() ? 0 : 16; 693 unsigned GlobalAlign8 = ST.hasUnalignedBufferAccess() ? 0 : 8; 694 695 // TODO: Refine based on subtargets which support unaligned access or 128-bit 696 // LDS 697 // TODO: Unsupported flat for SI. 698 699 for (unsigned Op : {G_LOAD, G_STORE}) { 700 const bool IsStore = Op == G_STORE; 701 702 auto &Actions = getActionDefinitionsBuilder(Op); 703 // Whitelist the common cases. 704 // TODO: Pointer loads 705 // TODO: Wide constant loads 706 // TODO: Only CI+ has 3x loads 707 // TODO: Loads to s16 on gfx9 708 Actions.legalForTypesWithMemDesc({{S32, GlobalPtr, 32, GlobalAlign32}, 709 {V2S32, GlobalPtr, 64, GlobalAlign32}, 710 {V3S32, GlobalPtr, 96, GlobalAlign32}, 711 {S96, GlobalPtr, 96, GlobalAlign32}, 712 {V4S32, GlobalPtr, 128, GlobalAlign32}, 713 {S128, GlobalPtr, 128, GlobalAlign32}, 714 {S64, GlobalPtr, 64, GlobalAlign32}, 715 {V2S64, GlobalPtr, 128, GlobalAlign32}, 716 {V2S16, GlobalPtr, 32, GlobalAlign32}, 717 {S32, GlobalPtr, 8, GlobalAlign8}, 718 {S32, GlobalPtr, 16, GlobalAlign16}, 719 720 {S32, LocalPtr, 32, 32}, 721 {S64, LocalPtr, 64, 32}, 722 {V2S32, LocalPtr, 64, 32}, 723 {S32, LocalPtr, 8, 8}, 724 {S32, LocalPtr, 16, 16}, 725 {V2S16, LocalPtr, 32, 32}, 726 727 {S32, PrivatePtr, 32, 32}, 728 {S32, PrivatePtr, 8, 8}, 729 {S32, PrivatePtr, 16, 16}, 730 {V2S16, PrivatePtr, 32, 32}, 731 732 {S32, FlatPtr, 32, GlobalAlign32}, 733 {S32, FlatPtr, 16, GlobalAlign16}, 734 {S32, FlatPtr, 8, GlobalAlign8}, 735 {V2S16, FlatPtr, 32, GlobalAlign32}, 736 737 {S32, ConstantPtr, 32, GlobalAlign32}, 738 {V2S32, ConstantPtr, 64, GlobalAlign32}, 739 {V3S32, ConstantPtr, 96, GlobalAlign32}, 740 {V4S32, ConstantPtr, 128, GlobalAlign32}, 741 {S64, ConstantPtr, 64, GlobalAlign32}, 742 {S128, ConstantPtr, 128, GlobalAlign32}, 743 {V2S32, ConstantPtr, 32, GlobalAlign32}}); 744 Actions 745 .customIf(typeIs(1, Constant32Ptr)) 746 .narrowScalarIf( 747 [=](const LegalityQuery &Query) -> bool { 748 return !Query.Types[0].isVector() && 749 needToSplitMemOp(Query, Op == G_LOAD); 750 }, 751 [=](const LegalityQuery &Query) -> std::pair<unsigned, LLT> { 752 const LLT DstTy = Query.Types[0]; 753 const LLT PtrTy = Query.Types[1]; 754 755 const unsigned DstSize = DstTy.getSizeInBits(); 756 unsigned MemSize = Query.MMODescrs[0].SizeInBits; 757 758 // Split extloads. 759 if (DstSize > MemSize) 760 return std::make_pair(0, LLT::scalar(MemSize)); 761 762 if (DstSize > 32 && (DstSize % 32 != 0)) { 763 // FIXME: Need a way to specify non-extload of larger size if 764 // suitably aligned. 765 return std::make_pair(0, LLT::scalar(32 * (DstSize / 32))); 766 } 767 768 unsigned MaxSize = maxSizeForAddrSpace(PtrTy.getAddressSpace(), 769 Op == G_LOAD); 770 if (MemSize > MaxSize) 771 return std::make_pair(0, LLT::scalar(MaxSize)); 772 773 unsigned Align = Query.MMODescrs[0].AlignInBits; 774 return std::make_pair(0, LLT::scalar(Align)); 775 }) 776 .fewerElementsIf( 777 [=](const LegalityQuery &Query) -> bool { 778 return Query.Types[0].isVector() && 779 needToSplitMemOp(Query, Op == G_LOAD); 780 }, 781 [=](const LegalityQuery &Query) -> std::pair<unsigned, LLT> { 782 const LLT DstTy = Query.Types[0]; 783 const LLT PtrTy = Query.Types[1]; 784 785 LLT EltTy = DstTy.getElementType(); 786 unsigned MaxSize = maxSizeForAddrSpace(PtrTy.getAddressSpace(), 787 Op == G_LOAD); 788 789 // Split if it's too large for the address space. 790 if (Query.MMODescrs[0].SizeInBits > MaxSize) { 791 unsigned NumElts = DstTy.getNumElements(); 792 unsigned EltSize = EltTy.getSizeInBits(); 793 794 if (MaxSize % EltSize == 0) { 795 return std::make_pair( 796 0, LLT::scalarOrVector(MaxSize / EltSize, EltTy)); 797 } 798 799 unsigned NumPieces = Query.MMODescrs[0].SizeInBits / MaxSize; 800 801 // FIXME: Refine when odd breakdowns handled 802 // The scalars will need to be re-legalized. 803 if (NumPieces == 1 || NumPieces >= NumElts || 804 NumElts % NumPieces != 0) 805 return std::make_pair(0, EltTy); 806 807 return std::make_pair(0, 808 LLT::vector(NumElts / NumPieces, EltTy)); 809 } 810 811 // Need to split because of alignment. 812 unsigned Align = Query.MMODescrs[0].AlignInBits; 813 unsigned EltSize = EltTy.getSizeInBits(); 814 if (EltSize > Align && 815 (EltSize / Align < DstTy.getNumElements())) { 816 return std::make_pair(0, LLT::vector(EltSize / Align, EltTy)); 817 } 818 819 // May need relegalization for the scalars. 820 return std::make_pair(0, EltTy); 821 }) 822 .minScalar(0, S32); 823 824 if (IsStore) 825 Actions.narrowScalarIf(isWideScalarTruncStore(0), changeTo(0, S32)); 826 827 // TODO: Need a bitcast lower option? 828 Actions 829 .legalIf([=](const LegalityQuery &Query) { 830 const LLT Ty0 = Query.Types[0]; 831 unsigned Size = Ty0.getSizeInBits(); 832 unsigned MemSize = Query.MMODescrs[0].SizeInBits; 833 unsigned Align = Query.MMODescrs[0].AlignInBits; 834 835 // FIXME: Widening store from alignment not valid. 836 if (MemSize < Size) 837 MemSize = std::max(MemSize, Align); 838 839 // No extending vector loads. 840 if (Size > MemSize && Ty0.isVector()) 841 return false; 842 843 switch (MemSize) { 844 case 8: 845 case 16: 846 return Size == 32; 847 case 32: 848 case 64: 849 case 128: 850 return true; 851 case 96: 852 return ST.hasDwordx3LoadStores(); 853 case 256: 854 case 512: 855 return true; 856 default: 857 return false; 858 } 859 }) 860 .widenScalarToNextPow2(0) 861 // TODO: v3s32->v4s32 with alignment 862 .moreElementsIf(vectorSmallerThan(0, 32), moreEltsToNext32Bit(0)); 863 } 864 865 auto &ExtLoads = getActionDefinitionsBuilder({G_SEXTLOAD, G_ZEXTLOAD}) 866 .legalForTypesWithMemDesc({{S32, GlobalPtr, 8, 8}, 867 {S32, GlobalPtr, 16, 2 * 8}, 868 {S32, LocalPtr, 8, 8}, 869 {S32, LocalPtr, 16, 16}, 870 {S32, PrivatePtr, 8, 8}, 871 {S32, PrivatePtr, 16, 16}, 872 {S32, ConstantPtr, 8, 8}, 873 {S32, ConstantPtr, 16, 2 * 8}}); 874 if (ST.hasFlatAddressSpace()) { 875 ExtLoads.legalForTypesWithMemDesc( 876 {{S32, FlatPtr, 8, 8}, {S32, FlatPtr, 16, 16}}); 877 } 878 879 ExtLoads.clampScalar(0, S32, S32) 880 .widenScalarToNextPow2(0) 881 .unsupportedIfMemSizeNotPow2() 882 .lower(); 883 884 auto &Atomics = getActionDefinitionsBuilder( 885 {G_ATOMICRMW_XCHG, G_ATOMICRMW_ADD, G_ATOMICRMW_SUB, 886 G_ATOMICRMW_AND, G_ATOMICRMW_OR, G_ATOMICRMW_XOR, 887 G_ATOMICRMW_MAX, G_ATOMICRMW_MIN, G_ATOMICRMW_UMAX, 888 G_ATOMICRMW_UMIN}) 889 .legalFor({{S32, GlobalPtr}, {S32, LocalPtr}, 890 {S64, GlobalPtr}, {S64, LocalPtr}}); 891 if (ST.hasFlatAddressSpace()) { 892 Atomics.legalFor({{S32, FlatPtr}, {S64, FlatPtr}}); 893 } 894 895 getActionDefinitionsBuilder(G_ATOMICRMW_FADD) 896 .legalFor({{S32, LocalPtr}}); 897 898 // BUFFER/FLAT_ATOMIC_CMP_SWAP on GCN GPUs needs input marshalling, and output 899 // demarshalling 900 getActionDefinitionsBuilder(G_ATOMIC_CMPXCHG) 901 .customFor({{S32, GlobalPtr}, {S64, GlobalPtr}, 902 {S32, FlatPtr}, {S64, FlatPtr}}) 903 .legalFor({{S32, LocalPtr}, {S64, LocalPtr}, 904 {S32, RegionPtr}, {S64, RegionPtr}}); 905 // TODO: Pointer types, any 32-bit or 64-bit vector 906 907 // Condition should be s32 for scalar, s1 for vector. 908 getActionDefinitionsBuilder(G_SELECT) 909 .legalForCartesianProduct({S32, S64, S16, V2S32, V2S16, V4S16, 910 GlobalPtr, LocalPtr, FlatPtr, PrivatePtr, 911 LLT::vector(2, LocalPtr), LLT::vector(2, PrivatePtr)}, {S1, S32}) 912 .clampScalar(0, S16, S64) 913 .moreElementsIf(isSmallOddVector(0), oneMoreElement(0)) 914 .fewerElementsIf(numElementsNotEven(0), scalarize(0)) 915 .scalarize(1) 916 .clampMaxNumElements(0, S32, 2) 917 .clampMaxNumElements(0, LocalPtr, 2) 918 .clampMaxNumElements(0, PrivatePtr, 2) 919 .scalarize(0) 920 .widenScalarToNextPow2(0) 921 .legalIf(all(isPointer(0), typeInSet(1, {S1, S32}))); 922 923 // TODO: Only the low 4/5/6 bits of the shift amount are observed, so we can 924 // be more flexible with the shift amount type. 925 auto &Shifts = getActionDefinitionsBuilder({G_SHL, G_LSHR, G_ASHR}) 926 .legalFor({{S32, S32}, {S64, S32}}); 927 if (ST.has16BitInsts()) { 928 if (ST.hasVOP3PInsts()) { 929 Shifts.legalFor({{S16, S32}, {S16, S16}, {V2S16, V2S16}}) 930 .clampMaxNumElements(0, S16, 2); 931 } else 932 Shifts.legalFor({{S16, S32}, {S16, S16}}); 933 934 // TODO: Support 16-bit shift amounts 935 Shifts.clampScalar(1, S32, S32); 936 Shifts.clampScalar(0, S16, S64); 937 Shifts.widenScalarToNextPow2(0, 16); 938 } else { 939 // Make sure we legalize the shift amount type first, as the general 940 // expansion for the shifted type will produce much worse code if it hasn't 941 // been truncated already. 942 Shifts.clampScalar(1, S32, S32); 943 Shifts.clampScalar(0, S32, S64); 944 Shifts.widenScalarToNextPow2(0, 32); 945 } 946 Shifts.scalarize(0); 947 948 for (unsigned Op : {G_EXTRACT_VECTOR_ELT, G_INSERT_VECTOR_ELT}) { 949 unsigned VecTypeIdx = Op == G_EXTRACT_VECTOR_ELT ? 1 : 0; 950 unsigned EltTypeIdx = Op == G_EXTRACT_VECTOR_ELT ? 0 : 1; 951 unsigned IdxTypeIdx = 2; 952 953 getActionDefinitionsBuilder(Op) 954 .customIf([=](const LegalityQuery &Query) { 955 const LLT EltTy = Query.Types[EltTypeIdx]; 956 const LLT VecTy = Query.Types[VecTypeIdx]; 957 const LLT IdxTy = Query.Types[IdxTypeIdx]; 958 return (EltTy.getSizeInBits() == 16 || 959 EltTy.getSizeInBits() % 32 == 0) && 960 VecTy.getSizeInBits() % 32 == 0 && 961 VecTy.getSizeInBits() <= 1024 && 962 IdxTy.getSizeInBits() == 32; 963 }) 964 .clampScalar(EltTypeIdx, S32, S64) 965 .clampScalar(VecTypeIdx, S32, S64) 966 .clampScalar(IdxTypeIdx, S32, S32); 967 } 968 969 getActionDefinitionsBuilder(G_EXTRACT_VECTOR_ELT) 970 .unsupportedIf([=](const LegalityQuery &Query) { 971 const LLT &EltTy = Query.Types[1].getElementType(); 972 return Query.Types[0] != EltTy; 973 }); 974 975 for (unsigned Op : {G_EXTRACT, G_INSERT}) { 976 unsigned BigTyIdx = Op == G_EXTRACT ? 1 : 0; 977 unsigned LitTyIdx = Op == G_EXTRACT ? 0 : 1; 978 979 // FIXME: Doesn't handle extract of illegal sizes. 980 getActionDefinitionsBuilder(Op) 981 .lowerIf(all(typeIs(LitTyIdx, S16), sizeIs(BigTyIdx, 32))) 982 // FIXME: Multiples of 16 should not be legal. 983 .legalIf([=](const LegalityQuery &Query) { 984 const LLT BigTy = Query.Types[BigTyIdx]; 985 const LLT LitTy = Query.Types[LitTyIdx]; 986 return (BigTy.getSizeInBits() % 32 == 0) && 987 (LitTy.getSizeInBits() % 16 == 0); 988 }) 989 .widenScalarIf( 990 [=](const LegalityQuery &Query) { 991 const LLT BigTy = Query.Types[BigTyIdx]; 992 return (BigTy.getScalarSizeInBits() < 16); 993 }, 994 LegalizeMutations::widenScalarOrEltToNextPow2(BigTyIdx, 16)) 995 .widenScalarIf( 996 [=](const LegalityQuery &Query) { 997 const LLT LitTy = Query.Types[LitTyIdx]; 998 return (LitTy.getScalarSizeInBits() < 16); 999 }, 1000 LegalizeMutations::widenScalarOrEltToNextPow2(LitTyIdx, 16)) 1001 .moreElementsIf(isSmallOddVector(BigTyIdx), oneMoreElement(BigTyIdx)) 1002 .widenScalarToNextPow2(BigTyIdx, 32); 1003 1004 } 1005 1006 auto &BuildVector = getActionDefinitionsBuilder(G_BUILD_VECTOR) 1007 .legalForCartesianProduct(AllS32Vectors, {S32}) 1008 .legalForCartesianProduct(AllS64Vectors, {S64}) 1009 .clampNumElements(0, V16S32, V32S32) 1010 .clampNumElements(0, V2S64, V16S64) 1011 .fewerElementsIf(isWideVec16(0), changeTo(0, V2S16)); 1012 1013 if (ST.hasScalarPackInsts()) 1014 BuildVector.legalFor({V2S16, S32}); 1015 1016 BuildVector 1017 .minScalarSameAs(1, 0) 1018 .legalIf(isRegisterType(0)) 1019 .minScalarOrElt(0, S32); 1020 1021 if (ST.hasScalarPackInsts()) { 1022 getActionDefinitionsBuilder(G_BUILD_VECTOR_TRUNC) 1023 .legalFor({V2S16, S32}) 1024 .lower(); 1025 } else { 1026 getActionDefinitionsBuilder(G_BUILD_VECTOR_TRUNC) 1027 .lower(); 1028 } 1029 1030 getActionDefinitionsBuilder(G_CONCAT_VECTORS) 1031 .legalIf(isRegisterType(0)); 1032 1033 // TODO: Don't fully scalarize v2s16 pieces? Or combine out thosse 1034 // pre-legalize. 1035 if (ST.hasVOP3PInsts()) { 1036 getActionDefinitionsBuilder(G_SHUFFLE_VECTOR) 1037 .customFor({V2S16, V2S16}) 1038 .lower(); 1039 } else 1040 getActionDefinitionsBuilder(G_SHUFFLE_VECTOR).lower(); 1041 1042 // Merge/Unmerge 1043 for (unsigned Op : {G_MERGE_VALUES, G_UNMERGE_VALUES}) { 1044 unsigned BigTyIdx = Op == G_MERGE_VALUES ? 0 : 1; 1045 unsigned LitTyIdx = Op == G_MERGE_VALUES ? 1 : 0; 1046 1047 auto notValidElt = [=](const LegalityQuery &Query, unsigned TypeIdx) { 1048 const LLT &Ty = Query.Types[TypeIdx]; 1049 if (Ty.isVector()) { 1050 const LLT &EltTy = Ty.getElementType(); 1051 if (EltTy.getSizeInBits() < 8 || EltTy.getSizeInBits() > 64) 1052 return true; 1053 if (!isPowerOf2_32(EltTy.getSizeInBits())) 1054 return true; 1055 } 1056 return false; 1057 }; 1058 1059 auto &Builder = getActionDefinitionsBuilder(Op) 1060 // Try to widen to s16 first for small types. 1061 // TODO: Only do this on targets with legal s16 shifts 1062 .minScalarOrEltIf(narrowerThan(LitTyIdx, 16), LitTyIdx, S16) 1063 1064 .widenScalarToNextPow2(LitTyIdx, /*Min*/ 16) 1065 .lowerFor({{S16, V2S16}}) 1066 .moreElementsIf(isSmallOddVector(BigTyIdx), oneMoreElement(BigTyIdx)) 1067 .fewerElementsIf(all(typeIs(0, S16), vectorWiderThan(1, 32), 1068 elementTypeIs(1, S16)), 1069 changeTo(1, V2S16)) 1070 // Clamp the little scalar to s8-s256 and make it a power of 2. It's not 1071 // worth considering the multiples of 64 since 2*192 and 2*384 are not 1072 // valid. 1073 .clampScalar(LitTyIdx, S32, S256) 1074 .widenScalarToNextPow2(LitTyIdx, /*Min*/ 32) 1075 // Break up vectors with weird elements into scalars 1076 .fewerElementsIf( 1077 [=](const LegalityQuery &Query) { return notValidElt(Query, 0); }, 1078 scalarize(0)) 1079 .fewerElementsIf( 1080 [=](const LegalityQuery &Query) { return notValidElt(Query, 1); }, 1081 scalarize(1)) 1082 .clampScalar(BigTyIdx, S32, S1024); 1083 1084 if (Op == G_MERGE_VALUES) { 1085 Builder.widenScalarIf( 1086 // TODO: Use 16-bit shifts if legal for 8-bit values? 1087 [=](const LegalityQuery &Query) { 1088 const LLT Ty = Query.Types[LitTyIdx]; 1089 return Ty.getSizeInBits() < 32; 1090 }, 1091 changeTo(LitTyIdx, S32)); 1092 } 1093 1094 Builder.widenScalarIf( 1095 [=](const LegalityQuery &Query) { 1096 const LLT Ty = Query.Types[BigTyIdx]; 1097 return !isPowerOf2_32(Ty.getSizeInBits()) && 1098 Ty.getSizeInBits() % 16 != 0; 1099 }, 1100 [=](const LegalityQuery &Query) { 1101 // Pick the next power of 2, or a multiple of 64 over 128. 1102 // Whichever is smaller. 1103 const LLT &Ty = Query.Types[BigTyIdx]; 1104 unsigned NewSizeInBits = 1 << Log2_32_Ceil(Ty.getSizeInBits() + 1); 1105 if (NewSizeInBits >= 256) { 1106 unsigned RoundedTo = alignTo<64>(Ty.getSizeInBits() + 1); 1107 if (RoundedTo < NewSizeInBits) 1108 NewSizeInBits = RoundedTo; 1109 } 1110 return std::make_pair(BigTyIdx, LLT::scalar(NewSizeInBits)); 1111 }) 1112 .legalIf([=](const LegalityQuery &Query) { 1113 const LLT &BigTy = Query.Types[BigTyIdx]; 1114 const LLT &LitTy = Query.Types[LitTyIdx]; 1115 1116 if (BigTy.isVector() && BigTy.getSizeInBits() < 32) 1117 return false; 1118 if (LitTy.isVector() && LitTy.getSizeInBits() < 32) 1119 return false; 1120 1121 return BigTy.getSizeInBits() % 16 == 0 && 1122 LitTy.getSizeInBits() % 16 == 0 && 1123 BigTy.getSizeInBits() <= 1024; 1124 }) 1125 // Any vectors left are the wrong size. Scalarize them. 1126 .scalarize(0) 1127 .scalarize(1); 1128 } 1129 1130 // TODO: Make legal for s32, s64. s64 case needs break down in regbankselect. 1131 auto &SextInReg = getActionDefinitionsBuilder(G_SEXT_INREG); 1132 if (ST.hasVOP3PInsts()) { 1133 SextInReg.lowerFor({{S32}, {S64}, {S16}, {V2S16}}) 1134 // Prefer to reduce vector widths for 16-bit vectors before lowering, to 1135 // get more vector shift opportunities, since we'll get those when 1136 // expanded. 1137 .fewerElementsIf(elementTypeIs(0, S16), changeTo(0, V2S16)); 1138 } else if (ST.has16BitInsts()) { 1139 SextInReg.lowerFor({{S32}, {S64}, {S16}}); 1140 } else { 1141 // Prefer to promote to s32 before lowering if we don't have 16-bit 1142 // shifts. This avoid a lot of intermediate truncate and extend operations. 1143 SextInReg.lowerFor({{S32}, {S64}}); 1144 } 1145 1146 SextInReg 1147 .scalarize(0) 1148 .clampScalar(0, MinLegalScalarShiftTy, S64) 1149 .lower(); 1150 1151 getActionDefinitionsBuilder(G_READCYCLECOUNTER) 1152 .legalFor({S64}); 1153 1154 getActionDefinitionsBuilder({ 1155 // TODO: Verify V_BFI_B32 is generated from expanded bit ops 1156 G_FCOPYSIGN, 1157 1158 G_ATOMIC_CMPXCHG_WITH_SUCCESS, 1159 G_READ_REGISTER, 1160 G_WRITE_REGISTER, 1161 1162 G_SADDO, G_SSUBO, 1163 1164 // TODO: Implement 1165 G_FMINIMUM, G_FMAXIMUM 1166 }).lower(); 1167 1168 getActionDefinitionsBuilder({G_VASTART, G_VAARG, G_BRJT, G_JUMP_TABLE, 1169 G_DYN_STACKALLOC, G_INDEXED_LOAD, G_INDEXED_SEXTLOAD, 1170 G_INDEXED_ZEXTLOAD, G_INDEXED_STORE}) 1171 .unsupported(); 1172 1173 computeTables(); 1174 verify(*ST.getInstrInfo()); 1175 } 1176 1177 bool AMDGPULegalizerInfo::legalizeCustom(MachineInstr &MI, 1178 MachineRegisterInfo &MRI, 1179 MachineIRBuilder &B, 1180 GISelChangeObserver &Observer) const { 1181 switch (MI.getOpcode()) { 1182 case TargetOpcode::G_ADDRSPACE_CAST: 1183 return legalizeAddrSpaceCast(MI, MRI, B); 1184 case TargetOpcode::G_FRINT: 1185 return legalizeFrint(MI, MRI, B); 1186 case TargetOpcode::G_FCEIL: 1187 return legalizeFceil(MI, MRI, B); 1188 case TargetOpcode::G_INTRINSIC_TRUNC: 1189 return legalizeIntrinsicTrunc(MI, MRI, B); 1190 case TargetOpcode::G_SITOFP: 1191 return legalizeITOFP(MI, MRI, B, true); 1192 case TargetOpcode::G_UITOFP: 1193 return legalizeITOFP(MI, MRI, B, false); 1194 case TargetOpcode::G_FPTOSI: 1195 return legalizeFPTOI(MI, MRI, B, true); 1196 case TargetOpcode::G_FPTOUI: 1197 return legalizeFPTOI(MI, MRI, B, false); 1198 case TargetOpcode::G_FMINNUM: 1199 case TargetOpcode::G_FMAXNUM: 1200 case TargetOpcode::G_FMINNUM_IEEE: 1201 case TargetOpcode::G_FMAXNUM_IEEE: 1202 return legalizeMinNumMaxNum(MI, MRI, B); 1203 case TargetOpcode::G_EXTRACT_VECTOR_ELT: 1204 return legalizeExtractVectorElt(MI, MRI, B); 1205 case TargetOpcode::G_INSERT_VECTOR_ELT: 1206 return legalizeInsertVectorElt(MI, MRI, B); 1207 case TargetOpcode::G_SHUFFLE_VECTOR: 1208 return legalizeShuffleVector(MI, MRI, B); 1209 case TargetOpcode::G_FSIN: 1210 case TargetOpcode::G_FCOS: 1211 return legalizeSinCos(MI, MRI, B); 1212 case TargetOpcode::G_GLOBAL_VALUE: 1213 return legalizeGlobalValue(MI, MRI, B); 1214 case TargetOpcode::G_LOAD: 1215 return legalizeLoad(MI, MRI, B, Observer); 1216 case TargetOpcode::G_FMAD: 1217 return legalizeFMad(MI, MRI, B); 1218 case TargetOpcode::G_FDIV: 1219 return legalizeFDIV(MI, MRI, B); 1220 case TargetOpcode::G_ATOMIC_CMPXCHG: 1221 return legalizeAtomicCmpXChg(MI, MRI, B); 1222 case TargetOpcode::G_FLOG: 1223 return legalizeFlog(MI, B, 1.0f / numbers::log2ef); 1224 case TargetOpcode::G_FLOG10: 1225 return legalizeFlog(MI, B, numbers::ln2f / numbers::ln10f); 1226 default: 1227 return false; 1228 } 1229 1230 llvm_unreachable("expected switch to return"); 1231 } 1232 1233 Register AMDGPULegalizerInfo::getSegmentAperture( 1234 unsigned AS, 1235 MachineRegisterInfo &MRI, 1236 MachineIRBuilder &B) const { 1237 MachineFunction &MF = B.getMF(); 1238 const GCNSubtarget &ST = MF.getSubtarget<GCNSubtarget>(); 1239 const LLT S32 = LLT::scalar(32); 1240 1241 assert(AS == AMDGPUAS::LOCAL_ADDRESS || AS == AMDGPUAS::PRIVATE_ADDRESS); 1242 1243 if (ST.hasApertureRegs()) { 1244 // FIXME: Use inline constants (src_{shared, private}_base) instead of 1245 // getreg. 1246 unsigned Offset = AS == AMDGPUAS::LOCAL_ADDRESS ? 1247 AMDGPU::Hwreg::OFFSET_SRC_SHARED_BASE : 1248 AMDGPU::Hwreg::OFFSET_SRC_PRIVATE_BASE; 1249 unsigned WidthM1 = AS == AMDGPUAS::LOCAL_ADDRESS ? 1250 AMDGPU::Hwreg::WIDTH_M1_SRC_SHARED_BASE : 1251 AMDGPU::Hwreg::WIDTH_M1_SRC_PRIVATE_BASE; 1252 unsigned Encoding = 1253 AMDGPU::Hwreg::ID_MEM_BASES << AMDGPU::Hwreg::ID_SHIFT_ | 1254 Offset << AMDGPU::Hwreg::OFFSET_SHIFT_ | 1255 WidthM1 << AMDGPU::Hwreg::WIDTH_M1_SHIFT_; 1256 1257 Register GetReg = MRI.createVirtualRegister(&AMDGPU::SReg_32RegClass); 1258 1259 B.buildInstr(AMDGPU::S_GETREG_B32) 1260 .addDef(GetReg) 1261 .addImm(Encoding); 1262 MRI.setType(GetReg, S32); 1263 1264 auto ShiftAmt = B.buildConstant(S32, WidthM1 + 1); 1265 return B.buildShl(S32, GetReg, ShiftAmt).getReg(0); 1266 } 1267 1268 Register QueuePtr = MRI.createGenericVirtualRegister( 1269 LLT::pointer(AMDGPUAS::CONSTANT_ADDRESS, 64)); 1270 1271 const SIMachineFunctionInfo *MFI = MF.getInfo<SIMachineFunctionInfo>(); 1272 if (!loadInputValue(QueuePtr, B, &MFI->getArgInfo().QueuePtr)) 1273 return Register(); 1274 1275 // Offset into amd_queue_t for group_segment_aperture_base_hi / 1276 // private_segment_aperture_base_hi. 1277 uint32_t StructOffset = (AS == AMDGPUAS::LOCAL_ADDRESS) ? 0x40 : 0x44; 1278 1279 // TODO: can we be smarter about machine pointer info? 1280 MachinePointerInfo PtrInfo(AMDGPUAS::CONSTANT_ADDRESS); 1281 MachineMemOperand *MMO = MF.getMachineMemOperand( 1282 PtrInfo, 1283 MachineMemOperand::MOLoad | 1284 MachineMemOperand::MODereferenceable | 1285 MachineMemOperand::MOInvariant, 1286 4, 1287 MinAlign(64, StructOffset)); 1288 1289 Register LoadAddr; 1290 1291 B.materializePtrAdd(LoadAddr, QueuePtr, LLT::scalar(64), StructOffset); 1292 return B.buildLoad(S32, LoadAddr, *MMO).getReg(0); 1293 } 1294 1295 bool AMDGPULegalizerInfo::legalizeAddrSpaceCast( 1296 MachineInstr &MI, MachineRegisterInfo &MRI, 1297 MachineIRBuilder &B) const { 1298 MachineFunction &MF = B.getMF(); 1299 1300 B.setInstr(MI); 1301 1302 const LLT S32 = LLT::scalar(32); 1303 Register Dst = MI.getOperand(0).getReg(); 1304 Register Src = MI.getOperand(1).getReg(); 1305 1306 LLT DstTy = MRI.getType(Dst); 1307 LLT SrcTy = MRI.getType(Src); 1308 unsigned DestAS = DstTy.getAddressSpace(); 1309 unsigned SrcAS = SrcTy.getAddressSpace(); 1310 1311 // TODO: Avoid reloading from the queue ptr for each cast, or at least each 1312 // vector element. 1313 assert(!DstTy.isVector()); 1314 1315 const AMDGPUTargetMachine &TM 1316 = static_cast<const AMDGPUTargetMachine &>(MF.getTarget()); 1317 1318 const GCNSubtarget &ST = MF.getSubtarget<GCNSubtarget>(); 1319 if (ST.getTargetLowering()->isNoopAddrSpaceCast(SrcAS, DestAS)) { 1320 MI.setDesc(B.getTII().get(TargetOpcode::G_BITCAST)); 1321 return true; 1322 } 1323 1324 if (DestAS == AMDGPUAS::CONSTANT_ADDRESS_32BIT) { 1325 // Truncate. 1326 B.buildExtract(Dst, Src, 0); 1327 MI.eraseFromParent(); 1328 return true; 1329 } 1330 1331 if (SrcAS == AMDGPUAS::CONSTANT_ADDRESS_32BIT) { 1332 const SIMachineFunctionInfo *Info = MF.getInfo<SIMachineFunctionInfo>(); 1333 uint32_t AddrHiVal = Info->get32BitAddressHighBits(); 1334 1335 // FIXME: This is a bit ugly due to creating a merge of 2 pointers to 1336 // another. Merge operands are required to be the same type, but creating an 1337 // extra ptrtoint would be kind of pointless. 1338 auto HighAddr = B.buildConstant( 1339 LLT::pointer(AMDGPUAS::CONSTANT_ADDRESS_32BIT, 32), AddrHiVal); 1340 B.buildMerge(Dst, {Src, HighAddr.getReg(0)}); 1341 MI.eraseFromParent(); 1342 return true; 1343 } 1344 1345 if (SrcAS == AMDGPUAS::FLAT_ADDRESS) { 1346 assert(DestAS == AMDGPUAS::LOCAL_ADDRESS || 1347 DestAS == AMDGPUAS::PRIVATE_ADDRESS); 1348 unsigned NullVal = TM.getNullPointerValue(DestAS); 1349 1350 auto SegmentNull = B.buildConstant(DstTy, NullVal); 1351 auto FlatNull = B.buildConstant(SrcTy, 0); 1352 1353 // Extract low 32-bits of the pointer. 1354 auto PtrLo32 = B.buildExtract(DstTy, Src, 0); 1355 1356 auto CmpRes = 1357 B.buildICmp(CmpInst::ICMP_NE, LLT::scalar(1), Src, FlatNull.getReg(0)); 1358 B.buildSelect(Dst, CmpRes, PtrLo32, SegmentNull.getReg(0)); 1359 1360 MI.eraseFromParent(); 1361 return true; 1362 } 1363 1364 if (SrcAS != AMDGPUAS::LOCAL_ADDRESS && SrcAS != AMDGPUAS::PRIVATE_ADDRESS) 1365 return false; 1366 1367 if (!ST.hasFlatAddressSpace()) 1368 return false; 1369 1370 auto SegmentNull = 1371 B.buildConstant(SrcTy, TM.getNullPointerValue(SrcAS)); 1372 auto FlatNull = 1373 B.buildConstant(DstTy, TM.getNullPointerValue(DestAS)); 1374 1375 Register ApertureReg = getSegmentAperture(SrcAS, MRI, B); 1376 if (!ApertureReg.isValid()) 1377 return false; 1378 1379 auto CmpRes = 1380 B.buildICmp(CmpInst::ICMP_NE, LLT::scalar(1), Src, SegmentNull.getReg(0)); 1381 1382 // Coerce the type of the low half of the result so we can use merge_values. 1383 Register SrcAsInt = B.buildPtrToInt(S32, Src).getReg(0); 1384 1385 // TODO: Should we allow mismatched types but matching sizes in merges to 1386 // avoid the ptrtoint? 1387 auto BuildPtr = B.buildMerge(DstTy, {SrcAsInt, ApertureReg}); 1388 B.buildSelect(Dst, CmpRes, BuildPtr, FlatNull); 1389 1390 MI.eraseFromParent(); 1391 return true; 1392 } 1393 1394 bool AMDGPULegalizerInfo::legalizeFrint( 1395 MachineInstr &MI, MachineRegisterInfo &MRI, 1396 MachineIRBuilder &B) const { 1397 B.setInstr(MI); 1398 1399 Register Src = MI.getOperand(1).getReg(); 1400 LLT Ty = MRI.getType(Src); 1401 assert(Ty.isScalar() && Ty.getSizeInBits() == 64); 1402 1403 APFloat C1Val(APFloat::IEEEdouble(), "0x1.0p+52"); 1404 APFloat C2Val(APFloat::IEEEdouble(), "0x1.fffffffffffffp+51"); 1405 1406 auto C1 = B.buildFConstant(Ty, C1Val); 1407 auto CopySign = B.buildFCopysign(Ty, C1, Src); 1408 1409 // TODO: Should this propagate fast-math-flags? 1410 auto Tmp1 = B.buildFAdd(Ty, Src, CopySign); 1411 auto Tmp2 = B.buildFSub(Ty, Tmp1, CopySign); 1412 1413 auto C2 = B.buildFConstant(Ty, C2Val); 1414 auto Fabs = B.buildFAbs(Ty, Src); 1415 1416 auto Cond = B.buildFCmp(CmpInst::FCMP_OGT, LLT::scalar(1), Fabs, C2); 1417 B.buildSelect(MI.getOperand(0).getReg(), Cond, Src, Tmp2); 1418 return true; 1419 } 1420 1421 bool AMDGPULegalizerInfo::legalizeFceil( 1422 MachineInstr &MI, MachineRegisterInfo &MRI, 1423 MachineIRBuilder &B) const { 1424 B.setInstr(MI); 1425 1426 const LLT S1 = LLT::scalar(1); 1427 const LLT S64 = LLT::scalar(64); 1428 1429 Register Src = MI.getOperand(1).getReg(); 1430 assert(MRI.getType(Src) == S64); 1431 1432 // result = trunc(src) 1433 // if (src > 0.0 && src != result) 1434 // result += 1.0 1435 1436 auto Trunc = B.buildIntrinsicTrunc(S64, Src); 1437 1438 const auto Zero = B.buildFConstant(S64, 0.0); 1439 const auto One = B.buildFConstant(S64, 1.0); 1440 auto Lt0 = B.buildFCmp(CmpInst::FCMP_OGT, S1, Src, Zero); 1441 auto NeTrunc = B.buildFCmp(CmpInst::FCMP_ONE, S1, Src, Trunc); 1442 auto And = B.buildAnd(S1, Lt0, NeTrunc); 1443 auto Add = B.buildSelect(S64, And, One, Zero); 1444 1445 // TODO: Should this propagate fast-math-flags? 1446 B.buildFAdd(MI.getOperand(0).getReg(), Trunc, Add); 1447 return true; 1448 } 1449 1450 static MachineInstrBuilder extractF64Exponent(unsigned Hi, 1451 MachineIRBuilder &B) { 1452 const unsigned FractBits = 52; 1453 const unsigned ExpBits = 11; 1454 LLT S32 = LLT::scalar(32); 1455 1456 auto Const0 = B.buildConstant(S32, FractBits - 32); 1457 auto Const1 = B.buildConstant(S32, ExpBits); 1458 1459 auto ExpPart = B.buildIntrinsic(Intrinsic::amdgcn_ubfe, {S32}, false) 1460 .addUse(Const0.getReg(0)) 1461 .addUse(Const1.getReg(0)); 1462 1463 return B.buildSub(S32, ExpPart, B.buildConstant(S32, 1023)); 1464 } 1465 1466 bool AMDGPULegalizerInfo::legalizeIntrinsicTrunc( 1467 MachineInstr &MI, MachineRegisterInfo &MRI, 1468 MachineIRBuilder &B) const { 1469 B.setInstr(MI); 1470 1471 const LLT S1 = LLT::scalar(1); 1472 const LLT S32 = LLT::scalar(32); 1473 const LLT S64 = LLT::scalar(64); 1474 1475 Register Src = MI.getOperand(1).getReg(); 1476 assert(MRI.getType(Src) == S64); 1477 1478 // TODO: Should this use extract since the low half is unused? 1479 auto Unmerge = B.buildUnmerge({S32, S32}, Src); 1480 Register Hi = Unmerge.getReg(1); 1481 1482 // Extract the upper half, since this is where we will find the sign and 1483 // exponent. 1484 auto Exp = extractF64Exponent(Hi, B); 1485 1486 const unsigned FractBits = 52; 1487 1488 // Extract the sign bit. 1489 const auto SignBitMask = B.buildConstant(S32, UINT32_C(1) << 31); 1490 auto SignBit = B.buildAnd(S32, Hi, SignBitMask); 1491 1492 const auto FractMask = B.buildConstant(S64, (UINT64_C(1) << FractBits) - 1); 1493 1494 const auto Zero32 = B.buildConstant(S32, 0); 1495 1496 // Extend back to 64-bits. 1497 auto SignBit64 = B.buildMerge(S64, {Zero32.getReg(0), SignBit.getReg(0)}); 1498 1499 auto Shr = B.buildAShr(S64, FractMask, Exp); 1500 auto Not = B.buildNot(S64, Shr); 1501 auto Tmp0 = B.buildAnd(S64, Src, Not); 1502 auto FiftyOne = B.buildConstant(S32, FractBits - 1); 1503 1504 auto ExpLt0 = B.buildICmp(CmpInst::ICMP_SLT, S1, Exp, Zero32); 1505 auto ExpGt51 = B.buildICmp(CmpInst::ICMP_SGT, S1, Exp, FiftyOne); 1506 1507 auto Tmp1 = B.buildSelect(S64, ExpLt0, SignBit64, Tmp0); 1508 B.buildSelect(MI.getOperand(0).getReg(), ExpGt51, Src, Tmp1); 1509 return true; 1510 } 1511 1512 bool AMDGPULegalizerInfo::legalizeITOFP( 1513 MachineInstr &MI, MachineRegisterInfo &MRI, 1514 MachineIRBuilder &B, bool Signed) const { 1515 B.setInstr(MI); 1516 1517 Register Dst = MI.getOperand(0).getReg(); 1518 Register Src = MI.getOperand(1).getReg(); 1519 1520 const LLT S64 = LLT::scalar(64); 1521 const LLT S32 = LLT::scalar(32); 1522 1523 assert(MRI.getType(Src) == S64 && MRI.getType(Dst) == S64); 1524 1525 auto Unmerge = B.buildUnmerge({S32, S32}, Src); 1526 1527 auto CvtHi = Signed ? 1528 B.buildSITOFP(S64, Unmerge.getReg(1)) : 1529 B.buildUITOFP(S64, Unmerge.getReg(1)); 1530 1531 auto CvtLo = B.buildUITOFP(S64, Unmerge.getReg(0)); 1532 1533 auto ThirtyTwo = B.buildConstant(S32, 32); 1534 auto LdExp = B.buildIntrinsic(Intrinsic::amdgcn_ldexp, {S64}, false) 1535 .addUse(CvtHi.getReg(0)) 1536 .addUse(ThirtyTwo.getReg(0)); 1537 1538 // TODO: Should this propagate fast-math-flags? 1539 B.buildFAdd(Dst, LdExp, CvtLo); 1540 MI.eraseFromParent(); 1541 return true; 1542 } 1543 1544 // TODO: Copied from DAG implementation. Verify logic and document how this 1545 // actually works. 1546 bool AMDGPULegalizerInfo::legalizeFPTOI( 1547 MachineInstr &MI, MachineRegisterInfo &MRI, 1548 MachineIRBuilder &B, bool Signed) const { 1549 B.setInstr(MI); 1550 1551 Register Dst = MI.getOperand(0).getReg(); 1552 Register Src = MI.getOperand(1).getReg(); 1553 1554 const LLT S64 = LLT::scalar(64); 1555 const LLT S32 = LLT::scalar(32); 1556 1557 assert(MRI.getType(Src) == S64 && MRI.getType(Dst) == S64); 1558 1559 unsigned Flags = MI.getFlags(); 1560 1561 auto Trunc = B.buildIntrinsicTrunc(S64, Src, Flags); 1562 auto K0 = B.buildFConstant(S64, BitsToDouble(UINT64_C(0x3df0000000000000))); 1563 auto K1 = B.buildFConstant(S64, BitsToDouble(UINT64_C(0xc1f0000000000000))); 1564 1565 auto Mul = B.buildFMul(S64, Trunc, K0, Flags); 1566 auto FloorMul = B.buildFFloor(S64, Mul, Flags); 1567 auto Fma = B.buildFMA(S64, FloorMul, K1, Trunc, Flags); 1568 1569 auto Hi = Signed ? 1570 B.buildFPTOSI(S32, FloorMul) : 1571 B.buildFPTOUI(S32, FloorMul); 1572 auto Lo = B.buildFPTOUI(S32, Fma); 1573 1574 B.buildMerge(Dst, { Lo.getReg(0), Hi.getReg(0) }); 1575 MI.eraseFromParent(); 1576 1577 return true; 1578 } 1579 1580 bool AMDGPULegalizerInfo::legalizeMinNumMaxNum( 1581 MachineInstr &MI, MachineRegisterInfo &MRI, 1582 MachineIRBuilder &B) const { 1583 MachineFunction &MF = B.getMF(); 1584 const SIMachineFunctionInfo *MFI = MF.getInfo<SIMachineFunctionInfo>(); 1585 1586 const bool IsIEEEOp = MI.getOpcode() == AMDGPU::G_FMINNUM_IEEE || 1587 MI.getOpcode() == AMDGPU::G_FMAXNUM_IEEE; 1588 1589 // With ieee_mode disabled, the instructions have the correct behavior 1590 // already for G_FMINNUM/G_FMAXNUM 1591 if (!MFI->getMode().IEEE) 1592 return !IsIEEEOp; 1593 1594 if (IsIEEEOp) 1595 return true; 1596 1597 MachineIRBuilder HelperBuilder(MI); 1598 GISelObserverWrapper DummyObserver; 1599 LegalizerHelper Helper(MF, DummyObserver, HelperBuilder); 1600 HelperBuilder.setInstr(MI); 1601 return Helper.lowerFMinNumMaxNum(MI) == LegalizerHelper::Legalized; 1602 } 1603 1604 bool AMDGPULegalizerInfo::legalizeExtractVectorElt( 1605 MachineInstr &MI, MachineRegisterInfo &MRI, 1606 MachineIRBuilder &B) const { 1607 // TODO: Should move some of this into LegalizerHelper. 1608 1609 // TODO: Promote dynamic indexing of s16 to s32 1610 // TODO: Dynamic s64 indexing is only legal for SGPR. 1611 Optional<int64_t> IdxVal = getConstantVRegVal(MI.getOperand(2).getReg(), MRI); 1612 if (!IdxVal) // Dynamic case will be selected to register indexing. 1613 return true; 1614 1615 Register Dst = MI.getOperand(0).getReg(); 1616 Register Vec = MI.getOperand(1).getReg(); 1617 1618 LLT VecTy = MRI.getType(Vec); 1619 LLT EltTy = VecTy.getElementType(); 1620 assert(EltTy == MRI.getType(Dst)); 1621 1622 B.setInstr(MI); 1623 1624 if (IdxVal.getValue() < VecTy.getNumElements()) 1625 B.buildExtract(Dst, Vec, IdxVal.getValue() * EltTy.getSizeInBits()); 1626 else 1627 B.buildUndef(Dst); 1628 1629 MI.eraseFromParent(); 1630 return true; 1631 } 1632 1633 bool AMDGPULegalizerInfo::legalizeInsertVectorElt( 1634 MachineInstr &MI, MachineRegisterInfo &MRI, 1635 MachineIRBuilder &B) const { 1636 // TODO: Should move some of this into LegalizerHelper. 1637 1638 // TODO: Promote dynamic indexing of s16 to s32 1639 // TODO: Dynamic s64 indexing is only legal for SGPR. 1640 Optional<int64_t> IdxVal = getConstantVRegVal(MI.getOperand(3).getReg(), MRI); 1641 if (!IdxVal) // Dynamic case will be selected to register indexing. 1642 return true; 1643 1644 Register Dst = MI.getOperand(0).getReg(); 1645 Register Vec = MI.getOperand(1).getReg(); 1646 Register Ins = MI.getOperand(2).getReg(); 1647 1648 LLT VecTy = MRI.getType(Vec); 1649 LLT EltTy = VecTy.getElementType(); 1650 assert(EltTy == MRI.getType(Ins)); 1651 1652 B.setInstr(MI); 1653 1654 if (IdxVal.getValue() < VecTy.getNumElements()) 1655 B.buildInsert(Dst, Vec, Ins, IdxVal.getValue() * EltTy.getSizeInBits()); 1656 else 1657 B.buildUndef(Dst); 1658 1659 MI.eraseFromParent(); 1660 return true; 1661 } 1662 1663 static bool isLegalVOP3PShuffleMask(ArrayRef<int> Mask) { 1664 assert(Mask.size() == 2); 1665 1666 // If one half is undef, the other is trivially in the same reg. 1667 if (Mask[0] == -1 || Mask[1] == -1) 1668 return true; 1669 return ((Mask[0] == 0 || Mask[0] == 1) && (Mask[1] == 0 || Mask[1] == 1)) || 1670 ((Mask[0] == 2 || Mask[0] == 3) && (Mask[1] == 2 || Mask[1] == 3)); 1671 } 1672 1673 bool AMDGPULegalizerInfo::legalizeShuffleVector( 1674 MachineInstr &MI, MachineRegisterInfo &MRI, 1675 MachineIRBuilder &B) const { 1676 const LLT V2S16 = LLT::vector(2, 16); 1677 1678 Register Dst = MI.getOperand(0).getReg(); 1679 Register Src0 = MI.getOperand(1).getReg(); 1680 LLT DstTy = MRI.getType(Dst); 1681 LLT SrcTy = MRI.getType(Src0); 1682 1683 if (SrcTy == V2S16 && DstTy == V2S16 && 1684 isLegalVOP3PShuffleMask(MI.getOperand(3).getShuffleMask())) 1685 return true; 1686 1687 MachineIRBuilder HelperBuilder(MI); 1688 GISelObserverWrapper DummyObserver; 1689 LegalizerHelper Helper(B.getMF(), DummyObserver, HelperBuilder); 1690 HelperBuilder.setInstr(MI); 1691 return Helper.lowerShuffleVector(MI) == LegalizerHelper::Legalized; 1692 } 1693 1694 bool AMDGPULegalizerInfo::legalizeSinCos( 1695 MachineInstr &MI, MachineRegisterInfo &MRI, 1696 MachineIRBuilder &B) const { 1697 B.setInstr(MI); 1698 1699 Register DstReg = MI.getOperand(0).getReg(); 1700 Register SrcReg = MI.getOperand(1).getReg(); 1701 LLT Ty = MRI.getType(DstReg); 1702 unsigned Flags = MI.getFlags(); 1703 1704 Register TrigVal; 1705 auto OneOver2Pi = B.buildFConstant(Ty, 0.5 / M_PI); 1706 if (ST.hasTrigReducedRange()) { 1707 auto MulVal = B.buildFMul(Ty, SrcReg, OneOver2Pi, Flags); 1708 TrigVal = B.buildIntrinsic(Intrinsic::amdgcn_fract, {Ty}, false) 1709 .addUse(MulVal.getReg(0)) 1710 .setMIFlags(Flags).getReg(0); 1711 } else 1712 TrigVal = B.buildFMul(Ty, SrcReg, OneOver2Pi, Flags).getReg(0); 1713 1714 Intrinsic::ID TrigIntrin = MI.getOpcode() == AMDGPU::G_FSIN ? 1715 Intrinsic::amdgcn_sin : Intrinsic::amdgcn_cos; 1716 B.buildIntrinsic(TrigIntrin, makeArrayRef<Register>(DstReg), false) 1717 .addUse(TrigVal) 1718 .setMIFlags(Flags); 1719 MI.eraseFromParent(); 1720 return true; 1721 } 1722 1723 bool AMDGPULegalizerInfo::buildPCRelGlobalAddress( 1724 Register DstReg, LLT PtrTy, 1725 MachineIRBuilder &B, const GlobalValue *GV, 1726 unsigned Offset, unsigned GAFlags) const { 1727 // In order to support pc-relative addressing, SI_PC_ADD_REL_OFFSET is lowered 1728 // to the following code sequence: 1729 // 1730 // For constant address space: 1731 // s_getpc_b64 s[0:1] 1732 // s_add_u32 s0, s0, $symbol 1733 // s_addc_u32 s1, s1, 0 1734 // 1735 // s_getpc_b64 returns the address of the s_add_u32 instruction and then 1736 // a fixup or relocation is emitted to replace $symbol with a literal 1737 // constant, which is a pc-relative offset from the encoding of the $symbol 1738 // operand to the global variable. 1739 // 1740 // For global address space: 1741 // s_getpc_b64 s[0:1] 1742 // s_add_u32 s0, s0, $symbol@{gotpc}rel32@lo 1743 // s_addc_u32 s1, s1, $symbol@{gotpc}rel32@hi 1744 // 1745 // s_getpc_b64 returns the address of the s_add_u32 instruction and then 1746 // fixups or relocations are emitted to replace $symbol@*@lo and 1747 // $symbol@*@hi with lower 32 bits and higher 32 bits of a literal constant, 1748 // which is a 64-bit pc-relative offset from the encoding of the $symbol 1749 // operand to the global variable. 1750 // 1751 // What we want here is an offset from the value returned by s_getpc 1752 // (which is the address of the s_add_u32 instruction) to the global 1753 // variable, but since the encoding of $symbol starts 4 bytes after the start 1754 // of the s_add_u32 instruction, we end up with an offset that is 4 bytes too 1755 // small. This requires us to add 4 to the global variable offset in order to 1756 // compute the correct address. 1757 1758 LLT ConstPtrTy = LLT::pointer(AMDGPUAS::CONSTANT_ADDRESS, 64); 1759 1760 Register PCReg = PtrTy.getSizeInBits() != 32 ? DstReg : 1761 B.getMRI()->createGenericVirtualRegister(ConstPtrTy); 1762 1763 MachineInstrBuilder MIB = B.buildInstr(AMDGPU::SI_PC_ADD_REL_OFFSET) 1764 .addDef(PCReg); 1765 1766 MIB.addGlobalAddress(GV, Offset + 4, GAFlags); 1767 if (GAFlags == SIInstrInfo::MO_NONE) 1768 MIB.addImm(0); 1769 else 1770 MIB.addGlobalAddress(GV, Offset + 4, GAFlags + 1); 1771 1772 B.getMRI()->setRegClass(PCReg, &AMDGPU::SReg_64RegClass); 1773 1774 if (PtrTy.getSizeInBits() == 32) 1775 B.buildExtract(DstReg, PCReg, 0); 1776 return true; 1777 } 1778 1779 bool AMDGPULegalizerInfo::legalizeGlobalValue( 1780 MachineInstr &MI, MachineRegisterInfo &MRI, 1781 MachineIRBuilder &B) const { 1782 Register DstReg = MI.getOperand(0).getReg(); 1783 LLT Ty = MRI.getType(DstReg); 1784 unsigned AS = Ty.getAddressSpace(); 1785 1786 const GlobalValue *GV = MI.getOperand(1).getGlobal(); 1787 MachineFunction &MF = B.getMF(); 1788 SIMachineFunctionInfo *MFI = MF.getInfo<SIMachineFunctionInfo>(); 1789 B.setInstr(MI); 1790 1791 if (AS == AMDGPUAS::LOCAL_ADDRESS || AS == AMDGPUAS::REGION_ADDRESS) { 1792 if (!MFI->isEntryFunction()) { 1793 const Function &Fn = MF.getFunction(); 1794 DiagnosticInfoUnsupported BadLDSDecl( 1795 Fn, "local memory global used by non-kernel function", MI.getDebugLoc()); 1796 Fn.getContext().diagnose(BadLDSDecl); 1797 } 1798 1799 // TODO: We could emit code to handle the initialization somewhere. 1800 if (!AMDGPUTargetLowering::hasDefinedInitializer(GV)) { 1801 const SITargetLowering *TLI = ST.getTargetLowering(); 1802 if (!TLI->shouldUseLDSConstAddress(GV)) { 1803 MI.getOperand(1).setTargetFlags(SIInstrInfo::MO_ABS32_LO); 1804 return true; // Leave in place; 1805 } 1806 1807 B.buildConstant(DstReg, MFI->allocateLDSGlobal(B.getDataLayout(), *GV)); 1808 MI.eraseFromParent(); 1809 return true; 1810 } 1811 1812 const Function &Fn = MF.getFunction(); 1813 DiagnosticInfoUnsupported BadInit( 1814 Fn, "unsupported initializer for address space", MI.getDebugLoc()); 1815 Fn.getContext().diagnose(BadInit); 1816 return true; 1817 } 1818 1819 const SITargetLowering *TLI = ST.getTargetLowering(); 1820 1821 if (TLI->shouldEmitFixup(GV)) { 1822 buildPCRelGlobalAddress(DstReg, Ty, B, GV, 0); 1823 MI.eraseFromParent(); 1824 return true; 1825 } 1826 1827 if (TLI->shouldEmitPCReloc(GV)) { 1828 buildPCRelGlobalAddress(DstReg, Ty, B, GV, 0, SIInstrInfo::MO_REL32); 1829 MI.eraseFromParent(); 1830 return true; 1831 } 1832 1833 LLT PtrTy = LLT::pointer(AMDGPUAS::CONSTANT_ADDRESS, 64); 1834 Register GOTAddr = MRI.createGenericVirtualRegister(PtrTy); 1835 1836 MachineMemOperand *GOTMMO = MF.getMachineMemOperand( 1837 MachinePointerInfo::getGOT(MF), 1838 MachineMemOperand::MOLoad | MachineMemOperand::MODereferenceable | 1839 MachineMemOperand::MOInvariant, 1840 8 /*Size*/, 8 /*Align*/); 1841 1842 buildPCRelGlobalAddress(GOTAddr, PtrTy, B, GV, 0, SIInstrInfo::MO_GOTPCREL32); 1843 1844 if (Ty.getSizeInBits() == 32) { 1845 // Truncate if this is a 32-bit constant adrdess. 1846 auto Load = B.buildLoad(PtrTy, GOTAddr, *GOTMMO); 1847 B.buildExtract(DstReg, Load, 0); 1848 } else 1849 B.buildLoad(DstReg, GOTAddr, *GOTMMO); 1850 1851 MI.eraseFromParent(); 1852 return true; 1853 } 1854 1855 bool AMDGPULegalizerInfo::legalizeLoad( 1856 MachineInstr &MI, MachineRegisterInfo &MRI, 1857 MachineIRBuilder &B, GISelChangeObserver &Observer) const { 1858 B.setInstr(MI); 1859 LLT ConstPtr = LLT::pointer(AMDGPUAS::CONSTANT_ADDRESS, 64); 1860 auto Cast = B.buildAddrSpaceCast(ConstPtr, MI.getOperand(1).getReg()); 1861 Observer.changingInstr(MI); 1862 MI.getOperand(1).setReg(Cast.getReg(0)); 1863 Observer.changedInstr(MI); 1864 return true; 1865 } 1866 1867 bool AMDGPULegalizerInfo::legalizeFMad( 1868 MachineInstr &MI, MachineRegisterInfo &MRI, 1869 MachineIRBuilder &B) const { 1870 LLT Ty = MRI.getType(MI.getOperand(0).getReg()); 1871 assert(Ty.isScalar()); 1872 1873 MachineFunction &MF = B.getMF(); 1874 const SIMachineFunctionInfo *MFI = MF.getInfo<SIMachineFunctionInfo>(); 1875 1876 // TODO: Always legal with future ftz flag. 1877 if (Ty == LLT::scalar(32) && !MFI->getMode().FP32Denormals) 1878 return true; 1879 if (Ty == LLT::scalar(16) && !MFI->getMode().FP64FP16Denormals) 1880 return true; 1881 1882 1883 MachineIRBuilder HelperBuilder(MI); 1884 GISelObserverWrapper DummyObserver; 1885 LegalizerHelper Helper(MF, DummyObserver, HelperBuilder); 1886 HelperBuilder.setMBB(*MI.getParent()); 1887 return Helper.lowerFMad(MI) == LegalizerHelper::Legalized; 1888 } 1889 1890 bool AMDGPULegalizerInfo::legalizeAtomicCmpXChg( 1891 MachineInstr &MI, MachineRegisterInfo &MRI, MachineIRBuilder &B) const { 1892 Register DstReg = MI.getOperand(0).getReg(); 1893 Register PtrReg = MI.getOperand(1).getReg(); 1894 Register CmpVal = MI.getOperand(2).getReg(); 1895 Register NewVal = MI.getOperand(3).getReg(); 1896 1897 assert(SITargetLowering::isFlatGlobalAddrSpace( 1898 MRI.getType(PtrReg).getAddressSpace()) && 1899 "this should not have been custom lowered"); 1900 1901 LLT ValTy = MRI.getType(CmpVal); 1902 LLT VecTy = LLT::vector(2, ValTy); 1903 1904 B.setInstr(MI); 1905 Register PackedVal = B.buildBuildVector(VecTy, { NewVal, CmpVal }).getReg(0); 1906 1907 B.buildInstr(AMDGPU::G_AMDGPU_ATOMIC_CMPXCHG) 1908 .addDef(DstReg) 1909 .addUse(PtrReg) 1910 .addUse(PackedVal) 1911 .setMemRefs(MI.memoperands()); 1912 1913 MI.eraseFromParent(); 1914 return true; 1915 } 1916 1917 bool AMDGPULegalizerInfo::legalizeFlog( 1918 MachineInstr &MI, MachineIRBuilder &B, double Log2BaseInverted) const { 1919 Register Dst = MI.getOperand(0).getReg(); 1920 Register Src = MI.getOperand(1).getReg(); 1921 LLT Ty = B.getMRI()->getType(Dst); 1922 unsigned Flags = MI.getFlags(); 1923 B.setInstr(MI); 1924 1925 auto Log2Operand = B.buildFLog2(Ty, Src, Flags); 1926 auto Log2BaseInvertedOperand = B.buildFConstant(Ty, Log2BaseInverted); 1927 1928 B.buildFMul(Dst, Log2Operand, Log2BaseInvertedOperand, Flags); 1929 MI.eraseFromParent(); 1930 return true; 1931 } 1932 1933 // Return the use branch instruction, otherwise null if the usage is invalid. 1934 static MachineInstr *verifyCFIntrinsic(MachineInstr &MI, 1935 MachineRegisterInfo &MRI, 1936 MachineInstr *&Br) { 1937 Register CondDef = MI.getOperand(0).getReg(); 1938 if (!MRI.hasOneNonDBGUse(CondDef)) 1939 return nullptr; 1940 1941 MachineInstr &UseMI = *MRI.use_instr_nodbg_begin(CondDef); 1942 if (UseMI.getParent() != MI.getParent() || 1943 UseMI.getOpcode() != AMDGPU::G_BRCOND) 1944 return nullptr; 1945 1946 // Make sure the cond br is followed by a G_BR 1947 MachineBasicBlock::iterator Next = std::next(UseMI.getIterator()); 1948 if (Next != MI.getParent()->end()) { 1949 if (Next->getOpcode() != AMDGPU::G_BR) 1950 return nullptr; 1951 Br = &*Next; 1952 } 1953 1954 return &UseMI; 1955 } 1956 1957 Register AMDGPULegalizerInfo::getLiveInRegister(MachineRegisterInfo &MRI, 1958 Register Reg, LLT Ty) const { 1959 Register LiveIn = MRI.getLiveInVirtReg(Reg); 1960 if (LiveIn) 1961 return LiveIn; 1962 1963 Register NewReg = MRI.createGenericVirtualRegister(Ty); 1964 MRI.addLiveIn(Reg, NewReg); 1965 return NewReg; 1966 } 1967 1968 bool AMDGPULegalizerInfo::loadInputValue(Register DstReg, MachineIRBuilder &B, 1969 const ArgDescriptor *Arg) const { 1970 if (!Arg->isRegister() || !Arg->getRegister().isValid()) 1971 return false; // TODO: Handle these 1972 1973 assert(Arg->getRegister().isPhysical()); 1974 1975 MachineRegisterInfo &MRI = *B.getMRI(); 1976 1977 LLT Ty = MRI.getType(DstReg); 1978 Register LiveIn = getLiveInRegister(MRI, Arg->getRegister(), Ty); 1979 1980 if (Arg->isMasked()) { 1981 // TODO: Should we try to emit this once in the entry block? 1982 const LLT S32 = LLT::scalar(32); 1983 const unsigned Mask = Arg->getMask(); 1984 const unsigned Shift = countTrailingZeros<unsigned>(Mask); 1985 1986 Register AndMaskSrc = LiveIn; 1987 1988 if (Shift != 0) { 1989 auto ShiftAmt = B.buildConstant(S32, Shift); 1990 AndMaskSrc = B.buildLShr(S32, LiveIn, ShiftAmt).getReg(0); 1991 } 1992 1993 B.buildAnd(DstReg, AndMaskSrc, B.buildConstant(S32, Mask >> Shift)); 1994 } else 1995 B.buildCopy(DstReg, LiveIn); 1996 1997 // Insert the argument copy if it doens't already exist. 1998 // FIXME: It seems EmitLiveInCopies isn't called anywhere? 1999 if (!MRI.getVRegDef(LiveIn)) { 2000 // FIXME: Should have scoped insert pt 2001 MachineBasicBlock &OrigInsBB = B.getMBB(); 2002 auto OrigInsPt = B.getInsertPt(); 2003 2004 MachineBasicBlock &EntryMBB = B.getMF().front(); 2005 EntryMBB.addLiveIn(Arg->getRegister()); 2006 B.setInsertPt(EntryMBB, EntryMBB.begin()); 2007 B.buildCopy(LiveIn, Arg->getRegister()); 2008 2009 B.setInsertPt(OrigInsBB, OrigInsPt); 2010 } 2011 2012 return true; 2013 } 2014 2015 bool AMDGPULegalizerInfo::legalizePreloadedArgIntrin( 2016 MachineInstr &MI, 2017 MachineRegisterInfo &MRI, 2018 MachineIRBuilder &B, 2019 AMDGPUFunctionArgInfo::PreloadedValue ArgType) const { 2020 B.setInstr(MI); 2021 2022 const SIMachineFunctionInfo *MFI = B.getMF().getInfo<SIMachineFunctionInfo>(); 2023 2024 const ArgDescriptor *Arg; 2025 const TargetRegisterClass *RC; 2026 std::tie(Arg, RC) = MFI->getPreloadedValue(ArgType); 2027 if (!Arg) { 2028 LLVM_DEBUG(dbgs() << "Required arg register missing\n"); 2029 return false; 2030 } 2031 2032 if (loadInputValue(MI.getOperand(0).getReg(), B, Arg)) { 2033 MI.eraseFromParent(); 2034 return true; 2035 } 2036 2037 return false; 2038 } 2039 2040 bool AMDGPULegalizerInfo::legalizeFDIV(MachineInstr &MI, 2041 MachineRegisterInfo &MRI, 2042 MachineIRBuilder &B) const { 2043 B.setInstr(MI); 2044 Register Dst = MI.getOperand(0).getReg(); 2045 LLT DstTy = MRI.getType(Dst); 2046 LLT S16 = LLT::scalar(16); 2047 LLT S32 = LLT::scalar(32); 2048 LLT S64 = LLT::scalar(64); 2049 2050 if (legalizeFastUnsafeFDIV(MI, MRI, B)) 2051 return true; 2052 2053 if (DstTy == S16) 2054 return legalizeFDIV16(MI, MRI, B); 2055 if (DstTy == S32) 2056 return legalizeFDIV32(MI, MRI, B); 2057 if (DstTy == S64) 2058 return legalizeFDIV64(MI, MRI, B); 2059 2060 return false; 2061 } 2062 2063 bool AMDGPULegalizerInfo::legalizeFastUnsafeFDIV(MachineInstr &MI, 2064 MachineRegisterInfo &MRI, 2065 MachineIRBuilder &B) const { 2066 Register Res = MI.getOperand(0).getReg(); 2067 Register LHS = MI.getOperand(1).getReg(); 2068 Register RHS = MI.getOperand(2).getReg(); 2069 2070 uint16_t Flags = MI.getFlags(); 2071 2072 LLT ResTy = MRI.getType(Res); 2073 LLT S32 = LLT::scalar(32); 2074 LLT S64 = LLT::scalar(64); 2075 2076 const MachineFunction &MF = B.getMF(); 2077 bool Unsafe = 2078 MF.getTarget().Options.UnsafeFPMath || MI.getFlag(MachineInstr::FmArcp); 2079 2080 if (!MF.getTarget().Options.UnsafeFPMath && ResTy == S64) 2081 return false; 2082 2083 if (!Unsafe && ResTy == S32 && 2084 MF.getInfo<SIMachineFunctionInfo>()->getMode().FP32Denormals) 2085 return false; 2086 2087 if (auto CLHS = getConstantFPVRegVal(LHS, MRI)) { 2088 // 1 / x -> RCP(x) 2089 if (CLHS->isExactlyValue(1.0)) { 2090 B.buildIntrinsic(Intrinsic::amdgcn_rcp, Res, false) 2091 .addUse(RHS) 2092 .setMIFlags(Flags); 2093 2094 MI.eraseFromParent(); 2095 return true; 2096 } 2097 2098 // -1 / x -> RCP( FNEG(x) ) 2099 if (CLHS->isExactlyValue(-1.0)) { 2100 auto FNeg = B.buildFNeg(ResTy, RHS, Flags); 2101 B.buildIntrinsic(Intrinsic::amdgcn_rcp, Res, false) 2102 .addUse(FNeg.getReg(0)) 2103 .setMIFlags(Flags); 2104 2105 MI.eraseFromParent(); 2106 return true; 2107 } 2108 } 2109 2110 // x / y -> x * (1.0 / y) 2111 if (Unsafe) { 2112 auto RCP = B.buildIntrinsic(Intrinsic::amdgcn_rcp, {ResTy}, false) 2113 .addUse(RHS) 2114 .setMIFlags(Flags); 2115 B.buildFMul(Res, LHS, RCP, Flags); 2116 2117 MI.eraseFromParent(); 2118 return true; 2119 } 2120 2121 return false; 2122 } 2123 2124 bool AMDGPULegalizerInfo::legalizeFDIV16(MachineInstr &MI, 2125 MachineRegisterInfo &MRI, 2126 MachineIRBuilder &B) const { 2127 B.setInstr(MI); 2128 Register Res = MI.getOperand(0).getReg(); 2129 Register LHS = MI.getOperand(1).getReg(); 2130 Register RHS = MI.getOperand(2).getReg(); 2131 2132 uint16_t Flags = MI.getFlags(); 2133 2134 LLT S16 = LLT::scalar(16); 2135 LLT S32 = LLT::scalar(32); 2136 2137 auto LHSExt = B.buildFPExt(S32, LHS, Flags); 2138 auto RHSExt = B.buildFPExt(S32, RHS, Flags); 2139 2140 auto RCP = B.buildIntrinsic(Intrinsic::amdgcn_rcp, {S32}, false) 2141 .addUse(RHSExt.getReg(0)) 2142 .setMIFlags(Flags); 2143 2144 auto QUOT = B.buildFMul(S32, LHSExt, RCP, Flags); 2145 auto RDst = B.buildFPTrunc(S16, QUOT, Flags); 2146 2147 B.buildIntrinsic(Intrinsic::amdgcn_div_fixup, Res, false) 2148 .addUse(RDst.getReg(0)) 2149 .addUse(RHS) 2150 .addUse(LHS) 2151 .setMIFlags(Flags); 2152 2153 MI.eraseFromParent(); 2154 return true; 2155 } 2156 2157 // Enable or disable FP32 denorm mode. When 'Enable' is true, emit instructions 2158 // to enable denorm mode. When 'Enable' is false, disable denorm mode. 2159 static void toggleSPDenormMode(bool Enable, 2160 MachineIRBuilder &B, 2161 const GCNSubtarget &ST, 2162 AMDGPU::SIModeRegisterDefaults Mode) { 2163 // Set SP denorm mode to this value. 2164 unsigned SPDenormMode = 2165 Enable ? FP_DENORM_FLUSH_NONE : FP_DENORM_FLUSH_IN_FLUSH_OUT; 2166 2167 if (ST.hasDenormModeInst()) { 2168 // Preserve default FP64FP16 denorm mode while updating FP32 mode. 2169 unsigned DPDenormModeDefault = Mode.FP64FP16Denormals 2170 ? FP_DENORM_FLUSH_NONE 2171 : FP_DENORM_FLUSH_IN_FLUSH_OUT; 2172 2173 unsigned NewDenormModeValue = SPDenormMode | (DPDenormModeDefault << 2); 2174 B.buildInstr(AMDGPU::S_DENORM_MODE) 2175 .addImm(NewDenormModeValue); 2176 2177 } else { 2178 // Select FP32 bit field in mode register. 2179 unsigned SPDenormModeBitField = AMDGPU::Hwreg::ID_MODE | 2180 (4 << AMDGPU::Hwreg::OFFSET_SHIFT_) | 2181 (1 << AMDGPU::Hwreg::WIDTH_M1_SHIFT_); 2182 2183 B.buildInstr(AMDGPU::S_SETREG_IMM32_B32) 2184 .addImm(SPDenormMode) 2185 .addImm(SPDenormModeBitField); 2186 } 2187 } 2188 2189 bool AMDGPULegalizerInfo::legalizeFDIV32(MachineInstr &MI, 2190 MachineRegisterInfo &MRI, 2191 MachineIRBuilder &B) const { 2192 B.setInstr(MI); 2193 Register Res = MI.getOperand(0).getReg(); 2194 Register LHS = MI.getOperand(1).getReg(); 2195 Register RHS = MI.getOperand(2).getReg(); 2196 const SIMachineFunctionInfo *MFI = B.getMF().getInfo<SIMachineFunctionInfo>(); 2197 AMDGPU::SIModeRegisterDefaults Mode = MFI->getMode(); 2198 2199 uint16_t Flags = MI.getFlags(); 2200 2201 LLT S32 = LLT::scalar(32); 2202 LLT S1 = LLT::scalar(1); 2203 2204 auto One = B.buildFConstant(S32, 1.0f); 2205 2206 auto DenominatorScaled = 2207 B.buildIntrinsic(Intrinsic::amdgcn_div_scale, {S32, S1}, false) 2208 .addUse(RHS) 2209 .addUse(LHS) 2210 .addImm(1) 2211 .setMIFlags(Flags); 2212 auto NumeratorScaled = 2213 B.buildIntrinsic(Intrinsic::amdgcn_div_scale, {S32, S1}, false) 2214 .addUse(LHS) 2215 .addUse(RHS) 2216 .addImm(0) 2217 .setMIFlags(Flags); 2218 2219 auto ApproxRcp = B.buildIntrinsic(Intrinsic::amdgcn_rcp, {S32}, false) 2220 .addUse(DenominatorScaled.getReg(0)) 2221 .setMIFlags(Flags); 2222 auto NegDivScale0 = B.buildFNeg(S32, DenominatorScaled, Flags); 2223 2224 // FIXME: Doesn't correctly model the FP mode switch, and the FP operations 2225 // aren't modeled as reading it. 2226 if (!Mode.FP32Denormals) 2227 toggleSPDenormMode(true, B, ST, Mode); 2228 2229 auto Fma0 = B.buildFMA(S32, NegDivScale0, ApproxRcp, One, Flags); 2230 auto Fma1 = B.buildFMA(S32, Fma0, ApproxRcp, ApproxRcp, Flags); 2231 auto Mul = B.buildFMul(S32, NumeratorScaled, Fma1, Flags); 2232 auto Fma2 = B.buildFMA(S32, NegDivScale0, Mul, NumeratorScaled, Flags); 2233 auto Fma3 = B.buildFMA(S32, Fma2, Fma1, Mul, Flags); 2234 auto Fma4 = B.buildFMA(S32, NegDivScale0, Fma3, NumeratorScaled, Flags); 2235 2236 if (!Mode.FP32Denormals) 2237 toggleSPDenormMode(false, B, ST, Mode); 2238 2239 auto Fmas = B.buildIntrinsic(Intrinsic::amdgcn_div_fmas, {S32}, false) 2240 .addUse(Fma4.getReg(0)) 2241 .addUse(Fma1.getReg(0)) 2242 .addUse(Fma3.getReg(0)) 2243 .addUse(NumeratorScaled.getReg(1)) 2244 .setMIFlags(Flags); 2245 2246 B.buildIntrinsic(Intrinsic::amdgcn_div_fixup, Res, false) 2247 .addUse(Fmas.getReg(0)) 2248 .addUse(RHS) 2249 .addUse(LHS) 2250 .setMIFlags(Flags); 2251 2252 MI.eraseFromParent(); 2253 return true; 2254 } 2255 2256 bool AMDGPULegalizerInfo::legalizeFDIV64(MachineInstr &MI, 2257 MachineRegisterInfo &MRI, 2258 MachineIRBuilder &B) const { 2259 B.setInstr(MI); 2260 Register Res = MI.getOperand(0).getReg(); 2261 Register LHS = MI.getOperand(1).getReg(); 2262 Register RHS = MI.getOperand(2).getReg(); 2263 2264 uint16_t Flags = MI.getFlags(); 2265 2266 LLT S64 = LLT::scalar(64); 2267 LLT S1 = LLT::scalar(1); 2268 2269 auto One = B.buildFConstant(S64, 1.0); 2270 2271 auto DivScale0 = B.buildIntrinsic(Intrinsic::amdgcn_div_scale, {S64, S1}, false) 2272 .addUse(LHS) 2273 .addUse(RHS) 2274 .addImm(1) 2275 .setMIFlags(Flags); 2276 2277 auto NegDivScale0 = B.buildFNeg(S64, DivScale0.getReg(0), Flags); 2278 2279 auto Rcp = B.buildIntrinsic(Intrinsic::amdgcn_rcp, {S64}, false) 2280 .addUse(DivScale0.getReg(0)) 2281 .setMIFlags(Flags); 2282 2283 auto Fma0 = B.buildFMA(S64, NegDivScale0, Rcp, One, Flags); 2284 auto Fma1 = B.buildFMA(S64, Rcp, Fma0, Rcp, Flags); 2285 auto Fma2 = B.buildFMA(S64, NegDivScale0, Fma1, One, Flags); 2286 2287 auto DivScale1 = B.buildIntrinsic(Intrinsic::amdgcn_div_scale, {S64, S1}, false) 2288 .addUse(LHS) 2289 .addUse(RHS) 2290 .addImm(0) 2291 .setMIFlags(Flags); 2292 2293 auto Fma3 = B.buildFMA(S64, Fma1, Fma2, Fma1, Flags); 2294 auto Mul = B.buildMul(S64, DivScale1.getReg(0), Fma3, Flags); 2295 auto Fma4 = B.buildFMA(S64, NegDivScale0, Mul, DivScale1.getReg(0), Flags); 2296 2297 Register Scale; 2298 if (!ST.hasUsableDivScaleConditionOutput()) { 2299 // Workaround a hardware bug on SI where the condition output from div_scale 2300 // is not usable. 2301 2302 LLT S32 = LLT::scalar(32); 2303 2304 auto NumUnmerge = B.buildUnmerge(S32, LHS); 2305 auto DenUnmerge = B.buildUnmerge(S32, RHS); 2306 auto Scale0Unmerge = B.buildUnmerge(S32, DivScale0); 2307 auto Scale1Unmerge = B.buildUnmerge(S32, DivScale1); 2308 2309 auto CmpNum = B.buildICmp(ICmpInst::ICMP_EQ, S1, NumUnmerge.getReg(1), 2310 Scale1Unmerge.getReg(1)); 2311 auto CmpDen = B.buildICmp(ICmpInst::ICMP_EQ, S1, DenUnmerge.getReg(1), 2312 Scale0Unmerge.getReg(1)); 2313 Scale = B.buildXor(S1, CmpNum, CmpDen).getReg(0); 2314 } else { 2315 Scale = DivScale1.getReg(1); 2316 } 2317 2318 auto Fmas = B.buildIntrinsic(Intrinsic::amdgcn_div_fmas, {S64}, false) 2319 .addUse(Fma4.getReg(0)) 2320 .addUse(Fma3.getReg(0)) 2321 .addUse(Mul.getReg(0)) 2322 .addUse(Scale) 2323 .setMIFlags(Flags); 2324 2325 B.buildIntrinsic(Intrinsic::amdgcn_div_fixup, makeArrayRef(Res), false) 2326 .addUse(Fmas.getReg(0)) 2327 .addUse(RHS) 2328 .addUse(LHS) 2329 .setMIFlags(Flags); 2330 2331 MI.eraseFromParent(); 2332 return true; 2333 } 2334 2335 bool AMDGPULegalizerInfo::legalizeFDIVFastIntrin(MachineInstr &MI, 2336 MachineRegisterInfo &MRI, 2337 MachineIRBuilder &B) const { 2338 B.setInstr(MI); 2339 Register Res = MI.getOperand(0).getReg(); 2340 Register LHS = MI.getOperand(2).getReg(); 2341 Register RHS = MI.getOperand(3).getReg(); 2342 uint16_t Flags = MI.getFlags(); 2343 2344 LLT S32 = LLT::scalar(32); 2345 LLT S1 = LLT::scalar(1); 2346 2347 auto Abs = B.buildFAbs(S32, RHS, Flags); 2348 const APFloat C0Val(1.0f); 2349 2350 auto C0 = B.buildConstant(S32, 0x6f800000); 2351 auto C1 = B.buildConstant(S32, 0x2f800000); 2352 auto C2 = B.buildConstant(S32, FloatToBits(1.0f)); 2353 2354 auto CmpRes = B.buildFCmp(CmpInst::FCMP_OGT, S1, Abs, C0, Flags); 2355 auto Sel = B.buildSelect(S32, CmpRes, C1, C2, Flags); 2356 2357 auto Mul0 = B.buildFMul(S32, RHS, Sel, Flags); 2358 2359 auto RCP = B.buildIntrinsic(Intrinsic::amdgcn_rcp, {S32}, false) 2360 .addUse(Mul0.getReg(0)) 2361 .setMIFlags(Flags); 2362 2363 auto Mul1 = B.buildFMul(S32, LHS, RCP, Flags); 2364 2365 B.buildFMul(Res, Sel, Mul1, Flags); 2366 2367 MI.eraseFromParent(); 2368 return true; 2369 } 2370 2371 bool AMDGPULegalizerInfo::legalizeImplicitArgPtr(MachineInstr &MI, 2372 MachineRegisterInfo &MRI, 2373 MachineIRBuilder &B) const { 2374 const SIMachineFunctionInfo *MFI = B.getMF().getInfo<SIMachineFunctionInfo>(); 2375 if (!MFI->isEntryFunction()) { 2376 return legalizePreloadedArgIntrin(MI, MRI, B, 2377 AMDGPUFunctionArgInfo::IMPLICIT_ARG_PTR); 2378 } 2379 2380 B.setInstr(MI); 2381 2382 uint64_t Offset = 2383 ST.getTargetLowering()->getImplicitParameterOffset( 2384 B.getMF(), AMDGPUTargetLowering::FIRST_IMPLICIT); 2385 Register DstReg = MI.getOperand(0).getReg(); 2386 LLT DstTy = MRI.getType(DstReg); 2387 LLT IdxTy = LLT::scalar(DstTy.getSizeInBits()); 2388 2389 const ArgDescriptor *Arg; 2390 const TargetRegisterClass *RC; 2391 std::tie(Arg, RC) 2392 = MFI->getPreloadedValue(AMDGPUFunctionArgInfo::KERNARG_SEGMENT_PTR); 2393 if (!Arg) 2394 return false; 2395 2396 Register KernargPtrReg = MRI.createGenericVirtualRegister(DstTy); 2397 if (!loadInputValue(KernargPtrReg, B, Arg)) 2398 return false; 2399 2400 B.buildPtrAdd(DstReg, KernargPtrReg, B.buildConstant(IdxTy, Offset).getReg(0)); 2401 MI.eraseFromParent(); 2402 return true; 2403 } 2404 2405 bool AMDGPULegalizerInfo::legalizeIsAddrSpace(MachineInstr &MI, 2406 MachineRegisterInfo &MRI, 2407 MachineIRBuilder &B, 2408 unsigned AddrSpace) const { 2409 B.setInstr(MI); 2410 Register ApertureReg = getSegmentAperture(AddrSpace, MRI, B); 2411 auto Hi32 = B.buildExtract(LLT::scalar(32), MI.getOperand(2).getReg(), 32); 2412 B.buildICmp(ICmpInst::ICMP_EQ, MI.getOperand(0), Hi32, ApertureReg); 2413 MI.eraseFromParent(); 2414 return true; 2415 } 2416 2417 // The raw.(t)buffer and struct.(t)buffer intrinsics have two offset args: 2418 // offset (the offset that is included in bounds checking and swizzling, to be 2419 // split between the instruction's voffset and immoffset fields) and soffset 2420 // (the offset that is excluded from bounds checking and swizzling, to go in 2421 // the instruction's soffset field). This function takes the first kind of 2422 // offset and figures out how to split it between voffset and immoffset. 2423 std::tuple<Register, unsigned, unsigned> 2424 AMDGPULegalizerInfo::splitBufferOffsets(MachineIRBuilder &B, 2425 Register OrigOffset) const { 2426 const unsigned MaxImm = 4095; 2427 Register BaseReg; 2428 unsigned TotalConstOffset; 2429 MachineInstr *OffsetDef; 2430 const LLT S32 = LLT::scalar(32); 2431 2432 std::tie(BaseReg, TotalConstOffset, OffsetDef) 2433 = AMDGPU::getBaseWithConstantOffset(*B.getMRI(), OrigOffset); 2434 2435 unsigned ImmOffset = TotalConstOffset; 2436 2437 // If the immediate value is too big for the immoffset field, put the value 2438 // and -4096 into the immoffset field so that the value that is copied/added 2439 // for the voffset field is a multiple of 4096, and it stands more chance 2440 // of being CSEd with the copy/add for another similar load/store. 2441 // However, do not do that rounding down to a multiple of 4096 if that is a 2442 // negative number, as it appears to be illegal to have a negative offset 2443 // in the vgpr, even if adding the immediate offset makes it positive. 2444 unsigned Overflow = ImmOffset & ~MaxImm; 2445 ImmOffset -= Overflow; 2446 if ((int32_t)Overflow < 0) { 2447 Overflow += ImmOffset; 2448 ImmOffset = 0; 2449 } 2450 2451 if (Overflow != 0) { 2452 if (!BaseReg) { 2453 BaseReg = B.buildConstant(S32, Overflow).getReg(0); 2454 } else { 2455 auto OverflowVal = B.buildConstant(S32, Overflow); 2456 BaseReg = B.buildAdd(S32, BaseReg, OverflowVal).getReg(0); 2457 } 2458 } 2459 2460 if (!BaseReg) 2461 BaseReg = B.buildConstant(S32, 0).getReg(0); 2462 2463 return std::make_tuple(BaseReg, ImmOffset, TotalConstOffset); 2464 } 2465 2466 /// Handle register layout difference for f16 images for some subtargets. 2467 Register AMDGPULegalizerInfo::handleD16VData(MachineIRBuilder &B, 2468 MachineRegisterInfo &MRI, 2469 Register Reg) const { 2470 if (!ST.hasUnpackedD16VMem()) 2471 return Reg; 2472 2473 const LLT S16 = LLT::scalar(16); 2474 const LLT S32 = LLT::scalar(32); 2475 LLT StoreVT = MRI.getType(Reg); 2476 assert(StoreVT.isVector() && StoreVT.getElementType() == S16); 2477 2478 auto Unmerge = B.buildUnmerge(S16, Reg); 2479 2480 SmallVector<Register, 4> WideRegs; 2481 for (int I = 0, E = Unmerge->getNumOperands() - 1; I != E; ++I) 2482 WideRegs.push_back(B.buildAnyExt(S32, Unmerge.getReg(I)).getReg(0)); 2483 2484 int NumElts = StoreVT.getNumElements(); 2485 2486 return B.buildBuildVector(LLT::vector(NumElts, S32), WideRegs).getReg(0); 2487 } 2488 2489 Register AMDGPULegalizerInfo::fixStoreSourceType( 2490 MachineIRBuilder &B, Register VData, bool IsFormat) const { 2491 MachineRegisterInfo *MRI = B.getMRI(); 2492 LLT Ty = MRI->getType(VData); 2493 2494 const LLT S16 = LLT::scalar(16); 2495 2496 // Fixup illegal register types for i8 stores. 2497 if (Ty == LLT::scalar(8) || Ty == S16) { 2498 Register AnyExt = B.buildAnyExt(LLT::scalar(32), VData).getReg(0); 2499 return AnyExt; 2500 } 2501 2502 if (Ty.isVector()) { 2503 if (Ty.getElementType() == S16 && Ty.getNumElements() <= 4) { 2504 if (IsFormat) 2505 return handleD16VData(B, *MRI, VData); 2506 } 2507 } 2508 2509 return VData; 2510 } 2511 2512 bool AMDGPULegalizerInfo::legalizeBufferStore(MachineInstr &MI, 2513 MachineRegisterInfo &MRI, 2514 MachineIRBuilder &B, 2515 bool IsTyped, 2516 bool IsFormat) const { 2517 B.setInstr(MI); 2518 2519 Register VData = MI.getOperand(1).getReg(); 2520 LLT Ty = MRI.getType(VData); 2521 LLT EltTy = Ty.getScalarType(); 2522 const bool IsD16 = IsFormat && (EltTy.getSizeInBits() == 16); 2523 const LLT S32 = LLT::scalar(32); 2524 2525 VData = fixStoreSourceType(B, VData, IsFormat); 2526 Register RSrc = MI.getOperand(2).getReg(); 2527 2528 MachineMemOperand *MMO = *MI.memoperands_begin(); 2529 const int MemSize = MMO->getSize(); 2530 2531 unsigned ImmOffset; 2532 unsigned TotalOffset; 2533 2534 // The typed intrinsics add an immediate after the registers. 2535 const unsigned NumVIndexOps = IsTyped ? 8 : 7; 2536 2537 // The struct intrinsic variants add one additional operand over raw. 2538 const bool HasVIndex = MI.getNumOperands() == NumVIndexOps; 2539 Register VIndex; 2540 int OpOffset = 0; 2541 if (HasVIndex) { 2542 VIndex = MI.getOperand(3).getReg(); 2543 OpOffset = 1; 2544 } 2545 2546 Register VOffset = MI.getOperand(3 + OpOffset).getReg(); 2547 Register SOffset = MI.getOperand(4 + OpOffset).getReg(); 2548 2549 unsigned Format = 0; 2550 if (IsTyped) { 2551 Format = MI.getOperand(5 + OpOffset).getImm(); 2552 ++OpOffset; 2553 } 2554 2555 unsigned AuxiliaryData = MI.getOperand(5 + OpOffset).getImm(); 2556 2557 std::tie(VOffset, ImmOffset, TotalOffset) = splitBufferOffsets(B, VOffset); 2558 if (TotalOffset != 0) 2559 MMO = B.getMF().getMachineMemOperand(MMO, TotalOffset, MemSize); 2560 2561 unsigned Opc; 2562 if (IsTyped) { 2563 Opc = IsD16 ? AMDGPU::G_AMDGPU_TBUFFER_STORE_FORMAT_D16 : 2564 AMDGPU::G_AMDGPU_TBUFFER_STORE_FORMAT; 2565 } else if (IsFormat) { 2566 Opc = IsD16 ? AMDGPU::G_AMDGPU_BUFFER_STORE_FORMAT_D16 : 2567 AMDGPU::G_AMDGPU_BUFFER_STORE_FORMAT; 2568 } else { 2569 switch (MemSize) { 2570 case 1: 2571 Opc = AMDGPU::G_AMDGPU_BUFFER_STORE_BYTE; 2572 break; 2573 case 2: 2574 Opc = AMDGPU::G_AMDGPU_BUFFER_STORE_SHORT; 2575 break; 2576 default: 2577 Opc = AMDGPU::G_AMDGPU_BUFFER_STORE; 2578 break; 2579 } 2580 } 2581 2582 if (!VIndex) 2583 VIndex = B.buildConstant(S32, 0).getReg(0); 2584 2585 auto MIB = B.buildInstr(Opc) 2586 .addUse(VData) // vdata 2587 .addUse(RSrc) // rsrc 2588 .addUse(VIndex) // vindex 2589 .addUse(VOffset) // voffset 2590 .addUse(SOffset) // soffset 2591 .addImm(ImmOffset); // offset(imm) 2592 2593 if (IsTyped) 2594 MIB.addImm(Format); 2595 2596 MIB.addImm(AuxiliaryData) // cachepolicy, swizzled buffer(imm) 2597 .addImm(HasVIndex ? -1 : 0) // idxen(imm) 2598 .addMemOperand(MMO); 2599 2600 MI.eraseFromParent(); 2601 return true; 2602 } 2603 2604 bool AMDGPULegalizerInfo::legalizeBufferLoad(MachineInstr &MI, 2605 MachineRegisterInfo &MRI, 2606 MachineIRBuilder &B, 2607 bool IsFormat, 2608 bool IsTyped) const { 2609 B.setInstr(MI); 2610 2611 // FIXME: Verifier should enforce 1 MMO for these intrinsics. 2612 MachineMemOperand *MMO = *MI.memoperands_begin(); 2613 const int MemSize = MMO->getSize(); 2614 const LLT S32 = LLT::scalar(32); 2615 2616 Register Dst = MI.getOperand(0).getReg(); 2617 Register RSrc = MI.getOperand(2).getReg(); 2618 2619 // The typed intrinsics add an immediate after the registers. 2620 const unsigned NumVIndexOps = IsTyped ? 8 : 7; 2621 2622 // The struct intrinsic variants add one additional operand over raw. 2623 const bool HasVIndex = MI.getNumOperands() == NumVIndexOps; 2624 Register VIndex; 2625 int OpOffset = 0; 2626 if (HasVIndex) { 2627 VIndex = MI.getOperand(3).getReg(); 2628 OpOffset = 1; 2629 } 2630 2631 Register VOffset = MI.getOperand(3 + OpOffset).getReg(); 2632 Register SOffset = MI.getOperand(4 + OpOffset).getReg(); 2633 2634 unsigned Format = 0; 2635 if (IsTyped) { 2636 Format = MI.getOperand(5 + OpOffset).getImm(); 2637 ++OpOffset; 2638 } 2639 2640 unsigned AuxiliaryData = MI.getOperand(5 + OpOffset).getImm(); 2641 unsigned ImmOffset; 2642 unsigned TotalOffset; 2643 2644 LLT Ty = MRI.getType(Dst); 2645 LLT EltTy = Ty.getScalarType(); 2646 const bool IsD16 = IsFormat && (EltTy.getSizeInBits() == 16); 2647 const bool Unpacked = ST.hasUnpackedD16VMem(); 2648 2649 std::tie(VOffset, ImmOffset, TotalOffset) = splitBufferOffsets(B, VOffset); 2650 if (TotalOffset != 0) 2651 MMO = B.getMF().getMachineMemOperand(MMO, TotalOffset, MemSize); 2652 2653 unsigned Opc; 2654 2655 if (IsTyped) { 2656 Opc = IsD16 ? AMDGPU::G_AMDGPU_TBUFFER_LOAD_FORMAT_D16 : 2657 AMDGPU::G_AMDGPU_TBUFFER_LOAD_FORMAT; 2658 } else if (IsFormat) { 2659 Opc = IsD16 ? AMDGPU::G_AMDGPU_BUFFER_LOAD_FORMAT_D16 : 2660 AMDGPU::G_AMDGPU_BUFFER_LOAD_FORMAT; 2661 } else { 2662 switch (MemSize) { 2663 case 1: 2664 Opc = AMDGPU::G_AMDGPU_BUFFER_LOAD_UBYTE; 2665 break; 2666 case 2: 2667 Opc = AMDGPU::G_AMDGPU_BUFFER_LOAD_USHORT; 2668 break; 2669 default: 2670 Opc = AMDGPU::G_AMDGPU_BUFFER_LOAD; 2671 break; 2672 } 2673 } 2674 2675 Register LoadDstReg; 2676 2677 bool IsExtLoad = (!IsD16 && MemSize < 4) || (IsD16 && !Ty.isVector()); 2678 LLT UnpackedTy = Ty.changeElementSize(32); 2679 2680 if (IsExtLoad) 2681 LoadDstReg = B.getMRI()->createGenericVirtualRegister(S32); 2682 else if (Unpacked && IsD16 && Ty.isVector()) 2683 LoadDstReg = B.getMRI()->createGenericVirtualRegister(UnpackedTy); 2684 else 2685 LoadDstReg = Dst; 2686 2687 if (!VIndex) 2688 VIndex = B.buildConstant(S32, 0).getReg(0); 2689 2690 auto MIB = B.buildInstr(Opc) 2691 .addDef(LoadDstReg) // vdata 2692 .addUse(RSrc) // rsrc 2693 .addUse(VIndex) // vindex 2694 .addUse(VOffset) // voffset 2695 .addUse(SOffset) // soffset 2696 .addImm(ImmOffset); // offset(imm) 2697 2698 if (IsTyped) 2699 MIB.addImm(Format); 2700 2701 MIB.addImm(AuxiliaryData) // cachepolicy, swizzled buffer(imm) 2702 .addImm(HasVIndex ? -1 : 0) // idxen(imm) 2703 .addMemOperand(MMO); 2704 2705 if (LoadDstReg != Dst) { 2706 B.setInsertPt(B.getMBB(), ++B.getInsertPt()); 2707 2708 // Widen result for extending loads was widened. 2709 if (IsExtLoad) 2710 B.buildTrunc(Dst, LoadDstReg); 2711 else { 2712 // Repack to original 16-bit vector result 2713 // FIXME: G_TRUNC should work, but legalization currently fails 2714 auto Unmerge = B.buildUnmerge(S32, LoadDstReg); 2715 SmallVector<Register, 4> Repack; 2716 for (unsigned I = 0, N = Unmerge->getNumOperands() - 1; I != N; ++I) 2717 Repack.push_back(B.buildTrunc(EltTy, Unmerge.getReg(I)).getReg(0)); 2718 B.buildMerge(Dst, Repack); 2719 } 2720 } 2721 2722 MI.eraseFromParent(); 2723 return true; 2724 } 2725 2726 bool AMDGPULegalizerInfo::legalizeAtomicIncDec(MachineInstr &MI, 2727 MachineIRBuilder &B, 2728 bool IsInc) const { 2729 B.setInstr(MI); 2730 unsigned Opc = IsInc ? AMDGPU::G_AMDGPU_ATOMIC_INC : 2731 AMDGPU::G_AMDGPU_ATOMIC_DEC; 2732 B.buildInstr(Opc) 2733 .addDef(MI.getOperand(0).getReg()) 2734 .addUse(MI.getOperand(2).getReg()) 2735 .addUse(MI.getOperand(3).getReg()) 2736 .cloneMemRefs(MI); 2737 MI.eraseFromParent(); 2738 return true; 2739 } 2740 2741 static unsigned getBufferAtomicPseudo(Intrinsic::ID IntrID) { 2742 switch (IntrID) { 2743 case Intrinsic::amdgcn_raw_buffer_atomic_swap: 2744 case Intrinsic::amdgcn_struct_buffer_atomic_swap: 2745 return AMDGPU::G_AMDGPU_BUFFER_ATOMIC_SWAP; 2746 case Intrinsic::amdgcn_raw_buffer_atomic_add: 2747 case Intrinsic::amdgcn_struct_buffer_atomic_add: 2748 return AMDGPU::G_AMDGPU_BUFFER_ATOMIC_ADD; 2749 case Intrinsic::amdgcn_raw_buffer_atomic_sub: 2750 case Intrinsic::amdgcn_struct_buffer_atomic_sub: 2751 return AMDGPU::G_AMDGPU_BUFFER_ATOMIC_SUB; 2752 case Intrinsic::amdgcn_raw_buffer_atomic_smin: 2753 case Intrinsic::amdgcn_struct_buffer_atomic_smin: 2754 return AMDGPU::G_AMDGPU_BUFFER_ATOMIC_SMIN; 2755 case Intrinsic::amdgcn_raw_buffer_atomic_umin: 2756 case Intrinsic::amdgcn_struct_buffer_atomic_umin: 2757 return AMDGPU::G_AMDGPU_BUFFER_ATOMIC_UMIN; 2758 case Intrinsic::amdgcn_raw_buffer_atomic_smax: 2759 case Intrinsic::amdgcn_struct_buffer_atomic_smax: 2760 return AMDGPU::G_AMDGPU_BUFFER_ATOMIC_SMAX; 2761 case Intrinsic::amdgcn_raw_buffer_atomic_umax: 2762 case Intrinsic::amdgcn_struct_buffer_atomic_umax: 2763 return AMDGPU::G_AMDGPU_BUFFER_ATOMIC_UMAX; 2764 case Intrinsic::amdgcn_raw_buffer_atomic_and: 2765 case Intrinsic::amdgcn_struct_buffer_atomic_and: 2766 return AMDGPU::G_AMDGPU_BUFFER_ATOMIC_AND; 2767 case Intrinsic::amdgcn_raw_buffer_atomic_or: 2768 case Intrinsic::amdgcn_struct_buffer_atomic_or: 2769 return AMDGPU::G_AMDGPU_BUFFER_ATOMIC_OR; 2770 case Intrinsic::amdgcn_raw_buffer_atomic_xor: 2771 case Intrinsic::amdgcn_struct_buffer_atomic_xor: 2772 return AMDGPU::G_AMDGPU_BUFFER_ATOMIC_XOR; 2773 case Intrinsic::amdgcn_raw_buffer_atomic_inc: 2774 case Intrinsic::amdgcn_struct_buffer_atomic_inc: 2775 return AMDGPU::G_AMDGPU_BUFFER_ATOMIC_INC; 2776 case Intrinsic::amdgcn_raw_buffer_atomic_dec: 2777 case Intrinsic::amdgcn_struct_buffer_atomic_dec: 2778 return AMDGPU::G_AMDGPU_BUFFER_ATOMIC_DEC; 2779 case Intrinsic::amdgcn_raw_buffer_atomic_cmpswap: 2780 case Intrinsic::amdgcn_struct_buffer_atomic_cmpswap: 2781 return AMDGPU::G_AMDGPU_BUFFER_ATOMIC_CMPSWAP; 2782 default: 2783 llvm_unreachable("unhandled atomic opcode"); 2784 } 2785 } 2786 2787 bool AMDGPULegalizerInfo::legalizeBufferAtomic(MachineInstr &MI, 2788 MachineIRBuilder &B, 2789 Intrinsic::ID IID) const { 2790 B.setInstr(MI); 2791 2792 const bool IsCmpSwap = IID == Intrinsic::amdgcn_raw_buffer_atomic_cmpswap || 2793 IID == Intrinsic::amdgcn_struct_buffer_atomic_cmpswap; 2794 2795 Register Dst = MI.getOperand(0).getReg(); 2796 Register VData = MI.getOperand(2).getReg(); 2797 2798 Register CmpVal; 2799 int OpOffset = 0; 2800 2801 if (IsCmpSwap) { 2802 CmpVal = MI.getOperand(3 + OpOffset).getReg(); 2803 ++OpOffset; 2804 } 2805 2806 Register RSrc = MI.getOperand(3 + OpOffset).getReg(); 2807 const unsigned NumVIndexOps = IsCmpSwap ? 9 : 8; 2808 2809 // The struct intrinsic variants add one additional operand over raw. 2810 const bool HasVIndex = MI.getNumOperands() == NumVIndexOps; 2811 Register VIndex; 2812 if (HasVIndex) { 2813 VIndex = MI.getOperand(4 + OpOffset).getReg(); 2814 ++OpOffset; 2815 } 2816 2817 Register VOffset = MI.getOperand(4 + OpOffset).getReg(); 2818 Register SOffset = MI.getOperand(5 + OpOffset).getReg(); 2819 unsigned AuxiliaryData = MI.getOperand(6 + OpOffset).getImm(); 2820 2821 MachineMemOperand *MMO = *MI.memoperands_begin(); 2822 2823 unsigned ImmOffset; 2824 unsigned TotalOffset; 2825 std::tie(VOffset, ImmOffset, TotalOffset) = splitBufferOffsets(B, VOffset); 2826 if (TotalOffset != 0) 2827 MMO = B.getMF().getMachineMemOperand(MMO, TotalOffset, MMO->getSize()); 2828 2829 if (!VIndex) 2830 VIndex = B.buildConstant(LLT::scalar(32), 0).getReg(0); 2831 2832 auto MIB = B.buildInstr(getBufferAtomicPseudo(IID)) 2833 .addDef(Dst) 2834 .addUse(VData); // vdata 2835 2836 if (IsCmpSwap) 2837 MIB.addReg(CmpVal); 2838 2839 MIB.addUse(RSrc) // rsrc 2840 .addUse(VIndex) // vindex 2841 .addUse(VOffset) // voffset 2842 .addUse(SOffset) // soffset 2843 .addImm(ImmOffset) // offset(imm) 2844 .addImm(AuxiliaryData) // cachepolicy, swizzled buffer(imm) 2845 .addImm(HasVIndex ? -1 : 0) // idxen(imm) 2846 .addMemOperand(MMO); 2847 2848 MI.eraseFromParent(); 2849 return true; 2850 } 2851 2852 bool AMDGPULegalizerInfo::legalizeImageIntrinsic( 2853 MachineInstr &MI, MachineIRBuilder &B, 2854 GISelChangeObserver &Observer, 2855 const AMDGPU::ImageDimIntrinsicInfo *ImageDimIntr) const { 2856 // We are only processing the operands of d16 image operations on subtargets 2857 // that use the unpacked register layout. 2858 if (!ST.hasUnpackedD16VMem()) 2859 return true; 2860 2861 const AMDGPU::MIMGBaseOpcodeInfo *BaseOpcode = 2862 AMDGPU::getMIMGBaseOpcodeInfo(ImageDimIntr->BaseOpcode); 2863 2864 if (BaseOpcode->Atomic) // No d16 atomics 2865 return true; 2866 2867 MachineRegisterInfo *MRI = B.getMRI(); 2868 const LLT S32 = LLT::scalar(32); 2869 const LLT S16 = LLT::scalar(16); 2870 2871 if (BaseOpcode->Store) { 2872 Register VData = MI.getOperand(1).getReg(); 2873 LLT Ty = MRI->getType(VData); 2874 if (!Ty.isVector() || Ty.getElementType() != S16) 2875 return true; 2876 2877 B.setInstr(MI); 2878 2879 Observer.changingInstr(MI); 2880 MI.getOperand(1).setReg(handleD16VData(B, *MRI, VData)); 2881 Observer.changedInstr(MI); 2882 return true; 2883 } 2884 2885 // Must be an image load. 2886 Register DstReg = MI.getOperand(0).getReg(); 2887 LLT Ty = MRI->getType(DstReg); 2888 if (!Ty.isVector() || Ty.getElementType() != S16) 2889 return true; 2890 2891 B.setInsertPt(*MI.getParent(), ++MI.getIterator()); 2892 2893 LLT WidenedTy = Ty.changeElementType(S32); 2894 Register WideDstReg = MRI->createGenericVirtualRegister(WidenedTy); 2895 2896 Observer.changingInstr(MI); 2897 MI.getOperand(0).setReg(WideDstReg); 2898 Observer.changedInstr(MI); 2899 2900 // FIXME: Just vector trunc should be sufficent, but legalization currently 2901 // broken. 2902 auto Unmerge = B.buildUnmerge(S32, WideDstReg); 2903 2904 int NumOps = Unmerge->getNumOperands() - 1; 2905 SmallVector<Register, 4> RemergeParts(NumOps); 2906 for (int I = 0; I != NumOps; ++I) 2907 RemergeParts[I] = B.buildTrunc(S16, Unmerge.getReg(I)).getReg(0); 2908 2909 B.buildBuildVector(DstReg, RemergeParts); 2910 return true; 2911 } 2912 2913 bool AMDGPULegalizerInfo::legalizeIntrinsic(MachineInstr &MI, 2914 MachineIRBuilder &B, 2915 GISelChangeObserver &Observer) const { 2916 MachineRegisterInfo &MRI = *B.getMRI(); 2917 2918 // Replace the use G_BRCOND with the exec manipulate and branch pseudos. 2919 auto IntrID = MI.getIntrinsicID(); 2920 switch (IntrID) { 2921 case Intrinsic::amdgcn_if: 2922 case Intrinsic::amdgcn_else: { 2923 MachineInstr *Br = nullptr; 2924 if (MachineInstr *BrCond = verifyCFIntrinsic(MI, MRI, Br)) { 2925 const SIRegisterInfo *TRI 2926 = static_cast<const SIRegisterInfo *>(MRI.getTargetRegisterInfo()); 2927 2928 B.setInstr(*BrCond); 2929 Register Def = MI.getOperand(1).getReg(); 2930 Register Use = MI.getOperand(3).getReg(); 2931 2932 MachineBasicBlock *BrTarget = BrCond->getOperand(1).getMBB(); 2933 if (Br) 2934 BrTarget = Br->getOperand(0).getMBB(); 2935 2936 if (IntrID == Intrinsic::amdgcn_if) { 2937 B.buildInstr(AMDGPU::SI_IF) 2938 .addDef(Def) 2939 .addUse(Use) 2940 .addMBB(BrTarget); 2941 } else { 2942 B.buildInstr(AMDGPU::SI_ELSE) 2943 .addDef(Def) 2944 .addUse(Use) 2945 .addMBB(BrTarget) 2946 .addImm(0); 2947 } 2948 2949 if (Br) 2950 Br->getOperand(0).setMBB(BrCond->getOperand(1).getMBB()); 2951 2952 MRI.setRegClass(Def, TRI->getWaveMaskRegClass()); 2953 MRI.setRegClass(Use, TRI->getWaveMaskRegClass()); 2954 MI.eraseFromParent(); 2955 BrCond->eraseFromParent(); 2956 return true; 2957 } 2958 2959 return false; 2960 } 2961 case Intrinsic::amdgcn_loop: { 2962 MachineInstr *Br = nullptr; 2963 if (MachineInstr *BrCond = verifyCFIntrinsic(MI, MRI, Br)) { 2964 const SIRegisterInfo *TRI 2965 = static_cast<const SIRegisterInfo *>(MRI.getTargetRegisterInfo()); 2966 2967 B.setInstr(*BrCond); 2968 2969 // FIXME: Need to adjust branch targets based on unconditional branch. 2970 Register Reg = MI.getOperand(2).getReg(); 2971 B.buildInstr(AMDGPU::SI_LOOP) 2972 .addUse(Reg) 2973 .addMBB(BrCond->getOperand(1).getMBB()); 2974 MI.eraseFromParent(); 2975 BrCond->eraseFromParent(); 2976 MRI.setRegClass(Reg, TRI->getWaveMaskRegClass()); 2977 return true; 2978 } 2979 2980 return false; 2981 } 2982 case Intrinsic::amdgcn_kernarg_segment_ptr: 2983 return legalizePreloadedArgIntrin( 2984 MI, MRI, B, AMDGPUFunctionArgInfo::KERNARG_SEGMENT_PTR); 2985 case Intrinsic::amdgcn_implicitarg_ptr: 2986 return legalizeImplicitArgPtr(MI, MRI, B); 2987 case Intrinsic::amdgcn_workitem_id_x: 2988 return legalizePreloadedArgIntrin(MI, MRI, B, 2989 AMDGPUFunctionArgInfo::WORKITEM_ID_X); 2990 case Intrinsic::amdgcn_workitem_id_y: 2991 return legalizePreloadedArgIntrin(MI, MRI, B, 2992 AMDGPUFunctionArgInfo::WORKITEM_ID_Y); 2993 case Intrinsic::amdgcn_workitem_id_z: 2994 return legalizePreloadedArgIntrin(MI, MRI, B, 2995 AMDGPUFunctionArgInfo::WORKITEM_ID_Z); 2996 case Intrinsic::amdgcn_workgroup_id_x: 2997 return legalizePreloadedArgIntrin(MI, MRI, B, 2998 AMDGPUFunctionArgInfo::WORKGROUP_ID_X); 2999 case Intrinsic::amdgcn_workgroup_id_y: 3000 return legalizePreloadedArgIntrin(MI, MRI, B, 3001 AMDGPUFunctionArgInfo::WORKGROUP_ID_Y); 3002 case Intrinsic::amdgcn_workgroup_id_z: 3003 return legalizePreloadedArgIntrin(MI, MRI, B, 3004 AMDGPUFunctionArgInfo::WORKGROUP_ID_Z); 3005 case Intrinsic::amdgcn_dispatch_ptr: 3006 return legalizePreloadedArgIntrin(MI, MRI, B, 3007 AMDGPUFunctionArgInfo::DISPATCH_PTR); 3008 case Intrinsic::amdgcn_queue_ptr: 3009 return legalizePreloadedArgIntrin(MI, MRI, B, 3010 AMDGPUFunctionArgInfo::QUEUE_PTR); 3011 case Intrinsic::amdgcn_implicit_buffer_ptr: 3012 return legalizePreloadedArgIntrin( 3013 MI, MRI, B, AMDGPUFunctionArgInfo::IMPLICIT_BUFFER_PTR); 3014 case Intrinsic::amdgcn_dispatch_id: 3015 return legalizePreloadedArgIntrin(MI, MRI, B, 3016 AMDGPUFunctionArgInfo::DISPATCH_ID); 3017 case Intrinsic::amdgcn_fdiv_fast: 3018 return legalizeFDIVFastIntrin(MI, MRI, B); 3019 case Intrinsic::amdgcn_is_shared: 3020 return legalizeIsAddrSpace(MI, MRI, B, AMDGPUAS::LOCAL_ADDRESS); 3021 case Intrinsic::amdgcn_is_private: 3022 return legalizeIsAddrSpace(MI, MRI, B, AMDGPUAS::PRIVATE_ADDRESS); 3023 case Intrinsic::amdgcn_wavefrontsize: { 3024 B.setInstr(MI); 3025 B.buildConstant(MI.getOperand(0), ST.getWavefrontSize()); 3026 MI.eraseFromParent(); 3027 return true; 3028 } 3029 case Intrinsic::amdgcn_raw_buffer_store: 3030 case Intrinsic::amdgcn_struct_buffer_store: 3031 return legalizeBufferStore(MI, MRI, B, false, false); 3032 case Intrinsic::amdgcn_raw_buffer_store_format: 3033 case Intrinsic::amdgcn_struct_buffer_store_format: 3034 return legalizeBufferStore(MI, MRI, B, false, true); 3035 case Intrinsic::amdgcn_raw_tbuffer_store: 3036 case Intrinsic::amdgcn_struct_tbuffer_store: 3037 return legalizeBufferStore(MI, MRI, B, true, true); 3038 case Intrinsic::amdgcn_raw_buffer_load: 3039 case Intrinsic::amdgcn_struct_buffer_load: 3040 return legalizeBufferLoad(MI, MRI, B, false, false); 3041 case Intrinsic::amdgcn_raw_buffer_load_format: 3042 case Intrinsic::amdgcn_struct_buffer_load_format: 3043 return legalizeBufferLoad(MI, MRI, B, true, false); 3044 case Intrinsic::amdgcn_raw_tbuffer_load: 3045 case Intrinsic::amdgcn_struct_tbuffer_load: 3046 return legalizeBufferLoad(MI, MRI, B, true, true); 3047 case Intrinsic::amdgcn_raw_buffer_atomic_swap: 3048 case Intrinsic::amdgcn_struct_buffer_atomic_swap: 3049 case Intrinsic::amdgcn_raw_buffer_atomic_add: 3050 case Intrinsic::amdgcn_struct_buffer_atomic_add: 3051 case Intrinsic::amdgcn_raw_buffer_atomic_sub: 3052 case Intrinsic::amdgcn_struct_buffer_atomic_sub: 3053 case Intrinsic::amdgcn_raw_buffer_atomic_smin: 3054 case Intrinsic::amdgcn_struct_buffer_atomic_smin: 3055 case Intrinsic::amdgcn_raw_buffer_atomic_umin: 3056 case Intrinsic::amdgcn_struct_buffer_atomic_umin: 3057 case Intrinsic::amdgcn_raw_buffer_atomic_smax: 3058 case Intrinsic::amdgcn_struct_buffer_atomic_smax: 3059 case Intrinsic::amdgcn_raw_buffer_atomic_umax: 3060 case Intrinsic::amdgcn_struct_buffer_atomic_umax: 3061 case Intrinsic::amdgcn_raw_buffer_atomic_and: 3062 case Intrinsic::amdgcn_struct_buffer_atomic_and: 3063 case Intrinsic::amdgcn_raw_buffer_atomic_or: 3064 case Intrinsic::amdgcn_struct_buffer_atomic_or: 3065 case Intrinsic::amdgcn_raw_buffer_atomic_xor: 3066 case Intrinsic::amdgcn_struct_buffer_atomic_xor: 3067 case Intrinsic::amdgcn_raw_buffer_atomic_inc: 3068 case Intrinsic::amdgcn_struct_buffer_atomic_inc: 3069 case Intrinsic::amdgcn_raw_buffer_atomic_dec: 3070 case Intrinsic::amdgcn_struct_buffer_atomic_dec: 3071 case Intrinsic::amdgcn_raw_buffer_atomic_cmpswap: 3072 case Intrinsic::amdgcn_struct_buffer_atomic_cmpswap: 3073 return legalizeBufferAtomic(MI, B, IntrID); 3074 case Intrinsic::amdgcn_atomic_inc: 3075 return legalizeAtomicIncDec(MI, B, true); 3076 case Intrinsic::amdgcn_atomic_dec: 3077 return legalizeAtomicIncDec(MI, B, false); 3078 default: { 3079 if (const AMDGPU::ImageDimIntrinsicInfo *ImageDimIntr = 3080 AMDGPU::getImageDimIntrinsicInfo(IntrID)) 3081 return legalizeImageIntrinsic(MI, B, Observer, ImageDimIntr); 3082 return true; 3083 } 3084 } 3085 3086 return true; 3087 } 3088