CIRCT  20.0.0git
HWLowerInstanceChoices.cpp
Go to the documentation of this file.
1 //===- HWLowerInstanceChoices.cpp - IR Prepass for Emitter ----------------===//
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 implements the "prepare" pass that walks the IR before the emitter
10 // gets involved. This allows us to do some transformations that would be
11 // awkward to implement inline in the emitter.
12 //
13 // NOTE: This file covers the preparation phase of `ExportVerilog` which mainly
14 // legalizes the IR and makes adjustments necessary for emission. This is the
15 // place to mutate the IR if emission needs it. The IR cannot be modified during
16 // emission itself, which happens in parallel.
17 //
18 //===----------------------------------------------------------------------===//
19 
20 #include "ExportVerilogInternals.h"
22 #include "circt/Dialect/HW/HWOps.h"
23 #include "circt/Dialect/SV/SVOps.h"
24 #include "circt/Support/LLVM.h"
26 #include "circt/Support/SymCache.h"
27 #include "mlir/IR/ImplicitLocOpBuilder.h"
28 #include "mlir/IR/SymbolTable.h"
29 #include "mlir/Pass/Pass.h"
30 
31 namespace circt {
32 #define GEN_PASS_DEF_HWLOWERINSTANCECHOICES
33 #include "circt/Conversion/Passes.h.inc"
34 } // namespace circt
35 
36 using namespace mlir;
37 using namespace circt;
38 using namespace hw;
39 using namespace sv;
40 using namespace ExportVerilog;
41 
42 namespace {
43 
44 struct HWLowerInstanceChoicesPass
45  : public circt::impl::HWLowerInstanceChoicesBase<
46  HWLowerInstanceChoicesPass> {
47  void runOnOperation() override;
48 };
49 
50 } // end anonymous namespace
51 
52 LogicalResult ExportVerilog::lowerHWInstanceChoices(mlir::ModuleOp module) {
53  // Collect all instance choices & symbols.
54  SmallVector<InstanceChoiceOp> instances;
55  SymbolCache symCache;
56  for (Operation &op : *module.getBody()) {
57  if (auto sym = dyn_cast<SymbolOpInterface>(&op))
58  symCache.addSymbol(sym);
59 
60  if (auto module = dyn_cast<HWModuleOp>(&op))
61  module.walk([&](InstanceChoiceOp inst) { instances.push_back(inst); });
62  }
63 
64  // Build a namespace to generate unique macro names.
65  Namespace ns;
66  ns.add(symCache);
67 
68  auto declBuilder = OpBuilder::atBlockBegin(module.getBody());
69  for (InstanceChoiceOp inst : instances) {
70  auto parent = inst->getParentOfType<HWModuleOp>();
71 
72  auto defaultModuleOp = cast<HWModuleLike>(
73  symCache.getDefinition(inst.getDefaultModuleNameAttr()));
74 
75  // Generate a macro name to describe the target of this instance.
76  SmallString<128> name;
77  {
78  llvm::raw_svector_ostream os(name);
79  os << "__circt_choice_" << parent.getName() << "_"
80  << inst.getInstanceName();
81  }
82 
83  auto symName = ns.newName(name);
84  auto symNameAttr = declBuilder.getStringAttr(symName);
85  auto symRef = FlatSymbolRefAttr::get(symNameAttr);
86  declBuilder.create<MacroDeclOp>(inst.getLoc(), symNameAttr,
87  /*args=*/ArrayAttr{},
88  /*verilogName=*/StringAttr{});
89 
90  // This pass now generates the macros and attaches them to the instance
91  // choice as an attribute. As a better solution, this pass should be moved
92  // out of the umbrella of ExportVerilog and it should lower the `hw`
93  // instance choices to a better SV-level representation of the operation.
94  ImplicitLocOpBuilder builder(inst.getLoc(), inst);
95  builder.create<sv::IfDefOp>(
96  symName, [&] {},
97  [&] {
98  builder.create<sv::MacroDefOp>(
99  symRef, builder.getStringAttr("{{0}}"),
100  builder.getArrayAttr(
101  {FlatSymbolRefAttr::get(defaultModuleOp.getNameAttr())}));
102  });
103  inst->setAttr("hw.choiceTarget", symRef);
104  }
105 
106  return success();
107 }
108 
109 void HWLowerInstanceChoicesPass::runOnOperation() {
110  ModuleOp module = getOperation();
111  if (failed(lowerHWInstanceChoices(module)))
112  signalPassFailure();
113 }
114 
115 std::unique_ptr<mlir::Pass> circt::createHWLowerInstanceChoicesPass() {
116  return std::make_unique<HWLowerInstanceChoicesPass>();
117 }
A namespace that is used to store existing names and generate new names in some scope within the IR.
Definition: Namespace.h:30
void add(mlir::ModuleOp module)
Definition: Namespace.h:48
StringRef newName(const Twine &name)
Return a unique name, derived from the input name, and add the new name to the internal namespace.
Definition: Namespace.h:85
void addSymbol(mlir::SymbolOpInterface op)
Adds the symbol-defining 'op' to the cache.
Definition: SymCache.h:33
Default symbol cache implementation; stores associations between names (StringAttr's) to mlir::Operat...
Definition: SymCache.h:85
mlir::Operation * getDefinition(mlir::Attribute attr) const override
Lookup a definition for 'symbol' in the cache.
Definition: SymCache.h:94
Definition: sv.py:15
LogicalResult lowerHWInstanceChoices(mlir::ModuleOp module)
Generates the macros used by instance choices.
Direction get(bool isOutput)
Returns an output direction if isOutput is true, otherwise returns an input direction.
Definition: CalyxOps.cpp:55
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
Definition: DebugAnalysis.h:21
std::unique_ptr< mlir::Pass > createHWLowerInstanceChoicesPass()
Definition: hw.py:1
Definition: sv.py:1