28#include "llvm/IR/IntrinsicsAMDGPU.h"
34#define DEBUG_TYPE "amdgpu-lower-kernel-arguments"
78 if (Arg.hasNoAliasAttr() && !Arg.use_empty())
81 if (NoAliasArgs.
empty())
89 for (
unsigned I = 0u;
I < NoAliasArgs.
size(); ++
I) {
92 NewScopes.
insert({Arg, NewScope});
97 Inst != InstEnd; ++Inst) {
102 bool IsUnrestrictedCall =
false;
117 if (!Arg->getType()->isPointerTy())
132 for (
const Value *Val : PtrArgs) {
138 bool RequiresNoCaptureBefore =
false;
139 bool UsesUnknownObject =
false;
140 bool UsesAliasingPtr =
false;
142 for (
const Value *Val : ObjSet) {
147 if (!Arg->hasAttribute(Attribute::NoAlias))
148 UsesAliasingPtr =
true;
150 UsesAliasingPtr =
true;
154 RequiresNoCaptureBefore =
true;
157 UsesUnknownObject =
true;
161 if (UsesUnknownObject)
164 if (IsUnrestrictedCall)
165 RequiresNoCaptureBefore =
true;
168 for (
const Argument *Arg : NoAliasArgs) {
172 if (!RequiresNoCaptureBefore ||
180 if (!UsesAliasingPtr && !IsUnrestrictedCall)
181 for (
const Argument *Arg : NoAliasArgs) {
182 if (ObjSet.
count(Arg))
183 Scopes.push_back(NewScopes[Arg]);
191 Inst->setMetadata(LLVMContext::MD_noalias, NewMD);
195 if (!Scopes.empty()) {
199 Inst->setMetadata(LLVMContext::MD_alias_scope, NewMD);
216 const Align KernArgBaseAlign(16);
217 const uint64_t BaseOffset = ST.getExplicitKernelArgOffset();
221 const uint64_t TotalKernArgSize = ST.getKernArgSegmentSize(
F, MaxAlign);
222 if (TotalKernArgSize == 0)
225 CallInst *KernArgSegment = Builder.CreateIntrinsicWithoutFolding(
226 Intrinsic::amdgcn_kernarg_segment_ptr, {},
nullptr,
227 F.getName() +
".kernarg.segment");
228 KernArgSegment->
addRetAttr(Attribute::NonNull);
237 const bool IsByRef = Arg.hasByRefAttr();
238 Type *ArgTy = IsByRef ? Arg.getParamByRefType() : Arg.getType();
239 MaybeAlign ParamAlign = IsByRef ? Arg.getParamAlign() : std::nullopt;
240 Align ABITypeAlign =
DL.getValueOrABITypeAlignment(ParamAlign, ArgTy);
243 uint64_t AllocSize =
DL.getTypeAllocSize(ArgTy);
245 uint64_t EltOffset =
alignTo(ExplicitArgOffset, ABITypeAlign) + BaseOffset;
246 ExplicitArgOffset =
alignTo(ExplicitArgOffset, ABITypeAlign) + AllocSize;
249 if (Arg.use_empty() || Arg.hasInRegAttr())
255 Value *ArgOffsetPtr = Builder.CreateConstInBoundsGEP1_64(
256 Builder.getInt8Ty(), KernArgSegment, EltOffset,
257 Arg.getName() +
".byval.kernarg.offset");
259 Value *CastOffsetPtr =
260 Builder.CreateAddrSpaceCast(ArgOffsetPtr, Arg.
getType());
272 !ST.hasUsableDSOffset())
277 bool IsV3 = VT && VT->getNumElements() == 3;
282 int64_t AlignDownOffset =
alignDown(EltOffset, 4);
283 int64_t OffsetDiff = EltOffset - AlignDownOffset;
285 KernArgBaseAlign, DoShiftOpt ? AlignDownOffset : EltOffset);
297 ArgPtr = Builder.CreateConstInBoundsGEP1_64(
298 Builder.getInt8Ty(), KernArgSegment, AlignDownOffset,
299 Arg.getName() +
".kernarg.offset.align.down");
302 ArgPtr = Builder.CreateConstInBoundsGEP1_64(
303 Builder.getInt8Ty(), KernArgSegment, EltOffset,
304 Arg.getName() +
".kernarg.offset");
305 AdjustedArgTy = ArgTy;
308 if (IsV3 &&
Size >= 32) {
311 AdjustedArgTy = V4Ty;
315 Builder.CreateAlignedLoad(AdjustedArgTy, ArgPtr, AdjustedAlign);
316 Load->setMetadata(LLVMContext::MD_invariant_load,
MDNode::get(Ctx, {}));
320 if (Arg.hasAttribute(Attribute::NoUndef) && AdjustedArgTy == ArgTy)
323 if (Arg.hasAttribute(Attribute::Range) && AdjustedArgTy == ArgTy) {
325 Arg.getAttribute(Attribute::Range).getValueAsConstantRange();
326 Load->setMetadata(LLVMContext::MD_range,
330 if (Arg.hasAttribute(Attribute::NoFPClass) && AdjustedArgTy == ArgTy) {
333 LLVMContext::MD_nofpclass,
339 if (Arg.hasNonNullAttr())
342 uint64_t DerefBytes = Arg.getDereferenceableBytes();
343 if (DerefBytes != 0) {
345 LLVMContext::MD_dereferenceable,
348 ConstantInt::get(Builder.getInt64Ty(), DerefBytes))));
351 uint64_t DerefOrNullBytes = Arg.getDereferenceableOrNullBytes();
352 if (DerefOrNullBytes != 0) {
354 LLVMContext::MD_dereferenceable_or_null,
357 DerefOrNullBytes))));
360 if (
MaybeAlign ParamAlign = Arg.getParamAlign()) {
362 LLVMContext::MD_align,
364 Builder.getInt64Ty(), ParamAlign->value()))));
369 Value *ExtractBits = OffsetDiff == 0 ?
370 Load : Builder.CreateLShr(
Load, OffsetDiff * 8);
373 Value *Trunc = Builder.CreateTrunc(ExtractBits, ArgIntTy);
374 Value *NewVal = Builder.CreateBitCast(Trunc, ArgTy,
375 Arg.getName() +
".load");
379 Arg.getName() +
".load");
382 Load->setName(Arg.getName() +
".load");
383 Arg.replaceAllUsesWith(
Load);
393bool AMDGPULowerKernelArguments::runOnFunction(
Function &
F) {
394 auto &TPC = getAnalysis<TargetPassConfig>();
395 const TargetMachine &TM = TPC.getTM<TargetMachine>();
396 DominatorTree &DT = getAnalysis<DominatorTreeWrapperPass>().getDomTree();
401 "AMDGPU Lower Kernel Arguments",
false,
false)
405char AMDGPULowerKernelArguments::ID = 0;
408 return new AMDGPULowerKernelArguments();
static void addAliasScopeMetadata(Function &F, const DataLayout &DL, DominatorTree &DT)
static BasicBlock::iterator getInsertPt(BasicBlock &BB)
static bool lowerKernelArguments(Function &F, const TargetMachine &TM, DominatorTree &DT)
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
This file contains the simple types necessary to represent the attributes associated with functions a...
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
static cl::opt< bool > NoAliases("csky-no-aliases", cl::desc("Disable the emission of assembler pseudo instructions"), cl::init(false), cl::Hidden)
static bool runOnFunction(Function &F, bool PostInlining)
AMD GCN specific subclass of TargetSubtarget.
ConstantRange Range(APInt(BitWidth, Low), APInt(BitWidth, High))
#define INITIALIZE_PASS_END(passName, arg, name, cfg, analysis)
#define INITIALIZE_PASS_BEGIN(passName, arg, name, cfg, analysis)
This is the interface for a metadata-based scoped no-alias analysis.
Target-Independent Code Generator Pass Configuration Options pass.
PreservedAnalyses run(Function &, FunctionAnalysisManager &)
an instruction to allocate memory on the stack
LLVM_ABI bool isStaticAlloca() const
Return true if this alloca is in the entry block of the function and is a constant size.
PassT::Result & getResult(IRUnitT &IR, ExtraArgTs... ExtraArgs)
Get the result of an analysis pass for a given IR unit.
Represent the analysis usage information of a pass.
AnalysisUsage & addRequired()
void setPreservesAll()
Set by analyses that do not transform their input at all.
This class represents an incoming formal argument to a Function.
Represent a constant reference to an array (0 or more elements consecutively in memory),...
static LLVM_ABI Attribute getWithDereferenceableBytes(LLVMContext &Context, uint64_t Bytes)
static LLVM_ABI Attribute getWithAlignment(LLVMContext &Context, Align Alignment)
Return a uniquified Attribute object that has the specific alignment set.
LLVM Basic Block Representation.
LLVM_ABI const_iterator getFirstInsertionPt() const
Returns an iterator to the first instruction in this block that is suitable for inserting a non-PHI i...
InstListType::iterator iterator
Instruction iterators...
Represents analyses that only rely on functions' control flow.
Base class for all callable instructions (InvokeInst and CallInst) Holds everything related to callin...
void addRetAttr(Attribute::AttrKind Kind)
Adds the attribute to the return value.
This class represents a function call, abstracting a target machine's calling convention.
This class represents a range of values.
A parsed version of the target data layout string in and methods for querying it.
std::pair< iterator, bool > insert(const std::pair< KeyT, ValueT > &KV)
Analysis pass which computes a DominatorTree.
Legacy analysis pass which computes a DominatorTree.
Concrete subclass of DominatorTreeBase that is used to compute a normal dominator tree.
static LLVM_ABI FixedVectorType * get(Type *ElementType, unsigned NumElts)
FunctionPass class - This class is used to implement most global optimizations.
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
Class to represent integer types.
This is an important class for using LLVM in a threaded context.
An instruction for reading from memory.
MDNode * createAnonymousAliasScope(MDNode *Domain, StringRef Name=StringRef())
Return metadata appropriate for an alias scope root node.
LLVM_ABI ConstantAsMetadata * createConstant(Constant *C)
Return the given constant as metadata.
LLVM_ABI MDNode * createRange(const APInt &Lo, const APInt &Hi)
Return metadata describing the range [Lo, Hi).
MDNode * createAnonymousAliasScopeDomain(StringRef Name=StringRef())
Return metadata appropriate for an alias scope domain node.
static LLVM_ABI MDNode * concatenate(MDNode *A, MDNode *B)
Methods for metadata merging.
static MDTuple * get(LLVMContext &Context, ArrayRef< Metadata * > MDs)
bool doesNotAccessMemory() const
Whether this function accesses no memory.
bool onlyAccessesInaccessibleMem() const
Whether this function only (at most) accesses inaccessible memory.
bool onlyAccessesArgPointees() const
Whether this function only (at most) accesses argument memory.
static LLVM_ABI std::optional< MemoryLocation > getOrNone(const Instruction *Inst)
A set of analyses that are preserved following a run of a transformation pass.
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
PreservedAnalyses & preserveSet()
Mark an analysis set as preserved.
size_type count(ConstPtrType Ptr) const
count - Return 1 if the specified pointer is in the set, 0 otherwise.
void insert_range(Range &&R)
bool contains(ConstPtrType Ptr) const
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Primary interface to the complete machine description for the target machine.
const STC & getSubtarget(const Function &F) const
This method returns a pointer to the specified type of TargetSubtargetInfo.
Target-Independent Code Generator Pass Configuration Options.
The instances of the Type class are immutable: once they are created, they are never changed.
static LLVM_ABI IntegerType * getInt32Ty(LLVMContext &C)
bool isAggregateType() const
Return true if the type is an aggregate type.
static LLVM_ABI IntegerType * getIntNTy(LLVMContext &C, unsigned N)
LLVM Value Representation.
Type * getType() const
All values are typed, get the type of this value.
LLVM_ABI void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
LLVM_ABI StringRef getName() const
Return a constant reference to the value's name.
@ REGION_ADDRESS
Address space for region memory. (GDS)
@ LOCAL_ADDRESS
Address space for local memory.
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
@ AMDGPU_KERNEL
Used for AMDGPU code object kernels.
This is an optimization pass for GlobalISel generic memory operations.
InstIterator< SymbolTableList< BasicBlock >, Function::iterator, BasicBlock::iterator, Instruction > inst_iterator
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
@ Load
The value being inserted comes from a load (InsertElement only).
constexpr T alignDown(U Value, V Align, W Skew=0)
Returns the largest unsigned integer less than or equal to Value and is Skew mod Align.
MemoryEffectsBase< IRMemLocation > MemoryEffects
Summary of how a function affects memory in the program.
inst_iterator inst_begin(Function *F)
LLVM_ABI bool PointerMayBeCapturedBefore(const Value *V, bool ReturnCaptures, const Instruction *I, const DominatorTree *DT, bool IncludeI=false, unsigned MaxUsesToExplore=0, const LoopInfo *LI=nullptr)
PointerMayBeCapturedBefore - Return true if this pointer value may be captured by the enclosing funct...
FPClassTest
Floating-point class tests, supported by 'is_fpclass' intrinsic.
FunctionPass * createAMDGPULowerKernelArgumentsPass()
constexpr uint64_t alignTo(uint64_t Size, Align A)
Returns a multiple of A needed to store Size bytes.
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
inst_iterator inst_end(Function *F)
LLVM_ABI bool isEscapeSource(const Value *V)
Returns true if the pointer is one which would have been considered an escape by isNotCapturedBefore.
Align commonAlignment(Align A, uint64_t Offset)
Returns the alignment that satisfies both alignments.
bool capturesAnything(CaptureComponents CC)
AnalysisManager< Function > FunctionAnalysisManager
Convenience typedef for the Function analysis manager.
LLVM_ABI void getUnderlyingObjects(const Value *V, SmallVectorImpl< const Value * > &Objects, const LoopInfo *LI=nullptr, unsigned MaxLookup=MaxLookupSearchDepth)
This method is similar to getUnderlyingObject except that it can look through phi and select instruct...
LLVM_ABI bool isIdentifiedObject(const Value *V)
Return true if this pointer refers to a distinct and identifiable object.
This struct is a compact representation of a valid (non-zero power of two) alignment.
This struct is a compact representation of a valid (power of two) or undefined (0) alignment.