[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,
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))
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.

View File

@ -19,8 +19,10 @@ LogicalResult WrapValidReadyOp::fold(FoldAdaptor,
SmallVectorImpl<OpFoldResult> &results) {
if (!getChanOutput().getUsers().empty())
return failure();
results.push_back(NullChannelAttr::get(
getContext(), TypeAttr::get(getChanOutput().getType())));
OpBuilder builder(getContext());
results.push_back(
builder.create<NullSourceOp>(getLoc(), getChanOutput().getType())
.getOut());
results.push_back(IntegerAttr::get(IntegerType::get(getContext(), 1), 1));
return success();
}
@ -44,22 +46,30 @@ LogicalResult UnwrapFIFOOp::canonicalize(UnwrapFIFOOp op,
LogicalResult WrapFIFOOp::fold(FoldAdaptor,
SmallVectorImpl<OpFoldResult> &results) {
if (getChanOutput().getUsers().empty()) {
results.push_back({});
results.push_back(IntegerAttr::get(
IntegerType::get(getContext(), 1, IntegerType::Signless), 0));
return success();
}
return failure();
if (!getChanOutput().getUsers().empty())
return failure();
OpBuilder builder(getContext());
results.push_back(
builder.create<NullSourceOp>(getLoc(), getChanOutput().getType())
.getOut());
results.push_back(IntegerAttr::get(
IntegerType::get(getContext(), 1, IntegerType::Signless), 0));
return success();
}
LogicalResult WrapFIFOOp::canonicalize(WrapFIFOOp op,
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)))
return success();
return failure();
return rewriter.notifyMatchFailure(
op, "could not find corresponding unwrap for wrap");
}
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
}