1 /*========================== begin_copyright_notice ============================
2
3 Copyright (C) 2017-2021 Intel Corporation
4
5 SPDX-License-Identifier: MIT
6
7 ============================= end_copyright_notice ===========================*/
8
9 #include "Compiler/IGCPassSupport.h"
10
11 #include "common/LLVMWarningsPush.hpp"
12 #include "llvm/ADT/PostOrderIterator.h"
13 #include "llvm/Analysis/CallGraph.h"
14 #include "llvm/IR/Module.h"
15 #include "llvm/IR/Instructions.h"
16 #include "llvm/IR/Constants.h"
17 #include "llvm/Pass.h"
18 #include "common/LLVMWarningsPop.hpp"
19
20 using namespace llvm;
21
22 namespace {
23
24 class PruneUnusedArguments : public ModulePass {
25 public:
26 static char ID;
27 PruneUnusedArguments();
28 bool runOnModule(Module& M) override;
getAnalysisUsage(AnalysisUsage & AU) const29 void getAnalysisUsage(AnalysisUsage& AU) const override {
30 AU.addRequired<CallGraphWrapperPass>();
31 AU.addPreserved<CallGraphWrapperPass>();
32 AU.setPreservesCFG();
33 }
34 };
35
36 } // namespace
37
38 namespace IGC {
createPruneUnusedArgumentsPass()39 llvm::ModulePass* createPruneUnusedArgumentsPass() {
40 return new PruneUnusedArguments();
41 }
42 } // namespace IGC
43
44 IGC_INITIALIZE_PASS_BEGIN(PruneUnusedArguments, "PruneUnusedArguments", "PruneUnusedArguments", false, false)
45 IGC_INITIALIZE_PASS_DEPENDENCY(CallGraphWrapperPass)
46 IGC_INITIALIZE_PASS_END(PruneUnusedArguments, "PruneUnusedArguments", "PruneUnusedArguments", false, false)
47
48 char PruneUnusedArguments::ID = 0;
49
50 /// Optimize unused arguments, all indirectly unused arguments will be replaced
51 /// with undef and vISA emission will skip these copies. This is in fact a
52 /// cleanup to the unification passes, which run early in the pipeline. With
53 /// subroutines, this issue becomes worse.
54 ///
55 /// Note that (1) we do not delete those dead arguments since there may have
56 /// metadata on those functions; (2) the way we do private memory resolution may
57 /// introduce uses to r0 or payloadHeader(!!). For this reason, we run this pass
58 /// after private meomry resolution and no other pass should introduce such uses
59 /// after. If r0 is given by an intrinsic, then this is not an issue by design.
60 ///
runOnModule(Module & M)61 bool PruneUnusedArguments::runOnModule(Module& M) {
62 CallGraph& CG = getAnalysis<CallGraphWrapperPass>().getCallGraph();
63
64 // Visit functions in a post order DFS, i.e. reversed topological ordering. If
65 // an argument is not used then let its callers pass undef.
66 bool Changed = false;
67 for (auto I = po_begin(CG.getExternalCallingNode()),
68 E = po_end(CG.getExternalCallingNode());
69 I != E; ++I) {
70 auto CGNode = *I;
71 // Skip external and indirect nodes.
72 if (auto F = CGNode->getFunction()) {
73 // Conservatively declarations use all arguments.
74 if (F->isDeclaration())
75 continue;
76 // Ignore externally linked functions
77 if (F->hasFnAttribute("referenced-indirectly"))
78 continue;
79
80 // Collect unused arguments and their indices.
81 SmallVector<std::pair<Argument*, unsigned>, 8> UnusedArgs;
82 unsigned Index = 0;
83 for (auto& Arg : F->args()) {
84 if (Arg.use_empty())
85 UnusedArgs.push_back(std::make_pair(&Arg, Index));
86 Index++;
87 }
88
89 if (UnusedArgs.empty())
90 continue;
91
92 // Update call sites.
93 for (auto U : F->users()) {
94 CallInst* CI = dyn_cast<CallInst>(U);
95 if (!CI)
96 continue;
97 for (auto Item : UnusedArgs) {
98 auto Arg = Item.first;
99 auto Index = Item.second;
100 if (!isa<UndefValue>(CI->getArgOperand(Index))) {
101 CI->setArgOperand(Index, UndefValue::get(Arg->getType()));
102 Changed = true;
103 }
104 }
105 }
106 }
107 }
108
109 return Changed;
110 }
111
PruneUnusedArguments()112 PruneUnusedArguments::PruneUnusedArguments() : ModulePass(ID) {
113 initializePruneUnusedArgumentsPass(*PassRegistry::getPassRegistry());
114 }
115