CIRCT 20.0.0git
Loading...
Searching...
No Matches
KanagawaContainerize.cpp
Go to the documentation of this file.
1//===- KanagawaContainerize.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
11#include "mlir/Pass/Pass.h"
12
17
20#include "mlir/Transforms/DialectConversion.h"
21
22namespace circt {
23namespace kanagawa {
24#define GEN_PASS_DEF_KANAGAWACONTAINERIZE
25#include "circt/Dialect/Kanagawa/KanagawaPasses.h.inc"
26} // namespace kanagawa
27} // namespace circt
28
29using namespace circt;
30using namespace kanagawa;
31
32namespace {
33
34struct OutlineContainerPattern : public OpConversionPattern<ContainerOp> {
35 OutlineContainerPattern(MLIRContext *context, Namespace &ns)
36 : OpConversionPattern<ContainerOp>(context), ns(ns) {}
37
38 using OpAdaptor = typename OpConversionPattern<ContainerOp>::OpAdaptor;
39
40 LogicalResult
41 matchAndRewrite(ContainerOp op, OpAdaptor adaptor,
42 ConversionPatternRewriter &rewriter) const override {
43 // Outline the container into the module scope, by prefixing it with the
44 // parent class name.
45 auto parentClass =
46 dyn_cast_or_null<ClassOp>(op.getOperation()->getParentOp());
47 assert(parentClass && "This pattern should never be called on a container"
48 "that is not nested within a class.");
49 auto design = parentClass.getParentOp<DesignOp>();
50 assert(design && "Parent class should be nested within a design.");
51
52 rewriter.setInsertionPoint(parentClass);
53 StringAttr newContainerName = rewriter.getStringAttr(
54 ns.newName(parentClass.getInnerNameAttr().strref() + "_" +
55 op.getInnerNameAttr().strref()));
56 auto newContainer = rewriter.create<ContainerOp>(
57 op.getLoc(), newContainerName, /*isTopLevel=*/false);
58
59 rewriter.mergeBlocks(op.getBodyBlock(), newContainer.getBodyBlock(), {});
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
73struct 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(),
82 /*topLevel*/ false, op.getNameAttr());
83 rewriter.mergeBlocks(op.getBodyBlock(), newContainer.getBodyBlock(), {});
84 rewriter.eraseOp(op);
85 return success();
86 }
87};
88
89struct InstanceToContainerInstancePattern
90 : public OpConversionPattern<InstanceOp> {
92
93 LogicalResult
94 matchAndRewrite(InstanceOp op, OpAdaptor adaptor,
95 ConversionPatternRewriter &rewriter) const override {
96 // Replace the instance by a container instance of the same name.
97 rewriter.replaceOpWithNewOp<ContainerInstanceOp>(op, op.getInnerSym(),
98 op.getTargetNameAttr());
99 return success();
100 }
101};
102
103/// Run all the physical lowerings.
104struct ContainerizePass
105 : public circt::kanagawa::impl::KanagawaContainerizeBase<ContainerizePass> {
106 void runOnOperation() override;
107
108private:
109 // Outlines containers nested within classes into the module scope.
110 LogicalResult outlineContainers();
111
112 // Converts classes to containers.
113 LogicalResult containerizeClasses();
114};
115} // anonymous namespace
116
117LogicalResult ContainerizePass::outlineContainers() {
118 auto *context = &getContext();
119 ConversionTarget target(*context);
120 target.addLegalDialect<KanagawaDialect>();
121 target.addDynamicallyLegalOp<ContainerOp>(
122 [&](auto *op) { return !isa<kanagawa::ClassOp>(op->getParentOp()); });
123 RewritePatternSet patterns(context);
124
125 // Setup a namespace to ensure that the new container names are unique.
126 // Grab existing names from the InnerSymbolTable of the top-level design op.
127 SymbolCache symCache;
129 getOperation(), [&](StringAttr name, const hw::InnerSymTarget &target) {
130 symCache.addDefinition(name, target.getOp());
131 return success();
132 });
133
134 Namespace ns;
135 symCache.addDefinitions(getOperation());
136 ns.add(symCache);
137 patterns.insert<OutlineContainerPattern>(context, ns);
138 return applyPartialConversion(getOperation(), target, std::move(patterns));
139}
140
141LogicalResult ContainerizePass::containerizeClasses() {
142 auto *context = &getContext();
143 ConversionTarget target(*context);
144 target.addLegalDialect<KanagawaDialect>();
145 target.addIllegalOp<ClassOp, InstanceOp>();
146 RewritePatternSet patterns(context);
147 patterns.insert<ClassToContainerPattern, InstanceToContainerInstancePattern>(
148 context);
149 return applyPartialConversion(getOperation(), target, std::move(patterns));
150}
151
152void ContainerizePass::runOnOperation() {
153 if (failed(outlineContainers()) || failed(containerizeClasses()))
154 signalPassFailure();
155}
156
158 return std::make_unique<ContainerizePass>();
159}
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: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 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
The target of an inner symbol, the entity the symbol is a handle for.
static RetTy walkSymbols(Operation *op, FuncTy &&callback)
Walk the given IST operation and invoke the callback for all encountered inner symbols.
std::unique_ptr< mlir::Pass > createContainerizePass()
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.