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 declared and defined functions. |
11 | // |
12 | //===----------------------------------------------------------------------===// |
13 | |
14 | #include "ReduceArguments.h" |
15 | #include "Delta.h" |
16 | #include "Utils.h" |
17 | #include "llvm/ADT/SmallVector.h" |
18 | #include "llvm/IR/Constants.h" |
19 | #include "llvm/IR/Instructions.h" |
20 | #include "llvm/IR/Intrinsics.h" |
21 | #include <set> |
22 | #include <vector> |
23 | |
24 | using namespace llvm; |
25 | |
26 | /// Goes over OldF calls and replaces them with a call to NewF |
27 | static void replaceFunctionCalls(Function &OldF, Function &NewF, |
28 | const std::set<int> &ArgIndexesToKeep) { |
29 | const auto &Users = OldF.users(); |
30 | for (auto I = Users.begin(), E = Users.end(); I != E; ) |
31 | if (auto *CI = dyn_cast<CallInst>(Val: *I++)) { |
32 | // Skip uses in call instructions where OldF isn't the called function |
33 | // (e.g. if OldF is an argument of the call). |
34 | if (CI->getCalledFunction() != &OldF) |
35 | continue; |
36 | SmallVector<Value *, 8> Args; |
37 | for (auto ArgI = CI->arg_begin(), E = CI->arg_end(); ArgI != E; ++ArgI) |
38 | if (ArgIndexesToKeep.count(x: ArgI - CI->arg_begin())) |
39 | Args.push_back(Elt: *ArgI); |
40 | |
41 | CallInst *NewCI = CallInst::Create(Func: &NewF, Args); |
42 | NewCI->setCallingConv(NewF.getCallingConv()); |
43 | if (!CI->use_empty()) |
44 | CI->replaceAllUsesWith(V: NewCI); |
45 | ReplaceInstWithInst(From: CI, To: NewCI); |
46 | } |
47 | } |
48 | |
49 | /// Returns whether or not this function should be considered a candidate for |
50 | /// argument removal. Currently, functions with no arguments and intrinsics are |
51 | /// not considered. Intrinsics aren't considered because their signatures are |
52 | /// fixed. |
53 | static bool shouldRemoveArguments(const Function &F) { |
54 | return !F.arg_empty() && !F.isIntrinsic(); |
55 | } |
56 | |
57 | /// Removes out-of-chunk arguments from functions, and modifies their calls |
58 | /// accordingly. It also removes allocations of out-of-chunk arguments. |
59 | static void (Oracle &O, ReducerWorkItem &WorkItem) { |
60 | Module &Program = WorkItem.getModule(); |
61 | std::vector<Argument *> InitArgsToKeep; |
62 | std::vector<Function *> Funcs; |
63 | // Get inside-chunk arguments, as well as their parent function |
64 | for (auto &F : Program) |
65 | if (shouldRemoveArguments(F)) { |
66 | Funcs.push_back(x: &F); |
67 | for (auto &A : F.args()) |
68 | if (O.shouldKeep()) |
69 | InitArgsToKeep.push_back(x: &A); |
70 | } |
71 | |
72 | // We create a vector first, then convert it to a set, so that we don't have |
73 | // to pay the cost of rebalancing the set frequently if the order we insert |
74 | // the elements doesn't match the order they should appear inside the set. |
75 | std::set<Argument *> ArgsToKeep(InitArgsToKeep.begin(), InitArgsToKeep.end()); |
76 | |
77 | for (auto *F : Funcs) { |
78 | ValueToValueMapTy VMap; |
79 | std::vector<WeakVH> InstToDelete; |
80 | for (auto &A : F->args()) |
81 | if (!ArgsToKeep.count(x: &A)) { |
82 | // By adding undesired arguments to the VMap, CloneFunction will remove |
83 | // them from the resulting Function |
84 | VMap[&A] = getDefaultValue(T: A.getType()); |
85 | for (auto *U : A.users()) |
86 | if (auto *I = dyn_cast<Instruction>(Val: *&U)) |
87 | InstToDelete.push_back(x: I); |
88 | } |
89 | // Delete any (unique) instruction that uses the argument |
90 | for (Value *V : InstToDelete) { |
91 | if (!V) |
92 | continue; |
93 | auto *I = cast<Instruction>(Val: V); |
94 | I->replaceAllUsesWith(V: getDefaultValue(T: I->getType())); |
95 | if (!I->isTerminator()) |
96 | I->eraseFromParent(); |
97 | } |
98 | |
99 | // No arguments to reduce |
100 | if (VMap.empty()) |
101 | continue; |
102 | |
103 | std::set<int> ArgIndexesToKeep; |
104 | for (const auto &[Index, Arg] : enumerate(First: F->args())) |
105 | if (ArgsToKeep.count(x: &Arg)) |
106 | ArgIndexesToKeep.insert(x: Index); |
107 | |
108 | auto *ClonedFunc = CloneFunction(F, VMap); |
109 | // In order to preserve function order, we move Clone after old Function |
110 | ClonedFunc->removeFromParent(); |
111 | Program.getFunctionList().insertAfter(where: F->getIterator(), New: ClonedFunc); |
112 | |
113 | replaceFunctionCalls(OldF&: *F, NewF&: *ClonedFunc, ArgIndexesToKeep); |
114 | // Rename Cloned Function to Old's name |
115 | std::string FName = std::string(F->getName()); |
116 | F->replaceAllUsesWith(V: ClonedFunc); |
117 | F->eraseFromParent(); |
118 | ClonedFunc->setName(FName); |
119 | } |
120 | } |
121 | |
122 | void llvm::reduceArgumentsDeltaPass(TestRunner &Test) { |
123 | runDeltaPass(Test, ExtractChunksFromModule: extractArgumentsFromModule, Message: "Reducing Arguments" ); |
124 | } |
125 | |