Andrew Lenharth | cf996d4 | 2008-09-03 21:00:28 +0000 | [diff] [blame] | 1 | //===-- PartialSpecialization.cpp - Specialize for common constants--------===// |
| 2 | // |
| 3 | // The LLVM Compiler Infrastructure |
| 4 | // |
| 5 | // This file is distributed under the University of Illinois Open Source |
| 6 | // License. See LICENSE.TXT for details. |
| 7 | // |
| 8 | //===----------------------------------------------------------------------===// |
| 9 | // |
| 10 | // This pass finds function arguments that are often a common constant and |
| 11 | // specializes a version of the called function for that constant. |
| 12 | // |
Andrew Lenharth | ef78032 | 2008-09-04 14:34:22 +0000 | [diff] [blame] | 13 | // This pass simply does the cloning for functions it specializes. It depends |
| 14 | // on IPSCCP and DAE to clean up the results. |
| 15 | // |
| 16 | // The initial heuristic favors constant arguments that are used in control |
| 17 | // flow. |
Andrew Lenharth | cf996d4 | 2008-09-03 21:00:28 +0000 | [diff] [blame] | 18 | // |
| 19 | //===----------------------------------------------------------------------===// |
| 20 | |
| 21 | #define DEBUG_TYPE "partialspecialization" |
| 22 | #include "llvm/Transforms/IPO.h" |
| 23 | #include "llvm/Constant.h" |
| 24 | #include "llvm/Instructions.h" |
| 25 | #include "llvm/Module.h" |
| 26 | #include "llvm/Pass.h" |
| 27 | #include "llvm/ADT/Statistic.h" |
| 28 | #include "llvm/Transforms/Utils/Cloning.h" |
Andrew Lenharth | eb50479 | 2008-09-04 18:51:26 +0000 | [diff] [blame] | 29 | #include "llvm/Support/CallSite.h" |
Andrew Lenharth | eb50479 | 2008-09-04 18:51:26 +0000 | [diff] [blame] | 30 | #include "llvm/ADT/DenseSet.h" |
Andrew Lenharth | cf996d4 | 2008-09-03 21:00:28 +0000 | [diff] [blame] | 31 | #include <map> |
Andrew Lenharth | cf996d4 | 2008-09-03 21:00:28 +0000 | [diff] [blame] | 32 | using namespace llvm; |
| 33 | |
| 34 | STATISTIC(numSpecialized, "Number of specialized functions created"); |
Kenneth Uildriks | 3a4340d | 2010-06-05 14:50:21 +0000 | [diff] [blame] | 35 | STATISTIC(numReplaced, "Number of callers replaced by specialization"); |
| 36 | |
| 37 | // Maximum number of arguments markable interested |
| 38 | static const int MaxInterests = 6; |
Andrew Lenharth | cf996d4 | 2008-09-03 21:00:28 +0000 | [diff] [blame] | 39 | |
Andrew Lenharth | ef78032 | 2008-09-04 14:34:22 +0000 | [diff] [blame] | 40 | // Call must be used at least occasionally |
Andrew Lenharth | cf996d4 | 2008-09-03 21:00:28 +0000 | [diff] [blame] | 41 | static const int CallsMin = 5; |
Andrew Lenharth | ef78032 | 2008-09-04 14:34:22 +0000 | [diff] [blame] | 42 | |
| 43 | // Must have 10% of calls having the same constant to specialize on |
Andrew Lenharth | cf996d4 | 2008-09-03 21:00:28 +0000 | [diff] [blame] | 44 | static const double ConstValPercent = .1; |
| 45 | |
| 46 | namespace { |
Kenneth Uildriks | 3a4340d | 2010-06-05 14:50:21 +0000 | [diff] [blame] | 47 | typedef SmallVector<int, MaxInterests> InterestingArgVector; |
Nick Lewycky | 6726b6d | 2009-10-25 06:33:48 +0000 | [diff] [blame] | 48 | class PartSpec : public ModulePass { |
Kenneth Uildriks | 3a4340d | 2010-06-05 14:50:21 +0000 | [diff] [blame] | 49 | void scanForInterest(Function&, InterestingArgVector&); |
Andrew Lenharth | cf996d4 | 2008-09-03 21:00:28 +0000 | [diff] [blame] | 50 | int scanDistribution(Function&, int, std::map<Constant*, int>&); |
| 51 | public : |
| 52 | static char ID; // Pass identification, replacement for typeid |
Owen Anderson | 1f74590 | 2010-08-06 00:23:35 +0000 | [diff] [blame] | 53 | PartSpec() : ModulePass(&ID) {} |
Andrew Lenharth | cf996d4 | 2008-09-03 21:00:28 +0000 | [diff] [blame] | 54 | bool runOnModule(Module &M); |
| 55 | }; |
| 56 | } |
| 57 | |
| 58 | char PartSpec::ID = 0; |
Owen Anderson | d13db2c | 2010-07-21 22:09:45 +0000 | [diff] [blame] | 59 | INITIALIZE_PASS(PartSpec, "partialspecialization", |
| 60 | "Partial Specialization", false, false); |
Andrew Lenharth | cf996d4 | 2008-09-03 21:00:28 +0000 | [diff] [blame] | 61 | |
Andrew Lenharth | eb50479 | 2008-09-04 18:51:26 +0000 | [diff] [blame] | 62 | // Specialize F by replacing the arguments (keys) in replacements with the |
| 63 | // constants (values). Replace all calls to F with those constants with |
| 64 | // a call to the specialized function. Returns the specialized function |
| 65 | static Function* |
| 66 | SpecializeFunction(Function* F, |
Devang Patel | e9916a3 | 2010-06-24 00:33:28 +0000 | [diff] [blame] | 67 | ValueMap<const Value*, Value*>& replacements) { |
Andrew Lenharth | eb50479 | 2008-09-04 18:51:26 +0000 | [diff] [blame] | 68 | // arg numbers of deleted arguments |
Kenneth Uildriks | 3a4340d | 2010-06-05 14:50:21 +0000 | [diff] [blame] | 69 | DenseMap<unsigned, const Argument*> deleted; |
Devang Patel | e9916a3 | 2010-06-24 00:33:28 +0000 | [diff] [blame] | 70 | for (ValueMap<const Value*, Value*>::iterator |
Andrew Lenharth | eb50479 | 2008-09-04 18:51:26 +0000 | [diff] [blame] | 71 | repb = replacements.begin(), repe = replacements.end(); |
Kenneth Uildriks | 3a4340d | 2010-06-05 14:50:21 +0000 | [diff] [blame] | 72 | repb != repe; ++repb) { |
| 73 | Argument const *arg = cast<const Argument>(repb->first); |
| 74 | deleted[arg->getArgNo()] = arg; |
| 75 | } |
Andrew Lenharth | eb50479 | 2008-09-04 18:51:26 +0000 | [diff] [blame] | 76 | |
| 77 | Function* NF = CloneFunction(F, replacements); |
| 78 | NF->setLinkage(GlobalValue::InternalLinkage); |
| 79 | F->getParent()->getFunctionList().push_back(NF); |
| 80 | |
| 81 | for (Value::use_iterator ii = F->use_begin(), ee = F->use_end(); |
| 82 | ii != ee; ) { |
Nick Lewycky | d694a78 | 2009-03-08 19:02:17 +0000 | [diff] [blame] | 83 | Value::use_iterator i = ii; |
Andrew Lenharth | eb50479 | 2008-09-04 18:51:26 +0000 | [diff] [blame] | 84 | ++ii; |
Gabor Greif | efdf039 | 2010-07-22 13:04:32 +0000 | [diff] [blame] | 85 | User *U = *i; |
Gabor Greif | 945f1ab | 2010-07-22 13:07:39 +0000 | [diff] [blame] | 86 | CallSite CS(U); |
| 87 | if (CS) { |
Andrew Lenharth | eb50479 | 2008-09-04 18:51:26 +0000 | [diff] [blame] | 88 | if (CS.getCalledFunction() == F) { |
Andrew Lenharth | eb50479 | 2008-09-04 18:51:26 +0000 | [diff] [blame] | 89 | SmallVector<Value*, 6> args; |
Kenneth Uildriks | 3a4340d | 2010-06-05 14:50:21 +0000 | [diff] [blame] | 90 | // Assemble the non-specialized arguments for the updated callsite. |
| 91 | // In the process, make sure that the specialized arguments are |
| 92 | // constant and match the specialization. If that's not the case, |
| 93 | // this callsite needs to call the original or some other |
| 94 | // specialization; don't change it here. |
| 95 | CallSite::arg_iterator as = CS.arg_begin(), ae = CS.arg_end(); |
| 96 | for (CallSite::arg_iterator ai = as; ai != ae; ++ai) { |
| 97 | DenseMap<unsigned, const Argument*>::iterator delit = deleted.find( |
| 98 | std::distance(as, ai)); |
| 99 | if (delit == deleted.end()) |
| 100 | args.push_back(cast<Value>(ai)); |
| 101 | else { |
| 102 | Constant *ci = dyn_cast<Constant>(ai); |
| 103 | if (!(ci && ci == replacements[delit->second])) |
| 104 | goto next_use; |
| 105 | } |
| 106 | } |
Andrew Lenharth | eb50479 | 2008-09-04 18:51:26 +0000 | [diff] [blame] | 107 | Value* NCall; |
Gabor Greif | efdf039 | 2010-07-22 13:04:32 +0000 | [diff] [blame] | 108 | if (CallInst *CI = dyn_cast<CallInst>(U)) { |
Andrew Lenharth | eb50479 | 2008-09-04 18:51:26 +0000 | [diff] [blame] | 109 | NCall = CallInst::Create(NF, args.begin(), args.end(), |
Nick Lewycky | d694a78 | 2009-03-08 19:02:17 +0000 | [diff] [blame] | 110 | CI->getName(), CI); |
| 111 | cast<CallInst>(NCall)->setTailCall(CI->isTailCall()); |
| 112 | cast<CallInst>(NCall)->setCallingConv(CI->getCallingConv()); |
| 113 | } else { |
Gabor Greif | efdf039 | 2010-07-22 13:04:32 +0000 | [diff] [blame] | 114 | InvokeInst *II = cast<InvokeInst>(U); |
Nick Lewycky | d694a78 | 2009-03-08 19:02:17 +0000 | [diff] [blame] | 115 | NCall = InvokeInst::Create(NF, II->getNormalDest(), |
| 116 | II->getUnwindDest(), |
Andrew Lenharth | eb50479 | 2008-09-04 18:51:26 +0000 | [diff] [blame] | 117 | args.begin(), args.end(), |
Nick Lewycky | d694a78 | 2009-03-08 19:02:17 +0000 | [diff] [blame] | 118 | II->getName(), II); |
| 119 | cast<InvokeInst>(NCall)->setCallingConv(II->getCallingConv()); |
| 120 | } |
Andrew Lenharth | eb50479 | 2008-09-04 18:51:26 +0000 | [diff] [blame] | 121 | CS.getInstruction()->replaceAllUsesWith(NCall); |
| 122 | CS.getInstruction()->eraseFromParent(); |
Kenneth Uildriks | 3a4340d | 2010-06-05 14:50:21 +0000 | [diff] [blame] | 123 | ++numReplaced; |
Andrew Lenharth | eb50479 | 2008-09-04 18:51:26 +0000 | [diff] [blame] | 124 | } |
| 125 | } |
Gabor Greif | efdf039 | 2010-07-22 13:04:32 +0000 | [diff] [blame] | 126 | next_use:; |
Andrew Lenharth | eb50479 | 2008-09-04 18:51:26 +0000 | [diff] [blame] | 127 | } |
| 128 | return NF; |
| 129 | } |
| 130 | |
| 131 | |
Andrew Lenharth | cf996d4 | 2008-09-03 21:00:28 +0000 | [diff] [blame] | 132 | bool PartSpec::runOnModule(Module &M) { |
| 133 | bool Changed = false; |
| 134 | for (Module::iterator I = M.begin(); I != M.end(); ++I) { |
| 135 | Function &F = *I; |
Nuno Lopes | 7a85a62 | 2008-10-08 18:45:59 +0000 | [diff] [blame] | 136 | if (F.isDeclaration() || F.mayBeOverridden()) continue; |
Kenneth Uildriks | 3a4340d | 2010-06-05 14:50:21 +0000 | [diff] [blame] | 137 | InterestingArgVector interestingArgs; |
Andrew Lenharth | ef78032 | 2008-09-04 14:34:22 +0000 | [diff] [blame] | 138 | scanForInterest(F, interestingArgs); |
| 139 | |
| 140 | // Find the first interesting Argument that we can specialize on |
| 141 | // If there are multiple interesting Arguments, then those will be found |
| 142 | // when processing the cloned function. |
| 143 | bool breakOuter = false; |
| 144 | for (unsigned int x = 0; !breakOuter && x < interestingArgs.size(); ++x) { |
| 145 | std::map<Constant*, int> distribution; |
| 146 | int total = scanDistribution(F, interestingArgs[x], distribution); |
| 147 | if (total > CallsMin) |
| 148 | for (std::map<Constant*, int>::iterator ii = distribution.begin(), |
| 149 | ee = distribution.end(); ii != ee; ++ii) |
| 150 | if (total > ii->second && ii->first && |
| 151 | ii->second > total * ConstValPercent) { |
Devang Patel | e9916a3 | 2010-06-24 00:33:28 +0000 | [diff] [blame] | 152 | ValueMap<const Value*, Value*> m; |
Andrew Lenharth | eb50479 | 2008-09-04 18:51:26 +0000 | [diff] [blame] | 153 | Function::arg_iterator arg = F.arg_begin(); |
| 154 | for (int y = 0; y < interestingArgs[x]; ++y) |
| 155 | ++arg; |
| 156 | m[&*arg] = ii->first; |
| 157 | SpecializeFunction(&F, m); |
| 158 | ++numSpecialized; |
Andrew Lenharth | ef78032 | 2008-09-04 14:34:22 +0000 | [diff] [blame] | 159 | breakOuter = true; |
| 160 | Changed = true; |
| 161 | } |
Andrew Lenharth | cf996d4 | 2008-09-03 21:00:28 +0000 | [diff] [blame] | 162 | } |
| 163 | } |
| 164 | return Changed; |
| 165 | } |
| 166 | |
| 167 | /// scanForInterest - This function decides which arguments would be worth |
Andrew Lenharth | ef78032 | 2008-09-04 14:34:22 +0000 | [diff] [blame] | 168 | /// specializing on. |
Kenneth Uildriks | 3a4340d | 2010-06-05 14:50:21 +0000 | [diff] [blame] | 169 | void PartSpec::scanForInterest(Function& F, InterestingArgVector& args) { |
Andrew Lenharth | cf996d4 | 2008-09-03 21:00:28 +0000 | [diff] [blame] | 170 | for(Function::arg_iterator ii = F.arg_begin(), ee = F.arg_end(); |
| 171 | ii != ee; ++ii) { |
| 172 | for(Value::use_iterator ui = ii->use_begin(), ue = ii->use_end(); |
| 173 | ui != ue; ++ui) { |
Andrew Lenharth | eb50479 | 2008-09-04 18:51:26 +0000 | [diff] [blame] | 174 | |
| 175 | bool interesting = false; |
Gabor Greif | efdf039 | 2010-07-22 13:04:32 +0000 | [diff] [blame] | 176 | User *U = *ui; |
| 177 | if (isa<CmpInst>(U)) interesting = true; |
| 178 | else if (isa<CallInst>(U)) |
Andrew Lenharth | eb50479 | 2008-09-04 18:51:26 +0000 | [diff] [blame] | 179 | interesting = ui->getOperand(0) == ii; |
Gabor Greif | efdf039 | 2010-07-22 13:04:32 +0000 | [diff] [blame] | 180 | else if (isa<InvokeInst>(U)) |
Andrew Lenharth | eb50479 | 2008-09-04 18:51:26 +0000 | [diff] [blame] | 181 | interesting = ui->getOperand(0) == ii; |
Gabor Greif | efdf039 | 2010-07-22 13:04:32 +0000 | [diff] [blame] | 182 | else if (isa<SwitchInst>(U)) interesting = true; |
| 183 | else if (isa<BranchInst>(U)) interesting = true; |
Andrew Lenharth | eb50479 | 2008-09-04 18:51:26 +0000 | [diff] [blame] | 184 | |
| 185 | if (interesting) { |
Andrew Lenharth | cf996d4 | 2008-09-03 21:00:28 +0000 | [diff] [blame] | 186 | args.push_back(std::distance(F.arg_begin(), ii)); |
| 187 | break; |
| 188 | } |
| 189 | } |
| 190 | } |
| 191 | } |
| 192 | |
Andrew Lenharth | 06a1242 | 2008-11-03 19:29:29 +0000 | [diff] [blame] | 193 | /// scanDistribution - Construct a histogram of constants for arg of F at arg. |
Andrew Lenharth | cf996d4 | 2008-09-03 21:00:28 +0000 | [diff] [blame] | 194 | int PartSpec::scanDistribution(Function& F, int arg, |
| 195 | std::map<Constant*, int>& dist) { |
Andrew Lenharth | ef78032 | 2008-09-04 14:34:22 +0000 | [diff] [blame] | 196 | bool hasIndirect = false; |
Andrew Lenharth | cf996d4 | 2008-09-03 21:00:28 +0000 | [diff] [blame] | 197 | int total = 0; |
Gabor Greif | efdf039 | 2010-07-22 13:04:32 +0000 | [diff] [blame] | 198 | for (Value::use_iterator ii = F.use_begin(), ee = F.use_end(); |
| 199 | ii != ee; ++ii) { |
| 200 | User *U = *ii; |
| 201 | CallSite CS(U); |
| 202 | if (CS && CS.getCalledFunction() == &F) { |
| 203 | ++dist[dyn_cast<Constant>(CS.getArgument(arg))]; |
Andrew Lenharth | cf996d4 | 2008-09-03 21:00:28 +0000 | [diff] [blame] | 204 | ++total; |
| 205 | } else |
Andrew Lenharth | ef78032 | 2008-09-04 14:34:22 +0000 | [diff] [blame] | 206 | hasIndirect = true; |
Gabor Greif | efdf039 | 2010-07-22 13:04:32 +0000 | [diff] [blame] | 207 | } |
Andrew Lenharth | ef78032 | 2008-09-04 14:34:22 +0000 | [diff] [blame] | 208 | |
| 209 | // Preserve the original address taken function even if all other uses |
| 210 | // will be specialized. |
| 211 | if (hasIndirect) ++total; |
Andrew Lenharth | cf996d4 | 2008-09-03 21:00:28 +0000 | [diff] [blame] | 212 | return total; |
| 213 | } |
| 214 | |
| 215 | ModulePass* llvm::createPartialSpecializationPass() { return new PartSpec(); } |