From bd8183051c1f24b612c2cf46929069aa3f928c44 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Fri, 29 Mar 2024 15:22:29 +0000 Subject: [PATCH] Refactor calculation of aggregate bounds. Fixes #837 --- NEWS.md | 2 + src/bounds.c | 20 +++-- src/common.c | 155 +++++++++++++++++++++++++++++++++ src/common.h | 3 + src/lower.c | 130 +++++---------------------- src/names.c | 112 +++++++++++------------- src/rt/standard.c | 2 - test/bounds/issue54.vhd | 4 +- test/parse/aggregate.vhd | 14 +++ test/regress/array19.vhd | 31 +++++++ test/regress/bounds26.vhd | 3 +- test/regress/bounds42.vhd | 12 +-- test/regress/gold/bounds24.txt | 2 +- test/regress/gold/bounds42.txt | 1 + test/regress/issue873.vhd | 54 ++++++++++++ test/regress/testlist.txt | 2 + test/test_bounds.c | 11 +-- test/test_parse.c | 55 ++++++++++++ 18 files changed, 418 insertions(+), 195 deletions(-) create mode 100644 test/parse/aggregate.vhd create mode 100644 test/regress/array19.vhd create mode 100644 test/regress/issue873.vhd diff --git a/NEWS.md b/NEWS.md index d8fe8edb..cf5e1749 100644 --- a/NEWS.md +++ b/NEWS.md @@ -23,6 +23,8 @@ - Resolved several other minor issues (#654, #854, #855, #859, #863). - The default standard version was changed to VHDL-2008. - The `--vhpi-trace` option now implies `--vhpi-debug`. +- The bounds of array aggregates are now calculated correctly in several + corner cases (#873). ## Version 1.11.3 - 2024-02-04 - Fixed incorrect effective value when a signal has multiple sources due diff --git a/src/bounds.c b/src/bounds.c index 79997b1a..ca4ad321 100644 --- a/src/bounds.c +++ b/src/bounds.c @@ -603,17 +603,23 @@ static void bounds_check_aggregate(tree_t t) if (rkind == RANGE_TO || rkind == RANGE_DOWNTO) { tree_t left = tree_left(r), right = tree_right(r); - if (!bounds_check_index(left, index_type, rkind, - "aggregate choice", low, high)) - known_elem_count = false; - if (!bounds_check_index(right, index_type, rkind, - "aggregate choice", low, high)) - known_elem_count = false; - int64_t ileft, iright; if (folded_int(left, &ileft) && folded_int(right, &iright)) { ilow = (rkind == RANGE_TO ? ileft : iright); ihigh = (rkind == RANGE_TO ? iright : ileft); + + // Cannot check either index unless both are known + // since the range may be null + if (ilow <= ihigh) { + if (!bounds_check_index(left, index_type, rkind, + "aggregate choice", low, high)) + known_elem_count = false; + if (!bounds_check_index(right, index_type, rkind, + "aggregate choice", low, high)) + known_elem_count = false; + } + else + known_elem_count = false; } else known_elem_count = false; diff --git a/src/common.c b/src/common.c index ec2c0ac9..1dd324f1 100644 --- a/src/common.c +++ b/src/common.c @@ -225,6 +225,20 @@ tree_t get_int_lit(tree_t t, type_t type, int64_t i) return f; } +tree_t get_discrete_lit(tree_t t, type_t type, int64_t i) +{ + if (type_is_enum(type)) { + type_t base = type_base_recur(type); + const int maxlit = type_enum_literals(base); + if (i >= maxlit) + return NULL; + else + return get_enum_lit(t, type, i); + } + else + return get_int_lit(t, type, i); +} + tree_t get_real_lit(tree_t t, type_t type, double r) { tree_t f = tree_new(T_LITERAL); @@ -2544,3 +2558,144 @@ void instance_name_to_path(text_buf_t *tb, const char *str) tb_append(tb, *p); } } + +bool calculate_aggregate_bounds(tree_t expr, range_kind_t *kind, + int64_t *left, int64_t *right) +{ + // Calculate the direction and bounds of an array aggregate using the + // rules in LRM 93 7.3.2.2 + + type_t type = tree_type(expr); + type_t index_type = index_type_of(type, 0); + tree_t index_r = range_of(index_type, 0), base_r = index_r; + + int64_t low, high; + if (!folded_bounds(index_r, &low, &high)) + return false; + + int64_t clow = INT64_MAX, chigh = INT64_MIN; // Actual bounds computed below + + range_kind_t dir; + if (type_is_unconstrained(type)) + dir = tree_subkind(index_r); + else { + base_r = range_of(type, 0); + dir = tree_subkind(base_r); + } + + const int nassocs = tree_assocs(expr); + + if (standard() >= STD_08) { + // VHDL-2008 range association determines index direction for + // unconstrained aggregate when the expression type matches the + // array type + for (int i = 0; i < nassocs; i++) { + tree_t a = tree_assoc(expr, i); + if (tree_subkind(a) == A_SLICE) + dir = tree_subkind(tree_range(a, 0)); + } + } + + if (dir != RANGE_TO && dir != RANGE_DOWNTO) + return false; + + int64_t pos = 0; + for (int i = 0; i < nassocs; i++) { + tree_t a = tree_assoc(expr, i); + int64_t ilow = 0, ihigh = 0; + const assoc_kind_t akind = tree_subkind(a); + + switch (akind) { + case A_NAMED: + { + tree_t name = tree_name(a); + if (folded_int(name, &ilow)) + ihigh = ilow; + else + return false; + } + break; + + case A_RANGE: + case A_SLICE: + { + tree_t r = tree_range(a, 0); + const range_kind_t rkind = tree_subkind(r); + if (rkind == RANGE_TO || rkind == RANGE_DOWNTO) { + tree_t left = tree_left(r), right = tree_right(r); + + int64_t ileft, iright; + if (folded_int(left, &ileft) && folded_int(right, &iright)) { + ilow = (rkind == RANGE_TO ? ileft : iright); + ihigh = (rkind == RANGE_TO ? iright : ileft); + } + else + return false; + } + else + return false; + } + break; + + case A_OTHERS: + return false; + + case A_POS: + if (i == 0) { + int64_t ileft; + if (folded_int(tree_left(base_r), &ileft)) + ilow = ihigh = ileft; + else + return false; + } + else if (dir == RANGE_TO) + ilow = ihigh = clow + pos; + else + ilow = ihigh = chigh - pos; + pos++; + break; + + case A_CONCAT: + { + type_t value_type = tree_type(tree_value(a)); + + int64_t length; + if (type_is_unconstrained(value_type)) + return false; + else if (folded_length(range_of(value_type, 0), &length)) { + if (i == 0) { + int64_t ileft; + if (folded_int(tree_left(base_r), &ileft)) + ilow = ihigh = ileft; + else + return false; + } + else if (dir == RANGE_TO) { + ilow = clow + pos; + ihigh = ilow + length - 1; + } + else { + ihigh = chigh - pos; + ilow = ihigh - length + 1; + } + pos += length; + } + else + return false; + } + break; + } + + clow = MIN(clow, ilow); + chigh = MAX(chigh, ihigh); + } + + if (clow < low || chigh > high) + return false; // Will raise a bounds check error later + + *kind = dir; + *left = dir == RANGE_TO ? clow : chigh; + *right = dir == RANGE_TO ? chigh : clow; + + return true; +} diff --git a/src/common.h b/src/common.h index c32423e6..0cab7bc2 100644 --- a/src/common.h +++ b/src/common.h @@ -35,6 +35,7 @@ bool folded_bounds_real(tree_t r, double *low, double *high); tree_t get_int_lit(tree_t t, type_t type, int64_t i); tree_t get_enum_lit(tree_t t, type_t type, int pos); tree_t get_real_lit(tree_t t, type_t type, double r); +tree_t get_discrete_lit(tree_t t, type_t type, int64_t i); tree_t make_ref(tree_t to); int record_field_to_net(type_t type, unsigned pos); tree_t find_record_field(tree_t rref); @@ -90,6 +91,8 @@ bool all_character_literals(type_t type); bool is_operator_symbol(ident_t ident); bool same_tree(tree_t a, tree_t b); void instance_name_to_path(text_buf_t *tb, const char *str); +bool calculate_aggregate_bounds(tree_t expr, range_kind_t *kind, + int64_t *left, int64_t *right); void analyse_file(const char *file, jit_t *jit, unit_registry_t *ur); diff --git a/src/lower.c b/src/lower.c index 9ef45aca..00222f8e 100644 --- a/src/lower.c +++ b/src/lower.c @@ -3611,116 +3611,14 @@ static vcode_reg_t lower_aggregate_bounds(lower_unit_t *lu, tree_t expr, assert(type_is_unconstrained(type)); type_t index_type = index_type_of(type, 0); - tree_t base_r = range_of(index_type, 0); - - int64_t low, high; - if (!folded_bounds(base_r, &low, &high)) - fatal_trace("index type %s has unknown bounds", type_pp(index_type)); - - int64_t clow = high, chigh = low; // Actual bounds computed below - range_kind_t dir = tree_subkind(base_r); - - const int nassocs = tree_assocs(expr); - - int64_t pos = 0; - bool known_elem_count = true; - for (int i = 0; i < nassocs; i++) { - tree_t a = tree_assoc(expr, i); - int64_t ilow = 0, ihigh = 0; - const assoc_kind_t akind = tree_subkind(a); - - switch (akind) { - case A_NAMED: - { - tree_t name = tree_name(a); - if (folded_int(name, &ilow)) - ihigh = ilow; - else - known_elem_count = false; - } - break; - - case A_RANGE: - case A_SLICE: - { - tree_t r = tree_range(a, 0); - const range_kind_t rkind = tree_subkind(r); - if (rkind == RANGE_TO || rkind == RANGE_DOWNTO) { - tree_t left = tree_left(r), right = tree_right(r); - - int64_t ileft, iright; - if (folded_int(left, &ileft) && folded_int(right, &iright)) { - ilow = (rkind == RANGE_TO ? ileft : iright); - ihigh = (rkind == RANGE_TO ? iright : ileft); - } - else - known_elem_count = false; - - if (akind == A_SLICE) { - // VHDL-2008 range association determines index - // direction for unconstrained aggregate when the - // expression type matches the array type - dir = rkind; - } - } - else - known_elem_count = false; - } - break; - - case A_OTHERS: - known_elem_count = false; - break; - - case A_POS: - if (dir == RANGE_TO) { - ilow = low + pos++; - ihigh = ilow; - } - else { - ihigh = high - pos++; - ilow = ihigh; - } - break; - - case A_CONCAT: - { - type_t value_type = tree_type(tree_value(a)); - - int64_t length; - if (type_is_unconstrained(value_type)) - known_elem_count = false; - else if (folded_length(range_of(value_type, 0), &length)) { - if (dir == RANGE_TO) { - ilow = low + pos; - ihigh = ilow + length - 1; - } - else { - ihigh = high - pos; - ilow = ihigh - length + 1; - } - - pos += length; - } - else - known_elem_count = false; - - } - break; - } - - clow = MIN(clow, ilow); - chigh = MAX(chigh, ihigh); - } - - const int64_t ileft = dir == RANGE_TO ? clow : chigh; - const int64_t iright = dir == RANGE_TO ? chigh : clow; vcode_reg_t left_reg = VCODE_INVALID_REG, right_reg = VCODE_INVALID_REG, dir_reg = VCODE_INVALID_REG; - if (known_elem_count) { + range_kind_t dir; + int64_t ileft, iright; + if (calculate_aggregate_bounds(expr, &dir, &ileft, &iright)) { vcode_type_t vindex = lower_type(index_type); left_reg = emit_const(vindex, ileft); right_reg = emit_const(vindex, iright); @@ -3729,6 +3627,8 @@ static vcode_reg_t lower_aggregate_bounds(lower_unit_t *lu, tree_t expr, else { vcode_type_t voffset = vtype_offset(); vcode_reg_t length_reg = VCODE_INVALID_REG; + + const int nassocs = tree_assocs(expr); for (int i = 0; i < nassocs; i++) { tree_t a = tree_assoc(expr, i); const assoc_kind_t akind = tree_subkind(a); @@ -3737,7 +3637,7 @@ static vcode_reg_t lower_aggregate_bounds(lower_unit_t *lu, tree_t expr, case A_NAMED: assert(nassocs == 1); // Must have a single association left_reg = right_reg = lower_rvalue(lu, tree_name(a)); - dir_reg = emit_const(vtype_bool(), dir); + dir_reg = lower_range_dir(lu, range_of(index_type, 0)); break; case A_RANGE: case A_SLICE: @@ -3776,8 +3676,9 @@ static vcode_reg_t lower_aggregate_bounds(lower_unit_t *lu, tree_t expr, vcode_reg_t delta_reg = emit_sub(length_reg, emit_const(voffset, 1)); vcode_reg_t cast_reg = emit_cast(vindex, vindex, delta_reg); - left_reg = emit_const(vindex, ileft); - dir_reg = emit_const(vtype_bool(), dir); + tree_t base_r = range_of(index_type, 0); + left_reg = lower_range_left(lu, base_r); + dir_reg = lower_range_dir(lu, base_r); right_reg = emit_add(left_reg, cast_reg); } } @@ -3972,6 +3873,17 @@ static vcode_reg_t lower_array_aggregate(lower_unit_t *lu, tree_t expr, vcode_reg_t dim0_len = lower_array_len(lu, type, 0, bounds_reg); vcode_reg_t len_reg = emit_mul(dim0_len, stride); + if (is_unconstrained) + hint = VCODE_INVALID_REG; + else if (hint != VCODE_INVALID_REG && def_value == NULL) { + // It is not safe to use the hint location if the aggregate has + // non-static bounds and those bounds were not derived from the + // context in the case of an OTHERS association + int64_t rlow, rhigh; + if (!folded_bounds(range_of(type, 0), &rlow, &rhigh)) + hint = VCODE_INVALID_REG; + } + vcode_reg_t mem_reg; if (hint != VCODE_INVALID_REG) mem_reg = lower_array_data(hint); @@ -4085,7 +3997,7 @@ static vcode_reg_t lower_array_aggregate(lower_unit_t *lu, tree_t expr, vcode_type_t vindex = lower_type(index_type); - vcode_reg_t low_reg = emit_select(dir_reg, right_reg, left_reg); + vcode_reg_t low_reg = emit_select(dir_reg, right_reg, left_reg); for (int i = 0; i < nassocs; i++) { tree_t a = tree_assoc(expr, i); diff --git a/src/names.c b/src/names.c index 02478869..db13b657 100644 --- a/src/names.c +++ b/src/names.c @@ -4274,7 +4274,7 @@ static type_t solve_attr_ref(nametab_t *tab, tree_t aref) } } -static void solve_record_aggregate(nametab_t *tab, tree_t agg, type_t type) +static type_t solve_record_aggregate(nametab_t *tab, tree_t agg, type_t type) { const int nfields = type_fields(type); const int nassocs = tree_assocs(agg); @@ -4345,9 +4345,10 @@ static void solve_record_aggregate(nametab_t *tab, tree_t agg, type_t type) } mask_free(&fmask); + return type; } -static void solve_array_aggregate(nametab_t *tab, tree_t agg, type_t type) +static type_t solve_array_aggregate(nametab_t *tab, tree_t agg, type_t type) { // All elements must be of the composite base type if this is a // one-dimensional array otherwise construct an array type with @@ -4369,7 +4370,7 @@ static void solve_array_aggregate(nametab_t *tab, tree_t agg, type_t type) type_t index_type = index_type_of(type, 0); - bool all_simple_pos = true; + bool have_named = false, have_others = false; const int nassocs = tree_assocs(agg); for (int i = 0; i < nassocs; i++) { tree_t a = tree_assoc(agg, i); @@ -4378,9 +4379,11 @@ static void solve_array_aggregate(nametab_t *tab, tree_t agg, type_t type) switch (kind) { case A_POS: case A_CONCAT: - case A_OTHERS: case A_SLICE: break; + case A_OTHERS: + have_others = true; + break; case A_NAMED: { tree_t name = tree_name(a); @@ -4407,10 +4410,13 @@ static void solve_array_aggregate(nametab_t *tab, tree_t agg, type_t type) tree_add_range(a, r); } } + + have_named = true; } break; case A_RANGE: solve_types(tab, tree_range(a, 0), index_type); + have_named = true; break; } @@ -4428,68 +4434,58 @@ static void solve_array_aggregate(nametab_t *tab, tree_t agg, type_t type) case A_POS: tree_set_subkind(a, A_CONCAT); break; default: break; } - all_simple_pos = false; } - else if (kind != A_POS) - all_simple_pos = false; } type_set_pop(tab); - if (type_is_unconstrained(type) && ndims == 1) { - // Create a new constrained array subtype for simple cases - // where the bounds are known - - range_kind_t dir = RANGE_ERROR; - tree_t left = NULL, right = NULL; - if (all_simple_pos) { - tree_t index_r = range_of(index_type, 0); - left = tree_left(index_r); - dir = tree_subkind(index_r); - - int64_t ileft; - if (folded_int(left, &ileft)) { - if (type_is_enum(tree_type(left))) { - type_t base = type_base_recur(index_type); - const int maxlit = type_enum_literals(base); - if (ileft + nassocs - 1 < maxlit) - right = get_enum_lit(agg, index_type, ileft + nassocs - 1); - } - else - right = get_int_lit(agg, index_type, ileft + nassocs - 1); - } - } - else if (nassocs == 1) { - tree_t a0 = tree_assoc(agg, 0); - if (tree_subkind(a0) == A_RANGE) { - tree_t r = tree_range(a0, 0); - dir = tree_subkind(r); - if (dir == RANGE_TO || dir == RANGE_DOWNTO) { - left = tree_left(r); - right = tree_right(r); - } - } - } + bool bounds_from_context = true; + if (type_is_unconstrained(type) && ndims == 1) + bounds_from_context = false; + else if (have_named && !have_others && is_anonymous_subtype(type)) + bounds_from_context = false; - if (left != NULL && right != NULL && dir != RANGE_ERROR) { - type_t sub = type_new(T_SUBTYPE); - type_set_base(sub, type); + if (bounds_from_context) + return type; - tree_t cons = tree_new(T_CONSTRAINT); - tree_set_subkind(cons, C_INDEX); + type_t base = type_base_recur(type); - tree_t r = tree_new(T_RANGE); - tree_set_subkind(r, dir); - tree_set_left(r, left); - tree_set_type(r, index_type); + range_kind_t dir; + int64_t ileft, iright; + if (calculate_aggregate_bounds(agg, &dir, &ileft, &iright)) { + tree_t left = get_discrete_lit(agg, index_type, ileft); + tree_t right = get_discrete_lit(agg, index_type, iright); + assert(left != NULL && right != NULL); - tree_set_right(r, right); - tree_add_range(cons, r); - type_add_constraint(sub, cons); + type_t sub = type_new(T_SUBTYPE); + type_set_base(sub, base); + type_set_elem(sub, type_elem(type)); - tree_set_type(agg, (type = sub)); - } + tree_t cons = tree_new(T_CONSTRAINT); + tree_set_subkind(cons, C_INDEX); + + tree_t r = tree_new(T_RANGE); + tree_set_subkind(r, dir); + tree_set_type(r, index_type); + tree_set_left(r, left); + tree_set_right(r, right); + + tree_add_range(cons, r); + + for (int i = 1; i < ndims; i++) + tree_add_range(cons, range_of(type, i)); + + type_add_constraint(sub, cons); + + tree_set_type(agg, sub); + return sub; + } + else if (ndims == 1) { + tree_set_type(agg, base); + return base; } + + return type; } static type_t try_solve_aggregate(nametab_t *tab, tree_t agg) @@ -4513,11 +4509,9 @@ static type_t try_solve_aggregate(nametab_t *tab, tree_t agg) tree_set_type(agg, type); if (type_is_record(type)) - solve_record_aggregate(tab, agg, type); + return solve_record_aggregate(tab, agg, type); else - solve_array_aggregate(tab, agg, type); - - return type; + return solve_array_aggregate(tab, agg, type); } static type_t solve_aggregate(nametab_t *tab, tree_t agg) diff --git a/src/rt/standard.c b/src/rt/standard.c index 2c5a00bf..0ff60710 100644 --- a/src/rt/standard.c +++ b/src/rt/standard.c @@ -38,8 +38,6 @@ static void bit_vec_to_string(jit_scalar_t *args, tlab_t *tlab, int log_base) const int left_pad = (log_base - (vec_len % log_base)) % log_base; char *buf = tlab_alloc(tlab, result_len); - printf("result_len=%zu\n", result_len); - for (int i = 0; i < result_len; i++) { unsigned nibble = 0; for (int j = 0; j < log_base; j++) { diff --git a/test/bounds/issue54.vhd b/test/bounds/issue54.vhd index a5a9efb3..fe8907b2 100644 --- a/test/bounds/issue54.vhd +++ b/test/bounds/issue54.vhd @@ -7,8 +7,8 @@ begin p : process variable v : bit_vector(7 downto 0) := (others => '0'); begin - v(3 downto 0) := (7 downto 4 => '1'); -- Error - v(7 downto 4) := (3 downto 0 => '1'); -- Error + v(3 downto 0) := (7 downto 4 => '1'); -- OK + v(7 downto 4) := (3 downto 0 => '1'); -- OK v(7 downto 4) := (3 downto 0 => '1', others => '0'); -- Error assert (v = (7 downto 0 => '1')); wait; diff --git a/test/parse/aggregate.vhd b/test/parse/aggregate.vhd new file mode 100644 index 00000000..4d6dafb7 --- /dev/null +++ b/test/parse/aggregate.vhd @@ -0,0 +1,14 @@ +package aggregate is + type int_vec_up is array (natural range <>) of integer; + + type down_natural is range 100 downto 0; + type int_vec_down is array (down_natural range <>) of integer; + + constant c1 : int_vec_up(1 to 2) := (1, 2); -- (1 to 2); + constant c2 : int_vec_up(7 to 8) := (1 => 1, 2 => 2); -- (1 to 2); + constant c3 : int_vec_up := (1, 2); -- (0 to 1); + constant c4 : int_vec_down := (1, 2, 3); -- (100 downto 98) + constant c5 : int_vec_down(7 downto 6) := (1 => 1, 2 => 2); -- (2 downto 1) + constant c6 : int_vec_up := (c1, c1); -- (0 to 3) + constant c7 : int_vec_up := (1, c1); -- (0 to 2) +end package; diff --git a/test/regress/array19.vhd b/test/regress/array19.vhd new file mode 100644 index 00000000..757397a4 --- /dev/null +++ b/test/regress/array19.vhd @@ -0,0 +1,31 @@ +entity array19 is + generic ( N : integer := 2 ); +end entity; + +architecture test of array19 is + subtype t_two is integer range 1 to N; + type t_enum is (a, b); + type t_table is array (t_two, t_two, t_enum) of boolean; + + constant table : t_table := ( + 1 => ( 1 => (others => true), + 2 => (others => false) ), + 2 => ( 1 => (others => false), + 2 => (others => true ) ) ); + +begin + + check: process is + variable v : bit_vector(31 downto 0); + variable i : integer := 3; + begin + assert table(2, 1, a) = false; + assert table(1, 1, b) = true; + + v(i*8+7 downto i*8) := (i*8+7 downto i*8 => '1'); + assert v = X"FF000000"; + + wait; + end process; + +end architecture; diff --git a/test/regress/bounds26.vhd b/test/regress/bounds26.vhd index e07f9829..5ce8606b 100644 --- a/test/regress/bounds26.vhd +++ b/test/regress/bounds26.vhd @@ -6,7 +6,8 @@ architecture test of bounds26 is type char_map is array (character range <>) of integer; function func (right : character) return integer is - variable r : char_map('a' to 'c') := ('a' to right => 1); + subtype a_to_c_map is char_map('a' to 'c'); + variable r : a_to_c_map := ('a' to right => 1); begin return r('a') + r('b') + r('c'); end function; diff --git a/test/regress/bounds42.vhd b/test/regress/bounds42.vhd index bbd72d1f..0ce1bb9f 100644 --- a/test/regress/bounds42.vhd +++ b/test/regress/bounds42.vhd @@ -7,13 +7,13 @@ architecture test of bounds42 is begin p1: process is + procedure test (x : bit_vector) is + begin + report to_string( bit_vector'(x'range => (3 downto 0 => '0', 7 downto 4 => '1'))); + end procedure; begin - -- OK - report to_string( bit_vector'(c2'range => (3 downto 0 => '0', 7 downto 4 => '1'))); - - -- Error - report to_string( bit_vector'(c1'range => (3 downto 0 => '0', 7 downto 4 => '1'))); - + test(c2); -- OK + test(c1); -- Error wait; end process; diff --git a/test/regress/gold/bounds24.txt b/test/regress/gold/bounds24.txt index de7f42e0..e0803038 100644 --- a/test/regress/gold/bounds24.txt +++ b/test/regress/gold/bounds24.txt @@ -1 +1 @@ -index 1000 outside of NATURAL range 1 to 3 +value length 1000 does not match variable R length 3 diff --git a/test/regress/gold/bounds42.txt b/test/regress/gold/bounds42.txt index 38107fd7..95b87bd4 100644 --- a/test/regress/gold/bounds42.txt +++ b/test/regress/gold/bounds42.txt @@ -1 +1,2 @@ +0ms+0: 00001111 0ms+0: choice length 8 does not match expected length 3 diff --git a/test/regress/issue873.vhd b/test/regress/issue873.vhd new file mode 100644 index 00000000..6d326538 --- /dev/null +++ b/test/regress/issue873.vhd @@ -0,0 +1,54 @@ +entity ent is +generic ( + DWIDTH : natural := 4; + OFFSET : natural := 10 +); +port ( + enable : in bit; + in_data : in bit_vector(DWIDTH+OFFSET-1 downto OFFSET); + out_data : out bit_vector(DWIDTH+OFFSET-1 downto OFFSET) +); +end entity; + +architecture arch of ent is + function apply_enable(data : bit_vector; en : bit) return bit_vector is + variable mask : bit_vector(data'range); + variable data_masked : bit_vector(data'range); + begin + mask := (data'length-1 downto 0 => en); + data_masked := data and mask; + return data_masked; + end function; +begin + out_data <= apply_enable(in_data, enable); +end architecture arch; + +------------------------------------------------------------------------------- + +entity issue873 is +end entity; + +architecture test of issue873 is + signal enable : bit; + signal in_data : bit_vector(3 downto 0); + signal out_data : bit_vector(3 downto 0); +begin + + uut: entity work.ent + port map (enable, in_data, out_data); + + check: process is + begin + wait for 0 ns; + assert out_data = "0000"; + in_data <= "1010"; + enable <= '1'; + wait for 1 ns; + assert out_data = "1010"; + enable <= '0'; + wait for 1 ns; + assert out_data = "0000"; + wait; + end process; + +end architecture; diff --git a/test/regress/testlist.txt b/test/regress/testlist.txt index 22ffe113..5ee4518d 100644 --- a/test/regress/testlist.txt +++ b/test/regress/testlist.txt @@ -959,3 +959,5 @@ vhpi12 normal,vhpi issue862 normal,gold,2008,relaxed issue858 normal,2008 vhpi13 normal,vhpi +issue873 normal +array19 normal diff --git a/test/test_bounds.c b/test/test_bounds.c index 750d6f66..fa835444 100644 --- a/test/test_bounds.c +++ b/test/test_bounds.c @@ -46,8 +46,8 @@ START_TEST(test_bounds) { 60, "length of value 10 does not match length of target 3" }, { 66, "array S index 11 outside of POSITIVE range 1 to 10" }, { 67, "array S index -1 outside of POSITIVE range 1 to 10" }, - { 74, "aggregate choice index 5 outside of POSITIVE range 1 to 3" }, - { 74, "aggregate choice index 0 outside of POSITIVE range 1 to 3" }, + { 74, "aggregate choice index 0 outside of POSITIVE range 1 to " + "2147483647" }, { 83, "value '1' outside of ALPHA range 'a' to 'z' for variable A" }, { 84, "0 outside of POSITIVE range 1 to 2147483647 for variable P" }, { 89, "invalid dimension 5 for type MY_VEC1" }, @@ -203,10 +203,6 @@ END_TEST START_TEST(test_issue54) { const error_t expect[] = { - { 10, "index 7 outside of NATURAL range 3 downto 0" }, - { 10, "index 4 outside of NATURAL range 3 downto 0" }, - { 11, "index 3 outside of NATURAL range 7 downto 4" }, - { 11, "index 0 outside of NATURAL range 7 downto 4" }, { 12, "index 3 outside of NATURAL range 7 downto 4" }, { 12, "index 0 outside of NATURAL range 7 downto 4" }, { -1, NULL } @@ -430,8 +426,7 @@ START_TEST(test_aggregate) "aggregate with index type NATURAL range 1 to 3" }, { 22, "missing choice for element 5 of INTEGER_VECTOR with index " "type NATURAL range 1 to 5" }, - { 24, "missing choice for element 3 of INTEGER_VECTOR with index " - "type NATURAL range 1 to 3" }, + { 24, "length of value 2 does not match length of target 3" }, { 25, "discrete range has 4 elements but length of expression is 3" }, { 29, "discrete range has 4 elements but length of expression is 3" }, { -1, NULL } diff --git a/test/test_parse.c b/test/test_parse.c index 079a78d0..9d3ad5be 100644 --- a/test/test_parse.c +++ b/test/test_parse.c @@ -28,6 +28,7 @@ #include #include #include +#include #include START_TEST(test_entity) @@ -6196,6 +6197,59 @@ START_TEST(test_issue870) fail_if(a == NULL); fail_unless(tree_kind(a) == T_ARCH); + fail_unless(parse() == NULL); + + fail_if_errors(); +} +END_TEST + +START_TEST(test_aggregate) +{ + set_standard(STD_08); + + input_from_file(TESTDIR "/parse/aggregate.vhd"); + + tree_t p = parse(); + fail_if(p == NULL); + fail_unless(tree_kind(p) == T_PACKAGE); + + static const struct { + const char *name; + int64_t left; + range_kind_t dir; + int64_t right; + } cases[] = { + { "C1", 1, RANGE_TO, 2 }, + { "C2", 1, RANGE_TO, 2 }, + { "C3", 0, RANGE_TO, 1 }, + { "C4", 100, RANGE_DOWNTO, 98 }, + { "C5", 2, RANGE_DOWNTO, 1 }, + { "C6", 0, RANGE_TO, 3 }, + { "C7", 0, RANGE_TO, 2 }, + }; + + for (int i = 0; i < ARRAY_LEN(cases); i++) { + tree_t d = search_decls(p, ident_new(cases[i].name), 0); + fail_if(d == NULL); + + type_t type = tree_type(tree_value(d)); + fail_unless(type_is_array(type)); + + tree_t r = range_of(type, 0); + const range_kind_t kind = tree_subkind(r); + const int64_t left = assume_int(tree_left(r)); + const int64_t right = assume_int(tree_right(r)); + + if (kind != cases[i].dir || left != cases[i].left + || right != cases[i].right) { + fmt_loc(stdout, tree_loc(d)); + ck_abort_msg("range mismatch: %d %"PRIi64" %"PRIi64, + kind, left, right); + } + } + + fail_unless(parse() == NULL); + fail_if_errors(); } END_TEST @@ -6338,6 +6392,7 @@ Suite *get_parse_tests(void) tcase_add_test(tc_core, test_issue845); tcase_add_test(tc_core, test_issue848); tcase_add_test(tc_core, test_issue870); + tcase_add_test(tc_core, test_aggregate); suite_add_tcase(s, tc_core); return s; -- 2.39.2