From d01d8f340c9e0f53e2f9839039880ab72f687d34 Mon Sep 17 00:00:00 2001 From: woshiren Date: Sat, 16 May 2026 17:54:51 +0800 Subject: [PATCH 01/10] [SimToSV] Lower sim.triggered to sv.always --- lib/Conversion/SimToSV/SimToSV.cpp | 28 ++++++++++++ test/Conversion/SimToSV/triggered.mlir | 63 ++++++++++++++++++++++++++ 2 files changed, 91 insertions(+) create mode 100644 test/Conversion/SimToSV/triggered.mlir diff --git a/lib/Conversion/SimToSV/SimToSV.cpp b/lib/Conversion/SimToSV/SimToSV.cpp index 838e5b12af10..68eac4d78b1c 100644 --- a/lib/Conversion/SimToSV/SimToSV.cpp +++ b/lib/Conversion/SimToSV/SimToSV.cpp @@ -267,6 +267,33 @@ static LogicalResult convert(PauseOp op, PatternRewriter &rewriter) { return success(); } +class TriggeredLowering : public OpConversionPattern { +public: + using OpConversionPattern::OpConversionPattern; + + LogicalResult + matchAndRewrite(TriggeredOp op, OpAdaptor adaptor, + ConversionPatternRewriter &rewriter) const final { + auto loc = op.getLoc(); + auto trigger = seq::FromClockOp::create(rewriter, loc, adaptor.getClock()); + auto alwaysOp = sv::AlwaysOp::create( + rewriter, loc, + ArrayRef{sv::EventControl::AtPosEdge}, + ArrayRef{trigger}); + + Block *destination = alwaysOp.getBodyBlock(); + if (auto condition = adaptor.getCondition()) { + rewriter.setInsertionPointToStart(destination); + destination = + sv::IfOp::create(rewriter, loc, condition, [] {}).getThenBlock(); + } + + rewriter.mergeBlocks(op.getBodyBlock(), destination); + rewriter.eraseOp(op); + return success(); + } +}; + class DPICallLowering : public SimConversionPattern { public: using SimConversionPattern::SimConversionPattern; @@ -843,6 +870,7 @@ struct SimToSVPass : public circt::impl::LowerSimToSVBase { patterns.add(convert); patterns.add(convert); patterns.add(convert); + patterns.add(typeConverter, context); patterns.add(context, state); auto result = applyPartialConversion(module, target, std::move(patterns)); diff --git a/test/Conversion/SimToSV/triggered.mlir b/test/Conversion/SimToSV/triggered.mlir new file mode 100644 index 000000000000..f6a7d9d07088 --- /dev/null +++ b/test/Conversion/SimToSV/triggered.mlir @@ -0,0 +1,63 @@ +// RUN: circt-opt --lower-sim-to-sv %s | FileCheck %s + +// CHECK-LABEL: hw.module @simple_triggered +hw.module @simple_triggered(in %clock : !seq.clock) { + %msg = sim.fmt.literal "tick" + sim.triggered %clock { + sim.proc.print %msg + } + + // CHECK: %[[CLOCK:.*]] = seq.from_clock %clock + // CHECK-NEXT: sv.always posedge %[[CLOCK]] { + // CHECK-NEXT: sv.write "tick" + // CHECK-NEXT: } +} + +// CHECK-LABEL: hw.module @conditional_triggered +hw.module @conditional_triggered( + in %clock : !seq.clock, in %en : i1, in %val : i8) { + %prefix = sim.fmt.literal "value=" + %value = sim.fmt.hex %val, isUpper false specifierWidth 2 : i8 + %msg = sim.fmt.concat (%prefix, %value) + sim.triggered %clock if %en { + sim.proc.print %msg + } + + // CHECK: %[[CLOCK:.*]] = seq.from_clock %clock + // CHECK-NEXT: sv.always posedge %[[CLOCK]] { + // CHECK-NEXT: sv.if %en { + // CHECK-NEXT: sv.write "value=%02x"(%val) : i8 + // CHECK-NEXT: } + // CHECK-NEXT: } +} + +// CHECK-LABEL: hw.module @multiple_triggered +hw.module @multiple_triggered( + in %clock : !seq.clock, in %en : i1, in %lhs : i8, in %rhs : i8) { + %lhsPrefix = sim.fmt.literal "lhs=" + %lhsValue = sim.fmt.hex %lhs, isUpper false specifierWidth 2 : i8 + %lhsMsg = sim.fmt.concat (%lhsPrefix, %lhsValue) + + %rhsPrefix = sim.fmt.literal "rhs=" + %rhsValue = sim.fmt.hex %rhs, isUpper false specifierWidth 2 : i8 + %rhsMsg = sim.fmt.concat (%rhsPrefix, %rhsValue) + + sim.triggered %clock { + sim.proc.print %lhsMsg + } + + sim.triggered %clock if %en { + sim.proc.print %rhsMsg + } + + // CHECK: %[[CLOCK0:.*]] = seq.from_clock %clock + // CHECK-NEXT: sv.always posedge %[[CLOCK0]] { + // CHECK-NEXT: sv.write "lhs=%02x"(%lhs) : i8 + // CHECK-NEXT: } + // CHECK: %[[CLOCK1:.*]] = seq.from_clock %clock + // CHECK-NEXT: sv.always posedge %[[CLOCK1]] { + // CHECK-NEXT: sv.if %en { + // CHECK-NEXT: sv.write "rhs=%02x"(%rhs) : i8 + // CHECK-NEXT: } + // CHECK-NEXT: } +} From a729db138645572a3767807248e45dcffb0f9368 Mon Sep 17 00:00:00 2001 From: woshiren Date: Sat, 16 May 2026 17:57:15 +0800 Subject: [PATCH 02/10] fix format error --- lib/Conversion/SimToSV/SimToSV.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/Conversion/SimToSV/SimToSV.cpp b/lib/Conversion/SimToSV/SimToSV.cpp index 68eac4d78b1c..4216ac5afb50 100644 --- a/lib/Conversion/SimToSV/SimToSV.cpp +++ b/lib/Conversion/SimToSV/SimToSV.cpp @@ -277,8 +277,7 @@ class TriggeredLowering : public OpConversionPattern { auto loc = op.getLoc(); auto trigger = seq::FromClockOp::create(rewriter, loc, adaptor.getClock()); auto alwaysOp = sv::AlwaysOp::create( - rewriter, loc, - ArrayRef{sv::EventControl::AtPosEdge}, + rewriter, loc, ArrayRef{sv::EventControl::AtPosEdge}, ArrayRef{trigger}); Block *destination = alwaysOp.getBodyBlock(); From aa1c16b6375c8cc8bb7155917dc94fe7cf1571d6 Mon Sep 17 00:00:00 2001 From: woshiren Date: Sat, 16 May 2026 19:06:47 +0800 Subject: [PATCH 03/10] update the test --- test/Conversion/SimToSV/triggered.mlir | 33 +++++++++----------------- 1 file changed, 11 insertions(+), 22 deletions(-) diff --git a/test/Conversion/SimToSV/triggered.mlir b/test/Conversion/SimToSV/triggered.mlir index f6a7d9d07088..92b42d6e0d14 100644 --- a/test/Conversion/SimToSV/triggered.mlir +++ b/test/Conversion/SimToSV/triggered.mlir @@ -1,63 +1,52 @@ -// RUN: circt-opt --lower-sim-to-sv %s | FileCheck %s +// RUN: circt-opt --lower-sim-to-sv --allow-unregistered-dialect %s | FileCheck %s // CHECK-LABEL: hw.module @simple_triggered hw.module @simple_triggered(in %clock : !seq.clock) { - %msg = sim.fmt.literal "tick" sim.triggered %clock { - sim.proc.print %msg + "some.user"() : () -> () } // CHECK: %[[CLOCK:.*]] = seq.from_clock %clock // CHECK-NEXT: sv.always posedge %[[CLOCK]] { - // CHECK-NEXT: sv.write "tick" + // CHECK-NEXT: "some.user"() : () -> () // CHECK-NEXT: } } // CHECK-LABEL: hw.module @conditional_triggered hw.module @conditional_triggered( - in %clock : !seq.clock, in %en : i1, in %val : i8) { - %prefix = sim.fmt.literal "value=" - %value = sim.fmt.hex %val, isUpper false specifierWidth 2 : i8 - %msg = sim.fmt.concat (%prefix, %value) + in %clock : !seq.clock, in %en : i1) { sim.triggered %clock if %en { - sim.proc.print %msg + "some.user"() : () -> () } // CHECK: %[[CLOCK:.*]] = seq.from_clock %clock // CHECK-NEXT: sv.always posedge %[[CLOCK]] { // CHECK-NEXT: sv.if %en { - // CHECK-NEXT: sv.write "value=%02x"(%val) : i8 + // CHECK-NEXT: "some.user"() : () -> () // CHECK-NEXT: } // CHECK-NEXT: } } // CHECK-LABEL: hw.module @multiple_triggered hw.module @multiple_triggered( - in %clock : !seq.clock, in %en : i1, in %lhs : i8, in %rhs : i8) { - %lhsPrefix = sim.fmt.literal "lhs=" - %lhsValue = sim.fmt.hex %lhs, isUpper false specifierWidth 2 : i8 - %lhsMsg = sim.fmt.concat (%lhsPrefix, %lhsValue) - - %rhsPrefix = sim.fmt.literal "rhs=" - %rhsValue = sim.fmt.hex %rhs, isUpper false specifierWidth 2 : i8 - %rhsMsg = sim.fmt.concat (%rhsPrefix, %rhsValue) + in %clock : !seq.clock, in %en : i1) { sim.triggered %clock { - sim.proc.print %lhsMsg + "some.user"() : () -> () } sim.triggered %clock if %en { - sim.proc.print %rhsMsg + "some.user"() : () -> () } // CHECK: %[[CLOCK0:.*]] = seq.from_clock %clock // CHECK-NEXT: sv.always posedge %[[CLOCK0]] { - // CHECK-NEXT: sv.write "lhs=%02x"(%lhs) : i8 + // CHECK-NEXT: "some.user"() : () -> () // CHECK-NEXT: } // CHECK: %[[CLOCK1:.*]] = seq.from_clock %clock // CHECK-NEXT: sv.always posedge %[[CLOCK1]] { // CHECK-NEXT: sv.if %en { - // CHECK-NEXT: sv.write "rhs=%02x"(%rhs) : i8 + // CHECK-NEXT: "some.user"() : () -> () // CHECK-NEXT: } // CHECK-NEXT: } } From 1b60bd61cc40763c2759c0bdd12bdfe55b09174b Mon Sep 17 00:00:00 2001 From: woshiren Date: Sat, 16 May 2026 20:14:22 +0800 Subject: [PATCH 04/10] add SYNTHESIS guard --- lib/Conversion/SimToSV/SimToSV.cpp | 20 ++++++++++-- test/Conversion/SimToSV/triggered.mlir | 44 ++++++++++++++++---------- 2 files changed, 45 insertions(+), 19 deletions(-) diff --git a/lib/Conversion/SimToSV/SimToSV.cpp b/lib/Conversion/SimToSV/SimToSV.cpp index 4216ac5afb50..220400ab6abf 100644 --- a/lib/Conversion/SimToSV/SimToSV.cpp +++ b/lib/Conversion/SimToSV/SimToSV.cpp @@ -65,6 +65,7 @@ struct SimConversionState { bool usedSynthesisMacro = false; bool usedFileDescriptorRuntime = false; SetVector dpiCallees; + llvm::SmallDenseMap synthesisGuards; }; struct SimTypeConverter : public TypeConverter { @@ -267,14 +268,27 @@ static LogicalResult convert(PauseOp op, PatternRewriter &rewriter) { return success(); } -class TriggeredLowering : public OpConversionPattern { +class TriggeredLowering : public SimConversionPattern { public: - using OpConversionPattern::OpConversionPattern; + using SimConversionPattern::SimConversionPattern; LogicalResult matchAndRewrite(TriggeredOp op, OpAdaptor adaptor, ConversionPatternRewriter &rewriter) const final { auto loc = op.getLoc(); + state.usedSynthesisMacro = true; + + auto [it, inserted] = state.synthesisGuards.try_emplace(op->getBlock()); + auto ifdefOp = it->second; + if (!inserted) { + ifdefOp->moveBefore(op); + } else { + ifdefOp = sv::IfDefOp::create( + rewriter, loc, "SYNTHESIS", [] {}, [] {}); + it->second = ifdefOp; + } + rewriter.setInsertionPointToEnd(ifdefOp.getElseBlock()); + auto trigger = seq::FromClockOp::create(rewriter, loc, adaptor.getClock()); auto alwaysOp = sv::AlwaysOp::create( rewriter, loc, ArrayRef{sv::EventControl::AtPosEdge}, @@ -869,7 +883,7 @@ struct SimToSVPass : public circt::impl::LowerSimToSVBase { patterns.add(convert); patterns.add(convert); patterns.add(convert); - patterns.add(typeConverter, context); + patterns.add(context, state); patterns.add(context, state); auto result = applyPartialConversion(module, target, std::move(patterns)); diff --git a/test/Conversion/SimToSV/triggered.mlir b/test/Conversion/SimToSV/triggered.mlir index 92b42d6e0d14..d41c272908e9 100644 --- a/test/Conversion/SimToSV/triggered.mlir +++ b/test/Conversion/SimToSV/triggered.mlir @@ -6,9 +6,12 @@ hw.module @simple_triggered(in %clock : !seq.clock) { "some.user"() : () -> () } - // CHECK: %[[CLOCK:.*]] = seq.from_clock %clock - // CHECK-NEXT: sv.always posedge %[[CLOCK]] { - // CHECK-NEXT: "some.user"() : () -> () + // CHECK: sv.ifdef @SYNTHESIS { + // CHECK-NEXT: } else { + // CHECK-NEXT: %[[CLOCK:.*]] = seq.from_clock %clock + // CHECK-NEXT: sv.always posedge %[[CLOCK]] { + // CHECK-NEXT: "some.user"() : () -> () + // CHECK-NEXT: } // CHECK-NEXT: } } @@ -19,34 +22,43 @@ hw.module @conditional_triggered( "some.user"() : () -> () } - // CHECK: %[[CLOCK:.*]] = seq.from_clock %clock - // CHECK-NEXT: sv.always posedge %[[CLOCK]] { - // CHECK-NEXT: sv.if %en { - // CHECK-NEXT: "some.user"() : () -> () + // CHECK: sv.ifdef @SYNTHESIS { + // CHECK-NEXT: } else { + // CHECK-NEXT: %[[CLOCK:.*]] = seq.from_clock %clock + // CHECK-NEXT: sv.always posedge %[[CLOCK]] { + // CHECK-NEXT: sv.if %en { + // CHECK-NEXT: "some.user"() : () -> () + // CHECK-NEXT: } // CHECK-NEXT: } // CHECK-NEXT: } } // CHECK-LABEL: hw.module @multiple_triggered hw.module @multiple_triggered( - in %clock : !seq.clock, in %en : i1) { + in %clock : !seq.clock) { sim.triggered %clock { "some.user"() : () -> () } - sim.triggered %clock if %en { + %late_cond = "some.value"() : () -> i1 + + sim.triggered %clock if %late_cond { "some.user"() : () -> () } - // CHECK: %[[CLOCK0:.*]] = seq.from_clock %clock - // CHECK-NEXT: sv.always posedge %[[CLOCK0]] { - // CHECK-NEXT: "some.user"() : () -> () - // CHECK-NEXT: } - // CHECK: %[[CLOCK1:.*]] = seq.from_clock %clock - // CHECK-NEXT: sv.always posedge %[[CLOCK1]] { - // CHECK-NEXT: sv.if %en { + // CHECK: %[[LATE:.*]] = "some.value"() : () -> i1 + // CHECK-NEXT: sv.ifdef @SYNTHESIS { + // CHECK-NEXT: } else { + // CHECK-NEXT: %[[CLOCK0:.*]] = seq.from_clock %clock + // CHECK-NEXT: sv.always posedge %[[CLOCK0]] { // CHECK-NEXT: "some.user"() : () -> () // CHECK-NEXT: } + // CHECK-NEXT: %[[CLOCK1:.*]] = seq.from_clock %clock + // CHECK-NEXT: sv.always posedge %[[CLOCK1]] { + // CHECK-NEXT: sv.if %[[LATE]] { + // CHECK-NEXT: "some.user"() : () -> () + // CHECK-NEXT: } + // CHECK-NEXT: } // CHECK-NEXT: } } From c1d8d5368dc08fb3bd888f40bf27e84f2feabb4e Mon Sep 17 00:00:00 2001 From: woshiren Date: Sat, 16 May 2026 21:34:25 +0800 Subject: [PATCH 05/10] create a dedicated guard pre triggererOp --- lib/Conversion/SimToSV/SimToSV.cpp | 40 +++++++++++--------------- test/Conversion/SimToSV/triggered.mlir | 14 ++++----- 2 files changed, 23 insertions(+), 31 deletions(-) diff --git a/lib/Conversion/SimToSV/SimToSV.cpp b/lib/Conversion/SimToSV/SimToSV.cpp index 220400ab6abf..efcbded241ec 100644 --- a/lib/Conversion/SimToSV/SimToSV.cpp +++ b/lib/Conversion/SimToSV/SimToSV.cpp @@ -65,7 +65,6 @@ struct SimConversionState { bool usedSynthesisMacro = false; bool usedFileDescriptorRuntime = false; SetVector dpiCallees; - llvm::SmallDenseMap synthesisGuards; }; struct SimTypeConverter : public TypeConverter { @@ -278,30 +277,23 @@ class TriggeredLowering : public SimConversionPattern { auto loc = op.getLoc(); state.usedSynthesisMacro = true; - auto [it, inserted] = state.synthesisGuards.try_emplace(op->getBlock()); - auto ifdefOp = it->second; - if (!inserted) { - ifdefOp->moveBefore(op); - } else { - ifdefOp = sv::IfDefOp::create( - rewriter, loc, "SYNTHESIS", [] {}, [] {}); - it->second = ifdefOp; - } - rewriter.setInsertionPointToEnd(ifdefOp.getElseBlock()); - - auto trigger = seq::FromClockOp::create(rewriter, loc, adaptor.getClock()); - auto alwaysOp = sv::AlwaysOp::create( - rewriter, loc, ArrayRef{sv::EventControl::AtPosEdge}, - ArrayRef{trigger}); - - Block *destination = alwaysOp.getBodyBlock(); - if (auto condition = adaptor.getCondition()) { - rewriter.setInsertionPointToStart(destination); - destination = - sv::IfOp::create(rewriter, loc, condition, [] {}).getThenBlock(); - } + sv::IfDefOp::create(rewriter, loc, "SYNTHESIS", [] {}, [&] { + auto trigger = + seq::FromClockOp::create(rewriter, loc, adaptor.getClock()); + auto alwaysOp = sv::AlwaysOp::create( + rewriter, loc, + ArrayRef{sv::EventControl::AtPosEdge}, + ArrayRef{trigger}); + + Block *destination = alwaysOp.getBodyBlock(); + if (auto condition = adaptor.getCondition()) { + rewriter.setInsertionPointToStart(destination); + destination = + sv::IfOp::create(rewriter, loc, condition, [] {}).getThenBlock(); + } - rewriter.mergeBlocks(op.getBodyBlock(), destination); + rewriter.mergeBlocks(op.getBodyBlock(), destination); + }); rewriter.eraseOp(op); return success(); } diff --git a/test/Conversion/SimToSV/triggered.mlir b/test/Conversion/SimToSV/triggered.mlir index d41c272908e9..7e80ae1bf922 100644 --- a/test/Conversion/SimToSV/triggered.mlir +++ b/test/Conversion/SimToSV/triggered.mlir @@ -35,28 +35,28 @@ hw.module @conditional_triggered( // CHECK-LABEL: hw.module @multiple_triggered hw.module @multiple_triggered( - in %clock : !seq.clock) { + in %clock : !seq.clock, in %en : i1) { sim.triggered %clock { "some.user"() : () -> () } - %late_cond = "some.value"() : () -> i1 - - sim.triggered %clock if %late_cond { + sim.triggered %clock if %en { "some.user"() : () -> () } - // CHECK: %[[LATE:.*]] = "some.value"() : () -> i1 - // CHECK-NEXT: sv.ifdef @SYNTHESIS { + // CHECK: sv.ifdef @SYNTHESIS { // CHECK-NEXT: } else { // CHECK-NEXT: %[[CLOCK0:.*]] = seq.from_clock %clock // CHECK-NEXT: sv.always posedge %[[CLOCK0]] { // CHECK-NEXT: "some.user"() : () -> () // CHECK-NEXT: } + // CHECK-NEXT: } + // CHECK: sv.ifdef @SYNTHESIS { + // CHECK-NEXT: } else { // CHECK-NEXT: %[[CLOCK1:.*]] = seq.from_clock %clock // CHECK-NEXT: sv.always posedge %[[CLOCK1]] { - // CHECK-NEXT: sv.if %[[LATE]] { + // CHECK-NEXT: sv.if %en { // CHECK-NEXT: "some.user"() : () -> () // CHECK-NEXT: } // CHECK-NEXT: } From 6af9a401576ef15a20d668e4d2a244fad71f6c38 Mon Sep 17 00:00:00 2001 From: woshiren Date: Sat, 16 May 2026 21:35:10 +0800 Subject: [PATCH 06/10] fix format --- lib/Conversion/SimToSV/SimToSV.cpp | 34 ++++++++++++++++-------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/lib/Conversion/SimToSV/SimToSV.cpp b/lib/Conversion/SimToSV/SimToSV.cpp index efcbded241ec..df3b07239a28 100644 --- a/lib/Conversion/SimToSV/SimToSV.cpp +++ b/lib/Conversion/SimToSV/SimToSV.cpp @@ -277,23 +277,25 @@ class TriggeredLowering : public SimConversionPattern { auto loc = op.getLoc(); state.usedSynthesisMacro = true; - sv::IfDefOp::create(rewriter, loc, "SYNTHESIS", [] {}, [&] { - auto trigger = - seq::FromClockOp::create(rewriter, loc, adaptor.getClock()); - auto alwaysOp = sv::AlwaysOp::create( - rewriter, loc, - ArrayRef{sv::EventControl::AtPosEdge}, - ArrayRef{trigger}); - - Block *destination = alwaysOp.getBodyBlock(); - if (auto condition = adaptor.getCondition()) { - rewriter.setInsertionPointToStart(destination); - destination = - sv::IfOp::create(rewriter, loc, condition, [] {}).getThenBlock(); - } + sv::IfDefOp::create( + rewriter, loc, "SYNTHESIS", [] {}, + [&] { + auto trigger = + seq::FromClockOp::create(rewriter, loc, adaptor.getClock()); + auto alwaysOp = sv::AlwaysOp::create( + rewriter, loc, + ArrayRef{sv::EventControl::AtPosEdge}, + ArrayRef{trigger}); + + Block *destination = alwaysOp.getBodyBlock(); + if (auto condition = adaptor.getCondition()) { + rewriter.setInsertionPointToStart(destination); + destination = sv::IfOp::create(rewriter, loc, condition, [] { + }).getThenBlock(); + } - rewriter.mergeBlocks(op.getBodyBlock(), destination); - }); + rewriter.mergeBlocks(op.getBodyBlock(), destination); + }); rewriter.eraseOp(op); return success(); } From f36a74f56be9ac103203828ae670201625969185 Mon Sep 17 00:00:00 2001 From: woshiren Date: Sat, 16 May 2026 21:52:56 +0800 Subject: [PATCH 07/10] add test triggered_with_pause --- test/Conversion/SimToSV/triggered.mlir | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/test/Conversion/SimToSV/triggered.mlir b/test/Conversion/SimToSV/triggered.mlir index 7e80ae1bf922..8b09292702f4 100644 --- a/test/Conversion/SimToSV/triggered.mlir +++ b/test/Conversion/SimToSV/triggered.mlir @@ -62,3 +62,19 @@ hw.module @multiple_triggered( // CHECK-NEXT: } // CHECK-NEXT: } } + +// CHECK-LABEL: hw.module @triggered_with_pause +hw.module @triggered_with_pause(in %clock : !seq.clock) { + sim.triggered %clock { + sim.pause quiet + } + + // CHECK: sv.ifdef @SYNTHESIS { + // CHECK-NOT: sv.ifdef.procedural @SYNTHESIS + // CHECK-NEXT: } else { + // CHECK-NEXT: %[[CLOCK:.*]] = seq.from_clock %clock + // CHECK-NEXT: sv.always posedge %[[CLOCK]] { + // CHECK-NEXT: sv.stop 0 + // CHECK-NEXT: } + // CHECK-NEXT: } +} From 85acb842976fc48b2271cd1737f2fc7687bcce8b Mon Sep 17 00:00:00 2001 From: woshiren Date: Sat, 16 May 2026 21:55:59 +0800 Subject: [PATCH 08/10] skil sim.trigger in moveOpsIntoIfdefGuardsAndProcesses --- lib/Conversion/SimToSV/SimToSV.cpp | 165 +++++++++++++++-------------- 1 file changed, 87 insertions(+), 78 deletions(-) diff --git a/lib/Conversion/SimToSV/SimToSV.cpp b/lib/Conversion/SimToSV/SimToSV.cpp index df3b07239a28..e63284d0b929 100644 --- a/lib/Conversion/SimToSV/SimToSV.cpp +++ b/lib/Conversion/SimToSV/SimToSV.cpp @@ -468,89 +468,98 @@ addFragments(hw::HWModuleOp module, static bool moveOpsIntoIfdefGuardsAndProcesses(Operation *rootOp) { bool usedSynthesisMacro = false; - rootOp->walk([&](Operation *op) { - auto loc = op->getLoc(); - - // Move the op into an ifdef guard if needed. - if (needsIfdefGuard(op)) { - // Try to reuse an ifdef guard immediately before the op. - Block *block = nullptr; - if (op->getPrevNode()) - block = TypeSwitch(op->getPrevNode()) - .Case( - [&](auto guardOp) -> Block * { - if (guardOp.getCond().getIdent().getAttr() == - "SYNTHESIS" && - guardOp.hasElse()) - return guardOp.getElseBlock(); - return nullptr; - }) - .Default([](auto) { return nullptr; }); - - // If there was no pre-existing guard, create one. - if (!block) { - OpBuilder builder(op); - if (op->getParentOp()->hasTrait()) - block = sv::IfDefProceduralOp::create( - builder, loc, "SYNTHESIS", [] {}, [] {}) - .getElseBlock(); - else - block = sv::IfDefOp::create( - builder, loc, "SYNTHESIS", [] {}, [] {}) - .getElseBlock(); - usedSynthesisMacro = true; - } + rootOp->walk( + [&](Operation *op) -> mlir::WalkResult { + // `sim.triggered` is lowered as a whole later on. Do not pre-wrap the + // ops nested inside it here, or we may create redundant/invalid + // structure. + if (isa(op)) + return mlir::WalkResult::skip(); + + auto loc = op->getLoc(); + + // Move the op into an ifdef guard if needed. + if (needsIfdefGuard(op)) { + // Try to reuse an ifdef guard immediately before the op. + Block *block = nullptr; + if (op->getPrevNode()) + block = TypeSwitch(op->getPrevNode()) + .Case( + [&](auto guardOp) -> Block * { + if (guardOp.getCond().getIdent().getAttr() == + "SYNTHESIS" && + guardOp.hasElse()) + return guardOp.getElseBlock(); + return nullptr; + }) + .Default([](auto) { return nullptr; }); + + // If there was no pre-existing guard, create one. + if (!block) { + OpBuilder builder(op); + if (op->getParentOp()->hasTrait()) + block = sv::IfDefProceduralOp::create( + builder, loc, "SYNTHESIS", [] {}, [] {}) + .getElseBlock(); + else + block = sv::IfDefOp::create( + builder, loc, "SYNTHESIS", [] {}, [] {}) + .getElseBlock(); + usedSynthesisMacro = true; + } - // Move the op into the guard block. - op->moveBefore(block, block->end()); - } + // Move the op into the guard block. + op->moveBefore(block, block->end()); + } - // Check if the op requires an clock and condition wrapper. - auto [clock, condition] = needsClockAndConditionWrapper(op); - - // Create an enclosing always process. - if (clock) { - // Try to reuse an always process immediately before the op. - Block *block = nullptr; - if (auto alwaysOp = dyn_cast_or_null(op->getPrevNode())) - if (alwaysOp.getNumConditions() == 1 && - alwaysOp.getCondition(0).event == sv::EventControl::AtPosEdge) - if (auto clockOp = alwaysOp.getCondition(0) - .value.getDefiningOp()) - if (clockOp.getInput() == clock) - block = alwaysOp.getBodyBlock(); - - // If there was no pre-existing always process, create one. - if (!block) { - OpBuilder builder(op); - clock = seq::FromClockOp::create(builder, loc, clock); - block = sv::AlwaysOp::create(builder, loc, sv::EventControl::AtPosEdge, - clock, [] {}) - .getBodyBlock(); - } + // Check if the op requires an clock and condition wrapper. + auto [clock, condition] = needsClockAndConditionWrapper(op); + + // Create an enclosing always process. + if (clock) { + // Try to reuse an always process immediately before the op. + Block *block = nullptr; + if (auto alwaysOp = dyn_cast_or_null(op->getPrevNode())) + if (alwaysOp.getNumConditions() == 1 && + alwaysOp.getCondition(0).event == sv::EventControl::AtPosEdge) + if (auto clockOp = alwaysOp.getCondition(0) + .value.getDefiningOp()) + if (clockOp.getInput() == clock) + block = alwaysOp.getBodyBlock(); + + // If there was no pre-existing always process, create one. + if (!block) { + OpBuilder builder(op); + clock = seq::FromClockOp::create(builder, loc, clock); + block = sv::AlwaysOp::create( + builder, loc, sv::EventControl::AtPosEdge, clock, [] {}) + .getBodyBlock(); + } - // Move the op into the process. - op->moveBefore(block, block->end()); - } + // Move the op into the process. + op->moveBefore(block, block->end()); + } - // Create an enclosing if condition. - if (condition) { - // Try to reuse an if statement immediately before the op. - Block *block = nullptr; - if (auto ifOp = dyn_cast_or_null(op->getPrevNode())) - if (ifOp.getCond() == condition) - block = ifOp.getThenBlock(); - - // If there was no pre-existing if statement, create one. - if (!block) { - OpBuilder builder(op); - block = sv::IfOp::create(builder, loc, condition, [] {}).getThenBlock(); - } + // Create an enclosing if condition. + if (condition) { + // Try to reuse an if statement immediately before the op. + Block *block = nullptr; + if (auto ifOp = dyn_cast_or_null(op->getPrevNode())) + if (ifOp.getCond() == condition) + block = ifOp.getThenBlock(); + + // If there was no pre-existing if statement, create one. + if (!block) { + OpBuilder builder(op); + block = + sv::IfOp::create(builder, loc, condition, [] {}).getThenBlock(); + } - // Move the op into the if body. - op->moveBefore(block, block->end()); - } - }); + // Move the op into the if body. + op->moveBefore(block, block->end()); + } + return mlir::WalkResult::advance(); + }); return usedSynthesisMacro; } From 2bdf90856d1e0919bd282afcceb658bd33505c05 Mon Sep 17 00:00:00 2001 From: woshiren Date: Sat, 16 May 2026 22:19:57 +0800 Subject: [PATCH 09/10] remove the mlir qualifier --- lib/Conversion/SimToSV/SimToSV.cpp | 174 ++++++++++++++--------------- 1 file changed, 87 insertions(+), 87 deletions(-) diff --git a/lib/Conversion/SimToSV/SimToSV.cpp b/lib/Conversion/SimToSV/SimToSV.cpp index e63284d0b929..a0f2ae35b80e 100644 --- a/lib/Conversion/SimToSV/SimToSV.cpp +++ b/lib/Conversion/SimToSV/SimToSV.cpp @@ -26,6 +26,7 @@ #include "mlir/IR/DialectImplementation.h" #include "mlir/IR/ImplicitLocOpBuilder.h" #include "mlir/IR/Threading.h" +#include "mlir/IR/Visitors.h" #include "mlir/Pass/Pass.h" #include "mlir/Transforms/DialectConversion.h" #include "mlir/Transforms/RegionUtils.h" @@ -40,6 +41,7 @@ namespace circt { using namespace circt; using namespace sim; +using mlir::WalkOrder; /// Check whether an op should be placed inside an ifdef guard that prevents it /// from affecting synthesis runs. @@ -468,98 +470,96 @@ addFragments(hw::HWModuleOp module, static bool moveOpsIntoIfdefGuardsAndProcesses(Operation *rootOp) { bool usedSynthesisMacro = false; - rootOp->walk( - [&](Operation *op) -> mlir::WalkResult { - // `sim.triggered` is lowered as a whole later on. Do not pre-wrap the - // ops nested inside it here, or we may create redundant/invalid - // structure. - if (isa(op)) - return mlir::WalkResult::skip(); - - auto loc = op->getLoc(); - - // Move the op into an ifdef guard if needed. - if (needsIfdefGuard(op)) { - // Try to reuse an ifdef guard immediately before the op. - Block *block = nullptr; - if (op->getPrevNode()) - block = TypeSwitch(op->getPrevNode()) - .Case( - [&](auto guardOp) -> Block * { - if (guardOp.getCond().getIdent().getAttr() == - "SYNTHESIS" && - guardOp.hasElse()) - return guardOp.getElseBlock(); - return nullptr; - }) - .Default([](auto) { return nullptr; }); - - // If there was no pre-existing guard, create one. - if (!block) { - OpBuilder builder(op); - if (op->getParentOp()->hasTrait()) - block = sv::IfDefProceduralOp::create( - builder, loc, "SYNTHESIS", [] {}, [] {}) - .getElseBlock(); - else - block = sv::IfDefOp::create( - builder, loc, "SYNTHESIS", [] {}, [] {}) - .getElseBlock(); - usedSynthesisMacro = true; - } + rootOp->walk([&](Operation *op) { + // `sim.triggered` is lowered as a whole later on. Do not pre-wrap the + // ops nested inside it here, or we may create redundant/invalid + // structure. + if (isa(op)) + return mlir::WalkResult::skip(); + + auto loc = op->getLoc(); + + // Move the op into an ifdef guard if needed. + if (needsIfdefGuard(op)) { + // Try to reuse an ifdef guard immediately before the op. + Block *block = nullptr; + if (op->getPrevNode()) + block = TypeSwitch(op->getPrevNode()) + .Case( + [&](auto guardOp) -> Block * { + if (guardOp.getCond().getIdent().getAttr() == + "SYNTHESIS" && + guardOp.hasElse()) + return guardOp.getElseBlock(); + return nullptr; + }) + .Default([](auto) { return nullptr; }); + + // If there was no pre-existing guard, create one. + if (!block) { + OpBuilder builder(op); + if (op->getParentOp()->hasTrait()) + block = sv::IfDefProceduralOp::create( + builder, loc, "SYNTHESIS", [] {}, [] {}) + .getElseBlock(); + else + block = sv::IfDefOp::create( + builder, loc, "SYNTHESIS", [] {}, [] {}) + .getElseBlock(); + usedSynthesisMacro = true; + } - // Move the op into the guard block. - op->moveBefore(block, block->end()); - } + // Move the op into the guard block. + op->moveBefore(block, block->end()); + } - // Check if the op requires an clock and condition wrapper. - auto [clock, condition] = needsClockAndConditionWrapper(op); - - // Create an enclosing always process. - if (clock) { - // Try to reuse an always process immediately before the op. - Block *block = nullptr; - if (auto alwaysOp = dyn_cast_or_null(op->getPrevNode())) - if (alwaysOp.getNumConditions() == 1 && - alwaysOp.getCondition(0).event == sv::EventControl::AtPosEdge) - if (auto clockOp = alwaysOp.getCondition(0) - .value.getDefiningOp()) - if (clockOp.getInput() == clock) - block = alwaysOp.getBodyBlock(); - - // If there was no pre-existing always process, create one. - if (!block) { - OpBuilder builder(op); - clock = seq::FromClockOp::create(builder, loc, clock); - block = sv::AlwaysOp::create( - builder, loc, sv::EventControl::AtPosEdge, clock, [] {}) - .getBodyBlock(); - } + // Check if the op requires an clock and condition wrapper. + auto [clock, condition] = needsClockAndConditionWrapper(op); + + // Create an enclosing always process. + if (clock) { + // Try to reuse an always process immediately before the op. + Block *block = nullptr; + if (auto alwaysOp = dyn_cast_or_null(op->getPrevNode())) + if (alwaysOp.getNumConditions() == 1 && + alwaysOp.getCondition(0).event == sv::EventControl::AtPosEdge) + if (auto clockOp = alwaysOp.getCondition(0) + .value.getDefiningOp()) + if (clockOp.getInput() == clock) + block = alwaysOp.getBodyBlock(); + + // If there was no pre-existing always process, create one. + if (!block) { + OpBuilder builder(op); + clock = seq::FromClockOp::create(builder, loc, clock); + block = sv::AlwaysOp::create(builder, loc, sv::EventControl::AtPosEdge, + clock, [] {}) + .getBodyBlock(); + } - // Move the op into the process. - op->moveBefore(block, block->end()); - } + // Move the op into the process. + op->moveBefore(block, block->end()); + } - // Create an enclosing if condition. - if (condition) { - // Try to reuse an if statement immediately before the op. - Block *block = nullptr; - if (auto ifOp = dyn_cast_or_null(op->getPrevNode())) - if (ifOp.getCond() == condition) - block = ifOp.getThenBlock(); - - // If there was no pre-existing if statement, create one. - if (!block) { - OpBuilder builder(op); - block = - sv::IfOp::create(builder, loc, condition, [] {}).getThenBlock(); - } + // Create an enclosing if condition. + if (condition) { + // Try to reuse an if statement immediately before the op. + Block *block = nullptr; + if (auto ifOp = dyn_cast_or_null(op->getPrevNode())) + if (ifOp.getCond() == condition) + block = ifOp.getThenBlock(); + + // If there was no pre-existing if statement, create one. + if (!block) { + OpBuilder builder(op); + block = sv::IfOp::create(builder, loc, condition, [] {}).getThenBlock(); + } - // Move the op into the if body. - op->moveBefore(block, block->end()); - } - return mlir::WalkResult::advance(); - }); + // Move the op into the if body. + op->moveBefore(block, block->end()); + } + return mlir::WalkResult::advance(); + }); return usedSynthesisMacro; } From 63a14bf6a445504e55ee0665580651e67ee5ec5c Mon Sep 17 00:00:00 2001 From: woshiren Date: Sat, 16 May 2026 22:31:39 +0800 Subject: [PATCH 10/10] using namespace mlir --- lib/Conversion/SimToSV/SimToSV.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/Conversion/SimToSV/SimToSV.cpp b/lib/Conversion/SimToSV/SimToSV.cpp index a0f2ae35b80e..607e3df9e45f 100644 --- a/lib/Conversion/SimToSV/SimToSV.cpp +++ b/lib/Conversion/SimToSV/SimToSV.cpp @@ -41,7 +41,7 @@ namespace circt { using namespace circt; using namespace sim; -using mlir::WalkOrder; +using namespace mlir; /// Check whether an op should be placed inside an ifdef guard that prevents it /// from affecting synthesis runs. @@ -475,7 +475,7 @@ static bool moveOpsIntoIfdefGuardsAndProcesses(Operation *rootOp) { // ops nested inside it here, or we may create redundant/invalid // structure. if (isa(op)) - return mlir::WalkResult::skip(); + return WalkResult::skip(); auto loc = op->getLoc(); @@ -558,7 +558,7 @@ static bool moveOpsIntoIfdefGuardsAndProcesses(Operation *rootOp) { // Move the op into the if body. op->moveBefore(block, block->end()); } - return mlir::WalkResult::advance(); + return WalkResult::advance(); }); return usedSynthesisMacro;