CIRCT 23.0.0git
Loading...
Searching...
No Matches
PopulateInstanceChoiceSymbols.cpp
Go to the documentation of this file.
1//===----------------------------------------------------------------------===//
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// This file defines the PopulateInstanceChoiceSymbols pass, which populates
10// globally unique instance macros for all instance choice operations.
11//
12//===----------------------------------------------------------------------===//
13
20#include "mlir/Pass/Pass.h"
21#include "llvm/ADT/DenseMap.h"
22#include "llvm/Support/Debug.h"
23
24#define DEBUG_TYPE "firrtl-populate-instance-choice-symbols"
25
26namespace circt {
27namespace firrtl {
28#define GEN_PASS_DEF_POPULATEINSTANCECHOICESYMBOLS
29#include "circt/Dialect/FIRRTL/Passes.h.inc"
30} // namespace firrtl
31} // namespace circt
32
33using namespace circt;
34using namespace firrtl;
35
36namespace {
37
38void getOptionCaseMacroName(StringAttr optionName, StringAttr caseName,
39 SmallVectorImpl<char> &macroName) {
40 llvm::raw_svector_ostream os(macroName);
41 os << "__option_" << optionName.getValue() << "_" << caseName.getValue();
42}
43
44class PopulateInstanceChoiceSymbolsPass
45 : public impl::PopulateInstanceChoiceSymbolsBase<
46 PopulateInstanceChoiceSymbolsPass> {
47public:
48 void runOnOperation() override;
49
50private:
51 /// Assign a unique instance macro symbol to the given instance choice
52 /// operation. Returns the assigned symbol, or nullptr if the operation
53 /// already has a symbol.
54 FlatSymbolRefAttr assignSymbol(InstanceChoiceOp op);
55
56 /// The namespace associated with the circuit. This is lazily constructed
57 /// using `getNamespace`.
58 std::optional<CircuitNamespace> circuitNamespace;
59 CircuitNamespace &getNamespace() {
60 if (!circuitNamespace)
61 circuitNamespace = CircuitNamespace(getOperation());
62 return *circuitNamespace;
63 }
64};
65} // namespace
66
67FlatSymbolRefAttr
68PopulateInstanceChoiceSymbolsPass::assignSymbol(InstanceChoiceOp op) {
69 // Skip if already has an instance macro.
70 if (op.getInstanceMacroAttr())
71 return nullptr;
72
73 // Get the parent module name.
74 auto parentModule = op->getParentOfType<FModuleLike>();
75
76 // Get the option name.
77 auto optionName = op.getOptionNameAttr();
78
79 // Generate the instance macro name.
80 // This is not public API and can be generated in any way as long as it's
81 // unique.
82 SmallString<128> instanceMacroName;
83 {
84 llvm::raw_svector_ostream os(instanceMacroName);
85 os << "__target_" << optionName.getValue() << "_"
86 << parentModule.getModuleName() << "_" << op.getInstanceName();
87 }
88
89 // Ensure global uniqueness using CircuitNamespace.
90 auto uniqueName = StringAttr::get(op.getContext(),
91 getNamespace().newName(instanceMacroName));
92 auto instanceMacro = FlatSymbolRefAttr::get(uniqueName);
93 op.setInstanceMacroAttr(instanceMacro);
94
95 LLVM_DEBUG(llvm::dbgs() << "Assigned instance macro '" << uniqueName
96 << "' to instance choice '" << op.getInstanceName()
97 << "' in module '" << parentModule.getModuleName()
98 << "'\n");
99
100 return instanceMacro;
101}
102
103void PopulateInstanceChoiceSymbolsPass::runOnOperation() {
104 auto circuit = getOperation();
105 auto &instanceGraph = getAnalysis<InstanceGraph>();
106
107 OpBuilder builder(circuit.getContext());
108 builder.setInsertionPointToStart(circuit.getBodyBlock());
109
110 llvm::DenseSet<StringAttr> createdInstanceMacros;
111 bool changed = false;
112
113 // First, walk all OptionOps and assign case macros to OptionCaseOps.
114 for (auto optionOp : circuit.getOps<OptionOp>()) {
115 auto optionName = optionOp.getSymNameAttr();
116
117 for (auto caseOp : optionOp.getOps<OptionCaseOp>()) {
118 // Skip if already has a case macro.
119 if (caseOp.getCaseMacroAttr())
120 continue;
121
122 auto caseName = caseOp.getSymNameAttr();
123 SmallString<128> caseMacroName;
124 getOptionCaseMacroName(optionName, caseName, caseMacroName);
125
126 // Ensure global uniqueness using CircuitNamespace.
127 auto caseMacro = FlatSymbolRefAttr::get(
128 circuit.getContext(), getNamespace().newName(caseMacroName));
129
130 // Set the case_macro attribute on the OptionCaseOp.
131 caseOp.setCaseMacroAttr(caseMacro);
132 changed = true;
133
134 // Create macro declaration.
135 sv::MacroDeclOp::create(builder, circuit.getLoc(), caseMacro.getValue());
136
137 LLVM_DEBUG(llvm::dbgs() << "Assigned case macro '" << caseMacro.getValue()
138 << "' to option case '" << caseName
139 << "' in option '" << optionName << "'\n");
140 }
141 }
142
143 // Second, iterate through all instance choices and assign instance macros.
144 instanceGraph.walkPostOrder([&](igraph::InstanceGraphNode &node) {
145 auto module = dyn_cast<FModuleLike>(node.getModule().getOperation());
146 if (!module)
147 return;
148
149 for (auto *record : node) {
150 auto op = record->getInstance<InstanceChoiceOp>();
151 if (!op)
152 continue;
153
154 auto instanceMacro = assignSymbol(op);
155 if (!instanceMacro)
156 continue;
157 changed = true;
158
159 // Create instance macro declaration only if we haven't created it yet.
160 if (createdInstanceMacros.insert(instanceMacro.getAttr()).second)
161 sv::MacroDeclOp::create(builder, circuit.getLoc(),
162 instanceMacro.getAttr());
163 }
164 });
165
166 circuitNamespace.reset();
167 if (!changed)
168 return markAllAnalysesPreserved();
169
170 markAnalysesPreserved<InstanceGraph, InstanceInfo>();
171}
This is a Node in the InstanceGraph.
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
The namespace of a CircuitOp, generally inhabited by modules.
Definition Namespace.h:24