mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2025-02-09 10:55:03 +00:00
Rework CFG edges to encode potentially unreachable edges, instead of just making them NULL.
This is to support some analyses, like -Wunreachable-code, that will need to recover the original unprunned CFG edges in order to suppress issues that aren't really bugs in practice. There are two important changes here: - AdjacentBlock replaces CFGBlock* for CFG successors/predecessors. This has the size of 2 pointers, instead of 1. This is unlikely to have a significant memory impact on Sema since a single CFG usually exists at one time, but could impact the memory usage of the static analyzer. This could possibly be optimized down to a single pointer with some cleverness. - Predecessors can now contain null predecessors, which means some analyses doing a reverse traversal will need to take into account. This already exists for successors, which contain successor slots for specific branch kinds (e.g., 'if') that expect a fixed number of successors, even if a branch is not reachable. llvm-svn: 202325
This commit is contained in:
parent
2eab2bd86d
commit
4b6fee6cc4
@ -412,9 +412,64 @@ class CFGBlock {
|
||||
/// of the CFG.
|
||||
unsigned BlockID;
|
||||
|
||||
public:
|
||||
/// This class represents a potential adjacent block in the CFG. It encodes
|
||||
/// whether or not the block is actually reachable, or can be proved to be
|
||||
/// trivially unreachable. For some cases it allows one to encode scenarios
|
||||
/// where a block was substituted because the original (now alternate) block
|
||||
/// is unreachable.
|
||||
class AdjacentBlock {
|
||||
enum Kind {
|
||||
AB_Normal,
|
||||
AB_Unreachable,
|
||||
AB_Alternate
|
||||
};
|
||||
|
||||
CFGBlock *ReachableBlock;
|
||||
llvm::PointerIntPair<CFGBlock*, 2> UnreachableBlock;
|
||||
|
||||
public:
|
||||
/// Construct an AdjacentBlock with a possibly unreachable block.
|
||||
AdjacentBlock(CFGBlock *B, bool IsReachable);
|
||||
|
||||
/// Construct an AdjacentBlock with a reachable block and an alternate
|
||||
/// unreachable block.
|
||||
AdjacentBlock(CFGBlock *B, CFGBlock *AlternateBlock);
|
||||
|
||||
/// Get the reachable block, if one exists.
|
||||
CFGBlock *getReachableBlock() const {
|
||||
return ReachableBlock;
|
||||
}
|
||||
|
||||
/// Get the potentially unreachable block.
|
||||
CFGBlock *getPossiblyUnreachableBlock() const {
|
||||
return UnreachableBlock.getPointer();
|
||||
}
|
||||
|
||||
/// Provide an implicit conversion to CFGBlock* so that
|
||||
/// AdjacentBlock can be substituted for CFGBlock*.
|
||||
operator CFGBlock*() const {
|
||||
return getReachableBlock();
|
||||
}
|
||||
|
||||
CFGBlock& operator *() const {
|
||||
return *getReachableBlock();
|
||||
}
|
||||
|
||||
CFGBlock* operator ->() const {
|
||||
return getReachableBlock();
|
||||
}
|
||||
|
||||
bool isReachable() const {
|
||||
Kind K = (Kind) UnreachableBlock.getInt();
|
||||
return K == AB_Normal || K == AB_Alternate;
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
/// Predecessors/Successors - Keep track of the predecessor / successor
|
||||
/// CFG blocks.
|
||||
typedef BumpVector<CFGBlock*> AdjacentBlocks;
|
||||
typedef BumpVector<AdjacentBlock> AdjacentBlocks;
|
||||
AdjacentBlocks Preds;
|
||||
AdjacentBlocks Succs;
|
||||
|
||||
@ -504,9 +559,11 @@ public:
|
||||
class FilterOptions {
|
||||
public:
|
||||
FilterOptions() {
|
||||
IgnoreNullPredecessors = 1;
|
||||
IgnoreDefaultsWithCoveredEnums = 0;
|
||||
}
|
||||
|
||||
unsigned IgnoreNullPredecessors : 1;
|
||||
unsigned IgnoreDefaultsWithCoveredEnums : 1;
|
||||
};
|
||||
|
||||
@ -588,11 +645,8 @@ public:
|
||||
OS << "BB#" << getBlockID();
|
||||
}
|
||||
|
||||
void addSuccessor(CFGBlock *Block, BumpVectorContext &C) {
|
||||
if (Block)
|
||||
Block->Preds.push_back(this, C);
|
||||
Succs.push_back(Block, C);
|
||||
}
|
||||
/// Adds a (potentially unreachable) successor block to the current block.
|
||||
void addSuccessor(AdjacentBlock Succ, BumpVectorContext &C);
|
||||
|
||||
void appendStmt(Stmt *statement, BumpVectorContext &C) {
|
||||
Elements.push_back(CFGStmt(statement), C);
|
||||
|
@ -483,8 +483,16 @@ private:
|
||||
void prependAutomaticObjDtorsWithTerminator(CFGBlock *Blk,
|
||||
LocalScope::const_iterator B, LocalScope::const_iterator E);
|
||||
|
||||
void addSuccessor(CFGBlock *B, CFGBlock *S) {
|
||||
B->addSuccessor(S, cfg->getBumpVectorContext());
|
||||
void addSuccessor(CFGBlock *B, CFGBlock *S, bool IsReachable = true) {
|
||||
B->addSuccessor(CFGBlock::AdjacentBlock(S, IsReachable),
|
||||
cfg->getBumpVectorContext());
|
||||
}
|
||||
|
||||
/// Add a reachable successor to a block, with the alternate variant that is
|
||||
/// unreachable.
|
||||
void addSuccessor(CFGBlock *B, CFGBlock *ReachableBlock, CFGBlock *AltBlock) {
|
||||
B->addSuccessor(CFGBlock::AdjacentBlock(ReachableBlock, AltBlock),
|
||||
cfg->getBumpVectorContext());
|
||||
}
|
||||
|
||||
/// Try and evaluate an expression to an integer constant.
|
||||
@ -3495,13 +3503,37 @@ bool CFGImplicitDtor::isNoReturn(ASTContext &astContext) const {
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Filtered walking of the CFG.
|
||||
// CFGBlock operations.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
CFGBlock::AdjacentBlock::AdjacentBlock(CFGBlock *B, bool IsReachable)
|
||||
: ReachableBlock(IsReachable ? B : 0),
|
||||
UnreachableBlock(!IsReachable ? B : 0,
|
||||
B && IsReachable ? AB_Normal : AB_Unreachable) {}
|
||||
|
||||
CFGBlock::AdjacentBlock::AdjacentBlock(CFGBlock *B, CFGBlock *AlternateBlock)
|
||||
: ReachableBlock(B),
|
||||
UnreachableBlock(B == AlternateBlock ? 0 : AlternateBlock,
|
||||
B == AlternateBlock ? AB_Alternate : AB_Normal) {}
|
||||
|
||||
void CFGBlock::addSuccessor(AdjacentBlock Succ,
|
||||
BumpVectorContext &C) {
|
||||
if (CFGBlock *B = Succ.getReachableBlock())
|
||||
B->Preds.push_back(CFGBlock::AdjacentBlock(this, Succ.isReachable()), C);
|
||||
|
||||
if (CFGBlock *UnreachableB = Succ.getPossiblyUnreachableBlock())
|
||||
UnreachableB->Preds.push_back(CFGBlock::AdjacentBlock(this, false), C);
|
||||
|
||||
Succs.push_back(Succ, C);
|
||||
}
|
||||
|
||||
bool CFGBlock::FilterEdge(const CFGBlock::FilterOptions &F,
|
||||
const CFGBlock *From, const CFGBlock *To) {
|
||||
|
||||
if (To && F.IgnoreDefaultsWithCoveredEnums) {
|
||||
if (F.IgnoreNullPredecessors && !From)
|
||||
return true;
|
||||
|
||||
if (To && From && F.IgnoreDefaultsWithCoveredEnums) {
|
||||
// If the 'To' has no label or is labeled but the label isn't a
|
||||
// CaseStmt then filter this edge.
|
||||
if (const SwitchStmt *S =
|
||||
@ -3963,7 +3995,16 @@ static void print_block(raw_ostream &OS, const CFG* cfg,
|
||||
if (i % 10 == 8)
|
||||
OS << "\n ";
|
||||
|
||||
OS << " B" << (*I)->getBlockID();
|
||||
CFGBlock *B = *I;
|
||||
bool Reachable = true;
|
||||
if (!B) {
|
||||
Reachable = false;
|
||||
B = I->getPossiblyUnreachableBlock();
|
||||
}
|
||||
|
||||
OS << " B" << B->getBlockID();
|
||||
if (!Reachable)
|
||||
OS << "(Unreachable)";
|
||||
}
|
||||
|
||||
if (ShowColors)
|
||||
|
@ -69,7 +69,8 @@ void CFGReverseBlockReachabilityAnalysis::mapReachability(const CFGBlock *Dst) {
|
||||
// Add the predecessors to the worklist.
|
||||
for (CFGBlock::const_pred_iterator i = block->pred_begin(),
|
||||
e = block->pred_end(); i != e; ++i) {
|
||||
worklist.push_back(*i);
|
||||
if (*i)
|
||||
worklist.push_back(*i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -535,6 +535,9 @@ public:
|
||||
for (CFGBlock::const_pred_iterator I = B->pred_begin(), E = B->pred_end();
|
||||
I != E; ++I) {
|
||||
const CFGBlock *Pred = *I;
|
||||
if (!Pred)
|
||||
continue;
|
||||
|
||||
Value AtPredExit = vals.getValue(Pred, B, vd);
|
||||
if (AtPredExit == Initialized)
|
||||
// This block initializes the variable.
|
||||
@ -751,6 +754,8 @@ static bool runOnBlock(const CFGBlock *block, const CFG &cfg,
|
||||
for (CFGBlock::const_pred_iterator I = block->pred_begin(),
|
||||
E = block->pred_end(); I != E; ++I) {
|
||||
const CFGBlock *pred = *I;
|
||||
if (!pred)
|
||||
continue;
|
||||
if (wasAnalyzed[pred->getBlockID()]) {
|
||||
vals.mergeIntoScratch(vals.getValueVector(pred), isFirst);
|
||||
isFirst = false;
|
||||
|
Loading…
x
Reference in New Issue
Block a user