Skip to content

Commit a2af164

Browse files
committed
[FIRRTL] LowerLayers: Inline enabled layers
1 parent bdc3b8d commit a2af164

6 files changed

Lines changed: 228 additions & 110 deletions

File tree

include/circt/Dialect/FIRRTL/LayerSet.h

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,43 @@ struct LayerSetCompare {
4242

4343
using LayerSet = SmallSet<SymbolRefAttr, 4, LayerSetCompare>;
4444

45+
//===----------------------------------------------------------------------===//
46+
// Layer Verification Utilities
47+
//===----------------------------------------------------------------------===//
48+
49+
/// Get the ambient layers active at the given op.
50+
LayerSet getAmbientLayersAt(Operation *op);
51+
52+
/// Get the ambient layer requirements at the definition site of the value.
53+
LayerSet getAmbientLayersFor(Value value);
54+
55+
/// Get the effective layer requirements for the given value.
56+
/// The effective layers for a value is the union of
57+
/// - the ambient layers for the cannonical storage location.
58+
/// - any explicit layer annotations in the value's type.
59+
LayerSet getLayersFor(Value value);
60+
61+
/// Check that the source layer is compatible with the destination layer.
62+
/// Either the source and destination are identical, or the source-layer
63+
/// is a parent of the destination. For example `A` is compatible with `A.B.C`,
64+
/// because any definition valid in `A` is also valid in `A.B.C`.
65+
bool isLayerCompatibleWith(mlir::SymbolRefAttr srcLayer,
66+
mlir::SymbolRefAttr dstLayer);
67+
68+
/// Check that the source layer is present in the destination layers.
69+
bool isLayerCompatibleWith(SymbolRefAttr srcLayer, const LayerSet &dstLayers);
70+
71+
/// Check that the source layers are all present in the destination layers.
72+
/// True if all source layers are present in the destination.
73+
/// Outputs the set of source layers that are missing in the destination.
74+
bool isLayerSetCompatibleWith(const LayerSet &src, const LayerSet &dst,
75+
SmallVectorImpl<SymbolRefAttr> &missing);
76+
77+
LogicalResult checkLayerCompatibility(
78+
Operation *op, const LayerSet &src, const LayerSet &dst,
79+
const Twine &errorMsg,
80+
const Twine &noteMsg = Twine("missing layer requirements"));
81+
4582
} // namespace firrtl
4683
} // namespace circt
4784

lib/Dialect/FIRRTL/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ set(CIRCT_FIRRTL_Sources
1919
FIRRTLOps.cpp
2020
FIRRTLTypes.cpp
2121
FIRRTLUtils.cpp
22+
LayerSet.cpp
2223
NLATable.cpp
2324
)
2425

lib/Dialect/FIRRTL/FIRRTLOps.cpp

Lines changed: 0 additions & 106 deletions
Original file line numberDiff line numberDiff line change
@@ -313,112 +313,6 @@ void getAsmBlockArgumentNamesImpl(Operation *op, mlir::Region &region,
313313
static ParseResult parseNameKind(OpAsmParser &parser,
314314
firrtl::NameKindEnumAttr &result);
315315

316-
//===----------------------------------------------------------------------===//
317-
// Layer Verification Utilities
318-
//===----------------------------------------------------------------------===//
319-
320-
/// Get the ambient layers active at the given op.
321-
static LayerSet getAmbientLayersAt(Operation *op) {
322-
// Crawl through the parent ops, accumulating all ambient layers at the given
323-
// operation.
324-
LayerSet result;
325-
for (; op != nullptr; op = op->getParentOp()) {
326-
if (auto module = dyn_cast<FModuleLike>(op)) {
327-
auto layers = module.getLayersAttr().getAsRange<SymbolRefAttr>();
328-
result.insert(layers.begin(), layers.end());
329-
break;
330-
}
331-
if (auto layerblock = dyn_cast<LayerBlockOp>(op)) {
332-
result.insert(layerblock.getLayerName());
333-
continue;
334-
}
335-
}
336-
return result;
337-
}
338-
339-
/// Get the ambient layer requirements at the definition site of the value.
340-
static LayerSet getAmbientLayersFor(Value value) {
341-
return getAmbientLayersAt(getFieldRefFromValue(value).getDefiningOp());
342-
}
343-
344-
/// Get the effective layer requirements for the given value.
345-
/// The effective layers for a value is the union of
346-
/// - the ambient layers for the cannonical storage location.
347-
/// - any explicit layer annotations in the value's type.
348-
static LayerSet getLayersFor(Value value) {
349-
auto result = getAmbientLayersFor(value);
350-
if (auto type = dyn_cast<RefType>(value.getType()))
351-
if (auto layer = type.getLayer())
352-
result.insert(type.getLayer());
353-
return result;
354-
}
355-
356-
/// Check that the source layer is compatible with the destination layer.
357-
/// Either the source and destination are identical, or the source-layer
358-
/// is a parent of the destination. For example `A` is compatible with `A.B.C`,
359-
/// because any definition valid in `A` is also valid in `A.B.C`.
360-
static bool isLayerCompatibleWith(mlir::SymbolRefAttr srcLayer,
361-
mlir::SymbolRefAttr dstLayer) {
362-
// A non-colored probe may be cast to any colored probe.
363-
if (!srcLayer)
364-
return true;
365-
366-
// A colored probe cannot be cast to an uncolored probe.
367-
if (!dstLayer)
368-
return false;
369-
370-
// Return true if the srcLayer is a prefix of the dstLayer.
371-
if (srcLayer.getRootReference() != dstLayer.getRootReference())
372-
return false;
373-
374-
auto srcNames = srcLayer.getNestedReferences();
375-
auto dstNames = dstLayer.getNestedReferences();
376-
if (dstNames.size() < srcNames.size())
377-
return false;
378-
379-
return llvm::all_of(llvm::zip_first(srcNames, dstNames),
380-
[](auto x) { return std::get<0>(x) == std::get<1>(x); });
381-
}
382-
383-
/// Check that the source layer is present in the destination layers.
384-
static bool isLayerCompatibleWith(SymbolRefAttr srcLayer,
385-
const LayerSet &dstLayers) {
386-
// fast path: the required layer is directly listed in the provided layers.
387-
if (dstLayers.contains(srcLayer))
388-
return true;
389-
390-
// Slow path: the required layer is not directly listed in the provided
391-
// layers, but the layer may still be provided by a nested layer.
392-
return any_of(dstLayers, [=](SymbolRefAttr dstLayer) {
393-
return isLayerCompatibleWith(srcLayer, dstLayer);
394-
});
395-
}
396-
397-
/// Check that the source layers are all present in the destination layers.
398-
/// True if all source layers are present in the destination.
399-
/// Outputs the set of source layers that are missing in the destination.
400-
static bool isLayerSetCompatibleWith(const LayerSet &src, const LayerSet &dst,
401-
SmallVectorImpl<SymbolRefAttr> &missing) {
402-
for (auto srcLayer : src)
403-
if (!isLayerCompatibleWith(srcLayer, dst))
404-
missing.push_back(srcLayer);
405-
406-
llvm::sort(missing, LayerSetCompare());
407-
return missing.empty();
408-
}
409-
410-
static LogicalResult checkLayerCompatibility(
411-
Operation *op, const LayerSet &src, const LayerSet &dst,
412-
const Twine &errorMsg,
413-
const Twine &noteMsg = Twine("missing layer requirements")) {
414-
SmallVector<SymbolRefAttr> missing;
415-
if (isLayerSetCompatibleWith(src, dst, missing))
416-
return success();
417-
interleaveComma(missing, op->emitOpError(errorMsg).attachNote()
418-
<< noteMsg << ": ");
419-
return failure();
420-
}
421-
422316
//===----------------------------------------------------------------------===//
423317
// CircuitOp
424318
//===----------------------------------------------------------------------===//

lib/Dialect/FIRRTL/LayerSet.cpp

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
#include "circt/Dialect/FIRRTL/LayerSet.h"
2+
#include "circt/Dialect/FIRRTL/FIRRTLOps.h"
3+
#include "circt/Dialect/FIRRTL/FIRRTLUtils.h"
4+
#include "llvm/ADT/SmallSet.h"
5+
6+
using namespace mlir;
7+
using namespace circt;
8+
using namespace firrtl;
9+
10+
LayerSet circt::firrtl::getAmbientLayersAt(Operation *op) {
11+
// Crawl through the parent ops, accumulating all ambient layers at the given
12+
// operation.
13+
LayerSet result;
14+
for (; op != nullptr; op = op->getParentOp()) {
15+
if (auto module = dyn_cast<FModuleLike>(op)) {
16+
auto layers = module.getLayersAttr().getAsRange<SymbolRefAttr>();
17+
result.insert(layers.begin(), layers.end());
18+
break;
19+
}
20+
if (auto layerblock = dyn_cast<LayerBlockOp>(op)) {
21+
result.insert(layerblock.getLayerName());
22+
continue;
23+
}
24+
}
25+
return result;
26+
}
27+
28+
LayerSet circt::firrtl::getAmbientLayersFor(Value value) {
29+
return getAmbientLayersAt(getFieldRefFromValue(value).getDefiningOp());
30+
}
31+
32+
LayerSet circt::firrtl::getLayersFor(Value value) {
33+
auto result = getAmbientLayersFor(value);
34+
if (auto type = dyn_cast<RefType>(value.getType()))
35+
if (auto layer = type.getLayer())
36+
result.insert(type.getLayer());
37+
return result;
38+
}
39+
40+
bool circt::firrtl::isLayerCompatibleWith(mlir::SymbolRefAttr srcLayer,
41+
mlir::SymbolRefAttr dstLayer) {
42+
// A non-colored probe may be cast to any colored probe.
43+
if (!srcLayer)
44+
return true;
45+
46+
// A colored probe cannot be cast to an uncolored probe.
47+
if (!dstLayer)
48+
return false;
49+
50+
// Return true if the srcLayer is a prefix of the dstLayer.
51+
if (srcLayer.getRootReference() != dstLayer.getRootReference())
52+
return false;
53+
54+
auto srcNames = srcLayer.getNestedReferences();
55+
auto dstNames = dstLayer.getNestedReferences();
56+
if (dstNames.size() < srcNames.size())
57+
return false;
58+
59+
return llvm::all_of(llvm::zip_first(srcNames, dstNames),
60+
[](auto x) { return std::get<0>(x) == std::get<1>(x); });
61+
}
62+
63+
bool circt::firrtl::isLayerCompatibleWith(SymbolRefAttr srcLayer,
64+
const LayerSet &dstLayers) {
65+
// fast path: the required layer is directly listed in the provided layers.
66+
if (dstLayers.contains(srcLayer))
67+
return true;
68+
69+
// Slow path: the required layer is not directly listed in the provided
70+
// layers, but the layer may still be provided by a nested layer.
71+
return any_of(dstLayers, [=](SymbolRefAttr dstLayer) {
72+
return isLayerCompatibleWith(srcLayer, dstLayer);
73+
});
74+
}
75+
76+
bool circt::firrtl::isLayerSetCompatibleWith(
77+
const LayerSet &src, const LayerSet &dst,
78+
SmallVectorImpl<SymbolRefAttr> &missing) {
79+
for (auto srcLayer : src)
80+
if (!isLayerCompatibleWith(srcLayer, dst))
81+
missing.push_back(srcLayer);
82+
83+
llvm::sort(missing, LayerSetCompare());
84+
return missing.empty();
85+
}
86+
87+
LogicalResult circt::firrtl::checkLayerCompatibility(Operation *op,
88+
const LayerSet &src,
89+
const LayerSet &dst,
90+
const Twine &errorMsg,
91+
const Twine &noteMsg) {
92+
SmallVector<SymbolRefAttr> missing;
93+
if (isLayerSetCompatibleWith(src, dst, missing))
94+
return success();
95+
interleaveComma(missing, op->emitOpError(errorMsg).attachNote()
96+
<< noteMsg << ": ");
97+
return failure();
98+
}

lib/Dialect/FIRRTL/Transforms/LowerLayers.cpp

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include "circt/Dialect/FIRRTL/FIRRTLInstanceGraph.h"
1414
#include "circt/Dialect/FIRRTL/FIRRTLOps.h"
1515
#include "circt/Dialect/FIRRTL/FIRRTLUtils.h"
16+
#include "circt/Dialect/FIRRTL/LayerSet.h"
1617
#include "circt/Dialect/FIRRTL/Namespace.h"
1718
#include "circt/Dialect/FIRRTL/Passes.h"
1819
#include "circt/Dialect/HW/HierPathCache.h"
@@ -22,6 +23,7 @@
2223
#include "mlir/Pass/Pass.h"
2324
#include "llvm/ADT/PostOrderIterator.h"
2425
#include "llvm/ADT/SmallPtrSet.h"
26+
#include "llvm/ADT/SmallSet.h"
2527
#include "llvm/Support/Debug.h"
2628
#include "llvm/Support/Mutex.h"
2729

@@ -231,7 +233,8 @@ class LowerLayersPass
231233
FailureOr<InnerRefMap> runOnModuleLike(FModuleLike moduleLike);
232234

233235
/// Extract layerblocks and strip probe colors from all ops under the module.
234-
LogicalResult runOnModuleBody(FModuleOp moduleOp, InnerRefMap &innerRefMap);
236+
LogicalResult runOnModuleBody(FModuleOp moduleOp, InnerRefMap &innerRefMap,
237+
const LayerSet &enabledLayers);
235238

236239
/// Update the module's port types to remove any explicit layer requirements
237240
/// from any probe types.
@@ -243,6 +246,9 @@ class LowerLayersPass
243246
/// Lower an inline layerblock to an ifdef block.
244247
void lowerInlineLayerBlock(LayerOp layer, LayerBlockOp layerBlock);
245248

249+
/// Inline an enabled layerblock directly into its parent.
250+
void inlineLayerBlock(LayerBlockOp layerBlock);
251+
246252
/// Build macro declarations and cache information about the layers.
247253
void preprocessLayers(CircuitNamespace &ns, OpBuilder &b, LayerOp layer,
248254
StringRef circuitName,
@@ -364,9 +370,12 @@ LowerLayersPass::runOnModuleLike(FModuleLike moduleLike) {
364370
auto result =
365371
TypeSwitch<Operation *, LogicalResult>(moduleLike.getOperation())
366372
.Case<FModuleOp>([&](auto op) {
373+
LayerSet enabledLayers;
374+
enabledLayers.insert_range(
375+
op.getLayersAttr().template getAsRange<SymbolRefAttr>());
367376
op.setLayers({});
368377
removeLayersFromPorts(op);
369-
return runOnModuleBody(op, innerRefMap);
378+
return runOnModuleBody(op, innerRefMap, enabledLayers);
370379
})
371380
.Case<FExtModuleOp>([&](auto op) {
372381
op.setKnownLayers({});
@@ -400,8 +409,15 @@ void LowerLayersPass::lowerInlineLayerBlock(LayerOp layer,
400409
layerBlock.erase();
401410
}
402411

412+
void LowerLayersPass::inlineLayerBlock(LayerBlockOp layerBlock) {
413+
layerBlock->getBlock()->getOperations().splice(
414+
Block::iterator(layerBlock), layerBlock.getBody()->getOperations());
415+
layerBlock.erase();
416+
}
417+
403418
LogicalResult LowerLayersPass::runOnModuleBody(FModuleOp moduleOp,
404-
InnerRefMap &innerRefMap) {
419+
InnerRefMap &innerRefMap,
420+
const LayerSet &enabledLayers) {
405421
hw::InnerSymbolNamespace ns(moduleOp);
406422

407423
// Get or create a node op for a value captured by a layer block.
@@ -694,6 +710,11 @@ LogicalResult LowerLayersPass::runOnModuleBody(FModuleOp moduleOp,
694710
// After this point, we are dealing with a layer block.
695711
auto layer = symbolToLayer.lookup(layerBlock.getLayerName());
696712

713+
if (isLayerCompatibleWith(layerBlock.getLayerName(), enabledLayers)) {
714+
inlineLayerBlock(layerBlock);
715+
return WalkResult::advance();
716+
}
717+
697718
if (layer.getConvention() == LayerConvention::Inline) {
698719
lowerInlineLayerBlock(layer, layerBlock);
699720
return WalkResult::advance();

0 commit comments

Comments
 (0)