From 60ab76ffd8eb90d2e0265f08fa426029edc94d75 Mon Sep 17 00:00:00 2001 From: Leon Hielscher Date: Sat, 11 Apr 2026 13:15:48 +0200 Subject: [PATCH 1/2] [LLHD][SV] Unify the ProceduralRegion trait in CIRCTSupport Move the `ProceduralRegion` operation traits of the LLHD and SV dialects to a common declaration within the CIRCT support library. This should allow us to (temporarily) include procedural operations of one dialect under procedural regions of another dialect during lowering, without triggering an IR verification error. The behavior of the trait within the dialects remains unchanged. --- include/circt/Dialect/LLHD/LLHDOps.h | 10 +----- include/circt/Dialect/LLHD/LLHDOps.td | 5 +-- include/circt/Dialect/SV/SV.td | 5 +-- include/circt/Dialect/SV/SVOps.h | 10 +----- include/circt/Support/ProceduralRegionTrait.h | 32 +++++++++++++++++++ .../circt/Support/ProceduralRegionTrait.td | 18 +++++++++++ .../ExportVerilog/ExportVerilog.cpp | 1 + .../ExportVerilog/PrepareForEmission.cpp | 1 + lib/Conversion/SimToSV/SimToSV.cpp | 3 +- lib/Dialect/SV/SVOps.cpp | 5 +-- lib/Dialect/SV/Transforms/HWCleanup.cpp | 3 +- .../SV/Transforms/HWLegalizeModules.cpp | 3 +- lib/Dialect/Sim/SimOps.cpp | 3 +- 13 files changed, 67 insertions(+), 32 deletions(-) create mode 100644 include/circt/Support/ProceduralRegionTrait.h create mode 100644 include/circt/Support/ProceduralRegionTrait.td diff --git a/include/circt/Dialect/LLHD/LLHDOps.h b/include/circt/Dialect/LLHD/LLHDOps.h index 3655ebbda22b..1e3729e87958 100644 --- a/include/circt/Dialect/LLHD/LLHDOps.h +++ b/include/circt/Dialect/LLHD/LLHDOps.h @@ -14,6 +14,7 @@ #include "circt/Dialect/LLHD/LLHDEnums.h.inc" #include "circt/Dialect/LLHD/LLHDTypes.h" #include "circt/Support/LLVM.h" +#include "circt/Support/ProceduralRegionTrait.h" #include "mlir/IR/BuiltinTypes.h" #include "mlir/Interfaces/CallInterfaces.h" #include "mlir/Interfaces/ControlFlowInterfaces.h" @@ -32,15 +33,6 @@ namespace llhd { unsigned getLLHDTypeWidth(Type type); Type getLLHDElementType(Type type); -/// Signals that an operations regions are procedural. -template -class ProceduralRegion - : public mlir::OpTrait::TraitBase { - static LogicalResult verifyTrait(Operation *op) { - return mlir::OpTrait::impl::verifyNRegions(op, 1); - } -}; - void registerDestructableIntegerExternalModel(mlir::DialectRegistry ®istry); } // namespace llhd diff --git a/include/circt/Dialect/LLHD/LLHDOps.td b/include/circt/Dialect/LLHD/LLHDOps.td index 67aa9c5da25a..04f5f7b30324 100644 --- a/include/circt/Dialect/LLHD/LLHDOps.td +++ b/include/circt/Dialect/LLHD/LLHDOps.td @@ -11,6 +11,7 @@ include "circt/Dialect/LLHD/LLHDDialect.td" include "circt/Dialect/LLHD/LLHDTypes.td" +include "circt/Support/ProceduralRegionTrait.td" include "mlir/IR/EnumAttr.td" include "mlir/IR/OpAsmInterface.td" include "mlir/IR/SymbolInterfaces.td" @@ -54,10 +55,6 @@ class SmallerOrEqualResultTypeWidthConstraint CPred<"llhd::getLLHDTypeWidth($" # result # ".getType()) <= " # "llhd::getLLHDTypeWidth($" # input # ".getType())">>; -def ProceduralRegion : NativeOpTrait<"ProceduralRegion"> { - let cppNamespace = "::circt::llhd"; -} - //===----------------------------------------------------------------------===// // Constants //===----------------------------------------------------------------------===// diff --git a/include/circt/Dialect/SV/SV.td b/include/circt/Dialect/SV/SV.td index 1a781fb964af..7902aaa27fbe 100644 --- a/include/circt/Dialect/SV/SV.td +++ b/include/circt/Dialect/SV/SV.td @@ -13,6 +13,7 @@ #ifndef CIRCT_DIALECT_SV_SV #define CIRCT_DIALECT_SV_SV +include "circt/Support/ProceduralRegionTrait.td" include "mlir/IR/AttrTypeBase.td" include "mlir/IR/OpBase.td" include "mlir/IR/OpAsmInterface.td" @@ -25,10 +26,6 @@ include "circt/Dialect/SV/SVDialect.td" class SVOp traits = []> : Op; -def ProceduralRegion : NativeOpTrait<"ProceduralRegion"> { - let cppNamespace = "::circt::sv"; -} - def ProceduralOp : NativeOpTrait<"ProceduralOp"> { let cppNamespace = "::circt::sv"; } diff --git a/include/circt/Dialect/SV/SVOps.h b/include/circt/Dialect/SV/SVOps.h index 700f324b3bac..f84b81fe3180 100644 --- a/include/circt/Dialect/SV/SVOps.h +++ b/include/circt/Dialect/SV/SVOps.h @@ -20,6 +20,7 @@ #include "circt/Dialect/SV/SVAttributes.h" #include "circt/Dialect/SV/SVDialect.h" #include "circt/Dialect/SV/SVTypes.h" +#include "circt/Support/ProceduralRegionTrait.h" #include "mlir/IR/OpImplementation.h" #include "mlir/IR/SymbolTable.h" #include "mlir/Interfaces/CallInterfaces.h" @@ -170,15 +171,6 @@ LogicalResult verifyInProceduralRegion(Operation *op); /// Return true if the specified operation is not in a procedural region. LogicalResult verifyInNonProceduralRegion(Operation *op); -/// Signals that an operations regions are procedural. -template -class ProceduralRegion - : public mlir::OpTrait::TraitBase { - static LogicalResult verifyTrait(Operation *op) { - return mlir::OpTrait::impl::verifyAtLeastNRegions(op, 1); - } -}; - /// This class verifies that the specified op is located in a procedural region. template class ProceduralOp diff --git a/include/circt/Support/ProceduralRegionTrait.h b/include/circt/Support/ProceduralRegionTrait.h new file mode 100644 index 000000000000..39c0ea0ca5c6 --- /dev/null +++ b/include/circt/Support/ProceduralRegionTrait.h @@ -0,0 +1,32 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This header file defines the `ProceduralRegion` trait. +// +//===----------------------------------------------------------------------===// + +#ifndef CIRCT_SUPPORT_PROCEDURALREGIONTRAIT_H +#define CIRCT_SUPPORT_PROCEDURALREGIONTRAIT_H + +#include "mlir/IR/OpDefinition.h" +#include "llvm/Support/LogicalResult.h" + +namespace circt { + +/// Signals that an operation's regions are procedural. +template +class ProceduralRegion + : public mlir::OpTrait::TraitBase { + static LogicalResult verifyTrait(Operation *op) { + return mlir::OpTrait::impl::verifyNRegions(op, 1); + } +}; + +} // namespace circt + +#endif // CIRCT_SUPPORT_PROCEDURALREGIONTRAIT_H diff --git a/include/circt/Support/ProceduralRegionTrait.td b/include/circt/Support/ProceduralRegionTrait.td new file mode 100644 index 000000000000..a1653a967d97 --- /dev/null +++ b/include/circt/Support/ProceduralRegionTrait.td @@ -0,0 +1,18 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef CIRCT_SUPPORT_PROCDURALREGIONTRAIT_TD +#define CIRCT_SUPPORT_PROCDURALREGIONTRAIT_TD + +include "mlir/IR/OpBase.td" + +def ProceduralRegion : NativeOpTrait<"ProceduralRegion"> { + let cppNamespace = "::circt"; +} + +#endif // CIRCT_SUPPORT_PROCDURALREGIONTRAIT_TD diff --git a/lib/Conversion/ExportVerilog/ExportVerilog.cpp b/lib/Conversion/ExportVerilog/ExportVerilog.cpp index 7a426c39dbd6..c210208395e5 100644 --- a/lib/Conversion/ExportVerilog/ExportVerilog.cpp +++ b/lib/Conversion/ExportVerilog/ExportVerilog.cpp @@ -37,6 +37,7 @@ #include "circt/Support/Path.h" #include "circt/Support/PrettyPrinter.h" #include "circt/Support/PrettyPrinterHelpers.h" +#include "circt/Support/ProceduralRegionTrait.h" #include "circt/Support/Version.h" #include "mlir/IR/BuiltinOps.h" #include "mlir/IR/ImplicitLocOpBuilder.h" diff --git a/lib/Conversion/ExportVerilog/PrepareForEmission.cpp b/lib/Conversion/ExportVerilog/PrepareForEmission.cpp index 8a8192cdce8f..d0840f59a261 100644 --- a/lib/Conversion/ExportVerilog/PrepareForEmission.cpp +++ b/lib/Conversion/ExportVerilog/PrepareForEmission.cpp @@ -24,6 +24,7 @@ #include "circt/Dialect/LTL/LTLDialect.h" #include "circt/Dialect/Verif/VerifDialect.h" #include "circt/Support/LoweringOptions.h" +#include "circt/Support/ProceduralRegionTrait.h" #include "mlir/IR/ImplicitLocOpBuilder.h" #include "mlir/Interfaces/CallInterfaces.h" #include "mlir/Pass/Pass.h" diff --git a/lib/Conversion/SimToSV/SimToSV.cpp b/lib/Conversion/SimToSV/SimToSV.cpp index 965ac5cd38b1..cef99575ae74 100644 --- a/lib/Conversion/SimToSV/SimToSV.cpp +++ b/lib/Conversion/SimToSV/SimToSV.cpp @@ -19,6 +19,7 @@ #include "circt/Dialect/Sim/SimDialect.h" #include "circt/Dialect/Sim/SimOps.h" #include "circt/Support/Namespace.h" +#include "circt/Support/ProceduralRegionTrait.h" #include "mlir/IR/Builders.h" #include "mlir/IR/DialectImplementation.h" #include "mlir/IR/ImplicitLocOpBuilder.h" @@ -398,7 +399,7 @@ static bool moveOpsIntoIfdefGuardsAndProcesses(Operation *rootOp) { // If there was no pre-existing guard, create one. if (!block) { OpBuilder builder(op); - if (op->getParentOp()->hasTrait()) + if (op->getParentOp()->hasTrait()) block = sv::IfDefProceduralOp::create( builder, loc, "SYNTHESIS", [] {}, [] {}) .getElseBlock(); diff --git a/lib/Dialect/SV/SVOps.cpp b/lib/Dialect/SV/SVOps.cpp index 12d1288ab61d..b4a7bf1c49c2 100644 --- a/lib/Dialect/SV/SVOps.cpp +++ b/lib/Dialect/SV/SVOps.cpp @@ -21,6 +21,7 @@ #include "circt/Dialect/HW/ModuleImplementation.h" #include "circt/Dialect/SV/SVAttributes.h" #include "circt/Support/CustomDirectiveImpl.h" +#include "circt/Support/ProceduralRegionTrait.h" #include "mlir/IR/Builders.h" #include "mlir/IR/BuiltinTypes.h" #include "mlir/IR/Matchers.h" @@ -56,14 +57,14 @@ bool sv::isExpression(Operation *op) { } LogicalResult sv::verifyInProceduralRegion(Operation *op) { - if (op->getParentOp()->hasTrait()) + if (op->getParentOp()->hasTrait()) return success(); op->emitError() << op->getName() << " should be in a procedural region"; return failure(); } LogicalResult sv::verifyInNonProceduralRegion(Operation *op) { - if (!op->getParentOp()->hasTrait()) + if (!op->getParentOp()->hasTrait()) return success(); op->emitError() << op->getName() << " should be in a non-procedural region"; return failure(); diff --git a/lib/Dialect/SV/Transforms/HWCleanup.cpp b/lib/Dialect/SV/Transforms/HWCleanup.cpp index 3c5e5a7730df..941848fb83d3 100644 --- a/lib/Dialect/SV/Transforms/HWCleanup.cpp +++ b/lib/Dialect/SV/Transforms/HWCleanup.cpp @@ -17,6 +17,7 @@ #include "circt/Dialect/SV/SVAttributes.h" #include "circt/Dialect/SV/SVOps.h" #include "circt/Dialect/SV/SVPasses.h" +#include "circt/Support/ProceduralRegionTrait.h" #include "mlir/Pass/Pass.h" namespace circt { @@ -144,7 +145,7 @@ void HWCleanupPass::runOnOperation() { /// Recursively process all of the regions in the specified op, dispatching to /// graph or procedural processing as appropriate. void HWCleanupPass::runOnRegionsInOp(Operation &op) { - if (op.hasTrait()) { + if (op.hasTrait()) { for (auto ®ion : op.getRegions()) runOnProceduralRegion(region); } else { diff --git a/lib/Dialect/SV/Transforms/HWLegalizeModules.cpp b/lib/Dialect/SV/Transforms/HWLegalizeModules.cpp index 6587c383047a..e4ee0ee262a3 100644 --- a/lib/Dialect/SV/Transforms/HWLegalizeModules.cpp +++ b/lib/Dialect/SV/Transforms/HWLegalizeModules.cpp @@ -20,6 +20,7 @@ #include "circt/Dialect/SV/SVOps.h" #include "circt/Dialect/SV/SVPasses.h" #include "circt/Support/LoweringOptions.h" +#include "circt/Support/ProceduralRegionTrait.h" #include "mlir/IR/Builders.h" #include "mlir/Pass/Pass.h" @@ -288,7 +289,7 @@ Value HWLegalizeModulesPass::lowerLookupToCasez(Operation &op, Value input, // A casez is a procedural operation, so if we're in a // non-procedural region we need to inject an always_comb // block. - if (!op.getParentOp()->hasTrait()) { + if (!op.getParentOp()->hasTrait()) { auto alwaysComb = sv::AlwaysCombOp::create(builder, loc); builder.setInsertionPointToEnd(alwaysComb.getBodyBlock()); } diff --git a/lib/Dialect/Sim/SimOps.cpp b/lib/Dialect/Sim/SimOps.cpp index 92dc72ff735c..3e74b53b51dd 100644 --- a/lib/Dialect/Sim/SimOps.cpp +++ b/lib/Dialect/Sim/SimOps.cpp @@ -15,6 +15,7 @@ #include "circt/Dialect/HW/HWTypes.h" #include "circt/Dialect/SV/SVOps.h" #include "circt/Support/CustomDirectiveImpl.h" +#include "circt/Support/ProceduralRegionTrait.h" #include "mlir/Dialect/Func/IR/FuncOps.h" #include "mlir/Dialect/LLVMIR/LLVMTypes.h" #include "mlir/IR/PatternMatch.h" @@ -639,7 +640,7 @@ LogicalResult PrintFormattedProcOp::verify() { } if (isa_and_nonnull(parentOp->getDialect())) { - if (!parentOp->hasTrait()) + if (!parentOp->hasTrait()) return emitOpError("must be within a procedural region."); return success(); } From 1db780a42815571280d74373acb28a5a94a1cc83 Mon Sep 17 00:00:00 2001 From: Leon Hielscher Date: Mon, 13 Apr 2026 18:01:56 +0200 Subject: [PATCH 2/2] Add support header --- include/circt/Support/ProceduralRegionTrait.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/circt/Support/ProceduralRegionTrait.h b/include/circt/Support/ProceduralRegionTrait.h index 39c0ea0ca5c6..a2be345d7723 100644 --- a/include/circt/Support/ProceduralRegionTrait.h +++ b/include/circt/Support/ProceduralRegionTrait.h @@ -13,6 +13,7 @@ #ifndef CIRCT_SUPPORT_PROCEDURALREGIONTRAIT_H #define CIRCT_SUPPORT_PROCEDURALREGIONTRAIT_H +#include "circt/Support/LLVM.h" #include "mlir/IR/OpDefinition.h" #include "llvm/Support/LogicalResult.h"