diff --git a/include/circt/Dialect/Moore/MooreOps.td b/include/circt/Dialect/Moore/MooreOps.td index 584369c67ade..e7fafc24a63c 100644 --- a/include/circt/Dialect/Moore/MooreOps.td +++ b/include/circt/Dialect/Moore/MooreOps.td @@ -459,7 +459,7 @@ def DetectEventOp : MooreOp<"detect_event", [ } //===----------------------------------------------------------------------===// -// Expressions +// Constants //===----------------------------------------------------------------------===// def ConstantOp : MooreOp<"constant", [Pure, ConstantLike]> { @@ -476,37 +476,6 @@ def ConstantOp : MooreOp<"constant", [Pure, ConstantLike]> { ]; } -def Parameter : I32EnumAttrCase<"Parameter", 0, "parameter">; -def LocalParameter : I32EnumAttrCase<"LocalParameter", 1, "localparam">; -def SpecParameter : I32EnumAttrCase<"SpecParameter", 2, "specparam">; - -def NamedConstAttr : I32EnumAttr<"NamedConst", "elaboration-time constants", - [Parameter, LocalParameter, SpecParameter]>{ - let cppNamespace = "circt::moore"; -} - -def NamedConstantOp : MooreOp<"named_constant", [ - SameOperandsAndResultType, - DeclareOpInterfaceMethods -]>{ - let summary = "An elaboration time constant expression"; - let description = [{ - Constants are named data objects that never change. SystemVerilog provides - three elaboration-time constants: parameter, localparam, and specparam. - - See IEEE 1800-2017 ยง 6.20 "Constants". - }]; - let arguments = (ins StrAttr:$name, - NamedConstAttr:$kind, - IntType:$value); - let results = (outs IntType:$result); - let assemblyFormat = [{ - $kind - ``custom($name) - $value `:` type($result) attr-dict - }]; -} - def StringConstantOp : MooreOp<"string_constant", [Pure]> { let summary = "Produce a constant string value"; let description = [{ @@ -522,6 +491,10 @@ def StringConstantOp : MooreOp<"string_constant", [Pure]> { let assemblyFormat = "$value attr-dict `:` type($result)"; } +//===----------------------------------------------------------------------===// +// Expressions +//===----------------------------------------------------------------------===// + def ConversionOp : MooreOp<"conversion", [Pure]> { let summary = "A type conversion"; let description = [{ diff --git a/lib/Conversion/ImportVerilog/CMakeLists.txt b/lib/Conversion/ImportVerilog/CMakeLists.txt index bb321c581a1f..af170d99715a 100644 --- a/lib/Conversion/ImportVerilog/CMakeLists.txt +++ b/lib/Conversion/ImportVerilog/CMakeLists.txt @@ -40,6 +40,7 @@ add_circt_translation_library(CIRCTImportVerilog slang_slang LINK_LIBS PUBLIC + CIRCTDebug CIRCTHW CIRCTMoore MLIRFuncDialect diff --git a/lib/Conversion/ImportVerilog/ImportVerilog.cpp b/lib/Conversion/ImportVerilog/ImportVerilog.cpp index ba0c76c0c3c6..16462f8d1a1f 100644 --- a/lib/Conversion/ImportVerilog/ImportVerilog.cpp +++ b/lib/Conversion/ImportVerilog/ImportVerilog.cpp @@ -264,8 +264,9 @@ LogicalResult ImportDriver::importVerilog(ModuleOp module) { return success(); // Traverse the parsed Verilog AST and map it to the equivalent CIRCT ops. - mlirContext->loadDialect(); + mlirContext + ->loadDialect(); auto conversionTimer = ts.nest("Verilog to dialect mapping"); Context context(options, *compilation, module, driver.sourceManager, bufferFilePaths); diff --git a/lib/Conversion/ImportVerilog/ImportVerilogInternals.h b/lib/Conversion/ImportVerilog/ImportVerilogInternals.h index bfeab47d4e3f..f99e1c156395 100644 --- a/lib/Conversion/ImportVerilog/ImportVerilogInternals.h +++ b/lib/Conversion/ImportVerilog/ImportVerilogInternals.h @@ -11,6 +11,7 @@ #define CONVERSION_IMPORTVERILOG_IMPORTVERILOGINTERNALS_H #include "circt/Conversion/ImportVerilog.h" +#include "circt/Dialect/Debug/DebugOps.h" #include "circt/Dialect/HW/HWOps.h" #include "circt/Dialect/Moore/MooreOps.h" #include "mlir/Dialect/ControlFlow/IR/ControlFlowOps.h" diff --git a/lib/Conversion/ImportVerilog/Structure.cpp b/lib/Conversion/ImportVerilog/Structure.cpp index 441d4c9f367c..07296d93d4fe 100644 --- a/lib/Conversion/ImportVerilog/Structure.cpp +++ b/lib/Conversion/ImportVerilog/Structure.cpp @@ -12,6 +12,21 @@ using namespace circt; using namespace ImportVerilog; +//===----------------------------------------------------------------------===// +// Utilities +//===----------------------------------------------------------------------===// + +static void guessNamespacePrefix(const slang::ast::Symbol &symbol, + SmallString<64> &prefix) { + if (symbol.kind != slang::ast::SymbolKind::Package) + return; + guessNamespacePrefix(symbol.getParentScope()->asSymbol(), prefix); + if (!symbol.name.empty()) { + prefix += symbol.name; + prefix += "::"; + } +} + //===----------------------------------------------------------------------===// // Base Visitor //===----------------------------------------------------------------------===// @@ -20,6 +35,13 @@ namespace { /// Base visitor which ignores AST nodes that are handled by Slang's name /// resolution and type checking. struct BaseVisitor { + Context &context; + Location loc; + OpBuilder &builder; + + BaseVisitor(Context &context, Location loc) + : context(context), loc(loc), builder(context.builder) {} + // Skip semicolons. LogicalResult visit(const slang::ast::EmptyMemberSymbol &) { return success(); @@ -41,6 +63,46 @@ struct BaseVisitor { LogicalResult visit(const slang::ast::WildcardImportSymbol &) { return success(); } + + // Skip type parameters. The Slang AST is already monomorphized. + LogicalResult visit(const slang::ast::TypeParameterSymbol &) { + return success(); + } + + // Handle parameters. + LogicalResult visit(const slang::ast::ParameterSymbol ¶m) { + visitParameter(param); + return success(); + } + + LogicalResult visit(const slang::ast::SpecparamSymbol ¶m) { + visitParameter(param); + return success(); + } + + template + void visitParameter(const Node ¶m) { + // If debug info is enabled, try to materialize the parameter's constant + // value on a best-effort basis and create a `dbg.variable` to track the + // value. + if (!context.options.debugInfo) + return; + auto value = + context.materializeConstant(param.getValue(), param.getType(), loc); + if (!value) + return; + if (builder.getInsertionBlock()->getParentOp() == context.intoModuleOp) + context.orderedRootOps.insert({param.location, value.getDefiningOp()}); + + // Prefix the parameter name with the surrounding namespace to create + // somewhat sane names in the IR. + SmallString<64> paramName; + guessNamespacePrefix(param.getParentScope()->asSymbol(), paramName); + paramName += param.name; + + builder.create(loc, builder.getStringAttr(paramName), + value, Value{}); + } }; } // namespace @@ -50,15 +112,9 @@ struct BaseVisitor { namespace { struct RootVisitor : public BaseVisitor { + using BaseVisitor::BaseVisitor; using BaseVisitor::visit; - Context &context; - Location loc; - OpBuilder &builder; - - RootVisitor(Context &context, Location loc) - : context(context), loc(loc), builder(context.builder) {} - // Handle packages. LogicalResult visit(const slang::ast::PackageSymbol &package) { return context.convertPackage(package); @@ -85,22 +141,9 @@ struct RootVisitor : public BaseVisitor { namespace { struct PackageVisitor : public BaseVisitor { + using BaseVisitor::BaseVisitor; using BaseVisitor::visit; - Context &context; - Location loc; - OpBuilder &builder; - - PackageVisitor(Context &context, Location loc) - : context(context), loc(loc), builder(context.builder) {} - - // Ignore parameters. These are materialized on-the-fly as `ConstantOp`s. - LogicalResult visit(const slang::ast::ParameterSymbol &) { return success(); } - LogicalResult visit(const slang::ast::SpecparamSymbol &) { return success(); } - LogicalResult visit(const slang::ast::TypeParameterSymbol &) { - return success(); - } - // Handle functions and tasks. LogicalResult visit(const slang::ast::SubroutineSymbol &subroutine) { return context.convertFunction(subroutine); @@ -177,15 +220,9 @@ static moore::NetKind convertNetKind(slang::ast::NetType::NetKind kind) { namespace { struct ModuleVisitor : public BaseVisitor { + using BaseVisitor::BaseVisitor; using BaseVisitor::visit; - Context &context; - Location loc; - OpBuilder &builder; - - ModuleVisitor(Context &context, Location loc) - : context(context), loc(loc), builder(context.builder) {} - // Skip ports which are already handled by the module itself. LogicalResult visit(const slang::ast::PortSymbol &) { return success(); } LogicalResult visit(const slang::ast::MultiPortSymbol &) { return success(); } @@ -453,45 +490,6 @@ struct ModuleVisitor : public BaseVisitor { return success(); } - // Handle parameters. - LogicalResult visit(const slang::ast::ParameterSymbol ¶mNode) { - auto type = cast(context.convertType(paramNode.getType())); - if (!type) - return failure(); - - auto valueInt = paramNode.getValue().integer().as().value(); - Value value = builder.create(loc, type, valueInt); - - auto namedConstantOp = builder.create( - loc, type, builder.getStringAttr(paramNode.name), - paramNode.isLocalParam() - ? moore::NamedConstAttr::get(context.getContext(), - moore::NamedConst::LocalParameter) - : moore::NamedConstAttr::get(context.getContext(), - moore::NamedConst::Parameter), - value); - context.valueSymbols.insert(¶mNode, namedConstantOp); - return success(); - } - - // Handle specparam. - LogicalResult visit(const slang::ast::SpecparamSymbol &spNode) { - auto type = cast(context.convertType(spNode.getType())); - if (!type) - return failure(); - - auto valueInt = spNode.getValue().integer().as().value(); - Value value = builder.create(loc, type, valueInt); - - auto namedConstantOp = builder.create( - loc, type, builder.getStringAttr(spNode.name), - moore::NamedConstAttr::get(context.getContext(), - moore::NamedConst::SpecParameter), - value); - context.valueSymbols.insert(&spNode, namedConstantOp); - return success(); - } - // Handle generate block. LogicalResult visit(const slang::ast::GenerateBlockSymbol &genNode) { if (!genNode.isUninstantiated) { @@ -794,17 +792,6 @@ Context::convertPackage(const slang::ast::PackageSymbol &package) { return success(); } -static void guessNamespacePrefix(const slang::ast::Symbol &symbol, - SmallString<64> &prefix) { - if (symbol.kind == slang::ast::SymbolKind::Root) - return; - guessNamespacePrefix(symbol.getParentScope()->asSymbol(), prefix); - if (!symbol.name.empty()) { - prefix += symbol.name; - prefix += "::"; - } -} - /// Convert a function and its arguments to a function declaration in the IR. /// This does not convert the function body. FunctionLowering * diff --git a/lib/Conversion/MooreToCore/MooreToCore.cpp b/lib/Conversion/MooreToCore/MooreToCore.cpp index 2a2a95f30d72..f6fa3472f2e7 100644 --- a/lib/Conversion/MooreToCore/MooreToCore.cpp +++ b/lib/Conversion/MooreToCore/MooreToCore.cpp @@ -515,35 +515,6 @@ struct ConstantOpConv : public OpConversionPattern { } }; -struct NamedConstantOpConv : public OpConversionPattern { - using OpConversionPattern::OpConversionPattern; - - LogicalResult - matchAndRewrite(NamedConstantOp op, OpAdaptor adaptor, - ConversionPatternRewriter &rewriter) const override { - - Type resultType = typeConverter->convertType(op.getResult().getType()); - SmallString<32> symStr; - switch (op.getKind()) { - case NamedConst::Parameter: - symStr = "parameter"; - break; - case NamedConst::LocalParameter: - symStr = "localparameter"; - break; - case NamedConst::SpecParameter: - symStr = "specparameter"; - break; - } - auto symAttr = - rewriter.getStringAttr(symStr + Twine("_") + adaptor.getName()); - rewriter.replaceOpWithNewOp(op, resultType, adaptor.getValue(), - op.getNameAttr(), - hw::InnerSymAttr::get(symAttr)); - return success(); - } -}; - struct ConcatOpConversion : public OpConversionPattern { using OpConversionPattern::OpConversionPattern; LogicalResult @@ -1375,7 +1346,7 @@ static void populateOpConversion(RewritePatternSet &patterns, // Patterns of miscellaneous operations. ConstantOpConv, ConcatOpConversion, ReplicateOpConversion, ExtractOpConversion, DynExtractOpConversion, DynExtractRefOpConversion, - ConversionOpConversion, ReadOpConversion, NamedConstantOpConv, + ConversionOpConversion, ReadOpConversion, StructExtractOpConversion, StructExtractRefOpConversion, ExtractRefOpConversion, StructCreateOpConversion, ConditionalOpConversion, YieldOpConversion, OutputOpConversion, diff --git a/lib/Dialect/Moore/MooreOps.cpp b/lib/Dialect/Moore/MooreOps.cpp index 609b2bf14c65..5deef56f322d 100644 --- a/lib/Dialect/Moore/MooreOps.cpp +++ b/lib/Dialect/Moore/MooreOps.cpp @@ -633,14 +633,6 @@ OpFoldResult ConstantOp::fold(FoldAdaptor adaptor) { return getValueAttr(); } -//===----------------------------------------------------------------------===// -// NamedConstantOp -//===----------------------------------------------------------------------===// - -void NamedConstantOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) { - setNameFn(getResult(), getName()); -} - //===----------------------------------------------------------------------===// // ConcatOp //===----------------------------------------------------------------------===// diff --git a/test/Conversion/ImportVerilog/basic.sv b/test/Conversion/ImportVerilog/basic.sv index 21a84b4f30d2..e82a536ab3e6 100644 --- a/test/Conversion/ImportVerilog/basic.sv +++ b/test/Conversion/ImportVerilog/basic.sv @@ -1,4 +1,4 @@ -// RUN: circt-translate --import-verilog %s | FileCheck %s +// RUN: circt-verilog --parse-only -g %s | FileCheck %s // RUN: circt-verilog --ir-moore %s // REQUIRES: slang @@ -132,30 +132,6 @@ module Basic; bit [0:0] b1; bit b2 = b1; - // CHECK: [[TMP:%.+]] = moore.constant 1 : l32 - // CHECK: %p1 = moore.named_constant parameter [[TMP]] : l32 - parameter p1 = 1; - - // CHECK: [[TMP:%.+]] = moore.constant 1 : l32 - // CHECK: %p2 = moore.named_constant parameter [[TMP]] : l32 - parameter p2 = p1; - - // CHECK: [[TMP:%.+]] = moore.constant 2 : l32 - // CHECK: %lp1 = moore.named_constant localparam [[TMP]] : l32 - localparam lp1 = 2; - - // CHECK: [[TMP:%.+]] = moore.constant 2 : l32 - // CHECK: %lp2 = moore.named_constant localparam [[TMP]] : l32 - localparam lp2 = lp1; - - // CHECK: [[TMP:%.+]] = moore.constant 3 : l32 - // CHECK: %sp1 = moore.named_constant specparam [[TMP]] : l32 - specparam sp1 = 3; - - // CHECK: [[TMP:%.+]] = moore.constant 3 : l32 - // CHECK: %sp2 = moore.named_constant specparam [[TMP]] : l32 - specparam sp2 = sp1; - // CHECK: moore.procedure initial { // CHECK: } initial; @@ -236,11 +212,62 @@ endmodule // CHECK-LABEL: func.func private @dummyB( // CHECK-LABEL: func.func private @dummyC( // CHECK-LABEL: func.func private @dummyD( +// CHECK-LABEL: func.func private @dummyE( +// CHECK-LABEL: func.func private @dummyF( function void dummyA(); endfunction function void dummyB(); endfunction function void dummyC(); endfunction function void dummyD(int a); endfunction function bit dummyE(bit a); return a; endfunction +function void dummyF(integer a); endfunction + +// CHECK-LABEL: moore.module @Parameters( +module Parameters; + // CHECK: [[TMP:%.+]] = moore.constant 1 : l32 + // CHECK: dbg.variable "p1", [[TMP]] : !moore.l32 + parameter p1 = 1; + + // CHECK: [[TMP:%.+]] = moore.constant 1 : l32 + // CHECK: dbg.variable "p2", [[TMP]] : !moore.l32 + parameter p2 = p1; + + // CHECK: [[TMP:%.+]] = moore.constant 2 : l32 + // CHECK: dbg.variable "lp1", [[TMP]] : !moore.l32 + localparam lp1 = 2; + + // CHECK: [[TMP:%.+]] = moore.constant 2 : l32 + // CHECK: dbg.variable "lp2", [[TMP]] : !moore.l32 + localparam lp2 = lp1; + + // CHECK: [[TMP:%.+]] = moore.constant 3 : l32 + // CHECK: dbg.variable "sp1", [[TMP]] : !moore.l32 + specparam sp1 = 3; + + // CHECK: [[TMP:%.+]] = moore.constant 3 : l32 + // CHECK: dbg.variable "sp2", [[TMP]] : !moore.l32 + specparam sp2 = sp1; + + initial begin + // CHECK: [[TMP:%.+]] = moore.constant 1 : l32 + // CHECK: func.call @dummyF([[TMP]]) + // CHECK: [[TMP:%.+]] = moore.constant 1 : l32 + // CHECK: func.call @dummyF([[TMP]]) + // CHECK: [[TMP:%.+]] = moore.constant 2 : l32 + // CHECK: func.call @dummyF([[TMP]]) + // CHECK: [[TMP:%.+]] = moore.constant 2 : l32 + // CHECK: func.call @dummyF([[TMP]]) + // CHECK: [[TMP:%.+]] = moore.constant 3 : l32 + // CHECK: func.call @dummyF([[TMP]]) + // CHECK: [[TMP:%.+]] = moore.constant 3 : l32 + // CHECK: func.call @dummyF([[TMP]]) + dummyF(p1); + dummyF(p2); + dummyF(lp1); + dummyF(lp2); + dummyF(sp1); + dummyF(sp2); + end +endmodule // CHECK-LABEL: func.func private @ConditionalStatements( // CHECK-SAME: %arg0: !moore.i1 @@ -1529,27 +1556,28 @@ endmodule // CHECK-LABEL: moore.module @GenerateConstructs() module GenerateConstructs; genvar i; - parameter p=2; + // CHECK: [[TMP:%.+]] = moore.constant 2 + // CHECK: dbg.variable "p", [[TMP]] + parameter p = 2; generate - // CHECK: [[TMP1:%.+]] = moore.constant 0 : l32 - // CHECK: %i = moore.named_constant localparam [[TMP1]] : l32 - // CHECK: [[TMP2:%.+]] = moore.conversion %i : !moore.l32 -> !moore.i32 - // CHECK: %g1 = moore.variable [[TMP2]] : - // CHECK: [[TMP3:%.+]] = moore.constant 1 : l32 - // CHECK: %i_0 = moore.named_constant localparam name "i" [[TMP3]] : l32 - // CHECK: [[TMP4:%.+]] = moore.conversion %i_0 : !moore.l32 -> !moore.i32 - // CHECK: %g1_1 = moore.variable name "g1" [[TMP4]] : - for(i=0; i<2; i=i+1) begin - int g1 = i; + // CHECK: [[TMP:%.+]] = moore.constant 0 + // CHECK: dbg.variable "i", [[TMP]] + // CHECK: [[TMP:%.+]] = moore.constant 0 + // CHECK: %g1 = moore.variable [[TMP]] + // CHECK: [[TMP:%.+]] = moore.constant 1 + // CHECK: dbg.variable "i", [[TMP]] + // CHECK: [[TMP:%.+]] = moore.constant 1 + // CHECK: moore.variable name "g1" [[TMP]] + for (i = 0; i < 2; i = i + 1) begin + integer g1 = i; end // CHECK: [[TMP:%.+]] = moore.constant 2 : i32 // CHECK: %g2 = moore.variable [[TMP]] : - if(p == 2) begin + if (p == 2) begin int g2 = 2; - end - else begin + end else begin int g2 = 3; end @@ -1558,10 +1586,10 @@ module GenerateConstructs; case (p) 2: begin int g3 = 2; - end + end default: begin int g3 = 3; - end + end endcase endgenerate endmodule @@ -1979,3 +2007,21 @@ module ImmediateAssertiWithActionBlock; // CHEK: } assert (x) a = 1; else a = 0; endmodule + +// CHECK: [[TMP:%.+]] = moore.constant 42 : i32 +// CHECK: dbg.variable "rootParam1", [[TMP]] : !moore.i32 +parameter int rootParam1 = 42; + +// CHECK: [[TMP:%.+]] = moore.constant 9001 : i32 +// CHECK: dbg.variable "rootParam2", [[TMP]] : !moore.i32 +localparam int rootParam2 = 9001; + +package ParamPackage; + // CHECK: [[TMP:%.+]] = moore.constant 42 : i32 + // CHECK: dbg.variable "ParamPackage::param1", [[TMP]] : !moore.i32 + parameter int param1 = 42; + + // CHECK: [[TMP:%.+]] = moore.constant 9001 : i32 + // CHECK: dbg.variable "ParamPackage::param2", [[TMP]] : !moore.i32 + localparam int param2 = 9001; +endpackage diff --git a/test/Conversion/MooreToCore/basic.mlir b/test/Conversion/MooreToCore/basic.mlir index 91a36aad9704..d5f303bb4dd2 100644 --- a/test/Conversion/MooreToCore/basic.mlir +++ b/test/Conversion/MooreToCore/basic.mlir @@ -362,25 +362,6 @@ moore.module private @SubModule_0(in %a : !moore.l1, in %b : !moore.l1, out c : moore.output %0 : !moore.l1 } -// CHECK-LABEL: hw.module @ParamTest() { -moore.module @ParamTest(){ - - // CHECK-NEXT: [[Pa:%.+]] = hw.constant 1 : i32 - // CHECK-NEXT: %p1 = hw.wire [[Pa]] sym @parameter_p1 : i32 - %0 = moore.constant 1 : l32 - %p1 = moore.named_constant parameter %0 : l32 - - // CHECK-NEXT: [[LPa:%.+]] = hw.constant 2 : i32 - // CHECK-NEXT: %lp1 = hw.wire [[LPa]] sym @localparameter_lp1 : i32 - %1 = moore.constant 2 : l32 - %lp1 = moore.named_constant localparam %1 : l32 - - // CHECK-NEXT: [[SPa:%.+]] = hw.constant 3 : i32 - // CHECK-NEXT: %sp1 = hw.wire [[SPa]] sym @specparameter_sp1 : i32 - %2 = moore.constant 3 : l32 - %sp1 = moore.named_constant specparam %2 : l32 -} - moore.module @Variable() { // CHECK: [[TMP0:%.+]] = hw.constant 0 : i32 // CHECK: %a = llhd.sig [[TMP0]] : i32