mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-02-06 23:32:27 +00:00
Teach SimplifyCFG about magic pointer constants.
Weird code sometimes uses pointer constants other than null. This patch teaches SimplifyCFG to build switch instructions in those cases. Code like this: void f(const char *x) { if (!x) puts("null"); else if ((uintptr_t)x == 1) puts("one"); else if (x == (char*)2 || x == (char*)3) puts("two"); else if ((intptr_t)x == 4) puts("four"); else puts(x); } Now becomes a switch: define void @f(i8* %x) nounwind ssp { entry: %magicptr23 = ptrtoint i8* %x to i64 ; <i64> [#uses=1] switch i64 %magicptr23, label %if.else16 [ i64 0, label %if.then i64 1, label %if.then2 i64 2, label %if.then9 i64 3, label %if.then9 i64 4, label %if.then14 ] Note that LLVM's own DenseMap uses magic pointers. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@95439 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
00cb3fe786
commit
58e9ee85fd
@ -131,7 +131,7 @@ bool EliminateDuplicatePHINodes(BasicBlock *BB);
|
|||||||
///
|
///
|
||||||
/// WARNING: The entry node of a method may not be simplified.
|
/// WARNING: The entry node of a method may not be simplified.
|
||||||
///
|
///
|
||||||
bool SimplifyCFG(BasicBlock *BB);
|
bool SimplifyCFG(BasicBlock *BB, const TargetData *TD = 0);
|
||||||
|
|
||||||
/// FoldBranchToCommonDest - If this basic block is ONLY a setcc and a branch,
|
/// FoldBranchToCommonDest - If this basic block is ONLY a setcc and a branch,
|
||||||
/// and if a predecessor branches to us and one of our successors, fold the
|
/// and if a predecessor branches to us and one of our successors, fold the
|
||||||
|
@ -30,6 +30,7 @@
|
|||||||
#include "llvm/Attributes.h"
|
#include "llvm/Attributes.h"
|
||||||
#include "llvm/Support/CFG.h"
|
#include "llvm/Support/CFG.h"
|
||||||
#include "llvm/Pass.h"
|
#include "llvm/Pass.h"
|
||||||
|
#include "llvm/Target/TargetData.h"
|
||||||
#include "llvm/ADT/SmallVector.h"
|
#include "llvm/ADT/SmallVector.h"
|
||||||
#include "llvm/ADT/SmallPtrSet.h"
|
#include "llvm/ADT/SmallPtrSet.h"
|
||||||
#include "llvm/ADT/Statistic.h"
|
#include "llvm/ADT/Statistic.h"
|
||||||
@ -261,7 +262,7 @@ static bool MergeEmptyReturnBlocks(Function &F) {
|
|||||||
|
|
||||||
/// IterativeSimplifyCFG - Call SimplifyCFG on all the blocks in the function,
|
/// IterativeSimplifyCFG - Call SimplifyCFG on all the blocks in the function,
|
||||||
/// iterating until no more changes are made.
|
/// iterating until no more changes are made.
|
||||||
static bool IterativeSimplifyCFG(Function &F) {
|
static bool IterativeSimplifyCFG(Function &F, const TargetData *TD) {
|
||||||
bool Changed = false;
|
bool Changed = false;
|
||||||
bool LocalChange = true;
|
bool LocalChange = true;
|
||||||
while (LocalChange) {
|
while (LocalChange) {
|
||||||
@ -271,7 +272,7 @@ static bool IterativeSimplifyCFG(Function &F) {
|
|||||||
// if they are unneeded...
|
// if they are unneeded...
|
||||||
//
|
//
|
||||||
for (Function::iterator BBIt = ++F.begin(); BBIt != F.end(); ) {
|
for (Function::iterator BBIt = ++F.begin(); BBIt != F.end(); ) {
|
||||||
if (SimplifyCFG(BBIt++)) {
|
if (SimplifyCFG(BBIt++, TD)) {
|
||||||
LocalChange = true;
|
LocalChange = true;
|
||||||
++NumSimpl;
|
++NumSimpl;
|
||||||
}
|
}
|
||||||
@ -285,9 +286,10 @@ static bool IterativeSimplifyCFG(Function &F) {
|
|||||||
// simplify the CFG.
|
// simplify the CFG.
|
||||||
//
|
//
|
||||||
bool CFGSimplifyPass::runOnFunction(Function &F) {
|
bool CFGSimplifyPass::runOnFunction(Function &F) {
|
||||||
|
const TargetData *TD = getAnalysisIfAvailable<TargetData>();
|
||||||
bool EverChanged = RemoveUnreachableBlocksFromFn(F);
|
bool EverChanged = RemoveUnreachableBlocksFromFn(F);
|
||||||
EverChanged |= MergeEmptyReturnBlocks(F);
|
EverChanged |= MergeEmptyReturnBlocks(F);
|
||||||
EverChanged |= IterativeSimplifyCFG(F);
|
EverChanged |= IterativeSimplifyCFG(F, TD);
|
||||||
|
|
||||||
// If neither pass changed anything, we're done.
|
// If neither pass changed anything, we're done.
|
||||||
if (!EverChanged) return false;
|
if (!EverChanged) return false;
|
||||||
@ -301,7 +303,7 @@ bool CFGSimplifyPass::runOnFunction(Function &F) {
|
|||||||
return true;
|
return true;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
EverChanged = IterativeSimplifyCFG(F);
|
EverChanged = IterativeSimplifyCFG(F, TD);
|
||||||
EverChanged |= RemoveUnreachableBlocksFromFn(F);
|
EverChanged |= RemoveUnreachableBlocksFromFn(F);
|
||||||
} while (EverChanged);
|
} while (EverChanged);
|
||||||
|
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
#include "llvm/Support/Debug.h"
|
#include "llvm/Support/Debug.h"
|
||||||
#include "llvm/Support/raw_ostream.h"
|
#include "llvm/Support/raw_ostream.h"
|
||||||
#include "llvm/Analysis/ConstantFolding.h"
|
#include "llvm/Analysis/ConstantFolding.h"
|
||||||
|
#include "llvm/Target/TargetData.h"
|
||||||
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
|
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
|
||||||
#include "llvm/ADT/DenseMap.h"
|
#include "llvm/ADT/DenseMap.h"
|
||||||
#include "llvm/ADT/SmallVector.h"
|
#include "llvm/ADT/SmallVector.h"
|
||||||
@ -36,6 +37,28 @@ using namespace llvm;
|
|||||||
|
|
||||||
STATISTIC(NumSpeculations, "Number of speculative executed instructions");
|
STATISTIC(NumSpeculations, "Number of speculative executed instructions");
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
class SimplifyCFGOpt {
|
||||||
|
const TargetData *const TD;
|
||||||
|
|
||||||
|
ConstantInt *GetConstantInt(Value *V);
|
||||||
|
Value *GatherConstantSetEQs(Value *V, std::vector<ConstantInt*> &Values);
|
||||||
|
Value *GatherConstantSetNEs(Value *V, std::vector<ConstantInt*> &Values);
|
||||||
|
bool GatherValueComparisons(Instruction *Cond, Value *&CompVal,
|
||||||
|
std::vector<ConstantInt*> &Values);
|
||||||
|
Value *isValueEqualityComparison(TerminatorInst *TI);
|
||||||
|
BasicBlock *GetValueEqualityComparisonCases(TerminatorInst *TI,
|
||||||
|
std::vector<std::pair<ConstantInt*, BasicBlock*> > &Cases);
|
||||||
|
bool SimplifyEqualityComparisonWithOnlyPredecessor(TerminatorInst *TI,
|
||||||
|
BasicBlock *Pred);
|
||||||
|
bool FoldValueComparisonIntoPredecessors(TerminatorInst *TI);
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit SimplifyCFGOpt(const TargetData *td) : TD(td) {}
|
||||||
|
bool run(BasicBlock *BB);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/// SafeToMergeTerminators - Return true if it is safe to merge these two
|
/// SafeToMergeTerminators - Return true if it is safe to merge these two
|
||||||
/// terminator instructions together.
|
/// terminator instructions together.
|
||||||
///
|
///
|
||||||
@ -243,17 +266,48 @@ static bool DominatesMergePoint(Value *V, BasicBlock *BB,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// GetConstantInt - Extract ConstantInt from value, looking through IntToPtr
|
||||||
|
/// and PointerNullValue. Return NULL if value is not a constant int.
|
||||||
|
ConstantInt *SimplifyCFGOpt::GetConstantInt(Value *V) {
|
||||||
|
// Normal constant int.
|
||||||
|
ConstantInt *CI = dyn_cast<ConstantInt>(V);
|
||||||
|
if (CI || !TD || !isa<Constant>(V) || !isa<PointerType>(V->getType()))
|
||||||
|
return CI;
|
||||||
|
|
||||||
|
// This is some kind of pointer constant. Turn it into a pointer-sized
|
||||||
|
// ConstantInt if possible.
|
||||||
|
const IntegerType *PtrTy = TD->getIntPtrType(V->getContext());
|
||||||
|
|
||||||
|
// Null pointer means 0, see SelectionDAGBuilder::getValue(const Value*).
|
||||||
|
if (isa<ConstantPointerNull>(V))
|
||||||
|
return ConstantInt::get(PtrTy, 0);
|
||||||
|
|
||||||
|
// IntToPtr const int.
|
||||||
|
if (ConstantExpr *CE = dyn_cast<ConstantExpr>(V))
|
||||||
|
if (CE->getOpcode() == Instruction::IntToPtr)
|
||||||
|
if (ConstantInt *CI = dyn_cast<ConstantInt>(CE->getOperand(0))) {
|
||||||
|
// The constant is very likely to have the right type already.
|
||||||
|
if (CI->getType() == PtrTy)
|
||||||
|
return CI;
|
||||||
|
else
|
||||||
|
return cast<ConstantInt>
|
||||||
|
(ConstantExpr::getIntegerCast(CI, PtrTy, /*isSigned=*/false));
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/// GatherConstantSetEQs - Given a potentially 'or'd together collection of
|
/// GatherConstantSetEQs - Given a potentially 'or'd together collection of
|
||||||
/// icmp_eq instructions that compare a value against a constant, return the
|
/// icmp_eq instructions that compare a value against a constant, return the
|
||||||
/// value being compared, and stick the constant into the Values vector.
|
/// value being compared, and stick the constant into the Values vector.
|
||||||
static Value *GatherConstantSetEQs(Value *V, std::vector<ConstantInt*> &Values){
|
Value *SimplifyCFGOpt::
|
||||||
|
GatherConstantSetEQs(Value *V, std::vector<ConstantInt*> &Values) {
|
||||||
if (Instruction *Inst = dyn_cast<Instruction>(V)) {
|
if (Instruction *Inst = dyn_cast<Instruction>(V)) {
|
||||||
if (Inst->getOpcode() == Instruction::ICmp &&
|
if (Inst->getOpcode() == Instruction::ICmp &&
|
||||||
cast<ICmpInst>(Inst)->getPredicate() == ICmpInst::ICMP_EQ) {
|
cast<ICmpInst>(Inst)->getPredicate() == ICmpInst::ICMP_EQ) {
|
||||||
if (ConstantInt *C = dyn_cast<ConstantInt>(Inst->getOperand(1))) {
|
if (ConstantInt *C = GetConstantInt(Inst->getOperand(1))) {
|
||||||
Values.push_back(C);
|
Values.push_back(C);
|
||||||
return Inst->getOperand(0);
|
return Inst->getOperand(0);
|
||||||
} else if (ConstantInt *C = dyn_cast<ConstantInt>(Inst->getOperand(0))) {
|
} else if (ConstantInt *C = GetConstantInt(Inst->getOperand(0))) {
|
||||||
Values.push_back(C);
|
Values.push_back(C);
|
||||||
return Inst->getOperand(1);
|
return Inst->getOperand(1);
|
||||||
}
|
}
|
||||||
@ -270,14 +324,15 @@ static Value *GatherConstantSetEQs(Value *V, std::vector<ConstantInt*> &Values){
|
|||||||
/// GatherConstantSetNEs - Given a potentially 'and'd together collection of
|
/// GatherConstantSetNEs - Given a potentially 'and'd together collection of
|
||||||
/// setne instructions that compare a value against a constant, return the value
|
/// setne instructions that compare a value against a constant, return the value
|
||||||
/// being compared, and stick the constant into the Values vector.
|
/// being compared, and stick the constant into the Values vector.
|
||||||
static Value *GatherConstantSetNEs(Value *V, std::vector<ConstantInt*> &Values){
|
Value *SimplifyCFGOpt::
|
||||||
|
GatherConstantSetNEs(Value *V, std::vector<ConstantInt*> &Values) {
|
||||||
if (Instruction *Inst = dyn_cast<Instruction>(V)) {
|
if (Instruction *Inst = dyn_cast<Instruction>(V)) {
|
||||||
if (Inst->getOpcode() == Instruction::ICmp &&
|
if (Inst->getOpcode() == Instruction::ICmp &&
|
||||||
cast<ICmpInst>(Inst)->getPredicate() == ICmpInst::ICMP_NE) {
|
cast<ICmpInst>(Inst)->getPredicate() == ICmpInst::ICMP_NE) {
|
||||||
if (ConstantInt *C = dyn_cast<ConstantInt>(Inst->getOperand(1))) {
|
if (ConstantInt *C = GetConstantInt(Inst->getOperand(1))) {
|
||||||
Values.push_back(C);
|
Values.push_back(C);
|
||||||
return Inst->getOperand(0);
|
return Inst->getOperand(0);
|
||||||
} else if (ConstantInt *C = dyn_cast<ConstantInt>(Inst->getOperand(0))) {
|
} else if (ConstantInt *C = GetConstantInt(Inst->getOperand(0))) {
|
||||||
Values.push_back(C);
|
Values.push_back(C);
|
||||||
return Inst->getOperand(1);
|
return Inst->getOperand(1);
|
||||||
}
|
}
|
||||||
@ -294,8 +349,8 @@ static Value *GatherConstantSetNEs(Value *V, std::vector<ConstantInt*> &Values){
|
|||||||
/// GatherValueComparisons - If the specified Cond is an 'and' or 'or' of a
|
/// GatherValueComparisons - If the specified Cond is an 'and' or 'or' of a
|
||||||
/// bunch of comparisons of one value against constants, return the value and
|
/// bunch of comparisons of one value against constants, return the value and
|
||||||
/// the constants being compared.
|
/// the constants being compared.
|
||||||
static bool GatherValueComparisons(Instruction *Cond, Value *&CompVal,
|
bool SimplifyCFGOpt::GatherValueComparisons(Instruction *Cond, Value *&CompVal,
|
||||||
std::vector<ConstantInt*> &Values) {
|
std::vector<ConstantInt*> &Values) {
|
||||||
if (Cond->getOpcode() == Instruction::Or) {
|
if (Cond->getOpcode() == Instruction::Or) {
|
||||||
CompVal = GatherConstantSetEQs(Cond, Values);
|
CompVal = GatherConstantSetEQs(Cond, Values);
|
||||||
|
|
||||||
@ -327,29 +382,32 @@ static void EraseTerminatorInstAndDCECond(TerminatorInst *TI) {
|
|||||||
|
|
||||||
/// isValueEqualityComparison - Return true if the specified terminator checks
|
/// isValueEqualityComparison - Return true if the specified terminator checks
|
||||||
/// to see if a value is equal to constant integer value.
|
/// to see if a value is equal to constant integer value.
|
||||||
static Value *isValueEqualityComparison(TerminatorInst *TI) {
|
Value *SimplifyCFGOpt::isValueEqualityComparison(TerminatorInst *TI) {
|
||||||
|
Value *CV = 0;
|
||||||
if (SwitchInst *SI = dyn_cast<SwitchInst>(TI)) {
|
if (SwitchInst *SI = dyn_cast<SwitchInst>(TI)) {
|
||||||
// Do not permit merging of large switch instructions into their
|
// Do not permit merging of large switch instructions into their
|
||||||
// predecessors unless there is only one predecessor.
|
// predecessors unless there is only one predecessor.
|
||||||
if (SI->getNumSuccessors() * std::distance(pred_begin(SI->getParent()),
|
if (SI->getNumSuccessors()*std::distance(pred_begin(SI->getParent()),
|
||||||
pred_end(SI->getParent())) > 128)
|
pred_end(SI->getParent())) <= 128)
|
||||||
return 0;
|
CV = SI->getCondition();
|
||||||
|
} else if (BranchInst *BI = dyn_cast<BranchInst>(TI))
|
||||||
return SI->getCondition();
|
|
||||||
}
|
|
||||||
if (BranchInst *BI = dyn_cast<BranchInst>(TI))
|
|
||||||
if (BI->isConditional() && BI->getCondition()->hasOneUse())
|
if (BI->isConditional() && BI->getCondition()->hasOneUse())
|
||||||
if (ICmpInst *ICI = dyn_cast<ICmpInst>(BI->getCondition()))
|
if (ICmpInst *ICI = dyn_cast<ICmpInst>(BI->getCondition()))
|
||||||
if ((ICI->getPredicate() == ICmpInst::ICMP_EQ ||
|
if ((ICI->getPredicate() == ICmpInst::ICMP_EQ ||
|
||||||
ICI->getPredicate() == ICmpInst::ICMP_NE) &&
|
ICI->getPredicate() == ICmpInst::ICMP_NE) &&
|
||||||
isa<ConstantInt>(ICI->getOperand(1)))
|
GetConstantInt(ICI->getOperand(1)))
|
||||||
return ICI->getOperand(0);
|
CV = ICI->getOperand(0);
|
||||||
return 0;
|
|
||||||
|
// Unwrap any lossless ptrtoint cast.
|
||||||
|
if (TD && CV && CV->getType() == TD->getIntPtrType(CV->getContext()))
|
||||||
|
if (PtrToIntInst *PTII = dyn_cast<PtrToIntInst>(CV))
|
||||||
|
CV = PTII->getOperand(0);
|
||||||
|
return CV;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// GetValueEqualityComparisonCases - Given a value comparison instruction,
|
/// GetValueEqualityComparisonCases - Given a value comparison instruction,
|
||||||
/// decode all of the 'cases' that it represents and return the 'default' block.
|
/// decode all of the 'cases' that it represents and return the 'default' block.
|
||||||
static BasicBlock *
|
BasicBlock *SimplifyCFGOpt::
|
||||||
GetValueEqualityComparisonCases(TerminatorInst *TI,
|
GetValueEqualityComparisonCases(TerminatorInst *TI,
|
||||||
std::vector<std::pair<ConstantInt*,
|
std::vector<std::pair<ConstantInt*,
|
||||||
BasicBlock*> > &Cases) {
|
BasicBlock*> > &Cases) {
|
||||||
@ -362,7 +420,7 @@ GetValueEqualityComparisonCases(TerminatorInst *TI,
|
|||||||
|
|
||||||
BranchInst *BI = cast<BranchInst>(TI);
|
BranchInst *BI = cast<BranchInst>(TI);
|
||||||
ICmpInst *ICI = cast<ICmpInst>(BI->getCondition());
|
ICmpInst *ICI = cast<ICmpInst>(BI->getCondition());
|
||||||
Cases.push_back(std::make_pair(cast<ConstantInt>(ICI->getOperand(1)),
|
Cases.push_back(std::make_pair(GetConstantInt(ICI->getOperand(1)),
|
||||||
BI->getSuccessor(ICI->getPredicate() ==
|
BI->getSuccessor(ICI->getPredicate() ==
|
||||||
ICmpInst::ICMP_NE)));
|
ICmpInst::ICMP_NE)));
|
||||||
return BI->getSuccessor(ICI->getPredicate() == ICmpInst::ICMP_EQ);
|
return BI->getSuccessor(ICI->getPredicate() == ICmpInst::ICMP_EQ);
|
||||||
@ -421,8 +479,9 @@ ValuesOverlap(std::vector<std::pair<ConstantInt*, BasicBlock*> > &C1,
|
|||||||
/// comparison with the same value, and if that comparison determines the
|
/// comparison with the same value, and if that comparison determines the
|
||||||
/// outcome of this comparison. If so, simplify TI. This does a very limited
|
/// outcome of this comparison. If so, simplify TI. This does a very limited
|
||||||
/// form of jump threading.
|
/// form of jump threading.
|
||||||
static bool SimplifyEqualityComparisonWithOnlyPredecessor(TerminatorInst *TI,
|
bool SimplifyCFGOpt::
|
||||||
BasicBlock *Pred) {
|
SimplifyEqualityComparisonWithOnlyPredecessor(TerminatorInst *TI,
|
||||||
|
BasicBlock *Pred) {
|
||||||
Value *PredVal = isValueEqualityComparison(Pred->getTerminator());
|
Value *PredVal = isValueEqualityComparison(Pred->getTerminator());
|
||||||
if (!PredVal) return false; // Not a value comparison in predecessor.
|
if (!PredVal) return false; // Not a value comparison in predecessor.
|
||||||
|
|
||||||
@ -548,7 +607,7 @@ namespace {
|
|||||||
/// equality comparison instruction (either a switch or a branch on "X == c").
|
/// equality comparison instruction (either a switch or a branch on "X == c").
|
||||||
/// See if any of the predecessors of the terminator block are value comparisons
|
/// See if any of the predecessors of the terminator block are value comparisons
|
||||||
/// on the same value. If so, and if safe to do so, fold them together.
|
/// on the same value. If so, and if safe to do so, fold them together.
|
||||||
static bool FoldValueComparisonIntoPredecessors(TerminatorInst *TI) {
|
bool SimplifyCFGOpt::FoldValueComparisonIntoPredecessors(TerminatorInst *TI) {
|
||||||
BasicBlock *BB = TI->getParent();
|
BasicBlock *BB = TI->getParent();
|
||||||
Value *CV = isValueEqualityComparison(TI); // CondVal
|
Value *CV = isValueEqualityComparison(TI); // CondVal
|
||||||
assert(CV && "Not a comparison?");
|
assert(CV && "Not a comparison?");
|
||||||
@ -641,6 +700,13 @@ static bool FoldValueComparisonIntoPredecessors(TerminatorInst *TI) {
|
|||||||
for (unsigned i = 0, e = NewSuccessors.size(); i != e; ++i)
|
for (unsigned i = 0, e = NewSuccessors.size(); i != e; ++i)
|
||||||
AddPredecessorToBlock(NewSuccessors[i], Pred, BB);
|
AddPredecessorToBlock(NewSuccessors[i], Pred, BB);
|
||||||
|
|
||||||
|
// Convert pointer to int before we switch.
|
||||||
|
if (isa<PointerType>(CV->getType())) {
|
||||||
|
assert(TD && "Cannot switch on pointer without TargetData");
|
||||||
|
CV = new PtrToIntInst(CV, TD->getIntPtrType(CV->getContext()),
|
||||||
|
"magicptr", PTI);
|
||||||
|
}
|
||||||
|
|
||||||
// Now that the successors are updated, create the new Switch instruction.
|
// Now that the successors are updated, create the new Switch instruction.
|
||||||
SwitchInst *NewSI = SwitchInst::Create(CV, PredDefault,
|
SwitchInst *NewSI = SwitchInst::Create(CV, PredDefault,
|
||||||
PredCases.size(), PTI);
|
PredCases.size(), PTI);
|
||||||
@ -1589,14 +1655,7 @@ static bool SimplifyCondBranchToCondBranch(BranchInst *PBI, BranchInst *BI) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// SimplifyCFG - This function is used to do simplification of a CFG. For
|
bool SimplifyCFGOpt::run(BasicBlock *BB) {
|
||||||
/// example, it adjusts branches to branches to eliminate the extra hop, it
|
|
||||||
/// eliminates unreachable basic blocks, and does other "peephole" optimization
|
|
||||||
/// of the CFG. It returns true if a modification was made.
|
|
||||||
///
|
|
||||||
/// WARNING: The entry node of a function may not be simplified.
|
|
||||||
///
|
|
||||||
bool llvm::SimplifyCFG(BasicBlock *BB) {
|
|
||||||
bool Changed = false;
|
bool Changed = false;
|
||||||
Function *M = BB->getParent();
|
Function *M = BB->getParent();
|
||||||
|
|
||||||
@ -1997,7 +2056,7 @@ bool llvm::SimplifyCFG(BasicBlock *BB) {
|
|||||||
Value *CompVal = 0;
|
Value *CompVal = 0;
|
||||||
std::vector<ConstantInt*> Values;
|
std::vector<ConstantInt*> Values;
|
||||||
bool TrueWhenEqual = GatherValueComparisons(Cond, CompVal, Values);
|
bool TrueWhenEqual = GatherValueComparisons(Cond, CompVal, Values);
|
||||||
if (CompVal && CompVal->getType()->isInteger()) {
|
if (CompVal) {
|
||||||
// There might be duplicate constants in the list, which the switch
|
// There might be duplicate constants in the list, which the switch
|
||||||
// instruction can't handle, remove them now.
|
// instruction can't handle, remove them now.
|
||||||
std::sort(Values.begin(), Values.end(), ConstantIntOrdering());
|
std::sort(Values.begin(), Values.end(), ConstantIntOrdering());
|
||||||
@ -2008,6 +2067,14 @@ bool llvm::SimplifyCFG(BasicBlock *BB) {
|
|||||||
BasicBlock *EdgeBB = BI->getSuccessor(0);
|
BasicBlock *EdgeBB = BI->getSuccessor(0);
|
||||||
if (!TrueWhenEqual) std::swap(DefaultBB, EdgeBB);
|
if (!TrueWhenEqual) std::swap(DefaultBB, EdgeBB);
|
||||||
|
|
||||||
|
// Convert pointer to int before we switch.
|
||||||
|
if (isa<PointerType>(CompVal->getType())) {
|
||||||
|
assert(TD && "Cannot switch on pointer without TargetData");
|
||||||
|
CompVal = new PtrToIntInst(CompVal,
|
||||||
|
TD->getIntPtrType(CompVal->getContext()),
|
||||||
|
"magicptr", BI);
|
||||||
|
}
|
||||||
|
|
||||||
// Create the new switch instruction now.
|
// Create the new switch instruction now.
|
||||||
SwitchInst *New = SwitchInst::Create(CompVal, DefaultBB,
|
SwitchInst *New = SwitchInst::Create(CompVal, DefaultBB,
|
||||||
Values.size(), BI);
|
Values.size(), BI);
|
||||||
@ -2035,3 +2102,14 @@ bool llvm::SimplifyCFG(BasicBlock *BB) {
|
|||||||
|
|
||||||
return Changed;
|
return Changed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// SimplifyCFG - This function is used to do simplification of a CFG. For
|
||||||
|
/// example, it adjusts branches to branches to eliminate the extra hop, it
|
||||||
|
/// eliminates unreachable basic blocks, and does other "peephole" optimization
|
||||||
|
/// of the CFG. It returns true if a modification was made.
|
||||||
|
///
|
||||||
|
/// WARNING: The entry node of a function may not be simplified.
|
||||||
|
///
|
||||||
|
bool llvm::SimplifyCFG(BasicBlock *BB, const TargetData *TD) {
|
||||||
|
return SimplifyCFGOpt(TD).run(BB);
|
||||||
|
}
|
||||||
|
76
test/Transforms/SimplifyCFG/MagicPointer.ll
Normal file
76
test/Transforms/SimplifyCFG/MagicPointer.ll
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
; Test that simplifycfg can create switch instructions from constant pointers.
|
||||||
|
;
|
||||||
|
; RUN: opt < %s -simplifycfg -S | FileCheck %s
|
||||||
|
|
||||||
|
; CHECK: switch i64 %magicptr
|
||||||
|
; CHECK: i64 0, label
|
||||||
|
; CHECK: i64 1, label
|
||||||
|
; CHECK: i64 2, label
|
||||||
|
; CHECK: i64 3, label
|
||||||
|
; CHECK: i64 4, label
|
||||||
|
; CHECK-NOT: br
|
||||||
|
; CHECK: }
|
||||||
|
|
||||||
|
target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
|
||||||
|
target triple = "x86_64-apple-darwin10.0.0"
|
||||||
|
|
||||||
|
@.str = private constant [5 x i8] c"null\00" ; <[5 x i8]*> [#uses=2]
|
||||||
|
@.str1 = private constant [4 x i8] c"one\00" ; <[4 x i8]*> [#uses=2]
|
||||||
|
@.str2 = private constant [4 x i8] c"two\00" ; <[4 x i8]*> [#uses=2]
|
||||||
|
@.str3 = private constant [5 x i8] c"four\00" ; <[5 x i8]*> [#uses=2]
|
||||||
|
|
||||||
|
define void @f(i8* %x) nounwind ssp {
|
||||||
|
entry:
|
||||||
|
%tobool = icmp eq i8* %x, null ; <i1> [#uses=1]
|
||||||
|
br i1 %tobool, label %if.then, label %if.else
|
||||||
|
|
||||||
|
if.then: ; preds = %entry
|
||||||
|
%call = call i32 @puts(i8* getelementptr inbounds ([5 x i8]* @.str, i64 0, i64 0)) nounwind ; <i32> [#uses=0]
|
||||||
|
br label %if.end21
|
||||||
|
|
||||||
|
if.else: ; preds = %entry
|
||||||
|
%cmp = icmp eq i8* %x, inttoptr (i64 1 to i8*) ; <i1> [#uses=1]
|
||||||
|
br i1 %cmp, label %if.then2, label %if.else4
|
||||||
|
|
||||||
|
if.then2: ; preds = %if.else
|
||||||
|
%call3 = call i32 @puts(i8* getelementptr inbounds ([4 x i8]* @.str1, i64 0, i64 0)) nounwind ; <i32> [#uses=0]
|
||||||
|
br label %if.end20
|
||||||
|
|
||||||
|
if.else4: ; preds = %if.else
|
||||||
|
%cmp6 = icmp eq i8* %x, inttoptr (i64 2 to i8*) ; <i1> [#uses=1]
|
||||||
|
br i1 %cmp6, label %if.then9, label %lor.lhs.false
|
||||||
|
|
||||||
|
lor.lhs.false: ; preds = %if.else4
|
||||||
|
%cmp8 = icmp eq i8* %x, inttoptr (i64 3 to i8*) ; <i1> [#uses=1]
|
||||||
|
br i1 %cmp8, label %if.then9, label %if.else11
|
||||||
|
|
||||||
|
if.then9: ; preds = %lor.lhs.false, %if.else4
|
||||||
|
%call10 = call i32 @puts(i8* getelementptr inbounds ([4 x i8]* @.str2, i64 0, i64 0)) nounwind ; <i32> [#uses=0]
|
||||||
|
br label %if.end19
|
||||||
|
|
||||||
|
if.else11: ; preds = %lor.lhs.false
|
||||||
|
%cmp13 = icmp eq i8* %x, inttoptr (i64 4 to i8*) ; <i1> [#uses=1]
|
||||||
|
br i1 %cmp13, label %if.then14, label %if.else16
|
||||||
|
|
||||||
|
if.then14: ; preds = %if.else11
|
||||||
|
%call15 = call i32 @puts(i8* getelementptr inbounds ([5 x i8]* @.str3, i64 0, i64 0)) nounwind ; <i32> [#uses=0]
|
||||||
|
br label %if.end
|
||||||
|
|
||||||
|
if.else16: ; preds = %if.else11
|
||||||
|
%call18 = call i32 @puts(i8* %x) nounwind ; <i32> [#uses=0]
|
||||||
|
br label %if.end
|
||||||
|
|
||||||
|
if.end: ; preds = %if.else16, %if.then14
|
||||||
|
br label %if.end19
|
||||||
|
|
||||||
|
if.end19: ; preds = %if.end, %if.then9
|
||||||
|
br label %if.end20
|
||||||
|
|
||||||
|
if.end20: ; preds = %if.end19, %if.then2
|
||||||
|
br label %if.end21
|
||||||
|
|
||||||
|
if.end21: ; preds = %if.end20, %if.then
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
|
||||||
|
declare i32 @puts(i8*)
|
Loading…
x
Reference in New Issue
Block a user