From e2ab4646567a32cdc8ae47cd1f7db8abe0e381dd Mon Sep 17 00:00:00 2001 From: Ethan Sifferman Date: Thu, 2 Jul 2026 16:20:20 -0700 Subject: [PATCH] Fix unequal-length string comparison --- elab_expr.cc | 11 ++++++++ ivtest/ivltests/param_string_compare.v | 36 ++++++++++++++++++++++++++ ivtest/regress-sv.list | 1 + 3 files changed, 48 insertions(+) create mode 100644 ivtest/ivltests/param_string_compare.v diff --git a/elab_expr.cc b/elab_expr.cc index 6c9d7b17a..291db1a08 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -916,6 +916,17 @@ NetExpr* PEBComp::elaborate_expr(Design*des, NetScope*scope, eval_expr(lp, l_width_); eval_expr(rp, r_width_); + // test_width() does not equalize operand widths for string + // operands, but constant evaluation expects equal widths. + if (left_->expr_type() == IVL_VT_STRING || + right_->expr_type() == IVL_VT_STRING) { + if (dynamic_cast(lp) && dynamic_cast(rp)) { + unsigned use_wid = max(lp->expr_width(), rp->expr_width()); + lp = pad_to_width(lp, use_wid, false, *this); + rp = pad_to_width(rp, use_wid, false, *this); + } + } + // Handle some operand-specific special cases... switch (op_) { case 'E': /* === */ diff --git a/ivtest/ivltests/param_string_compare.v b/ivtest/ivltests/param_string_compare.v new file mode 100644 index 000000000..61e1f81e6 --- /dev/null +++ b/ivtest/ivltests/param_string_compare.v @@ -0,0 +1,36 @@ +// Regression test: comparing a `string` parameter to a string constant of +// a different length must constant-fold cleanly instead of tripping the +// "lv.len() == rv.len()" assertion in the NetEBComp evaluation functions. +// Covers ==, !=, ===, !==, ==? and !=? with the string operand on either +// side and both shorter and longer than the other operand. + +module main #(parameter string Target = "A", + parameter string Long = "ABC"); + + integer errors = 0; + + // Equality / inequality, parameter shorter than the literal. + if (Target == "AA") initial begin errors += 1; $display("FAILED: Target == \"AA\""); end + if (Target != "A") initial begin errors += 1; $display("FAILED: Target != \"A\""); end + + // Literal on the left. + if ("AA" == Target) initial begin errors += 1; $display("FAILED: \"AA\" == Target"); end + + // Parameter longer than the literal. + if (Long == "AB") initial begin errors += 1; $display("FAILED: Long == \"AB\""); end + if (Long != "ABC") initial begin errors += 1; $display("FAILED: Long != \"ABC\""); end + + // Two string parameters of different lengths. + if (Target == Long) initial begin errors += 1; $display("FAILED: Target == Long"); end + + // Case equality. + if (Target === "AA") initial begin errors += 1; $display("FAILED: Target === \"AA\""); end + if (Target !== "A") initial begin errors += 1; $display("FAILED: Target !== \"A\""); end + + // Wildcard equality. + if (Target ==? "AA") initial begin errors += 1; $display("FAILED: Target ==? \"AA\""); end + if (Target !=? "A") initial begin errors += 1; $display("FAILED: Target !=? \"A\""); end + + initial #1 if (errors == 0) $display("PASSED"); + +endmodule diff --git a/ivtest/regress-sv.list b/ivtest/regress-sv.list index dade32337..ee2dc7757 100644 --- a/ivtest/regress-sv.list +++ b/ivtest/regress-sv.list @@ -416,6 +416,7 @@ net_string_fail CE,-g2005-sv ivltests package_vec_part_select normal,-g2005-sv ivltests packeda normal,-g2009 ivltests packeda2 normal,-g2009 ivltests +param_string_compare normal,-g2009 ivltests parameter_in_generate2 CE,-g2005-sv ivltests parameter_no_default normal,-g2005-sv ivltests parameter_no_default_fail1 CE ivltests