CIRCT  19.0.0git
IbisContainerize.cpp
Go to the documentation of this file.
1 //===- IbisContainerize.cpp - Implementation of containerizing ------------===//
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 #include "PassDetails.h"
10 
15 
17 #include "circt/Support/SymCache.h"
18 #include "mlir/Transforms/DialectConversion.h"
19 
20 using namespace circt;
21 using namespace ibis;
22 
23 namespace {
24 
25 struct OutlineContainerPattern : public OpConversionPattern<ContainerOp> {
26  OutlineContainerPattern(MLIRContext *context, Namespace &ns)
27  : OpConversionPattern<ContainerOp>(context), ns(ns) {}
28 
29  using OpAdaptor = typename OpConversionPattern<ContainerOp>::OpAdaptor;
30 
31  LogicalResult
32  matchAndRewrite(ContainerOp op, OpAdaptor adaptor,
33  ConversionPatternRewriter &rewriter) const override {
34  // Outline the container into the module scope, by prefixing it with the
35  // parent class name.
36  auto parentClass =
37  dyn_cast_or_null<ClassOp>(op.getOperation()->getParentOp());
38  assert(parentClass && "This pattern should never be called on a container"
39  "that is not nested within a class.");
40  auto design = parentClass.getParentOp<DesignOp>();
41  assert(design && "Parent class should be nested within a design.");
42 
43  rewriter.setInsertionPoint(parentClass);
44  StringAttr newContainerName = rewriter.getStringAttr(
45  ns.newName(parentClass.getInnerNameAttr().strref() + "_" +
46  op.getInnerNameAttr().strref()));
47  auto newContainer = rewriter.create<ContainerOp>(
48  op.getLoc(), newContainerName, /*isTopLevel=*/false);
49 
50  rewriter.mergeBlocks(op.getBodyBlock(), newContainer.getBodyBlock(), {});
51 
52  // Rename the ibis.this operation to refer to the proper op.
53  auto thisOp =
54  cast<ThisOp>(cast<ScopeOpInterface>(*newContainer.getOperation())
55  .getThis()
56  .getDefiningOp());
57  rewriter.setInsertionPoint(thisOp);
58  rewriter.replaceOpWithNewOp<ThisOp>(thisOp, design.getSymNameAttr(),
59  newContainer.getInnerSymAttr());
60 
61  // Create a container instance op in the parent class.
62  rewriter.setInsertionPoint(op);
63  rewriter.create<ContainerInstanceOp>(
64  parentClass.getLoc(), hw::InnerSymAttr::get(newContainerName),
65  newContainer.getInnerRef());
66  rewriter.eraseOp(op);
67  return success();
68  }
69 
70  Namespace &ns;
71 };
72 
73 struct ClassToContainerPattern : public OpConversionPattern<ClassOp> {
75 
76  LogicalResult
77  matchAndRewrite(ClassOp op, OpAdaptor adaptor,
78  ConversionPatternRewriter &rewriter) const override {
79  // Replace the class by a container of the same name.
80  auto newContainer =
81  rewriter.create<ContainerOp>(op.getLoc(), op.getInnerSymAttr(), false);
82  rewriter.mergeBlocks(op.getBodyBlock(), newContainer.getBodyBlock(), {});
83  rewriter.eraseOp(op);
84  return success();
85  }
86 };
87 
88 struct InstanceToContainerInstancePattern
89  : public OpConversionPattern<InstanceOp> {
91 
92  LogicalResult
93  matchAndRewrite(InstanceOp op, OpAdaptor adaptor,
94  ConversionPatternRewriter &rewriter) const override {
95  // Replace the instance by a container instance of the same name.
96  rewriter.replaceOpWithNewOp<ContainerInstanceOp>(op, op.getInnerSym(),
97  op.getTargetNameAttr());
98  return success();
99  }
100 };
101 
102 /// Run all the physical lowerings.
103 struct ContainerizePass : public IbisContainerizeBase<ContainerizePass> {
104  void runOnOperation() override;
105 
106 private:
107  // Outlines containers nested within classes into the module scope.
108  LogicalResult outlineContainers();
109 
110  // Converts classes to containers.
111  LogicalResult containerizeClasses();
112 };
113 } // anonymous namespace
114 
115 LogicalResult ContainerizePass::outlineContainers() {
116  auto *context = &getContext();
117  ConversionTarget target(*context);
118  target.addLegalDialect<IbisDialect>();
119  target.addDynamicallyLegalOp<ContainerOp>(
120  [&](auto *op) { return !isa<ibis::ClassOp>(op->getParentOp()); });
121  RewritePatternSet patterns(context);
122 
123  // Setup a namespace to ensure that the new container names are unique.
124  // Grab existing names from the InnerSymbolTable of the top-level design op.
125  SymbolCache symCache;
127  getOperation(), [&](StringAttr name, const hw::InnerSymTarget &target) {
128  symCache.addDefinition(name, target.getOp());
129  return success();
130  });
131 
132  Namespace ns;
133  symCache.addDefinitions(getOperation());
134  ns.add(symCache);
135  patterns.insert<OutlineContainerPattern>(context, ns);
136  return applyPartialConversion(getOperation(), target, std::move(patterns));
137 }
138 
139 LogicalResult ContainerizePass::containerizeClasses() {
140  auto *context = &getContext();
141  ConversionTarget target(*context);
142  target.addLegalDialect<IbisDialect>();
143  target.addIllegalOp<ClassOp, InstanceOp>();
144  RewritePatternSet patterns(context);
145  patterns.insert<ClassToContainerPattern, InstanceToContainerInstancePattern>(
146  context);
147  return applyPartialConversion(getOperation(), target, std::move(patterns));
148 }
149 
150 void ContainerizePass::runOnOperation() {
151  if (failed(outlineContainers()) || failed(containerizeClasses()))
152  signalPassFailure();
153 }
154 
155 std::unique_ptr<Pass> circt::ibis::createContainerizePass() {
156  return std::make_unique<ContainerizePass>();
157 }
assert(baseType &&"element must be base type")
A namespace that is used to store existing names and generate new names in some scope within the IR.
Definition: Namespace.h:29
void add(SymbolCache &symCache)
SymbolCache initializer; initialize from every key that is convertible to a StringAttr in the SymbolC...
Definition: Namespace.h:47
void addDefinitions(mlir::Operation *top)
Populate the symbol cache with all symbol-defining operations within the 'top' operation.
Definition: SymCache.cpp:23
Default symbol cache implementation; stores associations between names (StringAttr's) to mlir::Operat...
Definition: SymCache.h:85
void addDefinition(mlir::Attribute key, mlir::Operation *op) override
In the building phase, add symbols.
Definition: SymCache.h:88
static RetTy walkSymbols(Operation *op, FuncTy &&callback)
Walk the given IST operation and invoke the callback for all encountered inner symbols.
Direction get(bool isOutput)
Returns an output direction if isOutput is true, otherwise returns an input direction.
Definition: CalyxOps.cpp:54
std::unique_ptr< mlir::Pass > createContainerizePass()
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
Definition: DebugAnalysis.h:21