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