[PM] Port ConstantHoisting to the new Pass Manager

Differential Revision: http://reviews.llvm.org/D21945

llvm-svn: 274411
This commit is contained in:
Michael Kuperstein 2016-07-02 00:16:47 +00:00
parent f9656821ec
commit 42c218049d
7 changed files with 204 additions and 136 deletions

View File

@ -88,7 +88,7 @@ void initializeCallGraphPrinterLegacyPassPass(PassRegistry&);
void initializeCallGraphViewerPass(PassRegistry&);
void initializeCallGraphWrapperPassPass(PassRegistry &);
void initializeCodeGenPreparePass(PassRegistry&);
void initializeConstantHoistingPass(PassRegistry&);
void initializeConstantHoistingLegacyPassPass(PassRegistry&);
void initializeConstantMergeLegacyPassPass(PassRegistry &);
void initializeConstantPropagationPass(PassRegistry&);
void initializeCorrelatedValuePropagationPass(PassRegistry&);

View File

@ -0,0 +1,146 @@
//===-- ConstantHoisting.h - Prepare code for expensive constants ---------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This pass identifies expensive constants to hoist and coalesces them to
// better prepare it for SelectionDAG-based code generation. This works around
// the limitations of the basic-block-at-a-time approach.
//
// First it scans all instructions for integer constants and calculates its
// cost. If the constant can be folded into the instruction (the cost is
// TCC_Free) or the cost is just a simple operation (TCC_BASIC), then we don't
// consider it expensive and leave it alone. This is the default behavior and
// the default implementation of getIntImmCost will always return TCC_Free.
//
// If the cost is more than TCC_BASIC, then the integer constant can't be folded
// into the instruction and it might be beneficial to hoist the constant.
// Similar constants are coalesced to reduce register pressure and
// materialization code.
//
// When a constant is hoisted, it is also hidden behind a bitcast to force it to
// be live-out of the basic block. Otherwise the constant would be just
// duplicated and each basic block would have its own copy in the SelectionDAG.
// The SelectionDAG recognizes such constants as opaque and doesn't perform
// certain transformations on them, which would create a new expensive constant.
//
// This optimization is only applied to integer constants in instructions and
// simple (this means not nested) constant cast expressions. For example:
// %0 = load i64* inttoptr (i64 big_constant to i64*)
//===----------------------------------------------------------------------===//
#ifndef LLVM_TRANSFORMS_SCALAR_CONSTANTHOISTING_H
#define LLVM_TRANSFORMS_SCALAR_CONSTANTHOISTING_H
#include "llvm/Analysis/TargetTransformInfo.h"
#include "llvm/IR/Dominators.h"
#include "llvm/IR/PassManager.h"
namespace llvm {
/// A private "module" namespace for types and utilities used by
/// ConstantHoisting. These are implementation details and should not be used by
/// clients.
namespace consthoist {
/// \brief Keeps track of the user of a constant and the operand index where the
/// constant is used.
struct ConstantUser {
Instruction *Inst;
unsigned OpndIdx;
ConstantUser(Instruction *Inst, unsigned Idx) : Inst(Inst), OpndIdx(Idx) { }
};
typedef SmallVector<ConstantUser, 8> ConstantUseListType;
/// \brief Keeps track of a constant candidate and its uses.
struct ConstantCandidate {
ConstantUseListType Uses;
ConstantInt *ConstInt;
unsigned CumulativeCost;
ConstantCandidate(ConstantInt *ConstInt)
: ConstInt(ConstInt), CumulativeCost(0) { }
/// \brief Add the user to the use list and update the cost.
void addUser(Instruction *Inst, unsigned Idx, unsigned Cost) {
CumulativeCost += Cost;
Uses.push_back(ConstantUser(Inst, Idx));
}
};
/// \brief This represents a constant that has been rebased with respect to a
/// base constant. The difference to the base constant is recorded in Offset.
struct RebasedConstantInfo {
ConstantUseListType Uses;
Constant *Offset;
RebasedConstantInfo(ConstantUseListType &&Uses, Constant *Offset)
: Uses(std::move(Uses)), Offset(Offset) { }
};
typedef SmallVector<RebasedConstantInfo, 4> RebasedConstantListType;
/// \brief A base constant and all its rebased constants.
struct ConstantInfo {
ConstantInt *BaseConstant;
RebasedConstantListType RebasedConstants;
};
}
class ConstantHoistingPass : public PassInfoMixin<ConstantHoistingPass> {
public:
PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM);
// Glue for old PM.
bool runImpl(Function &F, TargetTransformInfo &TTI, DominatorTree &DT,
BasicBlock &Entry);
void releaseMemory() {
ConstantVec.clear();
ClonedCastMap.clear();
ConstCandVec.clear();
}
private:
typedef DenseMap<ConstantInt *, unsigned> ConstCandMapType;
typedef std::vector<consthoist::ConstantCandidate> ConstCandVecType;
const TargetTransformInfo *TTI;
DominatorTree *DT;
BasicBlock *Entry;
/// Keeps track of constant candidates found in the function.
ConstCandVecType ConstCandVec;
/// Keep track of cast instructions we already cloned.
SmallDenseMap<Instruction *, Instruction *> ClonedCastMap;
/// These are the final constants we decided to hoist.
SmallVector<consthoist::ConstantInfo, 8> ConstantVec;
Instruction *findMatInsertPt(Instruction *Inst, unsigned Idx = ~0U) const;
Instruction *findConstantInsertionPoint(
const consthoist::ConstantInfo &ConstInfo) const;
void collectConstantCandidates(ConstCandMapType &ConstCandMap,
Instruction *Inst, unsigned Idx,
ConstantInt *ConstInt);
void collectConstantCandidates(ConstCandMapType &ConstCandMap,
Instruction *Inst);
void collectConstantCandidates(Function &Fn);
void findAndMakeBaseConstant(ConstCandVecType::iterator S,
ConstCandVecType::iterator E);
void findBaseConstants();
void emitBaseConstants(Instruction *Base, Constant *Offset,
const consthoist::ConstantUser &ConstUser);
bool emitBaseConstants();
void deleteDeadCastInst() const;
bool optimizeConstants(Function &Fn);
};
}
#endif // LLVM_TRANSFORMS_SCALAR_CONSTANTHOISTING_H

View File

@ -74,6 +74,7 @@
#include "llvm/Transforms/Scalar/AlignmentFromAssumptions.h"
#include "llvm/Transforms/Scalar/BDCE.h"
#include "llvm/Transforms/Scalar/DCE.h"
#include "llvm/Transforms/Scalar/ConstantHoisting.h"
#include "llvm/Transforms/Scalar/DeadStoreElimination.h"
#include "llvm/Transforms/Scalar/EarlyCSE.h"
#include "llvm/Transforms/Scalar/Float2Int.h"

View File

@ -125,6 +125,7 @@ FUNCTION_PASS("adce", ADCEPass())
FUNCTION_PASS("add-discriminators", AddDiscriminatorsPass())
FUNCTION_PASS("alignment-from-assumptions", AlignmentFromAssumptionsPass())
FUNCTION_PASS("bdce", BDCEPass())
FUNCTION_PASS("consthoist", ConstantHoistingPass())
FUNCTION_PASS("dce", DCEPass())
FUNCTION_PASS("dse", DSEPass())
FUNCTION_PASS("early-cse", EarlyCSEPass())

View File

@ -33,20 +33,20 @@
// %0 = load i64* inttoptr (i64 big_constant to i64*)
//===----------------------------------------------------------------------===//
#include "llvm/Transforms/Scalar.h"
#include "llvm/Transforms/Scalar/ConstantHoisting.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Analysis/TargetTransformInfo.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/Dominators.h"
#include "llvm/IR/IntrinsicInst.h"
#include "llvm/Pass.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Transforms/Scalar.h"
#include <tuple>
using namespace llvm;
using namespace consthoist;
#define DEBUG_TYPE "consthoist"
@ -54,75 +54,12 @@ STATISTIC(NumConstantsHoisted, "Number of constants hoisted");
STATISTIC(NumConstantsRebased, "Number of constants rebased");
namespace {
struct ConstantUser;
struct RebasedConstantInfo;
typedef SmallVector<ConstantUser, 8> ConstantUseListType;
typedef SmallVector<RebasedConstantInfo, 4> RebasedConstantListType;
/// \brief Keeps track of the user of a constant and the operand index where the
/// constant is used.
struct ConstantUser {
Instruction *Inst;
unsigned OpndIdx;
ConstantUser(Instruction *Inst, unsigned Idx) : Inst(Inst), OpndIdx(Idx) { }
};
/// \brief Keeps track of a constant candidate and its uses.
struct ConstantCandidate {
ConstantUseListType Uses;
ConstantInt *ConstInt;
unsigned CumulativeCost;
ConstantCandidate(ConstantInt *ConstInt)
: ConstInt(ConstInt), CumulativeCost(0) { }
/// \brief Add the user to the use list and update the cost.
void addUser(Instruction *Inst, unsigned Idx, unsigned Cost) {
CumulativeCost += Cost;
Uses.push_back(ConstantUser(Inst, Idx));
}
};
/// \brief This represents a constant that has been rebased with respect to a
/// base constant. The difference to the base constant is recorded in Offset.
struct RebasedConstantInfo {
ConstantUseListType Uses;
Constant *Offset;
RebasedConstantInfo(ConstantUseListType &&Uses, Constant *Offset)
: Uses(std::move(Uses)), Offset(Offset) { }
};
/// \brief A base constant and all its rebased constants.
struct ConstantInfo {
ConstantInt *BaseConstant;
RebasedConstantListType RebasedConstants;
};
/// \brief The constant hoisting pass.
class ConstantHoisting : public FunctionPass {
typedef DenseMap<ConstantInt *, unsigned> ConstCandMapType;
typedef std::vector<ConstantCandidate> ConstCandVecType;
const TargetTransformInfo *TTI;
DominatorTree *DT;
BasicBlock *Entry;
/// Keeps track of constant candidates found in the function.
ConstCandVecType ConstCandVec;
/// Keep track of cast instructions we already cloned.
SmallDenseMap<Instruction *, Instruction *> ClonedCastMap;
/// These are the final constants we decided to hoist.
SmallVector<ConstantInfo, 8> ConstantVec;
class ConstantHoistingLegacyPass : public FunctionPass {
public:
static char ID; // Pass identification, replacement for typeid
ConstantHoisting() : FunctionPass(ID), TTI(nullptr), DT(nullptr),
Entry(nullptr) {
initializeConstantHoistingPass(*PassRegistry::getPassRegistry());
ConstantHoistingLegacyPass() : FunctionPass(ID) {
initializeConstantHoistingLegacyPassPass(*PassRegistry::getPassRegistry());
}
bool runOnFunction(Function &Fn) override;
@ -135,67 +72,36 @@ public:
AU.addRequired<TargetTransformInfoWrapperPass>();
}
void releaseMemory() override { Impl.releaseMemory(); }
private:
/// \brief Initialize the pass.
void setup(Function &Fn) {
DT = &getAnalysis<DominatorTreeWrapperPass>().getDomTree();
TTI = &getAnalysis<TargetTransformInfoWrapperPass>().getTTI(Fn);
Entry = &Fn.getEntryBlock();
}
/// \brief Cleanup.
void cleanup() {
ConstantVec.clear();
ClonedCastMap.clear();
ConstCandVec.clear();
TTI = nullptr;
DT = nullptr;
Entry = nullptr;
}
Instruction *findMatInsertPt(Instruction *Inst, unsigned Idx = ~0U) const;
Instruction *findConstantInsertionPoint(const ConstantInfo &ConstInfo) const;
void collectConstantCandidates(ConstCandMapType &ConstCandMap,
Instruction *Inst, unsigned Idx,
ConstantInt *ConstInt);
void collectConstantCandidates(ConstCandMapType &ConstCandMap,
Instruction *Inst);
void collectConstantCandidates(Function &Fn);
void findAndMakeBaseConstant(ConstCandVecType::iterator S,
ConstCandVecType::iterator E);
void findBaseConstants();
void emitBaseConstants(Instruction *Base, Constant *Offset,
const ConstantUser &ConstUser);
bool emitBaseConstants();
void deleteDeadCastInst() const;
bool optimizeConstants(Function &Fn);
ConstantHoistingPass Impl;
};
}
char ConstantHoisting::ID = 0;
INITIALIZE_PASS_BEGIN(ConstantHoisting, "consthoist", "Constant Hoisting",
false, false)
char ConstantHoistingLegacyPass::ID = 0;
INITIALIZE_PASS_BEGIN(ConstantHoistingLegacyPass, "consthoist",
"Constant Hoisting", false, false)
INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass)
INITIALIZE_PASS_DEPENDENCY(TargetTransformInfoWrapperPass)
INITIALIZE_PASS_END(ConstantHoisting, "consthoist", "Constant Hoisting",
false, false)
INITIALIZE_PASS_END(ConstantHoistingLegacyPass, "consthoist",
"Constant Hoisting", false, false)
FunctionPass *llvm::createConstantHoistingPass() {
return new ConstantHoisting();
return new ConstantHoistingLegacyPass();
}
/// \brief Perform the constant hoisting optimization for the given function.
bool ConstantHoisting::runOnFunction(Function &Fn) {
bool ConstantHoistingLegacyPass::runOnFunction(Function &Fn) {
if (skipFunction(Fn))
return false;
DEBUG(dbgs() << "********** Begin Constant Hoisting **********\n");
DEBUG(dbgs() << "********** Function: " << Fn.getName() << '\n');
setup(Fn);
bool MadeChange = optimizeConstants(Fn);
bool MadeChange = Impl.runImpl(
Fn, getAnalysis<TargetTransformInfoWrapperPass>().getTTI(Fn),
getAnalysis<DominatorTreeWrapperPass>().getDomTree(), Fn.getEntryBlock());
if (MadeChange) {
DEBUG(dbgs() << "********** Function after Constant Hoisting: "
@ -204,15 +110,13 @@ bool ConstantHoisting::runOnFunction(Function &Fn) {
}
DEBUG(dbgs() << "********** End Constant Hoisting **********\n");
cleanup();
return MadeChange;
}
/// \brief Find the constant materialization insertion point.
Instruction *ConstantHoisting::findMatInsertPt(Instruction *Inst,
unsigned Idx) const {
Instruction *ConstantHoistingPass::findMatInsertPt(Instruction *Inst,
unsigned Idx) const {
// If the operand is a cast instruction, then we have to materialize the
// constant before the cast instruction.
if (Idx != ~0U) {
@ -237,8 +141,8 @@ Instruction *ConstantHoisting::findMatInsertPt(Instruction *Inst,
}
/// \brief Find an insertion point that dominates all uses.
Instruction *ConstantHoisting::
findConstantInsertionPoint(const ConstantInfo &ConstInfo) const {
Instruction *ConstantHoistingPass::findConstantInsertionPoint(
const ConstantInfo &ConstInfo) const {
assert(!ConstInfo.RebasedConstants.empty() && "Invalid constant info entry.");
// Collect all basic blocks.
SmallPtrSet<BasicBlock *, 8> BBs;
@ -272,10 +176,9 @@ findConstantInsertionPoint(const ConstantInfo &ConstInfo) const {
/// The operand at index Idx is not necessarily the constant integer itself. It
/// could also be a cast instruction or a constant expression that uses the
// constant integer.
void ConstantHoisting::collectConstantCandidates(ConstCandMapType &ConstCandMap,
Instruction *Inst,
unsigned Idx,
ConstantInt *ConstInt) {
void ConstantHoistingPass::collectConstantCandidates(
ConstCandMapType &ConstCandMap, Instruction *Inst, unsigned Idx,
ConstantInt *ConstInt) {
unsigned Cost;
// Ask the target about the cost of materializing the constant for the given
// instruction and operand index.
@ -309,8 +212,8 @@ void ConstantHoisting::collectConstantCandidates(ConstCandMapType &ConstCandMap,
/// \brief Scan the instruction for expensive integer constants and record them
/// in the constant candidate vector.
void ConstantHoisting::collectConstantCandidates(ConstCandMapType &ConstCandMap,
Instruction *Inst) {
void ConstantHoistingPass::collectConstantCandidates(
ConstCandMapType &ConstCandMap, Instruction *Inst) {
// Skip all cast instructions. They are visited indirectly later on.
if (Inst->isCast())
return;
@ -375,7 +278,7 @@ void ConstantHoisting::collectConstantCandidates(ConstCandMapType &ConstCandMap,
/// \brief Collect all integer constants in the function that cannot be folded
/// into an instruction itself.
void ConstantHoisting::collectConstantCandidates(Function &Fn) {
void ConstantHoistingPass::collectConstantCandidates(Function &Fn) {
ConstCandMapType ConstCandMap;
for (BasicBlock &BB : Fn)
for (Instruction &Inst : BB)
@ -384,8 +287,8 @@ void ConstantHoisting::collectConstantCandidates(Function &Fn) {
/// \brief Find the base constant within the given range and rebase all other
/// constants with respect to the base constant.
void ConstantHoisting::findAndMakeBaseConstant(ConstCandVecType::iterator S,
ConstCandVecType::iterator E) {
void ConstantHoistingPass::findAndMakeBaseConstant(
ConstCandVecType::iterator S, ConstCandVecType::iterator E) {
auto MaxCostItr = S;
unsigned NumUses = 0;
// Use the constant that has the maximum cost as base constant.
@ -416,7 +319,7 @@ void ConstantHoisting::findAndMakeBaseConstant(ConstCandVecType::iterator S,
/// \brief Finds and combines constant candidates that can be easily
/// rematerialized with an add from a common base constant.
void ConstantHoisting::findBaseConstants() {
void ConstantHoistingPass::findBaseConstants() {
// Sort the constants by value and type. This invalidates the mapping!
std::sort(ConstCandVec.begin(), ConstCandVec.end(),
[](const ConstantCandidate &LHS, const ConstantCandidate &RHS) {
@ -478,8 +381,9 @@ static bool updateOperand(Instruction *Inst, unsigned Idx, Instruction *Mat) {
/// \brief Emit materialization code for all rebased constants and update their
/// users.
void ConstantHoisting::emitBaseConstants(Instruction *Base, Constant *Offset,
const ConstantUser &ConstUser) {
void ConstantHoistingPass::emitBaseConstants(Instruction *Base,
Constant *Offset,
const ConstantUser &ConstUser) {
Instruction *Mat = Base;
if (Offset) {
Instruction *InsertionPt = findMatInsertPt(ConstUser.Inst,
@ -550,7 +454,7 @@ void ConstantHoisting::emitBaseConstants(Instruction *Base, Constant *Offset,
/// \brief Hoist and hide the base constant behind a bitcast and emit
/// materialization code for derived constants.
bool ConstantHoisting::emitBaseConstants() {
bool ConstantHoistingPass::emitBaseConstants() {
bool MadeChange = false;
for (auto const &ConstInfo : ConstantVec) {
// Hoist and hide the base constant behind a bitcast.
@ -584,14 +488,18 @@ bool ConstantHoisting::emitBaseConstants() {
/// \brief Check all cast instructions we made a copy of and remove them if they
/// have no more users.
void ConstantHoisting::deleteDeadCastInst() const {
void ConstantHoistingPass::deleteDeadCastInst() const {
for (auto const &I : ClonedCastMap)
if (I.first->use_empty())
I.first->eraseFromParent();
}
/// \brief Optimize expensive integer constants in the given function.
bool ConstantHoisting::optimizeConstants(Function &Fn) {
bool ConstantHoistingPass::runImpl(Function &Fn, TargetTransformInfo &TTI,
DominatorTree &DT, BasicBlock &Entry) {
this->TTI = &TTI;
this->DT = &DT;
this->Entry = &Entry;
// Collect all constant candidates.
collectConstantCandidates(Fn);
@ -616,3 +524,14 @@ bool ConstantHoisting::optimizeConstants(Function &Fn) {
return MadeChange;
}
PreservedAnalyses ConstantHoistingPass::run(Function &F,
FunctionAnalysisManager &AM) {
auto &DT = AM.getResult<DominatorTreeAnalysis>(F);
auto &TTI = AM.getResult<TargetIRAnalysis>(F);
if (!runImpl(F, TTI, DT, F.getEntryBlock()))
return PreservedAnalyses::all();
// FIXME: This should also 'preserve the CFG'.
return PreservedAnalyses::none();
}

View File

@ -34,7 +34,7 @@ void llvm::initializeScalarOpts(PassRegistry &Registry) {
initializeADCELegacyPassPass(Registry);
initializeBDCELegacyPassPass(Registry);
initializeAlignmentFromAssumptionsPass(Registry);
initializeConstantHoistingPass(Registry);
initializeConstantHoistingLegacyPassPass(Registry);
initializeConstantPropagationPass(Registry);
initializeCorrelatedValuePropagationPass(Registry);
initializeDCELegacyPassPass(Registry);

View File

@ -1,4 +1,5 @@
; RUN: opt -S -consthoist < %s | FileCheck %s
; RUN: opt -S -passes='consthoist' < %s | FileCheck %s
target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-apple-macosx10.9.0"