tgt-vlog95: Use concatenation for unsigned expression contexts

The vlog95 backend currently emits `$unsigned()` when it needs to create a
self-determined unsigned expression context. `$unsigned()` is part of the
optional signed expression support in this backend and is only available when
the signed support flag is enabled.

Concatenation is part of the baseline Verilog-95 output and also creates a
self-determined unsigned expression context. Use `{expr}` for the unsigned case
and keep using `$signed()` when a signed context is needed.

Remove `-pallowsigned=1` from the existing vlog95 regression tests that now
pass without the optional signed support flag.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
This commit is contained in:
Lars-Peter Clausen 2024-01-15 10:17:23 -08:00
parent daadc38f18
commit e75b0d7968
3 changed files with 50 additions and 41 deletions

View File

@ -603,10 +603,10 @@ br_gh219 EF,-g2009,-pallowsigned=1 ivltests
# creates a CA for the part select, but has nothing to connect it to.
# It leaves the gate output unconnected.
rise_fall_decay2 CE ivltests
# The code generator is generating unnecessary calls to $unsigned.
# The code generator emits signed casts for this test.
array_packed_2d normal,-g2009,-pallowsigned=1 ivltests gold=array_packed_2d.gold
br_gh112c normal,-g2009,-pallowsigned=1 ivltests
br_gh112d normal,-g2009,-pallowsigned=1 ivltests
br_gh112c normal,-g2009 ivltests
br_gh112d normal,-g2009 ivltests
# This generates a very larg (65536 bit) constant, and the parser can't cope.
br_gh162 TE ivltests
@ -827,7 +827,7 @@ writemem-error normal ivltests gold=writemem-error-vlog95.gold
# For Verilog 95 signed is supported as an option (-pallowsigned=1).
array6 normal,-pallowsigned=1 ivltests
assign_op_oob normal,-g2009,-pallowsigned=1 ivltests
assign_op_oob normal,-g2009 ivltests
assign_op_type normal,-g2009,-pallowsigned=1 ivltests
bitp1 normal,-g2009,-pallowsigned=1 ivltests
bits normal,-g2009,-pallowsigned=1 ivltests
@ -867,8 +867,8 @@ br_gh1237 normal,-pallowsigned=1 ivltests
ca_mult normal,-pallowsigned=1 ivltests gold=ca_mult.gold
cast_int normal,-pallowsigned=1 ivltests
cfunc_assign_op_vec normal,-g2009,-pallowsigned=1 ivltests
constfunc4 normal,-pallowsigned=1 ivltests
constfunc6 normal,-pallowsigned=1 ivltests
constfunc4 normal ivltests
constfunc6 normal ivltests
constfunc7 normal,-pallowsigned=1 ivltests
constfunc13 normal,-pallowsigned=1 ivltests
constfunc14 normal,-pallowsigned=1 ivltests
@ -909,7 +909,7 @@ pr1793749 normal,-pallowsigned=1 ivltests gold=pr1793749.gold
pr1879226 normal,-pallowsigned=1 ivltests
pr1883052 normal,-pallowsigned=1 ivltests
pr1883052b normal,-pallowsigned=1 ivltests
pr1950282 normal,-pallowsigned=1 ivltests
pr1950282 normal ivltests
pr1958801 normal,-pallowsigned=1 ivltests
pr1993479 normal,-pallowsigned=1 ivltests gold=pr1993479.gold
pr2030767 normal,-pallowsigned=1 ivltests
@ -959,7 +959,7 @@ simple_byte normal,-g2009,-pallowsigned=1 ivltests
simple_int normal,-g2009,-pallowsigned=1 ivltests
simple_longint normal,-g2009,-pallowsigned=1 ivltests
simple_shortint normal,-g2009,-pallowsigned=1 ivltests
size_cast3 normal,-g2009,-pallowsigned=1 ivltests
size_cast3 normal,-g2009 ivltests
size_cast5 normal,-g2009,-pallowsigned=1 ivltests
struct_member_signed normal,-g2009,-pallowsigned=1 ivltests
struct_packed_array normal,-g2009,-pallowsigned=1 ivltests

View File

@ -26,7 +26,8 @@
ivl_parameter_t emitting_param = 0;
/*
* Data type used to signify if a $signed or $unsigned should be emitted.
* Data type used to signify whether to emit $signed() or wrap the
* expression in a concatenation for an unsigned self-determined context.
*/
typedef enum expr_sign_e {
NO_SIGN = 0,
@ -77,7 +78,7 @@ static expr_sign_t expr_get_binary_sign_type(ivl_expr_t expr)
break;
}
/* Check to see if a $signed() or $unsigned() is needed. */
/* Check to see if the expression sign needs to be forced. */
if (expr_sign && ! opr_sign) rtn = NEED_SIGNED;
if (! expr_sign && opr_sign) rtn = NEED_UNSIGNED;
@ -97,11 +98,11 @@ static expr_sign_t expr_get_select_sign_type(ivl_expr_t expr,
ivl_expr_t oper1 = ivl_expr_oper1(expr);
opr_sign = ivl_expr_signed(oper1);
/* If the expression being padded is not a signal then don't
* skip a soft $unsigned() (from the binary operator). */
* skip the soft unsigned context from the binary operator. */
if (ivl_expr_type(oper1) != IVL_EX_SIGNAL) can_skip_unsigned -= 1;
}
/* Check to see if a $signed() or $unsigned() is needed. */
/* Check to see if the expression sign needs to be forced. */
if (expr_sign && ! opr_sign) rtn = NEED_SIGNED;
if (! expr_sign && opr_sign && ! can_skip_unsigned) rtn = NEED_UNSIGNED;
@ -115,7 +116,7 @@ static expr_sign_t expr_get_signal_sign_type(ivl_expr_t expr,
int expr_sign = ivl_expr_signed(expr);
expr_sign_t rtn = NO_SIGN;
/* Check to see if a $signed() or $unsigned() is needed. */
/* Check to see if the expression sign needs to be forced. */
if (expr_sign && ! opr_sign) rtn = NEED_SIGNED;
if (! expr_sign && opr_sign && ! can_skip_unsigned) rtn = NEED_UNSIGNED;
@ -210,10 +211,10 @@ static unsigned expr_is_binary_self_det(ivl_expr_t expr)
}
/*
* Determine if a $signed() or $unsigned() system function is needed to get
* Determine if $signed() or a single-element concatenation is needed to get
* the expression sign information correct. can_skip_unsigned may be set for
* the binary/ternary operators if one of the operands will implicitly cast
* the expression to unsigned. See calc_can_skip_unsigned() for the details.
* the binary/ternary operators if one of the operands will implicitly make
* the expression unsigned. See calc_can_skip_unsigned() for the details.
*/
static expr_sign_t expr_get_sign_type(ivl_expr_t expr, unsigned wid,
unsigned can_skip_unsigned,
@ -399,8 +400,8 @@ static unsigned calc_can_skip_unsigned(ivl_expr_t oper1, ivl_expr_t oper2)
oper2_signed |= (ivl_expr_type(oper2) == IVL_EX_SELECT) &&
(! ivl_expr_oper2(oper2)) &&
(ivl_expr_signed(ivl_expr_oper1(oper2)));
/* If either operand is a hard unsigned skip adding an explicit
* $unsigned() since it will be added implicitly. */
/* If either operand is hard unsigned, the operator result is already
* unsigned so skip adding an explicit unsigned context. */
return ! oper1_signed || ! oper2_signed;
}
@ -1145,7 +1146,7 @@ void emit_expr(ivl_scope_t scope, ivl_expr_t expr, unsigned wid,
sign_type = expr_get_sign_type(expr, wid, can_skip_unsigned,
is_full_prec);
/* Check to see if a $signed() or $unsigned() needs to be emitted
/* Check to see if a $signed() or concatenation needs to be emitted
* before the expression. */
if (sign_type == NEED_SIGNED) {
fprintf(vlog_out, "$signed(");
@ -1161,14 +1162,8 @@ void emit_expr(ivl_scope_t scope, ivl_expr_t expr, unsigned wid,
is_full_prec = 0;
}
if (sign_type == NEED_UNSIGNED) {
fprintf(vlog_out, "$unsigned(");
if (! allow_signed) {
fprintf(stderr, "%s:%u: vlog95 error: $unsigned() is not "
"supported.\n",
ivl_expr_file(expr), ivl_expr_lineno(expr));
vlog_errors += 1;
}
/* A $unsigned() creates a self-determined context. */
fprintf(vlog_out, "{");
/* A `{x}` creates a self-determined context. */
wid = 0;
/* It also clears the full precision flag. */
is_full_prec = 0;
@ -1276,6 +1271,15 @@ void emit_expr(ivl_scope_t scope, ivl_expr_t expr, unsigned wid,
vlog_errors += 1;
break;
}
/* Close the $signed() or $unsigned() if need. */
if (sign_type != NO_SIGN) fprintf(vlog_out, ")");
/* Close the $signed() or concatenation if needed. */
switch (sign_type) {
case NEED_SIGNED:
fprintf(vlog_out, ")");
break;
case NEED_UNSIGNED:
fprintf(vlog_out, "}");
break;
default:
break;
}
}

View File

@ -22,7 +22,8 @@
# include "vlog95_priv.h"
/*
* Data type used to signify if a $signed or $unsigned should be emitted.
* Data type used to signify whether to emit $signed() or wrap the
* expression in a concatenation for an unsigned self-determined context.
*/
typedef enum lpm_sign_e {
NO_SIGN = 0,
@ -119,7 +120,7 @@ static lpm_sign_t lpm_get_sign_type(ivl_lpm_t lpm,
break;
}
/* Check to see if a $signed() or $unsigned() is needed. */
/* Check to see if the expression sign needs to be forced. */
if (lpm_sign && ! opr_sign) rtn = NEED_SIGNED;
if (! lpm_sign && opr_sign && ! can_skip_unsigned) rtn = NEED_UNSIGNED;
@ -1173,7 +1174,7 @@ static void emit_lpm_as_ca(ivl_scope_t scope, ivl_lpm_t lpm,
unsigned sign_extend)
{
lpm_sign_t sign_type;
/* Check to see if a $signed() or $unsigned() needs to be emitted
/* Check to see if a $signed() or concatenation needs to be emitted
* before the expression. */
sign_type = lpm_get_sign_type(lpm, 0);
if (sign_type == NEED_SIGNED) {
@ -1185,14 +1186,9 @@ static void emit_lpm_as_ca(ivl_scope_t scope, ivl_lpm_t lpm,
vlog_errors += 1;
}
}
/* A concatenation creates a self-determined unsigned context */
if (sign_type == NEED_UNSIGNED) {
fprintf(vlog_out, "$unsigned(");
if (! allow_signed) {
fprintf(stderr, "%s:%u: vlog95 error: $unsigned() is not "
"supported.\n",
ivl_lpm_file(lpm), ivl_lpm_lineno(lpm));
vlog_errors += 1;
}
fprintf(vlog_out, "{");
}
switch (ivl_lpm_type(lpm)) {
@ -1472,8 +1468,17 @@ static void emit_lpm_as_ca(ivl_scope_t scope, ivl_lpm_t lpm,
vlog_errors += 1;
}
/* Close the $signed() or $unsigned() if needed. */
if (sign_type != NO_SIGN) fprintf(vlog_out, ")");
/* Close the $signed() or concatenation if needed. */
switch (sign_type) {
case NEED_SIGNED:
fprintf(vlog_out, ")");
break;
case NEED_UNSIGNED:
fprintf(vlog_out, "}");
break;
default:
break;
}
}
static void emit_posedge_dff_prim(void)