LLVM 23.0.0git
NVPTXSetByValParamAlign.cpp
Go to the documentation of this file.
1//===-- NVPTXSetByValParamAlign.cpp - Set byval param alignment -----------===//
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// Set explicit alignment on byval parameter attributes in the NVPTX backend.
10// Without this, the alignment is left unspecified and IR-level analyses (e.g.,
11// computeKnownBits via Value::getPointerAlignment) conservatively assume
12// Align(1), since the actual alignment is a target-specific codegen detail not
13// visible at the IR level.
14//
15// The alignment is chosen as follows:
16// - Externally-visible functions: ABI type alignment (capped at 128).
17// - Internal/private functions: max(16, ABI align) to enable 128-bit
18// vectorized param loads. The compiler can _increase_ alignment beyond ABI
19// in this case because it has control over all of the call sites and byval
20// parameters are copies allocated by the caller in .param space.
21//
22// After updating the attribute, the pass propagates the improved alignment to
23// all loads from the byval pointer that use a known constant offset.
24//
25// TODO: Consider removing the load propagation in favor of infer-alignment,
26// which should be able to pick up the improved alignment from the attribute.
27//
28//===----------------------------------------------------------------------===//
29
30#include "NVPTX.h"
31#include "NVPTXUtilities.h"
32#include "llvm/IR/Function.h"
35#include "llvm/Pass.h"
36#include "llvm/Support/Debug.h"
37#include <queue>
38
39#define DEBUG_TYPE "nvptx-set-byval-param-align"
40
41using namespace llvm;
42
43namespace {
44class NVPTXSetByValParamAlignLegacyPass : public FunctionPass {
45 bool runOnFunction(Function &F) override;
46
47public:
48 static char ID;
49 NVPTXSetByValParamAlignLegacyPass() : FunctionPass(ID) {}
50 StringRef getPassName() const override {
51 return "Set alignment of byval parameters (NVPTX)";
52 }
53};
54} // namespace
55
56char NVPTXSetByValParamAlignLegacyPass::ID = 0;
57
58INITIALIZE_PASS(NVPTXSetByValParamAlignLegacyPass,
59 "nvptx-set-byval-param-align",
60 "Set alignment of byval parameters (NVPTX)", false, false)
61
62static Align setByValParamAlign(Argument *Arg) {
63 Function *F = Arg->getParent();
64 Type *ByValType = Arg->getParamByValType();
65 const DataLayout &DL = F->getDataLayout();
66
67 const Align OptimizedAlign = getFunctionParamOptimizedAlign(F, ByValType, DL);
68 const Align CurrentAlign = Arg->getParamAlign().valueOrOne();
69
70 if (CurrentAlign >= OptimizedAlign)
71 return CurrentAlign;
72
73 LLVM_DEBUG(dbgs() << "Try to use alignment " << OptimizedAlign.value()
74 << " instead of " << CurrentAlign.value() << " for " << *Arg
75 << '\n');
76
77 Arg->removeAttr(Attribute::Alignment);
78 Arg->addAttr(Attribute::getWithAlignment(F->getContext(), OptimizedAlign));
79
80 return OptimizedAlign;
81}
82
83// Adjust alignment of arguments passed byval in .param address space. We can
84// increase alignment of such arguments in a way that ensures that we can
85// effectively vectorize their loads. We should also traverse all loads from
86// byval pointer and adjust their alignment, if those were using known offset.
87// Such alignment changes must be conformed with parameter store and load in
88// NVPTXTargetLowering::LowerCall.
89static void propagateAlignmentToLoads(Value *Val, Align NewAlign,
90 const DataLayout &DL) {
91 struct Load {
92 LoadInst *Inst;
94 };
95
96 struct LoadContext {
97 Value *InitialVal;
99 };
100
101 SmallVector<Load> Loads;
102 std::queue<LoadContext> Worklist;
103 Worklist.push({Val, 0});
104
105 while (!Worklist.empty()) {
106 LoadContext Ctx = Worklist.front();
107 Worklist.pop();
108
109 for (User *CurUser : Ctx.InitialVal->users()) {
110 if (auto *I = dyn_cast<LoadInst>(CurUser))
111 Loads.push_back({I, Ctx.Offset});
112 else if (isa<BitCastInst>(CurUser) || isa<AddrSpaceCastInst>(CurUser))
113 Worklist.push({cast<Instruction>(CurUser), Ctx.Offset});
114 else if (auto *I = dyn_cast<GetElementPtrInst>(CurUser)) {
115 APInt OffsetAccumulated =
116 APInt::getZero(DL.getIndexTypeSizeInBits(I->getType()));
117
118 if (!I->accumulateConstantOffset(DL, OffsetAccumulated))
119 continue;
120
121 uint64_t OffsetLimit = -1;
122 uint64_t Offset = OffsetAccumulated.getLimitedValue(OffsetLimit);
123 assert(Offset != OffsetLimit && "Expect Offset less than UINT64_MAX");
124
125 Worklist.push({I, Ctx.Offset + Offset});
126 }
127 }
128 }
129
130 for (Load &CurLoad : Loads) {
131 Align NewLoadAlign = commonAlignment(NewAlign, CurLoad.Offset);
132 Align CurLoadAlign = CurLoad.Inst->getAlign();
133 CurLoad.Inst->setAlignment(std::max(NewLoadAlign, CurLoadAlign));
134 }
135}
136
138 const DataLayout &DL = F.getDataLayout();
139 bool Changed = false;
140 for (Argument &Arg : F.args()) {
141 if (!Arg.hasByValAttr())
142 continue;
143 const Align NewArgAlign = setByValParamAlign(&Arg);
144 propagateAlignmentToLoads(&Arg, NewArgAlign, DL);
145 Changed = true;
146 }
147 return Changed;
148}
149
150bool NVPTXSetByValParamAlignLegacyPass::runOnFunction(Function &F) {
152}
153
155 return new NVPTXSetByValParamAlignLegacyPass();
156}
157
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
static bool runOnFunction(Function &F, bool PostInlining)
#define F(x, y, z)
Definition MD5.cpp:54
#define I(x, y, z)
Definition MD5.cpp:57
static bool setByValParamAlignment(Function &F)
static void propagateAlignmentToLoads(Value *Val, Align NewAlign, const DataLayout &DL)
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
Definition PassSupport.h:56
#define LLVM_DEBUG(...)
Definition Debug.h:114
Class for arbitrary precision integers.
Definition APInt.h:78
uint64_t getLimitedValue(uint64_t Limit=UINT64_MAX) const
If this value is smaller than the specified limit, return it, otherwise return the limit value.
Definition APInt.h:476
static APInt getZero(unsigned numBits)
Get the '0' value for the specified bit-width.
Definition APInt.h:201
This class represents an incoming formal argument to a Function.
Definition Argument.h:32
static LLVM_ABI Attribute getWithAlignment(LLVMContext &Context, Align Alignment)
Return a uniquified Attribute object that has the specific alignment set.
A parsed version of the target data layout string in and methods for querying it.
Definition DataLayout.h:64
FunctionPass class - This class is used to implement most global optimizations.
Definition Pass.h:314
An instruction for reading from memory.
A set of analyses that are preserved following a run of a transformation pass.
Definition Analysis.h:112
static PreservedAnalyses none()
Convenience factory function for the empty preserved set.
Definition Analysis.h:115
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
Definition Analysis.h:118
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
StringRef - Represent a constant reference to a string, i.e.
Definition StringRef.h:55
The instances of the Type class are immutable: once they are created, they are never changed.
Definition Type.h:46
LLVM Value Representation.
Definition Value.h:75
iterator_range< user_iterator > users()
Definition Value.h:427
Changed
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
Definition CallingConv.h:24
This is an optimization pass for GlobalISel generic memory operations.
Definition Types.h:26
@ Offset
Definition DWP.cpp:532
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:643
FunctionPass * createNVPTXSetByValParamAlignPass()
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition Debug.cpp:207
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...
Definition Casting.h:547
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:559
Align commonAlignment(Align A, uint64_t Offset)
Returns the alignment that satisfies both alignments.
Definition Alignment.h:201
AnalysisManager< Function > FunctionAnalysisManager
Convenience typedef for the Function analysis manager.
Align getFunctionParamOptimizedAlign(const Function *F, Type *ArgTy, const DataLayout &DL)
Since function arguments are passed via .param space, we may want to increase their alignment in a wa...
This struct is a compact representation of a valid (non-zero power of two) alignment.
Definition Alignment.h:39
constexpr uint64_t value() const
This is a hole in the type system and should not be abused.
Definition Alignment.h:77
PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM)