diff --git a/lib/Conversion/ImportVerilog/Statements.cpp b/lib/Conversion/ImportVerilog/Statements.cpp index 06b01251b933..0c0a7ad9e969 100644 --- a/lib/Conversion/ImportVerilog/Statements.cpp +++ b/lib/Conversion/ImportVerilog/Statements.cpp @@ -222,47 +222,6 @@ struct StmtVisitor { if (handled == true) return success(); } - - // According to IEEE 1800-2023 Section 21.3.3 "Formatting data to a - // string" the first argument of $sformat/$swrite is its output; the - // other arguments work like a FormatString. - // In Moore we only support writing to a location if it is a reference; - // However, Section 21.3.3 explains that the output of $sformat/$swrite - // is assigned as if it were cast from a string literal (Section 5.9), - // so this implementation casts the string to the target value. - if (!call->getSubroutineName().compare("$sformat") || - !call->getSubroutineName().compare("$swrite")) { - - // Use the first argument as the output location - auto *lhsExpr = call->arguments().front(); - // Format the second and all later arguments as a string - auto fmtValue = - context.convertFormatString(call->arguments().subspan(1), loc, - moore::IntFormat::Decimal, false); - if (failed(fmtValue)) - return failure(); - // Convert the FormatString to a StringType - auto strValue = moore::FormatStringToStringOp::create(builder, loc, - fmtValue.value()); - // The Slang AST produces a `AssignmentExpression` for the first - // argument; the RHS of this expression is invalid though - // (`EmptyArgument`), so we only use the LHS of the - // `AssignmentExpression` and plug in the formatted string for the RHS. - if (auto assignExpr = - lhsExpr->as_if()) { - auto lhs = context.convertLvalueExpression(assignExpr->left()); - if (!lhs) - return failure(); - - auto convertedValue = context.materializeConversion( - cast(lhs.getType()).getNestedType(), strValue, - false, loc); - moore::BlockingAssignOp::create(builder, loc, lhs, convertedValue); - return success(); - } else { - return failure(); - } - } } auto value = context.convertRvalueExpression(stmt.expr); @@ -1006,11 +965,12 @@ struct StmtVisitor { } // Display and Write Tasks (`$display[boh]?` or `$write[boh]?` or - // `$fdisplay[boh]?` or `$fwrite[boh]?`) + // `$fdisplay[boh]?` or `$fwrite[boh]?` or `$swrite[boh]` or `$sformat`) using moore::IntFormat; bool isDisplay = false; bool isFDisplay = false; + bool isSWrite = false; bool appendNewline = false; IntFormat defaultFormat = IntFormat::Decimal; switch (nameId) { @@ -1082,6 +1042,22 @@ struct StmtVisitor { isFDisplay = true; defaultFormat = IntFormat::HexLower; break; + case ksn::SWrite: + case ksn::SFormat: + isSWrite = true; + break; + case ksn::SWriteB: + isSWrite = true; + defaultFormat = IntFormat::Binary; + break; + case ksn::SWriteO: + isSWrite = true; + defaultFormat = IntFormat::Octal; + break; + case ksn::SWriteH: + isSWrite = true; + defaultFormat = IntFormat::HexLower; + break; default: break; } @@ -1116,6 +1092,36 @@ struct StmtVisitor { return true; } + // According to IEEE 1800-2023 Section 21.3.3 "Formatting data to a + // string" the first argument of $sformat/$swrite is its output; the + // other arguments work like a FormatString. + // In Moore we only support writing to a location if it is a reference; + // However, Section 21.3.3 explains that the output of $sformat/$swrite + // is assigned as if it were cast from a string literal (Section 5.9), + // so this implementation casts the string to the target value. + if (isSWrite) { + auto fmtValue = + context.convertFormatString(args.subspan(1), loc, defaultFormat, + /*appendNewline=*/false); + if (failed(fmtValue)) + return failure(); + auto strValue = + moore::FormatStringToStringOp::create(builder, loc, *fmtValue); + auto *lhsExpr = args[0]; + if (auto *assignExpr = + lhsExpr->as_if()) { + auto lhs = context.convertLvalueExpression(assignExpr->left()); + if (!lhs) + return failure(); + auto convertedValue = context.materializeConversion( + cast(lhs.getType()).getNestedType(), strValue, + false, loc); + moore::BlockingAssignOp::create(builder, loc, lhs, convertedValue); + return true; + } + return failure(); + } + // Severity Tasks using moore::Severity; std::optional severity; diff --git a/test/Conversion/ImportVerilog/basic.sv b/test/Conversion/ImportVerilog/basic.sv index f3babc585f7f..a2568c6a94f5 100644 --- a/test/Conversion/ImportVerilog/basic.sv +++ b/test/Conversion/ImportVerilog/basic.sv @@ -3632,6 +3632,26 @@ function automatic void Swrite(string testStr, string otherString, ref string ou $swrite(logicVector, "%s %s", testStr, otherString); endfunction +// CHECK-LABEL: func.func private @SwriteVariants( +// CHECK-SAME: [[X:%[^,]+]]: !moore.i32 +// CHECK-SAME: [[OUT:%[^,]+]]: !moore.ref +function automatic void SwriteVariants(int x, ref string outputString); + // CHECK: [[FMT1:%.+]] = moore.fmt.int binary [[X]], align right, pad zero : i32 + // CHECK-NEXT: [[STR1:%.+]] = moore.fstring_to_string [[FMT1]] + // CHECK-NEXT: moore.blocking_assign [[OUT]], [[STR1]] : string + $swriteb(outputString, x); + + // CHECK: [[FMT2:%.+]] = moore.fmt.int octal [[X]], align right, pad zero : i32 + // CHECK-NEXT: [[STR2:%.+]] = moore.fstring_to_string [[FMT2]] + // CHECK-NEXT: moore.blocking_assign [[OUT]], [[STR2]] : string + $swriteo(outputString, x); + + // CHECK: [[FMT3:%.+]] = moore.fmt.int hex_lower [[X]], align right, pad zero : i32 + // CHECK-NEXT: [[STR3:%.+]] = moore.fstring_to_string [[FMT3]] + // CHECK-NEXT: moore.blocking_assign [[OUT]], [[STR3]] : string + $swriteh(outputString, x); +endfunction + // CHECK-LABEL: moore.module @ContinuousAssignment( module ContinuousAssignment; // CHECK-NEXT: [[A:%.+]] = moore.variable