CIRCT 20.0.0git
Loading...
Searching...
No Matches
MaterializeDebugInfo.cpp
Go to the documentation of this file.
1//===- MaterializeDebugInfo.cpp - DI materialization ----------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
14#include "mlir/IR/Attributes.h"
15#include "mlir/IR/Builders.h"
16#include "mlir/Pass/Pass.h"
17
18namespace circt {
19namespace firrtl {
20#define GEN_PASS_DEF_MATERIALIZEDEBUGINFO
21#include "circt/Dialect/FIRRTL/Passes.h.inc"
22} // namespace firrtl
23} // namespace circt
24
25using namespace mlir;
26using namespace circt;
27using namespace firrtl;
28
29namespace {
30struct MaterializeDebugInfoPass
31 : public circt::firrtl::impl::MaterializeDebugInfoBase<
32 MaterializeDebugInfoPass> {
33 void runOnOperation() override;
34 void materializeVariable(OpBuilder &builder, StringAttr name, Value value);
35 Value convertToDebugAggregates(OpBuilder &builder, Value value);
36};
37} // namespace
38
39void MaterializeDebugInfoPass::runOnOperation() {
40 auto module = getOperation();
41 auto builder = OpBuilder::atBlockBegin(module.getBodyBlock());
42
43 // Create DI variables for each port.
44 for (const auto &[port, value] :
45 llvm::zip(module.getPorts(), module.getArguments())) {
46 materializeVariable(builder, port.name, value);
47 }
48
49 // Create DI variables for each declaration in the module body.
50 module.walk([&](Operation *op) {
51 TypeSwitch<Operation *>(op).Case<WireOp, NodeOp, RegOp, RegResetOp>(
52 [&](auto op) {
53 builder.setInsertionPointAfter(op);
54 materializeVariable(builder, op.getNameAttr(), op.getResult());
55 });
56 });
57}
58
59/// Materialize debug variable ops for a value.
60void MaterializeDebugInfoPass::materializeVariable(OpBuilder &builder,
61 StringAttr name,
62 Value value) {
63 if (!name || isUselessName(name.getValue()))
64 return;
65 if (name.getValue().starts_with("_"))
66 return;
67 if (auto dbgValue = convertToDebugAggregates(builder, value))
68 builder.create<debug::VariableOp>(value.getLoc(), name, dbgValue,
69 /*scope=*/Value{});
70}
71
72/// Unpack all aggregates in a FIRRTL value and repack them as debug aggregates.
73/// For example, converts a FIRRTL vector `v` into `dbg.array [v[0],v[1],...]`.
74Value MaterializeDebugInfoPass::convertToDebugAggregates(OpBuilder &builder,
75 Value value) {
76 return FIRRTLTypeSwitch<Type, Value>(value.getType())
77 .Case<BundleType>([&](auto type) {
78 SmallVector<Value> fields;
79 SmallVector<Attribute> names;
80 SmallVector<Operation *> subOps;
81 for (auto [index, element] : llvm::enumerate(type.getElements())) {
82 auto subOp = builder.create<SubfieldOp>(value.getLoc(), value, index);
83 subOps.push_back(subOp);
84 if (auto dbgValue = convertToDebugAggregates(builder, subOp)) {
85 fields.push_back(dbgValue);
86 names.push_back(element.name);
87 }
88 }
89 auto result = builder.create<debug::StructOp>(
90 value.getLoc(), fields, builder.getArrayAttr(names));
91 for (auto *subOp : subOps)
92 if (subOp->use_empty())
93 subOp->erase();
94 return result;
95 })
96 .Case<FVectorType>([&](auto type) -> Value {
97 SmallVector<Value> elements;
98 SmallVector<Operation *> subOps;
99 for (unsigned index = 0; index < type.getNumElements(); ++index) {
100 auto subOp = builder.create<SubindexOp>(value.getLoc(), value, index);
101 subOps.push_back(subOp);
102 if (auto dbgValue = convertToDebugAggregates(builder, subOp))
103 elements.push_back(dbgValue);
104 }
105 Value result;
106 if (!elements.empty() && elements.size() == type.getNumElements())
107 result = builder.create<debug::ArrayOp>(value.getLoc(), elements);
108 for (auto *subOp : subOps)
109 if (subOp->use_empty())
110 subOp->erase();
111 return result;
112 })
113 .Case<FIRRTLBaseType>(
114 [&](auto type) { return type.isGround() ? value : Value{}; })
115 .Default({});
116}
117
119 return std::make_unique<MaterializeDebugInfoPass>();
120}
This class implements the same functionality as TypeSwitch except that it uses firrtl::type_dyn_cast ...
FIRRTLTypeSwitch< T, ResultT > & Case(CallableT &&caseFn)
Add a case on the given type.
std::unique_ptr< mlir::Pass > createMaterializeDebugInfoPass()
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
bool isUselessName(StringRef name)
Return true if this is a possibly useless temporary name.
Definition Naming.cpp:16