CIRCT 23.0.0git
Loading...
Searching...
No Matches
SpecializeOption.cpp
Go to the documentation of this file.
1//===- SpecializeOption.cpp -------------------------------------*- C++ -*-===//
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
11#include "mlir/IR/ImplicitLocOpBuilder.h"
12#include "mlir/IR/SymbolTable.h"
13#include "mlir/IR/Threading.h"
14#include "mlir/Pass/Pass.h"
15
16namespace circt {
17namespace firrtl {
18#define GEN_PASS_DEF_SPECIALIZEOPTION
19#include "circt/Dialect/FIRRTL/Passes.h.inc"
20} // namespace firrtl
21} // namespace circt
22
23using namespace mlir;
24using namespace circt;
25using namespace firrtl;
26
27namespace {
28struct SpecializeOptionPass
29 : public circt::firrtl::impl::SpecializeOptionBase<SpecializeOptionPass> {
30 using Base::Base;
31
32 void runOnOperation() override {
33 auto circuit = getOperation();
34 auto &symTbl = getAnalysis<SymbolTable>();
35
36 DenseMap<StringAttr, OptionCaseOp> selected;
37 if (auto choiceAttr = circuit.getSelectInstChoiceAttr()) {
38 for (auto attr : choiceAttr.getAsRange<StringAttr>()) {
39 const auto optionAndCase = attr.getValue().str();
40 size_t eq = optionAndCase.find("=");
41 if (eq == std::string::npos) {
42 mlir::emitError(circuit.getLoc(),
43 "invalid option format: \"" + optionAndCase + '"');
44 return signalPassFailure();
45 }
46
47 std::string optionName = optionAndCase.substr(0, eq);
48 // If the option is specified with `?=`, allow the absence of option.
49 bool allowNonExistent = !optionName.empty() && optionName.back() == '?';
50 if (allowNonExistent)
51 optionName.pop_back();
52 auto optionOp = symTbl.lookup<OptionOp>(optionName);
53 if (!optionOp) {
54 if (allowNonExistent)
55 continue;
56 mlir::emitError(circuit.getLoc(), "unknown option \"")
57 << optionName << '"';
58 return signalPassFailure();
59 }
60
61 std::string caseName = optionAndCase.substr(eq + 1);
62 if (caseName == "<default>") {
63 selected[StringAttr::get(&getContext(), optionName)] = {};
64 continue;
65 }
66
67 auto caseOp = optionOp.lookupSymbol<OptionCaseOp>(caseName);
68 if (!caseOp) {
69 mlir::emitError(circuit.getLoc(), "invalid option case \"")
70 << caseName << '"';
71 return signalPassFailure();
72 }
73 selected[StringAttr::get(&getContext(), optionName)] = caseOp;
74 }
75 }
76
77 bool failed = false;
78 mlir::parallelForEach(
79 &getContext(), circuit.getOps<FModuleOp>(), [&](auto module) {
80 module.walk([&](firrtl::InstanceChoiceOp inst) {
81 auto it = selected.find(inst.getOptionNameAttr());
82 FlatSymbolRefAttr target;
83 if (it == selected.end()) {
84 if (selectDefaultInstanceChoice)
85 target = inst.getDefaultTargetAttr();
86 else
87 return;
88 } else {
89 if (it->second)
90 target = inst.getTargetOrDefaultAttr(it->second);
91 else
92 target = inst.getDefaultTargetAttr();
93 }
94
95 ImplicitLocOpBuilder builder(inst.getLoc(), inst);
96 auto newInst = InstanceOp::create(
97 builder, inst->getResultTypes(), target, inst.getNameAttr(),
98 inst.getNameKindAttr(), inst.getPortDirectionsAttr(),
99 inst.getPortNamesAttr(), inst.getDomainInfoAttr(),
100 inst.getAnnotationsAttr(), inst.getPortAnnotationsAttr(),
101 builder.getArrayAttr({}), UnitAttr{}, UnitAttr{},
102 inst.getInnerSymAttr());
103 inst.replaceAllUsesWith(newInst);
104 inst.erase();
105
106 ++numInstances;
107 });
108 });
109
110 bool analysisPreserved = numInstances == 0;
111 circuit->walk([&](OptionOp optionOp) {
112 // When selectDefaultInstanceChoice is true, all instance choices are
113 // specialized (either to a selected case or to the default), so we can
114 // erase all options. Otherwise, only erase options that were selected.
115 if (!selectDefaultInstanceChoice &&
116 !selected.contains(optionOp.getSymNameAttr()))
117 return;
118 optionOp->erase();
119 analysisPreserved = false;
120 });
121 if (analysisPreserved)
122 markAllAnalysesPreserved();
123
124 if (failed)
125 signalPassFailure();
126 }
127};
128} // namespace
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.