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" |
Kenneth Uildriks | 74fa732 | 2010-10-09 22:06:36 +0000 | [diff] [blame^] | 28 | #include "llvm/Analysis/InlineCost.h" |
Andrew Lenharth | cf996d4 | 2008-09-03 21:00:28 +0000 | [diff] [blame] | 29 | #include "llvm/Transforms/Utils/Cloning.h" |
Andrew Lenharth | eb50479 | 2008-09-04 18:51:26 +0000 | [diff] [blame] | 30 | #include "llvm/Support/CallSite.h" |
Andrew Lenharth | eb50479 | 2008-09-04 18:51:26 +0000 | [diff] [blame] | 31 | #include "llvm/ADT/DenseSet.h" |
Andrew Lenharth | cf996d4 | 2008-09-03 21:00:28 +0000 | [diff] [blame] | 32 | #include <map> |
Andrew Lenharth | cf996d4 | 2008-09-03 21:00:28 +0000 | [diff] [blame] | 33 | using namespace llvm; |
| 34 | |
| 35 | STATISTIC(numSpecialized, "Number of specialized functions created"); |
Kenneth Uildriks | 3a4340d | 2010-06-05 14:50:21 +0000 | [diff] [blame] | 36 | STATISTIC(numReplaced, "Number of callers replaced by specialization"); |
| 37 | |
| 38 | // Maximum number of arguments markable interested |
| 39 | static const int MaxInterests = 6; |
Andrew Lenharth | cf996d4 | 2008-09-03 21:00:28 +0000 | [diff] [blame] | 40 | |
Andrew Lenharth | cf996d4 | 2008-09-03 21:00:28 +0000 | [diff] [blame] | 41 | namespace { |
Kenneth Uildriks | 3a4340d | 2010-06-05 14:50:21 +0000 | [diff] [blame] | 42 | typedef SmallVector<int, MaxInterests> InterestingArgVector; |
Nick Lewycky | 6726b6d | 2009-10-25 06:33:48 +0000 | [diff] [blame] | 43 | class PartSpec : public ModulePass { |
Kenneth Uildriks | 3a4340d | 2010-06-05 14:50:21 +0000 | [diff] [blame] | 44 | void scanForInterest(Function&, InterestingArgVector&); |
Andrew Lenharth | cf996d4 | 2008-09-03 21:00:28 +0000 | [diff] [blame] | 45 | int scanDistribution(Function&, int, std::map<Constant*, int>&); |
Kenneth Uildriks | 74fa732 | 2010-10-09 22:06:36 +0000 | [diff] [blame^] | 46 | InlineCostAnalyzer CA; |
Andrew Lenharth | cf996d4 | 2008-09-03 21:00:28 +0000 | [diff] [blame] | 47 | public : |
| 48 | static char ID; // Pass identification, replacement for typeid |
Owen Anderson | 90c579d | 2010-08-06 18:33:48 +0000 | [diff] [blame] | 49 | PartSpec() : ModulePass(ID) {} |
Andrew Lenharth | cf996d4 | 2008-09-03 21:00:28 +0000 | [diff] [blame] | 50 | bool runOnModule(Module &M); |
| 51 | }; |
| 52 | } |
| 53 | |
| 54 | char PartSpec::ID = 0; |
Owen Anderson | d13db2c | 2010-07-21 22:09:45 +0000 | [diff] [blame] | 55 | INITIALIZE_PASS(PartSpec, "partialspecialization", |
Owen Anderson | ce665bd | 2010-10-07 22:25:06 +0000 | [diff] [blame] | 56 | "Partial Specialization", false, false) |
Andrew Lenharth | cf996d4 | 2008-09-03 21:00:28 +0000 | [diff] [blame] | 57 | |
Andrew Lenharth | eb50479 | 2008-09-04 18:51:26 +0000 | [diff] [blame] | 58 | // Specialize F by replacing the arguments (keys) in replacements with the |
| 59 | // constants (values). Replace all calls to F with those constants with |
| 60 | // a call to the specialized function. Returns the specialized function |
| 61 | static Function* |
| 62 | SpecializeFunction(Function* F, |
Devang Patel | e9916a3 | 2010-06-24 00:33:28 +0000 | [diff] [blame] | 63 | ValueMap<const Value*, Value*>& replacements) { |
Andrew Lenharth | eb50479 | 2008-09-04 18:51:26 +0000 | [diff] [blame] | 64 | // arg numbers of deleted arguments |
Kenneth Uildriks | 3a4340d | 2010-06-05 14:50:21 +0000 | [diff] [blame] | 65 | DenseMap<unsigned, const Argument*> deleted; |
Devang Patel | e9916a3 | 2010-06-24 00:33:28 +0000 | [diff] [blame] | 66 | for (ValueMap<const Value*, Value*>::iterator |
Andrew Lenharth | eb50479 | 2008-09-04 18:51:26 +0000 | [diff] [blame] | 67 | repb = replacements.begin(), repe = replacements.end(); |
Kenneth Uildriks | 3a4340d | 2010-06-05 14:50:21 +0000 | [diff] [blame] | 68 | repb != repe; ++repb) { |
| 69 | Argument const *arg = cast<const Argument>(repb->first); |
| 70 | deleted[arg->getArgNo()] = arg; |
| 71 | } |
Andrew Lenharth | eb50479 | 2008-09-04 18:51:26 +0000 | [diff] [blame] | 72 | |
Dan Gohman | 6cb8c23 | 2010-08-26 15:41:53 +0000 | [diff] [blame] | 73 | Function* NF = CloneFunction(F, replacements, |
| 74 | /*ModuleLevelChanges=*/false); |
Andrew Lenharth | eb50479 | 2008-09-04 18:51:26 +0000 | [diff] [blame] | 75 | NF->setLinkage(GlobalValue::InternalLinkage); |
| 76 | F->getParent()->getFunctionList().push_back(NF); |
| 77 | |
Kenneth Uildriks | 74fa732 | 2010-10-09 22:06:36 +0000 | [diff] [blame^] | 78 | // FIXME: Specialized versions getting the same constants should also get |
| 79 | // the same name. That way, specializations for public functions can be |
| 80 | // marked linkonce_odr and reused across modules. |
| 81 | |
Andrew Lenharth | eb50479 | 2008-09-04 18:51:26 +0000 | [diff] [blame] | 82 | for (Value::use_iterator ii = F->use_begin(), ee = F->use_end(); |
| 83 | ii != ee; ) { |
Nick Lewycky | d694a78 | 2009-03-08 19:02:17 +0000 | [diff] [blame] | 84 | Value::use_iterator i = ii; |
Andrew Lenharth | eb50479 | 2008-09-04 18:51:26 +0000 | [diff] [blame] | 85 | ++ii; |
Gabor Greif | efdf039 | 2010-07-22 13:04:32 +0000 | [diff] [blame] | 86 | User *U = *i; |
Gabor Greif | 945f1ab | 2010-07-22 13:07:39 +0000 | [diff] [blame] | 87 | CallSite CS(U); |
| 88 | if (CS) { |
Andrew Lenharth | eb50479 | 2008-09-04 18:51:26 +0000 | [diff] [blame] | 89 | if (CS.getCalledFunction() == F) { |
Andrew Lenharth | eb50479 | 2008-09-04 18:51:26 +0000 | [diff] [blame] | 90 | SmallVector<Value*, 6> args; |
Kenneth Uildriks | 3a4340d | 2010-06-05 14:50:21 +0000 | [diff] [blame] | 91 | // Assemble the non-specialized arguments for the updated callsite. |
| 92 | // In the process, make sure that the specialized arguments are |
| 93 | // constant and match the specialization. If that's not the case, |
| 94 | // this callsite needs to call the original or some other |
| 95 | // specialization; don't change it here. |
| 96 | CallSite::arg_iterator as = CS.arg_begin(), ae = CS.arg_end(); |
| 97 | for (CallSite::arg_iterator ai = as; ai != ae; ++ai) { |
| 98 | DenseMap<unsigned, const Argument*>::iterator delit = deleted.find( |
| 99 | std::distance(as, ai)); |
| 100 | if (delit == deleted.end()) |
| 101 | args.push_back(cast<Value>(ai)); |
| 102 | else { |
| 103 | Constant *ci = dyn_cast<Constant>(ai); |
| 104 | if (!(ci && ci == replacements[delit->second])) |
| 105 | goto next_use; |
| 106 | } |
| 107 | } |
Andrew Lenharth | eb50479 | 2008-09-04 18:51:26 +0000 | [diff] [blame] | 108 | Value* NCall; |
Gabor Greif | efdf039 | 2010-07-22 13:04:32 +0000 | [diff] [blame] | 109 | if (CallInst *CI = dyn_cast<CallInst>(U)) { |
Andrew Lenharth | eb50479 | 2008-09-04 18:51:26 +0000 | [diff] [blame] | 110 | NCall = CallInst::Create(NF, args.begin(), args.end(), |
Nick Lewycky | d694a78 | 2009-03-08 19:02:17 +0000 | [diff] [blame] | 111 | CI->getName(), CI); |
| 112 | cast<CallInst>(NCall)->setTailCall(CI->isTailCall()); |
| 113 | cast<CallInst>(NCall)->setCallingConv(CI->getCallingConv()); |
| 114 | } else { |
Gabor Greif | efdf039 | 2010-07-22 13:04:32 +0000 | [diff] [blame] | 115 | InvokeInst *II = cast<InvokeInst>(U); |
Nick Lewycky | d694a78 | 2009-03-08 19:02:17 +0000 | [diff] [blame] | 116 | NCall = InvokeInst::Create(NF, II->getNormalDest(), |
| 117 | II->getUnwindDest(), |
Andrew Lenharth | eb50479 | 2008-09-04 18:51:26 +0000 | [diff] [blame] | 118 | args.begin(), args.end(), |
Nick Lewycky | d694a78 | 2009-03-08 19:02:17 +0000 | [diff] [blame] | 119 | II->getName(), II); |
| 120 | cast<InvokeInst>(NCall)->setCallingConv(II->getCallingConv()); |
| 121 | } |
Andrew Lenharth | eb50479 | 2008-09-04 18:51:26 +0000 | [diff] [blame] | 122 | CS.getInstruction()->replaceAllUsesWith(NCall); |
| 123 | CS.getInstruction()->eraseFromParent(); |
Kenneth Uildriks | 3a4340d | 2010-06-05 14:50:21 +0000 | [diff] [blame] | 124 | ++numReplaced; |
Andrew Lenharth | eb50479 | 2008-09-04 18:51:26 +0000 | [diff] [blame] | 125 | } |
| 126 | } |
Gabor Greif | efdf039 | 2010-07-22 13:04:32 +0000 | [diff] [blame] | 127 | next_use:; |
Andrew Lenharth | eb50479 | 2008-09-04 18:51:26 +0000 | [diff] [blame] | 128 | } |
| 129 | return NF; |
| 130 | } |
| 131 | |
| 132 | |
Andrew Lenharth | cf996d4 | 2008-09-03 21:00:28 +0000 | [diff] [blame] | 133 | bool PartSpec::runOnModule(Module &M) { |
| 134 | bool Changed = false; |
| 135 | for (Module::iterator I = M.begin(); I != M.end(); ++I) { |
| 136 | Function &F = *I; |
Nuno Lopes | 7a85a62 | 2008-10-08 18:45:59 +0000 | [diff] [blame] | 137 | if (F.isDeclaration() || F.mayBeOverridden()) continue; |
Kenneth Uildriks | 3a4340d | 2010-06-05 14:50:21 +0000 | [diff] [blame] | 138 | InterestingArgVector interestingArgs; |
Andrew Lenharth | ef78032 | 2008-09-04 14:34:22 +0000 | [diff] [blame] | 139 | scanForInterest(F, interestingArgs); |
| 140 | |
| 141 | // Find the first interesting Argument that we can specialize on |
| 142 | // If there are multiple interesting Arguments, then those will be found |
| 143 | // when processing the cloned function. |
| 144 | bool breakOuter = false; |
| 145 | for (unsigned int x = 0; !breakOuter && x < interestingArgs.size(); ++x) { |
| 146 | std::map<Constant*, int> distribution; |
Kenneth Uildriks | 74fa732 | 2010-10-09 22:06:36 +0000 | [diff] [blame^] | 147 | scanDistribution(F, interestingArgs[x], distribution); |
| 148 | for (std::map<Constant*, int>::iterator ii = distribution.begin(), |
| 149 | ee = distribution.end(); ii != ee; ++ii) { |
| 150 | // The distribution map might have an entry for NULL (i.e., one or more |
| 151 | // callsites were passing a non-constant there). We allow that to |
| 152 | // happen so that we can see whether any callsites pass a non-constant; |
| 153 | // if none do and the function is internal, we might have an opportunity |
| 154 | // to kill the original function. |
| 155 | if (!ii->first) continue; |
| 156 | int bonus = ii->second; |
| 157 | SmallVector<unsigned, 1> argnos; |
| 158 | argnos.push_back(interestingArgs[x]); |
| 159 | InlineCost cost = CA.getSpecializationCost(&F, argnos); |
| 160 | // FIXME: If this is the last constant entry, and no non-constant |
| 161 | // entries exist, and the target function is internal, the cost should |
| 162 | // be reduced by the original size of the target function, almost |
| 163 | // certainly making it negative and causing a specialization that will |
| 164 | // leave the original function dead and removable. |
| 165 | if (cost.isAlways() || |
| 166 | (cost.isVariable() && cost.getValue() < bonus)) { |
| 167 | ValueMap<const Value*, Value*> m; |
| 168 | Function::arg_iterator arg = F.arg_begin(); |
| 169 | for (int y = 0; y < interestingArgs[x]; ++y) |
| 170 | ++arg; |
| 171 | m[&*arg] = ii->first; |
| 172 | SpecializeFunction(&F, m); |
| 173 | ++numSpecialized; |
| 174 | breakOuter = true; |
| 175 | Changed = true; |
| 176 | } |
| 177 | } |
Andrew Lenharth | cf996d4 | 2008-09-03 21:00:28 +0000 | [diff] [blame] | 178 | } |
| 179 | } |
| 180 | return Changed; |
| 181 | } |
| 182 | |
| 183 | /// scanForInterest - This function decides which arguments would be worth |
Andrew Lenharth | ef78032 | 2008-09-04 14:34:22 +0000 | [diff] [blame] | 184 | /// specializing on. |
Kenneth Uildriks | 3a4340d | 2010-06-05 14:50:21 +0000 | [diff] [blame] | 185 | void PartSpec::scanForInterest(Function& F, InterestingArgVector& args) { |
Andrew Lenharth | cf996d4 | 2008-09-03 21:00:28 +0000 | [diff] [blame] | 186 | for(Function::arg_iterator ii = F.arg_begin(), ee = F.arg_end(); |
| 187 | ii != ee; ++ii) { |
Kenneth Uildriks | 74fa732 | 2010-10-09 22:06:36 +0000 | [diff] [blame^] | 188 | int argno = std::distance(F.arg_begin(), ii); |
| 189 | SmallVector<unsigned, 1> argnos; |
| 190 | argnos.push_back(argno); |
| 191 | int bonus = CA.getSpecializationBonus(&F, argnos); |
| 192 | if (bonus > 0) { |
| 193 | args.push_back(argno); |
Andrew Lenharth | cf996d4 | 2008-09-03 21:00:28 +0000 | [diff] [blame] | 194 | } |
| 195 | } |
| 196 | } |
| 197 | |
Andrew Lenharth | 06a1242 | 2008-11-03 19:29:29 +0000 | [diff] [blame] | 198 | /// scanDistribution - Construct a histogram of constants for arg of F at arg. |
Kenneth Uildriks | 74fa732 | 2010-10-09 22:06:36 +0000 | [diff] [blame^] | 199 | /// For each distinct constant, we'll compute the total of the specialization |
| 200 | /// bonus across all callsites passing that constant; if that total exceeds |
| 201 | /// the specialization cost, we will create the specialization. |
Andrew Lenharth | cf996d4 | 2008-09-03 21:00:28 +0000 | [diff] [blame] | 202 | int PartSpec::scanDistribution(Function& F, int arg, |
| 203 | std::map<Constant*, int>& dist) { |
Andrew Lenharth | ef78032 | 2008-09-04 14:34:22 +0000 | [diff] [blame] | 204 | bool hasIndirect = false; |
Andrew Lenharth | cf996d4 | 2008-09-03 21:00:28 +0000 | [diff] [blame] | 205 | int total = 0; |
Gabor Greif | efdf039 | 2010-07-22 13:04:32 +0000 | [diff] [blame] | 206 | for (Value::use_iterator ii = F.use_begin(), ee = F.use_end(); |
| 207 | ii != ee; ++ii) { |
| 208 | User *U = *ii; |
| 209 | CallSite CS(U); |
| 210 | if (CS && CS.getCalledFunction() == &F) { |
Kenneth Uildriks | 74fa732 | 2010-10-09 22:06:36 +0000 | [diff] [blame^] | 211 | SmallVector<unsigned, 1> argnos; |
| 212 | argnos.push_back(arg); |
| 213 | dist[dyn_cast<Constant>(CS.getArgument(arg))] += |
| 214 | CA.getSpecializationBonus(&F, argnos); |
Andrew Lenharth | cf996d4 | 2008-09-03 21:00:28 +0000 | [diff] [blame] | 215 | ++total; |
| 216 | } else |
Andrew Lenharth | ef78032 | 2008-09-04 14:34:22 +0000 | [diff] [blame] | 217 | hasIndirect = true; |
Gabor Greif | efdf039 | 2010-07-22 13:04:32 +0000 | [diff] [blame] | 218 | } |
Andrew Lenharth | ef78032 | 2008-09-04 14:34:22 +0000 | [diff] [blame] | 219 | |
| 220 | // Preserve the original address taken function even if all other uses |
| 221 | // will be specialized. |
| 222 | if (hasIndirect) ++total; |
Andrew Lenharth | cf996d4 | 2008-09-03 21:00:28 +0000 | [diff] [blame] | 223 | return total; |
| 224 | } |
| 225 | |
| 226 | ModulePass* llvm::createPartialSpecializationPass() { return new PartSpec(); } |