David Blaikie | 5adb3d2 | 2019-09-12 01:20:48 +0000 | [diff] [blame] | 1 | //===- ReduceArguments.cpp - Specialized Delta Pass -----------------------===// |
| 2 | // |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| 4 | // See https://llvm.org/LICENSE.txt for license information. |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| 6 | // |
| 7 | //===----------------------------------------------------------------------===// |
| 8 | // |
| 9 | // This file implements a function which calls the Generic Delta pass in order |
| 10 | // to reduce uninteresting Arguments from defined functions. |
| 11 | // |
| 12 | //===----------------------------------------------------------------------===// |
| 13 | |
| 14 | #include "ReduceArguments.h" |
| 15 | #include "Delta.h" |
| 16 | #include "llvm/ADT/SmallVector.h" |
| 17 | #include <set> |
| 18 | #include <vector> |
| 19 | |
| 20 | using namespace llvm; |
| 21 | |
| 22 | /// Goes over OldF calls and replaces them with a call to NewF |
| 23 | static void replaceFunctionCalls(Function &OldF, Function &NewF, |
| 24 | const std::set<int> &ArgIndexesToKeep) { |
| 25 | const auto &Users = OldF.users(); |
| 26 | for (auto I = Users.begin(), E = Users.end(); I != E; ) |
| 27 | if (auto *CI = dyn_cast<CallInst>(*I++)) { |
| 28 | SmallVector<Value *, 8> Args; |
| 29 | for (auto ArgI = CI->arg_begin(), E = CI->arg_end(); ArgI != E; ++ArgI) |
| 30 | if (ArgIndexesToKeep.count(ArgI - CI->arg_begin())) |
| 31 | Args.push_back(*ArgI); |
| 32 | |
| 33 | CallInst *NewCI = CallInst::Create(&NewF, Args); |
| 34 | NewCI->setCallingConv(NewF.getCallingConv()); |
| 35 | if (!CI->use_empty()) |
| 36 | CI->replaceAllUsesWith(NewCI); |
| 37 | ReplaceInstWithInst(CI, NewCI); |
| 38 | } |
| 39 | } |
| 40 | |
| 41 | /// Removes out-of-chunk arguments from functions, and modifies their calls |
| 42 | /// accordingly. It also removes allocations of out-of-chunk arguments. |
David Blaikie | 5adb3d2 | 2019-09-12 01:20:48 +0000 | [diff] [blame] | 43 | static void extractArgumentsFromModule(std::vector<Chunk> ChunksToKeep, |
| 44 | Module *Program) { |
David Blaikie | c4da7ee | 2019-09-18 22:30:25 +0000 | [diff] [blame] | 45 | int I = 0, ArgCount = 0; |
David Blaikie | 5adb3d2 | 2019-09-12 01:20:48 +0000 | [diff] [blame] | 46 | std::set<Argument *> ArgsToKeep; |
| 47 | std::vector<Function *> Funcs; |
| 48 | // Get inside-chunk arguments, as well as their parent function |
| 49 | for (auto &F : *Program) |
| 50 | if (!F.isDeclaration()) { |
| 51 | Funcs.push_back(&F); |
| 52 | for (auto &A : F.args()) |
David Blaikie | c4da7ee | 2019-09-18 22:30:25 +0000 | [diff] [blame] | 53 | if (I < (int)ChunksToKeep.size()) { |
David Blaikie | 5adb3d2 | 2019-09-12 01:20:48 +0000 | [diff] [blame] | 54 | if (ChunksToKeep[I].contains(++ArgCount)) |
| 55 | ArgsToKeep.insert(&A); |
| 56 | if (ChunksToKeep[I].end == ArgCount) |
| 57 | ++I; |
| 58 | } |
| 59 | } |
| 60 | |
| 61 | for (auto *F : Funcs) { |
| 62 | ValueToValueMapTy VMap; |
| 63 | std::vector<Instruction *> InstToDelete; |
| 64 | for (auto &A : F->args()) |
| 65 | if (!ArgsToKeep.count(&A)) { |
| 66 | // By adding undesired arguments to the VMap, CloneFunction will remove |
| 67 | // them from the resulting Function |
| 68 | VMap[&A] = UndefValue::get(A.getType()); |
| 69 | for (auto *U : A.users()) |
| 70 | if (auto *I = dyn_cast<Instruction>(*&U)) |
| 71 | InstToDelete.push_back(I); |
| 72 | } |
| 73 | // Delete any instruction that uses the argument |
| 74 | for (auto *I : InstToDelete) { |
| 75 | I->replaceAllUsesWith(UndefValue::get(I->getType())); |
| 76 | I->eraseFromParent(); |
| 77 | } |
| 78 | |
| 79 | // No arguments to reduce |
| 80 | if (VMap.empty()) |
| 81 | continue; |
| 82 | |
| 83 | std::set<int> ArgIndexesToKeep; |
| 84 | int ArgI = 0; |
| 85 | for (auto &Arg : F->args()) |
| 86 | if (ArgsToKeep.count(&Arg)) |
| 87 | ArgIndexesToKeep.insert(++ArgI); |
| 88 | |
| 89 | auto *ClonedFunc = CloneFunction(F, VMap); |
| 90 | // In order to preserve function order, we move Clone after old Function |
| 91 | ClonedFunc->removeFromParent(); |
| 92 | Program->getFunctionList().insertAfter(F->getIterator(), ClonedFunc); |
| 93 | |
| 94 | replaceFunctionCalls(*F, *ClonedFunc, ArgIndexesToKeep); |
| 95 | // Rename Cloned Function to Old's name |
| 96 | std::string FName = F->getName(); |
| 97 | F->eraseFromParent(); |
| 98 | ClonedFunc->setName(FName); |
| 99 | } |
| 100 | } |
| 101 | |
| 102 | /// Counts the amount of arguments in non-declaration functions and prints their |
| 103 | /// respective name, index, and parent function name |
| 104 | static int countArguments(Module *Program) { |
| 105 | // TODO: Silence index with --quiet flag |
| 106 | outs() << "----------------------------\n"; |
| 107 | outs() << "Param Index Reference:\n"; |
| 108 | int ArgsCount = 0; |
| 109 | for (auto &F : *Program) |
| 110 | if (!F.isDeclaration() && F.arg_size()) { |
| 111 | outs() << " " << F.getName() << "\n"; |
| 112 | for (auto &A : F.args()) |
| 113 | outs() << "\t" << ++ArgsCount << ": " << A.getName() << "\n"; |
| 114 | |
| 115 | outs() << "----------------------------\n"; |
| 116 | } |
| 117 | |
| 118 | return ArgsCount; |
| 119 | } |
| 120 | |
| 121 | void llvm::reduceArgumentsDeltaPass(TestRunner &Test) { |
| 122 | outs() << "*** Reducing Arguments...\n"; |
David Blaikie | c4da7ee | 2019-09-18 22:30:25 +0000 | [diff] [blame] | 123 | int ArgCount = countArguments(Test.getProgram()); |
David Blaikie | 5adb3d2 | 2019-09-12 01:20:48 +0000 | [diff] [blame] | 124 | runDeltaPass(Test, ArgCount, extractArgumentsFromModule); |
| 125 | } |