LLVM 22.0.0git
AMDGPULowerIntrinsics.cpp
Go to the documentation of this file.
1//===-- AMDGPULowerIntrinsics.cpp -------------------------------------------=//
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// Lower intrinsics that would otherwise require separate handling in both
10// SelectionDAG and GlobalISel.
11//
12//===----------------------------------------------------------------------===//
13
14#include "AMDGPU.h"
15#include "AMDGPUTargetMachine.h"
16#include "GCNSubtarget.h"
17#include "llvm/IR/IRBuilder.h"
19#include "llvm/IR/IntrinsicsAMDGPU.h"
21
22#define DEBUG_TYPE "amdgpu-lower-intrinsics"
23
24using namespace llvm;
25
26namespace {
27
28class AMDGPULowerIntrinsicsImpl {
29public:
30 Module &M;
31 const AMDGPUTargetMachine &TM;
32
33 AMDGPULowerIntrinsicsImpl(Module &M, const AMDGPUTargetMachine &TM)
34 : M(M), TM(TM) {}
35
36 bool run();
37
38private:
39 bool visitBarrier(IntrinsicInst &I);
40};
41
42class AMDGPULowerIntrinsicsLegacy : public ModulePass {
43public:
44 static char ID;
45
46 AMDGPULowerIntrinsicsLegacy() : ModulePass(ID) {}
47
48 bool runOnModule(Module &M) override;
49
50 void getAnalysisUsage(AnalysisUsage &AU) const override {
52 AU.setPreservesCFG();
53 }
54};
55
56template <class T> static void forEachCall(Function &Intrin, T Callback) {
57 for (User *U : make_early_inc_range(Intrin.users())) {
58 if (auto *CI = dyn_cast<IntrinsicInst>(U))
59 Callback(CI);
60 }
61}
62
63} // anonymous namespace
64
65bool AMDGPULowerIntrinsicsImpl::run() {
66 bool Changed = false;
67
68 for (Function &F : M) {
69 switch (F.getIntrinsicID()) {
70 default:
71 continue;
72 case Intrinsic::amdgcn_s_barrier:
73 case Intrinsic::amdgcn_s_barrier_signal:
74 case Intrinsic::amdgcn_s_barrier_signal_isfirst:
75 case Intrinsic::amdgcn_s_barrier_wait:
76 forEachCall(F, [&](IntrinsicInst *II) { Changed |= visitBarrier(*II); });
77 break;
78 }
79 }
80
81 return Changed;
82}
83
84// Optimize barriers and lower s_barrier to a sequence of split barrier
85// intrinsics.
86bool AMDGPULowerIntrinsicsImpl::visitBarrier(IntrinsicInst &I) {
87 assert(I.getIntrinsicID() == Intrinsic::amdgcn_s_barrier ||
88 I.getIntrinsicID() == Intrinsic::amdgcn_s_barrier_signal ||
89 I.getIntrinsicID() == Intrinsic::amdgcn_s_barrier_signal_isfirst ||
90 I.getIntrinsicID() == Intrinsic::amdgcn_s_barrier_wait);
91
92 const GCNSubtarget &ST = TM.getSubtarget<GCNSubtarget>(*I.getFunction());
93 bool IsSingleWaveWG = false;
94
95 if (TM.getOptLevel() > CodeGenOptLevel::None) {
96 unsigned WGMaxSize = ST.getFlatWorkGroupSizes(*I.getFunction()).second;
97 IsSingleWaveWG = WGMaxSize <= ST.getWavefrontSize();
98 }
99
100 IRBuilder<> B(&I);
101
102 if (IsSingleWaveWG) {
103 // Down-grade waits, remove split signals.
104 if (I.getIntrinsicID() == Intrinsic::amdgcn_s_barrier ||
105 I.getIntrinsicID() == Intrinsic::amdgcn_s_barrier_wait) {
106 B.CreateIntrinsic(B.getVoidTy(), Intrinsic::amdgcn_wave_barrier, {});
107 } else if (I.getIntrinsicID() ==
108 Intrinsic::amdgcn_s_barrier_signal_isfirst) {
109 // If we're the only wave of the workgroup, we're always first.
110 I.replaceAllUsesWith(B.getInt1(true));
111 }
112 I.eraseFromParent();
113 return true;
114 }
115
116 if (I.getIntrinsicID() == Intrinsic::amdgcn_s_barrier &&
117 ST.hasSplitBarriers()) {
118 // Lower to split barriers.
119 Value *BarrierID_32 = B.getInt32(AMDGPU::Barrier::WORKGROUP);
120 Value *BarrierID_16 = B.getInt16(AMDGPU::Barrier::WORKGROUP);
121 B.CreateIntrinsic(B.getVoidTy(), Intrinsic::amdgcn_s_barrier_signal,
122 {BarrierID_32});
123 B.CreateIntrinsic(B.getVoidTy(), Intrinsic::amdgcn_s_barrier_wait,
124 {BarrierID_16});
125 I.eraseFromParent();
126 return true;
127 }
128
129 return false;
130}
131
134 AMDGPULowerIntrinsicsImpl Impl(M, TM);
135 if (!Impl.run())
136 return PreservedAnalyses::all();
139 return PA;
140}
141
142bool AMDGPULowerIntrinsicsLegacy::runOnModule(Module &M) {
143 auto &TPC = getAnalysis<TargetPassConfig>();
144 const AMDGPUTargetMachine &TM = TPC.getTM<AMDGPUTargetMachine>();
145
146 AMDGPULowerIntrinsicsImpl Impl(M, TM);
147 return Impl.run();
148}
149
150#define PASS_DESC "AMDGPU lower intrinsics"
151INITIALIZE_PASS_BEGIN(AMDGPULowerIntrinsicsLegacy, DEBUG_TYPE, PASS_DESC, false,
152 false)
154INITIALIZE_PASS_END(AMDGPULowerIntrinsicsLegacy, DEBUG_TYPE, PASS_DESC, false,
155 false)
156
157char AMDGPULowerIntrinsicsLegacy::ID = 0;
158
160 return new AMDGPULowerIntrinsicsLegacy;
161}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
The AMDGPU TargetMachine interface definition for hw codegen targets.
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
AMD GCN specific subclass of TargetSubtarget.
#define DEBUG_TYPE
#define F(x, y, z)
Definition MD5.cpp:55
#define I(x, y, z)
Definition MD5.cpp:58
#define T
uint64_t IntrinsicInst * II
ModuleAnalysisManager MAM
#define INITIALIZE_PASS_DEPENDENCY(depName)
Definition PassSupport.h:42
#define INITIALIZE_PASS_END(passName, arg, name, cfg, analysis)
Definition PassSupport.h:44
#define INITIALIZE_PASS_BEGIN(passName, arg, name, cfg, analysis)
Definition PassSupport.h:39
static bool forEachCall(Function &Intrin, T Callback)
Represent the analysis usage information of a pass.
AnalysisUsage & addRequired()
LLVM_ABI void setPreservesCFG()
This function should be called by the pass, iff they do not:
Definition Pass.cpp:270
Represents analyses that only rely on functions' control flow.
Definition Analysis.h:73
A wrapper class for inspecting calls to intrinsic functions.
ModulePass class - This class is used to implement unstructured interprocedural optimizations and ana...
Definition Pass.h:255
A Module instance is used to store all the information related to an LLVM module.
Definition Module.h:67
A set of analyses that are preserved following a run of a transformation pass.
Definition Analysis.h:112
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
Definition Analysis.h:118
PreservedAnalyses & preserveSet()
Mark an analysis set as preserved.
Definition Analysis.h:151
CodeGenOptLevel getOptLevel() const
Returns the optimization level: None, Less, Default, or Aggressive.
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.
iterator_range< user_iterator > users()
Definition Value.h:426
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.
FunctionAddr VTableAddr Value
Definition InstrProf.h:137
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:649
iterator_range< early_inc_iterator_impl< detail::IterOfRange< RangeT > > > make_early_inc_range(RangeT &&Range)
Make a range that does early increment to allow mutation of the underlying range without disrupting i...
Definition STLExtras.h:646
ModulePass * createAMDGPULowerIntrinsicsLegacyPass()
IRBuilder(LLVMContext &, FolderTy, InserterTy, MDNode *, ArrayRef< OperandBundleDef >) -> IRBuilder< FolderTy, InserterTy >
AnalysisManager< Module > ModuleAnalysisManager
Convenience typedef for the Module analysis manager.
Definition MIRParser.h:39
PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM)