1 //===----------------------------------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 #include "ReduceOperandsToArgs.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"
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
;
30 static bool canReduceUse(Use
&Op
) {
31 Value
*Val
= Op
.get();
32 Type
*Ty
= Val
->getType();
34 // Only replace operands that can be passed-by-value.
35 if (!Ty
->isFirstClassType())
38 // Don't pass labels/metadata as arguments.
39 if (Ty
->isLabelTy() || Ty
->isMetadataTy())
42 // No need to replace values that are already arguments.
43 if (isa
<Argument
>(Val
))
46 // Do not replace literals.
47 if (isa
<ConstantData
>(Val
))
50 // Do not convert direct function calls to indirect calls.
51 if (auto *CI
= dyn_cast
<CallBase
>(Op
.getUser()))
52 if (&CI
->getCalledOperandUse() == &Op
)
58 /// Goes over OldF calls and replaces them with a call to 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
);
68 // Call arguments for NewF.
69 SmallVector
<Value
*> Args(NewF
->arg_size(), nullptr);
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
);
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
);
82 // Also preserve operand bundles.
83 SmallVector
<OperandBundleDef
> OperandBundles
;
84 CI
->getOperandBundlesAsDefs(OperandBundles
);
86 // Create the new function call.
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());
93 assert(isa
<CallInst
>(CI
));
94 NewCI
= CallInst::Create(NewF
, Args
, OperandBundles
, CI
->getName());
96 NewCI
->setCallingConv(NewF
->getCallingConv());
98 // Do the replacement for this use.
100 CI
->replaceAllUsesWith(NewCI
);
101 ReplaceInstWithInst(CI
, NewCI
);
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.
107 static void substituteOperandWithArgument(Function
*OldF
,
108 ArrayRef
<Use
*> OpsToReplace
) {
109 if (OpsToReplace
.empty())
112 SetVector
<Value
*> UniqueValues
;
113 for (Use
*Op
: OpsToReplace
)
114 UniqueValues
.insert(Op
->get());
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());
123 FunctionType::get(OldF
->getFunctionType()->getReturnType(), NewArgTypes
,
124 OldF
->getFunctionType()->isVarArg());
126 // Create the new function...
128 Function::Create(FTy
, OldF
->getLinkage(), OldF
->getAddressSpace(),
129 OldF
->getName(), OldF
->getParent());
131 // In order to preserve function order, we move NewF behind OldF
132 NewF
->removeFromParent();
133 OldF
->getParent()->getFunctionList().insertAfter(OldF
->getIterator(), NewF
);
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
);
141 NewArg
.setName(OldArg
.getName()); // Copy the name over...
142 VMap
[&OldArg
] = &NewArg
; // Add mapping to VMap
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
);
151 NewArg
.setName(OldVal
->getName());
152 OldValMap
[OldVal
] = &NewArg
;
155 SmallVector
<ReturnInst
*, 8> Returns
; // Ignore returns cloned.
156 CloneFunctionInto(NewF
, OldF
, VMap
, CloneFunctionChangeType::LocalChangesOnly
,
157 Returns
, "", /*CodeInfo=*/nullptr);
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()));
164 if (PHINode
*NewPhi
= dyn_cast
<PHINode
>(NewUser
)) {
165 PHINode
*OldPhi
= cast
<PHINode
>(Op
->getUser());
166 BasicBlock
*OldBB
= OldPhi
->getIncomingBlock(*Op
);
167 NewPhi
->setIncomingValueForBlock(cast
<BasicBlock
>(VMap
.lookup(OldBB
)),
170 NewUser
->setOperand(Op
->getOperandNo(), NewArg
);
173 // Replace all OldF uses with NewF.
174 replaceFunctionCalls(OldF
, NewF
);
176 // Rename NewF to OldF's name.
177 std::string FName
= OldF
->getName().str();
178 OldF
->replaceAllUsesWith(ConstantExpr::getBitCast(NewF
, OldF
->getType()));
179 OldF
->eraseFromParent();
180 NewF
->setName(FName
);
183 static void reduceOperandsToArgs(Oracle
&O
, ReducerWorkItem
&WorkItem
) {
184 Module
&Program
= WorkItem
.getModule();
186 SmallVector
<Use
*> OperandsToReduce
;
187 for (Function
&F
: make_early_inc_range(Program
.functions())) {
188 if (!canReplaceFunction(&F
))
190 OperandsToReduce
.clear();
191 for (Instruction
&I
: instructions(&F
)) {
192 for (Use
&Op
: I
.operands()) {
193 if (!canReduceUse(Op
))
198 OperandsToReduce
.push_back(&Op
);
202 substituteOperandWithArgument(&F
, OperandsToReduce
);
206 void llvm::reduceOperandsToArgsDeltaPass(TestRunner
&Test
) {
207 runDeltaPass(Test
, reduceOperandsToArgs
,
208 "Converting operands to function arguments");