// Check if we can reason about the region control-flow.
if (auto branch = dyn_cast<RegionBranchOpInterface>(op)) {
LDBG() << "Visiting region branch operation: "
<< OpWithFlags(op, OpPrintingFlags().skipRegions());
visitRegionBranchOperation(branch);
// Check if this is a callable operation.
} else if (auto callable = dyn_cast<CallableOpInterface>(op)) {
LDBG() << "Visiting callable operation: "
<< OpWithFlags(op, OpPrintingFlags().skipRegions());
const auto *callsites = getOrCreateFor<PredecessorState>(
getProgramPointAfter(op), getProgramPointAfter(callable));
// If the callsites could not be resolved or are known to be non-empty,
// mark the callable as executable.
if (!callsites->allPredecessorsKnown() ||
!callsites->getKnownPredecessors().empty())
markEntryBlocksLive(callable);
// Otherwise, conservatively mark all entry blocks as executable.
} else {
The above is a piece of dead code analysis code.I don’t quite understand why this is written here
const auto *callsites = getOrCreateFor<PredecessorState>(
getProgramPointAfter(op), getProgramPointAfter(callable));
In my view, getProgramPointAfter(op) and getProgramPointAfter(callable) are one and the same.
};
//===----------------------------------------------------------------------===//
// PredecessorState
//===----------------------------------------------------------------------===//
/// This analysis state represents a set of live control-flow "predecessors" of
/// a program point (either an operation or a block), which are the last
/// operations along all execution paths that pass through this point.
///
/// For example, in dead-code analysis, an operation with region control-flow
/// can be the predecessor of a region's entry block or itself, the exiting
/// terminator of a region can be the predecessor of the parent operation or
/// another region's entry block, the callsite of a callable operation can be
/// the predecessor to its entry block, and the exiting terminator or a callable
/// operation can be the predecessor of the call operation.
///
/// The state can optionally contain information about which values are
/// propagated from each predecessor to the successor point.
///
/// The state can indicate that it is underdefined, meaning that not all live
Another point is why the location of callsites is obtained through getProgramPointAfter(op) or getProgramPointAfter(callable).
func.func @func {
// Is this the location obtained by getProgramPointAfter(callable)?
entry block:
}
// Is the position obtained by getProgramPointAfter(callable) still here?
I hope someone can help me. Thank you very much.