blob: 47e4752e1dd7bb9bcafa4e4204142895363f332c [file] [log] [blame]
alan-baker4217b322019-03-06 08:56:12 -05001// Copyright 2019 The Clspv Authors. All rights reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#include "llvm/IR/CallingConv.h"
16#include "llvm/IR/Constants.h"
17#include "llvm/IR/Function.h"
18#include "llvm/IR/Instructions.h"
19#include "llvm/IR/Module.h"
20#include "llvm/Pass.h"
21#include "llvm/Support/raw_ostream.h"
22
23#include "clspv/Option.h"
Diego Novilloa4c44fa2019-04-11 10:56:15 -040024
25#include "Passes.h"
alan-baker4217b322019-03-06 08:56:12 -050026
27using namespace llvm;
28
29namespace {
30
31class RemoveUnusedArguments final : public ModulePass {
32public:
33 static char ID;
34 RemoveUnusedArguments() : ModulePass(ID) {}
35 bool runOnModule(Module &M) override;
36
37private:
38 struct Candidate {
39 Function *function;
40 SmallVector<Value *, 8> args;
41 };
42
43 // Populate |candidates| with non-kernel functions that have unused function
44 // parameters. Returns true if any such functions are found.
45 bool findCandidates(Module &M, std::vector<Candidate> *candidates);
46
47 // Remove unused parameters in |candidates|. Rebuilds the functions without
48 // the unused parameters. Updates calls and metadata to use the new function.
49 void removeUnusedParameters(Module &M,
50 const std::vector<Candidate> &candidates);
51};
52
Diego Novillo3cc8d7a2019-04-10 13:30:34 -040053} // namespace
alan-baker4217b322019-03-06 08:56:12 -050054
Diego Novilloa4c44fa2019-04-11 10:56:15 -040055char RemoveUnusedArguments::ID = 0;
56INITIALIZE_PASS(RemoveUnusedArguments, "RemoveUnusuedArguments",
57 "Remove unused arguments from non-kernel functions", false,
58 false)
59
alan-baker4217b322019-03-06 08:56:12 -050060namespace clspv {
Diego Novillo3cc8d7a2019-04-10 13:30:34 -040061ModulePass *createRemoveUnusedArgumentsPass() {
62 return new RemoveUnusedArguments();
alan-baker4217b322019-03-06 08:56:12 -050063}
Diego Novillo3cc8d7a2019-04-10 13:30:34 -040064} // namespace clspv
alan-baker4217b322019-03-06 08:56:12 -050065
66namespace {
67
68bool RemoveUnusedArguments::runOnModule(Module &M) {
69 if (clspv::Option::KeepUnusedArguments())
70 return false;
71
72 std::vector<Candidate> candidates;
73 bool changed = findCandidates(M, &candidates);
74 removeUnusedParameters(M, candidates);
75
76 return changed;
77}
78
Diego Novillo3cc8d7a2019-04-10 13:30:34 -040079bool RemoveUnusedArguments::findCandidates(Module &M,
80 std::vector<Candidate> *candidates) {
alan-baker4217b322019-03-06 08:56:12 -050081 bool changed = false;
82 for (auto &F : M) {
83 // Don't modify kernel functions.
84 if (F.isDeclaration() || F.getCallingConv() == CallingConv::SPIR_KERNEL)
85 continue;
86
87 if (F.getFunctionType()->isVarArg())
88 continue;
89
90 size_t i = 0;
91 bool local_changed = false;
92 SmallVector<Value *, 8> args;
Diego Novillo3cc8d7a2019-04-10 13:30:34 -040093 for (auto &Arg : F.args()) {
alan-baker4217b322019-03-06 08:56:12 -050094 if (Arg.use_empty()) {
95 local_changed = true;
96 args.push_back(nullptr);
97 } else {
98 ++i;
99 args.push_back(&Arg);
100 }
101 }
102
103 if (local_changed) {
104 candidates->push_back({&F, args});
105 changed = true;
106 }
107 }
108
109 return changed;
110}
111
112void RemoveUnusedArguments::removeUnusedParameters(
113 Module &M, const std::vector<Candidate> &candidates) {
114 for (auto &candidate : candidates) {
115 Function *f = candidate.function;
116 f->removeFromParent();
117
118 // Rebuild the type.
119 SmallVector<Type *, 8> arg_types;
120 for (auto *arg : candidate.args) {
121 if (arg) {
122 arg_types.push_back(arg->getType());
123 }
124 }
Diego Novillo3cc8d7a2019-04-10 13:30:34 -0400125 FunctionType *new_type =
126 FunctionType::get(f->getReturnType(), arg_types, false);
alan-baker4217b322019-03-06 08:56:12 -0500127
128 // Insert the new function. Copy the calling convention, attributes and
129 // metadata.
alan-bakerbccf62c2019-03-29 10:32:41 -0400130 auto inserted =
Diego Novillo3cc8d7a2019-04-10 13:30:34 -0400131 M.getOrInsertFunction(f->getName(), new_type, f->getAttributes())
132 .getCallee();
alan-baker4217b322019-03-06 08:56:12 -0500133 Function *new_function = cast<Function>(inserted);
134 new_function->setCallingConv(f->getCallingConv());
135 new_function->copyMetadata(f, 0);
136
137 // Move the basic blocks into the new function.
138 if (!f->isDeclaration()) {
139 std::vector<BasicBlock *> blocks;
140 for (auto &BB : *f) {
141 blocks.push_back(&BB);
142 }
143 for (auto *BB : blocks) {
144 BB->removeFromParent();
145 BB->insertInto(new_function);
146 }
147 }
148
149 // Replace uses of remaining args.
150 auto new_arg_iter = new_function->arg_begin();
151 for (size_t old_arg_index = 0; old_arg_index < candidate.args.size();
152 ++old_arg_index) {
153 if (auto *arg = candidate.args[old_arg_index]) {
154 arg->replaceAllUsesWith(&*new_arg_iter);
155 ++new_arg_iter;
156 }
157 }
158
159 // Update calls to the old function.
160 std::vector<User *> users;
161 for (auto *U : f->users()) {
162 users.push_back(U);
163 }
164
165 for (auto *U : users) {
166 if (auto *call = dyn_cast<CallInst>(U)) {
167 SmallVector<Value *, 8> args;
168 for (size_t i = 0; i < candidate.args.size(); ++i) {
169 if (candidate.args[i]) {
170 args.push_back(call->getOperand(i));
171 }
172 }
Diego Novillo3cc8d7a2019-04-10 13:30:34 -0400173 CallInst *new_call =
174 CallInst::Create(new_type, new_function, args, "", call);
alan-baker4217b322019-03-06 08:56:12 -0500175 new_call->takeName(call);
176 call->replaceAllUsesWith(new_call);
177 call->eraseFromParent();
178 }
179 }
180
181 // Now we can delete the old version.
182 delete f;
183 }
184}
185
Diego Novillo3cc8d7a2019-04-10 13:30:34 -0400186} // namespace