Skip to content

Commit 2adb69a

Browse files
Artem-Bsmallp-o-p
authored and
smallp-o-p
committed
[NVPTX] instcombine known pointer AS checks. (llvm#112964)
The change improves the code in general and, as a side effect, avoids crashing on an impossible address space casts guarded by `__isGlobal/__isShared`, which partially fixes llvm#112760 It's still possible to trigger the issue by using explicit AS casts w/o AS checks, but LLVM should no longer crash on valid code.
1 parent 270f083 commit 2adb69a

File tree

4 files changed

+372
-13
lines changed

4 files changed

+372
-13
lines changed
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
//===---------------- NVPTXAddrSpace.h -------------------------*- 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+
//
9+
/// \file
10+
/// NVPTX address space definition
11+
///
12+
//
13+
//===----------------------------------------------------------------------===//
14+
15+
#ifndef LLVM_SUPPORT_NVPTXADDRSPACE_H
16+
#define LLVM_SUPPORT_NVPTXADDRSPACE_H
17+
18+
namespace llvm {
19+
namespace NVPTXAS {
20+
enum AddressSpace : unsigned {
21+
ADDRESS_SPACE_GENERIC = 0,
22+
ADDRESS_SPACE_GLOBAL = 1,
23+
ADDRESS_SPACE_SHARED = 3,
24+
ADDRESS_SPACE_CONST = 4,
25+
ADDRESS_SPACE_LOCAL = 5,
26+
27+
ADDRESS_SPACE_PARAM = 101,
28+
};
29+
} // end namespace NVPTXAS
30+
31+
} // end namespace llvm
32+
33+
#endif // LLVM_SUPPORT_NVPTXADDRSPACE_H

llvm/lib/Target/NVPTX/MCTargetDesc/NVPTXBaseInfo.h

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,18 +16,10 @@
1616
#ifndef LLVM_LIB_TARGET_NVPTX_MCTARGETDESC_NVPTXBASEINFO_H
1717
#define LLVM_LIB_TARGET_NVPTX_MCTARGETDESC_NVPTXBASEINFO_H
1818

19+
#include "llvm/Support/NVPTXAddrSpace.h"
1920
namespace llvm {
2021

21-
enum AddressSpace {
22-
ADDRESS_SPACE_GENERIC = 0,
23-
ADDRESS_SPACE_GLOBAL = 1,
24-
ADDRESS_SPACE_SHARED = 3,
25-
ADDRESS_SPACE_CONST = 4,
26-
ADDRESS_SPACE_LOCAL = 5,
27-
28-
// NVVM Internal
29-
ADDRESS_SPACE_PARAM = 101
30-
};
22+
using namespace NVPTXAS;
3123

3224
namespace NVPTXII {
3325
enum {

llvm/lib/Target/NVPTX/NVPTXTargetTransformInfo.cpp

Lines changed: 60 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,12 @@
1515
#include "llvm/CodeGen/CostTable.h"
1616
#include "llvm/CodeGen/TargetLowering.h"
1717
#include "llvm/IR/Constants.h"
18+
#include "llvm/IR/IntrinsicInst.h"
1819
#include "llvm/IR/Intrinsics.h"
1920
#include "llvm/IR/IntrinsicsNVPTX.h"
2021
#include "llvm/IR/Value.h"
2122
#include "llvm/Support/Casting.h"
23+
#include "llvm/Support/ErrorHandling.h"
2224
#include "llvm/Transforms/InstCombine/InstCombiner.h"
2325
#include <optional>
2426
using namespace llvm;
@@ -117,7 +119,8 @@ bool NVPTXTTIImpl::isSourceOfDivergence(const Value *V) {
117119
}
118120

119121
// 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) {
121124
// Each NVVM intrinsic we can simplify can be replaced with one of:
122125
//
123126
// * an LLVM intrinsic,
@@ -413,11 +416,65 @@ static Instruction *simplifyNvvmIntrinsic(IntrinsicInst *II, InstCombiner &IC) {
413416
llvm_unreachable("All SpecialCase enumerators should be handled in switch.");
414417
}
415418

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+
416471
std::optional<Instruction *>
417472
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))
419476
return I;
420-
}
477+
421478
return std::nullopt;
422479
}
423480

0 commit comments

Comments
 (0)