Fix for pr2922063.

When handling the $signed/$unsigned system functions, the compiler
was applying the new signed/unsigned property to the NetExpr object
representing the input argument. This caused the input argument to
be evaluated incorrectly. This patch fixes this by applying the new
property to the NetExpr object created to pad the result to the
required size.

In testing this fix, it was also discovered that the width of the
input argument expression was not being calculated correctly. This
patch also fixes this issue.
This commit is contained in:
Martin Whitaker 2010-01-17 14:20:18 +00:00 committed by Stephen Williams
parent b855b0368d
commit 14b2037ce4
3 changed files with 54 additions and 22 deletions

View File

@ -682,6 +682,8 @@ class PECallFunction : public PExpr {
bool check_call_matches_definition_(Design*des, NetScope*dscope) const; bool check_call_matches_definition_(Design*des, NetScope*dscope) const;
NetExpr* cast_to_width_(NetExpr*expr, int wid, bool signed_flag) const;
NetExpr* elaborate_sfunc_(Design*des, NetScope*scope, int expr_wid) const; NetExpr* elaborate_sfunc_(Design*des, NetScope*scope, int expr_wid) const;
NetExpr* elaborate_access_func_(Design*des, NetScope*scope, ivl_nature_t) const; NetExpr* elaborate_access_func_(Design*des, NetScope*scope, ivl_nature_t) const;
unsigned test_width_sfunc_(Design*des, NetScope*scope, unsigned test_width_sfunc_(Design*des, NetScope*scope,

View File

@ -1087,14 +1087,20 @@ unsigned PECallFunction::test_width_sfunc_(Design*des, NetScope*scope,
if (expr == 0) if (expr == 0)
return 0; return 0;
expr_width_ = expr->test_width(des, scope, min, lval, expr_type__, unsized_flag); // The argument width is self-determined.
expr_width_ = expr->test_width(des, scope, 0, 0, expr_type__, unsized_flag);
expr_type_ = expr_type__; expr_type_ = expr_type__;
// The result width is context dependent.
if (expr_width_ > min)
min = expr_width_;
if (debug_elaborate) if (debug_elaborate)
cerr << get_fileline() << ": debug: test_width" cerr << get_fileline() << ": debug: $signed/$unsigned"
<< " of $signed/$unsigned returns test_width" << " argument width = " << expr_width_
<< " of subexpression." << endl; << ", result width = " << min << "." << endl;
return expr_width_;
return min;
} }
// Run through the arguments of the system function and make // Run through the arguments of the system function and make
@ -1208,6 +1214,34 @@ unsigned PECallFunction::test_width(Design*des, NetScope*scope,
return 0; return 0;
} }
NetExpr*PECallFunction::cast_to_width_(NetExpr*expr, int wid, bool signed_flag) const
{
/* If the expression is a const, then replace it with a new
const. This is a more efficient result. */
if (NetEConst*tmp = dynamic_cast<NetEConst*>(expr)) {
tmp->cast_signed(signed_flag);
if (wid > (int)(tmp->expr_width())) {
verinum oval = pad_to_width(tmp->value(), wid);
tmp = new NetEConst(oval);
tmp->set_line(*this);
delete expr;
}
return tmp;
}
if (wid < 0)
wid = expr->expr_width();
if (debug_elaborate)
cerr << get_fileline() << ": debug: cast to " << wid
<< " bits" << endl;
NetESelect*tmp = new NetESelect(expr, 0, wid);
tmp->set_line(*this);
tmp->cast_signed(signed_flag);
return tmp;
}
/* /*
* Given a call to a system function, generate the proper expression * Given a call to a system function, generate the proper expression
* nodes to represent the call in the netlist. Since we don't support * nodes to represent the call in the netlist. Since we don't support
@ -1217,11 +1251,9 @@ unsigned PECallFunction::test_width(Design*des, NetScope*scope,
NetExpr* PECallFunction::elaborate_sfunc_(Design*des, NetScope*scope, int expr_wid) const NetExpr* PECallFunction::elaborate_sfunc_(Design*des, NetScope*scope, int expr_wid) const
{ {
/* Catch the special case that the system function is the /* Catch the special case that the system function is the $signed
$signed function. This function is special, in that it does function. Its argument will be evaluated as a self-determined
not lead to executable code but takes the single parameter expression. */
and makes it into a signed expression. No bits are changed,
it just changes the interpretation. */
if (strcmp(peek_tail_name(path_), "$signed") == 0) { if (strcmp(peek_tail_name(path_), "$signed") == 0) {
if ((parms_.size() != 1) || (parms_[0] == 0)) { if ((parms_.size() != 1) || (parms_[0] == 0)) {
cerr << get_fileline() << ": error: The $signed() function " cerr << get_fileline() << ": error: The $signed() function "
@ -1231,11 +1263,11 @@ NetExpr* PECallFunction::elaborate_sfunc_(Design*des, NetScope*scope, int expr_w
} }
PExpr*expr = parms_[0]; PExpr*expr = parms_[0];
NetExpr*sub = expr->elaborate_expr(des, scope, -1, true); NetExpr*sub = expr->elaborate_expr(des, scope, expr_width_, true);
sub->cast_signed(true);
return sub; return cast_to_width_(sub, expr_wid, true);
} }
/* add $unsigned to match $signed */ /* As above, for the $unsigned function. */
if (strcmp(peek_tail_name(path_), "$unsigned") == 0) { if (strcmp(peek_tail_name(path_), "$unsigned") == 0) {
if ((parms_.size() != 1) || (parms_[0] == 0)) { if ((parms_.size() != 1) || (parms_[0] == 0)) {
cerr << get_fileline() << ": error: The $unsigned() function " cerr << get_fileline() << ": error: The $unsigned() function "
@ -1245,13 +1277,9 @@ NetExpr* PECallFunction::elaborate_sfunc_(Design*des, NetScope*scope, int expr_w
} }
PExpr*expr = parms_[0]; PExpr*expr = parms_[0];
NetExpr*sub = expr->elaborate_expr(des, scope, -1, true); NetExpr*sub = expr->elaborate_expr(des, scope, expr_width_, true);
sub->cast_signed(false);
if (expr_wid > 0 && (unsigned)expr_wid > sub->expr_width()) return cast_to_width_(sub, expr_wid, false);
sub = pad_to_width(sub, expr_wid, *this);
return sub;
} }
/* Interpret the internal $sizeof system function to return /* Interpret the internal $sizeof system function to return

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2003-2009 Stephen Williams (steve@icarus.com) * Copyright (c) 2003-2010 Stephen Williams (steve@icarus.com)
* *
* This source code is free software; you can redistribute it * This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU * and/or modify it in source code form under the terms of the GNU
@ -184,7 +184,9 @@ static int get_vpi_taskfunc_signal_arg(struct args_info *result,
if (ivl_expr_oper1(vexpr)) return 0; if (ivl_expr_oper1(vexpr)) return 0;
bexpr = ivl_expr_oper2(expr); bexpr = ivl_expr_oper2(expr);
assert(bexpr);
/* This is a pad operation. */
if (!bexpr) return 0;
/* This is a constant bit/part select. */ /* This is a constant bit/part select. */
if (number_is_immediate(bexpr, 64, 1)) { if (number_is_immediate(bexpr, 64, 1)) {