15f757f3fSDimitry Andric //===-- PPCMergeStringPool.cpp -------------------------------------------===// 25f757f3fSDimitry Andric // 35f757f3fSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 45f757f3fSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 55f757f3fSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 65f757f3fSDimitry Andric // 75f757f3fSDimitry Andric //===----------------------------------------------------------------------===// 85f757f3fSDimitry Andric // 95f757f3fSDimitry Andric // This transformation tries to merge the strings in the module into one pool 105f757f3fSDimitry Andric // of strings. The idea is to reduce the number of TOC entries in the module so 115f757f3fSDimitry Andric // that instead of having one TOC entry for each string there is only one global 125f757f3fSDimitry Andric // TOC entry and all of the strings are referenced off of that one entry plus 135f757f3fSDimitry Andric // an offset. 145f757f3fSDimitry Andric // 155f757f3fSDimitry Andric //===----------------------------------------------------------------------===// 165f757f3fSDimitry Andric 175f757f3fSDimitry Andric #include "PPC.h" 185f757f3fSDimitry Andric #include "llvm/ADT/Statistic.h" 195f757f3fSDimitry Andric #include "llvm/Analysis/DomTreeUpdater.h" 205f757f3fSDimitry Andric #include "llvm/Analysis/LoopInfo.h" 215f757f3fSDimitry Andric #include "llvm/Analysis/LoopIterator.h" 225f757f3fSDimitry Andric #include "llvm/Analysis/ScalarEvolution.h" 235f757f3fSDimitry Andric #include "llvm/Analysis/ScalarEvolutionAliasAnalysis.h" 245f757f3fSDimitry Andric #include "llvm/IR/Constants.h" 255f757f3fSDimitry Andric #include "llvm/IR/Instructions.h" 263a079333SDimitry Andric #include "llvm/IR/IntrinsicInst.h" 275f757f3fSDimitry Andric #include "llvm/IR/Module.h" 285f757f3fSDimitry Andric #include "llvm/IR/ValueSymbolTable.h" 295f757f3fSDimitry Andric #include "llvm/Pass.h" 305f757f3fSDimitry Andric #include "llvm/Support/CommandLine.h" 315f757f3fSDimitry Andric 325f757f3fSDimitry Andric #define DEBUG_TYPE "ppc-merge-strings" 335f757f3fSDimitry Andric 345f757f3fSDimitry Andric STATISTIC(NumPooledStrings, "Number of Strings Pooled"); 355f757f3fSDimitry Andric 365f757f3fSDimitry Andric using namespace llvm; 375f757f3fSDimitry Andric 385f757f3fSDimitry Andric static cl::opt<unsigned> 395f757f3fSDimitry Andric MaxStringsPooled("ppc-max-strings-pooled", cl::Hidden, cl::init(-1), 405f757f3fSDimitry Andric cl::desc("Maximum Number of Strings to Pool.")); 415f757f3fSDimitry Andric 425f757f3fSDimitry Andric static cl::opt<unsigned> 435f757f3fSDimitry Andric MinStringsBeforePool("ppc-min-strings-before-pool", cl::Hidden, cl::init(2), 445f757f3fSDimitry Andric cl::desc("Minimum number of string candidates before " 455f757f3fSDimitry Andric "pooling is considered.")); 465f757f3fSDimitry Andric 475f757f3fSDimitry Andric namespace { 485f757f3fSDimitry Andric struct { 495f757f3fSDimitry Andric bool operator()(const GlobalVariable *LHS, const GlobalVariable *RHS) const { 505f757f3fSDimitry Andric // First priority is alignment. 515f757f3fSDimitry Andric // If elements are sorted in terms of alignment then there won't be an 525f757f3fSDimitry Andric // issue with incorrect alignment that would require padding. 535f757f3fSDimitry Andric Align LHSAlign = LHS->getAlign().valueOrOne(); 545f757f3fSDimitry Andric Align RHSAlign = RHS->getAlign().valueOrOne(); 555f757f3fSDimitry Andric if (LHSAlign > RHSAlign) 565f757f3fSDimitry Andric return true; 575f757f3fSDimitry Andric else if (LHSAlign < RHSAlign) 585f757f3fSDimitry Andric return false; 595f757f3fSDimitry Andric 605f757f3fSDimitry Andric // Next priority is the number of uses. 615f757f3fSDimitry Andric // Smaller offsets are easier to materialize because materializing a large 625f757f3fSDimitry Andric // offset may require more than one instruction. (ie addis, addi). 635f757f3fSDimitry Andric if (LHS->getNumUses() > RHS->getNumUses()) 645f757f3fSDimitry Andric return true; 655f757f3fSDimitry Andric else if (LHS->getNumUses() < RHS->getNumUses()) 665f757f3fSDimitry Andric return false; 675f757f3fSDimitry Andric 685f757f3fSDimitry Andric const Constant *ConstLHS = LHS->getInitializer(); 695f757f3fSDimitry Andric const ConstantDataSequential *ConstDataLHS = 705f757f3fSDimitry Andric dyn_cast<ConstantDataSequential>(ConstLHS); 715f757f3fSDimitry Andric unsigned LHSSize = 725f757f3fSDimitry Andric ConstDataLHS->getNumElements() * ConstDataLHS->getElementByteSize(); 735f757f3fSDimitry Andric const Constant *ConstRHS = RHS->getInitializer(); 745f757f3fSDimitry Andric const ConstantDataSequential *ConstDataRHS = 755f757f3fSDimitry Andric dyn_cast<ConstantDataSequential>(ConstRHS); 765f757f3fSDimitry Andric unsigned RHSSize = 775f757f3fSDimitry Andric ConstDataRHS->getNumElements() * ConstDataRHS->getElementByteSize(); 785f757f3fSDimitry Andric 795f757f3fSDimitry Andric // Finally smaller constants should go first. This is, again, trying to 805f757f3fSDimitry Andric // minimize the offsets into the final struct. 815f757f3fSDimitry Andric return LHSSize < RHSSize; 825f757f3fSDimitry Andric } 835f757f3fSDimitry Andric } CompareConstants; 845f757f3fSDimitry Andric 855f757f3fSDimitry Andric class PPCMergeStringPool : public ModulePass { 865f757f3fSDimitry Andric public: 875f757f3fSDimitry Andric static char ID; 885f757f3fSDimitry Andric PPCMergeStringPool() : ModulePass(ID) {} 895f757f3fSDimitry Andric 90*0fca6ea1SDimitry Andric bool doInitialization(Module &M) override { return mergeModuleStringPool(M); } 91*0fca6ea1SDimitry Andric bool runOnModule(Module &M) override { return false; } 925f757f3fSDimitry Andric 935f757f3fSDimitry Andric StringRef getPassName() const override { return "PPC Merge String Pool"; } 945f757f3fSDimitry Andric 955f757f3fSDimitry Andric void getAnalysisUsage(AnalysisUsage &AU) const override { 965f757f3fSDimitry Andric AU.addPreserved<DominatorTreeWrapperPass>(); 975f757f3fSDimitry Andric AU.addPreserved<LoopInfoWrapperPass>(); 985f757f3fSDimitry Andric AU.addPreserved<ScalarEvolutionWrapperPass>(); 995f757f3fSDimitry Andric AU.addPreserved<SCEVAAWrapperPass>(); 1005f757f3fSDimitry Andric } 1015f757f3fSDimitry Andric 1025f757f3fSDimitry Andric private: 1035f757f3fSDimitry Andric // Globals in a Module are already unique so a set is not required and a 1045f757f3fSDimitry Andric // vector will do. 1055f757f3fSDimitry Andric std::vector<GlobalVariable *> MergeableStrings; 1065f757f3fSDimitry Andric Align MaxAlignment; 1075f757f3fSDimitry Andric Type *PooledStructType; 1085f757f3fSDimitry Andric LLVMContext *Context; 1095f757f3fSDimitry Andric void collectCandidateConstants(Module &M); 1105f757f3fSDimitry Andric bool mergeModuleStringPool(Module &M); 1115f757f3fSDimitry Andric void replaceUsesWithGEP(GlobalVariable *GlobalToReplace, GlobalVariable *GPool, 1125f757f3fSDimitry Andric unsigned ElementIndex); 1135f757f3fSDimitry Andric }; 1145f757f3fSDimitry Andric 1155f757f3fSDimitry Andric 1165f757f3fSDimitry Andric // In order for a constant to be pooled we need to be able to replace all of 1175f757f3fSDimitry Andric // the uses for that constant. This function checks all of the uses to make 1185f757f3fSDimitry Andric // sure that they can be replaced. 1195f757f3fSDimitry Andric static bool hasReplaceableUsers(GlobalVariable &GV) { 1205f757f3fSDimitry Andric for (User *CurrentUser : GV.users()) { 1213a079333SDimitry Andric if (auto *I = dyn_cast<Instruction>(CurrentUser)) { 1223a079333SDimitry Andric // Do not merge globals in exception pads. 1233a079333SDimitry Andric if (I->isEHPad()) 1243a079333SDimitry Andric return false; 1253a079333SDimitry Andric 1263a079333SDimitry Andric if (auto *II = dyn_cast<IntrinsicInst>(I)) { 1273a079333SDimitry Andric // Some intrinsics require a plain global. 1283a079333SDimitry Andric if (II->getIntrinsicID() == Intrinsic::eh_typeid_for) 1293a079333SDimitry Andric return false; 1303a079333SDimitry Andric } 1313a079333SDimitry Andric 1323a079333SDimitry Andric // Other instruction users are always valid. 1335f757f3fSDimitry Andric continue; 1343a079333SDimitry Andric } 1355f757f3fSDimitry Andric 1365f757f3fSDimitry Andric // We cannot replace GlobalValue users because they are not just nodes 1375f757f3fSDimitry Andric // in IR. To replace a user like this we would need to create a new 1385f757f3fSDimitry Andric // GlobalValue with the replacement and then try to delete the original 1395f757f3fSDimitry Andric // GlobalValue. Deleting the original would only happen if it has no other 1405f757f3fSDimitry Andric // uses. 1415f757f3fSDimitry Andric if (isa<GlobalValue>(CurrentUser)) 1425f757f3fSDimitry Andric return false; 1435f757f3fSDimitry Andric 1445f757f3fSDimitry Andric // We only support Instruction and Constant users. 1455f757f3fSDimitry Andric if (!isa<Constant>(CurrentUser)) 1465f757f3fSDimitry Andric return false; 1475f757f3fSDimitry Andric } 1485f757f3fSDimitry Andric 1495f757f3fSDimitry Andric return true; 1505f757f3fSDimitry Andric } 1515f757f3fSDimitry Andric 1525f757f3fSDimitry Andric // Run through all of the constants in the module and determine if they are 1535f757f3fSDimitry Andric // valid candidates to be merged into the string pool. Valid candidates will 1545f757f3fSDimitry Andric // be added to MergeableStrings. 1555f757f3fSDimitry Andric void PPCMergeStringPool::collectCandidateConstants(Module &M) { 1565f757f3fSDimitry Andric SmallVector<GlobalValue *, 4> UsedV; 1575f757f3fSDimitry Andric collectUsedGlobalVariables(M, UsedV, /*CompilerUsed=*/false); 1585f757f3fSDimitry Andric SmallVector<GlobalValue *, 4> UsedVCompiler; 1595f757f3fSDimitry Andric collectUsedGlobalVariables(M, UsedVCompiler, /*CompilerUsed=*/true); 1605f757f3fSDimitry Andric // Combine all of the Global Variables marked as used into a SmallPtrSet for 1615f757f3fSDimitry Andric // faster lookup inside the loop. 1625f757f3fSDimitry Andric SmallPtrSet<GlobalValue *, 8> AllUsedGlobals; 1635f757f3fSDimitry Andric AllUsedGlobals.insert(UsedV.begin(), UsedV.end()); 1645f757f3fSDimitry Andric AllUsedGlobals.insert(UsedVCompiler.begin(), UsedVCompiler.end()); 1655f757f3fSDimitry Andric 1665f757f3fSDimitry Andric for (GlobalVariable &Global : M.globals()) { 1675f757f3fSDimitry Andric LLVM_DEBUG(dbgs() << "Looking at global:"); 1685f757f3fSDimitry Andric LLVM_DEBUG(Global.dump()); 1695f757f3fSDimitry Andric LLVM_DEBUG(dbgs() << "isConstant() " << Global.isConstant() << "\n"); 1705f757f3fSDimitry Andric LLVM_DEBUG(dbgs() << "hasInitializer() " << Global.hasInitializer() 1715f757f3fSDimitry Andric << "\n"); 1725f757f3fSDimitry Andric 1735f757f3fSDimitry Andric // We can only pool constants. 1745f757f3fSDimitry Andric if (!Global.isConstant() || !Global.hasInitializer()) 1755f757f3fSDimitry Andric continue; 1765f757f3fSDimitry Andric 1775f757f3fSDimitry Andric // If a global constant has a section we do not try to pool it because 1785f757f3fSDimitry Andric // there is no guarantee that other constants will also be in the same 1795f757f3fSDimitry Andric // section. Trying to pool constants from different sections (or no 1805f757f3fSDimitry Andric // section) means that the pool has to be in multiple sections at the same 1815f757f3fSDimitry Andric // time. 1825f757f3fSDimitry Andric if (Global.hasSection()) 1835f757f3fSDimitry Andric continue; 1845f757f3fSDimitry Andric 1855f757f3fSDimitry Andric // Do not pool constants with metadata because we should not add metadata 1865f757f3fSDimitry Andric // to the pool when that metadata refers to a single constant in the pool. 1875f757f3fSDimitry Andric if (Global.hasMetadata()) 1885f757f3fSDimitry Andric continue; 1895f757f3fSDimitry Andric 1905f757f3fSDimitry Andric ConstantDataSequential *ConstData = 1915f757f3fSDimitry Andric dyn_cast<ConstantDataSequential>(Global.getInitializer()); 1925f757f3fSDimitry Andric 1935f757f3fSDimitry Andric // If the constant is undef then ConstData will be null. 1945f757f3fSDimitry Andric if (!ConstData) 1955f757f3fSDimitry Andric continue; 1965f757f3fSDimitry Andric 1975f757f3fSDimitry Andric // Do not pool globals that are part of llvm.used or llvm.compiler.end. 1985f757f3fSDimitry Andric if (AllUsedGlobals.contains(&Global)) 1995f757f3fSDimitry Andric continue; 2005f757f3fSDimitry Andric 2015f757f3fSDimitry Andric if (!hasReplaceableUsers(Global)) 2025f757f3fSDimitry Andric continue; 2035f757f3fSDimitry Andric 2045f757f3fSDimitry Andric Align AlignOfGlobal = Global.getAlign().valueOrOne(); 2055f757f3fSDimitry Andric 2065f757f3fSDimitry Andric // TODO: At this point do not allow over-aligned types. Adding a type 2075f757f3fSDimitry Andric // with larger alignment may lose the larger alignment once it is 2085f757f3fSDimitry Andric // added to the struct. 2095f757f3fSDimitry Andric // Fix this in a future patch. 2105f757f3fSDimitry Andric if (AlignOfGlobal.value() > ConstData->getElementByteSize()) 2115f757f3fSDimitry Andric continue; 2125f757f3fSDimitry Andric 2135f757f3fSDimitry Andric // Make sure that the global is only visible inside the compilation unit. 2145f757f3fSDimitry Andric if (Global.getLinkage() != GlobalValue::PrivateLinkage && 2155f757f3fSDimitry Andric Global.getLinkage() != GlobalValue::InternalLinkage) 2165f757f3fSDimitry Andric continue; 2175f757f3fSDimitry Andric 2185f757f3fSDimitry Andric LLVM_DEBUG(dbgs() << "Constant data of Global: "); 2195f757f3fSDimitry Andric LLVM_DEBUG(ConstData->dump()); 2205f757f3fSDimitry Andric LLVM_DEBUG(dbgs() << "\n\n"); 2215f757f3fSDimitry Andric 2225f757f3fSDimitry Andric MergeableStrings.push_back(&Global); 2235f757f3fSDimitry Andric if (MaxAlignment < AlignOfGlobal) 2245f757f3fSDimitry Andric MaxAlignment = AlignOfGlobal; 2255f757f3fSDimitry Andric 2265f757f3fSDimitry Andric // If we have already reached the maximum number of pooled strings then 2275f757f3fSDimitry Andric // there is no point in looking for more. 2285f757f3fSDimitry Andric if (MergeableStrings.size() >= MaxStringsPooled) 2295f757f3fSDimitry Andric break; 2305f757f3fSDimitry Andric } 2315f757f3fSDimitry Andric } 2325f757f3fSDimitry Andric 2335f757f3fSDimitry Andric bool PPCMergeStringPool::mergeModuleStringPool(Module &M) { 2345f757f3fSDimitry Andric 2355f757f3fSDimitry Andric LLVM_DEBUG(dbgs() << "Merging string pool for module: " << M.getName() 2365f757f3fSDimitry Andric << "\n"); 2375f757f3fSDimitry Andric LLVM_DEBUG(dbgs() << "Number of globals is: " << M.global_size() << "\n"); 2385f757f3fSDimitry Andric 2395f757f3fSDimitry Andric collectCandidateConstants(M); 2405f757f3fSDimitry Andric 2415f757f3fSDimitry Andric // If we have too few constants in the module that are merge candidates we 2425f757f3fSDimitry Andric // will skip doing the merging. 2435f757f3fSDimitry Andric if (MergeableStrings.size() < MinStringsBeforePool) 2445f757f3fSDimitry Andric return false; 2455f757f3fSDimitry Andric 2465f757f3fSDimitry Andric // Sort the global constants to make access more efficient. 2475f757f3fSDimitry Andric std::sort(MergeableStrings.begin(), MergeableStrings.end(), CompareConstants); 2485f757f3fSDimitry Andric 2495f757f3fSDimitry Andric SmallVector<Constant *> ConstantsInStruct; 2505f757f3fSDimitry Andric for (GlobalVariable *GV : MergeableStrings) 2515f757f3fSDimitry Andric ConstantsInStruct.push_back(GV->getInitializer()); 2525f757f3fSDimitry Andric 2535f757f3fSDimitry Andric // Use an anonymous struct to pool the strings. 2545f757f3fSDimitry Andric // TODO: This pass uses a single anonymous struct for all of the pooled 2555f757f3fSDimitry Andric // entries. This may cause a performance issue in the situation where 2565f757f3fSDimitry Andric // computing the offset requires two instructions (addis, addi). For the 2575f757f3fSDimitry Andric // future we may want to split this into multiple structs. 2585f757f3fSDimitry Andric Constant *ConstantPool = ConstantStruct::getAnon(ConstantsInStruct); 2595f757f3fSDimitry Andric PooledStructType = ConstantPool->getType(); 2605f757f3fSDimitry Andric 2615f757f3fSDimitry Andric // The GlobalVariable constructor calls 2625f757f3fSDimitry Andric // MM->insertGlobalVariable(PooledGlobal). 2635f757f3fSDimitry Andric GlobalVariable *PooledGlobal = 2645f757f3fSDimitry Andric new GlobalVariable(M, PooledStructType, 2655f757f3fSDimitry Andric /* isConstant */ true, GlobalValue::PrivateLinkage, 2665f757f3fSDimitry Andric ConstantPool, "__ModuleStringPool"); 2675f757f3fSDimitry Andric PooledGlobal->setAlignment(MaxAlignment); 2685f757f3fSDimitry Andric 2695f757f3fSDimitry Andric LLVM_DEBUG(dbgs() << "Constructing global variable for string pool: "); 2705f757f3fSDimitry Andric LLVM_DEBUG(PooledGlobal->dump()); 2715f757f3fSDimitry Andric 2725f757f3fSDimitry Andric Context = &M.getContext(); 2735f757f3fSDimitry Andric size_t ElementIndex = 0; 2745f757f3fSDimitry Andric for (GlobalVariable *GV : MergeableStrings) { 2755f757f3fSDimitry Andric 2765f757f3fSDimitry Andric LLVM_DEBUG(dbgs() << "The global:\n"); 2775f757f3fSDimitry Andric LLVM_DEBUG(GV->dump()); 2785f757f3fSDimitry Andric LLVM_DEBUG(dbgs() << "Has " << GV->getNumUses() << " uses.\n"); 2795f757f3fSDimitry Andric 2805f757f3fSDimitry Andric // Access to the pooled constant strings require an offset. Add a GEP 2815f757f3fSDimitry Andric // before every use in order to compute this offset. 2825f757f3fSDimitry Andric replaceUsesWithGEP(GV, PooledGlobal, ElementIndex); 2835f757f3fSDimitry Andric 284*0fca6ea1SDimitry Andric // Replace all the uses by metadata. 285*0fca6ea1SDimitry Andric if (GV->isUsedByMetadata()) { 286*0fca6ea1SDimitry Andric Constant *Indices[2] = { 287*0fca6ea1SDimitry Andric ConstantInt::get(Type::getInt32Ty(*Context), 0), 288*0fca6ea1SDimitry Andric ConstantInt::get(Type::getInt32Ty(*Context), ElementIndex)}; 289*0fca6ea1SDimitry Andric Constant *ConstGEP = ConstantExpr::getInBoundsGetElementPtr( 290*0fca6ea1SDimitry Andric PooledStructType, PooledGlobal, Indices); 291*0fca6ea1SDimitry Andric ValueAsMetadata::handleRAUW(GV, ConstGEP); 292*0fca6ea1SDimitry Andric } 293*0fca6ea1SDimitry Andric assert(!GV->isUsedByMetadata() && "Should be no metadata use anymore"); 294*0fca6ea1SDimitry Andric 2955f757f3fSDimitry Andric // This GV has no more uses so we can erase it. 2965f757f3fSDimitry Andric if (GV->use_empty()) 2975f757f3fSDimitry Andric GV->eraseFromParent(); 2985f757f3fSDimitry Andric 2995f757f3fSDimitry Andric NumPooledStrings++; 3005f757f3fSDimitry Andric ElementIndex++; 3015f757f3fSDimitry Andric } 3025f757f3fSDimitry Andric return true; 3035f757f3fSDimitry Andric } 3045f757f3fSDimitry Andric 3055f757f3fSDimitry Andric // For pooled strings we need to add the offset into the pool for each string. 3065f757f3fSDimitry Andric // This is done by adding a Get Element Pointer (GEP) before each user. This 3075f757f3fSDimitry Andric // function adds the GEP. 3085f757f3fSDimitry Andric void PPCMergeStringPool::replaceUsesWithGEP(GlobalVariable *GlobalToReplace, 3095f757f3fSDimitry Andric GlobalVariable *GPool, 3105f757f3fSDimitry Andric unsigned ElementIndex) { 3115f757f3fSDimitry Andric SmallVector<Value *, 2> Indices; 3125f757f3fSDimitry Andric Indices.push_back(ConstantInt::get(Type::getInt32Ty(*Context), 0)); 3135f757f3fSDimitry Andric Indices.push_back(ConstantInt::get(Type::getInt32Ty(*Context), ElementIndex)); 3145f757f3fSDimitry Andric 315f30188c4SDimitry Andric Constant *ConstGEP = 316f30188c4SDimitry Andric ConstantExpr::getInBoundsGetElementPtr(PooledStructType, GPool, Indices); 3175f757f3fSDimitry Andric LLVM_DEBUG(dbgs() << "Replacing this global:\n"); 3185f757f3fSDimitry Andric LLVM_DEBUG(GlobalToReplace->dump()); 3195f757f3fSDimitry Andric LLVM_DEBUG(dbgs() << "with this:\n"); 3203a079333SDimitry Andric LLVM_DEBUG(ConstGEP->dump()); 3213a079333SDimitry Andric GlobalToReplace->replaceAllUsesWith(ConstGEP); 3225f757f3fSDimitry Andric } 3235f757f3fSDimitry Andric 3245f757f3fSDimitry Andric } // namespace 3255f757f3fSDimitry Andric 3265f757f3fSDimitry Andric char PPCMergeStringPool::ID = 0; 3275f757f3fSDimitry Andric 3285f757f3fSDimitry Andric INITIALIZE_PASS(PPCMergeStringPool, DEBUG_TYPE, "PPC Merge String Pool", false, 3295f757f3fSDimitry Andric false) 3305f757f3fSDimitry Andric 3315f757f3fSDimitry Andric ModulePass *llvm::createPPCMergeStringPoolPass() { 3325f757f3fSDimitry Andric return new PPCMergeStringPool(); 3335f757f3fSDimitry Andric } 334