/// state.
void visitBlockArgument(Block *block, int i);
+ /// Mark the entry block of the given region as executable. Returns false if
+ /// the block was already marked executable. If `markArgsOverdefined` is true,
+ /// the arguments of the entry block are also set to overdefined.
+ bool markEntryBlockExecutable(Region *region, bool markArgsOverdefined);
+
/// Mark the given block as executable. Returns false if the block was already
/// marked executable.
bool markBlockExecutable(Block *block);
SCCPSolver::SCCPSolver(Operation *op) {
/// Initialize the solver with the regions within this operation.
for (Region ®ion : op->getRegions()) {
- if (region.empty())
- continue;
- Block *entryBlock = ®ion.front();
-
- // Mark the entry block as executable.
- markBlockExecutable(entryBlock);
-
- // The values passed to these regions are invisible, so mark any arguments
- // as overdefined.
- markAllOverdefined(entryBlock->getArguments());
+ // Mark the entry block as executable. The values passed to these regions
+ // are also invisible, so mark any arguments as overdefined.
+ markEntryBlockExecutable(®ion, /*markArgsOverdefined=*/true);
}
initializeSymbolCallables(op);
}
// If not all of the uses of this symbol are visible, we can't track the
// state of the arguments.
- if (symbol.isPublic() || (!allUsesVisible && symbol.isNested()))
- markAllOverdefined(callableRegion->getArguments());
+ if (symbol.isPublic() || (!allUsesVisible && symbol.isNested())) {
+ for (Region ®ion : callable->getRegions())
+ markEntryBlockExecutable(®ion, /*markArgsOverdefined=*/true);
+ }
}
if (callableLatticeState.empty())
return;
// This use isn't a call, so don't we know all of the callers.
auto *symbol = symbolTable.lookupSymbolIn(op, use.getSymbolRef());
auto it = callableLatticeState.find(symbol);
- if (it != callableLatticeState.end())
- markAllOverdefined(it->second.getCallableArguments());
+ if (it != callableLatticeState.end()) {
+ for (Region ®ion : it->first->getRegions())
+ markEntryBlockExecutable(®ion, /*markArgsOverdefined=*/true);
+ }
}
};
SymbolTable::walkSymbolTables(op, /*allSymUsesVisible=*/!op->getBlock(),
// Process callable operations. These are specially handled region operations
// that track dataflow via calls.
- if (isa<CallableOpInterface>(op))
+ if (isa<CallableOpInterface>(op)) {
+ // If this callable has a tracked lattice state, it will be visited by calls
+ // that reference it instead. This way, we don't assume that it is
+ // executable unless there is a proper reference to it.
+ if (callableLatticeState.count(op))
+ return;
return visitCallableOperation(op);
+ }
// Process region holding operations. The region visitor processes result
// values, so we can exit afterwards.
}
void SCCPSolver::visitCallableOperation(Operation *op) {
- // Mark the regions as executable.
+ // Mark the regions as executable. If we aren't tracking lattice state for
+ // this callable, mark all of the region arguments as overdefined.
bool isTrackingLatticeState = callableLatticeState.count(op);
- for (Region ®ion : op->getRegions()) {
- if (region.empty())
- continue;
- Block *entryBlock = ®ion.front();
- markBlockExecutable(entryBlock);
-
- // If we aren't tracking lattice state for this callable, mark all of the
- // region arguments as overdefined.
- if (!isTrackingLatticeState)
- markAllOverdefined(entryBlock->getArguments());
- }
+ for (Region ®ion : op->getRegions())
+ markEntryBlockExecutable(®ion, !isTrackingLatticeState);
// TODO: Add support for non-symbol callables when necessary. If the callable
// has non-call uses we would mark overdefined, otherwise allow for
visitUsers(callableArg);
}
+ // Visit the callable.
+ visitCallableOperation(callableOp);
+
// Merge in the lattice state for the callable results as well.
auto callableResults = callableLatticeIt->second.getResultLatticeValues();
for (auto it : llvm::zip(callResults, callableResults))
auto regionInterface = dyn_cast<RegionBranchOpInterface>(op);
if (!regionInterface) {
// If we can't, conservatively mark all regions as executable.
- for (Region ®ion : op->getRegions()) {
- if (region.empty())
- continue;
- Block *entryBlock = ®ion.front();
- markBlockExecutable(entryBlock);
- markAllOverdefined(entryBlock->getArguments());
- }
+ for (Region ®ion : op->getRegions())
+ markEntryBlockExecutable(®ion, /*markArgsOverdefined=*/true);
// Don't try to simulate the results of a region operation as we can't
// guarantee that folding will be out-of-place. We don't allow in-place
visitUsers(arg);
}
+bool SCCPSolver::markEntryBlockExecutable(Region *region,
+ bool markArgsOverdefined) {
+ if (!region->empty()) {
+ if (markArgsOverdefined)
+ markAllOverdefined(region->front().getArguments());
+ return markBlockExecutable(®ion->front());
+ }
+ return false;
+}
+
bool SCCPSolver::markBlockExecutable(Block *block) {
bool marked = executableBlocks.insert(block).second;
if (marked)