CIRCT  20.0.0git
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/Threading.h"
13 #include "mlir/Pass/Pass.h"
14 
15 namespace circt {
16 namespace firrtl {
17 #define GEN_PASS_DEF_SPECIALIZEOPTION
18 #include "circt/Dialect/FIRRTL/Passes.h.inc"
19 } // namespace firrtl
20 } // namespace circt
21 
22 using namespace mlir;
23 using namespace circt;
24 using namespace firrtl;
25 
26 namespace {
27 struct SpecializeOptionPass
28  : public circt::firrtl::impl::SpecializeOptionBase<SpecializeOptionPass> {
29  using SpecializeOptionBase::numInstances;
30  using SpecializeOptionBase::select;
31 
32  void runOnOperation() override {
33  auto circuit = getOperation();
34  if (select.empty()) {
35  markAllAnalysesPreserved();
36  return;
37  }
38 
39  DenseMap<StringAttr, OptionCaseOp> selected;
40  for (const auto &optionAndCase : select) {
41  size_t eq = optionAndCase.find("=");
42  if (eq == std::string::npos) {
43  mlir::emitError(circuit.getLoc(),
44  "invalid option format: \"" + optionAndCase + '"');
45  return signalPassFailure();
46  }
47 
48  std::string optionName = optionAndCase.substr(0, eq);
49  auto optionOp = circuit.lookupSymbol<OptionOp>(optionName);
50  if (!optionOp) {
51  mlir::emitWarning(circuit.getLoc(), "unknown option \"")
52  << optionName << '"';
53  continue;
54  }
55 
56  std::string caseName = optionAndCase.substr(eq + 1);
57  auto caseOp = optionOp.lookupSymbol<OptionCaseOp>(caseName);
58  if (!caseOp) {
59  mlir::emitWarning(circuit.getLoc(), "invalid option case \"")
60  << caseName << '"';
61  continue;
62  }
63  selected[StringAttr::get(&getContext(), optionName)] = caseOp;
64  }
65 
66  bool failed = false;
67  mlir::parallelForEach(
68  &getContext(), circuit.getOps<FModuleOp>(), [&](auto module) {
69  module.walk([&](firrtl::InstanceChoiceOp inst) {
70  auto it = selected.find(inst.getOptionNameAttr());
71  if (it == selected.end()) {
72  inst.emitError("missing specialization for option ")
73  << inst.getOptionNameAttr();
74  failed = true;
75  return;
76  }
77 
78  ImplicitLocOpBuilder builder(inst.getLoc(), inst);
79  auto newInst = builder.create<InstanceOp>(
80  inst->getResultTypes(), inst.getTargetOrDefaultAttr(it->second),
81  inst.getNameAttr(), inst.getNameKindAttr(),
82  inst.getPortDirectionsAttr(), inst.getPortNamesAttr(),
83  inst.getAnnotationsAttr(), inst.getPortAnnotationsAttr(),
84  builder.getArrayAttr({}), UnitAttr{}, inst.getInnerSymAttr());
85  inst.replaceAllUsesWith(newInst);
86  inst.erase();
87 
88  ++numInstances;
89  });
90  });
91 
92  if (failed)
93  signalPassFailure();
94  }
95 };
96 } // namespace
97 
98 std::unique_ptr<Pass> firrtl::createSpecializeOptionPass() {
99  return std::make_unique<SpecializeOptionPass>();
100 }
Direction get(bool isOutput)
Returns an output direction if isOutput is true, otherwise returns an input direction.
Definition: CalyxOps.cpp:55
std::unique_ptr< mlir::Pass > createSpecializeOptionPass()
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
Definition: DebugAnalysis.h:21