CIRCT  19.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 
9 #include "PassDetails.h"
13 #include "circt/Support/Naming.h"
14 #include "mlir/IR/Attributes.h"
15 #include "mlir/IR/Builders.h"
16 #include "llvm/ADT/StringExtras.h"
17 #include "llvm/Support/Parallel.h"
18 
19 using namespace mlir;
20 using namespace circt;
21 using namespace firrtl;
22 
23 namespace {
24 struct MaterializeDebugInfoPass
25  : public MaterializeDebugInfoBase<MaterializeDebugInfoPass> {
26  void runOnOperation() override;
27  void materializeVariable(OpBuilder &builder, StringAttr name, Value value);
28  Value convertToDebugAggregates(OpBuilder &builder, Value value);
29 };
30 } // namespace
31 
32 void MaterializeDebugInfoPass::runOnOperation() {
33  auto module = getOperation();
34  auto builder = OpBuilder::atBlockBegin(module.getBodyBlock());
35 
36  // Create DI variables for each port.
37  for (const auto &[port, value] :
38  llvm::zip(module.getPorts(), module.getArguments())) {
39  materializeVariable(builder, port.name, value);
40  }
41 
42  // Create DI variables for each declaration in the module body.
43  module.walk([&](Operation *op) {
44  TypeSwitch<Operation *>(op).Case<WireOp, NodeOp, RegOp, RegResetOp>(
45  [&](auto op) {
46  builder.setInsertionPointAfter(op);
47  materializeVariable(builder, op.getNameAttr(), op.getResult());
48  });
49  });
50 }
51 
52 /// Materialize debug variable ops for a value.
53 void MaterializeDebugInfoPass::materializeVariable(OpBuilder &builder,
54  StringAttr name,
55  Value value) {
56  if (!name || isUselessName(name.getValue()))
57  return;
58  if (name.getValue().starts_with("_"))
59  return;
60  if (auto dbgValue = convertToDebugAggregates(builder, value))
61  builder.create<debug::VariableOp>(value.getLoc(), name, dbgValue,
62  /*scope=*/Value{});
63 }
64 
65 /// Unpack all aggregates in a FIRRTL value and repack them as debug aggregates.
66 /// For example, converts a FIRRTL vector `v` into `dbg.array [v[0],v[1],...]`.
67 Value MaterializeDebugInfoPass::convertToDebugAggregates(OpBuilder &builder,
68  Value value) {
69  return FIRRTLTypeSwitch<Type, Value>(value.getType())
70  .Case<BundleType>([&](auto type) {
71  SmallVector<Value> fields;
72  SmallVector<Attribute> names;
73  SmallVector<Operation *> subOps;
74  for (auto [index, element] : llvm::enumerate(type.getElements())) {
75  auto subOp = builder.create<SubfieldOp>(value.getLoc(), value, index);
76  subOps.push_back(subOp);
77  if (auto dbgValue = convertToDebugAggregates(builder, subOp)) {
78  fields.push_back(dbgValue);
79  names.push_back(element.name);
80  }
81  }
82  auto result = builder.create<debug::StructOp>(
83  value.getLoc(), fields, builder.getArrayAttr(names));
84  for (auto *subOp : subOps)
85  if (subOp->use_empty())
86  subOp->erase();
87  return result;
88  })
89  .Case<FVectorType>([&](auto type) -> Value {
90  SmallVector<Value> elements;
91  SmallVector<Operation *> subOps;
92  for (unsigned index = 0; index < type.getNumElements(); ++index) {
93  auto subOp = builder.create<SubindexOp>(value.getLoc(), value, index);
94  subOps.push_back(subOp);
95  if (auto dbgValue = convertToDebugAggregates(builder, subOp))
96  elements.push_back(dbgValue);
97  }
98  Value result;
99  if (!elements.empty() && elements.size() == type.getNumElements())
100  result = builder.create<debug::ArrayOp>(value.getLoc(), elements);
101  for (auto *subOp : subOps)
102  if (subOp->use_empty())
103  subOp->erase();
104  return result;
105  })
106  .Case<FIRRTLBaseType>(
107  [&](auto type) { return type.isGround() ? value : Value{}; })
108  .Default({});
109 }
110 
111 std::unique_ptr<Pass> firrtl::createMaterializeDebugInfoPass() {
112  return std::make_unique<MaterializeDebugInfoPass>();
113 }
Builder builder
This class implements the same functionality as TypeSwitch except that it uses firrtl::type_dyn_cast ...
Definition: FIRRTLTypes.h:518
FIRRTLTypeSwitch< T, ResultT > & Case(CallableT &&caseFn)
Add a case on the given type.
Definition: FIRRTLTypes.h:528
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