[ESI] Fix wrap op canonicalizers (#8730)

Fixes the canonicalizers for wrap operations in the ESI dialect by replacing problematic attribute-based folding with proper operation creation and improving pattern matching logic.

- Updates `WrapValidReadyOp` and `WrapFIFOOp` fold methods to create `NullSourceOp` operations instead of using attributes
- Improves the `WrapFIFOOp` canonicalize method with better error handling and more robust user checking
- Delegates constant materialization to the HW dialect for better consistency
This commit is contained in:
John Demme 2025-07-17 15:50:53 -07:00 committed by GitHub
parent 0b3976c12e
commit 3e42dbce12
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 40 additions and 18 deletions

View File

@ -41,14 +41,11 @@ void ESIDialect::initialize() {
Operation *ESIDialect::materializeConstant(OpBuilder &builder, Attribute value, Operation *ESIDialect::materializeConstant(OpBuilder &builder, Attribute value,
Type type, Location loc) { Type type, Location loc) {
// Integer constants.
if (auto intType = dyn_cast<IntegerType>(type))
if (auto attrValue = dyn_cast<IntegerAttr>(value))
return builder.create<hw::ConstantOp>(loc, attrValue.getType(),
attrValue);
if (isa<mlir::UnitAttr>(value)) if (isa<mlir::UnitAttr>(value))
return builder.create<hw::ConstantOp>(loc, builder.getI1Type(), 1); return builder.create<hw::ConstantOp>(loc, builder.getI1Type(), 1);
return nullptr; return builder.getContext()
->getOrLoadDialect<hw::HWDialect>()
->materializeConstant(builder, value, type, loc);
} }
// Provide implementations for the enums we use. // Provide implementations for the enums we use.

View File

@ -19,8 +19,10 @@ LogicalResult WrapValidReadyOp::fold(FoldAdaptor,
SmallVectorImpl<OpFoldResult> &results) { SmallVectorImpl<OpFoldResult> &results) {
if (!getChanOutput().getUsers().empty()) if (!getChanOutput().getUsers().empty())
return failure(); return failure();
results.push_back(NullChannelAttr::get( OpBuilder builder(getContext());
getContext(), TypeAttr::get(getChanOutput().getType()))); results.push_back(
builder.create<NullSourceOp>(getLoc(), getChanOutput().getType())
.getOut());
results.push_back(IntegerAttr::get(IntegerType::get(getContext(), 1), 1)); results.push_back(IntegerAttr::get(IntegerType::get(getContext(), 1), 1));
return success(); return success();
} }
@ -44,22 +46,30 @@ LogicalResult UnwrapFIFOOp::canonicalize(UnwrapFIFOOp op,
LogicalResult WrapFIFOOp::fold(FoldAdaptor, LogicalResult WrapFIFOOp::fold(FoldAdaptor,
SmallVectorImpl<OpFoldResult> &results) { SmallVectorImpl<OpFoldResult> &results) {
if (getChanOutput().getUsers().empty()) { if (!getChanOutput().getUsers().empty())
results.push_back({}); return failure();
results.push_back(IntegerAttr::get(
IntegerType::get(getContext(), 1, IntegerType::Signless), 0)); OpBuilder builder(getContext());
return success(); results.push_back(
} builder.create<NullSourceOp>(getLoc(), getChanOutput().getType())
return failure(); .getOut());
results.push_back(IntegerAttr::get(
IntegerType::get(getContext(), 1, IntegerType::Signless), 0));
return success();
} }
LogicalResult WrapFIFOOp::canonicalize(WrapFIFOOp op, LogicalResult WrapFIFOOp::canonicalize(WrapFIFOOp op,
PatternRewriter &rewriter) { PatternRewriter &rewriter) {
auto unwrap =
dyn_cast_or_null<UnwrapFIFOOp>(*op.getChanOutput().getUsers().begin()); if (!op.getChanOutput().hasOneUse())
return rewriter.notifyMatchFailure(
op, "channel output doesn't have exactly one use");
auto unwrap = dyn_cast_or_null<UnwrapFIFOOp>(
op.getChanOutput().getUses().begin()->getOwner());
if (succeeded(UnwrapFIFOOp::mergeAndErase(unwrap, op, rewriter))) if (succeeded(UnwrapFIFOOp::mergeAndErase(unwrap, op, rewriter)))
return success(); return success();
return failure(); return rewriter.notifyMatchFailure(
op, "could not find corresponding unwrap for wrap");
} }
OpFoldResult WrapWindow::fold(FoldAdaptor) { OpFoldResult WrapWindow::fold(FoldAdaptor) {

View File

@ -0,0 +1,15 @@
// RUN: circt-opt %s --canonicalize | FileCheck %s
// CHECK-LABEL: hw.module @TestDanglingFIFO() {
// CHECK-NEXT: hw.output
hw.module @TestDanglingFIFO() {
%c0 = hw.constant 0 : i1
%chanOutput, %ready = esi.wrap.fifo %c0, %c0 : !esi.channel<i1, FIFO>
}
// CHECK-LABEL: hw.module @TestDanglingValidReady() {
// CHECK-NEXT: hw.output
hw.module @TestDanglingValidReady() {
%c0 = hw.constant 0 : i1
%chanOutput, %ready = esi.wrap.vr %c0, %c0 : i1
}