blob: f51660223ba540d0a18b8f5cc4504303a0149ae6 [file] [log] [blame]
Tim Northover3b0846e2014-05-24 12:50:23 +00001//=- AArch64PromoteConstant.cpp --- Promote constant to global for AArch64 -==//
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 file implements the AArch64PromoteConstant pass which promotes constants
11// to global variables when this is likely to be more efficient. Currently only
12// types related to constant vector (i.e., constant vector, array of constant
13// vectors, constant structure with a constant vector field, etc.) are promoted
14// to global variables. Constant vectors are likely to be lowered in target
15// constant pool during instruction selection already; therefore, the access
16// will remain the same (memory load), but the structure types are not split
17// into different constant pool accesses for each field. A bonus side effect is
18// that created globals may be merged by the global merge pass.
19//
20// FIXME: This pass may be useful for other targets too.
21//===----------------------------------------------------------------------===//
22
23#include "AArch64.h"
Tim Northover3b0846e2014-05-24 12:50:23 +000024#include "llvm/ADT/DenseMap.h"
Benjamin Kramer69b4ad22015-02-06 14:43:55 +000025#include "llvm/ADT/SmallPtrSet.h"
Tim Northover3b0846e2014-05-24 12:50:23 +000026#include "llvm/ADT/SmallVector.h"
Benjamin Kramer1f8930e2014-07-25 11:42:14 +000027#include "llvm/ADT/Statistic.h"
Tim Northover3b0846e2014-05-24 12:50:23 +000028#include "llvm/IR/Constants.h"
29#include "llvm/IR/Dominators.h"
30#include "llvm/IR/Function.h"
31#include "llvm/IR/GlobalVariable.h"
Benjamin Kramer1f8930e2014-07-25 11:42:14 +000032#include "llvm/IR/IRBuilder.h"
Tim Northover3b0846e2014-05-24 12:50:23 +000033#include "llvm/IR/InlineAsm.h"
Benjamin Kramer69b4ad22015-02-06 14:43:55 +000034#include "llvm/IR/InstIterator.h"
Tim Northover3b0846e2014-05-24 12:50:23 +000035#include "llvm/IR/Instructions.h"
36#include "llvm/IR/IntrinsicInst.h"
Tim Northover3b0846e2014-05-24 12:50:23 +000037#include "llvm/IR/Module.h"
38#include "llvm/Pass.h"
39#include "llvm/Support/CommandLine.h"
40#include "llvm/Support/Debug.h"
Benjamin Kramer799003b2015-03-23 19:32:43 +000041#include "llvm/Support/raw_ostream.h"
Tim Northover3b0846e2014-05-24 12:50:23 +000042
43using namespace llvm;
44
45#define DEBUG_TYPE "aarch64-promote-const"
46
47// Stress testing mode - disable heuristics.
48static cl::opt<bool> Stress("aarch64-stress-promote-const", cl::Hidden,
49 cl::desc("Promote all vector constants"));
50
51STATISTIC(NumPromoted, "Number of promoted constants");
52STATISTIC(NumPromotedUses, "Number of promoted constants uses");
53
54//===----------------------------------------------------------------------===//
55// AArch64PromoteConstant
56//===----------------------------------------------------------------------===//
57
58namespace {
59/// Promotes interesting constant into global variables.
60/// The motivating example is:
61/// static const uint16_t TableA[32] = {
62/// 41944, 40330, 38837, 37450, 36158, 34953, 33826, 32768,
63/// 31776, 30841, 29960, 29128, 28340, 27595, 26887, 26215,
64/// 25576, 24967, 24386, 23832, 23302, 22796, 22311, 21846,
65/// 21400, 20972, 20561, 20165, 19785, 19419, 19066, 18725,
66/// };
67///
68/// uint8x16x4_t LoadStatic(void) {
69/// uint8x16x4_t ret;
70/// ret.val[0] = vld1q_u16(TableA + 0);
71/// ret.val[1] = vld1q_u16(TableA + 8);
72/// ret.val[2] = vld1q_u16(TableA + 16);
73/// ret.val[3] = vld1q_u16(TableA + 24);
74/// return ret;
75/// }
76///
77/// The constants in this example are folded into the uses. Thus, 4 different
78/// constants are created.
79///
80/// As their type is vector the cheapest way to create them is to load them
81/// for the memory.
82///
83/// Therefore the final assembly final has 4 different loads. With this pass
84/// enabled, only one load is issued for the constants.
85class AArch64PromoteConstant : public ModulePass {
86
87public:
Duncan P. N. Exon Smithc3fa1ed2016-03-18 23:30:54 +000088 struct PromotedConstant {
89 bool ShouldConvert = false;
90 GlobalVariable *GV = nullptr;
91 };
92 typedef SmallDenseMap<Constant *, PromotedConstant, 16> PromotionCacheTy;
93
94 struct UpdateRecord {
95 Constant *C;
96 Instruction *User;
97 unsigned Op;
98
99 UpdateRecord(Constant *C, Instruction *User, unsigned Op)
100 : C(C), User(User), Op(Op) {}
101 };
102
Tim Northover3b0846e2014-05-24 12:50:23 +0000103 static char ID;
104 AArch64PromoteConstant() : ModulePass(ID) {}
105
106 const char *getPassName() const override { return "AArch64 Promote Constant"; }
107
108 /// Iterate over the functions and promote the interesting constants into
109 /// global variables with module scope.
110 bool runOnModule(Module &M) override {
111 DEBUG(dbgs() << getPassName() << '\n');
112 bool Changed = false;
Duncan P. N. Exon Smithc3fa1ed2016-03-18 23:30:54 +0000113 PromotionCacheTy PromotionCache;
Tim Northover3b0846e2014-05-24 12:50:23 +0000114 for (auto &MF : M) {
Duncan P. N. Exon Smithc3fa1ed2016-03-18 23:30:54 +0000115 Changed |= runOnFunction(MF, PromotionCache);
Tim Northover3b0846e2014-05-24 12:50:23 +0000116 }
117 return Changed;
118 }
119
120private:
121 /// Look for interesting constants used within the given function.
122 /// Promote them into global variables, load these global variables within
123 /// the related function, so that the number of inserted load is minimal.
Duncan P. N. Exon Smithc3fa1ed2016-03-18 23:30:54 +0000124 bool runOnFunction(Function &F, PromotionCacheTy &PromotionCache);
Tim Northover3b0846e2014-05-24 12:50:23 +0000125
126 // This transformation requires dominator info
127 void getAnalysisUsage(AnalysisUsage &AU) const override {
128 AU.setPreservesCFG();
129 AU.addRequired<DominatorTreeWrapperPass>();
130 AU.addPreserved<DominatorTreeWrapperPass>();
131 }
132
Benjamin Kramer69b4ad22015-02-06 14:43:55 +0000133 /// Type to store a list of Uses.
Duncan P. N. Exon Smithc3fa1ed2016-03-18 23:30:54 +0000134 typedef SmallVector<std::pair<Instruction *, unsigned>, 4> Uses;
Tim Northover3b0846e2014-05-24 12:50:23 +0000135 /// Map an insertion point to all the uses it dominates.
Benjamin Kramer69b4ad22015-02-06 14:43:55 +0000136 typedef DenseMap<Instruction *, Uses> InsertionPoints;
Tim Northover3b0846e2014-05-24 12:50:23 +0000137
138 /// Find the closest point that dominates the given Use.
Duncan P. N. Exon Smithc3fa1ed2016-03-18 23:30:54 +0000139 Instruction *findInsertionPoint(Instruction &User, unsigned OpNo);
Tim Northover3b0846e2014-05-24 12:50:23 +0000140
141 /// Check if the given insertion point is dominated by an existing
142 /// insertion point.
143 /// If true, the given use is added to the list of dominated uses for
144 /// the related existing point.
145 /// \param NewPt the insertion point to be checked
Duncan P. N. Exon Smith20be8762016-03-21 22:13:44 +0000146 /// \param User the user of the constant
147 /// \param OpNo the operand number of the use
Tim Northover3b0846e2014-05-24 12:50:23 +0000148 /// \param InsertPts existing insertion points
149 /// \pre NewPt and all instruction in InsertPts belong to the same function
150 /// \return true if one of the insertion point in InsertPts dominates NewPt,
151 /// false otherwise
Duncan P. N. Exon Smithc3fa1ed2016-03-18 23:30:54 +0000152 bool isDominated(Instruction *NewPt, Instruction *User, unsigned OpNo,
153 InsertionPoints &InsertPts);
Tim Northover3b0846e2014-05-24 12:50:23 +0000154
155 /// Check if the given insertion point can be merged with an existing
156 /// insertion point in a common dominator.
157 /// If true, the given use is added to the list of the created insertion
158 /// point.
159 /// \param NewPt the insertion point to be checked
Duncan P. N. Exon Smith20be8762016-03-21 22:13:44 +0000160 /// \param User the user of the constant
161 /// \param OpNo the operand number of the use
Tim Northover3b0846e2014-05-24 12:50:23 +0000162 /// \param InsertPts existing insertion points
163 /// \pre NewPt and all instruction in InsertPts belong to the same function
164 /// \pre isDominated returns false for the exact same parameters.
165 /// \return true if it exists an insertion point in InsertPts that could
166 /// have been merged with NewPt in a common dominator,
167 /// false otherwise
Duncan P. N. Exon Smithc3fa1ed2016-03-18 23:30:54 +0000168 bool tryAndMerge(Instruction *NewPt, Instruction *User, unsigned OpNo,
169 InsertionPoints &InsertPts);
Tim Northover3b0846e2014-05-24 12:50:23 +0000170
171 /// Compute the minimal insertion points to dominates all the interesting
172 /// uses of value.
173 /// Insertion points are group per function and each insertion point
174 /// contains a list of all the uses it dominates within the related function
Duncan P. N. Exon Smith20be8762016-03-21 22:13:44 +0000175 /// \param User the user of the constant
176 /// \param OpNo the operand number of the constant
177 /// \param[out] InsertPts output storage of the analysis
Duncan P. N. Exon Smithc3fa1ed2016-03-18 23:30:54 +0000178 void computeInsertionPoint(Instruction *User, unsigned OpNo,
179 InsertionPoints &InsertPts);
Tim Northover3b0846e2014-05-24 12:50:23 +0000180
181 /// Insert a definition of a new global variable at each point contained in
182 /// InsPtsPerFunc and update the related uses (also contained in
183 /// InsPtsPerFunc).
Duncan P. N. Exon Smithc3fa1ed2016-03-18 23:30:54 +0000184 void insertDefinitions(Function &F, GlobalVariable &GV,
185 InsertionPoints &InsertPts);
Tim Northover3b0846e2014-05-24 12:50:23 +0000186
Duncan P. N. Exon Smithc3fa1ed2016-03-18 23:30:54 +0000187 /// Sort the updates in a deterministic way.
188 void sortUpdates(SmallVectorImpl<UpdateRecord> &Updates);
Tim Northover3b0846e2014-05-24 12:50:23 +0000189
Duncan P. N. Exon Smithc3fa1ed2016-03-18 23:30:54 +0000190 /// Do the constant promotion indicated by the Updates records, keeping track
191 /// of globals in PromotionCache.
192 void promoteConstants(Function &F, SmallVectorImpl<UpdateRecord> &Updates,
193 PromotionCacheTy &PromotionCache);
Tim Northover3b0846e2014-05-24 12:50:23 +0000194
195 /// Transfer the list of dominated uses of IPI to NewPt in InsertPts.
Benjamin Kramer69b4ad22015-02-06 14:43:55 +0000196 /// Append Use to this list and delete the entry of IPI in InsertPts.
Duncan P. N. Exon Smithc3fa1ed2016-03-18 23:30:54 +0000197 static void appendAndTransferDominatedUses(Instruction *NewPt,
198 Instruction *User, unsigned OpNo,
Tim Northover3b0846e2014-05-24 12:50:23 +0000199 InsertionPoints::iterator &IPI,
200 InsertionPoints &InsertPts) {
201 // Record the dominated use.
Duncan P. N. Exon Smithc3fa1ed2016-03-18 23:30:54 +0000202 IPI->second.emplace_back(User, OpNo);
Tim Northover3b0846e2014-05-24 12:50:23 +0000203 // Transfer the dominated uses of IPI to NewPt
204 // Inserting into the DenseMap may invalidate existing iterator.
Sanjoy Dase5d14662015-03-02 00:17:18 +0000205 // Keep a copy of the key to find the iterator to erase. Keep a copy of the
206 // value so that we don't have to dereference IPI->second.
Tim Northover3b0846e2014-05-24 12:50:23 +0000207 Instruction *OldInstr = IPI->first;
Sanjoy Dase5d14662015-03-02 00:17:18 +0000208 Uses OldUses = std::move(IPI->second);
209 InsertPts[NewPt] = std::move(OldUses);
Tim Northover3b0846e2014-05-24 12:50:23 +0000210 // Erase IPI.
Benjamin Kramer69b4ad22015-02-06 14:43:55 +0000211 InsertPts.erase(OldInstr);
Tim Northover3b0846e2014-05-24 12:50:23 +0000212 }
213};
214} // end anonymous namespace
215
216char AArch64PromoteConstant::ID = 0;
217
218namespace llvm {
219void initializeAArch64PromoteConstantPass(PassRegistry &);
220}
221
222INITIALIZE_PASS_BEGIN(AArch64PromoteConstant, "aarch64-promote-const",
223 "AArch64 Promote Constant Pass", false, false)
224INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass)
225INITIALIZE_PASS_END(AArch64PromoteConstant, "aarch64-promote-const",
226 "AArch64 Promote Constant Pass", false, false)
227
228ModulePass *llvm::createAArch64PromoteConstantPass() {
229 return new AArch64PromoteConstant();
230}
231
232/// Check if the given type uses a vector type.
233static bool isConstantUsingVectorTy(const Type *CstTy) {
234 if (CstTy->isVectorTy())
235 return true;
236 if (CstTy->isStructTy()) {
237 for (unsigned EltIdx = 0, EndEltIdx = CstTy->getStructNumElements();
238 EltIdx < EndEltIdx; ++EltIdx)
239 if (isConstantUsingVectorTy(CstTy->getStructElementType(EltIdx)))
240 return true;
241 } else if (CstTy->isArrayTy())
242 return isConstantUsingVectorTy(CstTy->getArrayElementType());
243 return false;
244}
245
246/// Check if the given use (Instruction + OpIdx) of Cst should be converted into
247/// a load of a global variable initialized with Cst.
248/// A use should be converted if it is legal to do so.
249/// For instance, it is not legal to turn the mask operand of a shuffle vector
250/// into a load of a global variable.
251static bool shouldConvertUse(const Constant *Cst, const Instruction *Instr,
252 unsigned OpIdx) {
253 // shufflevector instruction expects a const for the mask argument, i.e., the
254 // third argument. Do not promote this use in that case.
255 if (isa<const ShuffleVectorInst>(Instr) && OpIdx == 2)
256 return false;
257
258 // extractvalue instruction expects a const idx.
259 if (isa<const ExtractValueInst>(Instr) && OpIdx > 0)
260 return false;
261
262 // extractvalue instruction expects a const idx.
263 if (isa<const InsertValueInst>(Instr) && OpIdx > 1)
264 return false;
265
266 if (isa<const AllocaInst>(Instr) && OpIdx > 0)
267 return false;
268
269 // Alignment argument must be constant.
270 if (isa<const LoadInst>(Instr) && OpIdx > 0)
271 return false;
272
273 // Alignment argument must be constant.
274 if (isa<const StoreInst>(Instr) && OpIdx > 1)
275 return false;
276
277 // Index must be constant.
278 if (isa<const GetElementPtrInst>(Instr) && OpIdx > 0)
279 return false;
280
281 // Personality function and filters must be constant.
282 // Give up on that instruction.
283 if (isa<const LandingPadInst>(Instr))
284 return false;
285
286 // Switch instruction expects constants to compare to.
287 if (isa<const SwitchInst>(Instr))
288 return false;
289
290 // Expected address must be a constant.
291 if (isa<const IndirectBrInst>(Instr))
292 return false;
293
294 // Do not mess with intrinsics.
295 if (isa<const IntrinsicInst>(Instr))
296 return false;
297
298 // Do not mess with inline asm.
299 const CallInst *CI = dyn_cast<const CallInst>(Instr);
Eric Christopher114fa1c2016-02-29 22:50:49 +0000300 return !(CI && isa<const InlineAsm>(CI->getCalledValue()));
Tim Northover3b0846e2014-05-24 12:50:23 +0000301}
302
303/// Check if the given Cst should be converted into
304/// a load of a global variable initialized with Cst.
305/// A constant should be converted if it is likely that the materialization of
306/// the constant will be tricky. Thus, we give up on zero or undef values.
307///
308/// \todo Currently, accept only vector related types.
309/// Also we give up on all simple vector type to keep the existing
310/// behavior. Otherwise, we should push here all the check of the lowering of
311/// BUILD_VECTOR. By giving up, we lose the potential benefit of merging
312/// constant via global merge and the fact that the same constant is stored
313/// only once with this method (versus, as many function that uses the constant
314/// for the regular approach, even for float).
315/// Again, the simplest solution would be to promote every
316/// constant and rematerialize them when they are actually cheap to create.
Duncan P. N. Exon Smithc3fa1ed2016-03-18 23:30:54 +0000317static bool shouldConvertImpl(const Constant *Cst) {
Tim Northover3b0846e2014-05-24 12:50:23 +0000318 if (isa<const UndefValue>(Cst))
319 return false;
320
321 // FIXME: In some cases, it may be interesting to promote in memory
322 // a zero initialized constant.
323 // E.g., when the type of Cst require more instructions than the
324 // adrp/add/load sequence or when this sequence can be shared by several
325 // instances of Cst.
326 // Ideally, we could promote this into a global and rematerialize the constant
327 // when it was a bad idea.
328 if (Cst->isZeroValue())
329 return false;
330
331 if (Stress)
332 return true;
333
334 // FIXME: see function \todo
335 if (Cst->getType()->isVectorTy())
336 return false;
337 return isConstantUsingVectorTy(Cst->getType());
338}
339
Duncan P. N. Exon Smithc3fa1ed2016-03-18 23:30:54 +0000340static bool
341shouldConvert(Constant &C,
342 AArch64PromoteConstant::PromotionCacheTy &PromotionCache) {
343 auto Converted = PromotionCache.insert(
344 std::make_pair(&C, AArch64PromoteConstant::PromotedConstant()));
345 if (Converted.second)
346 Converted.first->second.ShouldConvert = shouldConvertImpl(&C);
347 return Converted.first->second.ShouldConvert;
Tim Northover3b0846e2014-05-24 12:50:23 +0000348}
349
Duncan P. N. Exon Smithc3fa1ed2016-03-18 23:30:54 +0000350Instruction *AArch64PromoteConstant::findInsertionPoint(Instruction &User,
351 unsigned OpNo) {
352 // If this user is a phi, the insertion point is in the related
353 // incoming basic block.
354 if (PHINode *PhiInst = dyn_cast<PHINode>(&User))
355 return PhiInst->getIncomingBlock(OpNo)->getTerminator();
356
357 return &User;
358}
359
360bool AArch64PromoteConstant::isDominated(Instruction *NewPt, Instruction *User,
361 unsigned OpNo,
Tim Northover3b0846e2014-05-24 12:50:23 +0000362 InsertionPoints &InsertPts) {
363
364 DominatorTree &DT = getAnalysis<DominatorTreeWrapperPass>(
365 *NewPt->getParent()->getParent()).getDomTree();
366
367 // Traverse all the existing insertion points and check if one is dominating
368 // NewPt. If it is, remember that.
369 for (auto &IPI : InsertPts) {
370 if (NewPt == IPI.first || DT.dominates(IPI.first, NewPt) ||
371 // When IPI.first is a terminator instruction, DT may think that
372 // the result is defined on the edge.
373 // Here we are testing the insertion point, not the definition.
374 (IPI.first->getParent() != NewPt->getParent() &&
375 DT.dominates(IPI.first->getParent(), NewPt->getParent()))) {
376 // No need to insert this point. Just record the dominated use.
377 DEBUG(dbgs() << "Insertion point dominated by:\n");
378 DEBUG(IPI.first->print(dbgs()));
379 DEBUG(dbgs() << '\n');
Duncan P. N. Exon Smithc3fa1ed2016-03-18 23:30:54 +0000380 IPI.second.emplace_back(User, OpNo);
Tim Northover3b0846e2014-05-24 12:50:23 +0000381 return true;
382 }
383 }
384 return false;
385}
386
Duncan P. N. Exon Smithc3fa1ed2016-03-18 23:30:54 +0000387bool AArch64PromoteConstant::tryAndMerge(Instruction *NewPt, Instruction *User,
388 unsigned OpNo,
Tim Northover3b0846e2014-05-24 12:50:23 +0000389 InsertionPoints &InsertPts) {
390 DominatorTree &DT = getAnalysis<DominatorTreeWrapperPass>(
391 *NewPt->getParent()->getParent()).getDomTree();
392 BasicBlock *NewBB = NewPt->getParent();
393
394 // Traverse all the existing insertion point and check if one is dominated by
395 // NewPt and thus useless or can be combined with NewPt into a common
396 // dominator.
397 for (InsertionPoints::iterator IPI = InsertPts.begin(),
398 EndIPI = InsertPts.end();
399 IPI != EndIPI; ++IPI) {
400 BasicBlock *CurBB = IPI->first->getParent();
401 if (NewBB == CurBB) {
402 // Instructions are in the same block.
403 // By construction, NewPt is dominating the other.
404 // Indeed, isDominated returned false with the exact same arguments.
405 DEBUG(dbgs() << "Merge insertion point with:\n");
406 DEBUG(IPI->first->print(dbgs()));
407 DEBUG(dbgs() << "\nat considered insertion point.\n");
Duncan P. N. Exon Smithc3fa1ed2016-03-18 23:30:54 +0000408 appendAndTransferDominatedUses(NewPt, User, OpNo, IPI, InsertPts);
Tim Northover3b0846e2014-05-24 12:50:23 +0000409 return true;
410 }
411
412 // Look for a common dominator
413 BasicBlock *CommonDominator = DT.findNearestCommonDominator(NewBB, CurBB);
414 // If none exists, we cannot merge these two points.
415 if (!CommonDominator)
416 continue;
417
418 if (CommonDominator != NewBB) {
419 // By construction, the CommonDominator cannot be CurBB.
420 assert(CommonDominator != CurBB &&
421 "Instruction has not been rejected during isDominated check!");
422 // Take the last instruction of the CommonDominator as insertion point
423 NewPt = CommonDominator->getTerminator();
424 }
425 // else, CommonDominator is the block of NewBB, hence NewBB is the last
426 // possible insertion point in that block.
427 DEBUG(dbgs() << "Merge insertion point with:\n");
428 DEBUG(IPI->first->print(dbgs()));
429 DEBUG(dbgs() << '\n');
430 DEBUG(NewPt->print(dbgs()));
431 DEBUG(dbgs() << '\n');
Duncan P. N. Exon Smithc3fa1ed2016-03-18 23:30:54 +0000432 appendAndTransferDominatedUses(NewPt, User, OpNo, IPI, InsertPts);
Tim Northover3b0846e2014-05-24 12:50:23 +0000433 return true;
434 }
435 return false;
436}
437
Duncan P. N. Exon Smithc3fa1ed2016-03-18 23:30:54 +0000438void AArch64PromoteConstant::computeInsertionPoint(
439 Instruction *User, unsigned OpNo, InsertionPoints &InsertPts) {
440 DEBUG(dbgs() << "Considered use, opidx " << OpNo << ":\n");
441 DEBUG(User->print(dbgs()));
Tim Northover3b0846e2014-05-24 12:50:23 +0000442 DEBUG(dbgs() << '\n');
443
Duncan P. N. Exon Smithc3fa1ed2016-03-18 23:30:54 +0000444 Instruction *InsertionPoint = findInsertionPoint(*User, OpNo);
445
446 DEBUG(dbgs() << "Considered insertion point:\n");
447 DEBUG(InsertionPoint->print(dbgs()));
448 DEBUG(dbgs() << '\n');
449
450 if (isDominated(InsertionPoint, User, OpNo, InsertPts))
451 return;
452 // This insertion point is useful, check if we can merge some insertion
453 // point in a common dominator or if NewPt dominates an existing one.
454 if (tryAndMerge(InsertionPoint, User, OpNo, InsertPts))
455 return;
456
457 DEBUG(dbgs() << "Keep considered insertion point\n");
458
459 // It is definitely useful by its own
460 InsertPts[InsertionPoint].emplace_back(User, OpNo);
Tim Northover3b0846e2014-05-24 12:50:23 +0000461}
462
Duncan P. N. Exon Smithc3fa1ed2016-03-18 23:30:54 +0000463static void ensurePromotedGV(Function &F, Constant &C,
464 AArch64PromoteConstant::PromotedConstant &PC) {
465 assert(PC.ShouldConvert &&
466 "Expected that we should convert this to a global");
467 if (PC.GV)
468 return;
469 PC.GV = new GlobalVariable(
470 *F.getParent(), C.getType(), true, GlobalValue::InternalLinkage, nullptr,
471 "_PromotedConst", nullptr, GlobalVariable::NotThreadLocal);
472 PC.GV->setInitializer(&C);
473 DEBUG(dbgs() << "Global replacement: ");
474 DEBUG(PC.GV->print(dbgs()));
475 DEBUG(dbgs() << '\n');
476 ++NumPromoted;
477}
478
479void AArch64PromoteConstant::insertDefinitions(Function &F,
480 GlobalVariable &PromotedGV,
481 InsertionPoints &InsertPts) {
482#ifndef NDEBUG
483 // Do more checking for debug purposes.
484 DominatorTree &DT = getAnalysis<DominatorTreeWrapperPass>(F).getDomTree();
485#endif
486 assert(!InsertPts.empty() && "Empty uses does not need a definition");
487
488 for (const auto &IPI : InsertPts) {
489 // Create the load of the global variable.
490 IRBuilder<> Builder(IPI.first);
491 LoadInst *LoadedCst = Builder.CreateLoad(&PromotedGV);
492 DEBUG(dbgs() << "**********\n");
493 DEBUG(dbgs() << "New def: ");
494 DEBUG(LoadedCst->print(dbgs()));
495 DEBUG(dbgs() << '\n');
496
497 // Update the dominated uses.
498 for (auto Use : IPI.second) {
499#ifndef NDEBUG
500 assert(DT.dominates(LoadedCst,
501 findInsertionPoint(*Use.first, Use.second)) &&
502 "Inserted definition does not dominate all its uses!");
503#endif
504 DEBUG({
505 dbgs() << "Use to update " << Use.second << ":";
506 Use.first->print(dbgs());
507 dbgs() << '\n';
508 });
509 Use.first->setOperand(Use.second, LoadedCst);
510 ++NumPromotedUses;
511 }
512 }
513}
514
515void AArch64PromoteConstant::sortUpdates(
516 SmallVectorImpl<UpdateRecord> &Updates) {
517 // The order the constants were inserted is deterministic (unlike their
518 // address).
519 SmallDenseMap<const Constant *, unsigned, 128> InsertionOrder;
520 for (const auto &Record : Updates)
521 InsertionOrder.insert(std::make_pair(Record.C, InsertionOrder.size()));
522
523 // This is already sorted by Instruction ordering in the function and operand
524 // number, which is a good first step. Now reorder by constant.
525 std::stable_sort(
526 Updates.begin(), Updates.end(),
527 [&InsertionOrder](const UpdateRecord &L, const UpdateRecord &R) {
528 return InsertionOrder.lookup(L.C) < InsertionOrder.lookup(R.C);
529 });
530}
531
532void AArch64PromoteConstant::promoteConstants(
533 Function &F, SmallVectorImpl<UpdateRecord> &Updates,
534 PromotionCacheTy &PromotionCache) {
535 // Promote the constants.
536 for (auto U = Updates.begin(), E = Updates.end(); U != E;) {
537 DEBUG(dbgs() << "** Compute insertion points **\n");
538 auto First = U;
539 Constant *C = First->C;
540 InsertionPoints InsertPts;
541 do {
542 computeInsertionPoint(U->User, U->Op, InsertPts);
543 } while (++U != E && U->C == C);
544
545 auto &Promotion = PromotionCache[C];
546 ensurePromotedGV(F, *C, Promotion);
547 insertDefinitions(F, *Promotion.GV, InsertPts);
548 }
549}
550
551bool AArch64PromoteConstant::runOnFunction(Function &F,
552 PromotionCacheTy &PromotionCache) {
Tim Northover3b0846e2014-05-24 12:50:23 +0000553 // Look for instructions using constant vector. Promote that constant to a
554 // global variable. Create as few loads of this variable as possible and
555 // update the uses accordingly.
Duncan P. N. Exon Smithc3fa1ed2016-03-18 23:30:54 +0000556 SmallVector<UpdateRecord, 64> Updates;
Nico Rieck78199512015-08-06 19:10:45 +0000557 for (Instruction &I : instructions(&F)) {
Benjamin Kramer69b4ad22015-02-06 14:43:55 +0000558 // Traverse the operand, looking for constant vectors. Replace them by a
559 // load of a global variable of constant vector type.
Duncan P. N. Exon Smithc3fa1ed2016-03-18 23:30:54 +0000560 for (Use &U : I.operands()) {
561 Constant *Cst = dyn_cast<Constant>(U);
Benjamin Kramer69b4ad22015-02-06 14:43:55 +0000562 // There is no point in promoting global values as they are already
563 // global. Do not promote constant expressions either, as they may
564 // require some code expansion.
Duncan P. N. Exon Smithc3fa1ed2016-03-18 23:30:54 +0000565 if (!Cst || isa<GlobalValue>(Cst) || isa<ConstantExpr>(Cst))
566 continue;
567
568 // Check if this constant is worth promoting.
569 if (!shouldConvert(*Cst, PromotionCache))
570 continue;
571
572 // Check if this use should be promoted.
573 unsigned OpNo = &U - I.op_begin();
574 if (!shouldConvertUse(Cst, &I, OpNo))
575 continue;
576
577 Updates.emplace_back(Cst, &I, OpNo);
Tim Northover3b0846e2014-05-24 12:50:23 +0000578 }
579 }
Duncan P. N. Exon Smithc3fa1ed2016-03-18 23:30:54 +0000580
581 if (Updates.empty())
582 return false;
583
584 promoteConstants(F, Updates, PromotionCache);
585 return true;
Tim Northover3b0846e2014-05-24 12:50:23 +0000586}