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 "AMDGPU.h" 22 #include "AMDGPULegalizerInfo.h" 23 #include "AMDGPUTargetMachine.h" 24 #include "SIMachineFunctionInfo.h" 25 #include "llvm/CodeGen/GlobalISel/LegalizerHelper.h" 26 #include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h" 27 #include "llvm/CodeGen/TargetOpcodes.h" 28 #include "llvm/CodeGen/ValueTypes.h" 29 #include "llvm/IR/DerivedTypes.h" 30 #include "llvm/IR/DiagnosticInfo.h" 31 #include "llvm/IR/Type.h" 32 #include "llvm/Support/Debug.h" 33 34 #define DEBUG_TYPE "amdgpu-legalinfo" 35 36 using namespace llvm; 37 using namespace LegalizeActions; 38 using namespace LegalizeMutations; 39 using namespace LegalityPredicates; 40 41 42 static LegalityPredicate isMultiple32(unsigned TypeIdx, 43 unsigned MaxSize = 512) { 44 return [=](const LegalityQuery &Query) { 45 const LLT Ty = Query.Types[TypeIdx]; 46 const LLT EltTy = Ty.getScalarType(); 47 return Ty.getSizeInBits() <= MaxSize && EltTy.getSizeInBits() % 32 == 0; 48 }; 49 } 50 51 static LegalityPredicate isSmallOddVector(unsigned TypeIdx) { 52 return [=](const LegalityQuery &Query) { 53 const LLT Ty = Query.Types[TypeIdx]; 54 return Ty.isVector() && 55 Ty.getNumElements() % 2 != 0 && 56 Ty.getElementType().getSizeInBits() < 32; 57 }; 58 } 59 60 static LegalizeMutation oneMoreElement(unsigned TypeIdx) { 61 return [=](const LegalityQuery &Query) { 62 const LLT Ty = Query.Types[TypeIdx]; 63 const LLT EltTy = Ty.getElementType(); 64 return std::make_pair(TypeIdx, LLT::vector(Ty.getNumElements() + 1, EltTy)); 65 }; 66 } 67 68 static LegalizeMutation fewerEltsToSize64Vector(unsigned TypeIdx) { 69 return [=](const LegalityQuery &Query) { 70 const LLT Ty = Query.Types[TypeIdx]; 71 const LLT EltTy = Ty.getElementType(); 72 unsigned Size = Ty.getSizeInBits(); 73 unsigned Pieces = (Size + 63) / 64; 74 unsigned NewNumElts = (Ty.getNumElements() + 1) / Pieces; 75 return std::make_pair(TypeIdx, LLT::scalarOrVector(NewNumElts, EltTy)); 76 }; 77 } 78 79 // Increase the number of vector elements to reach the next multiple of 32-bit 80 // type. 81 static LegalizeMutation moreEltsToNext32Bit(unsigned TypeIdx) { 82 return [=](const LegalityQuery &Query) { 83 const LLT Ty = Query.Types[TypeIdx]; 84 85 const LLT EltTy = Ty.getElementType(); 86 const int Size = Ty.getSizeInBits(); 87 const int EltSize = EltTy.getSizeInBits(); 88 const int NextMul32 = (Size + 31) / 32; 89 90 assert(EltSize < 32); 91 92 const int NewNumElts = (32 * NextMul32 + EltSize - 1) / EltSize; 93 return std::make_pair(TypeIdx, LLT::vector(NewNumElts, EltTy)); 94 }; 95 } 96 97 static LegalityPredicate vectorSmallerThan(unsigned TypeIdx, unsigned Size) { 98 return [=](const LegalityQuery &Query) { 99 const LLT QueryTy = Query.Types[TypeIdx]; 100 return QueryTy.isVector() && QueryTy.getSizeInBits() < Size; 101 }; 102 } 103 104 static LegalityPredicate vectorWiderThan(unsigned TypeIdx, unsigned Size) { 105 return [=](const LegalityQuery &Query) { 106 const LLT QueryTy = Query.Types[TypeIdx]; 107 return QueryTy.isVector() && QueryTy.getSizeInBits() > Size; 108 }; 109 } 110 111 static LegalityPredicate numElementsNotEven(unsigned TypeIdx) { 112 return [=](const LegalityQuery &Query) { 113 const LLT QueryTy = Query.Types[TypeIdx]; 114 return QueryTy.isVector() && QueryTy.getNumElements() % 2 != 0; 115 }; 116 } 117 118 // Any combination of 32 or 64-bit elements up to 512 bits, and multiples of 119 // v2s16. 120 static LegalityPredicate isRegisterType(unsigned TypeIdx) { 121 return [=](const LegalityQuery &Query) { 122 const LLT Ty = Query.Types[TypeIdx]; 123 if (Ty.isVector()) { 124 const int EltSize = Ty.getElementType().getSizeInBits(); 125 return EltSize == 32 || EltSize == 64 || 126 (EltSize == 16 && Ty.getNumElements() % 2 == 0) || 127 EltSize == 128 || EltSize == 256; 128 } 129 130 return Ty.getSizeInBits() % 32 == 0 && Ty.getSizeInBits() <= 512; 131 }; 132 } 133 134 static LegalityPredicate elementTypeIs(unsigned TypeIdx, LLT Type) { 135 return [=](const LegalityQuery &Query) { 136 return Query.Types[TypeIdx].getElementType() == Type; 137 }; 138 } 139 140 static LegalityPredicate isWideScalarTruncStore(unsigned TypeIdx) { 141 return [=](const LegalityQuery &Query) { 142 const LLT Ty = Query.Types[TypeIdx]; 143 return !Ty.isVector() && Ty.getSizeInBits() > 32 && 144 Query.MMODescrs[0].SizeInBits < Ty.getSizeInBits(); 145 }; 146 } 147 148 AMDGPULegalizerInfo::AMDGPULegalizerInfo(const GCNSubtarget &ST_, 149 const GCNTargetMachine &TM) 150 : ST(ST_) { 151 using namespace TargetOpcode; 152 153 auto GetAddrSpacePtr = [&TM](unsigned AS) { 154 return LLT::pointer(AS, TM.getPointerSizeInBits(AS)); 155 }; 156 157 const LLT S1 = LLT::scalar(1); 158 const LLT S8 = LLT::scalar(8); 159 const LLT S16 = LLT::scalar(16); 160 const LLT S32 = LLT::scalar(32); 161 const LLT S64 = LLT::scalar(64); 162 const LLT S96 = LLT::scalar(96); 163 const LLT S128 = LLT::scalar(128); 164 const LLT S256 = LLT::scalar(256); 165 const LLT S512 = LLT::scalar(512); 166 167 const LLT V2S16 = LLT::vector(2, 16); 168 const LLT V4S16 = LLT::vector(4, 16); 169 170 const LLT V2S32 = LLT::vector(2, 32); 171 const LLT V3S32 = LLT::vector(3, 32); 172 const LLT V4S32 = LLT::vector(4, 32); 173 const LLT V5S32 = LLT::vector(5, 32); 174 const LLT V6S32 = LLT::vector(6, 32); 175 const LLT V7S32 = LLT::vector(7, 32); 176 const LLT V8S32 = LLT::vector(8, 32); 177 const LLT V9S32 = LLT::vector(9, 32); 178 const LLT V10S32 = LLT::vector(10, 32); 179 const LLT V11S32 = LLT::vector(11, 32); 180 const LLT V12S32 = LLT::vector(12, 32); 181 const LLT V13S32 = LLT::vector(13, 32); 182 const LLT V14S32 = LLT::vector(14, 32); 183 const LLT V15S32 = LLT::vector(15, 32); 184 const LLT V16S32 = LLT::vector(16, 32); 185 186 const LLT V2S64 = LLT::vector(2, 64); 187 const LLT V3S64 = LLT::vector(3, 64); 188 const LLT V4S64 = LLT::vector(4, 64); 189 const LLT V5S64 = LLT::vector(5, 64); 190 const LLT V6S64 = LLT::vector(6, 64); 191 const LLT V7S64 = LLT::vector(7, 64); 192 const LLT V8S64 = LLT::vector(8, 64); 193 194 std::initializer_list<LLT> AllS32Vectors = 195 {V2S32, V3S32, V4S32, V5S32, V6S32, V7S32, V8S32, 196 V9S32, V10S32, V11S32, V12S32, V13S32, V14S32, V15S32, V16S32}; 197 std::initializer_list<LLT> AllS64Vectors = 198 {V2S64, V3S64, V4S64, V5S64, V6S64, V7S64, V8S64}; 199 200 const LLT GlobalPtr = GetAddrSpacePtr(AMDGPUAS::GLOBAL_ADDRESS); 201 const LLT ConstantPtr = GetAddrSpacePtr(AMDGPUAS::CONSTANT_ADDRESS); 202 const LLT Constant32Ptr = GetAddrSpacePtr(AMDGPUAS::CONSTANT_ADDRESS_32BIT); 203 const LLT LocalPtr = GetAddrSpacePtr(AMDGPUAS::LOCAL_ADDRESS); 204 const LLT RegionPtr = GetAddrSpacePtr(AMDGPUAS::REGION_ADDRESS); 205 const LLT FlatPtr = GetAddrSpacePtr(AMDGPUAS::FLAT_ADDRESS); 206 const LLT PrivatePtr = GetAddrSpacePtr(AMDGPUAS::PRIVATE_ADDRESS); 207 208 const LLT CodePtr = FlatPtr; 209 210 const std::initializer_list<LLT> AddrSpaces64 = { 211 GlobalPtr, ConstantPtr, FlatPtr 212 }; 213 214 const std::initializer_list<LLT> AddrSpaces32 = { 215 LocalPtr, PrivatePtr, Constant32Ptr, RegionPtr 216 }; 217 218 const std::initializer_list<LLT> FPTypesBase = { 219 S32, S64 220 }; 221 222 const std::initializer_list<LLT> FPTypes16 = { 223 S32, S64, S16 224 }; 225 226 const std::initializer_list<LLT> FPTypesPK16 = { 227 S32, S64, S16, V2S16 228 }; 229 230 setAction({G_BRCOND, S1}, Legal); 231 232 // TODO: All multiples of 32, vectors of pointers, all v2s16 pairs, more 233 // elements for v3s16 234 getActionDefinitionsBuilder(G_PHI) 235 .legalFor({S32, S64, V2S16, V4S16, S1, S128, S256}) 236 .legalFor(AllS32Vectors) 237 .legalFor(AllS64Vectors) 238 .legalFor(AddrSpaces64) 239 .legalFor(AddrSpaces32) 240 .clampScalar(0, S32, S256) 241 .widenScalarToNextPow2(0, 32) 242 .clampMaxNumElements(0, S32, 16) 243 .moreElementsIf(isSmallOddVector(0), oneMoreElement(0)) 244 .legalIf(isPointer(0)); 245 246 if (ST.has16BitInsts()) { 247 getActionDefinitionsBuilder({G_ADD, G_SUB, G_MUL}) 248 .legalFor({S32, S16}) 249 .clampScalar(0, S16, S32) 250 .scalarize(0); 251 } else { 252 getActionDefinitionsBuilder({G_ADD, G_SUB, G_MUL}) 253 .legalFor({S32}) 254 .clampScalar(0, S32, S32) 255 .scalarize(0); 256 } 257 258 getActionDefinitionsBuilder({G_UMULH, G_SMULH}) 259 .legalFor({S32}) 260 .clampScalar(0, S32, S32) 261 .scalarize(0); 262 263 // Report legal for any types we can handle anywhere. For the cases only legal 264 // on the SALU, RegBankSelect will be able to re-legalize. 265 getActionDefinitionsBuilder({G_AND, G_OR, G_XOR}) 266 .legalFor({S32, S1, S64, V2S32, S16, V2S16, V4S16}) 267 .clampScalar(0, S32, S64) 268 .moreElementsIf(isSmallOddVector(0), oneMoreElement(0)) 269 .fewerElementsIf(vectorWiderThan(0, 32), fewerEltsToSize64Vector(0)) 270 .widenScalarToNextPow2(0) 271 .scalarize(0); 272 273 getActionDefinitionsBuilder({G_UADDO, G_SADDO, G_USUBO, G_SSUBO, 274 G_UADDE, G_SADDE, G_USUBE, G_SSUBE}) 275 .legalFor({{S32, S1}}) 276 .clampScalar(0, S32, S32); 277 278 getActionDefinitionsBuilder(G_BITCAST) 279 .legalForCartesianProduct({S32, V2S16}) 280 .legalForCartesianProduct({S64, V2S32, V4S16}) 281 .legalForCartesianProduct({V2S64, V4S32}) 282 // Don't worry about the size constraint. 283 .legalIf(all(isPointer(0), isPointer(1))) 284 // FIXME: Testing hack 285 .legalForCartesianProduct({S16, LLT::vector(2, 8), }); 286 287 getActionDefinitionsBuilder(G_FCONSTANT) 288 .legalFor({S32, S64, S16}) 289 .clampScalar(0, S16, S64); 290 291 getActionDefinitionsBuilder(G_IMPLICIT_DEF) 292 .legalFor({S1, S32, S64, S16, V2S32, V4S32, V2S16, V4S16, GlobalPtr, 293 ConstantPtr, LocalPtr, FlatPtr, PrivatePtr}) 294 .moreElementsIf(isSmallOddVector(0), oneMoreElement(0)) 295 .clampScalarOrElt(0, S32, S512) 296 .legalIf(isMultiple32(0)) 297 .widenScalarToNextPow2(0, 32) 298 .clampMaxNumElements(0, S32, 16); 299 300 301 // FIXME: i1 operands to intrinsics should always be legal, but other i1 302 // values may not be legal. We need to figure out how to distinguish 303 // between these two scenarios. 304 getActionDefinitionsBuilder(G_CONSTANT) 305 .legalFor({S1, S32, S64, S16, GlobalPtr, 306 LocalPtr, ConstantPtr, PrivatePtr, FlatPtr }) 307 .clampScalar(0, S32, S64) 308 .widenScalarToNextPow2(0) 309 .legalIf(isPointer(0)); 310 311 setAction({G_FRAME_INDEX, PrivatePtr}, Legal); 312 getActionDefinitionsBuilder(G_GLOBAL_VALUE).customFor({LocalPtr}); 313 314 315 auto &FPOpActions = getActionDefinitionsBuilder( 316 { G_FADD, G_FMUL, G_FMA, G_FCANONICALIZE}) 317 .legalFor({S32, S64}); 318 auto &TrigActions = getActionDefinitionsBuilder({G_FSIN, G_FCOS}) 319 .customFor({S32, S64}); 320 321 if (ST.has16BitInsts()) { 322 if (ST.hasVOP3PInsts()) 323 FPOpActions.legalFor({S16, V2S16}); 324 else 325 FPOpActions.legalFor({S16}); 326 327 TrigActions.customFor({S16}); 328 } 329 330 auto &MinNumMaxNum = getActionDefinitionsBuilder({ 331 G_FMINNUM, G_FMAXNUM, G_FMINNUM_IEEE, G_FMAXNUM_IEEE}); 332 333 if (ST.hasVOP3PInsts()) { 334 MinNumMaxNum.customFor(FPTypesPK16) 335 .clampMaxNumElements(0, S16, 2) 336 .clampScalar(0, S16, S64) 337 .scalarize(0); 338 } else if (ST.has16BitInsts()) { 339 MinNumMaxNum.customFor(FPTypes16) 340 .clampScalar(0, S16, S64) 341 .scalarize(0); 342 } else { 343 MinNumMaxNum.customFor(FPTypesBase) 344 .clampScalar(0, S32, S64) 345 .scalarize(0); 346 } 347 348 if (ST.hasVOP3PInsts()) 349 FPOpActions.clampMaxNumElements(0, S16, 2); 350 351 FPOpActions 352 .scalarize(0) 353 .clampScalar(0, ST.has16BitInsts() ? S16 : S32, S64); 354 355 TrigActions 356 .scalarize(0) 357 .clampScalar(0, ST.has16BitInsts() ? S16 : S32, S64); 358 359 getActionDefinitionsBuilder({G_FNEG, G_FABS}) 360 .legalFor(FPTypesPK16) 361 .clampMaxNumElements(0, S16, 2) 362 .scalarize(0) 363 .clampScalar(0, S16, S64); 364 365 // TODO: Implement 366 getActionDefinitionsBuilder({G_FMINIMUM, G_FMAXIMUM}).lower(); 367 368 if (ST.has16BitInsts()) { 369 getActionDefinitionsBuilder({G_FSQRT, G_FFLOOR}) 370 .legalFor({S32, S64, S16}) 371 .scalarize(0) 372 .clampScalar(0, S16, S64); 373 } else { 374 getActionDefinitionsBuilder({G_FSQRT, G_FFLOOR}) 375 .legalFor({S32, S64}) 376 .scalarize(0) 377 .clampScalar(0, S32, S64); 378 } 379 380 getActionDefinitionsBuilder(G_FPTRUNC) 381 .legalFor({{S32, S64}, {S16, S32}}) 382 .scalarize(0); 383 384 getActionDefinitionsBuilder(G_FPEXT) 385 .legalFor({{S64, S32}, {S32, S16}}) 386 .lowerFor({{S64, S16}}) // FIXME: Implement 387 .scalarize(0); 388 389 // TODO: Verify V_BFI_B32 is generated from expanded bit ops. 390 getActionDefinitionsBuilder(G_FCOPYSIGN).lower(); 391 392 getActionDefinitionsBuilder(G_FSUB) 393 // Use actual fsub instruction 394 .legalFor({S32}) 395 // Must use fadd + fneg 396 .lowerFor({S64, S16, V2S16}) 397 .scalarize(0) 398 .clampScalar(0, S32, S64); 399 400 // Whether this is legal depends on the floating point mode for the function. 401 auto &FMad = getActionDefinitionsBuilder(G_FMAD); 402 if (ST.hasMadF16()) 403 FMad.customFor({S32, S16}); 404 else 405 FMad.customFor({S32}); 406 FMad.scalarize(0) 407 .lower(); 408 409 getActionDefinitionsBuilder({G_SEXT, G_ZEXT, G_ANYEXT}) 410 .legalFor({{S64, S32}, {S32, S16}, {S64, S16}, 411 {S32, S1}, {S64, S1}, {S16, S1}, 412 {S96, S32}, 413 // FIXME: Hack 414 {S64, LLT::scalar(33)}, 415 {S32, S8}, {S128, S32}, {S128, S64}, {S32, LLT::scalar(24)}}) 416 .scalarize(0); 417 418 getActionDefinitionsBuilder({G_SITOFP, G_UITOFP}) 419 .legalFor({{S32, S32}, {S64, S32}, {S16, S32}}) 420 .lowerFor({{S32, S64}}) 421 .customFor({{S64, S64}}) 422 .scalarize(0); 423 424 getActionDefinitionsBuilder({G_FPTOSI, G_FPTOUI}) 425 .legalFor({{S32, S32}, {S32, S64}}) 426 .scalarize(0); 427 428 getActionDefinitionsBuilder(G_INTRINSIC_ROUND) 429 .legalFor({S32, S64}) 430 .scalarize(0); 431 432 if (ST.getGeneration() >= AMDGPUSubtarget::SEA_ISLANDS) { 433 getActionDefinitionsBuilder({G_INTRINSIC_TRUNC, G_FCEIL, G_FRINT}) 434 .legalFor({S32, S64}) 435 .clampScalar(0, S32, S64) 436 .scalarize(0); 437 } else { 438 getActionDefinitionsBuilder({G_INTRINSIC_TRUNC, G_FCEIL, G_FRINT}) 439 .legalFor({S32}) 440 .customFor({S64}) 441 .clampScalar(0, S32, S64) 442 .scalarize(0); 443 } 444 445 getActionDefinitionsBuilder(G_GEP) 446 .legalForCartesianProduct(AddrSpaces64, {S64}) 447 .legalForCartesianProduct(AddrSpaces32, {S32}) 448 .scalarize(0); 449 450 getActionDefinitionsBuilder(G_PTR_MASK) 451 .scalarize(0) 452 .alwaysLegal(); 453 454 setAction({G_BLOCK_ADDR, CodePtr}, Legal); 455 456 auto &CmpBuilder = 457 getActionDefinitionsBuilder(G_ICMP) 458 .legalForCartesianProduct( 459 {S1}, {S32, S64, GlobalPtr, LocalPtr, ConstantPtr, PrivatePtr, FlatPtr}) 460 .legalFor({{S1, S32}, {S1, S64}}); 461 if (ST.has16BitInsts()) { 462 CmpBuilder.legalFor({{S1, S16}}); 463 } 464 465 CmpBuilder 466 .widenScalarToNextPow2(1) 467 .clampScalar(1, S32, S64) 468 .scalarize(0) 469 .legalIf(all(typeIs(0, S1), isPointer(1))); 470 471 getActionDefinitionsBuilder(G_FCMP) 472 .legalForCartesianProduct({S1}, ST.has16BitInsts() ? FPTypes16 : FPTypesBase) 473 .widenScalarToNextPow2(1) 474 .clampScalar(1, S32, S64) 475 .scalarize(0); 476 477 // FIXME: fexp, flog2, flog10 needs to be custom lowered. 478 getActionDefinitionsBuilder({G_FPOW, G_FEXP, G_FEXP2, 479 G_FLOG, G_FLOG2, G_FLOG10}) 480 .legalFor({S32}) 481 .scalarize(0); 482 483 // The 64-bit versions produce 32-bit results, but only on the SALU. 484 getActionDefinitionsBuilder({G_CTLZ, G_CTLZ_ZERO_UNDEF, 485 G_CTTZ, G_CTTZ_ZERO_UNDEF, 486 G_CTPOP}) 487 .legalFor({{S32, S32}, {S32, S64}}) 488 .clampScalar(0, S32, S32) 489 .clampScalar(1, S32, S64) 490 .scalarize(0) 491 .widenScalarToNextPow2(0, 32) 492 .widenScalarToNextPow2(1, 32); 493 494 // TODO: Expand for > s32 495 getActionDefinitionsBuilder({G_BSWAP, G_BITREVERSE}) 496 .legalFor({S32}) 497 .clampScalar(0, S32, S32) 498 .scalarize(0); 499 500 if (ST.has16BitInsts()) { 501 if (ST.hasVOP3PInsts()) { 502 getActionDefinitionsBuilder({G_SMIN, G_SMAX, G_UMIN, G_UMAX}) 503 .legalFor({S32, S16, V2S16}) 504 .moreElementsIf(isSmallOddVector(0), oneMoreElement(0)) 505 .clampMaxNumElements(0, S16, 2) 506 .clampScalar(0, S16, S32) 507 .widenScalarToNextPow2(0) 508 .scalarize(0); 509 } else { 510 getActionDefinitionsBuilder({G_SMIN, G_SMAX, G_UMIN, G_UMAX}) 511 .legalFor({S32, S16}) 512 .widenScalarToNextPow2(0) 513 .clampScalar(0, S16, S32) 514 .scalarize(0); 515 } 516 } else { 517 getActionDefinitionsBuilder({G_SMIN, G_SMAX, G_UMIN, G_UMAX}) 518 .legalFor({S32}) 519 .clampScalar(0, S32, S32) 520 .widenScalarToNextPow2(0) 521 .scalarize(0); 522 } 523 524 auto smallerThan = [](unsigned TypeIdx0, unsigned TypeIdx1) { 525 return [=](const LegalityQuery &Query) { 526 return Query.Types[TypeIdx0].getSizeInBits() < 527 Query.Types[TypeIdx1].getSizeInBits(); 528 }; 529 }; 530 531 auto greaterThan = [](unsigned TypeIdx0, unsigned TypeIdx1) { 532 return [=](const LegalityQuery &Query) { 533 return Query.Types[TypeIdx0].getSizeInBits() > 534 Query.Types[TypeIdx1].getSizeInBits(); 535 }; 536 }; 537 538 getActionDefinitionsBuilder(G_INTTOPTR) 539 // List the common cases 540 .legalForCartesianProduct(AddrSpaces64, {S64}) 541 .legalForCartesianProduct(AddrSpaces32, {S32}) 542 .scalarize(0) 543 // Accept any address space as long as the size matches 544 .legalIf(sameSize(0, 1)) 545 .widenScalarIf(smallerThan(1, 0), 546 [](const LegalityQuery &Query) { 547 return std::make_pair(1, LLT::scalar(Query.Types[0].getSizeInBits())); 548 }) 549 .narrowScalarIf(greaterThan(1, 0), 550 [](const LegalityQuery &Query) { 551 return std::make_pair(1, LLT::scalar(Query.Types[0].getSizeInBits())); 552 }); 553 554 getActionDefinitionsBuilder(G_PTRTOINT) 555 // List the common cases 556 .legalForCartesianProduct(AddrSpaces64, {S64}) 557 .legalForCartesianProduct(AddrSpaces32, {S32}) 558 .scalarize(0) 559 // Accept any address space as long as the size matches 560 .legalIf(sameSize(0, 1)) 561 .widenScalarIf(smallerThan(0, 1), 562 [](const LegalityQuery &Query) { 563 return std::make_pair(0, LLT::scalar(Query.Types[1].getSizeInBits())); 564 }) 565 .narrowScalarIf( 566 greaterThan(0, 1), 567 [](const LegalityQuery &Query) { 568 return std::make_pair(0, LLT::scalar(Query.Types[1].getSizeInBits())); 569 }); 570 571 getActionDefinitionsBuilder(G_ADDRSPACE_CAST) 572 .scalarize(0) 573 .custom(); 574 575 // TODO: Should load to s16 be legal? Most loads extend to 32-bits, but we 576 // handle some operations by just promoting the register during 577 // selection. There are also d16 loads on GFX9+ which preserve the high bits. 578 auto maxSizeForAddrSpace = [this](unsigned AS) -> unsigned { 579 switch (AS) { 580 // FIXME: Private element size. 581 case AMDGPUAS::PRIVATE_ADDRESS: 582 return 32; 583 // FIXME: Check subtarget 584 case AMDGPUAS::LOCAL_ADDRESS: 585 return ST.useDS128() ? 128 : 64; 586 587 // Treat constant and global as identical. SMRD loads are sometimes usable 588 // for global loads (ideally constant address space should be eliminated) 589 // depending on the context. Legality cannot be context dependent, but 590 // RegBankSelect can split the load as necessary depending on the pointer 591 // register bank/uniformity and if the memory is invariant or not written in 592 // a kernel. 593 case AMDGPUAS::CONSTANT_ADDRESS: 594 case AMDGPUAS::GLOBAL_ADDRESS: 595 return 512; 596 default: 597 return 128; 598 } 599 }; 600 601 const auto needToSplitLoad = [=](const LegalityQuery &Query) -> bool { 602 const LLT DstTy = Query.Types[0]; 603 604 // Split vector extloads. 605 unsigned MemSize = Query.MMODescrs[0].SizeInBits; 606 if (DstTy.isVector() && DstTy.getSizeInBits() > MemSize) 607 return true; 608 609 const LLT PtrTy = Query.Types[1]; 610 unsigned AS = PtrTy.getAddressSpace(); 611 if (MemSize > maxSizeForAddrSpace(AS)) 612 return true; 613 614 // Catch weird sized loads that don't evenly divide into the access sizes 615 // TODO: May be able to widen depending on alignment etc. 616 unsigned NumRegs = MemSize / 32; 617 if (NumRegs == 3 && !ST.hasDwordx3LoadStores()) 618 return true; 619 620 unsigned Align = Query.MMODescrs[0].AlignInBits; 621 if (Align < MemSize) { 622 const SITargetLowering *TLI = ST.getTargetLowering(); 623 return !TLI->allowsMisalignedMemoryAccessesImpl(MemSize, AS, Align / 8); 624 } 625 626 return false; 627 }; 628 629 unsigned GlobalAlign32 = ST.hasUnalignedBufferAccess() ? 0 : 32; 630 unsigned GlobalAlign16 = ST.hasUnalignedBufferAccess() ? 0 : 16; 631 unsigned GlobalAlign8 = ST.hasUnalignedBufferAccess() ? 0 : 8; 632 633 // TODO: Refine based on subtargets which support unaligned access or 128-bit 634 // LDS 635 // TODO: Unsupported flat for SI. 636 637 for (unsigned Op : {G_LOAD, G_STORE}) { 638 const bool IsStore = Op == G_STORE; 639 640 auto &Actions = getActionDefinitionsBuilder(Op); 641 // Whitelist the common cases. 642 // TODO: Pointer loads 643 // TODO: Wide constant loads 644 // TODO: Only CI+ has 3x loads 645 // TODO: Loads to s16 on gfx9 646 Actions.legalForTypesWithMemDesc({{S32, GlobalPtr, 32, GlobalAlign32}, 647 {V2S32, GlobalPtr, 64, GlobalAlign32}, 648 {V3S32, GlobalPtr, 96, GlobalAlign32}, 649 {S96, GlobalPtr, 96, GlobalAlign32}, 650 {V4S32, GlobalPtr, 128, GlobalAlign32}, 651 {S128, GlobalPtr, 128, GlobalAlign32}, 652 {S64, GlobalPtr, 64, GlobalAlign32}, 653 {V2S64, GlobalPtr, 128, GlobalAlign32}, 654 {V2S16, GlobalPtr, 32, GlobalAlign32}, 655 {S32, GlobalPtr, 8, GlobalAlign8}, 656 {S32, GlobalPtr, 16, GlobalAlign16}, 657 658 {S32, LocalPtr, 32, 32}, 659 {S64, LocalPtr, 64, 32}, 660 {V2S32, LocalPtr, 64, 32}, 661 {S32, LocalPtr, 8, 8}, 662 {S32, LocalPtr, 16, 16}, 663 {V2S16, LocalPtr, 32, 32}, 664 665 {S32, PrivatePtr, 32, 32}, 666 {S32, PrivatePtr, 8, 8}, 667 {S32, PrivatePtr, 16, 16}, 668 {V2S16, PrivatePtr, 32, 32}, 669 670 {S32, FlatPtr, 32, GlobalAlign32}, 671 {S32, FlatPtr, 16, GlobalAlign16}, 672 {S32, FlatPtr, 8, GlobalAlign8}, 673 {V2S16, FlatPtr, 32, GlobalAlign32}, 674 675 {S32, ConstantPtr, 32, GlobalAlign32}, 676 {V2S32, ConstantPtr, 64, GlobalAlign32}, 677 {V3S32, ConstantPtr, 96, GlobalAlign32}, 678 {V4S32, ConstantPtr, 128, GlobalAlign32}, 679 {S64, ConstantPtr, 64, GlobalAlign32}, 680 {S128, ConstantPtr, 128, GlobalAlign32}, 681 {V2S32, ConstantPtr, 32, GlobalAlign32}}); 682 Actions 683 .customIf(typeIs(1, Constant32Ptr)) 684 .narrowScalarIf( 685 [=](const LegalityQuery &Query) -> bool { 686 return !Query.Types[0].isVector() && needToSplitLoad(Query); 687 }, 688 [=](const LegalityQuery &Query) -> std::pair<unsigned, LLT> { 689 const LLT DstTy = Query.Types[0]; 690 const LLT PtrTy = Query.Types[1]; 691 692 const unsigned DstSize = DstTy.getSizeInBits(); 693 unsigned MemSize = Query.MMODescrs[0].SizeInBits; 694 695 // Split extloads. 696 if (DstSize > MemSize) 697 return std::make_pair(0, LLT::scalar(MemSize)); 698 699 if (DstSize > 32 && (DstSize % 32 != 0)) { 700 // FIXME: Need a way to specify non-extload of larger size if 701 // suitably aligned. 702 return std::make_pair(0, LLT::scalar(32 * (DstSize / 32))); 703 } 704 705 unsigned MaxSize = maxSizeForAddrSpace(PtrTy.getAddressSpace()); 706 if (MemSize > MaxSize) 707 return std::make_pair(0, LLT::scalar(MaxSize)); 708 709 unsigned Align = Query.MMODescrs[0].AlignInBits; 710 return std::make_pair(0, LLT::scalar(Align)); 711 }) 712 .fewerElementsIf( 713 [=](const LegalityQuery &Query) -> bool { 714 return Query.Types[0].isVector() && needToSplitLoad(Query); 715 }, 716 [=](const LegalityQuery &Query) -> std::pair<unsigned, LLT> { 717 const LLT DstTy = Query.Types[0]; 718 const LLT PtrTy = Query.Types[1]; 719 720 LLT EltTy = DstTy.getElementType(); 721 unsigned MaxSize = maxSizeForAddrSpace(PtrTy.getAddressSpace()); 722 723 // Split if it's too large for the address space. 724 if (Query.MMODescrs[0].SizeInBits > MaxSize) { 725 unsigned NumElts = DstTy.getNumElements(); 726 unsigned NumPieces = Query.MMODescrs[0].SizeInBits / MaxSize; 727 728 // FIXME: Refine when odd breakdowns handled 729 // The scalars will need to be re-legalized. 730 if (NumPieces == 1 || NumPieces >= NumElts || 731 NumElts % NumPieces != 0) 732 return std::make_pair(0, EltTy); 733 734 return std::make_pair(0, 735 LLT::vector(NumElts / NumPieces, EltTy)); 736 } 737 738 // Need to split because of alignment. 739 unsigned Align = Query.MMODescrs[0].AlignInBits; 740 unsigned EltSize = EltTy.getSizeInBits(); 741 if (EltSize > Align && 742 (EltSize / Align < DstTy.getNumElements())) { 743 return std::make_pair(0, LLT::vector(EltSize / Align, EltTy)); 744 } 745 746 // May need relegalization for the scalars. 747 return std::make_pair(0, EltTy); 748 }) 749 .minScalar(0, S32); 750 751 if (IsStore) 752 Actions.narrowScalarIf(isWideScalarTruncStore(0), changeTo(0, S32)); 753 754 // TODO: Need a bitcast lower option? 755 Actions 756 .legalIf([=](const LegalityQuery &Query) { 757 const LLT Ty0 = Query.Types[0]; 758 unsigned Size = Ty0.getSizeInBits(); 759 unsigned MemSize = Query.MMODescrs[0].SizeInBits; 760 unsigned Align = Query.MMODescrs[0].AlignInBits; 761 762 // No extending vector loads. 763 if (Size > MemSize && Ty0.isVector()) 764 return false; 765 766 // FIXME: Widening store from alignment not valid. 767 if (MemSize < Size) 768 MemSize = std::max(MemSize, Align); 769 770 switch (MemSize) { 771 case 8: 772 case 16: 773 return Size == 32; 774 case 32: 775 case 64: 776 case 128: 777 return true; 778 case 96: 779 return ST.hasDwordx3LoadStores(); 780 case 256: 781 case 512: 782 return true; 783 default: 784 return false; 785 } 786 }) 787 .widenScalarToNextPow2(0) 788 // TODO: v3s32->v4s32 with alignment 789 .moreElementsIf(vectorSmallerThan(0, 32), moreEltsToNext32Bit(0)); 790 } 791 792 auto &ExtLoads = getActionDefinitionsBuilder({G_SEXTLOAD, G_ZEXTLOAD}) 793 .legalForTypesWithMemDesc({{S32, GlobalPtr, 8, 8}, 794 {S32, GlobalPtr, 16, 2 * 8}, 795 {S32, LocalPtr, 8, 8}, 796 {S32, LocalPtr, 16, 16}, 797 {S32, PrivatePtr, 8, 8}, 798 {S32, PrivatePtr, 16, 16}, 799 {S32, ConstantPtr, 8, 8}, 800 {S32, ConstantPtr, 16, 2 * 8}}); 801 if (ST.hasFlatAddressSpace()) { 802 ExtLoads.legalForTypesWithMemDesc( 803 {{S32, FlatPtr, 8, 8}, {S32, FlatPtr, 16, 16}}); 804 } 805 806 ExtLoads.clampScalar(0, S32, S32) 807 .widenScalarToNextPow2(0) 808 .unsupportedIfMemSizeNotPow2() 809 .lower(); 810 811 auto &Atomics = getActionDefinitionsBuilder( 812 {G_ATOMICRMW_XCHG, G_ATOMICRMW_ADD, G_ATOMICRMW_SUB, 813 G_ATOMICRMW_AND, G_ATOMICRMW_OR, G_ATOMICRMW_XOR, 814 G_ATOMICRMW_MAX, G_ATOMICRMW_MIN, G_ATOMICRMW_UMAX, 815 G_ATOMICRMW_UMIN, G_ATOMIC_CMPXCHG}) 816 .legalFor({{S32, GlobalPtr}, {S32, LocalPtr}, 817 {S64, GlobalPtr}, {S64, LocalPtr}}); 818 if (ST.hasFlatAddressSpace()) { 819 Atomics.legalFor({{S32, FlatPtr}, {S64, FlatPtr}}); 820 } 821 822 getActionDefinitionsBuilder(G_ATOMICRMW_FADD) 823 .legalFor({{S32, LocalPtr}}); 824 825 // TODO: Pointer types, any 32-bit or 64-bit vector 826 getActionDefinitionsBuilder(G_SELECT) 827 .legalForCartesianProduct({S32, S64, S16, V2S32, V2S16, V4S16, 828 GlobalPtr, LocalPtr, FlatPtr, PrivatePtr, 829 LLT::vector(2, LocalPtr), LLT::vector(2, PrivatePtr)}, {S1}) 830 .clampScalar(0, S16, S64) 831 .moreElementsIf(isSmallOddVector(0), oneMoreElement(0)) 832 .fewerElementsIf(numElementsNotEven(0), scalarize(0)) 833 .scalarize(1) 834 .clampMaxNumElements(0, S32, 2) 835 .clampMaxNumElements(0, LocalPtr, 2) 836 .clampMaxNumElements(0, PrivatePtr, 2) 837 .scalarize(0) 838 .widenScalarToNextPow2(0) 839 .legalIf(all(isPointer(0), typeIs(1, S1))); 840 841 // TODO: Only the low 4/5/6 bits of the shift amount are observed, so we can 842 // be more flexible with the shift amount type. 843 auto &Shifts = getActionDefinitionsBuilder({G_SHL, G_LSHR, G_ASHR}) 844 .legalFor({{S32, S32}, {S64, S32}}); 845 if (ST.has16BitInsts()) { 846 if (ST.hasVOP3PInsts()) { 847 Shifts.legalFor({{S16, S32}, {S16, S16}, {V2S16, V2S16}}) 848 .clampMaxNumElements(0, S16, 2); 849 } else 850 Shifts.legalFor({{S16, S32}, {S16, S16}}); 851 852 Shifts.clampScalar(1, S16, S32); 853 Shifts.clampScalar(0, S16, S64); 854 Shifts.widenScalarToNextPow2(0, 16); 855 } else { 856 // Make sure we legalize the shift amount type first, as the general 857 // expansion for the shifted type will produce much worse code if it hasn't 858 // been truncated already. 859 Shifts.clampScalar(1, S32, S32); 860 Shifts.clampScalar(0, S32, S64); 861 Shifts.widenScalarToNextPow2(0, 32); 862 } 863 Shifts.scalarize(0); 864 865 for (unsigned Op : {G_EXTRACT_VECTOR_ELT, G_INSERT_VECTOR_ELT}) { 866 unsigned VecTypeIdx = Op == G_EXTRACT_VECTOR_ELT ? 1 : 0; 867 unsigned EltTypeIdx = Op == G_EXTRACT_VECTOR_ELT ? 0 : 1; 868 unsigned IdxTypeIdx = 2; 869 870 getActionDefinitionsBuilder(Op) 871 .customIf([=](const LegalityQuery &Query) { 872 const LLT EltTy = Query.Types[EltTypeIdx]; 873 const LLT VecTy = Query.Types[VecTypeIdx]; 874 const LLT IdxTy = Query.Types[IdxTypeIdx]; 875 return (EltTy.getSizeInBits() == 16 || 876 EltTy.getSizeInBits() % 32 == 0) && 877 VecTy.getSizeInBits() % 32 == 0 && 878 VecTy.getSizeInBits() <= 512 && 879 IdxTy.getSizeInBits() == 32; 880 }) 881 .clampScalar(EltTypeIdx, S32, S64) 882 .clampScalar(VecTypeIdx, S32, S64) 883 .clampScalar(IdxTypeIdx, S32, S32); 884 } 885 886 getActionDefinitionsBuilder(G_EXTRACT_VECTOR_ELT) 887 .unsupportedIf([=](const LegalityQuery &Query) { 888 const LLT &EltTy = Query.Types[1].getElementType(); 889 return Query.Types[0] != EltTy; 890 }); 891 892 for (unsigned Op : {G_EXTRACT, G_INSERT}) { 893 unsigned BigTyIdx = Op == G_EXTRACT ? 1 : 0; 894 unsigned LitTyIdx = Op == G_EXTRACT ? 0 : 1; 895 896 // FIXME: Doesn't handle extract of illegal sizes. 897 getActionDefinitionsBuilder(Op) 898 .legalIf([=](const LegalityQuery &Query) { 899 const LLT BigTy = Query.Types[BigTyIdx]; 900 const LLT LitTy = Query.Types[LitTyIdx]; 901 return (BigTy.getSizeInBits() % 32 == 0) && 902 (LitTy.getSizeInBits() % 16 == 0); 903 }) 904 .widenScalarIf( 905 [=](const LegalityQuery &Query) { 906 const LLT BigTy = Query.Types[BigTyIdx]; 907 return (BigTy.getScalarSizeInBits() < 16); 908 }, 909 LegalizeMutations::widenScalarOrEltToNextPow2(BigTyIdx, 16)) 910 .widenScalarIf( 911 [=](const LegalityQuery &Query) { 912 const LLT LitTy = Query.Types[LitTyIdx]; 913 return (LitTy.getScalarSizeInBits() < 16); 914 }, 915 LegalizeMutations::widenScalarOrEltToNextPow2(LitTyIdx, 16)) 916 .moreElementsIf(isSmallOddVector(BigTyIdx), oneMoreElement(BigTyIdx)) 917 .widenScalarToNextPow2(BigTyIdx, 32); 918 919 } 920 921 auto &BuildVector = getActionDefinitionsBuilder(G_BUILD_VECTOR) 922 .legalForCartesianProduct(AllS32Vectors, {S32}) 923 .legalForCartesianProduct(AllS64Vectors, {S64}) 924 .clampNumElements(0, V16S32, V16S32) 925 .clampNumElements(0, V2S64, V8S64); 926 927 if (ST.hasScalarPackInsts()) 928 BuildVector.legalFor({V2S16, S32}); 929 930 BuildVector 931 .minScalarSameAs(1, 0) 932 .legalIf(isRegisterType(0)) 933 .minScalarOrElt(0, S32); 934 935 if (ST.hasScalarPackInsts()) { 936 getActionDefinitionsBuilder(G_BUILD_VECTOR_TRUNC) 937 .legalFor({V2S16, S32}) 938 .lower(); 939 } else { 940 getActionDefinitionsBuilder(G_BUILD_VECTOR_TRUNC) 941 .lower(); 942 } 943 944 getActionDefinitionsBuilder(G_CONCAT_VECTORS) 945 .legalIf(isRegisterType(0)); 946 947 // TODO: Don't fully scalarize v2s16 pieces 948 getActionDefinitionsBuilder(G_SHUFFLE_VECTOR).lower(); 949 950 // Merge/Unmerge 951 for (unsigned Op : {G_MERGE_VALUES, G_UNMERGE_VALUES}) { 952 unsigned BigTyIdx = Op == G_MERGE_VALUES ? 0 : 1; 953 unsigned LitTyIdx = Op == G_MERGE_VALUES ? 1 : 0; 954 955 auto notValidElt = [=](const LegalityQuery &Query, unsigned TypeIdx) { 956 const LLT &Ty = Query.Types[TypeIdx]; 957 if (Ty.isVector()) { 958 const LLT &EltTy = Ty.getElementType(); 959 if (EltTy.getSizeInBits() < 8 || EltTy.getSizeInBits() > 64) 960 return true; 961 if (!isPowerOf2_32(EltTy.getSizeInBits())) 962 return true; 963 } 964 return false; 965 }; 966 967 getActionDefinitionsBuilder(Op) 968 .widenScalarToNextPow2(LitTyIdx, /*Min*/ 16) 969 // Clamp the little scalar to s8-s256 and make it a power of 2. It's not 970 // worth considering the multiples of 64 since 2*192 and 2*384 are not 971 // valid. 972 .clampScalar(LitTyIdx, S16, S256) 973 .widenScalarToNextPow2(LitTyIdx, /*Min*/ 32) 974 .moreElementsIf(isSmallOddVector(BigTyIdx), oneMoreElement(BigTyIdx)) 975 .fewerElementsIf(all(typeIs(0, S16), vectorWiderThan(1, 32), 976 elementTypeIs(1, S16)), 977 changeTo(1, V2S16)) 978 // Break up vectors with weird elements into scalars 979 .fewerElementsIf( 980 [=](const LegalityQuery &Query) { return notValidElt(Query, 0); }, 981 scalarize(0)) 982 .fewerElementsIf( 983 [=](const LegalityQuery &Query) { return notValidElt(Query, 1); }, 984 scalarize(1)) 985 .clampScalar(BigTyIdx, S32, S512) 986 .lowerFor({{S16, V2S16}}) 987 .widenScalarIf( 988 [=](const LegalityQuery &Query) { 989 const LLT &Ty = Query.Types[BigTyIdx]; 990 return !isPowerOf2_32(Ty.getSizeInBits()) && 991 Ty.getSizeInBits() % 16 != 0; 992 }, 993 [=](const LegalityQuery &Query) { 994 // Pick the next power of 2, or a multiple of 64 over 128. 995 // Whichever is smaller. 996 const LLT &Ty = Query.Types[BigTyIdx]; 997 unsigned NewSizeInBits = 1 << Log2_32_Ceil(Ty.getSizeInBits() + 1); 998 if (NewSizeInBits >= 256) { 999 unsigned RoundedTo = alignTo<64>(Ty.getSizeInBits() + 1); 1000 if (RoundedTo < NewSizeInBits) 1001 NewSizeInBits = RoundedTo; 1002 } 1003 return std::make_pair(BigTyIdx, LLT::scalar(NewSizeInBits)); 1004 }) 1005 .legalIf([=](const LegalityQuery &Query) { 1006 const LLT &BigTy = Query.Types[BigTyIdx]; 1007 const LLT &LitTy = Query.Types[LitTyIdx]; 1008 1009 if (BigTy.isVector() && BigTy.getSizeInBits() < 32) 1010 return false; 1011 if (LitTy.isVector() && LitTy.getSizeInBits() < 32) 1012 return false; 1013 1014 return BigTy.getSizeInBits() % 16 == 0 && 1015 LitTy.getSizeInBits() % 16 == 0 && 1016 BigTy.getSizeInBits() <= 512; 1017 }) 1018 // Any vectors left are the wrong size. Scalarize them. 1019 .scalarize(0) 1020 .scalarize(1); 1021 } 1022 1023 getActionDefinitionsBuilder(G_SEXT_INREG).lower(); 1024 1025 computeTables(); 1026 verify(*ST.getInstrInfo()); 1027 } 1028 1029 bool AMDGPULegalizerInfo::legalizeCustom(MachineInstr &MI, 1030 MachineRegisterInfo &MRI, 1031 MachineIRBuilder &B, 1032 GISelChangeObserver &Observer) const { 1033 switch (MI.getOpcode()) { 1034 case TargetOpcode::G_ADDRSPACE_CAST: 1035 return legalizeAddrSpaceCast(MI, MRI, B); 1036 case TargetOpcode::G_FRINT: 1037 return legalizeFrint(MI, MRI, B); 1038 case TargetOpcode::G_FCEIL: 1039 return legalizeFceil(MI, MRI, B); 1040 case TargetOpcode::G_INTRINSIC_TRUNC: 1041 return legalizeIntrinsicTrunc(MI, MRI, B); 1042 case TargetOpcode::G_SITOFP: 1043 return legalizeITOFP(MI, MRI, B, true); 1044 case TargetOpcode::G_UITOFP: 1045 return legalizeITOFP(MI, MRI, B, false); 1046 case TargetOpcode::G_FMINNUM: 1047 case TargetOpcode::G_FMAXNUM: 1048 case TargetOpcode::G_FMINNUM_IEEE: 1049 case TargetOpcode::G_FMAXNUM_IEEE: 1050 return legalizeMinNumMaxNum(MI, MRI, B); 1051 case TargetOpcode::G_EXTRACT_VECTOR_ELT: 1052 return legalizeExtractVectorElt(MI, MRI, B); 1053 case TargetOpcode::G_INSERT_VECTOR_ELT: 1054 return legalizeInsertVectorElt(MI, MRI, B); 1055 case TargetOpcode::G_FSIN: 1056 case TargetOpcode::G_FCOS: 1057 return legalizeSinCos(MI, MRI, B); 1058 case TargetOpcode::G_GLOBAL_VALUE: 1059 return legalizeGlobalValue(MI, MRI, B); 1060 case TargetOpcode::G_LOAD: 1061 return legalizeLoad(MI, MRI, B, Observer); 1062 case TargetOpcode::G_FMAD: 1063 return legalizeFMad(MI, MRI, B); 1064 default: 1065 return false; 1066 } 1067 1068 llvm_unreachable("expected switch to return"); 1069 } 1070 1071 Register AMDGPULegalizerInfo::getSegmentAperture( 1072 unsigned AS, 1073 MachineRegisterInfo &MRI, 1074 MachineIRBuilder &B) const { 1075 MachineFunction &MF = B.getMF(); 1076 const GCNSubtarget &ST = MF.getSubtarget<GCNSubtarget>(); 1077 const LLT S32 = LLT::scalar(32); 1078 1079 if (ST.hasApertureRegs()) { 1080 // FIXME: Use inline constants (src_{shared, private}_base) instead of 1081 // getreg. 1082 unsigned Offset = AS == AMDGPUAS::LOCAL_ADDRESS ? 1083 AMDGPU::Hwreg::OFFSET_SRC_SHARED_BASE : 1084 AMDGPU::Hwreg::OFFSET_SRC_PRIVATE_BASE; 1085 unsigned WidthM1 = AS == AMDGPUAS::LOCAL_ADDRESS ? 1086 AMDGPU::Hwreg::WIDTH_M1_SRC_SHARED_BASE : 1087 AMDGPU::Hwreg::WIDTH_M1_SRC_PRIVATE_BASE; 1088 unsigned Encoding = 1089 AMDGPU::Hwreg::ID_MEM_BASES << AMDGPU::Hwreg::ID_SHIFT_ | 1090 Offset << AMDGPU::Hwreg::OFFSET_SHIFT_ | 1091 WidthM1 << AMDGPU::Hwreg::WIDTH_M1_SHIFT_; 1092 1093 Register ApertureReg = MRI.createGenericVirtualRegister(S32); 1094 Register GetReg = MRI.createVirtualRegister(&AMDGPU::SReg_32RegClass); 1095 1096 B.buildInstr(AMDGPU::S_GETREG_B32) 1097 .addDef(GetReg) 1098 .addImm(Encoding); 1099 MRI.setType(GetReg, S32); 1100 1101 auto ShiftAmt = B.buildConstant(S32, WidthM1 + 1); 1102 B.buildInstr(TargetOpcode::G_SHL) 1103 .addDef(ApertureReg) 1104 .addUse(GetReg) 1105 .addUse(ShiftAmt.getReg(0)); 1106 1107 return ApertureReg; 1108 } 1109 1110 Register QueuePtr = MRI.createGenericVirtualRegister( 1111 LLT::pointer(AMDGPUAS::CONSTANT_ADDRESS, 64)); 1112 1113 const SIMachineFunctionInfo *MFI = MF.getInfo<SIMachineFunctionInfo>(); 1114 if (!loadInputValue(QueuePtr, B, &MFI->getArgInfo().QueuePtr)) 1115 return Register(); 1116 1117 // Offset into amd_queue_t for group_segment_aperture_base_hi / 1118 // private_segment_aperture_base_hi. 1119 uint32_t StructOffset = (AS == AMDGPUAS::LOCAL_ADDRESS) ? 0x40 : 0x44; 1120 1121 // FIXME: Don't use undef 1122 Value *V = UndefValue::get(PointerType::get( 1123 Type::getInt8Ty(MF.getFunction().getContext()), 1124 AMDGPUAS::CONSTANT_ADDRESS)); 1125 1126 MachinePointerInfo PtrInfo(V, StructOffset); 1127 MachineMemOperand *MMO = MF.getMachineMemOperand( 1128 PtrInfo, 1129 MachineMemOperand::MOLoad | 1130 MachineMemOperand::MODereferenceable | 1131 MachineMemOperand::MOInvariant, 1132 4, 1133 MinAlign(64, StructOffset)); 1134 1135 Register LoadResult = MRI.createGenericVirtualRegister(S32); 1136 Register LoadAddr; 1137 1138 B.materializeGEP(LoadAddr, QueuePtr, LLT::scalar(64), StructOffset); 1139 B.buildLoad(LoadResult, LoadAddr, *MMO); 1140 return LoadResult; 1141 } 1142 1143 bool AMDGPULegalizerInfo::legalizeAddrSpaceCast( 1144 MachineInstr &MI, MachineRegisterInfo &MRI, 1145 MachineIRBuilder &B) const { 1146 MachineFunction &MF = B.getMF(); 1147 1148 B.setInstr(MI); 1149 1150 const LLT S32 = LLT::scalar(32); 1151 Register Dst = MI.getOperand(0).getReg(); 1152 Register Src = MI.getOperand(1).getReg(); 1153 1154 LLT DstTy = MRI.getType(Dst); 1155 LLT SrcTy = MRI.getType(Src); 1156 unsigned DestAS = DstTy.getAddressSpace(); 1157 unsigned SrcAS = SrcTy.getAddressSpace(); 1158 1159 // TODO: Avoid reloading from the queue ptr for each cast, or at least each 1160 // vector element. 1161 assert(!DstTy.isVector()); 1162 1163 const AMDGPUTargetMachine &TM 1164 = static_cast<const AMDGPUTargetMachine &>(MF.getTarget()); 1165 1166 const GCNSubtarget &ST = MF.getSubtarget<GCNSubtarget>(); 1167 if (ST.getTargetLowering()->isNoopAddrSpaceCast(SrcAS, DestAS)) { 1168 MI.setDesc(B.getTII().get(TargetOpcode::G_BITCAST)); 1169 return true; 1170 } 1171 1172 if (DestAS == AMDGPUAS::CONSTANT_ADDRESS_32BIT) { 1173 // Truncate. 1174 B.buildExtract(Dst, Src, 0); 1175 MI.eraseFromParent(); 1176 return true; 1177 } 1178 1179 if (SrcAS == AMDGPUAS::CONSTANT_ADDRESS_32BIT) { 1180 const SIMachineFunctionInfo *Info = MF.getInfo<SIMachineFunctionInfo>(); 1181 uint32_t AddrHiVal = Info->get32BitAddressHighBits(); 1182 1183 // FIXME: This is a bit ugly due to creating a merge of 2 pointers to 1184 // another. Merge operands are required to be the same type, but creating an 1185 // extra ptrtoint would be kind of pointless. 1186 auto HighAddr = B.buildConstant( 1187 LLT::pointer(AMDGPUAS::CONSTANT_ADDRESS_32BIT, 32), AddrHiVal); 1188 B.buildMerge(Dst, {Src, HighAddr.getReg(0)}); 1189 MI.eraseFromParent(); 1190 return true; 1191 } 1192 1193 if (SrcAS == AMDGPUAS::FLAT_ADDRESS) { 1194 assert(DestAS == AMDGPUAS::LOCAL_ADDRESS || 1195 DestAS == AMDGPUAS::PRIVATE_ADDRESS); 1196 unsigned NullVal = TM.getNullPointerValue(DestAS); 1197 1198 auto SegmentNull = B.buildConstant(DstTy, NullVal); 1199 auto FlatNull = B.buildConstant(SrcTy, 0); 1200 1201 Register PtrLo32 = MRI.createGenericVirtualRegister(DstTy); 1202 1203 // Extract low 32-bits of the pointer. 1204 B.buildExtract(PtrLo32, Src, 0); 1205 1206 Register CmpRes = MRI.createGenericVirtualRegister(LLT::scalar(1)); 1207 B.buildICmp(CmpInst::ICMP_NE, CmpRes, Src, FlatNull.getReg(0)); 1208 B.buildSelect(Dst, CmpRes, PtrLo32, SegmentNull.getReg(0)); 1209 1210 MI.eraseFromParent(); 1211 return true; 1212 } 1213 1214 if (SrcAS != AMDGPUAS::LOCAL_ADDRESS && SrcAS != AMDGPUAS::PRIVATE_ADDRESS) 1215 return false; 1216 1217 if (!ST.hasFlatAddressSpace()) 1218 return false; 1219 1220 auto SegmentNull = 1221 B.buildConstant(SrcTy, TM.getNullPointerValue(SrcAS)); 1222 auto FlatNull = 1223 B.buildConstant(DstTy, TM.getNullPointerValue(DestAS)); 1224 1225 Register ApertureReg = getSegmentAperture(DestAS, MRI, B); 1226 if (!ApertureReg.isValid()) 1227 return false; 1228 1229 Register CmpRes = MRI.createGenericVirtualRegister(LLT::scalar(1)); 1230 B.buildICmp(CmpInst::ICMP_NE, CmpRes, Src, SegmentNull.getReg(0)); 1231 1232 Register BuildPtr = MRI.createGenericVirtualRegister(DstTy); 1233 1234 // Coerce the type of the low half of the result so we can use merge_values. 1235 Register SrcAsInt = MRI.createGenericVirtualRegister(S32); 1236 B.buildInstr(TargetOpcode::G_PTRTOINT) 1237 .addDef(SrcAsInt) 1238 .addUse(Src); 1239 1240 // TODO: Should we allow mismatched types but matching sizes in merges to 1241 // avoid the ptrtoint? 1242 B.buildMerge(BuildPtr, {SrcAsInt, ApertureReg}); 1243 B.buildSelect(Dst, CmpRes, BuildPtr, FlatNull.getReg(0)); 1244 1245 MI.eraseFromParent(); 1246 return true; 1247 } 1248 1249 bool AMDGPULegalizerInfo::legalizeFrint( 1250 MachineInstr &MI, MachineRegisterInfo &MRI, 1251 MachineIRBuilder &B) const { 1252 B.setInstr(MI); 1253 1254 Register Src = MI.getOperand(1).getReg(); 1255 LLT Ty = MRI.getType(Src); 1256 assert(Ty.isScalar() && Ty.getSizeInBits() == 64); 1257 1258 APFloat C1Val(APFloat::IEEEdouble(), "0x1.0p+52"); 1259 APFloat C2Val(APFloat::IEEEdouble(), "0x1.fffffffffffffp+51"); 1260 1261 auto C1 = B.buildFConstant(Ty, C1Val); 1262 auto CopySign = B.buildFCopysign(Ty, C1, Src); 1263 1264 // TODO: Should this propagate fast-math-flags? 1265 auto Tmp1 = B.buildFAdd(Ty, Src, CopySign); 1266 auto Tmp2 = B.buildFSub(Ty, Tmp1, CopySign); 1267 1268 auto C2 = B.buildFConstant(Ty, C2Val); 1269 auto Fabs = B.buildFAbs(Ty, Src); 1270 1271 auto Cond = B.buildFCmp(CmpInst::FCMP_OGT, LLT::scalar(1), Fabs, C2); 1272 B.buildSelect(MI.getOperand(0).getReg(), Cond, Src, Tmp2); 1273 return true; 1274 } 1275 1276 bool AMDGPULegalizerInfo::legalizeFceil( 1277 MachineInstr &MI, MachineRegisterInfo &MRI, 1278 MachineIRBuilder &B) const { 1279 B.setInstr(MI); 1280 1281 const LLT S1 = LLT::scalar(1); 1282 const LLT S64 = LLT::scalar(64); 1283 1284 Register Src = MI.getOperand(1).getReg(); 1285 assert(MRI.getType(Src) == S64); 1286 1287 // result = trunc(src) 1288 // if (src > 0.0 && src != result) 1289 // result += 1.0 1290 1291 auto Trunc = B.buildInstr(TargetOpcode::G_INTRINSIC_TRUNC, {S64}, {Src}); 1292 1293 const auto Zero = B.buildFConstant(S64, 0.0); 1294 const auto One = B.buildFConstant(S64, 1.0); 1295 auto Lt0 = B.buildFCmp(CmpInst::FCMP_OGT, S1, Src, Zero); 1296 auto NeTrunc = B.buildFCmp(CmpInst::FCMP_ONE, S1, Src, Trunc); 1297 auto And = B.buildAnd(S1, Lt0, NeTrunc); 1298 auto Add = B.buildSelect(S64, And, One, Zero); 1299 1300 // TODO: Should this propagate fast-math-flags? 1301 B.buildFAdd(MI.getOperand(0).getReg(), Trunc, Add); 1302 return true; 1303 } 1304 1305 static MachineInstrBuilder extractF64Exponent(unsigned Hi, 1306 MachineIRBuilder &B) { 1307 const unsigned FractBits = 52; 1308 const unsigned ExpBits = 11; 1309 LLT S32 = LLT::scalar(32); 1310 1311 auto Const0 = B.buildConstant(S32, FractBits - 32); 1312 auto Const1 = B.buildConstant(S32, ExpBits); 1313 1314 auto ExpPart = B.buildIntrinsic(Intrinsic::amdgcn_ubfe, {S32}, false) 1315 .addUse(Const0.getReg(0)) 1316 .addUse(Const1.getReg(0)); 1317 1318 return B.buildSub(S32, ExpPart, B.buildConstant(S32, 1023)); 1319 } 1320 1321 bool AMDGPULegalizerInfo::legalizeIntrinsicTrunc( 1322 MachineInstr &MI, MachineRegisterInfo &MRI, 1323 MachineIRBuilder &B) const { 1324 B.setInstr(MI); 1325 1326 const LLT S1 = LLT::scalar(1); 1327 const LLT S32 = LLT::scalar(32); 1328 const LLT S64 = LLT::scalar(64); 1329 1330 Register Src = MI.getOperand(1).getReg(); 1331 assert(MRI.getType(Src) == S64); 1332 1333 // TODO: Should this use extract since the low half is unused? 1334 auto Unmerge = B.buildUnmerge({S32, S32}, Src); 1335 Register Hi = Unmerge.getReg(1); 1336 1337 // Extract the upper half, since this is where we will find the sign and 1338 // exponent. 1339 auto Exp = extractF64Exponent(Hi, B); 1340 1341 const unsigned FractBits = 52; 1342 1343 // Extract the sign bit. 1344 const auto SignBitMask = B.buildConstant(S32, UINT32_C(1) << 31); 1345 auto SignBit = B.buildAnd(S32, Hi, SignBitMask); 1346 1347 const auto FractMask = B.buildConstant(S64, (UINT64_C(1) << FractBits) - 1); 1348 1349 const auto Zero32 = B.buildConstant(S32, 0); 1350 1351 // Extend back to 64-bits. 1352 auto SignBit64 = B.buildMerge(S64, {Zero32.getReg(0), SignBit.getReg(0)}); 1353 1354 auto Shr = B.buildAShr(S64, FractMask, Exp); 1355 auto Not = B.buildNot(S64, Shr); 1356 auto Tmp0 = B.buildAnd(S64, Src, Not); 1357 auto FiftyOne = B.buildConstant(S32, FractBits - 1); 1358 1359 auto ExpLt0 = B.buildICmp(CmpInst::ICMP_SLT, S1, Exp, Zero32); 1360 auto ExpGt51 = B.buildICmp(CmpInst::ICMP_SGT, S1, Exp, FiftyOne); 1361 1362 auto Tmp1 = B.buildSelect(S64, ExpLt0, SignBit64, Tmp0); 1363 B.buildSelect(MI.getOperand(0).getReg(), ExpGt51, Src, Tmp1); 1364 return true; 1365 } 1366 1367 bool AMDGPULegalizerInfo::legalizeITOFP( 1368 MachineInstr &MI, MachineRegisterInfo &MRI, 1369 MachineIRBuilder &B, bool Signed) const { 1370 B.setInstr(MI); 1371 1372 Register Dst = MI.getOperand(0).getReg(); 1373 Register Src = MI.getOperand(1).getReg(); 1374 1375 const LLT S64 = LLT::scalar(64); 1376 const LLT S32 = LLT::scalar(32); 1377 1378 assert(MRI.getType(Src) == S64 && MRI.getType(Dst) == S64); 1379 1380 auto Unmerge = B.buildUnmerge({S32, S32}, Src); 1381 1382 auto CvtHi = Signed ? 1383 B.buildSITOFP(S64, Unmerge.getReg(1)) : 1384 B.buildUITOFP(S64, Unmerge.getReg(1)); 1385 1386 auto CvtLo = B.buildUITOFP(S64, Unmerge.getReg(0)); 1387 1388 auto ThirtyTwo = B.buildConstant(S32, 32); 1389 auto LdExp = B.buildIntrinsic(Intrinsic::amdgcn_ldexp, {S64}, false) 1390 .addUse(CvtHi.getReg(0)) 1391 .addUse(ThirtyTwo.getReg(0)); 1392 1393 // TODO: Should this propagate fast-math-flags? 1394 B.buildFAdd(Dst, LdExp, CvtLo); 1395 MI.eraseFromParent(); 1396 return true; 1397 } 1398 1399 bool AMDGPULegalizerInfo::legalizeMinNumMaxNum( 1400 MachineInstr &MI, MachineRegisterInfo &MRI, 1401 MachineIRBuilder &B) const { 1402 MachineFunction &MF = B.getMF(); 1403 const SIMachineFunctionInfo *MFI = MF.getInfo<SIMachineFunctionInfo>(); 1404 1405 const bool IsIEEEOp = MI.getOpcode() == AMDGPU::G_FMINNUM_IEEE || 1406 MI.getOpcode() == AMDGPU::G_FMAXNUM_IEEE; 1407 1408 // With ieee_mode disabled, the instructions have the correct behavior 1409 // already for G_FMINNUM/G_FMAXNUM 1410 if (!MFI->getMode().IEEE) 1411 return !IsIEEEOp; 1412 1413 if (IsIEEEOp) 1414 return true; 1415 1416 MachineIRBuilder HelperBuilder(MI); 1417 GISelObserverWrapper DummyObserver; 1418 LegalizerHelper Helper(MF, DummyObserver, HelperBuilder); 1419 HelperBuilder.setInstr(MI); 1420 return Helper.lowerFMinNumMaxNum(MI) == LegalizerHelper::Legalized; 1421 } 1422 1423 bool AMDGPULegalizerInfo::legalizeExtractVectorElt( 1424 MachineInstr &MI, MachineRegisterInfo &MRI, 1425 MachineIRBuilder &B) const { 1426 // TODO: Should move some of this into LegalizerHelper. 1427 1428 // TODO: Promote dynamic indexing of s16 to s32 1429 // TODO: Dynamic s64 indexing is only legal for SGPR. 1430 Optional<int64_t> IdxVal = getConstantVRegVal(MI.getOperand(2).getReg(), MRI); 1431 if (!IdxVal) // Dynamic case will be selected to register indexing. 1432 return true; 1433 1434 Register Dst = MI.getOperand(0).getReg(); 1435 Register Vec = MI.getOperand(1).getReg(); 1436 1437 LLT VecTy = MRI.getType(Vec); 1438 LLT EltTy = VecTy.getElementType(); 1439 assert(EltTy == MRI.getType(Dst)); 1440 1441 B.setInstr(MI); 1442 1443 if (IdxVal.getValue() < VecTy.getNumElements()) 1444 B.buildExtract(Dst, Vec, IdxVal.getValue() * EltTy.getSizeInBits()); 1445 else 1446 B.buildUndef(Dst); 1447 1448 MI.eraseFromParent(); 1449 return true; 1450 } 1451 1452 bool AMDGPULegalizerInfo::legalizeInsertVectorElt( 1453 MachineInstr &MI, MachineRegisterInfo &MRI, 1454 MachineIRBuilder &B) const { 1455 // TODO: Should move some of this into LegalizerHelper. 1456 1457 // TODO: Promote dynamic indexing of s16 to s32 1458 // TODO: Dynamic s64 indexing is only legal for SGPR. 1459 Optional<int64_t> IdxVal = getConstantVRegVal(MI.getOperand(3).getReg(), MRI); 1460 if (!IdxVal) // Dynamic case will be selected to register indexing. 1461 return true; 1462 1463 Register Dst = MI.getOperand(0).getReg(); 1464 Register Vec = MI.getOperand(1).getReg(); 1465 Register Ins = MI.getOperand(2).getReg(); 1466 1467 LLT VecTy = MRI.getType(Vec); 1468 LLT EltTy = VecTy.getElementType(); 1469 assert(EltTy == MRI.getType(Ins)); 1470 1471 B.setInstr(MI); 1472 1473 if (IdxVal.getValue() < VecTy.getNumElements()) 1474 B.buildInsert(Dst, Vec, Ins, IdxVal.getValue() * EltTy.getSizeInBits()); 1475 else 1476 B.buildUndef(Dst); 1477 1478 MI.eraseFromParent(); 1479 return true; 1480 } 1481 1482 bool AMDGPULegalizerInfo::legalizeSinCos( 1483 MachineInstr &MI, MachineRegisterInfo &MRI, 1484 MachineIRBuilder &B) const { 1485 B.setInstr(MI); 1486 1487 Register DstReg = MI.getOperand(0).getReg(); 1488 Register SrcReg = MI.getOperand(1).getReg(); 1489 LLT Ty = MRI.getType(DstReg); 1490 unsigned Flags = MI.getFlags(); 1491 1492 Register TrigVal; 1493 auto OneOver2Pi = B.buildFConstant(Ty, 0.5 / M_PI); 1494 if (ST.hasTrigReducedRange()) { 1495 auto MulVal = B.buildFMul(Ty, SrcReg, OneOver2Pi, Flags); 1496 TrigVal = B.buildIntrinsic(Intrinsic::amdgcn_fract, {Ty}, false) 1497 .addUse(MulVal.getReg(0)) 1498 .setMIFlags(Flags).getReg(0); 1499 } else 1500 TrigVal = B.buildFMul(Ty, SrcReg, OneOver2Pi, Flags).getReg(0); 1501 1502 Intrinsic::ID TrigIntrin = MI.getOpcode() == AMDGPU::G_FSIN ? 1503 Intrinsic::amdgcn_sin : Intrinsic::amdgcn_cos; 1504 B.buildIntrinsic(TrigIntrin, makeArrayRef<Register>(DstReg), false) 1505 .addUse(TrigVal) 1506 .setMIFlags(Flags); 1507 MI.eraseFromParent(); 1508 return true; 1509 } 1510 1511 bool AMDGPULegalizerInfo::legalizeGlobalValue( 1512 MachineInstr &MI, MachineRegisterInfo &MRI, 1513 MachineIRBuilder &B) const { 1514 Register DstReg = MI.getOperand(0).getReg(); 1515 LLT Ty = MRI.getType(DstReg); 1516 unsigned AS = Ty.getAddressSpace(); 1517 1518 const GlobalValue *GV = MI.getOperand(1).getGlobal(); 1519 MachineFunction &MF = B.getMF(); 1520 SIMachineFunctionInfo *MFI = MF.getInfo<SIMachineFunctionInfo>(); 1521 1522 if (AS == AMDGPUAS::LOCAL_ADDRESS || AS == AMDGPUAS::REGION_ADDRESS) { 1523 B.setInstr(MI); 1524 1525 if (!MFI->isEntryFunction()) { 1526 const Function &Fn = MF.getFunction(); 1527 DiagnosticInfoUnsupported BadLDSDecl( 1528 Fn, "local memory global used by non-kernel function", MI.getDebugLoc()); 1529 Fn.getContext().diagnose(BadLDSDecl); 1530 } 1531 1532 // TODO: We could emit code to handle the initialization somewhere. 1533 if (!AMDGPUTargetLowering::hasDefinedInitializer(GV)) { 1534 B.buildConstant(DstReg, MFI->allocateLDSGlobal(B.getDataLayout(), *GV)); 1535 MI.eraseFromParent(); 1536 return true; 1537 } 1538 } else 1539 return false; 1540 1541 const Function &Fn = MF.getFunction(); 1542 DiagnosticInfoUnsupported BadInit( 1543 Fn, "unsupported initializer for address space", MI.getDebugLoc()); 1544 Fn.getContext().diagnose(BadInit); 1545 return true; 1546 } 1547 1548 bool AMDGPULegalizerInfo::legalizeLoad( 1549 MachineInstr &MI, MachineRegisterInfo &MRI, 1550 MachineIRBuilder &B, GISelChangeObserver &Observer) const { 1551 B.setInstr(MI); 1552 LLT ConstPtr = LLT::pointer(AMDGPUAS::CONSTANT_ADDRESS, 64); 1553 auto Cast = B.buildAddrSpaceCast(ConstPtr, MI.getOperand(1).getReg()); 1554 Observer.changingInstr(MI); 1555 MI.getOperand(1).setReg(Cast.getReg(0)); 1556 Observer.changedInstr(MI); 1557 return true; 1558 } 1559 1560 bool AMDGPULegalizerInfo::legalizeFMad( 1561 MachineInstr &MI, MachineRegisterInfo &MRI, 1562 MachineIRBuilder &B) const { 1563 LLT Ty = MRI.getType(MI.getOperand(0).getReg()); 1564 assert(Ty.isScalar()); 1565 1566 // TODO: Always legal with future ftz flag. 1567 if (Ty == LLT::scalar(32) && !ST.hasFP32Denormals()) 1568 return true; 1569 if (Ty == LLT::scalar(16) && !ST.hasFP16Denormals()) 1570 return true; 1571 1572 MachineFunction &MF = B.getMF(); 1573 1574 MachineIRBuilder HelperBuilder(MI); 1575 GISelObserverWrapper DummyObserver; 1576 LegalizerHelper Helper(MF, DummyObserver, HelperBuilder); 1577 HelperBuilder.setMBB(*MI.getParent()); 1578 return Helper.lowerFMad(MI) == LegalizerHelper::Legalized; 1579 } 1580 1581 // Return the use branch instruction, otherwise null if the usage is invalid. 1582 static MachineInstr *verifyCFIntrinsic(MachineInstr &MI, 1583 MachineRegisterInfo &MRI) { 1584 Register CondDef = MI.getOperand(0).getReg(); 1585 if (!MRI.hasOneNonDBGUse(CondDef)) 1586 return nullptr; 1587 1588 MachineInstr &UseMI = *MRI.use_instr_nodbg_begin(CondDef); 1589 return UseMI.getParent() == MI.getParent() && 1590 UseMI.getOpcode() == AMDGPU::G_BRCOND ? &UseMI : nullptr; 1591 } 1592 1593 Register AMDGPULegalizerInfo::getLiveInRegister(MachineRegisterInfo &MRI, 1594 Register Reg, LLT Ty) const { 1595 Register LiveIn = MRI.getLiveInVirtReg(Reg); 1596 if (LiveIn) 1597 return LiveIn; 1598 1599 Register NewReg = MRI.createGenericVirtualRegister(Ty); 1600 MRI.addLiveIn(Reg, NewReg); 1601 return NewReg; 1602 } 1603 1604 bool AMDGPULegalizerInfo::loadInputValue(Register DstReg, MachineIRBuilder &B, 1605 const ArgDescriptor *Arg) const { 1606 if (!Arg->isRegister() || !Arg->getRegister().isValid()) 1607 return false; // TODO: Handle these 1608 1609 assert(Arg->getRegister().isPhysical()); 1610 1611 MachineRegisterInfo &MRI = *B.getMRI(); 1612 1613 LLT Ty = MRI.getType(DstReg); 1614 Register LiveIn = getLiveInRegister(MRI, Arg->getRegister(), Ty); 1615 1616 if (Arg->isMasked()) { 1617 // TODO: Should we try to emit this once in the entry block? 1618 const LLT S32 = LLT::scalar(32); 1619 const unsigned Mask = Arg->getMask(); 1620 const unsigned Shift = countTrailingZeros<unsigned>(Mask); 1621 1622 auto ShiftAmt = B.buildConstant(S32, Shift); 1623 auto LShr = B.buildLShr(S32, LiveIn, ShiftAmt); 1624 B.buildAnd(DstReg, LShr, B.buildConstant(S32, Mask >> Shift)); 1625 } else 1626 B.buildCopy(DstReg, LiveIn); 1627 1628 // Insert the argument copy if it doens't already exist. 1629 // FIXME: It seems EmitLiveInCopies isn't called anywhere? 1630 if (!MRI.getVRegDef(LiveIn)) { 1631 // FIXME: Should have scoped insert pt 1632 MachineBasicBlock &OrigInsBB = B.getMBB(); 1633 auto OrigInsPt = B.getInsertPt(); 1634 1635 MachineBasicBlock &EntryMBB = B.getMF().front(); 1636 EntryMBB.addLiveIn(Arg->getRegister()); 1637 B.setInsertPt(EntryMBB, EntryMBB.begin()); 1638 B.buildCopy(LiveIn, Arg->getRegister()); 1639 1640 B.setInsertPt(OrigInsBB, OrigInsPt); 1641 } 1642 1643 return true; 1644 } 1645 1646 bool AMDGPULegalizerInfo::legalizePreloadedArgIntrin( 1647 MachineInstr &MI, 1648 MachineRegisterInfo &MRI, 1649 MachineIRBuilder &B, 1650 AMDGPUFunctionArgInfo::PreloadedValue ArgType) const { 1651 B.setInstr(MI); 1652 1653 const SIMachineFunctionInfo *MFI = B.getMF().getInfo<SIMachineFunctionInfo>(); 1654 1655 const ArgDescriptor *Arg; 1656 const TargetRegisterClass *RC; 1657 std::tie(Arg, RC) = MFI->getPreloadedValue(ArgType); 1658 if (!Arg) { 1659 LLVM_DEBUG(dbgs() << "Required arg register missing\n"); 1660 return false; 1661 } 1662 1663 if (loadInputValue(MI.getOperand(0).getReg(), B, Arg)) { 1664 MI.eraseFromParent(); 1665 return true; 1666 } 1667 1668 return false; 1669 } 1670 1671 bool AMDGPULegalizerInfo::legalizeFDIVFast(MachineInstr &MI, 1672 MachineRegisterInfo &MRI, 1673 MachineIRBuilder &B) const { 1674 B.setInstr(MI); 1675 Register Res = MI.getOperand(0).getReg(); 1676 Register LHS = MI.getOperand(2).getReg(); 1677 Register RHS = MI.getOperand(3).getReg(); 1678 uint16_t Flags = MI.getFlags(); 1679 1680 LLT S32 = LLT::scalar(32); 1681 LLT S1 = LLT::scalar(1); 1682 1683 auto Abs = B.buildFAbs(S32, RHS, Flags); 1684 const APFloat C0Val(1.0f); 1685 1686 auto C0 = B.buildConstant(S32, 0x6f800000); 1687 auto C1 = B.buildConstant(S32, 0x2f800000); 1688 auto C2 = B.buildConstant(S32, FloatToBits(1.0f)); 1689 1690 auto CmpRes = B.buildFCmp(CmpInst::FCMP_OGT, S1, Abs, C0, Flags); 1691 auto Sel = B.buildSelect(S32, CmpRes, C1, C2, Flags); 1692 1693 auto Mul0 = B.buildFMul(S32, RHS, Sel, Flags); 1694 1695 auto RCP = B.buildIntrinsic(Intrinsic::amdgcn_rcp, {S32}, false) 1696 .addUse(Mul0.getReg(0)) 1697 .setMIFlags(Flags); 1698 1699 auto Mul1 = B.buildFMul(S32, LHS, RCP, Flags); 1700 1701 B.buildFMul(Res, Sel, Mul1, Flags); 1702 1703 MI.eraseFromParent(); 1704 return true; 1705 } 1706 1707 bool AMDGPULegalizerInfo::legalizeImplicitArgPtr(MachineInstr &MI, 1708 MachineRegisterInfo &MRI, 1709 MachineIRBuilder &B) const { 1710 const SIMachineFunctionInfo *MFI = B.getMF().getInfo<SIMachineFunctionInfo>(); 1711 if (!MFI->isEntryFunction()) { 1712 return legalizePreloadedArgIntrin(MI, MRI, B, 1713 AMDGPUFunctionArgInfo::IMPLICIT_ARG_PTR); 1714 } 1715 1716 B.setInstr(MI); 1717 1718 uint64_t Offset = 1719 ST.getTargetLowering()->getImplicitParameterOffset( 1720 B.getMF(), AMDGPUTargetLowering::FIRST_IMPLICIT); 1721 Register DstReg = MI.getOperand(0).getReg(); 1722 LLT DstTy = MRI.getType(DstReg); 1723 LLT IdxTy = LLT::scalar(DstTy.getSizeInBits()); 1724 1725 const ArgDescriptor *Arg; 1726 const TargetRegisterClass *RC; 1727 std::tie(Arg, RC) 1728 = MFI->getPreloadedValue(AMDGPUFunctionArgInfo::KERNARG_SEGMENT_PTR); 1729 if (!Arg) 1730 return false; 1731 1732 Register KernargPtrReg = MRI.createGenericVirtualRegister(DstTy); 1733 if (!loadInputValue(KernargPtrReg, B, Arg)) 1734 return false; 1735 1736 B.buildGEP(DstReg, KernargPtrReg, B.buildConstant(IdxTy, Offset).getReg(0)); 1737 MI.eraseFromParent(); 1738 return true; 1739 } 1740 1741 bool AMDGPULegalizerInfo::legalizeIsAddrSpace(MachineInstr &MI, 1742 MachineRegisterInfo &MRI, 1743 MachineIRBuilder &B, 1744 unsigned AddrSpace) const { 1745 B.setInstr(MI); 1746 Register ApertureReg = getSegmentAperture(AddrSpace, MRI, B); 1747 auto Hi32 = B.buildExtract(LLT::scalar(32), MI.getOperand(2).getReg(), 32); 1748 B.buildICmp(ICmpInst::ICMP_EQ, MI.getOperand(0), Hi32, ApertureReg); 1749 MI.eraseFromParent(); 1750 return true; 1751 } 1752 1753 bool AMDGPULegalizerInfo::legalizeIntrinsic(MachineInstr &MI, 1754 MachineRegisterInfo &MRI, 1755 MachineIRBuilder &B) const { 1756 // Replace the use G_BRCOND with the exec manipulate and branch pseudos. 1757 switch (MI.getOperand(MI.getNumExplicitDefs()).getIntrinsicID()) { 1758 case Intrinsic::amdgcn_if: { 1759 if (MachineInstr *BrCond = verifyCFIntrinsic(MI, MRI)) { 1760 const SIRegisterInfo *TRI 1761 = static_cast<const SIRegisterInfo *>(MRI.getTargetRegisterInfo()); 1762 1763 B.setInstr(*BrCond); 1764 Register Def = MI.getOperand(1).getReg(); 1765 Register Use = MI.getOperand(3).getReg(); 1766 B.buildInstr(AMDGPU::SI_IF) 1767 .addDef(Def) 1768 .addUse(Use) 1769 .addMBB(BrCond->getOperand(1).getMBB()); 1770 1771 MRI.setRegClass(Def, TRI->getWaveMaskRegClass()); 1772 MRI.setRegClass(Use, TRI->getWaveMaskRegClass()); 1773 MI.eraseFromParent(); 1774 BrCond->eraseFromParent(); 1775 return true; 1776 } 1777 1778 return false; 1779 } 1780 case Intrinsic::amdgcn_loop: { 1781 if (MachineInstr *BrCond = verifyCFIntrinsic(MI, MRI)) { 1782 const SIRegisterInfo *TRI 1783 = static_cast<const SIRegisterInfo *>(MRI.getTargetRegisterInfo()); 1784 1785 B.setInstr(*BrCond); 1786 Register Reg = MI.getOperand(2).getReg(); 1787 B.buildInstr(AMDGPU::SI_LOOP) 1788 .addUse(Reg) 1789 .addMBB(BrCond->getOperand(1).getMBB()); 1790 MI.eraseFromParent(); 1791 BrCond->eraseFromParent(); 1792 MRI.setRegClass(Reg, TRI->getWaveMaskRegClass()); 1793 return true; 1794 } 1795 1796 return false; 1797 } 1798 case Intrinsic::amdgcn_kernarg_segment_ptr: 1799 return legalizePreloadedArgIntrin( 1800 MI, MRI, B, AMDGPUFunctionArgInfo::KERNARG_SEGMENT_PTR); 1801 case Intrinsic::amdgcn_implicitarg_ptr: 1802 return legalizeImplicitArgPtr(MI, MRI, B); 1803 case Intrinsic::amdgcn_workitem_id_x: 1804 return legalizePreloadedArgIntrin(MI, MRI, B, 1805 AMDGPUFunctionArgInfo::WORKITEM_ID_X); 1806 case Intrinsic::amdgcn_workitem_id_y: 1807 return legalizePreloadedArgIntrin(MI, MRI, B, 1808 AMDGPUFunctionArgInfo::WORKITEM_ID_Y); 1809 case Intrinsic::amdgcn_workitem_id_z: 1810 return legalizePreloadedArgIntrin(MI, MRI, B, 1811 AMDGPUFunctionArgInfo::WORKITEM_ID_Z); 1812 case Intrinsic::amdgcn_workgroup_id_x: 1813 return legalizePreloadedArgIntrin(MI, MRI, B, 1814 AMDGPUFunctionArgInfo::WORKGROUP_ID_X); 1815 case Intrinsic::amdgcn_workgroup_id_y: 1816 return legalizePreloadedArgIntrin(MI, MRI, B, 1817 AMDGPUFunctionArgInfo::WORKGROUP_ID_Y); 1818 case Intrinsic::amdgcn_workgroup_id_z: 1819 return legalizePreloadedArgIntrin(MI, MRI, B, 1820 AMDGPUFunctionArgInfo::WORKGROUP_ID_Z); 1821 case Intrinsic::amdgcn_dispatch_ptr: 1822 return legalizePreloadedArgIntrin(MI, MRI, B, 1823 AMDGPUFunctionArgInfo::DISPATCH_PTR); 1824 case Intrinsic::amdgcn_queue_ptr: 1825 return legalizePreloadedArgIntrin(MI, MRI, B, 1826 AMDGPUFunctionArgInfo::QUEUE_PTR); 1827 case Intrinsic::amdgcn_implicit_buffer_ptr: 1828 return legalizePreloadedArgIntrin( 1829 MI, MRI, B, AMDGPUFunctionArgInfo::IMPLICIT_BUFFER_PTR); 1830 case Intrinsic::amdgcn_dispatch_id: 1831 return legalizePreloadedArgIntrin(MI, MRI, B, 1832 AMDGPUFunctionArgInfo::DISPATCH_ID); 1833 case Intrinsic::amdgcn_fdiv_fast: 1834 return legalizeFDIVFast(MI, MRI, B); 1835 case Intrinsic::amdgcn_is_shared: 1836 return legalizeIsAddrSpace(MI, MRI, B, AMDGPUAS::LOCAL_ADDRESS); 1837 case Intrinsic::amdgcn_is_private: 1838 return legalizeIsAddrSpace(MI, MRI, B, AMDGPUAS::PRIVATE_ADDRESS); 1839 case Intrinsic::amdgcn_wavefrontsize: { 1840 B.setInstr(MI); 1841 B.buildConstant(MI.getOperand(0), ST.getWavefrontSize()); 1842 MI.eraseFromParent(); 1843 return true; 1844 } 1845 default: 1846 return true; 1847 } 1848 1849 return true; 1850 } 1851