CIRCT  20.0.0git
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 
13 #include "circt/Support/Naming.h"
14 #include "mlir/IR/Attributes.h"
15 #include "mlir/IR/Builders.h"
16 #include "mlir/Pass/Pass.h"
17 
18 namespace circt {
19 namespace firrtl {
20 #define GEN_PASS_DEF_MATERIALIZEDEBUGINFO
21 #include "circt/Dialect/FIRRTL/Passes.h.inc"
22 } // namespace firrtl
23 } // namespace circt
24 
25 using namespace mlir;
26 using namespace circt;
27 using namespace firrtl;
28 
29 namespace {
30 struct 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 
39 void 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.
60 void 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],...]`.
74 Value 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 
118 std::unique_ptr<Pass> firrtl::createMaterializeDebugInfoPass() {
119  return std::make_unique<MaterializeDebugInfoPass>();
120 }
This class implements the same functionality as TypeSwitch except that it uses firrtl::type_dyn_cast ...
Definition: FIRRTLTypes.h:520
FIRRTLTypeSwitch< T, ResultT > & Case(CallableT &&caseFn)
Add a case on the given type.
Definition: FIRRTLTypes.h:530
std::unique_ptr< mlir::Pass > createMaterializeDebugInfoPass()
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
Definition: DebugAnalysis.h:21
bool isUselessName(StringRef name)
Return true if this is a possibly useless temporary name.
Definition: Naming.cpp:16