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:
parent
b855b0368d
commit
14b2037ce4
2
PExpr.h
2
PExpr.h
|
|
@ -682,6 +682,8 @@ class PECallFunction : public PExpr {
|
|||
|
||||
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_access_func_(Design*des, NetScope*scope, ivl_nature_t) const;
|
||||
unsigned test_width_sfunc_(Design*des, NetScope*scope,
|
||||
|
|
|
|||
68
elab_expr.cc
68
elab_expr.cc
|
|
@ -1087,14 +1087,20 @@ unsigned PECallFunction::test_width_sfunc_(Design*des, NetScope*scope,
|
|||
if (expr == 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__;
|
||||
|
||||
// The result width is context dependent.
|
||||
if (expr_width_ > min)
|
||||
min = expr_width_;
|
||||
|
||||
if (debug_elaborate)
|
||||
cerr << get_fileline() << ": debug: test_width"
|
||||
<< " of $signed/$unsigned returns test_width"
|
||||
<< " of subexpression." << endl;
|
||||
return expr_width_;
|
||||
cerr << get_fileline() << ": debug: $signed/$unsigned"
|
||||
<< " argument width = " << expr_width_
|
||||
<< ", result width = " << min << "." << endl;
|
||||
|
||||
return min;
|
||||
}
|
||||
|
||||
// Run through the arguments of the system function and make
|
||||
|
|
@ -1208,6 +1214,34 @@ unsigned PECallFunction::test_width(Design*des, NetScope*scope,
|
|||
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
|
||||
* 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
|
||||
{
|
||||
|
||||
/* Catch the special case that the system function is the
|
||||
$signed function. This function is special, in that it does
|
||||
not lead to executable code but takes the single parameter
|
||||
and makes it into a signed expression. No bits are changed,
|
||||
it just changes the interpretation. */
|
||||
/* Catch the special case that the system function is the $signed
|
||||
function. Its argument will be evaluated as a self-determined
|
||||
expression. */
|
||||
if (strcmp(peek_tail_name(path_), "$signed") == 0) {
|
||||
if ((parms_.size() != 1) || (parms_[0] == 0)) {
|
||||
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];
|
||||
NetExpr*sub = expr->elaborate_expr(des, scope, -1, true);
|
||||
sub->cast_signed(true);
|
||||
return sub;
|
||||
NetExpr*sub = expr->elaborate_expr(des, scope, expr_width_, true);
|
||||
|
||||
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 ((parms_.size() != 1) || (parms_[0] == 0)) {
|
||||
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];
|
||||
NetExpr*sub = expr->elaborate_expr(des, scope, -1, true);
|
||||
sub->cast_signed(false);
|
||||
NetExpr*sub = expr->elaborate_expr(des, scope, expr_width_, true);
|
||||
|
||||
if (expr_wid > 0 && (unsigned)expr_wid > sub->expr_width())
|
||||
sub = pad_to_width(sub, expr_wid, *this);
|
||||
|
||||
return sub;
|
||||
return cast_to_width_(sub, expr_wid, false);
|
||||
}
|
||||
|
||||
/* Interpret the internal $sizeof system function to return
|
||||
|
|
|
|||
|
|
@ -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
|
||||
* 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;
|
||||
|
||||
bexpr = ivl_expr_oper2(expr);
|
||||
assert(bexpr);
|
||||
|
||||
/* This is a pad operation. */
|
||||
if (!bexpr) return 0;
|
||||
|
||||
/* This is a constant bit/part select. */
|
||||
if (number_is_immediate(bexpr, 64, 1)) {
|
||||
|
|
|
|||
Loading…
Reference in New Issue