mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-02-12 18:33:22 +00:00
stub out some LazyValueInfo interfaces, and have JumpThreading
start using them in a trivial way when -enable-jump-threading-lvi is passed. enable-jump-threading-lvi will be my playground for awhile. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@86789 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
5606ec894e
commit
cc4d3b25f3
@ -18,23 +18,44 @@
|
|||||||
#include "llvm/Pass.h"
|
#include "llvm/Pass.h"
|
||||||
|
|
||||||
namespace llvm {
|
namespace llvm {
|
||||||
|
class Constant;
|
||||||
|
class TargetData;
|
||||||
|
class Value;
|
||||||
|
|
||||||
/// LazyValueInfo - This pass computes, caches, and vends lazy value constraint
|
/// LazyValueInfo - This pass computes, caches, and vends lazy value constraint
|
||||||
/// information.
|
/// information.
|
||||||
class LazyValueInfo : public FunctionPass {
|
class LazyValueInfo : public FunctionPass {
|
||||||
|
class TargetData *TD;
|
||||||
|
void *PImpl;
|
||||||
public:
|
public:
|
||||||
static char ID;
|
static char ID;
|
||||||
LazyValueInfo();
|
LazyValueInfo() : FunctionPass(&ID), PImpl(0) {}
|
||||||
|
|
||||||
|
/// Tristate - This is used to return yes/no/dunno results.
|
||||||
|
enum Tristate {
|
||||||
|
Unknown = -1, No = 0, Yes = 1
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// Public query interface.
|
||||||
|
|
||||||
|
|
||||||
|
/// isEqual - Determine whether the specified value is known to be equal or
|
||||||
|
/// not-equal to the specified constant at the end of the specified block.
|
||||||
|
Tristate isEqual(Value *V, Constant *C, BasicBlock *BB);
|
||||||
|
|
||||||
|
/// getConstant - Determine whether the specified value is known to be a
|
||||||
|
/// constant at the end of the specified block. Return null if not.
|
||||||
|
Constant *getConstant(Value *V, BasicBlock *BB);
|
||||||
|
|
||||||
|
|
||||||
|
// Implementation boilerplate.
|
||||||
|
|
||||||
virtual void getAnalysisUsage(AnalysisUsage &AU) const {
|
virtual void getAnalysisUsage(AnalysisUsage &AU) const {
|
||||||
AU.setPreservesAll();
|
AU.setPreservesAll();
|
||||||
}
|
}
|
||||||
virtual void releaseMemory();
|
virtual void releaseMemory();
|
||||||
|
virtual bool runOnFunction(Function &F);
|
||||||
virtual bool runOnFunction(Function &F) {
|
|
||||||
// Fully lazy.
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // end namespace llvm
|
} // end namespace llvm
|
||||||
|
@ -13,6 +13,11 @@
|
|||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
#include "llvm/Analysis/LazyValueInfo.h"
|
#include "llvm/Analysis/LazyValueInfo.h"
|
||||||
|
#include "llvm/Constants.h"
|
||||||
|
#include "llvm/Instructions.h"
|
||||||
|
#include "llvm/Analysis/ConstantFolding.h"
|
||||||
|
#include "llvm/Target/TargetData.h"
|
||||||
|
#include "llvm/ADT/PointerIntPair.h"
|
||||||
using namespace llvm;
|
using namespace llvm;
|
||||||
|
|
||||||
char LazyValueInfo::ID = 0;
|
char LazyValueInfo::ID = 0;
|
||||||
@ -23,9 +28,119 @@ namespace llvm {
|
|||||||
FunctionPass *createLazyValueInfoPass() { return new LazyValueInfo(); }
|
FunctionPass *createLazyValueInfoPass() { return new LazyValueInfo(); }
|
||||||
}
|
}
|
||||||
|
|
||||||
LazyValueInfo::LazyValueInfo() : FunctionPass(&ID) {
|
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
// LVILatticeVal
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
/// LVILatticeVal - This is the information tracked by LazyValueInfo for each
|
||||||
|
/// value.
|
||||||
|
///
|
||||||
|
/// FIXME: This is basically just for bringup, this can be made a lot more rich
|
||||||
|
/// in the future.
|
||||||
|
///
|
||||||
|
namespace {
|
||||||
|
class LVILatticeVal {
|
||||||
|
enum LatticeValueTy {
|
||||||
|
/// undefined - This LLVM Value has no known value yet.
|
||||||
|
undefined,
|
||||||
|
/// constant - This LLVM Value has a specific constant value.
|
||||||
|
constant,
|
||||||
|
/// overdefined - This instruction is not known to be constant, and we know
|
||||||
|
/// it has a value.
|
||||||
|
overdefined
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Val: This stores the current lattice value along with the Constant* for
|
||||||
|
/// the constant if this is a 'constant' value.
|
||||||
|
PointerIntPair<Constant *, 2, LatticeValueTy> Val;
|
||||||
|
|
||||||
|
public:
|
||||||
|
LVILatticeVal() : Val(0, undefined) {}
|
||||||
|
|
||||||
|
bool isUndefined() const { return Val.getInt() == undefined; }
|
||||||
|
bool isConstant() const { return Val.getInt() == constant; }
|
||||||
|
bool isOverdefined() const { return Val.getInt() == overdefined; }
|
||||||
|
|
||||||
|
Constant *getConstant() const {
|
||||||
|
assert(isConstant() && "Cannot get the constant of a non-constant!");
|
||||||
|
return Val.getPointer();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// getConstantInt - If this is a constant with a ConstantInt value, return it
|
||||||
|
/// otherwise return null.
|
||||||
|
ConstantInt *getConstantInt() const {
|
||||||
|
if (isConstant())
|
||||||
|
return dyn_cast<ConstantInt>(getConstant());
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// markOverdefined - Return true if this is a change in status.
|
||||||
|
bool markOverdefined() {
|
||||||
|
if (isOverdefined())
|
||||||
|
return false;
|
||||||
|
Val.setInt(overdefined);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// markConstant - Return true if this is a change in status.
|
||||||
|
bool markConstant(Constant *V) {
|
||||||
|
if (isConstant()) {
|
||||||
|
assert(getConstant() == V && "Marking constant with different value");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(isUndefined());
|
||||||
|
Val.setInt(constant);
|
||||||
|
assert(V && "Marking constant with NULL");
|
||||||
|
Val.setPointer(V);
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
} // end anonymous namespace.
|
||||||
|
|
||||||
|
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
// LazyValueInfo Impl
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
bool LazyValueInfo::runOnFunction(Function &F) {
|
||||||
|
TD = getAnalysisIfAvailable<TargetData>();
|
||||||
|
// Fully lazy.
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void LazyValueInfo::releaseMemory() {
|
void LazyValueInfo::releaseMemory() {
|
||||||
|
// No caching yet.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// isEqual - Determine whether the specified value is known to be equal or
|
||||||
|
/// not-equal to the specified constant at the end of the specified block.
|
||||||
|
LazyValueInfo::Tristate
|
||||||
|
LazyValueInfo::isEqual(Value *V, Constant *C, BasicBlock *BB) {
|
||||||
|
// If already a constant, we can use constant folding.
|
||||||
|
if (Constant *VC = dyn_cast<Constant>(V)) {
|
||||||
|
// Ignore FP for now. TODO, consider what form of equality we want.
|
||||||
|
if (C->getType()->isFPOrFPVector())
|
||||||
|
return Unknown;
|
||||||
|
|
||||||
|
Constant *Res = ConstantFoldCompareInstOperands(ICmpInst::ICMP_EQ, VC,C,TD);
|
||||||
|
if (ConstantInt *ResCI = dyn_cast<ConstantInt>(Res))
|
||||||
|
return ResCI->isZero() ? No : Yes;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Not a very good implementation.
|
||||||
|
return Unknown;
|
||||||
|
}
|
||||||
|
|
||||||
|
Constant *LazyValueInfo::getConstant(Value *V, BasicBlock *BB) {
|
||||||
|
// If already a constant, return it.
|
||||||
|
if (Constant *VC = dyn_cast<Constant>(V))
|
||||||
|
return VC;
|
||||||
|
|
||||||
|
// Not a very good implementation.
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
#include "llvm/LLVMContext.h"
|
#include "llvm/LLVMContext.h"
|
||||||
#include "llvm/Pass.h"
|
#include "llvm/Pass.h"
|
||||||
#include "llvm/Analysis/InstructionSimplify.h"
|
#include "llvm/Analysis/InstructionSimplify.h"
|
||||||
|
#include "llvm/Analysis/LazyValueInfo.h"
|
||||||
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
|
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
|
||||||
#include "llvm/Transforms/Utils/Local.h"
|
#include "llvm/Transforms/Utils/Local.h"
|
||||||
#include "llvm/Transforms/Utils/SSAUpdater.h"
|
#include "llvm/Transforms/Utils/SSAUpdater.h"
|
||||||
@ -40,6 +41,12 @@ Threshold("jump-threading-threshold",
|
|||||||
cl::desc("Max block size to duplicate for jump threading"),
|
cl::desc("Max block size to duplicate for jump threading"),
|
||||||
cl::init(6), cl::Hidden);
|
cl::init(6), cl::Hidden);
|
||||||
|
|
||||||
|
// Turn on use of LazyValueInfo.
|
||||||
|
static cl::opt<bool>
|
||||||
|
EnableLVI("enable-jump-threading-lvi", cl::ReallyHidden);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
/// This pass performs 'jump threading', which looks at blocks that have
|
/// This pass performs 'jump threading', which looks at blocks that have
|
||||||
/// multiple predecessors and multiple successors. If one or more of the
|
/// multiple predecessors and multiple successors. If one or more of the
|
||||||
@ -59,6 +66,7 @@ namespace {
|
|||||||
///
|
///
|
||||||
class JumpThreading : public FunctionPass {
|
class JumpThreading : public FunctionPass {
|
||||||
TargetData *TD;
|
TargetData *TD;
|
||||||
|
LazyValueInfo *LVI;
|
||||||
#ifdef NDEBUG
|
#ifdef NDEBUG
|
||||||
SmallPtrSet<BasicBlock*, 16> LoopHeaders;
|
SmallPtrSet<BasicBlock*, 16> LoopHeaders;
|
||||||
#else
|
#else
|
||||||
@ -69,8 +77,13 @@ namespace {
|
|||||||
JumpThreading() : FunctionPass(&ID) {}
|
JumpThreading() : FunctionPass(&ID) {}
|
||||||
|
|
||||||
bool runOnFunction(Function &F);
|
bool runOnFunction(Function &F);
|
||||||
void FindLoopHeaders(Function &F);
|
|
||||||
|
|
||||||
|
virtual void getAnalysisUsage(AnalysisUsage &AU) const {
|
||||||
|
if (EnableLVI)
|
||||||
|
AU.addRequired<LazyValueInfo>();
|
||||||
|
}
|
||||||
|
|
||||||
|
void FindLoopHeaders(Function &F);
|
||||||
bool ProcessBlock(BasicBlock *BB);
|
bool ProcessBlock(BasicBlock *BB);
|
||||||
bool ThreadEdge(BasicBlock *BB, const SmallVectorImpl<BasicBlock*> &PredBBs,
|
bool ThreadEdge(BasicBlock *BB, const SmallVectorImpl<BasicBlock*> &PredBBs,
|
||||||
BasicBlock *SuccBB);
|
BasicBlock *SuccBB);
|
||||||
@ -106,6 +119,7 @@ FunctionPass *llvm::createJumpThreadingPass() { return new JumpThreading(); }
|
|||||||
bool JumpThreading::runOnFunction(Function &F) {
|
bool JumpThreading::runOnFunction(Function &F) {
|
||||||
DEBUG(errs() << "Jump threading on function '" << F.getName() << "'\n");
|
DEBUG(errs() << "Jump threading on function '" << F.getName() << "'\n");
|
||||||
TD = getAnalysisIfAvailable<TargetData>();
|
TD = getAnalysisIfAvailable<TargetData>();
|
||||||
|
LVI = EnableLVI ? &getAnalysis<LazyValueInfo>() : 0;
|
||||||
|
|
||||||
FindLoopHeaders(F);
|
FindLoopHeaders(F);
|
||||||
|
|
||||||
@ -235,31 +249,48 @@ void JumpThreading::FindLoopHeaders(Function &F) {
|
|||||||
/// predecessors. If so, return the known list of value and pred BB in the
|
/// predecessors. If so, return the known list of value and pred BB in the
|
||||||
/// result vector. If a value is known to be undef, it is returned as null.
|
/// result vector. If a value is known to be undef, it is returned as null.
|
||||||
///
|
///
|
||||||
/// The BB basic block is known to start with a PHI node.
|
|
||||||
///
|
|
||||||
/// This returns true if there were any known values.
|
/// This returns true if there were any known values.
|
||||||
///
|
///
|
||||||
///
|
|
||||||
/// TODO: Per PR2563, we could infer value range information about a predecessor
|
|
||||||
/// based on its terminator.
|
|
||||||
bool JumpThreading::
|
bool JumpThreading::
|
||||||
ComputeValueKnownInPredecessors(Value *V, BasicBlock *BB,PredValueInfo &Result){
|
ComputeValueKnownInPredecessors(Value *V, BasicBlock *BB,PredValueInfo &Result){
|
||||||
PHINode *TheFirstPHI = cast<PHINode>(BB->begin());
|
|
||||||
|
|
||||||
// If V is a constantint, then it is known in all predecessors.
|
// If V is a constantint, then it is known in all predecessors.
|
||||||
if (isa<ConstantInt>(V) || isa<UndefValue>(V)) {
|
if (isa<ConstantInt>(V) || isa<UndefValue>(V)) {
|
||||||
ConstantInt *CI = dyn_cast<ConstantInt>(V);
|
ConstantInt *CI = dyn_cast<ConstantInt>(V);
|
||||||
Result.resize(TheFirstPHI->getNumIncomingValues());
|
|
||||||
for (unsigned i = 0, e = Result.size(); i != e; ++i)
|
for (pred_iterator PI = pred_begin(BB), E = pred_end(BB); PI != E; ++PI)
|
||||||
Result[i] = std::make_pair(CI, TheFirstPHI->getIncomingBlock(i));
|
Result.push_back(std::make_pair(CI, *PI));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If V is a non-instruction value, or an instruction in a different block,
|
// If V is a non-instruction value, or an instruction in a different block,
|
||||||
// then it can't be derived from a PHI.
|
// then it can't be derived from a PHI.
|
||||||
Instruction *I = dyn_cast<Instruction>(V);
|
Instruction *I = dyn_cast<Instruction>(V);
|
||||||
if (I == 0 || I->getParent() != BB)
|
if (I == 0 || I->getParent() != BB) {
|
||||||
|
|
||||||
|
// Okay, if this is a live-in value, see if it has a known value at the end
|
||||||
|
// of any of our predecessors.
|
||||||
|
//
|
||||||
|
// FIXME: This should be an edge property, not a block end property.
|
||||||
|
/// TODO: Per PR2563, we could infer value range information about a
|
||||||
|
/// predecessor based on its terminator.
|
||||||
|
//
|
||||||
|
if (LVI) {
|
||||||
|
for (pred_iterator PI = pred_begin(BB), E = pred_end(BB); PI != E; ++PI) {
|
||||||
|
// If the value is known by LazyValueInfo to be a constant in a
|
||||||
|
// predecessor, use that information to try to thread this block.
|
||||||
|
Constant *PredCst = LVI->getConstant(V, *PI);
|
||||||
|
if (PredCst == 0 ||
|
||||||
|
(!isa<ConstantInt>(PredCst) && !isa<UndefValue>(PredCst)))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
Result.push_back(std::make_pair(dyn_cast<ConstantInt>(PredCst), *PI));
|
||||||
|
}
|
||||||
|
|
||||||
|
return !Result.empty();
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/// If I is a PHI node, then we know the incoming values for any constants.
|
/// If I is a PHI node, then we know the incoming values for any constants.
|
||||||
if (PHINode *PN = dyn_cast<PHINode>(I)) {
|
if (PHINode *PN = dyn_cast<PHINode>(I)) {
|
||||||
@ -517,12 +548,8 @@ bool JumpThreading::ProcessBlock(BasicBlock *BB) {
|
|||||||
// a PHI node in the current block. If we can prove that any predecessors
|
// a PHI node in the current block. If we can prove that any predecessors
|
||||||
// compute a predictable value based on a PHI node, thread those predecessors.
|
// compute a predictable value based on a PHI node, thread those predecessors.
|
||||||
//
|
//
|
||||||
// We only bother doing this if the current block has a PHI node and if the
|
if (ProcessThreadableEdges(CondInst, BB))
|
||||||
// conditional instruction lives in the current block. If either condition
|
return true;
|
||||||
// fails, this won't be a computable value anyway.
|
|
||||||
if (CondInst->getParent() == BB && isa<PHINode>(BB->front()))
|
|
||||||
if (ProcessThreadableEdges(CondInst, BB))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
|
|
||||||
// TODO: If we have: "br (X > 0)" and we have a predecessor where we know
|
// TODO: If we have: "br (X > 0)" and we have a predecessor where we know
|
||||||
|
Loading…
x
Reference in New Issue
Block a user