Skip to content

Commit

Permalink
Implement 'last_value for record types. Fixes #1043
Browse files Browse the repository at this point in the history
  • Loading branch information
nickg committed Oct 28, 2024
1 parent 6e4b8e4 commit 5cb8638
Show file tree
Hide file tree
Showing 4 changed files with 79 additions and 12 deletions.
1 change: 1 addition & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
coverage bin must reach to be reported as covered.
- Added a warning for potential infinite loops in processes without
sensitivity and lacking any wait statements (from @NikLeberg).
- Fixed a crash when `'last_value` is used with record types (#1043).

## Version 1.14.1 - 2024-10-26
- Fixed an error when using the `work` library alias and the working
Expand Down
60 changes: 48 additions & 12 deletions src/lower.c
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ typedef struct {
typedef void (*lower_field_fn_t)(lower_unit_t *, tree_t, vcode_reg_t,
vcode_reg_t, vcode_reg_t, void *);
typedef void (*convert_emit_fn)(vcode_reg_t, vcode_reg_t, vcode_reg_t);
typedef vcode_reg_t (*resolved_fn_t)(vcode_reg_t);

typedef A(concat_param_t) concat_list_t;

Expand Down Expand Up @@ -163,6 +164,8 @@ static vcode_reg_t lower_get_type_bounds(lower_unit_t *lu, type_t type);
static vcode_reg_t lower_attr_prefix(lower_unit_t *lu, tree_t prefix);
static void lower_subprogram_ports(lower_unit_t *lu, tree_t body,
bool params_as_vars);
static vcode_type_t lower_func_result_type(type_t result);
static vcode_reg_t lower_context_for_call(lower_unit_t *lu, ident_t unit_name);

typedef vcode_reg_t (*lower_signal_flag_fn_t)(vcode_reg_t, vcode_reg_t);
typedef vcode_reg_t (*arith_fn_t)(vcode_reg_t, vcode_reg_t);
Expand Down Expand Up @@ -1091,7 +1094,7 @@ static vcode_reg_t lower_coerce_arrays(lower_unit_t *lu, type_t from, type_t to,

static void lower_resolved_field_cb(lower_unit_t *lu, tree_t field,
vcode_reg_t field_ptr, vcode_reg_t dst_ptr,
vcode_reg_t locus, void *__ctx)
vcode_reg_t locus, void *ctx)
{
type_t ftype = tree_type(field);
if (!type_is_homogeneous(ftype)) {
Expand All @@ -1114,13 +1117,14 @@ static void lower_resolved_field_cb(lower_unit_t *lu, tree_t field,
}

lower_for_each_field_2(lu, ftype, ftype, field_ptr, dst_ptr, locus,
lower_resolved_field_cb, NULL);
lower_resolved_field_cb, ctx);
}
else {
resolved_fn_t fn = ctx;
vcode_reg_t sig_reg = emit_load_indirect(field_ptr);

if (type_is_array(ftype)) {
vcode_reg_t r_reg = emit_resolved(lower_array_data(sig_reg));
vcode_reg_t r_reg = (*fn)(lower_array_data(sig_reg));

if (type_const_bounds(ftype)) {
vcode_reg_t count_reg =
Expand All @@ -1133,7 +1137,7 @@ static void lower_resolved_field_cb(lower_unit_t *lu, tree_t field,
}
}
else {
vcode_reg_t r_reg = emit_resolved(sig_reg);
vcode_reg_t r_reg = (*fn)(sig_reg);
emit_store_indirect(emit_load_indirect(r_reg), dst_ptr);
}
}
Expand Down Expand Up @@ -1359,13 +1363,30 @@ static vcode_reg_t lower_last_value(lower_unit_t *lu, tree_t ref)
vcode_reg_t nets = lower_lvalue(lu, ref);

type_t type = tree_type(ref);
if (type_is_array(type) && !type_const_bounds(type)) {
assert(vcode_reg_kind(nets) == VCODE_TYPE_UARRAY);
vcode_reg_t last_reg = emit_last_value(emit_unwrap(nets));
return lower_wrap_with_new_bounds(lu, type, type, nets, last_reg);
if (type_is_homogeneous(type)) {
vcode_reg_t data_reg = emit_last_value(lower_array_data(nets));
if (vcode_reg_kind(nets) == VCODE_TYPE_UARRAY)
return lower_rewrap(data_reg, nets);
else
return data_reg;
}
else {
// Use a helper function to convert a record signal into a record
// containing the resolved values

ident_t base_id = type_ident(type_base_recur(type));
ident_t helper_func = ident_prefix(base_id, ident_new("last_value"), '$');

vcode_reg_t arg_reg = nets;
if (type_is_array(type) && vcode_reg_kind(arg_reg) != VCODE_TYPE_UARRAY)
arg_reg = lower_wrap(lu, type, nets);

vcode_type_t vrtype = lower_func_result_type(type);

vcode_reg_t context_reg = lower_context_for_call(lu, helper_func);
vcode_reg_t args[] = { context_reg, arg_reg };
return emit_fcall(helper_func, vrtype, vrtype, args, 2);
}
else
return emit_last_value(nets);
}

static type_t lower_arg_type(tree_t fcall, int nth)
Expand Down Expand Up @@ -9412,7 +9433,8 @@ static void lower_value_helper(lower_unit_t *lu, object_t *obj)
}
}

static void lower_resolved_helper(lower_unit_t *lu, object_t *obj)
static void lower_resolved_record_fn(lower_unit_t *lu, object_t *obj,
resolved_fn_t fn)
{
tree_t decl = tree_from_object(obj);

Expand Down Expand Up @@ -9446,10 +9468,20 @@ static void lower_resolved_helper(lower_unit_t *lu, object_t *obj)
data_reg = result_reg = emit_index(var, VCODE_INVALID_VAR);

lower_for_each_field_2(lu, type, type, p_reg, data_reg, VCODE_INVALID_REG,
lower_resolved_field_cb, NULL);
lower_resolved_field_cb, fn);
emit_return(result_reg);
}

static void lower_resolved_helper(lower_unit_t *lu, object_t *obj)
{
lower_resolved_record_fn(lu, obj, emit_resolved);
}

static void lower_last_value_helper(lower_unit_t *lu, object_t *obj)
{
lower_resolved_record_fn(lu, obj, emit_last_value);
}

static void lower_copy_helper(lower_unit_t *lu, object_t *obj)
{
tree_t decl = tree_from_object(obj);
Expand Down Expand Up @@ -9766,6 +9798,10 @@ static void lower_decl(lower_unit_t *lu, tree_t decl)
ident_t resolved = ident_prefix(id, ident_new("resolved"), '$');
unit_registry_defer(lu->registry, resolved, lu, emit_function,
lower_resolved_helper, NULL, obj);

ident_t last_value = ident_prefix(id, ident_new("last_value"), '$');
unit_registry_defer(lu->registry, last_value, lu, emit_function,
lower_last_value_helper, NULL, obj);
}

if (!lower_trivially_copyable(type)) {
Expand Down
29 changes: 29 additions & 0 deletions test/regress/issue1043.vhd
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
entity issue1043 is
end entity;

architecture test of issue1043 is
type t_rec is record
x : integer;
y : real;
end record;

type t_array is array (natural range <>) of t_rec;

signal s : t_rec := (6, 42.0);
signal t : t_array(1 to 3) := (others => (0, 0.0));
begin

process is
begin
assert s'last_value = (6, 42.0);
assert t'last_value(1) = (0, 0.0);
s <= (4, 22.0);
wait for 1 ns;
assert s'last_value.x = 6;
t(3) <= (8, 55.0);
wait for 1 ns;
assert t'last_value = (1 to 3 => (0, 0.0));
wait;
end process;

end architecture;
1 change: 1 addition & 0 deletions test/regress/testlist.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1060,3 +1060,4 @@ vlog12 verilog
conv15 normal
cover25 cover=functional
issue1035 normal,vhpi,2008
issue1043 normal

0 comments on commit 5cb8638

Please sign in to comment.