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 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 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. 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. 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 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)), 168 NewArg); 169 } else 170 NewUser->setOperand(Op->getOperandNo(), NewArg); 171 } 172 173 // Replace all OldF uses with NewF. 174 replaceFunctionCalls(OldF, NewF); 175 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); 181 } 182 183 static void reduceOperandsToArgs(Oracle &O, ReducerWorkItem &WorkItem) { 184 Module &Program = WorkItem.getModule(); 185 186 SmallVector<Use *> OperandsToReduce; 187 for (Function &F : make_early_inc_range(Program.functions())) { 188 if (!canReplaceFunction(&F)) 189 continue; 190 OperandsToReduce.clear(); 191 for (Instruction &I : instructions(&F)) { 192 for (Use &Op : I.operands()) { 193 if (!canReduceUse(Op)) 194 continue; 195 if (O.shouldKeep()) 196 continue; 197 198 OperandsToReduce.push_back(&Op); 199 } 200 } 201 202 substituteOperandWithArgument(&F, OperandsToReduce); 203 } 204 } 205 206 void llvm::reduceOperandsToArgsDeltaPass(TestRunner &Test) { 207 runDeltaPass(Test, reduceOperandsToArgs, 208 "Converting operands to function arguments"); 209 } 210