45 #define DEBUG_TYPE "aarch64-promote-const"
49 cl::desc(
"Promote all vector constants"));
51 STATISTIC(NumPromoted,
"Number of promoted constants");
52 STATISTIC(NumPromotedUses,
"Number of promoted constants uses");
85 class AArch64PromoteConstant :
public ModulePass {
88 struct PromotedConstant {
89 bool ShouldConvert =
false;
100 : C(C), User(User), Op(Op) {}
108 StringRef getPassName()
const override {
return "AArch64 Promote Constant"; }
112 bool runOnModule(
Module &M)
override {
116 bool Changed =
false;
117 PromotionCacheTy PromotionCache;
119 Changed |= runOnFunction(MF, PromotionCache);
128 bool runOnFunction(
Function &
F, PromotionCacheTy &PromotionCache);
157 InsertionPoints &InsertPts);
173 InsertionPoints &InsertPts);
183 InsertionPoints &InsertPts);
189 InsertionPoints &InsertPts);
194 PromotionCacheTy &PromotionCache);
198 static void appendAndTransferDominatedUses(
Instruction *NewPt,
200 InsertionPoints::iterator &IPI,
201 InsertionPoints &InsertPts) {
203 IPI->second.emplace_back(User, OpNo);
209 Uses OldUses = std::move(IPI->second);
210 InsertPts[NewPt] = std::move(OldUses);
212 InsertPts.erase(OldInstr);
220 "AArch64 Promote Constant Pass",
false,
false)
226 return new AArch64PromoteConstant();
235 EltIdx < EndEltIdx; ++EltIdx)
252 if (isa<const ShuffleVectorInst>(Instr) && OpIdx == 2)
256 if (isa<const ExtractValueInst>(Instr) && OpIdx > 0)
260 if (isa<const InsertValueInst>(Instr) && OpIdx > 1)
263 if (isa<const AllocaInst>(Instr) && OpIdx > 0)
267 if (isa<const LoadInst>(Instr) && OpIdx > 0)
271 if (isa<const StoreInst>(Instr) && OpIdx > 1)
275 if (isa<const GetElementPtrInst>(Instr) && OpIdx > 0)
280 if (isa<const LandingPadInst>(Instr))
284 if (isa<const SwitchInst>(Instr))
288 if (isa<const IndirectBrInst>(Instr))
292 if (isa<const IntrinsicInst>(Instr))
315 if (isa<const UndefValue>(Cst))
340 auto Converted = PromotionCache.
insert(
341 std::make_pair(&C, AArch64PromoteConstant::PromotedConstant()));
342 if (Converted.second)
344 return Converted.first->second.ShouldConvert;
351 if (
PHINode *PhiInst = dyn_cast<PHINode>(&User))
352 return PhiInst->getIncomingBlock(OpNo)->getTerminator();
359 InsertionPoints &InsertPts) {
366 for (
auto &IPI : InsertPts) {
367 if (NewPt == IPI.first || DT.
dominates(IPI.first, NewPt) ||
371 (IPI.first->getParent() != NewPt->
getParent() &&
374 DEBUG(
dbgs() <<
"Insertion point dominated by:\n");
377 IPI.second.emplace_back(User, OpNo);
386 InsertionPoints &InsertPts) {
394 for (InsertionPoints::iterator IPI = InsertPts.begin(),
395 EndIPI = InsertPts.end();
396 IPI != EndIPI; ++IPI) {
398 if (NewBB == CurBB) {
402 DEBUG(
dbgs() <<
"Merge insertion point with:\n");
404 DEBUG(
dbgs() <<
"\nat considered insertion point.\n");
405 appendAndTransferDominatedUses(NewPt, User, OpNo, IPI, InsertPts);
412 if (!CommonDominator)
415 if (CommonDominator != NewBB) {
417 assert(CommonDominator != CurBB &&
418 "Instruction has not been rejected during isDominated check!");
424 DEBUG(
dbgs() <<
"Merge insertion point with:\n");
429 appendAndTransferDominatedUses(NewPt, User, OpNo, IPI, InsertPts);
435 void AArch64PromoteConstant::computeInsertionPoint(
436 Instruction *User,
unsigned OpNo, InsertionPoints &InsertPts) {
437 DEBUG(
dbgs() <<
"Considered use, opidx " << OpNo <<
":\n");
441 Instruction *InsertionPoint = findInsertionPoint(*User, OpNo);
443 DEBUG(
dbgs() <<
"Considered insertion point:\n");
447 if (isDominated(InsertionPoint, User, OpNo, InsertPts))
451 if (tryAndMerge(InsertionPoint, User, OpNo, InsertPts))
454 DEBUG(
dbgs() <<
"Keep considered insertion point\n");
457 InsertPts[InsertionPoint].emplace_back(User, OpNo);
461 AArch64PromoteConstant::PromotedConstant &
PC) {
462 assert(PC.ShouldConvert &&
463 "Expected that we should convert this to a global");
476 void AArch64PromoteConstant::insertDefinitions(
Function &
F,
478 InsertionPoints &InsertPts) {
481 DominatorTree &DT = getAnalysis<DominatorTreeWrapperPass>(
F).getDomTree();
483 assert(!InsertPts.empty() &&
"Empty uses does not need a definition");
485 for (
const auto &IPI : InsertPts) {
488 LoadInst *LoadedCst = Builder.CreateLoad(&PromotedGV);
495 for (
auto Use : IPI.second) {
498 findInsertionPoint(*
Use.first,
Use.second)) &&
499 "Inserted definition does not dominate all its uses!");
502 dbgs() <<
"Use to update " <<
Use.second <<
":";
506 Use.first->setOperand(
Use.second, LoadedCst);
512 void AArch64PromoteConstant::promoteConstants(
514 PromotionCacheTy &PromotionCache) {
516 for (
auto U = Updates.
begin(),
E = Updates.
end(); U !=
E;) {
517 DEBUG(
dbgs() <<
"** Compute insertion points **\n");
520 InsertionPoints InsertPts;
522 computeInsertionPoint(U->User, U->Op, InsertPts);
523 }
while (++U !=
E && U->C == C);
525 auto &Promotion = PromotionCache[
C];
527 insertDefinitions(F, *Promotion.GV, InsertPts);
531 bool AArch64PromoteConstant::runOnFunction(
Function &F,
532 PromotionCacheTy &PromotionCache) {
540 for (
Use &U :
I.operands()) {
545 if (!Cst || isa<GlobalValue>(Cst) || isa<ConstantExpr>(Cst))
553 unsigned OpNo = &U -
I.op_begin();
564 promoteConstants(F, Updates, PromotionCache);
Pass interface - Implemented by all 'passes'.
const Value * getCalledValue() const
Get a pointer to the function that is invoked by this instruction.
AnalysisUsage & addPreserved()
Add the specified Pass class to the set of analyses preserved by this pass.
static PassRegistry * getPassRegistry()
getPassRegistry - Access the global registry object, which is automatically initialized at applicatio...
STATISTIC(NumFunctions,"Total number of functions")
unsigned getStructNumElements() const
A Module instance is used to store all the information related to an LLVM module. ...
This class represents a function call, abstracting a target machine's calling convention.
const Function * getParent() const
Return the enclosing method, or null if none.
An instruction for reading from memory.
ModulePass * createAArch64PromoteConstantPass()
std::pair< iterator, bool > insert(const std::pair< KeyT, ValueT > &KV)
AnalysisUsage & addRequired()
#define INITIALIZE_PASS_DEPENDENCY(depName)
void setInitializer(Constant *InitVal)
setInitializer - Sets the initializer for this global variable, removing any existing initializer if ...
void print(raw_ostream &O, bool IsForDebug=false) const
Implement operator<< on Value.
Type * getArrayElementType() const
A Use represents the edge between a Value definition and its users.
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
LLVM_NODISCARD bool empty() const
Type * getStructElementType(unsigned N) const
bool isArrayTy() const
True if this is an instance of ArrayType.
Concrete subclass of DominatorTreeBase that is used to compute a normal dominator tree...
static GCRegistry::Add< CoreCLRGC > E("coreclr","CoreCLR-compatible GC")
void initializeAArch64PromoteConstantPass(PassRegistry &)
LLVM Basic Block Representation.
The instances of the Type class are immutable: once they are created, they are never changed...
bool isVectorTy() const
True if this is an instance of VectorType.
This is an important base class in LLVM.
LLVM_ATTRIBUTE_ALWAYS_INLINE iterator begin()
This file contains the declarations for the subclasses of Constant, which represent the different fla...
bool isZeroValue() const
Return true if the value is negative zero or null value.
Represent the analysis usage information of a pass.
INITIALIZE_PASS_END(RegBankSelect, DEBUG_TYPE,"Assign register bank of generic virtual registers", false, false) RegBankSelect
NodeT * findNearestCommonDominator(NodeT *A, NodeT *B)
findNearestCommonDominator - Find nearest common dominator basic block for basic block A and B...
bool dominates(const Instruction *Def, const Use &U) const
Return true if Def dominates a use in User.
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small...
Module.h This file contains the declarations for the Module class.
Type * getType() const
All values are typed, get the type of this value.
void setPreservesCFG()
This function should be called by the pass, iff they do not:
static GCRegistry::Add< ShadowStackGC > C("shadow-stack","Very portable GC for uncooperative code generators")
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
bool isStructTy() const
True if this is an instance of StructType.
LLVM_ATTRIBUTE_ALWAYS_INLINE iterator end()
void emplace_back(ArgTypes &&...Args)
TerminatorInst * getTerminator()
Returns the terminator instruction if the block is well formed or null if the block is not well forme...
ModulePass class - This class is used to implement unstructured interprocedural optimizations and ana...
LLVM_NODISCARD std::enable_if<!is_simple_type< Y >::value, typename cast_retty< X, const Y >::ret_type >::type dyn_cast(const Y &Val)
Rename collisions when linking (static functions).
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
Module * getParent()
Get the module that this global value is contained inside of...
StringRef - Represent a constant reference to a string, i.e.
inst_range instructions(Function *F)
Legacy analysis pass which computes a DominatorTree.
const BasicBlock * getParent() const