Skip to content

Commit

Permalink
[InferAddressSpaces] Support assumed addrspaces from addrspace predic…
Browse files Browse the repository at this point in the history
…ates.

- CUDA cannot associate memory space with pointer types. Even though Clang could add extra attributes to specify the address space explicitly on a pointer type, it breaks the portability between Clang and NVCC.
- This change proposes to assume the address space from a pointer from the assumption built upon target-specific address space predicates, such as `__isGlobal` from CUDA. E.g.,

```
  foo(float *p) {
    __builtin_assume(__isGlobal(p));
    // From there, we could assume p is a global pointer instead of a
    // generic one.
  }
```

This makes the code portable without introducing the implementation-specific features.

Note that NVCC starts to support __builtin_assume from version 11.

Reviewed By: arsenm

Differential Revision: https://reviews.llvm.org/D112041
  • Loading branch information
darkbuck committed Nov 8, 2021
1 parent f3798ad commit bf22593
Show file tree
Hide file tree
Showing 21 changed files with 478 additions and 69 deletions.
2 changes: 1 addition & 1 deletion clang/test/CodeGen/thinlto-distributed-newpm.ll
Expand Up @@ -47,11 +47,11 @@
; CHECK-O: Running pass: PromotePass
; CHECK-O: Running analysis: DominatorTreeAnalysis on main
; CHECK-O: Running analysis: AssumptionAnalysis on main
; CHECK-O: Running analysis: TargetIRAnalysis on main
; CHECK-O: Running pass: DeadArgumentEliminationPass
; CHECK-O: Running pass: InstCombinePass on main
; CHECK-O: Running analysis: TargetLibraryAnalysis on main
; CHECK-O: Running analysis: OptimizationRemarkEmitterAnalysis on main
; CHECK-O: Running analysis: TargetIRAnalysis on main
; CHECK-O: Running analysis: AAManager on main
; CHECK-O: Running analysis: BasicAA on main
; CHECK-O: Running analysis: ScopedNoAliasAA on main
Expand Down
10 changes: 6 additions & 4 deletions llvm/include/llvm/Analysis/AssumptionCache.h
Expand Up @@ -29,6 +29,7 @@ namespace llvm {
class AssumeInst;
class Function;
class raw_ostream;
class TargetTransformInfo;
class Value;

/// A cache of \@llvm.assume calls within a function.
Expand Down Expand Up @@ -59,6 +60,8 @@ class AssumptionCache {
/// We track this to lazily populate our assumptions.
Function &F;

TargetTransformInfo *TTI;

/// Vector of weak value handles to calls of the \@llvm.assume
/// intrinsic.
SmallVector<ResultElem, 4> AssumeHandles;
Expand Down Expand Up @@ -103,7 +106,8 @@ class AssumptionCache {
public:
/// Construct an AssumptionCache from a function by scanning all of
/// its instructions.
AssumptionCache(Function &F) : F(F) {}
AssumptionCache(Function &F, TargetTransformInfo *TTI = nullptr)
: F(F), TTI(TTI) {}

/// This cache is designed to be self-updating and so it should never be
/// invalidated.
Expand Down Expand Up @@ -174,9 +178,7 @@ class AssumptionAnalysis : public AnalysisInfoMixin<AssumptionAnalysis> {
public:
using Result = AssumptionCache;

AssumptionCache run(Function &F, FunctionAnalysisManager &) {
return AssumptionCache(F);
}
AssumptionCache run(Function &F, FunctionAnalysisManager &);
};

/// Printer pass for the \c AssumptionAnalysis results.
Expand Down
11 changes: 11 additions & 0 deletions llvm/include/llvm/Analysis/TargetTransformInfo.h
Expand Up @@ -30,6 +30,7 @@
#include "llvm/Support/DataTypes.h"
#include "llvm/Support/InstructionCost.h"
#include <functional>
#include <utility>

namespace llvm {

Expand Down Expand Up @@ -389,6 +390,9 @@ class TargetTransformInfo {

unsigned getAssumedAddrSpace(const Value *V) const;

std::pair<const Value *, unsigned>
getPredicatedAddrSpace(const Value *V) const;

/// Rewrite intrinsic call \p II such that \p OldV will be replaced with \p
/// NewV, which has a different address space. This should happen for every
/// operand index that collectFlatAddressOperands returned for the intrinsic.
Expand Down Expand Up @@ -1481,6 +1485,8 @@ class TargetTransformInfo::Concept {
virtual bool
canHaveNonUndefGlobalInitializerInAddressSpace(unsigned AS) const = 0;
virtual unsigned getAssumedAddrSpace(const Value *V) const = 0;
virtual std::pair<const Value *, unsigned>
getPredicatedAddrSpace(const Value *V) const = 0;
virtual Value *rewriteIntrinsicWithAddressSpace(IntrinsicInst *II,
Value *OldV,
Value *NewV) const = 0;
Expand Down Expand Up @@ -1824,6 +1830,11 @@ class TargetTransformInfo::Model final : public TargetTransformInfo::Concept {
return Impl.getAssumedAddrSpace(V);
}

std::pair<const Value *, unsigned>
getPredicatedAddrSpace(const Value *V) const override {
return Impl.getPredicatedAddrSpace(V);
}

Value *rewriteIntrinsicWithAddressSpace(IntrinsicInst *II, Value *OldV,
Value *NewV) const override {
return Impl.rewriteIntrinsicWithAddressSpace(II, OldV, NewV);
Expand Down
6 changes: 6 additions & 0 deletions llvm/include/llvm/Analysis/TargetTransformInfoImpl.h
Expand Up @@ -24,6 +24,7 @@
#include "llvm/IR/Operator.h"
#include "llvm/IR/PatternMatch.h"
#include "llvm/IR/Type.h"
#include <utility>

using namespace llvm::PatternMatch;

Expand Down Expand Up @@ -110,6 +111,11 @@ class TargetTransformInfoImplBase {

unsigned getAssumedAddrSpace(const Value *V) const { return -1; }

std::pair<const Value *, unsigned>
getPredicatedAddrSpace(const Value *V) const {
return std::make_pair(nullptr, -1);
}

Value *rewriteIntrinsicWithAddressSpace(IntrinsicInst *II, Value *OldV,
Value *NewV) const {
return nullptr;
Expand Down
5 changes: 5 additions & 0 deletions llvm/include/llvm/CodeGen/BasicTTIImpl.h
Expand Up @@ -283,6 +283,11 @@ class BasicTTIImplBase : public TargetTransformInfoImplCRTPBase<T> {
return getTLI()->getTargetMachine().getAssumedAddrSpace(V);
}

std::pair<const Value *, unsigned>
getPredicatedAddrSpace(const Value *V) const {
return getTLI()->getTargetMachine().getPredicatedAddrSpace(V);
}

Value *rewriteIntrinsicWithAddressSpace(IntrinsicInst *II, Value *OldV,
Value *NewV) const {
return nullptr;
Expand Down
13 changes: 13 additions & 0 deletions llvm/include/llvm/Target/TargetMachine.h
Expand Up @@ -25,6 +25,7 @@
#include "llvm/Target/CGPassBuilderOption.h"
#include "llvm/Target/TargetOptions.h"
#include <string>
#include <utility>

namespace llvm {

Expand Down Expand Up @@ -319,6 +320,18 @@ class TargetMachine {
/// properties.
virtual unsigned getAssumedAddrSpace(const Value *V) const { return -1; }

/// If the specified predicate checks whether a generic pointer falls within
/// a specified address space, return that generic pointer and the address
/// space being queried.
///
/// Such predicates could be specified in @llvm.assume intrinsics for the
/// optimizer to assume that the given generic pointer always falls within
/// the address space based on that predicate.
virtual std::pair<const Value *, unsigned>
getPredicatedAddrSpace(const Value *V) const {
return std::make_pair(nullptr, -1);
}

/// Get a \c TargetIRAnalysis appropriate for the target.
///
/// This is used to construct the new pass manager's target IR analysis pass,
Expand Down
26 changes: 22 additions & 4 deletions llvm/lib/Analysis/AssumptionCache.cpp
Expand Up @@ -16,6 +16,7 @@
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Analysis/TargetTransformInfo.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/InstrTypes.h"
Expand Down Expand Up @@ -56,7 +57,7 @@ AssumptionCache::getOrInsertAffectedValues(Value *V) {
}

static void
findAffectedValues(CallBase *CI,
findAffectedValues(CallBase *CI, TargetTransformInfo *TTI,
SmallVectorImpl<AssumptionCache::ResultElem> &Affected) {
// Note: This code must be kept in-sync with the code in
// computeKnownBitsFromAssume in ValueTracking.
Expand Down Expand Up @@ -124,11 +125,19 @@ findAffectedValues(CallBase *CI,
match(B, m_ConstantInt()))
AddAffected(X);
}

if (TTI) {
const Value *Ptr;
unsigned AS;
std::tie(Ptr, AS) = TTI->getPredicatedAddrSpace(Cond);
if (Ptr)
AddAffected(const_cast<Value *>(Ptr->stripInBoundsOffsets()));
}
}

void AssumptionCache::updateAffectedValues(AssumeInst *CI) {
SmallVector<AssumptionCache::ResultElem, 16> Affected;
findAffectedValues(CI, Affected);
findAffectedValues(CI, TTI, Affected);

for (auto &AV : Affected) {
auto &AVV = getOrInsertAffectedValues(AV.Assume);
Expand All @@ -141,7 +150,7 @@ void AssumptionCache::updateAffectedValues(AssumeInst *CI) {

void AssumptionCache::unregisterAssumption(AssumeInst *CI) {
SmallVector<AssumptionCache::ResultElem, 16> Affected;
findAffectedValues(CI, Affected);
findAffectedValues(CI, TTI, Affected);

for (auto &AV : Affected) {
auto AVI = AffectedValues.find_as(AV.Assume);
Expand Down Expand Up @@ -248,6 +257,12 @@ void AssumptionCache::registerAssumption(AssumeInst *CI) {
updateAffectedValues(CI);
}

AssumptionCache AssumptionAnalysis::run(Function &F,
FunctionAnalysisManager &FAM) {
auto &TTI = FAM.getResult<TargetIRAnalysis>(F);
return AssumptionCache(F, &TTI);
}

AnalysisKey AssumptionAnalysis::Key;

PreservedAnalyses AssumptionPrinterPass::run(Function &F,
Expand Down Expand Up @@ -278,10 +293,13 @@ AssumptionCache &AssumptionCacheTracker::getAssumptionCache(Function &F) {
if (I != AssumptionCaches.end())
return *I->second;

auto *TTIWP = getAnalysisIfAvailable<TargetTransformInfoWrapperPass>();
auto *TTI = TTIWP ? &TTIWP->getTTI(F) : nullptr;

// Ok, build a new cache by scanning the function, insert it and the value
// handle into our map, and return the newly populated cache.
auto IP = AssumptionCaches.insert(std::make_pair(
FunctionCallbackVH(&F, this), std::make_unique<AssumptionCache>(F)));
FunctionCallbackVH(&F, this), std::make_unique<AssumptionCache>(F, TTI)));
assert(IP.second && "Scanning function already in the map?");
return *IP.first->second;
}
Expand Down
5 changes: 5 additions & 0 deletions llvm/lib/Analysis/TargetTransformInfo.cpp
Expand Up @@ -268,6 +268,11 @@ unsigned TargetTransformInfo::getAssumedAddrSpace(const Value *V) const {
return TTIImpl->getAssumedAddrSpace(V);
}

std::pair<const Value *, unsigned>
TargetTransformInfo::getPredicatedAddrSpace(const Value *V) const {
return TTIImpl->getPredicatedAddrSpace(V);
}

Value *TargetTransformInfo::rewriteIntrinsicWithAddressSpace(
IntrinsicInst *II, Value *OldV, Value *NewV) const {
return TTIImpl->rewriteIntrinsicWithAddressSpace(II, OldV, NewV);
Expand Down
29 changes: 29 additions & 0 deletions llvm/lib/Target/AMDGPU/AMDGPUTargetMachine.cpp
Expand Up @@ -36,8 +36,10 @@
#include "llvm/CodeGen/Passes.h"
#include "llvm/CodeGen/RegAllocRegistry.h"
#include "llvm/CodeGen/TargetPassConfig.h"
#include "llvm/IR/IntrinsicsAMDGPU.h"
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/IR/PassManager.h"
#include "llvm/IR/PatternMatch.h"
#include "llvm/InitializePasses.h"
#include "llvm/MC/TargetRegistry.h"
#include "llvm/Passes/PassBuilder.h"
Expand Down Expand Up @@ -780,6 +782,33 @@ unsigned AMDGPUTargetMachine::getAssumedAddrSpace(const Value *V) const {
return AMDGPUAS::GLOBAL_ADDRESS;
}

std::pair<const Value *, unsigned>
AMDGPUTargetMachine::getPredicatedAddrSpace(const Value *V) const {
if (auto *II = dyn_cast<IntrinsicInst>(V)) {
switch (II->getIntrinsicID()) {
case Intrinsic::amdgcn_is_shared:
return std::make_pair(II->getArgOperand(0), AMDGPUAS::LOCAL_ADDRESS);
case Intrinsic::amdgcn_is_private:
return std::make_pair(II->getArgOperand(0), AMDGPUAS::PRIVATE_ADDRESS);
default:
break;
}
return std::make_pair(nullptr, -1);
}
// Check the global pointer predication based on
// (!is_share(p) && !is_private(p)). Note that logic 'and' is commutative and
// the order of 'is_shared' and 'is_private' is not significant.
Value *Ptr;
if (match(
const_cast<Value *>(V),
m_c_And(m_Not(m_Intrinsic<Intrinsic::amdgcn_is_shared>(m_Value(Ptr))),
m_Not(m_Intrinsic<Intrinsic::amdgcn_is_private>(
m_Deferred(Ptr))))))
return std::make_pair(Ptr, AMDGPUAS::GLOBAL_ADDRESS);

return std::make_pair(nullptr, -1);
}

//===----------------------------------------------------------------------===//
// GCN Target Machine (SI+)
//===----------------------------------------------------------------------===//
Expand Down
4 changes: 4 additions & 0 deletions llvm/lib/Target/AMDGPU/AMDGPUTargetMachine.h
Expand Up @@ -17,6 +17,7 @@
#include "GCNSubtarget.h"
#include "llvm/CodeGen/TargetPassConfig.h"
#include "llvm/Target/TargetMachine.h"
#include <utility>

namespace llvm {

Expand Down Expand Up @@ -63,6 +64,9 @@ class AMDGPUTargetMachine : public LLVMTargetMachine {
bool isNoopAddrSpaceCast(unsigned SrcAS, unsigned DestAS) const override;

unsigned getAssumedAddrSpace(const Value *V) const override;

std::pair<const Value *, unsigned>
getPredicatedAddrSpace(const Value *V) const override;
};

//===----------------------------------------------------------------------===//
Expand Down
20 changes: 20 additions & 0 deletions llvm/lib/Target/NVPTX/NVPTXTargetMachine.cpp
Expand Up @@ -23,6 +23,7 @@
#include "llvm/Analysis/TargetTransformInfo.h"
#include "llvm/CodeGen/Passes.h"
#include "llvm/CodeGen/TargetPassConfig.h"
#include "llvm/IR/IntrinsicsNVPTX.h"
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/MC/TargetRegistry.h"
#include "llvm/Pass.h"
Expand Down Expand Up @@ -240,6 +241,25 @@ NVPTXTargetMachine::getTargetTransformInfo(const Function &F) {
return TargetTransformInfo(NVPTXTTIImpl(this, F));
}

std::pair<const Value *, unsigned>
NVPTXTargetMachine::getPredicatedAddrSpace(const Value *V) const {
if (auto *II = dyn_cast<IntrinsicInst>(V)) {
switch (II->getIntrinsicID()) {
case Intrinsic::nvvm_isspacep_const:
return std::make_pair(II->getArgOperand(0), llvm::ADDRESS_SPACE_CONST);
case Intrinsic::nvvm_isspacep_global:
return std::make_pair(II->getArgOperand(0), llvm::ADDRESS_SPACE_GLOBAL);
case Intrinsic::nvvm_isspacep_local:
return std::make_pair(II->getArgOperand(0), llvm::ADDRESS_SPACE_LOCAL);
case Intrinsic::nvvm_isspacep_shared:
return std::make_pair(II->getArgOperand(0), llvm::ADDRESS_SPACE_SHARED);
default:
break;
}
}
return std::make_pair(nullptr, -1);
}

void NVPTXPassConfig::addEarlyCSEOrGVNPass() {
if (getOptLevel() == CodeGenOpt::Aggressive)
addPass(createGVNPass());
Expand Down
4 changes: 4 additions & 0 deletions llvm/lib/Target/NVPTX/NVPTXTargetMachine.h
Expand Up @@ -16,6 +16,7 @@
#include "ManagedStringPool.h"
#include "NVPTXSubtarget.h"
#include "llvm/Target/TargetMachine.h"
#include <utility>

namespace llvm {

Expand Down Expand Up @@ -69,6 +70,9 @@ class NVPTXTargetMachine : public LLVMTargetMachine {
bool isMachineVerifierClean() const override {
return false;
}

std::pair<const Value *, unsigned>
getPredicatedAddrSpace(const Value *V) const override;
}; // NVPTXTargetMachine.

class NVPTXTargetMachine32 : public NVPTXTargetMachine {
Expand Down

0 comments on commit bf22593

Please sign in to comment.