|
15 | 15 | #include "llvm/CodeGen/CostTable.h"
|
16 | 16 | #include "llvm/CodeGen/TargetLowering.h"
|
17 | 17 | #include "llvm/IR/Constants.h"
|
| 18 | +#include "llvm/IR/IntrinsicInst.h" |
18 | 19 | #include "llvm/IR/Intrinsics.h"
|
19 | 20 | #include "llvm/IR/IntrinsicsNVPTX.h"
|
20 | 21 | #include "llvm/IR/Value.h"
|
21 | 22 | #include "llvm/Support/Casting.h"
|
| 23 | +#include "llvm/Support/ErrorHandling.h" |
22 | 24 | #include "llvm/Transforms/InstCombine/InstCombiner.h"
|
23 | 25 | #include <optional>
|
24 | 26 | using namespace llvm;
|
@@ -117,7 +119,8 @@ bool NVPTXTTIImpl::isSourceOfDivergence(const Value *V) {
|
117 | 119 | }
|
118 | 120 |
|
119 | 121 | // Convert NVVM intrinsics to target-generic LLVM code where possible.
|
120 |
| -static Instruction *simplifyNvvmIntrinsic(IntrinsicInst *II, InstCombiner &IC) { |
| 122 | +static Instruction *convertNvvmIntrinsicToLlvm(InstCombiner &IC, |
| 123 | + IntrinsicInst *II) { |
121 | 124 | // Each NVVM intrinsic we can simplify can be replaced with one of:
|
122 | 125 | //
|
123 | 126 | // * an LLVM intrinsic,
|
@@ -413,11 +416,65 @@ static Instruction *simplifyNvvmIntrinsic(IntrinsicInst *II, InstCombiner &IC) {
|
413 | 416 | llvm_unreachable("All SpecialCase enumerators should be handled in switch.");
|
414 | 417 | }
|
415 | 418 |
|
| 419 | +// Returns an instruction pointer (may be nullptr if we do not know the answer). |
| 420 | +// Returns nullopt if `II` is not one of the `isspacep` intrinsics. |
| 421 | +static std::optional<Instruction *> |
| 422 | +handleSpaceCheckIntrinsics(InstCombiner &IC, IntrinsicInst &II) { |
| 423 | + Value *Op0 = II.getArgOperand(0); |
| 424 | + // Returns true/false when we know the answer, nullopt otherwise. |
| 425 | + auto CheckASMatch = [](unsigned IID, unsigned AS) -> std::optional<bool> { |
| 426 | + if (AS == NVPTXAS::ADDRESS_SPACE_GENERIC || |
| 427 | + AS == NVPTXAS::ADDRESS_SPACE_PARAM) |
| 428 | + return std::nullopt; // Got to check at run-time. |
| 429 | + switch (IID) { |
| 430 | + case Intrinsic::nvvm_isspacep_global: |
| 431 | + return AS == NVPTXAS::ADDRESS_SPACE_GLOBAL; |
| 432 | + case Intrinsic::nvvm_isspacep_local: |
| 433 | + return AS == NVPTXAS::ADDRESS_SPACE_LOCAL; |
| 434 | + case Intrinsic::nvvm_isspacep_shared: |
| 435 | + return AS == NVPTXAS::ADDRESS_SPACE_SHARED; |
| 436 | + case Intrinsic::nvvm_isspacep_shared_cluster: |
| 437 | + // We can't tell shared from shared_cluster at compile time from AS alone, |
| 438 | + // but it can't be either is AS is not shared. |
| 439 | + return AS == NVPTXAS::ADDRESS_SPACE_SHARED ? std::nullopt |
| 440 | + : std::optional{false}; |
| 441 | + case Intrinsic::nvvm_isspacep_const: |
| 442 | + return AS == NVPTXAS::ADDRESS_SPACE_CONST; |
| 443 | + default: |
| 444 | + llvm_unreachable("Unexpected intrinsic"); |
| 445 | + } |
| 446 | + }; |
| 447 | + |
| 448 | + switch (auto IID = II.getIntrinsicID()) { |
| 449 | + case Intrinsic::nvvm_isspacep_global: |
| 450 | + case Intrinsic::nvvm_isspacep_local: |
| 451 | + case Intrinsic::nvvm_isspacep_shared: |
| 452 | + case Intrinsic::nvvm_isspacep_shared_cluster: |
| 453 | + case Intrinsic::nvvm_isspacep_const: { |
| 454 | + auto *Ty = II.getType(); |
| 455 | + unsigned AS = Op0->getType()->getPointerAddressSpace(); |
| 456 | + // Peek through ASC to generic AS. |
| 457 | + // TODO: we could dig deeper through both ASCs and GEPs. |
| 458 | + if (AS == NVPTXAS::ADDRESS_SPACE_GENERIC) |
| 459 | + if (auto *ASCO = dyn_cast<AddrSpaceCastOperator>(Op0)) |
| 460 | + AS = ASCO->getOperand(0)->getType()->getPointerAddressSpace(); |
| 461 | + |
| 462 | + if (std::optional<bool> Answer = CheckASMatch(IID, AS)) |
| 463 | + return IC.replaceInstUsesWith(II, ConstantInt::get(Ty, *Answer)); |
| 464 | + return nullptr; // Don't know the answer, got to check at run time. |
| 465 | + } |
| 466 | + default: |
| 467 | + return std::nullopt; |
| 468 | + } |
| 469 | +} |
| 470 | + |
416 | 471 | std::optional<Instruction *>
|
417 | 472 | NVPTXTTIImpl::instCombineIntrinsic(InstCombiner &IC, IntrinsicInst &II) const {
|
418 |
| - if (Instruction *I = simplifyNvvmIntrinsic(&II, IC)) { |
| 473 | + if (std::optional<Instruction *> I = handleSpaceCheckIntrinsics(IC, II)) |
| 474 | + return *I; |
| 475 | + if (Instruction *I = convertNvvmIntrinsicToLlvm(IC, &II)) |
419 | 476 | return I;
|
420 |
| - } |
| 477 | + |
421 | 478 | return std::nullopt;
|
422 | 479 | }
|
423 | 480 |
|
|
0 commit comments