1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
|
//===--------------------- NVPTXAliasAnalysis.cpp--------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
/// \file
/// This is the NVPTX address space based alias analysis pass.
//===----------------------------------------------------------------------===//
#include "NVPTXAliasAnalysis.h"
#include "MCTargetDesc/NVPTXBaseInfo.h"
#include "NVPTX.h"
#include "llvm/Analysis/ValueTracking.h"
#include "llvm/IR/InlineAsm.h"
#include "llvm/IR/Instructions.h"
#include "llvm/Support/CommandLine.h"
using namespace llvm;
#define DEBUG_TYPE "NVPTX-aa"
static cl::opt<unsigned> TraverseAddressSpacesLimit(
"nvptx-traverse-address-aliasing-limit", cl::Hidden,
cl::desc("Depth limit for finding address space through traversal"),
cl::init(6));
AnalysisKey NVPTXAA::Key;
char NVPTXAAWrapperPass::ID = 0;
char NVPTXExternalAAWrapper::ID = 0;
INITIALIZE_PASS(NVPTXAAWrapperPass, "nvptx-aa",
"NVPTX Address space based Alias Analysis", false, true)
INITIALIZE_PASS(NVPTXExternalAAWrapper, "nvptx-aa-wrapper",
"NVPTX Address space based Alias Analysis Wrapper", false, true)
ImmutablePass *llvm::createNVPTXAAWrapperPass() {
return new NVPTXAAWrapperPass();
}
ImmutablePass *llvm::createNVPTXExternalAAWrapperPass() {
return new NVPTXExternalAAWrapper();
}
NVPTXAAWrapperPass::NVPTXAAWrapperPass() : ImmutablePass(ID) {}
void NVPTXAAWrapperPass::getAnalysisUsage(AnalysisUsage &AU) const {
AU.setPreservesAll();
}
static unsigned getAddressSpace(const Value *V, unsigned MaxLookup) {
// Find the first non-generic address space traversing the UD chain.
// It is undefined behaviour if a pointer belongs to more than one
// non-overlapping address spaces along a valid execution path.
auto GetAS = [](const Value *V) -> unsigned {
if (const auto *PTy = dyn_cast<PointerType>(V->getType()))
return PTy->getAddressSpace();
return ADDRESS_SPACE_GENERIC;
};
while (MaxLookup-- && GetAS(V) == ADDRESS_SPACE_GENERIC) {
const Value *NewV = getUnderlyingObject(V, 1);
if (NewV == V)
break;
V = NewV;
}
return GetAS(V);
}
static AliasResult::Kind getAliasResult(unsigned AS1, unsigned AS2) {
if ((AS1 == ADDRESS_SPACE_GENERIC) || (AS2 == ADDRESS_SPACE_GENERIC))
return AliasResult::MayAlias;
// PTX s6.4.1.1. Generic Addressing:
// A generic address maps to global memory unless it falls within
// the window for const, local, or shared memory. The Kernel
// Function Parameters (.param) window is contained within the
// .global window.
//
// Therefore a global pointer may alias with a param pointer on some
// GPUs via addrspacecast(param->generic->global) when cvta.param
// instruction is used (PTX 7.7+ and SM_70+).
//
// TODO: cvta.param is not yet supported. We need to change aliasing
// rules once it is added.
// Distributed shared memory aliases with shared memory.
if (((AS1 == ADDRESS_SPACE_SHARED) &&
(AS2 == ADDRESS_SPACE_SHARED_CLUSTER)) ||
((AS1 == ADDRESS_SPACE_SHARED_CLUSTER) && (AS2 == ADDRESS_SPACE_SHARED)))
return AliasResult::MayAlias;
return (AS1 == AS2 ? AliasResult::MayAlias : AliasResult::NoAlias);
}
AliasResult NVPTXAAResult::alias(const MemoryLocation &Loc1,
const MemoryLocation &Loc2, AAQueryInfo &AAQI,
const Instruction *) {
unsigned AS1 = getAddressSpace(Loc1.Ptr, TraverseAddressSpacesLimit);
unsigned AS2 = getAddressSpace(Loc2.Ptr, TraverseAddressSpacesLimit);
return getAliasResult(AS1, AS2);
}
// TODO: .param address space may be writable in presence of cvta.param, but
// this instruction is currently not supported. NVPTXLowerArgs also does not
// allow any writes to .param pointers.
static bool isConstOrParam(unsigned AS) {
return AS == AddressSpace::ADDRESS_SPACE_CONST ||
AS == AddressSpace::ADDRESS_SPACE_PARAM;
}
ModRefInfo NVPTXAAResult::getModRefInfoMask(const MemoryLocation &Loc,
AAQueryInfo &AAQI,
bool IgnoreLocals) {
if (isConstOrParam(getAddressSpace(Loc.Ptr, TraverseAddressSpacesLimit)))
return ModRefInfo::NoModRef;
return ModRefInfo::ModRef;
}
MemoryEffects NVPTXAAResult::getMemoryEffects(const CallBase *Call,
AAQueryInfo &AAQI) {
// Inline assembly with no side-effect or memory clobbers should not
// indirectly access memory in the PTX specification.
if (const auto *IA = dyn_cast<InlineAsm>(Call->getCalledOperand())) {
// Volatile is translated as side-effects.
if (IA->hasSideEffects())
return MemoryEffects::unknown();
for (const InlineAsm::ConstraintInfo &Constraint : IA->ParseConstraints()) {
// Indirect constraints (e.g. =*m) are unsupported in inline PTX.
if (Constraint.isIndirect)
return MemoryEffects::unknown();
// Memory clobbers prevent optimization.
if ((Constraint.Type & InlineAsm::ConstraintPrefix::isClobber) &&
any_of(Constraint.Codes,
[](const auto &Code) { return Code == "{memory}"; }))
return MemoryEffects::unknown();
}
return MemoryEffects::none();
}
return MemoryEffects::unknown();
}
|