diff --git a/lib/Transforms/IPO/ConstantMerge.cpp b/lib/Transforms/IPO/ConstantMerge.cpp index b979104401c..28c6519478f 100644 --- a/lib/Transforms/IPO/ConstantMerge.cpp +++ b/lib/Transforms/IPO/ConstantMerge.cpp @@ -3,19 +3,16 @@ // This file defines the interface to a pass that merges duplicate global // constants together into a single constant that is shared. This is useful // because some passes (ie TraceValues) insert a lot of string constants into -// the program, regardless of whether or not they duplicate an existing string. +// the program, regardless of whether or not an existing string is available. // // Algorithm: ConstantMerge is designed to build up a map of available constants -// and elminate duplicates when it is initialized. -// -// The DynamicConstantMerge method is a superset of the ConstantMerge algorithm -// that checks for each function to see if constants have been added to the -// constant pool since it was last run... if so, it processes them. +// and eliminate duplicates when it is initialized. // //===----------------------------------------------------------------------===// #include "llvm/Transforms/IPO.h" #include "llvm/Module.h" +#include "llvm/Constants.h" #include "llvm/Pass.h" #include "Support/StatisticReporter.h" @@ -26,9 +23,9 @@ namespace { // bool run(Module &M); - virtual void getAnalysisUsage(AnalysisUsage &AU) const { - AU.preservesCFG(); - } + private: + void replaceUsesOfWith(GlobalVariable *Old, GlobalVariable *New); + void replaceConstantWith(Constant *Old, Constant *New); }; Statistic<> NumMerged("constmerge\t\t- Number of global constants merged"); @@ -38,10 +35,6 @@ namespace { Pass *createConstantMergePass() { return new ConstantMerge(); } -// ConstantMerge::run - Workhorse for the pass. This eliminates duplicate -// constants, starting at global ConstantNo, and adds vars to the map if they -// are new and unique. -// bool ConstantMerge::run(Module &M) { std::map CMap; bool MadeChanges = false; @@ -58,7 +51,7 @@ bool ConstantMerge::run(Module &M) { CMap.insert(I, std::make_pair(Init, GV)); } else { // Yup, this is a duplicate! // Make all uses of the duplicate constant use the cannonical version... - GV->replaceAllUsesWith(I->second); + replaceUsesOfWith(GV, I->second); // Delete the global value from the module... and back up iterator to // not skip the next global... @@ -71,3 +64,98 @@ bool ConstantMerge::run(Module &M) { return MadeChanges; } + +/// replaceUsesOfWith - Replace all uses of Old with New. For instructions, +/// this is a really simple matter of replacing the reference to Old with a +/// reference to New. For constants references, however, we must carefully +/// build replacement constants to substitute in. +/// +void ConstantMerge::replaceUsesOfWith(GlobalVariable *Old, GlobalVariable *New){ + while (!Old->use_empty()) { + User *U = Old->use_back(); + if (ConstantPointerRef *CPR = dyn_cast(U)) + replaceConstantWith(CPR, ConstantPointerRef::get(New)); + else + U->replaceUsesOfWith(Old, New); + } +} + +/// replaceWith - Ok, so we have a constant 'Old' and we want to replace it with +/// 'New'. To do this, we have to recursively go through the uses of Old, +/// replacing them with new things. The problem is that if a constant uses Old, +/// then we need to replace the uses of the constant with uses of the equivalent +/// constant that uses New instead. +/// +void ConstantMerge::replaceConstantWith(Constant *Old, Constant *New) { + while (!Old->use_empty()) { + User *U = Old->use_back(); + + if (Constant *C = dyn_cast(U)) { + Constant *Replacement = 0; + + // Depending on the type of constant, build a suitable replacement... + if (ConstantExpr *CE = dyn_cast(C)) { + if (CE->getOpcode() == Instruction::GetElementPtr) { + std::vector Indices; + Constant *Pointer = cast(CE->getOperand(0)); + Indices.reserve(CE->getNumOperands()-1); + if (Pointer == Old) Pointer = New; + + for (unsigned i = 1, e = CE->getNumOperands(); i != e; ++i) { + Constant *Val = cast(CE->getOperand(i)); + if (Val == Old) Val = New; + Indices.push_back(Val); + } + Replacement = ConstantExpr::getGetElementPtr(Pointer, Indices); + } else if (CE->getOpcode() == Instruction::Cast) { + assert(CE->getOperand(0) == Old && "Cast only has one use!"); + Replacement = ConstantExpr::getCast(New, CE->getType()); + } else if (CE->getNumOperands() == 2) { + Constant *C1 = cast(CE->getOperand(0)); + Constant *C2 = cast(CE->getOperand(1)); + if (C1 == Old) C1 = New; + if (C2 == Old) C2 = New; + Replacement = ConstantExpr::get(CE->getOpcode(), C1, C2); + } else { + assert(0 && "Unknown ConstantExpr type!"); + } + + + } else if (ConstantArray *CA = dyn_cast(C)) { + std::vector Values; + Values.reserve(CA->getValues().size()); + for (unsigned i = 0, e = CA->getValues().size(); i != e; ++i) { + Constant *Val = cast(CA->getValues()[i]); + if (Val == Old) Val = New; + Values.push_back(Val); + } + + Replacement = ConstantArray::get(CA->getType(), Values); + } else if (ConstantStruct *CS = dyn_cast(C)) { + std::vector Values; + Values.reserve(CS->getValues().size()); + + for (unsigned i = 0, e = CS->getValues().size(); i != e; ++i) { + Constant *Val = cast(CS->getValues()[i]); + if (Val == Old) Val = New; + Values.push_back(Val); + } + + Replacement = ConstantStruct::get(CS->getType(), Values); + } else { + assert(0 && "Unexpected/unknown constant type!"); + } + + // Now that we have a suitable replacement, recursively eliminate C. + replaceConstantWith(C, Replacement); + + } else { + // If it is not a constant, we can simply replace uses of Old with New. + U->replaceUsesOfWith(Old, New); + } + + } + + // No-one refers to this old dead constant now, destroy it! + Old->destroyConstant(); +}