1 | //===----------------------------------------------------------------------===// |
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 | #include "ReduceOperandsToArgs.h" |
10 | #include "Utils.h" |
11 | #include "llvm/ADT/Sequence.h" |
12 | #include "llvm/IR/Constants.h" |
13 | #include "llvm/IR/InstIterator.h" |
14 | #include "llvm/IR/InstrTypes.h" |
15 | #include "llvm/IR/Instructions.h" |
16 | #include "llvm/IR/Operator.h" |
17 | #include "llvm/Transforms/Utils/BasicBlockUtils.h" |
18 | #include "llvm/Transforms/Utils/Cloning.h" |
19 | |
20 | using namespace llvm; |
21 | |
22 | static bool canReplaceFunction(const Function &F) { |
23 | // TODO: Add controls to avoid ABI breaks (e.g. don't break main) |
24 | return true; |
25 | } |
26 | |
27 | static bool canReduceUse(Use &Op) { |
28 | Value *Val = Op.get(); |
29 | Type *Ty = Val->getType(); |
30 | |
31 | // Only replace operands that can be passed-by-value. |
32 | if (!Ty->isFirstClassType()) |
33 | return false; |
34 | |
35 | // Don't pass labels/metadata as arguments. |
36 | if (Ty->isLabelTy() || Ty->isMetadataTy() || Ty->isTokenTy()) |
37 | return false; |
38 | |
39 | // No need to replace values that are already arguments. |
40 | if (isa<Argument>(Val)) |
41 | return false; |
42 | |
43 | // Do not replace literals. |
44 | if (isa<ConstantData>(Val)) |
45 | return false; |
46 | |
47 | // Do not convert direct function calls to indirect calls. |
48 | if (auto *CI = dyn_cast<CallBase>(Val: Op.getUser())) |
49 | if (&CI->getCalledOperandUse() == &Op) |
50 | return false; |
51 | |
52 | return true; |
53 | } |
54 | |
55 | /// Goes over OldF calls and replaces them with a call to NewF. |
56 | static void replaceFunctionCalls(Function *OldF, Function *NewF) { |
57 | SmallVector<CallBase *> Callers; |
58 | for (Use &U : OldF->uses()) { |
59 | auto *CI = dyn_cast<CallBase>(Val: U.getUser()); |
60 | if (!CI || !CI->isCallee(U: &U)) // RAUW can handle these fine. |
61 | continue; |
62 | |
63 | Function *CalledF = CI->getCalledFunction(); |
64 | if (CalledF == OldF) { |
65 | Callers.push_back(Elt: CI); |
66 | } else { |
67 | // The call may have undefined behavior by calling a function with a |
68 | // mismatched signature. In this case, do not bother adjusting the |
69 | // callsites to pad with any new arguments. |
70 | |
71 | // TODO: Better QoI to try to add new arguments to the end, and ignore |
72 | // existing mismatches. |
73 | assert(!CalledF && CI->getCalledOperand()->stripPointerCasts() == OldF && |
74 | "only expected call and function signature mismatch" ); |
75 | } |
76 | } |
77 | |
78 | // Call arguments for NewF. |
79 | SmallVector<Value *> Args(NewF->arg_size(), nullptr); |
80 | |
81 | // Fill up the additional parameters with default values. |
82 | for (auto ArgIdx : llvm::seq<size_t>(Begin: OldF->arg_size(), End: NewF->arg_size())) { |
83 | Type *NewArgTy = NewF->getArg(i: ArgIdx)->getType(); |
84 | Args[ArgIdx] = getDefaultValue(T: NewArgTy); |
85 | } |
86 | |
87 | for (CallBase *CI : Callers) { |
88 | // Preserve the original function arguments. |
89 | for (auto Z : zip_first(t: CI->args(), u&: Args)) |
90 | std::get<1>(t&: Z) = std::get<0>(t&: Z); |
91 | |
92 | // Also preserve operand bundles. |
93 | SmallVector<OperandBundleDef> OperandBundles; |
94 | CI->getOperandBundlesAsDefs(Defs&: OperandBundles); |
95 | |
96 | // Create the new function call. |
97 | CallBase *NewCI; |
98 | if (auto *II = dyn_cast<InvokeInst>(Val: CI)) { |
99 | NewCI = InvokeInst::Create(Func: NewF, IfNormal: II->getNormalDest(), IfException: II->getUnwindDest(), |
100 | Args, Bundles: OperandBundles, NameStr: CI->getName()); |
101 | } else { |
102 | assert(isa<CallInst>(CI)); |
103 | NewCI = CallInst::Create(Func: NewF, Args, Bundles: OperandBundles, NameStr: CI->getName()); |
104 | } |
105 | NewCI->setCallingConv(NewF->getCallingConv()); |
106 | NewCI->setAttributes(CI->getAttributes()); |
107 | |
108 | if (isa<FPMathOperator>(Val: NewCI)) |
109 | NewCI->setFastMathFlags(CI->getFastMathFlags()); |
110 | |
111 | NewCI->copyMetadata(SrcInst: *CI); |
112 | |
113 | // Do the replacement for this use. |
114 | if (!CI->use_empty()) |
115 | CI->replaceAllUsesWith(V: NewCI); |
116 | ReplaceInstWithInst(From: CI, To: NewCI); |
117 | } |
118 | } |
119 | |
120 | /// Add a new function argument to @p F for each use in @OpsToReplace, and |
121 | /// replace those operand values with the new function argument. |
122 | static void substituteOperandWithArgument(Function *OldF, |
123 | ArrayRef<Use *> OpsToReplace) { |
124 | if (OpsToReplace.empty()) |
125 | return; |
126 | |
127 | SetVector<Value *> UniqueValues; |
128 | for (Use *Op : OpsToReplace) |
129 | UniqueValues.insert(X: Op->get()); |
130 | |
131 | // Determine the new function's signature. |
132 | SmallVector<Type *> NewArgTypes(OldF->getFunctionType()->params()); |
133 | size_t ArgOffset = NewArgTypes.size(); |
134 | for (Value *V : UniqueValues) |
135 | NewArgTypes.push_back(Elt: V->getType()); |
136 | FunctionType *FTy = |
137 | FunctionType::get(Result: OldF->getFunctionType()->getReturnType(), Params: NewArgTypes, |
138 | isVarArg: OldF->getFunctionType()->isVarArg()); |
139 | |
140 | // Create the new function... |
141 | Function *NewF = Function::Create( |
142 | Ty: FTy, Linkage: OldF->getLinkage(), AddrSpace: OldF->getAddressSpace(), N: "" , M: OldF->getParent()); |
143 | |
144 | // In order to preserve function order, we move NewF behind OldF |
145 | NewF->removeFromParent(); |
146 | OldF->getParent()->getFunctionList().insertAfter(where: OldF->getIterator(), New: NewF); |
147 | |
148 | // Preserve the parameters of OldF. |
149 | ValueToValueMapTy VMap; |
150 | for (auto Z : zip_first(t: OldF->args(), u: NewF->args())) { |
151 | Argument &OldArg = std::get<0>(t&: Z); |
152 | Argument &NewArg = std::get<1>(t&: Z); |
153 | |
154 | NewArg.takeName(V: &OldArg); // Copy the name over... |
155 | VMap[&OldArg] = &NewArg; // Add mapping to VMap |
156 | } |
157 | |
158 | LLVMContext &Ctx = OldF->getContext(); |
159 | |
160 | // Adjust the new parameters. |
161 | ValueToValueMapTy OldValMap; |
162 | for (auto Z : zip_first(t&: UniqueValues, u: drop_begin(RangeOrContainer: NewF->args(), N: ArgOffset))) { |
163 | Value *OldVal = std::get<0>(t&: Z); |
164 | Argument &NewArg = std::get<1>(t&: Z); |
165 | |
166 | NewArg.setName(OldVal->getName()); |
167 | OldValMap[OldVal] = &NewArg; |
168 | } |
169 | |
170 | SmallVector<ReturnInst *, 8> Returns; // Ignore returns cloned. |
171 | CloneFunctionInto(NewFunc: NewF, OldFunc: OldF, VMap, Changes: CloneFunctionChangeType::LocalChangesOnly, |
172 | Returns, NameSuffix: "" , /*CodeInfo=*/nullptr); |
173 | |
174 | // Replace the actual operands. |
175 | for (Use *Op : OpsToReplace) { |
176 | Argument *NewArg = cast<Argument>(Val: OldValMap.lookup(Val: Op->get())); |
177 | auto *NewUser = cast<Instruction>(Val: VMap.lookup(Val: Op->getUser())); |
178 | |
179 | // Try to preserve any information contained metadata annotations as the |
180 | // equivalent parameter attributes if possible. |
181 | if (auto *MDSrcInst = dyn_cast<Instruction>(Val: Op)) { |
182 | AttrBuilder AB(Ctx); |
183 | NewArg->addAttrs(B&: AB.addFromEquivalentMetadata(I: *MDSrcInst)); |
184 | } |
185 | |
186 | if (PHINode *NewPhi = dyn_cast<PHINode>(Val: NewUser)) { |
187 | PHINode *OldPhi = cast<PHINode>(Val: Op->getUser()); |
188 | BasicBlock *OldBB = OldPhi->getIncomingBlock(U: *Op); |
189 | NewPhi->setIncomingValueForBlock(BB: cast<BasicBlock>(Val: VMap.lookup(Val: OldBB)), |
190 | V: NewArg); |
191 | } else |
192 | NewUser->setOperand(i: Op->getOperandNo(), Val: NewArg); |
193 | } |
194 | |
195 | // Replace all OldF uses with NewF. |
196 | replaceFunctionCalls(OldF, NewF); |
197 | |
198 | NewF->takeName(V: OldF); |
199 | OldF->replaceAllUsesWith(V: NewF); |
200 | OldF->eraseFromParent(); |
201 | } |
202 | |
203 | void llvm::reduceOperandsToArgsDeltaPass(Oracle &O, ReducerWorkItem &WorkItem) { |
204 | Module &Program = WorkItem.getModule(); |
205 | |
206 | SmallVector<Use *> OperandsToReduce; |
207 | for (Function &F : make_early_inc_range(Range: Program.functions())) { |
208 | if (!canReplaceFunction(F)) |
209 | continue; |
210 | OperandsToReduce.clear(); |
211 | for (Instruction &I : instructions(F: &F)) { |
212 | for (Use &Op : I.operands()) { |
213 | if (!canReduceUse(Op)) |
214 | continue; |
215 | if (O.shouldKeep()) |
216 | continue; |
217 | |
218 | OperandsToReduce.push_back(Elt: &Op); |
219 | } |
220 | } |
221 | |
222 | substituteOperandWithArgument(OldF: &F, OpsToReplace: OperandsToReduce); |
223 | } |
224 | } |
225 | |