106f32e7eSjoerg //===- AMDGPUAnnotateKernelFeaturesPass.cpp -------------------------------===//
206f32e7eSjoerg //
306f32e7eSjoerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
406f32e7eSjoerg // See https://llvm.org/LICENSE.txt for license information.
506f32e7eSjoerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
606f32e7eSjoerg //
706f32e7eSjoerg //===----------------------------------------------------------------------===//
806f32e7eSjoerg //
906f32e7eSjoerg /// \file This pass adds target attributes to functions which use intrinsics
1006f32e7eSjoerg /// which will impact calling convention lowering.
1106f32e7eSjoerg //
1206f32e7eSjoerg //===----------------------------------------------------------------------===//
1306f32e7eSjoerg
1406f32e7eSjoerg #include "AMDGPU.h"
15*da58b97aSjoerg #include "GCNSubtarget.h"
1606f32e7eSjoerg #include "llvm/Analysis/CallGraph.h"
1706f32e7eSjoerg #include "llvm/Analysis/CallGraphSCCPass.h"
1806f32e7eSjoerg #include "llvm/CodeGen/TargetPassConfig.h"
19*da58b97aSjoerg #include "llvm/IR/IntrinsicsAMDGPU.h"
20*da58b97aSjoerg #include "llvm/IR/IntrinsicsR600.h"
2106f32e7eSjoerg #include "llvm/Target/TargetMachine.h"
2206f32e7eSjoerg
2306f32e7eSjoerg #define DEBUG_TYPE "amdgpu-annotate-kernel-features"
2406f32e7eSjoerg
2506f32e7eSjoerg using namespace llvm;
2606f32e7eSjoerg
2706f32e7eSjoerg namespace {
28*da58b97aSjoerg static constexpr StringLiteral ImplicitAttrNames[] = {
29*da58b97aSjoerg // X ids unnecessarily propagated to kernels.
30*da58b97aSjoerg "amdgpu-work-item-id-x", "amdgpu-work-item-id-y",
31*da58b97aSjoerg "amdgpu-work-item-id-z", "amdgpu-work-group-id-x",
32*da58b97aSjoerg "amdgpu-work-group-id-y", "amdgpu-work-group-id-z",
33*da58b97aSjoerg "amdgpu-dispatch-ptr", "amdgpu-dispatch-id",
34*da58b97aSjoerg "amdgpu-queue-ptr", "amdgpu-implicitarg-ptr"};
3506f32e7eSjoerg
3606f32e7eSjoerg class AMDGPUAnnotateKernelFeatures : public CallGraphSCCPass {
3706f32e7eSjoerg private:
3806f32e7eSjoerg const TargetMachine *TM = nullptr;
3906f32e7eSjoerg SmallVector<CallGraphNode*, 8> NodeList;
4006f32e7eSjoerg
4106f32e7eSjoerg bool addFeatureAttributes(Function &F);
4206f32e7eSjoerg bool processUniformWorkGroupAttribute();
4306f32e7eSjoerg bool propagateUniformWorkGroupAttribute(Function &Caller, Function &Callee);
4406f32e7eSjoerg
4506f32e7eSjoerg public:
4606f32e7eSjoerg static char ID;
4706f32e7eSjoerg
AMDGPUAnnotateKernelFeatures()4806f32e7eSjoerg AMDGPUAnnotateKernelFeatures() : CallGraphSCCPass(ID) {}
4906f32e7eSjoerg
5006f32e7eSjoerg bool doInitialization(CallGraph &CG) override;
5106f32e7eSjoerg bool runOnSCC(CallGraphSCC &SCC) override;
5206f32e7eSjoerg
getPassName() const5306f32e7eSjoerg StringRef getPassName() const override {
5406f32e7eSjoerg return "AMDGPU Annotate Kernel Features";
5506f32e7eSjoerg }
5606f32e7eSjoerg
getAnalysisUsage(AnalysisUsage & AU) const5706f32e7eSjoerg void getAnalysisUsage(AnalysisUsage &AU) const override {
5806f32e7eSjoerg AU.setPreservesAll();
5906f32e7eSjoerg CallGraphSCCPass::getAnalysisUsage(AU);
6006f32e7eSjoerg }
6106f32e7eSjoerg
6206f32e7eSjoerg static bool visitConstantExpr(const ConstantExpr *CE);
6306f32e7eSjoerg static bool visitConstantExprsRecursively(
6406f32e7eSjoerg const Constant *EntryC,
65*da58b97aSjoerg SmallPtrSet<const Constant *, 8> &ConstantExprVisited, bool IsFunc,
66*da58b97aSjoerg bool HasApertureRegs);
6706f32e7eSjoerg };
6806f32e7eSjoerg
6906f32e7eSjoerg } // end anonymous namespace
7006f32e7eSjoerg
7106f32e7eSjoerg char AMDGPUAnnotateKernelFeatures::ID = 0;
7206f32e7eSjoerg
7306f32e7eSjoerg char &llvm::AMDGPUAnnotateKernelFeaturesID = AMDGPUAnnotateKernelFeatures::ID;
7406f32e7eSjoerg
7506f32e7eSjoerg INITIALIZE_PASS(AMDGPUAnnotateKernelFeatures, DEBUG_TYPE,
7606f32e7eSjoerg "Add AMDGPU function attributes", false, false)
7706f32e7eSjoerg
7806f32e7eSjoerg
7906f32e7eSjoerg // The queue ptr is only needed when casting to flat, not from it.
castRequiresQueuePtr(unsigned SrcAS)8006f32e7eSjoerg static bool castRequiresQueuePtr(unsigned SrcAS) {
8106f32e7eSjoerg return SrcAS == AMDGPUAS::LOCAL_ADDRESS || SrcAS == AMDGPUAS::PRIVATE_ADDRESS;
8206f32e7eSjoerg }
8306f32e7eSjoerg
castRequiresQueuePtr(const AddrSpaceCastInst * ASC)8406f32e7eSjoerg static bool castRequiresQueuePtr(const AddrSpaceCastInst *ASC) {
8506f32e7eSjoerg return castRequiresQueuePtr(ASC->getSrcAddressSpace());
8606f32e7eSjoerg }
8706f32e7eSjoerg
isDSAddress(const Constant * C)88*da58b97aSjoerg static bool isDSAddress(const Constant *C) {
89*da58b97aSjoerg const GlobalValue *GV = dyn_cast<GlobalValue>(C);
90*da58b97aSjoerg if (!GV)
91*da58b97aSjoerg return false;
92*da58b97aSjoerg unsigned AS = GV->getAddressSpace();
93*da58b97aSjoerg return AS == AMDGPUAS::LOCAL_ADDRESS || AS == AMDGPUAS::REGION_ADDRESS;
94*da58b97aSjoerg }
95*da58b97aSjoerg
visitConstantExpr(const ConstantExpr * CE)9606f32e7eSjoerg bool AMDGPUAnnotateKernelFeatures::visitConstantExpr(const ConstantExpr *CE) {
9706f32e7eSjoerg if (CE->getOpcode() == Instruction::AddrSpaceCast) {
9806f32e7eSjoerg unsigned SrcAS = CE->getOperand(0)->getType()->getPointerAddressSpace();
9906f32e7eSjoerg return castRequiresQueuePtr(SrcAS);
10006f32e7eSjoerg }
10106f32e7eSjoerg
10206f32e7eSjoerg return false;
10306f32e7eSjoerg }
10406f32e7eSjoerg
visitConstantExprsRecursively(const Constant * EntryC,SmallPtrSet<const Constant *,8> & ConstantExprVisited,bool IsFunc,bool HasApertureRegs)10506f32e7eSjoerg bool AMDGPUAnnotateKernelFeatures::visitConstantExprsRecursively(
10606f32e7eSjoerg const Constant *EntryC,
107*da58b97aSjoerg SmallPtrSet<const Constant *, 8> &ConstantExprVisited,
108*da58b97aSjoerg bool IsFunc, bool HasApertureRegs) {
10906f32e7eSjoerg
11006f32e7eSjoerg if (!ConstantExprVisited.insert(EntryC).second)
11106f32e7eSjoerg return false;
11206f32e7eSjoerg
11306f32e7eSjoerg SmallVector<const Constant *, 16> Stack;
11406f32e7eSjoerg Stack.push_back(EntryC);
11506f32e7eSjoerg
11606f32e7eSjoerg while (!Stack.empty()) {
11706f32e7eSjoerg const Constant *C = Stack.pop_back_val();
11806f32e7eSjoerg
119*da58b97aSjoerg // We need to trap on DS globals in non-entry functions.
120*da58b97aSjoerg if (IsFunc && isDSAddress(C))
121*da58b97aSjoerg return true;
122*da58b97aSjoerg
12306f32e7eSjoerg // Check this constant expression.
12406f32e7eSjoerg if (const auto *CE = dyn_cast<ConstantExpr>(C)) {
125*da58b97aSjoerg if (!HasApertureRegs && visitConstantExpr(CE))
12606f32e7eSjoerg return true;
12706f32e7eSjoerg }
12806f32e7eSjoerg
12906f32e7eSjoerg // Visit all sub-expressions.
13006f32e7eSjoerg for (const Use &U : C->operands()) {
13106f32e7eSjoerg const auto *OpC = dyn_cast<Constant>(U);
13206f32e7eSjoerg if (!OpC)
13306f32e7eSjoerg continue;
13406f32e7eSjoerg
13506f32e7eSjoerg if (!ConstantExprVisited.insert(OpC).second)
13606f32e7eSjoerg continue;
13706f32e7eSjoerg
13806f32e7eSjoerg Stack.push_back(OpC);
13906f32e7eSjoerg }
14006f32e7eSjoerg }
14106f32e7eSjoerg
14206f32e7eSjoerg return false;
14306f32e7eSjoerg }
14406f32e7eSjoerg
14506f32e7eSjoerg // We do not need to note the x workitem or workgroup id because they are always
14606f32e7eSjoerg // initialized.
14706f32e7eSjoerg //
14806f32e7eSjoerg // TODO: We should not add the attributes if the known compile time workgroup
14906f32e7eSjoerg // size is 1 for y/z.
intrinsicToAttrName(Intrinsic::ID ID,bool & NonKernelOnly,bool & IsQueuePtr)15006f32e7eSjoerg static StringRef intrinsicToAttrName(Intrinsic::ID ID,
15106f32e7eSjoerg bool &NonKernelOnly,
15206f32e7eSjoerg bool &IsQueuePtr) {
15306f32e7eSjoerg switch (ID) {
15406f32e7eSjoerg case Intrinsic::amdgcn_workitem_id_x:
15506f32e7eSjoerg NonKernelOnly = true;
15606f32e7eSjoerg return "amdgpu-work-item-id-x";
15706f32e7eSjoerg case Intrinsic::amdgcn_workgroup_id_x:
15806f32e7eSjoerg NonKernelOnly = true;
15906f32e7eSjoerg return "amdgpu-work-group-id-x";
16006f32e7eSjoerg case Intrinsic::amdgcn_workitem_id_y:
16106f32e7eSjoerg case Intrinsic::r600_read_tidig_y:
16206f32e7eSjoerg return "amdgpu-work-item-id-y";
16306f32e7eSjoerg case Intrinsic::amdgcn_workitem_id_z:
16406f32e7eSjoerg case Intrinsic::r600_read_tidig_z:
16506f32e7eSjoerg return "amdgpu-work-item-id-z";
16606f32e7eSjoerg case Intrinsic::amdgcn_workgroup_id_y:
16706f32e7eSjoerg case Intrinsic::r600_read_tgid_y:
16806f32e7eSjoerg return "amdgpu-work-group-id-y";
16906f32e7eSjoerg case Intrinsic::amdgcn_workgroup_id_z:
17006f32e7eSjoerg case Intrinsic::r600_read_tgid_z:
17106f32e7eSjoerg return "amdgpu-work-group-id-z";
17206f32e7eSjoerg case Intrinsic::amdgcn_dispatch_ptr:
17306f32e7eSjoerg return "amdgpu-dispatch-ptr";
17406f32e7eSjoerg case Intrinsic::amdgcn_dispatch_id:
17506f32e7eSjoerg return "amdgpu-dispatch-id";
17606f32e7eSjoerg case Intrinsic::amdgcn_kernarg_segment_ptr:
17706f32e7eSjoerg return "amdgpu-kernarg-segment-ptr";
17806f32e7eSjoerg case Intrinsic::amdgcn_implicitarg_ptr:
17906f32e7eSjoerg return "amdgpu-implicitarg-ptr";
18006f32e7eSjoerg case Intrinsic::amdgcn_queue_ptr:
18106f32e7eSjoerg case Intrinsic::amdgcn_is_shared:
18206f32e7eSjoerg case Intrinsic::amdgcn_is_private:
18306f32e7eSjoerg // TODO: Does not require queue ptr on gfx9+
18406f32e7eSjoerg case Intrinsic::trap:
18506f32e7eSjoerg case Intrinsic::debugtrap:
18606f32e7eSjoerg IsQueuePtr = true;
18706f32e7eSjoerg return "amdgpu-queue-ptr";
18806f32e7eSjoerg default:
18906f32e7eSjoerg return "";
19006f32e7eSjoerg }
19106f32e7eSjoerg }
19206f32e7eSjoerg
handleAttr(Function & Parent,const Function & Callee,StringRef Name)19306f32e7eSjoerg static bool handleAttr(Function &Parent, const Function &Callee,
19406f32e7eSjoerg StringRef Name) {
19506f32e7eSjoerg if (Callee.hasFnAttribute(Name)) {
19606f32e7eSjoerg Parent.addFnAttr(Name);
19706f32e7eSjoerg return true;
19806f32e7eSjoerg }
19906f32e7eSjoerg return false;
20006f32e7eSjoerg }
20106f32e7eSjoerg
copyFeaturesToFunction(Function & Parent,const Function & Callee,bool & NeedQueuePtr)20206f32e7eSjoerg static void copyFeaturesToFunction(Function &Parent, const Function &Callee,
20306f32e7eSjoerg bool &NeedQueuePtr) {
20406f32e7eSjoerg if (handleAttr(Parent, Callee, "amdgpu-queue-ptr"))
20506f32e7eSjoerg NeedQueuePtr = true;
20606f32e7eSjoerg
207*da58b97aSjoerg for (StringRef AttrName : ImplicitAttrNames)
20806f32e7eSjoerg handleAttr(Parent, Callee, AttrName);
20906f32e7eSjoerg }
21006f32e7eSjoerg
processUniformWorkGroupAttribute()21106f32e7eSjoerg bool AMDGPUAnnotateKernelFeatures::processUniformWorkGroupAttribute() {
21206f32e7eSjoerg bool Changed = false;
21306f32e7eSjoerg
21406f32e7eSjoerg for (auto *Node : reverse(NodeList)) {
21506f32e7eSjoerg Function *Caller = Node->getFunction();
21606f32e7eSjoerg
21706f32e7eSjoerg for (auto I : *Node) {
21806f32e7eSjoerg Function *Callee = std::get<1>(I)->getFunction();
21906f32e7eSjoerg if (Callee)
22006f32e7eSjoerg Changed = propagateUniformWorkGroupAttribute(*Caller, *Callee);
22106f32e7eSjoerg }
22206f32e7eSjoerg }
22306f32e7eSjoerg
22406f32e7eSjoerg return Changed;
22506f32e7eSjoerg }
22606f32e7eSjoerg
propagateUniformWorkGroupAttribute(Function & Caller,Function & Callee)22706f32e7eSjoerg bool AMDGPUAnnotateKernelFeatures::propagateUniformWorkGroupAttribute(
22806f32e7eSjoerg Function &Caller, Function &Callee) {
22906f32e7eSjoerg
23006f32e7eSjoerg // Check for externally defined function
23106f32e7eSjoerg if (!Callee.hasExactDefinition()) {
23206f32e7eSjoerg Callee.addFnAttr("uniform-work-group-size", "false");
23306f32e7eSjoerg if (!Caller.hasFnAttribute("uniform-work-group-size"))
23406f32e7eSjoerg Caller.addFnAttr("uniform-work-group-size", "false");
23506f32e7eSjoerg
23606f32e7eSjoerg return true;
23706f32e7eSjoerg }
23806f32e7eSjoerg // Check if the Caller has the attribute
23906f32e7eSjoerg if (Caller.hasFnAttribute("uniform-work-group-size")) {
24006f32e7eSjoerg // Check if the value of the attribute is true
24106f32e7eSjoerg if (Caller.getFnAttribute("uniform-work-group-size")
24206f32e7eSjoerg .getValueAsString().equals("true")) {
24306f32e7eSjoerg // Propagate the attribute to the Callee, if it does not have it
24406f32e7eSjoerg if (!Callee.hasFnAttribute("uniform-work-group-size")) {
24506f32e7eSjoerg Callee.addFnAttr("uniform-work-group-size", "true");
24606f32e7eSjoerg return true;
24706f32e7eSjoerg }
24806f32e7eSjoerg } else {
24906f32e7eSjoerg Callee.addFnAttr("uniform-work-group-size", "false");
25006f32e7eSjoerg return true;
25106f32e7eSjoerg }
25206f32e7eSjoerg } else {
25306f32e7eSjoerg // If the attribute is absent, set it as false
25406f32e7eSjoerg Caller.addFnAttr("uniform-work-group-size", "false");
25506f32e7eSjoerg Callee.addFnAttr("uniform-work-group-size", "false");
25606f32e7eSjoerg return true;
25706f32e7eSjoerg }
25806f32e7eSjoerg return false;
25906f32e7eSjoerg }
26006f32e7eSjoerg
addFeatureAttributes(Function & F)26106f32e7eSjoerg bool AMDGPUAnnotateKernelFeatures::addFeatureAttributes(Function &F) {
26206f32e7eSjoerg const GCNSubtarget &ST = TM->getSubtarget<GCNSubtarget>(F);
26306f32e7eSjoerg bool HasApertureRegs = ST.hasApertureRegs();
26406f32e7eSjoerg SmallPtrSet<const Constant *, 8> ConstantExprVisited;
26506f32e7eSjoerg
266*da58b97aSjoerg bool HaveStackObjects = false;
26706f32e7eSjoerg bool Changed = false;
26806f32e7eSjoerg bool NeedQueuePtr = false;
26906f32e7eSjoerg bool HaveCall = false;
270*da58b97aSjoerg bool HasIndirectCall = false;
27106f32e7eSjoerg bool IsFunc = !AMDGPU::isEntryFunctionCC(F.getCallingConv());
272*da58b97aSjoerg CallingConv::ID CC = F.getCallingConv();
273*da58b97aSjoerg bool CallingConvSupportsAllImplicits = (CC != CallingConv::AMDGPU_Gfx);
274*da58b97aSjoerg
275*da58b97aSjoerg // If this function hasAddressTaken() = true
276*da58b97aSjoerg // then add all attributes corresponding to the implicit args.
277*da58b97aSjoerg if (CallingConvSupportsAllImplicits &&
278*da58b97aSjoerg F.hasAddressTaken(nullptr, true, true, true)) {
279*da58b97aSjoerg for (StringRef AttrName : ImplicitAttrNames) {
280*da58b97aSjoerg F.addFnAttr(AttrName);
281*da58b97aSjoerg }
282*da58b97aSjoerg Changed = true;
283*da58b97aSjoerg }
28406f32e7eSjoerg
28506f32e7eSjoerg for (BasicBlock &BB : F) {
28606f32e7eSjoerg for (Instruction &I : BB) {
287*da58b97aSjoerg if (isa<AllocaInst>(I)) {
288*da58b97aSjoerg HaveStackObjects = true;
289*da58b97aSjoerg continue;
290*da58b97aSjoerg }
29106f32e7eSjoerg
292*da58b97aSjoerg if (auto *CB = dyn_cast<CallBase>(&I)) {
293*da58b97aSjoerg const Function *Callee =
294*da58b97aSjoerg dyn_cast<Function>(CB->getCalledOperand()->stripPointerCasts());
295*da58b97aSjoerg
296*da58b97aSjoerg // Note the occurence of indirect call.
29706f32e7eSjoerg if (!Callee) {
298*da58b97aSjoerg if (!CB->isInlineAsm()) {
299*da58b97aSjoerg HasIndirectCall = true;
30006f32e7eSjoerg HaveCall = true;
301*da58b97aSjoerg }
30206f32e7eSjoerg continue;
30306f32e7eSjoerg }
30406f32e7eSjoerg
30506f32e7eSjoerg Intrinsic::ID IID = Callee->getIntrinsicID();
30606f32e7eSjoerg if (IID == Intrinsic::not_intrinsic) {
30706f32e7eSjoerg HaveCall = true;
30806f32e7eSjoerg copyFeaturesToFunction(F, *Callee, NeedQueuePtr);
30906f32e7eSjoerg Changed = true;
31006f32e7eSjoerg } else {
31106f32e7eSjoerg bool NonKernelOnly = false;
312*da58b97aSjoerg
313*da58b97aSjoerg if (!IsFunc && IID == Intrinsic::amdgcn_kernarg_segment_ptr) {
314*da58b97aSjoerg F.addFnAttr("amdgpu-kernarg-segment-ptr");
315*da58b97aSjoerg } else {
316*da58b97aSjoerg StringRef AttrName = intrinsicToAttrName(IID, NonKernelOnly,
317*da58b97aSjoerg NeedQueuePtr);
31806f32e7eSjoerg if (!AttrName.empty() && (IsFunc || !NonKernelOnly)) {
31906f32e7eSjoerg F.addFnAttr(AttrName);
32006f32e7eSjoerg Changed = true;
32106f32e7eSjoerg }
32206f32e7eSjoerg }
32306f32e7eSjoerg }
324*da58b97aSjoerg }
32506f32e7eSjoerg
326*da58b97aSjoerg if (NeedQueuePtr || (!IsFunc && HasApertureRegs))
32706f32e7eSjoerg continue;
32806f32e7eSjoerg
32906f32e7eSjoerg if (const AddrSpaceCastInst *ASC = dyn_cast<AddrSpaceCastInst>(&I)) {
330*da58b97aSjoerg if (!HasApertureRegs && castRequiresQueuePtr(ASC)) {
33106f32e7eSjoerg NeedQueuePtr = true;
33206f32e7eSjoerg continue;
33306f32e7eSjoerg }
33406f32e7eSjoerg }
33506f32e7eSjoerg
33606f32e7eSjoerg for (const Use &U : I.operands()) {
33706f32e7eSjoerg const auto *OpC = dyn_cast<Constant>(U);
33806f32e7eSjoerg if (!OpC)
33906f32e7eSjoerg continue;
34006f32e7eSjoerg
341*da58b97aSjoerg if (visitConstantExprsRecursively(OpC, ConstantExprVisited, IsFunc,
342*da58b97aSjoerg HasApertureRegs)) {
34306f32e7eSjoerg NeedQueuePtr = true;
34406f32e7eSjoerg break;
34506f32e7eSjoerg }
34606f32e7eSjoerg }
34706f32e7eSjoerg }
34806f32e7eSjoerg }
34906f32e7eSjoerg
35006f32e7eSjoerg if (NeedQueuePtr) {
35106f32e7eSjoerg F.addFnAttr("amdgpu-queue-ptr");
35206f32e7eSjoerg Changed = true;
35306f32e7eSjoerg }
35406f32e7eSjoerg
35506f32e7eSjoerg // TODO: We could refine this to captured pointers that could possibly be
35606f32e7eSjoerg // accessed by flat instructions. For now this is mostly a poor way of
35706f32e7eSjoerg // estimating whether there are calls before argument lowering.
358*da58b97aSjoerg if (!IsFunc && HaveCall) {
359*da58b97aSjoerg F.addFnAttr("amdgpu-calls");
360*da58b97aSjoerg Changed = true;
361*da58b97aSjoerg }
362*da58b97aSjoerg
363*da58b97aSjoerg if (HaveStackObjects) {
364*da58b97aSjoerg F.addFnAttr("amdgpu-stack-objects");
365*da58b97aSjoerg Changed = true;
366*da58b97aSjoerg }
367*da58b97aSjoerg
368*da58b97aSjoerg // This pass cannot copy attributes from callees to callers
369*da58b97aSjoerg // if there is an indirect call and in thus such cases,
370*da58b97aSjoerg // hasAddressTaken() would be false for kernels and functions
371*da58b97aSjoerg // making an indirect call (if they are themselves not indirectly called).
372*da58b97aSjoerg // We must tag all such kernels/functions with all implicits attributes
373*da58b97aSjoerg // for correctness.
374*da58b97aSjoerg // e.g.
375*da58b97aSjoerg // 1. Kernel K1 makes an indirect call to function F1.
376*da58b97aSjoerg // Without detecting an indirect call in K1, this pass will not
377*da58b97aSjoerg // add all implicit args to K1 (which is incorrect).
378*da58b97aSjoerg // 2. Kernel K1 makes direct call to F1 which makes indirect call to function
379*da58b97aSjoerg // F2.
380*da58b97aSjoerg // Without detecting an indirect call in F1 (whose hasAddressTaken() is
381*da58b97aSjoerg // false), the pass will not add all implicit args to F1 (which is
382*da58b97aSjoerg // essential for correctness).
383*da58b97aSjoerg if (CallingConvSupportsAllImplicits && HasIndirectCall) {
384*da58b97aSjoerg for (StringRef AttrName : ImplicitAttrNames) {
385*da58b97aSjoerg F.addFnAttr(AttrName);
386*da58b97aSjoerg }
38706f32e7eSjoerg Changed = true;
38806f32e7eSjoerg }
38906f32e7eSjoerg
39006f32e7eSjoerg return Changed;
39106f32e7eSjoerg }
39206f32e7eSjoerg
runOnSCC(CallGraphSCC & SCC)39306f32e7eSjoerg bool AMDGPUAnnotateKernelFeatures::runOnSCC(CallGraphSCC &SCC) {
39406f32e7eSjoerg bool Changed = false;
39506f32e7eSjoerg
39606f32e7eSjoerg for (CallGraphNode *I : SCC) {
39706f32e7eSjoerg // Build a list of CallGraphNodes from most number of uses to least
39806f32e7eSjoerg if (I->getNumReferences())
39906f32e7eSjoerg NodeList.push_back(I);
40006f32e7eSjoerg else {
40106f32e7eSjoerg processUniformWorkGroupAttribute();
40206f32e7eSjoerg NodeList.clear();
40306f32e7eSjoerg }
40406f32e7eSjoerg
40506f32e7eSjoerg Function *F = I->getFunction();
406*da58b97aSjoerg // Ignore functions with graphics calling conventions, these are currently
407*da58b97aSjoerg // not allowed to have kernel arguments.
408*da58b97aSjoerg if (!F || F->isDeclaration() || AMDGPU::isGraphics(F->getCallingConv()))
40906f32e7eSjoerg continue;
410*da58b97aSjoerg // Add feature attributes
41106f32e7eSjoerg Changed |= addFeatureAttributes(*F);
41206f32e7eSjoerg }
41306f32e7eSjoerg
41406f32e7eSjoerg return Changed;
41506f32e7eSjoerg }
41606f32e7eSjoerg
doInitialization(CallGraph & CG)41706f32e7eSjoerg bool AMDGPUAnnotateKernelFeatures::doInitialization(CallGraph &CG) {
41806f32e7eSjoerg auto *TPC = getAnalysisIfAvailable<TargetPassConfig>();
41906f32e7eSjoerg if (!TPC)
42006f32e7eSjoerg report_fatal_error("TargetMachine is required");
42106f32e7eSjoerg
42206f32e7eSjoerg TM = &TPC->getTM<TargetMachine>();
42306f32e7eSjoerg return false;
42406f32e7eSjoerg }
42506f32e7eSjoerg
createAMDGPUAnnotateKernelFeaturesPass()42606f32e7eSjoerg Pass *llvm::createAMDGPUAnnotateKernelFeaturesPass() {
42706f32e7eSjoerg return new AMDGPUAnnotateKernelFeatures();
42806f32e7eSjoerg }
429