/
redgpu
/
clspv
Обзор
Документация
Войти
/
redgpu
/
clspv
Код
Запросы
0
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
lib/RemoveUnusedArguments.cpp
186 строк
5 KB
alan-baker
Update deps (#523)
12 мар 2020, 21:59
Не верифицирован
12 мар 2020, 21:59
0d095d6
Код
Авторство
О чём код?
// Copyright 2019 The Clspv Authors. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include "llvm/IR/CallingConv.h" #include "llvm/IR/Constants.h" #include "llvm/IR/Function.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/Module.h" #include "llvm/Pass.h" #include "llvm/Support/raw_ostream.h" #include "clspv/Option.h" #include "Passes.h" using namespace llvm; namespace { class RemoveUnusedArguments final : public ModulePass { public: static char ID; RemoveUnusedArguments() : ModulePass(ID) {} bool runOnModule(Module &M) override; private: struct Candidate { Function *function; SmallVector<Value *, 8> args; }; // Populate |candidates| with non-kernel functions that have unused function // parameters. Returns true if any such functions are found. bool findCandidates(Module &M, std::vector<Candidate> *candidates); // Remove unused parameters in |candidates|. Rebuilds the functions without // the unused parameters. Updates calls and metadata to use the new function. void removeUnusedParameters(Module &M, const std::vector<Candidate> &candidates); }; } // namespace char RemoveUnusedArguments::ID = 0; INITIALIZE_PASS(RemoveUnusedArguments, "RemoveUnusedArguments", "Remove unused arguments from non-kernel functions", false, false) namespace clspv { ModulePass *createRemoveUnusedArgumentsPass() { return new RemoveUnusedArguments(); } } // namespace clspv namespace { bool RemoveUnusedArguments::runOnModule(Module &M) { if (clspv::Option::KeepUnusedArguments()) return false; std::vector<Candidate> candidates; bool changed = findCandidates(M, &candidates); removeUnusedParameters(M, candidates); return changed; } bool RemoveUnusedArguments::findCandidates(Module &M, std::vector<Candidate> *candidates) { bool changed = false; for (auto &F : M) { // Don't modify kernel functions. if (F.isDeclaration() || F.getCallingConv() == CallingConv::SPIR_KERNEL) continue; if (F.getFunctionType()->isVarArg()) continue; size_t i = 0; bool local_changed = false; SmallVector<Value *, 8> args; for (auto &Arg : F.args()) { if (Arg.use_empty()) { local_changed = true; args.push_back(nullptr); } else { ++i; args.push_back(&Arg); } } if (local_changed) { candidates->push_back({&F, args}); changed = true; } } return changed; } void RemoveUnusedArguments::removeUnusedParameters( Module &M, const std::vector<Candidate> &candidates) { for (auto &candidate : candidates) { Function *f = candidate.function; f->removeFromParent(); // Rebuild the type. SmallVector<Type *, 8> arg_types; for (auto *arg : candidate.args) { if (arg) { arg_types.push_back(arg->getType()); } } FunctionType *new_type = FunctionType::get(f->getReturnType(), arg_types, false); // Insert the new function. Copy the calling convention, attributes and // metadata. auto inserted = M.getOrInsertFunction(f->getName(), new_type, f->getAttributes()) .getCallee(); Function *new_function = cast<Function>(inserted); new_function->setCallingConv(f->getCallingConv()); new_function->copyMetadata(f, 0); // Move the basic blocks into the new function. if (!f->isDeclaration()) { std::vector<BasicBlock *> blocks; for (auto &BB : *f) { blocks.push_back(&BB); } for (auto *BB : blocks) { BB->removeFromParent(); BB->insertInto(new_function); } } // Replace uses of remaining args. auto new_arg_iter = new_function->arg_begin(); for (size_t old_arg_index = 0; old_arg_index < candidate.args.size(); ++old_arg_index) { if (auto *arg = candidate.args[old_arg_index]) { arg->replaceAllUsesWith(&*new_arg_iter); ++new_arg_iter; } } // Update calls to the old function. std::vector<User *> users; for (auto *U : f->users()) { users.push_back(U); } for (auto *U : users) { if (auto *call = dyn_cast<CallInst>(U)) { SmallVector<Value *, 8> args; for (size_t i = 0; i < candidate.args.size(); ++i) { if (candidate.args[i]) { args.push_back(call->getOperand(i)); } } CallInst *new_call = CallInst::Create(new_type, new_function, args, "", call); new_call->takeName(call); call->replaceAllUsesWith(new_call); call->eraseFromParent(); } } // Now we can delete the old version. delete f; } } } // namespace