Skip to content

Commit

Permalink
Reflection for unconstrained record elements
Browse files Browse the repository at this point in the history
  • Loading branch information
nickg committed Jul 29, 2023
1 parent 5b4050d commit 2bf0278
Show file tree
Hide file tree
Showing 9 changed files with 88 additions and 19 deletions.
2 changes: 2 additions & 0 deletions src/jit/jit-irgen.c
Original file line number Diff line number Diff line change
Expand Up @@ -2369,6 +2369,8 @@ static void irgen_op_reflect_value(jit_irgen_t *g, int op)
else
j_send(g, 3, irgen_get_value(g, vreg));
}
else
j_send(g, 3, value);

macro_exit(g, JIT_EXIT_REFLECT_VALUE);

Expand Down
2 changes: 1 addition & 1 deletion src/jit/jit-layout.c
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ const jit_layout_t *layout_of(type_t type)
l->parts[0].align = l->parts[0].size;

l->parts[1].offset = sizeof(void *);
l->parts[1].size = sizeof(int32_t);
l->parts[1].size = sizeof(int64_t);
l->parts[1].repeat = ndims * 2;
l->parts[1].align = l->parts[1].size;
}
Expand Down
50 changes: 33 additions & 17 deletions src/rt/reflect.c
Original file line number Diff line number Diff line change
Expand Up @@ -278,25 +278,36 @@ static jit_scalar_t load_scalar(const void *base, size_t off, size_t size)
return elt;
}

static jit_scalar_t *get_array_bounds(type_t type)
static jit_scalar_t *get_array_bounds(type_t type, void *ptr)
{
const int ndims = dimension_of(type);

jit_scalar_t *fbounds = xmalloc_array(ndims*2 + 1, sizeof(jit_scalar_t));
fbounds[0].pointer = NULL;

for (int i = 0; i < ndims; i++) {
tree_t r = range_of(type, i);
if (type_is_unconstrained(type)) {
ffi_uarray_t *u = ptr;
fbounds[0].pointer = u->ptr;

for (int i = 0; i < ndims; i++) {
fbounds[i*2+1].integer = u->dims[i].left;
fbounds[i*2+2].integer = u->dims[i].length;
}
}
else {
fbounds[0].pointer = ptr;

int64_t left, length;
if (!folded_int(tree_left(r), &left))
goto not_const;
else if (!folded_length(r, &length))
goto not_const;
for (int i = 0; i < ndims; i++) {
tree_t r = range_of(type, i);

const range_kind_t dir = tree_subkind(r);
fbounds[i*2+1].integer = left;
fbounds[i*2+2].integer = (dir == RANGE_DOWNTO ? ~length : length);
int64_t left, length;
if (!folded_int(tree_left(r), &left))
goto not_const;
else if (!folded_length(r, &length))
goto not_const;

const range_kind_t dir = tree_subkind(r);
fbounds[i*2+1].integer = left;
fbounds[i*2+2].integer = (dir == RANGE_DOWNTO ? ~length : length);
}
}

return fbounds;
Expand Down Expand Up @@ -421,8 +432,7 @@ static value_mirror *get_value_mirror(void *context, jit_scalar_t value,
elements[i] = get_value_mirror(context, elt, ft, NULL);
}
else if (type_is_array(ft)) {
jit_scalar_t *fbounds LOCAL = get_array_bounds(ft);
fbounds[0].pointer = ptr;
jit_scalar_t *fbounds LOCAL = get_array_bounds(ft, ptr);
elements[i] = get_value_mirror(context, fbounds[0], ft, fbounds);
}
else {
Expand Down Expand Up @@ -676,14 +686,18 @@ static subtype_mirror *get_subtype_mirror(void *context, type_t type,
rsm->pt.f_fields->dims[0].length = nfields;
rsm->pt.f_fields->ptr = rsm->pt.f_fields + 1;

const jit_layout_t *l = layout_of(type);
assert(l->nparts == nfields);

field_rec *fields = rsm->pt.f_fields->ptr;
for (int i = 0; i < nfields; i++) {
tree_t f = type_field(base, i);
fields[i].f_name = get_string(istr(tree_ident(f)));

type_t ft = tree_type(f);
if (type_is_array(ft)) {
jit_scalar_t *fbounds LOCAL = get_array_bounds(ft);
void *ptr = bounds[0].pointer + l->parts[i].offset;
jit_scalar_t *fbounds LOCAL = get_array_bounds(ft, ptr);
fields[i].f_subtype = get_subtype_mirror(context, ft, fbounds);
}
else
Expand All @@ -708,7 +722,9 @@ void *x_reflect_value(void *context, jit_scalar_t value, tree_t where,

void *x_reflect_subtype(void *context, tree_t where, const jit_scalar_t *bounds)
{
return get_subtype_mirror(context, tree_type(where), bounds);
type_t type = tree_type(where);
assert(!type_is_unconstrained(type)); // Should be caught earlier
return get_subtype_mirror(context, type, bounds);
}

void _std_reflection_init(void)
Expand Down
3 changes: 3 additions & 0 deletions src/sem.c
Original file line number Diff line number Diff line change
Expand Up @@ -3914,6 +3914,9 @@ static bool sem_check_attr_ref(tree_t t, bool allow_range, nametab_t *tab)
if (get_type_or_null(name) == NULL)
sem_error(t, "prefix of attribute REFLECT is not a type mark or "
"an object with a type");
else if (named_type != NULL && type_is_unconstrained(named_type))
sem_error(t, "prefix of 'REFLECT attribute must be a fully "
"constrained subtype");

return true;

Expand Down
45 changes: 45 additions & 0 deletions test/regress/reflect4.vhd
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
entity reflect4 is
end entity;

use std.reflection.all;

architecture test of reflect4 is
type rec1 is record
a, b : integer;
c : string;
end record;
begin

p1: process is
variable v1 : rec1 := (1, 2, "abc");
variable vm : value_mirror;
variable rvm : record_value_mirror;
variable rstm : record_subtype_mirror;
variable astm : array_subtype_mirror;
begin
vm := v1'reflect;
rvm := vm.to_record;
rstm := rvm.get_subtype_mirror;
assert rstm.length = 3;
assert rstm.element_name(0) = "A";
assert rstm.element_name(1) = "B";
assert rstm.element_name(2) = "C";
assert rstm.element_index("B") = 1;
assert rstm.element_subtype("A") = integer'reflect;
assert rstm.element_subtype("C").get_type_class = class_array;

assert rvm.get(0).to_integer.value = 1;
assert rvm.get("b").to_integer.value = 2;

astm := rstm.element_subtype("C").to_array;
assert astm.length = 3;
assert astm.left = 1;
assert astm.right = 3;
assert astm.ascending;

assert rvm.get("c").to_array.get(1).to_enumeration.image = "'a'";
assert rvm.get("c").to_array.get(3).to_enumeration.image = "'c'";
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 @@ -829,3 +829,4 @@ toplevel3 normal,guut.i=2,guut.s=2
predef4 normal,2008
protected11 fail,gold,2002
issue744 normal,vhpi
reflect4 normal,2019
1 change: 1 addition & 0 deletions test/sem/lcs2016_41.vhd
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ begin
astm := stm.to_array; -- OK
vm := p1'reflect; -- Error
assert v'subtype'reflect.get_type_class = CLASS_ARRAY; -- OK
stm := bit_vector'reflect; -- Error
wait;
end process;

Expand Down
2 changes: 1 addition & 1 deletion test/test_jit.c
Original file line number Diff line number Diff line change
Expand Up @@ -867,7 +867,7 @@ START_TEST(test_layout)
ck_assert_int_eq(l->parts[0].repeat, 1);
ck_assert_int_eq(l->parts[0].align, 8);
ck_assert_int_eq(l->parts[1].offset, sizeof(void *));
ck_assert_int_eq(l->parts[1].size, 4);
ck_assert_int_eq(l->parts[1].size, sizeof(int64_t));
ck_assert_int_eq(l->parts[1].repeat, 2);

input_from_file(TESTDIR "/jit/layout.vhd");
Expand Down
1 change: 1 addition & 0 deletions test/test_sem.c
Original file line number Diff line number Diff line change
Expand Up @@ -3099,6 +3099,7 @@ START_TEST(test_lcs2016_41)
{ 19, "value VALUE_MIRROR does not match type of target INTEGER" },
{ 23, "prefix of attribute REFLECT is not a type mark or an object "
"with a type" },
{ 25, "prefix of 'REFLECT attribute must be a fully constrained " },
{ -1, NULL }
};
expect_errors(expect);
Expand Down

0 comments on commit 2bf0278

Please sign in to comment.