From c560ab9f1bea0a828473c3ce58f217da4319d60d Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Sat, 13 Jan 2024 19:21:45 +0000 Subject: [PATCH] Add separate assoc_kind_t for 2008 slices and concatenations --- src/bounds.c | 20 ++-- src/common.c | 2 + src/dump.c | 2 + src/lower.c | 206 ++++++++++++++++++++++++------------------ src/names.c | 15 ++- src/sem.c | 40 +++++--- src/tree.h | 4 +- test/regress/agg7.vhd | 2 + 8 files changed, 175 insertions(+), 116 deletions(-) diff --git a/src/bounds.c b/src/bounds.c index de7dc782..efdfd727 100644 --- a/src/bounds.c +++ b/src/bounds.c @@ -568,19 +568,17 @@ static void bounds_check_aggregate(tree_t t) for (int i = 0; i < nassocs; i++) { tree_t a = tree_assoc(t, i); int64_t ilow = 0, ihigh = 0, count = 1; + const assoc_kind_t akind = tree_subkind(a); - if (ndims == 1 && standard() >= STD_08) { - // Element type may also have the same type as the aggregate + if (akind == A_SLICE || akind == A_CONCAT) { type_t value_type = tree_type(tree_value(a)); - if (type_eq(value_type, type)) { - if (type_is_unconstrained(value_type)) - known_elem_count = false; - else if (!folded_length(range_of(value_type, 0), &count)) - known_elem_count = false; - } + if (type_is_unconstrained(value_type)) + known_elem_count = false; + else if (!folded_length(range_of(value_type, 0), &count)) + known_elem_count = false; } - switch (tree_subkind(a)) { + switch (akind) { case A_NAMED: { tree_t name = tree_name(a); @@ -595,6 +593,7 @@ static void bounds_check_aggregate(tree_t t) break; case A_RANGE: + case A_SLICE: { tree_t r = tree_range(a, 0); const range_kind_t rkind = tree_subkind(r); @@ -620,7 +619,7 @@ static void bounds_check_aggregate(tree_t t) bounds_error(a, "discrete range has %"PRIi64" elements but " "length of expression is %"PRIi64, ihigh - ilow + 1, count); - else if (unconstrained && count > 1) { + else if (unconstrained && akind == A_SLICE && count > 1) { // VHDL-2008 range association determines index // direction for unconstrained aggregate assert(standard() >= STD_08); @@ -637,6 +636,7 @@ static void bounds_check_aggregate(tree_t t) break; case A_POS: + case A_CONCAT: if (dir == RANGE_TO) { ilow = low + next_pos; ihigh = ilow + count - 1; diff --git a/src/common.c b/src/common.c index d2c5f634..4ea9a7a4 100644 --- a/src/common.c +++ b/src/common.c @@ -632,8 +632,10 @@ const char *assoc_kind_str(assoc_kind_t akind) { switch (akind) { case A_NAMED: return "named"; + case A_CONCAT: case A_POS: return "positional"; case A_OTHERS: return "others"; + case A_SLICE: case A_RANGE: return "range"; default: return "??"; } diff --git a/src/dump.c b/src/dump.c index 7e2e6713..a040bbad 100644 --- a/src/dump.c +++ b/src/dump.c @@ -284,6 +284,7 @@ static void dump_expr(tree_t t) tree_t value = tree_value(a); switch (tree_subkind(a)) { case A_POS: + case A_CONCAT: dump_expr(value); break; case A_NAMED: @@ -296,6 +297,7 @@ static void dump_expr(tree_t t) dump_expr(value); break; case A_RANGE: + case A_SLICE: dump_range(tree_range(a, 0)); print_syntax(" => "); dump_expr(value); diff --git a/src/lower.c b/src/lower.c index b8b504be..eff43fb2 100644 --- a/src/lower.c +++ b/src/lower.c @@ -188,6 +188,7 @@ static bool lower_is_const(tree_t t) return false; break; case A_RANGE: + case A_SLICE: { tree_t r = tree_range(a, 0); if (tree_subkind(r) == RANGE_EXPR) @@ -3499,8 +3500,8 @@ static vcode_reg_t *lower_const_array_aggregate(lower_unit_t *lu, tree_t t, tree_t r = range_of(type, dim); const int64_t left = assume_int(tree_left(r)); const bool is_downto = (tree_subkind(r) == RANGE_DOWNTO); - const bool multidim = dim > 0 || dimension_of(type) > 1; + int pos = 0; const int nassocs = tree_assocs(t); for (int i = 0; i < nassocs; i++) { tree_t a = tree_assoc(t, i); @@ -3529,7 +3530,9 @@ static vcode_reg_t *lower_const_array_aggregate(lower_unit_t *lu, tree_t t, switch (tree_subkind(a)) { case A_POS: - lower_copy_vals(vals + (i * nsub), sub, nsub); + case A_CONCAT: + lower_copy_vals(vals + pos, sub, nsub); + pos += nsub; break; case A_NAMED: @@ -3552,24 +3555,27 @@ static vcode_reg_t *lower_const_array_aggregate(lower_unit_t *lu, tree_t t, { tree_t r = tree_range(a, 0); - if (!multidim && type_eq(type, value_type)) { - // Element has same type as whole aggregate - assert(standard() >= STD_08); - const int64_t r_left = assume_int(tree_left(r)); - const int64_t off = is_downto ? left - r_left : r_left - left; - lower_copy_vals(vals + off * 1, sub, nsub); - } - else { - int64_t r_low, r_high; - range_bounds(r, &r_low, &r_high); + int64_t r_low, r_high; + range_bounds(r, &r_low, &r_high); - for (int j = r_low; j <= r_high; j++) { - const int64_t off = is_downto ? left - j : j - left; - lower_copy_vals(vals + (off * nsub), sub, nsub); - } + for (int j = r_low; j <= r_high; j++) { + const int64_t off = is_downto ? left - j : j - left; + lower_copy_vals(vals + (off * nsub), sub, nsub); } } break; + + case A_SLICE: + { + assert(standard() >= STD_08); + + tree_t r = tree_range(a, 0); + const int64_t r_left = assume_int(tree_left(r)); + const int64_t off = is_downto ? left - r_left : r_left - left; + + lower_copy_vals(vals + off, sub, nsub); + } + break; } if (sub != &tmp) @@ -3669,7 +3675,7 @@ static vcode_reg_t lower_record_aggregate(lower_unit_t *lu, tree_t expr, } break; - case A_RANGE: + default: fatal_trace("unexpected range association in record aggregate"); } } @@ -3803,16 +3809,14 @@ static vcode_reg_t lower_aggregate_bounds(lower_unit_t *lu, tree_t expr, const int nassocs = tree_assocs(expr); - const bool vhdl2008_slice = - standard() >= STD_08 && dimension_of(type) == 1; - 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 (tree_subkind(a)) { + switch (akind) { case A_NAMED: { tree_t name = tree_name(a); @@ -3824,6 +3828,7 @@ static vcode_reg_t lower_aggregate_bounds(lower_unit_t *lu, tree_t expr, break; case A_RANGE: + case A_SLICE: { tree_t r = tree_range(a, 0); const range_kind_t rkind = tree_subkind(r); @@ -3838,13 +3843,11 @@ static vcode_reg_t lower_aggregate_bounds(lower_unit_t *lu, tree_t expr, else known_elem_count = false; - if (vhdl2008_slice) { + if (akind == A_SLICE) { // VHDL-2008 range association determines index // direction for unconstrained aggregate when the // expression type matches the array type - type_t value_type = tree_type(tree_value(a)); - if (type_eq(type, value_type)) - dir = rkind; + dir = rkind; } } else @@ -3857,13 +3860,20 @@ static vcode_reg_t lower_aggregate_bounds(lower_unit_t *lu, tree_t expr, break; case A_POS: + if (dir == RANGE_TO) { + ilow = low + pos++; + ihigh = ilow; + } + else { + ihigh = high - pos++; + ilow = ihigh; + } + break; + + case A_CONCAT: { - int64_t length = 1; - if (vhdl2008_slice) { - type_t value_type = tree_type(tree_value(a)); - if (type_eq(type, value_type)) - length = lower_array_const_size(value_type); - } + type_t value_type = tree_type(tree_value(a)); + const int64_t length = lower_array_const_size(value_type); if (dir == RANGE_TO) { ilow = low + pos; @@ -3914,6 +3924,7 @@ static vcode_reg_t lower_aggregate_bounds(lower_unit_t *lu, tree_t expr, dir_reg = emit_const(vtype_bool(), dir); break; case A_RANGE: + case A_SLICE: { tree_t a0r = tree_range(a0, 0); left_reg = lower_range_left(lu, a0r); @@ -4229,18 +4240,16 @@ static vcode_reg_t lower_array_aggregate(lower_unit_t *lu, tree_t expr, tree_t a = tree_assoc(expr, i); tree_t value = tree_value(a); + const assoc_kind_t akind = tree_subkind(a); + vcode_reg_t value_reg = VCODE_INVALID_REG, count_reg = VCODE_INVALID_REG; - type_t value_type = tree_type(value); - if (!multidim && type_eq(type, value_type)) { - // Element has same type as whole aggregate - assert(standard() >= STD_08); + if (akind == A_CONCAT || akind == A_SLICE) { value_reg = lower_rvalue(lu, value); - count_reg = lower_array_len(lu, value_type, 0, value_reg); + count_reg = lower_array_len(lu, tree_type(value), 0, value_reg); } else if (tree_kind(value) != T_AGGREGATE) value_reg = lower_rvalue(lu, value); - vcode_reg_t loop_bb = VCODE_INVALID_BLOCK; vcode_reg_t exit_bb = VCODE_INVALID_BLOCK; @@ -4249,33 +4258,53 @@ static vcode_reg_t lower_array_aggregate(lower_unit_t *lu, tree_t expr, switch (tree_subkind(a)) { case A_POS: - if (next_pos == VCODE_INVALID_REG) { - off_reg = emit_const(voffset, tree_pos(a)); - next_pos = count_reg; - } - else if (count_reg == VCODE_INVALID_REG) { - off_reg = next_pos; - next_pos = emit_add(next_pos, emit_const(voffset, 1)); - } - else { - off_reg = next_pos; - next_pos = emit_add(next_pos, count_reg); + { + if (next_pos == VCODE_INVALID_REG) + off_reg = emit_const(voffset, tree_pos(a)); + else { + off_reg = next_pos; + next_pos = emit_add(next_pos, emit_const(voffset, 1)); + } + + vcode_reg_t locus = lower_debug_locus(a); + vcode_reg_t hint = lower_debug_locus(index_r); + + vcode_reg_t index_off_reg = emit_cast(vindex, vindex, off_reg); + + vcode_reg_t up_left_reg = emit_add(left_reg, index_off_reg); + vcode_reg_t down_left_reg = emit_add(right_reg, index_off_reg); + vcode_reg_t left_index_reg = + emit_select(dir_reg, down_left_reg, up_left_reg); + + emit_index_check(left_index_reg, left_reg, right_reg, + dir_reg, locus, hint); } + break; - vcode_reg_t locus = lower_debug_locus(a); - vcode_reg_t hint = lower_debug_locus(index_r); + case A_CONCAT: + { + if (next_pos == VCODE_INVALID_REG) { + off_reg = emit_const(voffset, tree_pos(a)); + next_pos = count_reg; + } + else { + off_reg = next_pos; + next_pos = emit_add(next_pos, count_reg); + } - vcode_reg_t index_off_reg = emit_cast(vindex, vindex, off_reg); + vcode_reg_t locus = lower_debug_locus(a); + vcode_reg_t hint = lower_debug_locus(index_r); - vcode_reg_t up_left_reg = emit_add(left_reg, index_off_reg); - vcode_reg_t down_left_reg = emit_add(right_reg, index_off_reg); - vcode_reg_t left_index_reg = - emit_select(dir_reg, down_left_reg, up_left_reg); + vcode_reg_t index_off_reg = emit_cast(vindex, vindex, off_reg); - emit_index_check(left_index_reg, left_reg, right_reg, - dir_reg, locus, hint); + vcode_reg_t up_left_reg = emit_add(left_reg, index_off_reg); + vcode_reg_t down_left_reg = emit_add(right_reg, index_off_reg); + vcode_reg_t left_index_reg = + emit_select(dir_reg, down_left_reg, up_left_reg); + + emit_index_check(left_index_reg, left_reg, right_reg, + dir_reg, locus, hint); - if (count_reg != VCODE_INVALID_REG) { vcode_reg_t one_reg = emit_const(voffset, 1); vcode_reg_t right_off_reg = emit_sub(emit_add(index_off_reg, count_reg), one_reg); @@ -4301,31 +4330,7 @@ static vcode_reg_t lower_array_aggregate(lower_unit_t *lu, tree_t expr, break; case A_RANGE: - if (count_reg != VCODE_INVALID_REG) { - tree_t r = tree_range(a, 0); - - vcode_reg_t r_left_reg = lower_range_left(lu, r); - vcode_reg_t r_right_reg = lower_range_right(lu, r); - vcode_reg_t r_dir_reg = lower_range_dir(lu, r); - - vcode_reg_t locus = lower_debug_locus(a); - emit_index_check(r_left_reg, left_reg, right_reg, dir_reg, - locus, locus); - emit_index_check(r_right_reg, left_reg, right_reg, dir_reg, - locus, locus); - - vcode_reg_t expect_reg = - emit_range_length(r_left_reg, r_right_reg, r_dir_reg); - emit_length_check(expect_reg, count_reg, locus, VCODE_INVALID_REG); - - vcode_reg_t dir_cmp_reg = - emit_cmp(VCODE_CMP_EQ, dir_reg, r_dir_reg); - vcode_reg_t base_reg = - emit_select(dir_cmp_reg, r_left_reg, r_right_reg); - - off_reg = lower_array_off(lu, base_reg, wrap_reg, type, 0); - } - else { + { loop_bb = emit_block(); exit_bb = emit_block(); @@ -4360,6 +4365,33 @@ static vcode_reg_t lower_array_aggregate(lower_unit_t *lu, tree_t expr, } break; + case A_SLICE: + { + tree_t r = tree_range(a, 0); + + vcode_reg_t r_left_reg = lower_range_left(lu, r); + vcode_reg_t r_right_reg = lower_range_right(lu, r); + vcode_reg_t r_dir_reg = lower_range_dir(lu, r); + + vcode_reg_t locus = lower_debug_locus(a); + emit_index_check(r_left_reg, left_reg, right_reg, dir_reg, + locus, locus); + emit_index_check(r_right_reg, left_reg, right_reg, dir_reg, + locus, locus); + + vcode_reg_t expect_reg = + emit_range_length(r_left_reg, r_right_reg, r_dir_reg); + emit_length_check(expect_reg, count_reg, locus, VCODE_INVALID_REG); + + vcode_reg_t dir_cmp_reg = + emit_cmp(VCODE_CMP_EQ, dir_reg, r_dir_reg); + vcode_reg_t base_reg = + emit_select(dir_cmp_reg, r_left_reg, r_right_reg); + + off_reg = lower_array_off(lu, base_reg, wrap_reg, type, 0); + } + break; + case A_OTHERS: // Handled above continue; @@ -12516,13 +12548,13 @@ vcode_unit_t lower_case_generate_thunk(lower_unit_t *parent, tree_t t) } break; - case A_RANGE: - fatal_at(tree_loc(a), "sorry, this form of choice is not " - "yet supported"); - case A_OTHERS: emit_return(emit_const(vint, i)); break; + + default: + fatal_at(tree_loc(a), "sorry, this form of choice is not " + "yet supported"); } } } diff --git a/src/names.c b/src/names.c index 129fda17..c0e924b3 100644 --- a/src/names.c +++ b/src/names.c @@ -4212,7 +4212,7 @@ static void solve_record_aggregate(nametab_t *tab, tree_t agg, type_t type) type_set_push(tab); tree_t a = tree_assoc(agg, i); - switch ((assoc_kind_t)tree_subkind(a)) { + switch (tree_subkind(a)) { case A_POS: { int pos = tree_pos(a); @@ -4302,7 +4302,9 @@ static void solve_array_aggregate(nametab_t *tab, tree_t agg, type_t type) const assoc_kind_t kind = tree_subkind(a); switch (kind) { case A_POS: + case A_CONCAT: case A_OTHERS: + case A_SLICE: break; case A_NAMED: { @@ -4344,9 +4346,16 @@ static void solve_array_aggregate(nametab_t *tab, tree_t agg, type_t type) type_set_add(tab, t0, NULL); type_set_add(tab, t1, NULL); - if (kind != A_POS) + if (t1 != NULL && type_eq(etype, t1)) { + // VHDL-2008 slice in aggregate + switch (kind) { + case A_RANGE: tree_set_subkind(a, A_SLICE); break; + case A_POS: tree_set_subkind(a, A_CONCAT); break; + default: break; + } all_simple_pos = false; - else if (all_simple_pos && t1 != NULL && type_eq(etype, t1)) + } + else if (kind != A_POS) all_simple_pos = false; } diff --git a/src/sem.c b/src/sem.c index efb14d22..0d1b7e32 100644 --- a/src/sem.c +++ b/src/sem.c @@ -2252,19 +2252,15 @@ static bool sem_check_aggregate_target_element(tree_t a, type_t type) // LRM 08 section 10.6.2.1: it is an error if the element // association contains a choice that is a discrete range and // an expression of a type other than the aggregate type. - if (type_eq(tree_type(value), type)) - break; - else { - diag_t *d = diag_new(DIAG_ERROR, tree_loc(value)); - diag_printf(d, "range choice expression must have same type " - "as aggregate"); - diag_hint(d, tree_loc(value), "expression type is %s but " - "aggregate is %s", type_pp(tree_type(value)), - type_pp(type)); - diag_lrm(d, STD_08, "10.6.2"); - diag_emit(d); - return false; - } + diag_t *d = diag_new(DIAG_ERROR, tree_loc(value)); + diag_printf(d, "range choice expression must have same type " + "as aggregate"); + diag_hint(d, tree_loc(value), "expression type is %s but " + "aggregate is %s", type_pp(tree_type(value)), + type_pp(type)); + diag_lrm(d, STD_08, "10.6.2"); + diag_emit(d); + return false; } // Fall-through case A_OTHERS: @@ -2272,6 +2268,8 @@ static bool sem_check_aggregate_target_element(tree_t a, type_t type) assoc_kind_str(kind)); case A_NAMED: case A_POS: + case A_SLICE: + case A_CONCAT: break; } @@ -3375,6 +3373,7 @@ static bool sem_check_array_aggregate(tree_t t, nametab_t *tab) const assoc_kind_t akind = tree_subkind(a); switch (akind) { case A_RANGE: + case A_SLICE: { tree_t r = tree_range(a, 0); if (!sem_check_discrete_range(r, index_type, tab)) @@ -3401,6 +3400,7 @@ static bool sem_check_array_aggregate(tree_t t, nametab_t *tab) break; case A_POS: + case A_CONCAT: have_pos = true; break; @@ -3420,8 +3420,9 @@ static bool sem_check_array_aggregate(tree_t t, nametab_t *tab) // LRM 08 section 9.3.3.3 allows the association to be of the // base aggregate type as well const bool allow_slice = - ndims == 1 && standard() >= STD_08 - && (akind == A_POS || akind == A_RANGE); + (akind == A_CONCAT || akind == A_SLICE) + || (ndims == 1 && standard() >= STD_08 + && (akind == A_POS || akind == A_RANGE)); if (allow_slice && !sem_check_type(value, composite_type, tab)) sem_error(value, "type of %s association %s does not match " @@ -3433,6 +3434,8 @@ static bool sem_check_array_aggregate(tree_t t, nametab_t *tab) sem_error(value, "type of %s association %s does not match " "aggregate element type %s", assoc_kind_str(akind), type_pp(tree_type(value)), type_pp(elem_type)); + else + assert(akind == A_CONCAT || akind == A_SLICE); } } @@ -3451,6 +3454,7 @@ static bool sem_check_array_aggregate(tree_t t, nametab_t *tab) tree_t choice = NULL; switch (tree_subkind(a)) { case A_NAMED: choice = tree_name(a); break; + case A_SLICE: case A_RANGE: choice = tree_range(a, 0); break; } @@ -3516,6 +3520,10 @@ static bool sem_check_record_aggregate(tree_t t, nametab_t *tab) case A_RANGE: sem_error(a, "range association invalid in record aggregate"); + + case A_SLICE: + case A_CONCAT: + fatal_trace("illegal association type in record aggregate"); } int nmatched = 0; @@ -3603,6 +3611,7 @@ static bool sem_check_aggregate(tree_t t, nametab_t *tab) switch (tree_subkind(a)) { case A_POS: + case A_CONCAT: if (state > POS) sem_error(a, "positional associations must appear " "first in aggregate"); @@ -3610,6 +3619,7 @@ static bool sem_check_aggregate(tree_t t, nametab_t *tab) case A_NAMED: case A_RANGE: + case A_SLICE: if (state > NAMED) sem_error(a, "named association must not follow " "others association in aggregate"); diff --git a/src/tree.h b/src/tree.h index df3b68c7..0622647f 100644 --- a/src/tree.h +++ b/src/tree.h @@ -66,7 +66,9 @@ typedef enum assoc_kind { A_POS, A_NAMED, A_RANGE, - A_OTHERS + A_OTHERS, + A_SLICE, + A_CONCAT, } assoc_kind_t; typedef enum literal_kind { diff --git a/test/regress/agg7.vhd b/test/regress/agg7.vhd index 9f43972f..70db5114 100644 --- a/test/regress/agg7.vhd +++ b/test/regress/agg7.vhd @@ -20,6 +20,8 @@ begin assert x = (7, 8, 1, 2); x := ( y, 9, 8 ); assert x = (5, 6, 9, 8); + x := (9, 8, (1, 2 )); + assert x = (9, 8, 1, 2); wait; end process; -- 2.39.2