xref: /openbsd-src/gnu/llvm/llvm/tools/llvm-reduce/deltas/ReduceOperandsToArgs.cpp (revision d415bd752c734aee168c4ee86ff32e8cc249eb16)
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 "Delta.h"
11 #include "Utils.h"
12 #include "llvm/ADT/Sequence.h"
13 #include "llvm/IR/Constants.h"
14 #include "llvm/IR/InstIterator.h"
15 #include "llvm/IR/InstrTypes.h"
16 #include "llvm/IR/Instructions.h"
17 #include "llvm/Transforms/Utils/BasicBlockUtils.h"
18 #include "llvm/Transforms/Utils/Cloning.h"
19 
20 using namespace llvm;
21 
canReplaceFunction(Function * F)22 static bool canReplaceFunction(Function *F) {
23   return all_of(F->uses(), [](Use &Op) {
24     if (auto *CI = dyn_cast<CallBase>(Op.getUser()))
25       return &CI->getCalledOperandUse() == &Op;
26     return false;
27   });
28 }
29 
canReduceUse(Use & Op)30 static bool canReduceUse(Use &Op) {
31   Value *Val = Op.get();
32   Type *Ty = Val->getType();
33 
34   // Only replace operands that can be passed-by-value.
35   if (!Ty->isFirstClassType())
36     return false;
37 
38   // Don't pass labels/metadata as arguments.
39   if (Ty->isLabelTy() || Ty->isMetadataTy())
40     return false;
41 
42   // No need to replace values that are already arguments.
43   if (isa<Argument>(Val))
44     return false;
45 
46   // Do not replace literals.
47   if (isa<ConstantData>(Val))
48     return false;
49 
50   // Do not convert direct function calls to indirect calls.
51   if (auto *CI = dyn_cast<CallBase>(Op.getUser()))
52     if (&CI->getCalledOperandUse() == &Op)
53       return false;
54 
55   return true;
56 }
57 
58 /// Goes over OldF calls and replaces them with a call to NewF.
replaceFunctionCalls(Function * OldF,Function * NewF)59 static void replaceFunctionCalls(Function *OldF, Function *NewF) {
60   SmallVector<CallBase *> Callers;
61   for (Use &U : OldF->uses()) {
62     auto *CI = cast<CallBase>(U.getUser());
63     assert(&U == &CI->getCalledOperandUse());
64     assert(CI->getCalledFunction() == OldF);
65     Callers.push_back(CI);
66   }
67 
68   // Call arguments for NewF.
69   SmallVector<Value *> Args(NewF->arg_size(), nullptr);
70 
71   // Fill up the additional parameters with default values.
72   for (auto ArgIdx : llvm::seq<size_t>(OldF->arg_size(), NewF->arg_size())) {
73     Type *NewArgTy = NewF->getArg(ArgIdx)->getType();
74     Args[ArgIdx] = getDefaultValue(NewArgTy);
75   }
76 
77   for (CallBase *CI : Callers) {
78     // Preserve the original function arguments.
79     for (auto Z : zip_first(CI->args(), Args))
80       std::get<1>(Z) = std::get<0>(Z);
81 
82     // Also preserve operand bundles.
83     SmallVector<OperandBundleDef> OperandBundles;
84     CI->getOperandBundlesAsDefs(OperandBundles);
85 
86     // Create the new function call.
87     CallBase *NewCI;
88     if (auto *II = dyn_cast<InvokeInst>(CI)) {
89       NewCI = InvokeInst::Create(NewF, cast<InvokeInst>(II)->getNormalDest(),
90                                  cast<InvokeInst>(II)->getUnwindDest(), Args,
91                                  OperandBundles, CI->getName());
92     } else {
93       assert(isa<CallInst>(CI));
94       NewCI = CallInst::Create(NewF, Args, OperandBundles, CI->getName());
95     }
96     NewCI->setCallingConv(NewF->getCallingConv());
97 
98     // Do the replacement for this use.
99     if (!CI->use_empty())
100       CI->replaceAllUsesWith(NewCI);
101     ReplaceInstWithInst(CI, NewCI);
102   }
103 }
104 
105 /// Add a new function argument to @p F for each use in @OpsToReplace, and
106 /// replace those operand values with the new function argument.
substituteOperandWithArgument(Function * OldF,ArrayRef<Use * > OpsToReplace)107 static void substituteOperandWithArgument(Function *OldF,
108                                           ArrayRef<Use *> OpsToReplace) {
109   if (OpsToReplace.empty())
110     return;
111 
112   SetVector<Value *> UniqueValues;
113   for (Use *Op : OpsToReplace)
114     UniqueValues.insert(Op->get());
115 
116   // Determine the new function's signature.
117   SmallVector<Type *> NewArgTypes;
118   llvm::append_range(NewArgTypes, OldF->getFunctionType()->params());
119   size_t ArgOffset = NewArgTypes.size();
120   for (Value *V : UniqueValues)
121     NewArgTypes.push_back(V->getType());
122   FunctionType *FTy =
123       FunctionType::get(OldF->getFunctionType()->getReturnType(), NewArgTypes,
124                         OldF->getFunctionType()->isVarArg());
125 
126   // Create the new function...
127   Function *NewF =
128       Function::Create(FTy, OldF->getLinkage(), OldF->getAddressSpace(),
129                        OldF->getName(), OldF->getParent());
130 
131   // In order to preserve function order, we move NewF behind OldF
132   NewF->removeFromParent();
133   OldF->getParent()->getFunctionList().insertAfter(OldF->getIterator(), NewF);
134 
135   // Preserve the parameters of OldF.
136   ValueToValueMapTy VMap;
137   for (auto Z : zip_first(OldF->args(), NewF->args())) {
138     Argument &OldArg = std::get<0>(Z);
139     Argument &NewArg = std::get<1>(Z);
140 
141     NewArg.setName(OldArg.getName()); // Copy the name over...
142     VMap[&OldArg] = &NewArg;          // Add mapping to VMap
143   }
144 
145   // Adjust the new parameters.
146   ValueToValueMapTy OldValMap;
147   for (auto Z : zip_first(UniqueValues, drop_begin(NewF->args(), ArgOffset))) {
148     Value *OldVal = std::get<0>(Z);
149     Argument &NewArg = std::get<1>(Z);
150 
151     NewArg.setName(OldVal->getName());
152     OldValMap[OldVal] = &NewArg;
153   }
154 
155   SmallVector<ReturnInst *, 8> Returns; // Ignore returns cloned.
156   CloneFunctionInto(NewF, OldF, VMap, CloneFunctionChangeType::LocalChangesOnly,
157                     Returns, "", /*CodeInfo=*/nullptr);
158 
159   // Replace the actual operands.
160   for (Use *Op : OpsToReplace) {
161     Value *NewArg = OldValMap.lookup(Op->get());
162     auto *NewUser = cast<Instruction>(VMap.lookup(Op->getUser()));
163     NewUser->setOperand(Op->getOperandNo(), NewArg);
164   }
165 
166   // Replace all OldF uses with NewF.
167   replaceFunctionCalls(OldF, NewF);
168 
169   // Rename NewF to OldF's name.
170   std::string FName = OldF->getName().str();
171   OldF->replaceAllUsesWith(ConstantExpr::getBitCast(NewF, OldF->getType()));
172   OldF->eraseFromParent();
173   NewF->setName(FName);
174 }
175 
reduceOperandsToArgs(Oracle & O,ReducerWorkItem & WorkItem)176 static void reduceOperandsToArgs(Oracle &O, ReducerWorkItem &WorkItem) {
177   Module &Program = WorkItem.getModule();
178 
179   SmallVector<Use *> OperandsToReduce;
180   for (Function &F : make_early_inc_range(Program.functions())) {
181     if (!canReplaceFunction(&F))
182       continue;
183     OperandsToReduce.clear();
184     for (Instruction &I : instructions(&F)) {
185       for (Use &Op : I.operands()) {
186         if (!canReduceUse(Op))
187           continue;
188         if (O.shouldKeep())
189           continue;
190 
191         OperandsToReduce.push_back(&Op);
192       }
193     }
194 
195     substituteOperandWithArgument(&F, OperandsToReduce);
196   }
197 }
198 
reduceOperandsToArgsDeltaPass(TestRunner & Test)199 void llvm::reduceOperandsToArgsDeltaPass(TestRunner &Test) {
200   runDeltaPass(Test, reduceOperandsToArgs,
201                "Converting operands to function arguments");
202 }
203