Skip to content

Commit 6687ef8

Browse files
authored
[Moore][ImportVerilog] Replace $sformat/$swrite string dispatch with ksn (#10557)
Move `$sformat` handling from the fallback path in `visit(ExpressionStatement)` into `visitSystemCall`, replacing string comparisons with `ksn::KnownSystemName` dispatch already used for all other system tasks. This also adds the previously missing `$swrite [boh]` variants with corresponding tests in `basic.sv`. Signed-off-by: adouard <alexandre.douard@ens-lyon.fr>
1 parent 5ab5135 commit 6687ef8

2 files changed

Lines changed: 82 additions & 42 deletions

File tree

lib/Conversion/ImportVerilog/Statements.cpp

Lines changed: 58 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -222,47 +222,6 @@ struct StmtVisitor {
222222
if (handled == true)
223223
return success();
224224
}
225-
226-
// According to IEEE 1800-2023 Section 21.3.3 "Formatting data to a
227-
// string" the first argument of $sformat/$swrite is its output; the
228-
// other arguments work like a FormatString.
229-
// In Moore we only support writing to a location if it is a reference;
230-
// However, Section 21.3.3 explains that the output of $sformat/$swrite
231-
// is assigned as if it were cast from a string literal (Section 5.9),
232-
// so this implementation casts the string to the target value.
233-
if (!call->getSubroutineName().compare("$sformat") ||
234-
!call->getSubroutineName().compare("$swrite")) {
235-
236-
// Use the first argument as the output location
237-
auto *lhsExpr = call->arguments().front();
238-
// Format the second and all later arguments as a string
239-
auto fmtValue =
240-
context.convertFormatString(call->arguments().subspan(1), loc,
241-
moore::IntFormat::Decimal, false);
242-
if (failed(fmtValue))
243-
return failure();
244-
// Convert the FormatString to a StringType
245-
auto strValue = moore::FormatStringToStringOp::create(builder, loc,
246-
fmtValue.value());
247-
// The Slang AST produces a `AssignmentExpression` for the first
248-
// argument; the RHS of this expression is invalid though
249-
// (`EmptyArgument`), so we only use the LHS of the
250-
// `AssignmentExpression` and plug in the formatted string for the RHS.
251-
if (auto assignExpr =
252-
lhsExpr->as_if<slang::ast::AssignmentExpression>()) {
253-
auto lhs = context.convertLvalueExpression(assignExpr->left());
254-
if (!lhs)
255-
return failure();
256-
257-
auto convertedValue = context.materializeConversion(
258-
cast<moore::RefType>(lhs.getType()).getNestedType(), strValue,
259-
false, loc);
260-
moore::BlockingAssignOp::create(builder, loc, lhs, convertedValue);
261-
return success();
262-
} else {
263-
return failure();
264-
}
265-
}
266225
}
267226

268227
auto value = context.convertRvalueExpression(stmt.expr);
@@ -1006,11 +965,13 @@ struct StmtVisitor {
1006965
}
1007966

1008967
// Display and Write Tasks (`$display[boh]?` or `$write[boh]?` or
1009-
// `$fdisplay[boh]?` or `$fwrite[boh]?`)
968+
// `$fdisplay[boh]?` or `$fwrite[boh]?` or `$swrite[boh]` or `$sformat`)
1010969

1011970
using moore::IntFormat;
1012971
bool isDisplay = false;
1013972
bool isFDisplay = false;
973+
bool isSWrite = false;
974+
bool isSFormat = false;
1014975
bool appendNewline = false;
1015976
IntFormat defaultFormat = IntFormat::Decimal;
1016977
switch (nameId) {
@@ -1082,6 +1043,24 @@ struct StmtVisitor {
10821043
isFDisplay = true;
10831044
defaultFormat = IntFormat::HexLower;
10841045
break;
1046+
case ksn::SFormat:
1047+
isSFormat = true;
1048+
break;
1049+
case ksn::SWrite:
1050+
isSWrite = true;
1051+
break;
1052+
case ksn::SWriteB:
1053+
isSWrite = true;
1054+
defaultFormat = IntFormat::Binary;
1055+
break;
1056+
case ksn::SWriteO:
1057+
isSWrite = true;
1058+
defaultFormat = IntFormat::Octal;
1059+
break;
1060+
case ksn::SWriteH:
1061+
isSWrite = true;
1062+
defaultFormat = IntFormat::HexLower;
1063+
break;
10851064
default:
10861065
break;
10871066
}
@@ -1116,6 +1095,43 @@ struct StmtVisitor {
11161095
return true;
11171096
}
11181097

1098+
// According to IEEE 1800-2023 Section 21.3.3 "Formatting data to a
1099+
// string" the first argument of $sformat/$swrite is its output; the
1100+
// other arguments work like a FormatString.
1101+
// In Moore we only support writing to a location if it is a reference;
1102+
// However, Section 21.3.3 explains that the output of $sformat/$swrite
1103+
// is assigned as if it were cast from a string literal (Section 5.9),
1104+
// so this implementation casts the string to the target value.
1105+
if (isSWrite || isSFormat) {
1106+
if (isSFormat && args.size() < 2)
1107+
return emitError(loc) << "$sformat requires at least 2 arguments";
1108+
if (isSWrite && args.size() < 1)
1109+
return emitError(loc) << "$swrite requires at least 1 argument";
1110+
1111+
auto fmtValue =
1112+
context.convertFormatString(args.subspan(1), loc, defaultFormat,
1113+
/*appendNewline=*/false);
1114+
if (failed(fmtValue))
1115+
return failure();
1116+
if (*fmtValue == Value{})
1117+
return true;
1118+
auto strValue =
1119+
moore::FormatStringToStringOp::create(builder, loc, *fmtValue);
1120+
auto *lhsExpr = args[0];
1121+
if (auto *assignExpr =
1122+
lhsExpr->as_if<slang::ast::AssignmentExpression>()) {
1123+
auto lhs = context.convertLvalueExpression(assignExpr->left());
1124+
if (!lhs)
1125+
return failure();
1126+
auto convertedValue = context.materializeConversion(
1127+
cast<moore::RefType>(lhs.getType()).getNestedType(), strValue,
1128+
false, loc);
1129+
moore::BlockingAssignOp::create(builder, loc, lhs, convertedValue);
1130+
return true;
1131+
}
1132+
return failure();
1133+
}
1134+
11191135
// Severity Tasks
11201136
using moore::Severity;
11211137
std::optional<Severity> severity;

test/Conversion/ImportVerilog/basic.sv

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3610,6 +3610,10 @@ function automatic void Swrite(string testStr, string otherString, ref string ou
36103610
// CHECK: [[LV:%.+]] = moore.variable : <l64>
36113611
logic [63:0] logicVector;
36123612

3613+
// $swrite with a single arg
3614+
// CHECK-NOT: moore.fstring_to_string
3615+
$swrite(outputString);
3616+
36133617
// $swrite to a string output
36143618
// CHECK: [[FMTSTR1:%.+]] = moore.fmt.string [[STR1]]
36153619
// CHECK-NEXT: [[SPC:%.+]] = moore.fmt.literal " "
@@ -3631,6 +3635,26 @@ function automatic void Swrite(string testStr, string otherString, ref string ou
36313635
$swrite(logicVector, "%s %s", testStr, otherString);
36323636
endfunction
36333637

3638+
// CHECK-LABEL: func.func private @SwriteVariants(
3639+
// CHECK-SAME: [[X:%[^,]+]]: !moore.i32
3640+
// CHECK-SAME: [[OUT:%[^,]+]]: !moore.ref<string>
3641+
function automatic void SwriteVariants(int x, ref string outputString);
3642+
// CHECK: [[FMT1:%.+]] = moore.fmt.int binary [[X]], align right, pad zero : i32
3643+
// CHECK-NEXT: [[STR1:%.+]] = moore.fstring_to_string [[FMT1]]
3644+
// CHECK-NEXT: moore.blocking_assign [[OUT]], [[STR1]] : string
3645+
$swriteb(outputString, x);
3646+
3647+
// CHECK: [[FMT2:%.+]] = moore.fmt.int octal [[X]], align right, pad zero : i32
3648+
// CHECK-NEXT: [[STR2:%.+]] = moore.fstring_to_string [[FMT2]]
3649+
// CHECK-NEXT: moore.blocking_assign [[OUT]], [[STR2]] : string
3650+
$swriteo(outputString, x);
3651+
3652+
// CHECK: [[FMT3:%.+]] = moore.fmt.int hex_lower [[X]], align right, pad zero : i32
3653+
// CHECK-NEXT: [[STR3:%.+]] = moore.fstring_to_string [[FMT3]]
3654+
// CHECK-NEXT: moore.blocking_assign [[OUT]], [[STR3]] : string
3655+
$swriteh(outputString, x);
3656+
endfunction
3657+
36343658
// CHECK-LABEL: moore.module @ContinuousAssignment(
36353659
module ContinuousAssignment;
36363660
// CHECK-NEXT: [[A:%.+]] = moore.variable

0 commit comments

Comments
 (0)