From 1d9449af8922c87fc181d3e86c53eda8d77921d7 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Mon, 1 Apr 2024 11:19:18 +0100 Subject: [PATCH] Fix more corner cases with aggregate subtype calculation. Fixes #874 --- src/bounds.c | 8 ++---- src/common.c | 56 +++++++++++++++++++++++++++++++++++++++ src/common.h | 1 + src/names.c | 40 ++++++---------------------- src/simp.c | 16 ++++++++++- test/regress/issue874.vhd | 20 ++++++++++++++ test/regress/testlist.txt | 1 + 7 files changed, 103 insertions(+), 39 deletions(-) create mode 100644 test/regress/issue874.vhd diff --git a/src/bounds.c b/src/bounds.c index ca4ad321..e0c89d2f 100644 --- a/src/bounds.c +++ b/src/bounds.c @@ -529,9 +529,6 @@ static void bounds_free_intervals(interval_t **list) static void bounds_check_aggregate(tree_t t) { - if (!tree_has_type(t)) - return; // VHDL-2008 aggregate resolution in subtype declaration - type_t type = tree_type(t); if (!type_is_array(type)) return; @@ -689,7 +686,7 @@ static void bounds_check_aggregate(tree_t t) // Check each sub-aggregate has the same length for an unconstrained // array aggregate - if (ndims > 1 && unconstrained) { + if (ndims > 1) { int64_t length = -1; for (int i = 0; i < nassocs; i++) { tree_t a = tree_assoc(t, i); @@ -706,8 +703,7 @@ static void bounds_check_aggregate(tree_t t) length = this_length; else if (length != this_length) bounds_error(a, "length of sub-aggregate %"PRIi64" does not match " - "expected length %"PRIi64, - this_length, length); + "expected length %"PRIi64, this_length, length); } } } diff --git a/src/common.c b/src/common.c index 1dd324f1..9253df2b 100644 --- a/src/common.c +++ b/src/common.c @@ -2699,3 +2699,59 @@ bool calculate_aggregate_bounds(tree_t expr, range_kind_t *kind, return true; } + +type_t calculate_aggregate_subtype(tree_t expr) +{ + range_kind_t dir; + int64_t ileft, iright; + if (!calculate_aggregate_bounds(expr, &dir, &ileft, &iright)) + return NULL; + + type_t type = tree_type(expr); + + const int ndims = dimension_of(type); + type_t a0_type = NULL; + if (ndims > 1) { + a0_type = tree_type(tree_value(tree_assoc(expr, 0))); + if (type_is_unconstrained(a0_type)) + return NULL; + + assert(dimension_of(a0_type) == ndims - 1); + } + + type_t index_type = index_type_of(type, 0); + + tree_t left = get_discrete_lit(expr, index_type, ileft); + tree_t right = get_discrete_lit(expr, index_type, iright); + assert(left != NULL && right != NULL); + + type_t sub = type_new(T_SUBTYPE); + type_set_base(sub, type_base_recur(type)); + + type_t elem = type_elem(type); + if (type_is_unconstrained(elem)) { + a0_type = tree_type(tree_value(tree_assoc(expr, 0))); + if (!type_is_unconstrained(a0_type)) + elem = a0_type; + } + + type_set_elem(sub, elem); + + 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(a0_type, i - 1)); + + type_add_constraint(sub, cons); + + return sub; +} diff --git a/src/common.h b/src/common.h index 0cab7bc2..4ad5a80b 100644 --- a/src/common.h +++ b/src/common.h @@ -93,6 +93,7 @@ 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); +type_t calculate_aggregate_subtype(tree_t expr); void analyse_file(const char *file, jit_t *jit, unit_registry_t *ur); diff --git a/src/names.c b/src/names.c index ea4db7a3..4e99b053 100644 --- a/src/names.c +++ b/src/names.c @@ -4440,7 +4440,7 @@ static type_t solve_array_aggregate(nametab_t *tab, tree_t agg, type_t type) type_set_pop(tab); bool bounds_from_context = true; - if (type_is_unconstrained(type) && ndims == 1) + if (type_is_unconstrained(type)) bounds_from_context = false; else if (have_named && !have_others && is_anonymous_subtype(type)) bounds_from_context = false; @@ -4448,44 +4448,20 @@ static type_t solve_array_aggregate(nametab_t *tab, tree_t agg, type_t type) if (bounds_from_context) return type; - type_t base = type_base_recur(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); - - type_t sub = type_new(T_SUBTYPE); - type_set_base(sub, base); + type_t sub = calculate_aggregate_subtype(agg); + if (sub == NULL) { + sub = type_new(T_SUBTYPE); + type_set_base(sub, type_base_recur(type)); type_set_elem(sub, type_elem(type)); 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)); + tree_set_subkind(cons, C_OPEN); 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; + tree_set_type(agg, sub); + return sub; } static type_t try_solve_aggregate(nametab_t *tab, tree_t agg) diff --git a/src/simp.c b/src/simp.c index aa71398e..28164506 100644 --- a/src/simp.c +++ b/src/simp.c @@ -1,5 +1,5 @@ // -// Copyright (C) 2011-2023 Nick Gasson +// Copyright (C) 2011-2024 Nick Gasson // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -1419,6 +1419,18 @@ static tree_t simp_cond_value(tree_t t) return t; } +static tree_t simp_aggregate(tree_t t) +{ + type_t type = tree_type(t); + if (type_is_array(type) && type_is_unconstrained(type)) { + type_t sub = calculate_aggregate_subtype(t); + if (sub != NULL) + tree_set_type(t, sub); + } + + return t; +} + static void simp_generic_map(tree_t t, tree_t unit) { switch (tree_kind(unit)) { @@ -1620,6 +1632,8 @@ static tree_t simp_tree(tree_t t, void *_ctx) if (!is_uninstantiated_package(t)) simp_generic_map(t, t); return t; + case T_AGGREGATE: + return simp_aggregate(t); default: return t; } diff --git a/test/regress/issue874.vhd b/test/regress/issue874.vhd new file mode 100644 index 00000000..f3ef9a20 --- /dev/null +++ b/test/regress/issue874.vhd @@ -0,0 +1,20 @@ +entity issue874 is +end entity; + +architecture arch of issue874 is + constant A : natural := 15; + constant B : natural := A-1; + type array1 is array (0 to 3) of bit_vector(A-1 downto 0); + signal s1 : array1 := (others => (others => '0')); + type array2 is array (0 to 3) of bit_vector; + signal s2 : array2(open)(B downto 0) := (others => (others => '0')); +begin + process + begin + assert s1 = (0 to 3 => (14 downto 0 => '0')); -- Crash + assert s1 = (0 to 3 => (B downto 0 => '0')); -- Crash + assert s1 = (0 to 3 => (A-1 downto 0 => '0')); -- Crash + assert s2 = (0 to 3 => (A-1 downto 0 => '0')); -- Crash + wait; + end process; +end architecture arch; diff --git a/test/regress/testlist.txt b/test/regress/testlist.txt index 5ee4518d..a14ff86d 100644 --- a/test/regress/testlist.txt +++ b/test/regress/testlist.txt @@ -961,3 +961,4 @@ issue858 normal,2008 vhpi13 normal,vhpi issue873 normal array19 normal +issue874 normal,2008 -- 2.39.2