Skip to content

Commit

Permalink
Guard against sign and overflow errors in rvalue array expressions
Browse files Browse the repository at this point in the history
  • Loading branch information
daglem committed Aug 12, 2023
1 parent db4ba06 commit e06ab0f
Showing 1 changed file with 17 additions and 9 deletions.
26 changes: 17 additions & 9 deletions frontends/ast/simplify.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2358,6 +2358,10 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin
input_error("Unsupported expression on dynamic range select on signal `%s'!\n", str.c_str());
}

int shift_expr_width_hint = -1;
bool shift_expr_sign_hint = true;
shift_expr->detectSignWidth(shift_expr_width_hint, shift_expr_sign_hint);

bool use_case_method = false;

if (id2ast->attributes.count(ID::nordshift)) {
Expand Down Expand Up @@ -2417,12 +2421,9 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin
}

// Limit case conditions to possible index range.
int case_width_hint = -1;
bool case_sign_hint = true;
shift_expr->detectSignWidth(case_width_hint, case_sign_hint);
int max_bits = min(case_width_hint, 31 + case_sign_hint);
int max_offset = (1u << (max_bits - case_sign_hint)) - 1;
int min_offset = case_sign_hint ? -(1u << (max_bits - 1)) : 0;
int max_bits = min(shift_expr_width_hint, 31 + shift_expr_sign_hint);
int max_offset = (1u << (max_bits - shift_expr_sign_hint)) - 1;
int min_offset = shift_expr_sign_hint ? -(1u << (max_bits - 1)) : 0;

// New identifier to replace the current rvalue; used as lvalue in AST_COND assignments.
AstNode *wire = new AstNode(AST_WIRE, new AstNode(AST_RANGE, node_int(result_width - 1), node_int(0)));
Expand All @@ -2443,7 +2444,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin
int end_bit = std::min(start_bit + result_width, source_offset + source_width) - 1;
if (start_bit/div_stride < min_offset || start_bit/div_stride > max_offset)
continue;
AstNode *cond = new AstNode(AST_COND, mkconst_int(start_bit/div_stride, case_sign_hint, case_width_hint));
AstNode *cond = new AstNode(AST_COND, mkconst_int(start_bit/div_stride, shift_expr_sign_hint, shift_expr_width_hint));
AstNode *rvalue = clone();
rvalue->delete_children();
if (member_node)
Expand Down Expand Up @@ -2474,7 +2475,14 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin
if (member_node)
rvalue->attributes[ID::wiretype] = member_node->clone();

if (source_offset != 0) {
if (!shift_expr_sign_hint && (source_offset || id2ast->range_swapped)) {
// convert to signed while preserving the sign and value
shift_expr = new AstNode(AST_TO_SIGNED,
new AstNode(AST_CAST_SIZE,
node_int(shift_expr_width_hint + 1),
shift_expr));
}
if (source_offset) {
// offset the shift amount by the lower bound of the dimension
shift_expr = new AstNode(AST_SUB, shift_expr, node_int(source_offset));
}
Expand All @@ -2485,7 +2493,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin

// Shift rvalue to the right so that the bit slice starts at bit 0.
newNode = new AstNode(AST_CAST_SIZE,
mkconst_int(result_width, true),
node_int(result_width),
new AstNode(AST_SHIFTX, rvalue, shift_expr));
}

Expand Down

0 comments on commit e06ab0f

Please sign in to comment.