CIRCT 20.0.0git
Loading...
Searching...
No Matches
DebugInfo.cpp
Go to the documentation of this file.
1//===- DebugInfo.cpp - Debug info analysis --------------------------------===//
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
12#include "mlir/IR/BuiltinOps.h"
13#include "llvm/Support/Debug.h"
14
15#define DEBUG_TYPE "di"
16
17using namespace mlir;
18using namespace circt;
19
20namespace circt {
21namespace detail {
22
23/// Helper to populate a `DebugInfo` with nodes.
27
28 void visitRoot(Operation *op);
29 void visitModule(hw::HWModuleOp moduleOp, DIModule &module);
30
32 return new (di.moduleAllocator.Allocate()) DIModule;
33 }
34
36 return new (di.instanceAllocator.Allocate()) DIInstance;
37 }
38
40 return new (di.variableAllocator.Allocate()) DIVariable;
41 }
42
43 DIModule &getOrCreateModule(StringAttr moduleName) {
44 auto &slot = di.moduleNodes[moduleName];
45 if (!slot) {
46 slot = createModule();
47 slot->name = moduleName;
48 }
49 return *slot;
50 }
51};
52
53void DebugInfoBuilder::visitRoot(Operation *op) {
54 op->walk<WalkOrder::PreOrder>([&](Operation *op) {
55 if (auto moduleOp = dyn_cast<hw::HWModuleOp>(op)) {
56 LLVM_DEBUG(llvm::dbgs()
57 << "Collect DI for module " << moduleOp.getNameAttr() << "\n");
58 auto &module = getOrCreateModule(moduleOp.getNameAttr());
59 module.op = op;
60 visitModule(moduleOp, module);
61 return WalkResult::skip();
62 }
63
64 if (auto moduleOp = dyn_cast<hw::HWModuleExternOp>(op)) {
65 LLVM_DEBUG(llvm::dbgs() << "Collect DI for extern module "
66 << moduleOp.getNameAttr() << "\n");
67 auto &module = getOrCreateModule(moduleOp.getNameAttr());
68 module.op = op;
69 module.isExtern = true;
70
71 // Add variables for each of the ports.
72 for (auto &port : moduleOp.getPortList()) {
73 auto *var = createVariable();
74 var->name = port.name;
75 var->loc = port.loc;
76 module.variables.push_back(var);
77 }
78
79 return WalkResult::skip();
80 }
81
82 return WalkResult::advance();
83 });
84}
85
87 // Try to gather debug info from debug ops in the module. If we find any,
88 // return. Otherwise collect ports, instances, and variables as a
89 // fallback.
90
91 // Check what kind of DI is present in the module. Also create additional
92 // `DIModule` hierarchy levels for each explicit scope op in the module.
94 bool hasVariables = false;
95 bool hasInstances = false;
96 moduleOp.walk([&](Operation *op) {
97 if (isa<debug::VariableOp>(op))
98 hasVariables = true;
99 if (auto scopeOp = dyn_cast<debug::ScopeOp>(op)) {
100 auto *node = createModule();
101 node->isInline = true;
102 node->name = scopeOp.getModuleNameAttr();
103 node->op = scopeOp;
104 scopes.insert({scopeOp, node});
105 }
106 });
107
108 // Helper function to resolve a `scope` operand on a variable to the
109 // `DIModule` into which the variable should be collected. If the `scope` is
110 // not set, or it isn't a valid `dbg.scope` op, returns the `module` argument
111 // of this function.
112 auto getScope = [&](Value scopeValue) -> DIModule & {
113 if (scopeValue)
114 if (auto scopeOp = scopeValue.getDefiningOp<debug::ScopeOp>())
115 return *scopes.lookup(scopeOp);
116 return module;
117 };
118
119 // If the module has no DI for variables, add variables for each of the ports
120 // as a fallback.
121 if (!hasVariables) {
122 auto inputValues = moduleOp.getBody().getArguments();
123 auto outputValues = moduleOp.getBodyBlock()->getTerminator()->getOperands();
124 for (auto &port : moduleOp.getPortList()) {
125 auto value = port.isOutput() ? outputValues[port.argNum]
126 : inputValues[port.argNum];
127 auto *var = createVariable();
128 var->name = port.name;
129 var->loc = port.loc;
130 var->value = value;
131 module.variables.push_back(var);
132 }
133 }
134
135 // Fill in any missing DI as a fallback.
136 moduleOp->walk([&](Operation *op) {
137 if (auto varOp = dyn_cast<debug::VariableOp>(op)) {
138 auto *var = createVariable();
139 var->name = varOp.getNameAttr();
140 var->loc = varOp.getLoc();
141 var->value = varOp.getValue();
142 getScope(varOp.getScope()).variables.push_back(var);
143 return;
144 }
145
146 if (auto scopeOp = dyn_cast<debug::ScopeOp>(op)) {
147 auto *instance = createInstance();
148 instance->name = scopeOp.getInstanceNameAttr();
149 instance->op = scopeOp;
150 instance->module = scopes.lookup(scopeOp);
151 getScope(scopeOp.getScope()).instances.push_back(instance);
152 }
153
154 // Fallback if the module has no DI for its instances.
155 if (!hasInstances) {
156 if (auto instOp = dyn_cast<hw::InstanceOp>(op)) {
157 auto &childModule =
158 getOrCreateModule(instOp.getModuleNameAttr().getAttr());
159 auto *instance = createInstance();
160 instance->name = instOp.getInstanceNameAttr();
161 instance->op = instOp;
162 instance->module = &childModule;
163 module.instances.push_back(instance);
164
165 // TODO: What do we do with the port assignments? These should be
166 // tracked somewhere.
167 return;
168 }
169 }
170
171 // Fallback if the module has no DI for its variables.
172 if (!hasVariables) {
173 if (auto wireOp = dyn_cast<hw::WireOp>(op)) {
174 auto *var = createVariable();
175 var->name = wireOp.getNameAttr();
176 var->loc = wireOp.getLoc();
177 var->value = wireOp;
178 module.variables.push_back(var);
179 return;
180 }
181 }
182 });
183}
184
185} // namespace detail
186} // namespace circt
187
188DebugInfo::DebugInfo(Operation *op) : operation(op) {
190}
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
Debug information attached to an operation and the operations nested within.
Definition DebugInfo.h:63
llvm::SpecificBumpPtrAllocator< DIInstance > instanceAllocator
Definition DebugInfo.h:75
llvm::SpecificBumpPtrAllocator< DIModule > moduleAllocator
Definition DebugInfo.h:74
llvm::SpecificBumpPtrAllocator< DIVariable > variableAllocator
Definition DebugInfo.h:76
llvm::MapVector< StringAttr, DIModule * > moduleNodes
A mapping from module name to module debug info.
Definition DebugInfo.h:70
DebugInfo(Operation *op)
Collect the debug information nested under the given operation.
Helper to populate a DebugInfo with nodes.
Definition DebugInfo.cpp:24
void visitRoot(Operation *op)
Definition DebugInfo.cpp:53
DIModule & getOrCreateModule(StringAttr moduleName)
Definition DebugInfo.cpp:43
void visitModule(hw::HWModuleOp moduleOp, DIModule &module)
Definition DebugInfo.cpp:86