51 #define DEBUG_TYPE "consthoist"
53 STATISTIC(NumConstantsHoisted,
"Number of constants hoisted");
54 STATISTIC(NumConstantsRebased,
"Number of constants rebased");
58 struct RebasedConstantInfo;
69 ConstantUser(
Instruction *Inst,
unsigned Idx) : Inst(Inst), OpndIdx(Idx) { }
73 struct ConstantCandidate {
74 ConstantUseListType Uses;
76 unsigned CumulativeCost;
79 : ConstInt(ConstInt), CumulativeCost(0) { }
82 void addUser(
Instruction *Inst,
unsigned Idx,
unsigned Cost) {
83 CumulativeCost += Cost;
84 Uses.push_back(ConstantUser(Inst, Idx));
90 struct RebasedConstantInfo {
91 ConstantUseListType Uses;
94 RebasedConstantInfo(ConstantUseListType &&Uses,
Constant *Offset)
95 : Uses(std::move(Uses)), Offset(Offset) { }
101 RebasedConstantListType RebasedConstants;
107 typedef std::vector<ConstantCandidate> ConstCandVecType;
114 ConstCandVecType ConstCandVec;
128 bool runOnFunction(
Function &Fn)
override;
130 const char *getPassName()
const override {
return "Constant Hoisting"; }
141 DT = &getAnalysis<DominatorTreeWrapperPass>().getDomTree();
142 TTI = &getAnalysis<TargetTransformInfoWrapperPass>().getTTI(Fn);
149 ClonedCastMap.clear();
150 ConstCandVec.clear();
159 void collectConstantCandidates(ConstCandMapType &ConstCandMap,
162 void collectConstantCandidates(ConstCandMapType &ConstCandMap,
164 void collectConstantCandidates(
Function &Fn);
165 void findAndMakeBaseConstant(ConstCandVecType::iterator S,
166 ConstCandVecType::iterator E);
167 void findBaseConstants();
169 const ConstantUser &ConstUser);
170 bool emitBaseConstants();
171 void deleteDeadCastInst()
const;
172 bool optimizeConstants(
Function &Fn);
185 return new ConstantHoisting();
189 bool ConstantHoisting::runOnFunction(
Function &Fn) {
190 if (skipOptnoneFunction(Fn))
193 DEBUG(
dbgs() <<
"********** Begin Constant Hoisting **********\n");
198 bool MadeChange = optimizeConstants(Fn);
201 DEBUG(
dbgs() <<
"********** Function after Constant Hoisting: "
205 DEBUG(
dbgs() <<
"********** End Constant Hoisting **********\n");
215 unsigned Idx)
const {
220 if (
auto CastInst = dyn_cast<Instruction>(Opnd))
226 if (!isa<PHINode>(Inst) && !isa<LandingPadInst>(Inst))
231 assert(Entry != Inst->
getParent() &&
"PHI or landing pad in entry block!");
232 if (Idx != ~0U && isa<PHINode>(Inst))
233 return cast<PHINode>(Inst)->getIncomingBlock(Idx)->getTerminator();
241 findConstantInsertionPoint(
const ConstantInfo &ConstInfo)
const {
242 assert(!ConstInfo.RebasedConstants.empty() &&
"Invalid constant info entry.");
245 for (
auto const &RCI : ConstInfo.RebasedConstants)
246 for (
auto const &U : RCI.Uses)
247 BBs.
insert(findMatInsertPt(U.Inst, U.OpndIdx)->getParent());
249 if (BBs.count(Entry))
250 return &Entry->front();
252 while (BBs.size() >= 2) {
255 BB2 = *std::next(BBs.begin());
256 BB = DT->findNearestCommonDominator(BB1, BB2);
258 return &Entry->
front();
263 assert((BBs.size() == 1) &&
"Expected only one element.");
265 return findMatInsertPt(&FirstInst);
275 void ConstantHoisting::collectConstantCandidates(ConstCandMapType &ConstCandMap,
282 if (
auto IntrInst = dyn_cast<IntrinsicInst>(Inst))
283 Cost = TTI->getIntImmCost(IntrInst->getIntrinsicID(), Idx,
291 ConstCandMapType::iterator Itr;
293 std::tie(Itr, Inserted) = ConstCandMap.insert(std::make_pair(ConstInt, 0));
295 ConstCandVec.push_back(ConstantCandidate(ConstInt));
296 Itr->second = ConstCandVec.size() - 1;
298 ConstCandVec[Itr->second].addUser(Inst, Idx, Cost);
300 dbgs() << "Collect constant " << *ConstInt << " from " << *Inst
301 << " with
cost " << Cost << '\n';
303 dbgs() << "Collect constant " << *ConstInt << " indirectly from "
304 << *Inst << " via " << *Inst->getOperand(Idx) << " with
cost "
312 void ConstantHoisting::collectConstantCandidates(ConstCandMapType &ConstCandMap,
319 if (
auto Call = dyn_cast<CallInst>(Inst))
320 if (isa<InlineAsm>(
Call->getCalledValue()))
324 for (
unsigned Idx = 0, E = Inst->getNumOperands(); Idx != E; ++Idx) {
325 Value *Opnd = Inst->getOperand(Idx);
328 if (
auto ConstInt = dyn_cast<ConstantInt>(Opnd)) {
329 collectConstantCandidates(ConstCandMap, Inst, Idx, ConstInt);
334 if (
auto CastInst = dyn_cast<Instruction>(Opnd)) {
343 collectConstantCandidates(ConstCandMap, Inst, Idx, ConstInt);
349 if (
auto ConstExpr = dyn_cast<ConstantExpr>(Opnd)) {
351 if (!ConstExpr->isCast())
354 if (
auto ConstInt = dyn_cast<ConstantInt>(ConstExpr->getOperand(0))) {
357 collectConstantCandidates(ConstCandMap, Inst, Idx, ConstInt);
366 void ConstantHoisting::collectConstantCandidates(
Function &Fn) {
367 ConstCandMapType ConstCandMap;
370 collectConstantCandidates(ConstCandMap, Inst);
375 void ConstantHoisting::findAndMakeBaseConstant(ConstCandVecType::iterator S,
376 ConstCandVecType::iterator E) {
378 unsigned NumUses = 0;
380 for (
auto ConstCand = S; ConstCand != E; ++ConstCand) {
381 NumUses += ConstCand->Uses.size();
382 if (ConstCand->CumulativeCost > MaxCostItr->CumulativeCost)
383 MaxCostItr = ConstCand;
391 ConstInfo.BaseConstant = MaxCostItr->ConstInt;
392 Type *Ty = ConstInfo.BaseConstant->getType();
395 for (
auto ConstCand = S; ConstCand != E; ++ConstCand) {
396 APInt Diff = ConstCand->ConstInt->getValue() -
397 ConstInfo.BaseConstant->getValue();
399 ConstInfo.RebasedConstants.push_back(
400 RebasedConstantInfo(std::move(ConstCand->Uses), Offset));
402 ConstantVec.push_back(std::move(ConstInfo));
407 void ConstantHoisting::findBaseConstants() {
409 std::sort(ConstCandVec.begin(), ConstCandVec.end(),
410 [](
const ConstantCandidate &LHS,
const ConstantCandidate &RHS) {
411 if (LHS.ConstInt->getType() != RHS.ConstInt->getType())
412 return LHS.ConstInt->getType()->getBitWidth() <
413 RHS.ConstInt->getType()->getBitWidth();
414 return LHS.ConstInt->getValue().ult(RHS.ConstInt->getValue());
419 auto MinValItr = ConstCandVec.begin();
420 for (
auto CC = std::next(ConstCandVec.begin()), E = ConstCandVec.end();
422 if (MinValItr->ConstInt->getType() == CC->ConstInt->getType()) {
424 APInt Diff = CC->ConstInt->getValue() - MinValItr->ConstInt->getValue();
431 findAndMakeBaseConstant(MinValItr, CC);
436 findAndMakeBaseConstant(MinValItr, ConstCandVec.end());
446 if (
auto PHI = dyn_cast<PHINode>(Inst)) {
454 for (
unsigned i = 0; i < Idx; ++i) {
455 if (
PHI->getIncomingBlock(i) == IncomingBB) {
456 Value *IncomingVal =
PHI->getIncomingValue(i);
470 const ConstantUser &ConstUser) {
473 Instruction *InsertionPt = findMatInsertPt(ConstUser.Inst,
476 "const_mat", InsertionPt);
479 <<
" + " << *Offset <<
") in BB "
483 Value *Opnd = ConstUser.Inst->getOperand(ConstUser.OpndIdx);
486 if (isa<ConstantInt>(Opnd)) {
487 DEBUG(
dbgs() <<
"Update: " << *ConstUser.Inst <<
'\n');
488 if (!
updateOperand(ConstUser.Inst, ConstUser.OpndIdx, Mat) && Offset)
490 DEBUG(
dbgs() <<
"To : " << *ConstUser.Inst <<
'\n');
495 if (
auto CastInst = dyn_cast<Instruction>(Opnd)) {
500 if (!ClonedCastInst) {
503 ClonedCastInst->insertAfter(
CastInst);
507 <<
"To : " << *ClonedCastInst <<
'\n');
510 DEBUG(
dbgs() <<
"Update: " << *ConstUser.Inst <<
'\n');
511 updateOperand(ConstUser.Inst, ConstUser.OpndIdx, ClonedCastInst);
512 DEBUG(
dbgs() <<
"To : " << *ConstUser.Inst <<
'\n');
517 if (
auto ConstExpr = dyn_cast<ConstantExpr>(Opnd)) {
518 Instruction *ConstExprInst = ConstExpr->getAsInstruction();
520 ConstExprInst->
insertBefore(findMatInsertPt(ConstUser.Inst,
524 ConstExprInst->
setDebugLoc(ConstUser.Inst->getDebugLoc());
526 DEBUG(
dbgs() <<
"Create instruction: " << *ConstExprInst <<
'\n'
527 <<
"From : " << *ConstExpr <<
'\n');
528 DEBUG(
dbgs() <<
"Update: " << *ConstUser.Inst <<
'\n');
529 if (!
updateOperand(ConstUser.Inst, ConstUser.OpndIdx, ConstExprInst)) {
534 DEBUG(
dbgs() <<
"To : " << *ConstUser.Inst <<
'\n');
541 bool ConstantHoisting::emitBaseConstants() {
542 bool MadeChange =
false;
543 for (
auto const &ConstInfo : ConstantVec) {
546 IntegerType *Ty = ConstInfo.BaseConstant->getType();
548 new BitCastInst(ConstInfo.BaseConstant, Ty,
"const", IP);
549 DEBUG(
dbgs() <<
"Hoist constant (" << *ConstInfo.BaseConstant <<
") to BB "
551 NumConstantsHoisted++;
554 for (
auto const &RCI : ConstInfo.RebasedConstants) {
555 NumConstantsRebased++;
556 for (
auto const &U : RCI.Uses)
557 emitBaseConstants(Base, RCI.Offset, U);
561 assert(!Base->
use_empty() &&
"The use list is empty!?");
562 assert(isa<Instruction>(Base->
user_back()) &&
563 "All uses should be instructions.");
567 NumConstantsRebased--;
575 void ConstantHoisting::deleteDeadCastInst()
const {
576 for (
auto const &
I : ClonedCastMap)
577 if (
I.first->use_empty())
578 I.first->eraseFromParent();
582 bool ConstantHoisting::optimizeConstants(
Function &Fn) {
584 collectConstantCandidates(Fn);
587 if (ConstCandVec.empty())
595 if (ConstantVec.empty())
600 bool MadeChange = emitBaseConstants();
603 deleteDeadCastInst();
iplist< Instruction >::iterator eraseFromParent()
eraseFromParent - This method unlinks 'this' from the containing basic block and deletes it...
IntegerType * getType() const
getType - Specialize the getType() method to always return an IntegerType, which reduces the amount o...
static PassRegistry * getPassRegistry()
getPassRegistry - Access the global registry object, which is automatically initialized at applicatio...
STATISTIC(NumFunctions,"Total number of functions")
static bool updateOperand(Instruction *Inst, unsigned Idx, Instruction *Mat)
Updates the operand at Idx in instruction Inst with the result of instruction Mat.
const Instruction & front() const
static void cleanup(BlockFrequencyInfoImplBase &BFI)
Clear all memory not needed downstream.
StringRef getName() const
Return a constant reference to the value's name.
iterator begin()
Instruction iterator methods.
AnalysisUsage & addRequired()
#define INITIALIZE_PASS_DEPENDENCY(depName)
This is the base class for all instructions that perform data casts.
const APInt & getValue() const
Return the constant as an APInt value reference.
#define INITIALIZE_PASS_END(passName, arg, name, cfg, analysis)
Instruction * clone() const
clone() - Create a copy of 'this' instruction that is identical in all ways except the following: ...
This class represents a no-op cast from one type to another.
Concrete subclass of DominatorTreeBase that is used to compute a normal dominator tree...
void initializeConstantHoistingPass(PassRegistry &)
void setDebugLoc(DebugLoc Loc)
setDebugLoc - Set the debug location information for this instruction.
void insertBefore(Instruction *InsertPos)
Insert an unlinked instruction into a basic block immediately before the specified instruction...
LLVM Basic Block Representation.
The instances of the Type class are immutable: once they are created, they are never changed...
This is an important base class in LLVM.
int64_t getSExtValue() const
Get sign extended value.
This file contains the declarations for the subclasses of Constant, which represent the different fla...
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
const DebugLoc & getDebugLoc() const
getDebugLoc - Return the debug location for this node as a DebugLoc.
Represent the analysis usage information of a pass.
unsigned getBitWidth() const
Return the number of bits in the APInt.
FunctionPass class - This class is used to implement most global optimizations.
Value * getOperand(unsigned i) const
Class to represent integer types.
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements...
This is the shared class of boolean and integer constants.
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small...
Instruction * user_back()
user_back - Specialize the methods defined in Value, as we know that an instruction can only be used ...
static Constant * get(Type *Ty, uint64_t V, bool isSigned=false)
If Ty is a vector type, return a Constant with a splat of the given value.
void setPreservesCFG()
This function should be called by the pass, iff they do not:
const BasicBlock & getEntryBlock() const
void setOperand(unsigned i, Value *Val)
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Class for arbitrary precision integers.
static BinaryOperator * Create(BinaryOps Op, Value *S1, Value *S2, const Twine &Name=Twine(), Instruction *InsertBefore=nullptr)
Construct a binary instruction, given the opcode and the two operands.
TerminatorInst * getTerminator()
Returns the terminator instruction if the block is well formed or null if the block is not well forme...
LLVM Value Representation.
unsigned getOpcode() const
getOpcode() returns a member of one of the enums like Instruction::Add.
Legacy analysis pass which computes a DominatorTree.
const BasicBlock * getParent() const
INITIALIZE_PASS_BEGIN(ConstantHoisting,"consthoist","Constant Hoisting", false, false) INITIALIZE_PASS_END(ConstantHoisting
FunctionPass * createConstantHoistingPass()