From e06ab0f993c80341df1663a64980b1194bc79ceb Mon Sep 17 00:00:00 2001 From: Dag Lem Date: Sat, 12 Aug 2023 10:54:15 +0200 Subject: [PATCH] Guard against sign and overflow errors in rvalue array expressions --- frontends/ast/simplify.cc | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index bc0d1975b88..6a1022615a7 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -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)) { @@ -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))); @@ -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) @@ -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)); } @@ -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)); }