1c9157d92SDimitry Andric //===-- PPCMergeStringPool.cpp -------------------------------------------===//
2c9157d92SDimitry Andric //
3c9157d92SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4c9157d92SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5c9157d92SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6c9157d92SDimitry Andric //
7c9157d92SDimitry Andric //===----------------------------------------------------------------------===//
8c9157d92SDimitry Andric //
9c9157d92SDimitry Andric // This transformation tries to merge the strings in the module into one pool
10c9157d92SDimitry Andric // of strings. The idea is to reduce the number of TOC entries in the module so
11c9157d92SDimitry Andric // that instead of having one TOC entry for each string there is only one global
12c9157d92SDimitry Andric // TOC entry and all of the strings are referenced off of that one entry plus
13c9157d92SDimitry Andric // an offset.
14c9157d92SDimitry Andric //
15c9157d92SDimitry Andric //===----------------------------------------------------------------------===//
16c9157d92SDimitry Andric
17c9157d92SDimitry Andric #include "PPC.h"
18c9157d92SDimitry Andric #include "llvm/ADT/Statistic.h"
19c9157d92SDimitry Andric #include "llvm/Analysis/DomTreeUpdater.h"
20c9157d92SDimitry Andric #include "llvm/Analysis/LoopInfo.h"
21c9157d92SDimitry Andric #include "llvm/Analysis/LoopIterator.h"
22c9157d92SDimitry Andric #include "llvm/Analysis/ScalarEvolution.h"
23c9157d92SDimitry Andric #include "llvm/Analysis/ScalarEvolutionAliasAnalysis.h"
24c9157d92SDimitry Andric #include "llvm/IR/Constants.h"
25c9157d92SDimitry Andric #include "llvm/IR/Instructions.h"
26f1e32799SDimitry Andric #include "llvm/IR/IntrinsicInst.h"
27c9157d92SDimitry Andric #include "llvm/IR/Module.h"
28c9157d92SDimitry Andric #include "llvm/IR/ValueSymbolTable.h"
29c9157d92SDimitry Andric #include "llvm/Pass.h"
30c9157d92SDimitry Andric #include "llvm/Support/CommandLine.h"
31c9157d92SDimitry Andric
32c9157d92SDimitry Andric #define DEBUG_TYPE "ppc-merge-strings"
33c9157d92SDimitry Andric
34c9157d92SDimitry Andric STATISTIC(NumPooledStrings, "Number of Strings Pooled");
35c9157d92SDimitry Andric
36c9157d92SDimitry Andric using namespace llvm;
37c9157d92SDimitry Andric
38c9157d92SDimitry Andric static cl::opt<unsigned>
39c9157d92SDimitry Andric MaxStringsPooled("ppc-max-strings-pooled", cl::Hidden, cl::init(-1),
40c9157d92SDimitry Andric cl::desc("Maximum Number of Strings to Pool."));
41c9157d92SDimitry Andric
42c9157d92SDimitry Andric static cl::opt<unsigned>
43c9157d92SDimitry Andric MinStringsBeforePool("ppc-min-strings-before-pool", cl::Hidden, cl::init(2),
44c9157d92SDimitry Andric cl::desc("Minimum number of string candidates before "
45c9157d92SDimitry Andric "pooling is considered."));
46c9157d92SDimitry Andric
47c9157d92SDimitry Andric namespace {
48c9157d92SDimitry Andric struct {
operator ()__anon6371d4af0111::__anon6371d4af020849c9157d92SDimitry Andric bool operator()(const GlobalVariable *LHS, const GlobalVariable *RHS) const {
50c9157d92SDimitry Andric // First priority is alignment.
51c9157d92SDimitry Andric // If elements are sorted in terms of alignment then there won't be an
52c9157d92SDimitry Andric // issue with incorrect alignment that would require padding.
53c9157d92SDimitry Andric Align LHSAlign = LHS->getAlign().valueOrOne();
54c9157d92SDimitry Andric Align RHSAlign = RHS->getAlign().valueOrOne();
55c9157d92SDimitry Andric if (LHSAlign > RHSAlign)
56c9157d92SDimitry Andric return true;
57c9157d92SDimitry Andric else if (LHSAlign < RHSAlign)
58c9157d92SDimitry Andric return false;
59c9157d92SDimitry Andric
60c9157d92SDimitry Andric // Next priority is the number of uses.
61c9157d92SDimitry Andric // Smaller offsets are easier to materialize because materializing a large
62c9157d92SDimitry Andric // offset may require more than one instruction. (ie addis, addi).
63c9157d92SDimitry Andric if (LHS->getNumUses() > RHS->getNumUses())
64c9157d92SDimitry Andric return true;
65c9157d92SDimitry Andric else if (LHS->getNumUses() < RHS->getNumUses())
66c9157d92SDimitry Andric return false;
67c9157d92SDimitry Andric
68c9157d92SDimitry Andric const Constant *ConstLHS = LHS->getInitializer();
69c9157d92SDimitry Andric const ConstantDataSequential *ConstDataLHS =
70c9157d92SDimitry Andric dyn_cast<ConstantDataSequential>(ConstLHS);
71c9157d92SDimitry Andric unsigned LHSSize =
72c9157d92SDimitry Andric ConstDataLHS->getNumElements() * ConstDataLHS->getElementByteSize();
73c9157d92SDimitry Andric const Constant *ConstRHS = RHS->getInitializer();
74c9157d92SDimitry Andric const ConstantDataSequential *ConstDataRHS =
75c9157d92SDimitry Andric dyn_cast<ConstantDataSequential>(ConstRHS);
76c9157d92SDimitry Andric unsigned RHSSize =
77c9157d92SDimitry Andric ConstDataRHS->getNumElements() * ConstDataRHS->getElementByteSize();
78c9157d92SDimitry Andric
79c9157d92SDimitry Andric // Finally smaller constants should go first. This is, again, trying to
80c9157d92SDimitry Andric // minimize the offsets into the final struct.
81c9157d92SDimitry Andric return LHSSize < RHSSize;
82c9157d92SDimitry Andric }
83c9157d92SDimitry Andric } CompareConstants;
84c9157d92SDimitry Andric
85c9157d92SDimitry Andric class PPCMergeStringPool : public ModulePass {
86c9157d92SDimitry Andric public:
87c9157d92SDimitry Andric static char ID;
PPCMergeStringPool()88c9157d92SDimitry Andric PPCMergeStringPool() : ModulePass(ID) {}
89c9157d92SDimitry Andric
runOnModule(Module & M)90c9157d92SDimitry Andric bool runOnModule(Module &M) override { return mergeModuleStringPool(M); }
91c9157d92SDimitry Andric
getPassName() const92c9157d92SDimitry Andric StringRef getPassName() const override { return "PPC Merge String Pool"; }
93c9157d92SDimitry Andric
getAnalysisUsage(AnalysisUsage & AU) const94c9157d92SDimitry Andric void getAnalysisUsage(AnalysisUsage &AU) const override {
95c9157d92SDimitry Andric AU.addPreserved<DominatorTreeWrapperPass>();
96c9157d92SDimitry Andric AU.addPreserved<LoopInfoWrapperPass>();
97c9157d92SDimitry Andric AU.addPreserved<ScalarEvolutionWrapperPass>();
98c9157d92SDimitry Andric AU.addPreserved<SCEVAAWrapperPass>();
99c9157d92SDimitry Andric }
100c9157d92SDimitry Andric
101c9157d92SDimitry Andric private:
102c9157d92SDimitry Andric // Globals in a Module are already unique so a set is not required and a
103c9157d92SDimitry Andric // vector will do.
104c9157d92SDimitry Andric std::vector<GlobalVariable *> MergeableStrings;
105c9157d92SDimitry Andric Align MaxAlignment;
106c9157d92SDimitry Andric Type *PooledStructType;
107c9157d92SDimitry Andric LLVMContext *Context;
108c9157d92SDimitry Andric void collectCandidateConstants(Module &M);
109c9157d92SDimitry Andric bool mergeModuleStringPool(Module &M);
110c9157d92SDimitry Andric void replaceUsesWithGEP(GlobalVariable *GlobalToReplace, GlobalVariable *GPool,
111c9157d92SDimitry Andric unsigned ElementIndex);
112c9157d92SDimitry Andric };
113c9157d92SDimitry Andric
114c9157d92SDimitry Andric
115c9157d92SDimitry Andric // In order for a constant to be pooled we need to be able to replace all of
116c9157d92SDimitry Andric // the uses for that constant. This function checks all of the uses to make
117c9157d92SDimitry Andric // sure that they can be replaced.
hasReplaceableUsers(GlobalVariable & GV)118c9157d92SDimitry Andric static bool hasReplaceableUsers(GlobalVariable &GV) {
119c9157d92SDimitry Andric for (User *CurrentUser : GV.users()) {
120f1e32799SDimitry Andric if (auto *I = dyn_cast<Instruction>(CurrentUser)) {
121f1e32799SDimitry Andric // Do not merge globals in exception pads.
122f1e32799SDimitry Andric if (I->isEHPad())
123f1e32799SDimitry Andric return false;
124f1e32799SDimitry Andric
125f1e32799SDimitry Andric if (auto *II = dyn_cast<IntrinsicInst>(I)) {
126f1e32799SDimitry Andric // Some intrinsics require a plain global.
127f1e32799SDimitry Andric if (II->getIntrinsicID() == Intrinsic::eh_typeid_for)
128f1e32799SDimitry Andric return false;
129f1e32799SDimitry Andric }
130f1e32799SDimitry Andric
131f1e32799SDimitry Andric // Other instruction users are always valid.
132c9157d92SDimitry Andric continue;
133f1e32799SDimitry Andric }
134c9157d92SDimitry Andric
135c9157d92SDimitry Andric // We cannot replace GlobalValue users because they are not just nodes
136c9157d92SDimitry Andric // in IR. To replace a user like this we would need to create a new
137c9157d92SDimitry Andric // GlobalValue with the replacement and then try to delete the original
138c9157d92SDimitry Andric // GlobalValue. Deleting the original would only happen if it has no other
139c9157d92SDimitry Andric // uses.
140c9157d92SDimitry Andric if (isa<GlobalValue>(CurrentUser))
141c9157d92SDimitry Andric return false;
142c9157d92SDimitry Andric
143c9157d92SDimitry Andric // We only support Instruction and Constant users.
144c9157d92SDimitry Andric if (!isa<Constant>(CurrentUser))
145c9157d92SDimitry Andric return false;
146c9157d92SDimitry Andric }
147c9157d92SDimitry Andric
148c9157d92SDimitry Andric return true;
149c9157d92SDimitry Andric }
150c9157d92SDimitry Andric
151c9157d92SDimitry Andric // Run through all of the constants in the module and determine if they are
152c9157d92SDimitry Andric // valid candidates to be merged into the string pool. Valid candidates will
153c9157d92SDimitry Andric // be added to MergeableStrings.
collectCandidateConstants(Module & M)154c9157d92SDimitry Andric void PPCMergeStringPool::collectCandidateConstants(Module &M) {
155c9157d92SDimitry Andric SmallVector<GlobalValue *, 4> UsedV;
156c9157d92SDimitry Andric collectUsedGlobalVariables(M, UsedV, /*CompilerUsed=*/false);
157c9157d92SDimitry Andric SmallVector<GlobalValue *, 4> UsedVCompiler;
158c9157d92SDimitry Andric collectUsedGlobalVariables(M, UsedVCompiler, /*CompilerUsed=*/true);
159c9157d92SDimitry Andric // Combine all of the Global Variables marked as used into a SmallPtrSet for
160c9157d92SDimitry Andric // faster lookup inside the loop.
161c9157d92SDimitry Andric SmallPtrSet<GlobalValue *, 8> AllUsedGlobals;
162c9157d92SDimitry Andric AllUsedGlobals.insert(UsedV.begin(), UsedV.end());
163c9157d92SDimitry Andric AllUsedGlobals.insert(UsedVCompiler.begin(), UsedVCompiler.end());
164c9157d92SDimitry Andric
165c9157d92SDimitry Andric for (GlobalVariable &Global : M.globals()) {
166c9157d92SDimitry Andric LLVM_DEBUG(dbgs() << "Looking at global:");
167c9157d92SDimitry Andric LLVM_DEBUG(Global.dump());
168c9157d92SDimitry Andric LLVM_DEBUG(dbgs() << "isConstant() " << Global.isConstant() << "\n");
169c9157d92SDimitry Andric LLVM_DEBUG(dbgs() << "hasInitializer() " << Global.hasInitializer()
170c9157d92SDimitry Andric << "\n");
171c9157d92SDimitry Andric
172c9157d92SDimitry Andric // We can only pool constants.
173c9157d92SDimitry Andric if (!Global.isConstant() || !Global.hasInitializer())
174c9157d92SDimitry Andric continue;
175c9157d92SDimitry Andric
176c9157d92SDimitry Andric // If a global constant has a section we do not try to pool it because
177c9157d92SDimitry Andric // there is no guarantee that other constants will also be in the same
178c9157d92SDimitry Andric // section. Trying to pool constants from different sections (or no
179c9157d92SDimitry Andric // section) means that the pool has to be in multiple sections at the same
180c9157d92SDimitry Andric // time.
181c9157d92SDimitry Andric if (Global.hasSection())
182c9157d92SDimitry Andric continue;
183c9157d92SDimitry Andric
184c9157d92SDimitry Andric // Do not pool constants with metadata because we should not add metadata
185c9157d92SDimitry Andric // to the pool when that metadata refers to a single constant in the pool.
186c9157d92SDimitry Andric if (Global.hasMetadata())
187c9157d92SDimitry Andric continue;
188c9157d92SDimitry Andric
189c9157d92SDimitry Andric ConstantDataSequential *ConstData =
190c9157d92SDimitry Andric dyn_cast<ConstantDataSequential>(Global.getInitializer());
191c9157d92SDimitry Andric
192c9157d92SDimitry Andric // If the constant is undef then ConstData will be null.
193c9157d92SDimitry Andric if (!ConstData)
194c9157d92SDimitry Andric continue;
195c9157d92SDimitry Andric
196c9157d92SDimitry Andric // Do not pool globals that are part of llvm.used or llvm.compiler.end.
197c9157d92SDimitry Andric if (AllUsedGlobals.contains(&Global))
198c9157d92SDimitry Andric continue;
199c9157d92SDimitry Andric
200c9157d92SDimitry Andric if (!hasReplaceableUsers(Global))
201c9157d92SDimitry Andric continue;
202c9157d92SDimitry Andric
203c9157d92SDimitry Andric Align AlignOfGlobal = Global.getAlign().valueOrOne();
204c9157d92SDimitry Andric
205c9157d92SDimitry Andric // TODO: At this point do not allow over-aligned types. Adding a type
206c9157d92SDimitry Andric // with larger alignment may lose the larger alignment once it is
207c9157d92SDimitry Andric // added to the struct.
208c9157d92SDimitry Andric // Fix this in a future patch.
209c9157d92SDimitry Andric if (AlignOfGlobal.value() > ConstData->getElementByteSize())
210c9157d92SDimitry Andric continue;
211c9157d92SDimitry Andric
212c9157d92SDimitry Andric // Make sure that the global is only visible inside the compilation unit.
213c9157d92SDimitry Andric if (Global.getLinkage() != GlobalValue::PrivateLinkage &&
214c9157d92SDimitry Andric Global.getLinkage() != GlobalValue::InternalLinkage)
215c9157d92SDimitry Andric continue;
216c9157d92SDimitry Andric
217c9157d92SDimitry Andric LLVM_DEBUG(dbgs() << "Constant data of Global: ");
218c9157d92SDimitry Andric LLVM_DEBUG(ConstData->dump());
219c9157d92SDimitry Andric LLVM_DEBUG(dbgs() << "\n\n");
220c9157d92SDimitry Andric
221c9157d92SDimitry Andric MergeableStrings.push_back(&Global);
222c9157d92SDimitry Andric if (MaxAlignment < AlignOfGlobal)
223c9157d92SDimitry Andric MaxAlignment = AlignOfGlobal;
224c9157d92SDimitry Andric
225c9157d92SDimitry Andric // If we have already reached the maximum number of pooled strings then
226c9157d92SDimitry Andric // there is no point in looking for more.
227c9157d92SDimitry Andric if (MergeableStrings.size() >= MaxStringsPooled)
228c9157d92SDimitry Andric break;
229c9157d92SDimitry Andric }
230c9157d92SDimitry Andric }
231c9157d92SDimitry Andric
mergeModuleStringPool(Module & M)232c9157d92SDimitry Andric bool PPCMergeStringPool::mergeModuleStringPool(Module &M) {
233c9157d92SDimitry Andric
234c9157d92SDimitry Andric LLVM_DEBUG(dbgs() << "Merging string pool for module: " << M.getName()
235c9157d92SDimitry Andric << "\n");
236c9157d92SDimitry Andric LLVM_DEBUG(dbgs() << "Number of globals is: " << M.global_size() << "\n");
237c9157d92SDimitry Andric
238c9157d92SDimitry Andric collectCandidateConstants(M);
239c9157d92SDimitry Andric
240c9157d92SDimitry Andric // If we have too few constants in the module that are merge candidates we
241c9157d92SDimitry Andric // will skip doing the merging.
242c9157d92SDimitry Andric if (MergeableStrings.size() < MinStringsBeforePool)
243c9157d92SDimitry Andric return false;
244c9157d92SDimitry Andric
245c9157d92SDimitry Andric // Sort the global constants to make access more efficient.
246c9157d92SDimitry Andric std::sort(MergeableStrings.begin(), MergeableStrings.end(), CompareConstants);
247c9157d92SDimitry Andric
248c9157d92SDimitry Andric SmallVector<Constant *> ConstantsInStruct;
249c9157d92SDimitry Andric for (GlobalVariable *GV : MergeableStrings)
250c9157d92SDimitry Andric ConstantsInStruct.push_back(GV->getInitializer());
251c9157d92SDimitry Andric
252c9157d92SDimitry Andric // Use an anonymous struct to pool the strings.
253c9157d92SDimitry Andric // TODO: This pass uses a single anonymous struct for all of the pooled
254c9157d92SDimitry Andric // entries. This may cause a performance issue in the situation where
255c9157d92SDimitry Andric // computing the offset requires two instructions (addis, addi). For the
256c9157d92SDimitry Andric // future we may want to split this into multiple structs.
257c9157d92SDimitry Andric Constant *ConstantPool = ConstantStruct::getAnon(ConstantsInStruct);
258c9157d92SDimitry Andric PooledStructType = ConstantPool->getType();
259c9157d92SDimitry Andric
260c9157d92SDimitry Andric // The GlobalVariable constructor calls
261c9157d92SDimitry Andric // MM->insertGlobalVariable(PooledGlobal).
262c9157d92SDimitry Andric GlobalVariable *PooledGlobal =
263c9157d92SDimitry Andric new GlobalVariable(M, PooledStructType,
264c9157d92SDimitry Andric /* isConstant */ true, GlobalValue::PrivateLinkage,
265c9157d92SDimitry Andric ConstantPool, "__ModuleStringPool");
266c9157d92SDimitry Andric PooledGlobal->setAlignment(MaxAlignment);
267c9157d92SDimitry Andric
268c9157d92SDimitry Andric LLVM_DEBUG(dbgs() << "Constructing global variable for string pool: ");
269c9157d92SDimitry Andric LLVM_DEBUG(PooledGlobal->dump());
270c9157d92SDimitry Andric
271c9157d92SDimitry Andric Context = &M.getContext();
272c9157d92SDimitry Andric size_t ElementIndex = 0;
273c9157d92SDimitry Andric for (GlobalVariable *GV : MergeableStrings) {
274c9157d92SDimitry Andric
275c9157d92SDimitry Andric LLVM_DEBUG(dbgs() << "The global:\n");
276c9157d92SDimitry Andric LLVM_DEBUG(GV->dump());
277c9157d92SDimitry Andric LLVM_DEBUG(dbgs() << "Has " << GV->getNumUses() << " uses.\n");
278c9157d92SDimitry Andric
279c9157d92SDimitry Andric // Access to the pooled constant strings require an offset. Add a GEP
280c9157d92SDimitry Andric // before every use in order to compute this offset.
281c9157d92SDimitry Andric replaceUsesWithGEP(GV, PooledGlobal, ElementIndex);
282c9157d92SDimitry Andric
283c9157d92SDimitry Andric // This GV has no more uses so we can erase it.
284c9157d92SDimitry Andric if (GV->use_empty())
285c9157d92SDimitry Andric GV->eraseFromParent();
286c9157d92SDimitry Andric
287c9157d92SDimitry Andric NumPooledStrings++;
288c9157d92SDimitry Andric ElementIndex++;
289c9157d92SDimitry Andric }
290c9157d92SDimitry Andric return true;
291c9157d92SDimitry Andric }
292c9157d92SDimitry Andric
293c9157d92SDimitry Andric // For pooled strings we need to add the offset into the pool for each string.
294c9157d92SDimitry Andric // This is done by adding a Get Element Pointer (GEP) before each user. This
295c9157d92SDimitry Andric // function adds the GEP.
replaceUsesWithGEP(GlobalVariable * GlobalToReplace,GlobalVariable * GPool,unsigned ElementIndex)296c9157d92SDimitry Andric void PPCMergeStringPool::replaceUsesWithGEP(GlobalVariable *GlobalToReplace,
297c9157d92SDimitry Andric GlobalVariable *GPool,
298c9157d92SDimitry Andric unsigned ElementIndex) {
299c9157d92SDimitry Andric SmallVector<Value *, 2> Indices;
300c9157d92SDimitry Andric Indices.push_back(ConstantInt::get(Type::getInt32Ty(*Context), 0));
301c9157d92SDimitry Andric Indices.push_back(ConstantInt::get(Type::getInt32Ty(*Context), ElementIndex));
302c9157d92SDimitry Andric
303*f5fb251aSDimitry Andric Constant *ConstGEP =
304*f5fb251aSDimitry Andric ConstantExpr::getInBoundsGetElementPtr(PooledStructType, GPool, Indices);
305c9157d92SDimitry Andric LLVM_DEBUG(dbgs() << "Replacing this global:\n");
306c9157d92SDimitry Andric LLVM_DEBUG(GlobalToReplace->dump());
307c9157d92SDimitry Andric LLVM_DEBUG(dbgs() << "with this:\n");
308f1e32799SDimitry Andric LLVM_DEBUG(ConstGEP->dump());
309f1e32799SDimitry Andric GlobalToReplace->replaceAllUsesWith(ConstGEP);
310c9157d92SDimitry Andric }
311c9157d92SDimitry Andric
312c9157d92SDimitry Andric } // namespace
313c9157d92SDimitry Andric
314c9157d92SDimitry Andric char PPCMergeStringPool::ID = 0;
315c9157d92SDimitry Andric
316c9157d92SDimitry Andric INITIALIZE_PASS(PPCMergeStringPool, DEBUG_TYPE, "PPC Merge String Pool", false,
317c9157d92SDimitry Andric false)
318c9157d92SDimitry Andric
createPPCMergeStringPoolPass()319c9157d92SDimitry Andric ModulePass *llvm::createPPCMergeStringPoolPass() {
320c9157d92SDimitry Andric return new PPCMergeStringPool();
321c9157d92SDimitry Andric }
322