mirror of https://github.com/llvm/circt.git
129 lines
3.8 KiB
C++
129 lines
3.8 KiB
C++
//===- DebugAnalysis.cpp --------------------------------------------------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "circt/Analysis/DebugAnalysis.h"
|
|
#include "circt/Dialect/Comb/CombOps.h"
|
|
#include "circt/Dialect/Debug/DebugOps.h"
|
|
#include "circt/Dialect/HW/HWOps.h"
|
|
#include "llvm/ADT/SetVector.h"
|
|
#include "llvm/Support/Debug.h"
|
|
|
|
using namespace circt;
|
|
using namespace debug;
|
|
using namespace mlir;
|
|
|
|
namespace {
|
|
struct DebugAnalysisBuilder {
|
|
DebugAnalysisBuilder(Operation *rootOp) : rootOp(rootOp) {}
|
|
void run();
|
|
void addDebugOp(Operation *op);
|
|
void addDebugValue(Value value);
|
|
void addDebugOperand(OpOperand *operand);
|
|
void maybeDebugOp(Operation *op);
|
|
|
|
Operation *rootOp;
|
|
SetVector<Operation *> worklist;
|
|
|
|
DenseSet<Operation *> debugOps;
|
|
DenseSet<Value> debugValues;
|
|
DenseSet<OpOperand *> debugOperands;
|
|
};
|
|
} // namespace
|
|
|
|
void DebugAnalysisBuilder::run() {
|
|
// Find all debug ops nested under the root op and mark them as debug-only
|
|
// to kickstart the analysis.
|
|
rootOp->walk([&](Operation *op) {
|
|
if (isa<debug::DebugDialect>(op->getDialect())) {
|
|
addDebugOp(op);
|
|
return;
|
|
}
|
|
for (auto ®ion : op->getRegions())
|
|
for (auto &block : region)
|
|
for (auto arg : block.getArguments())
|
|
if (isa<debug::DebugDialect>(arg.getType().getDialect()))
|
|
addDebugValue(arg);
|
|
for (auto result : op->getResults())
|
|
if (isa<debug::DebugDialect>(result.getType().getDialect()))
|
|
addDebugValue(result);
|
|
});
|
|
|
|
// Visit operations and check if all their operands or all their uses are
|
|
// marked as debug-only. If they are, mark the op itself as debug-only.
|
|
while (!worklist.empty()) {
|
|
auto *op = worklist.pop_back_val();
|
|
if (debugOps.contains(op))
|
|
continue;
|
|
|
|
// Do not propagate through stateful elements. This should probably be
|
|
// configurable, since certain forms of debug info extraction would be able
|
|
// to pull entire state machines out of the design. For now this just
|
|
// represents the common denominator across all debug infos.
|
|
if (!isa<hw::HWDialect, comb::CombDialect>(op->getDialect()))
|
|
continue;
|
|
if (op->hasAttr("name"))
|
|
continue;
|
|
|
|
if (op->getNumResults() > 0) {
|
|
auto allUsesDebug = llvm::all_of(op->getUses(), [&](auto &use) {
|
|
return debugOperands.contains(&use);
|
|
});
|
|
if (allUsesDebug) {
|
|
addDebugOp(op);
|
|
continue;
|
|
}
|
|
}
|
|
|
|
if (op->getNumOperands() > 0) {
|
|
auto allOperandsDebug =
|
|
llvm::all_of(op->getOperands(), [&](auto operand) {
|
|
return debugValues.contains(operand);
|
|
});
|
|
if (allOperandsDebug) {
|
|
addDebugOp(op);
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void DebugAnalysisBuilder::addDebugOp(Operation *op) {
|
|
if (debugOps.insert(op).second) {
|
|
for (auto &operand : op->getOpOperands())
|
|
addDebugOperand(&operand);
|
|
for (auto result : op->getResults())
|
|
addDebugValue(result);
|
|
}
|
|
}
|
|
|
|
void DebugAnalysisBuilder::addDebugValue(Value value) {
|
|
if (debugValues.insert(value).second) {
|
|
for (auto *user : value.getUsers())
|
|
maybeDebugOp(user);
|
|
}
|
|
}
|
|
|
|
void DebugAnalysisBuilder::addDebugOperand(OpOperand *operand) {
|
|
if (debugOperands.insert(operand).second)
|
|
maybeDebugOp(operand->get().getDefiningOp());
|
|
}
|
|
|
|
void DebugAnalysisBuilder::maybeDebugOp(Operation *op) {
|
|
if (!op || debugOps.contains(op))
|
|
return;
|
|
worklist.insert(op);
|
|
}
|
|
|
|
DebugAnalysis::DebugAnalysis(Operation *op) {
|
|
DebugAnalysisBuilder builder(op);
|
|
builder.run();
|
|
debugOps = std::move(builder.debugOps);
|
|
debugValues = std::move(builder.debugValues);
|
|
debugOperands = std::move(builder.debugOperands);
|
|
}
|