From 12a0eb46866af0bcaf78618618156db143647339 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Tue, 6 Feb 2018 19:24:13 +0000 Subject: [PATCH] Implicit resolution function for record types. Fixes #202 --- src/cgen.c | 44 ++++++++++++++-------- src/lower.c | 67 +++++++++++++++++++++++----------- src/rt/rtkern.c | 2 +- test/regress/gold/issue202.txt | 4 ++ test/regress/issue202.vhd | 34 +++++++++++++++++ test/regress/testlist.txt | 1 + tools/ghdl.sh | 3 +- 7 files changed, 117 insertions(+), 38 deletions(-) create mode 100644 test/regress/gold/issue202.txt create mode 100644 test/regress/issue202.vhd diff --git a/src/cgen.c b/src/cgen.c index 1b28ed09..ec8b109a 100644 --- a/src/cgen.c +++ b/src/cgen.c @@ -59,6 +59,7 @@ typedef struct { typedef struct { unsigned count; LLVMValueRef size; + LLVMValueRef resolution; } size_list_t; DECLARE_AND_DEFINE_ARRAY(size_list) @@ -78,6 +79,7 @@ static size_t n_link_args = 0; static size_t max_link_args = 0; static LLVMValueRef cgen_support_fn(const char *name); +static LLVMValueRef cgen_resolution_wrapper(ident_t name, vcode_type_t type); static LLVMValueRef llvm_int1(bool b) { @@ -1619,19 +1621,34 @@ static void cgen_op_sched_waveform(int op, cgen_ctx_t *ctx) } static void cgen_append_size_list(size_list_array_t *list, - vcode_type_t elem, unsigned count) + vcode_type_t elem, unsigned count, + const vcode_res_fn_t *resolution, + size_t *res_elem) { size_list_t *result = size_list_array_alloc(list); result->size = llvm_sizeof(cgen_type(elem)); result->count = count; + + if (resolution != NULL) { + assert(*res_elem < resolution->count); + + result->resolution = + cgen_resolution_wrapper(resolution->element[*res_elem].name, + resolution->element[*res_elem].type); + + ++(*res_elem); + } + else + result->resolution = LLVMConstNull(llvm_void_ptr()); } -static void cgen_size_list(size_list_array_t *list, vcode_type_t type) +static void cgen_size_list(size_list_array_t *list, vcode_type_t type, + const vcode_res_fn_t *resolution, size_t *res_elem) { switch (vtype_kind(type)) { case VCODE_TYPE_INT: case VCODE_TYPE_REAL: - cgen_append_size_list(list, type, 1); + cgen_append_size_list(list, type, 1, resolution, res_elem); break; case VCODE_TYPE_CARRAY: { @@ -1639,17 +1656,18 @@ static void cgen_size_list(size_list_array_t *list, vcode_type_t type) if (vtype_kind(elem) == VCODE_TYPE_RECORD) { const int nelems = vtype_size(type); for (int i = 0; i < nelems; i++) - cgen_size_list(list, elem); + cgen_size_list(list, elem, resolution, res_elem); } else - cgen_append_size_list(list, elem, vtype_size(type)); + cgen_append_size_list(list, elem, vtype_size(type), + resolution, res_elem); } break; case VCODE_TYPE_RECORD: { const int nfields = vtype_fields(type); for (int i = 0; i < nfields; i++) - cgen_size_list(list, vtype_field(type, i)); + cgen_size_list(list, vtype_field(type, i), resolution, res_elem); } break; default: @@ -1735,20 +1753,16 @@ static void cgen_op_set_initial(int op, cgen_ctx_t *ctx) LLVMValueRef valptr = cgen_pointer_to_arg_data(op, 0, ctx); + const vcode_res_fn_t *rdata = vcode_get_resolution(op); + + size_t res_elem = 0; size_list_array_t size_list = { 0, NULL }; - cgen_size_list(&size_list, type); + cgen_size_list(&size_list, type, rdata, &res_elem); LLVMValueRef list_mem = LLVMBuildArrayAlloca(builder, llvm_size_list_type(), llvm_int32(size_list.count), "size_list"); - LLVMValueRef resolution = NULL; - const vcode_res_fn_t *rdata = vcode_get_resolution(op); - if (rdata != NULL) - resolution = cgen_resolution_wrapper(rdata->element[0].name, rdata->element[0].type); - else - resolution = LLVMConstNull(llvm_void_ptr()); - for (unsigned i = 0; i < size_list.count; i++) { LLVMValueRef offset[] = { llvm_int32(i) }; LLVMValueRef elemptr = LLVMBuildGEP(builder, list_mem, offset, 1, ""); @@ -1757,7 +1771,7 @@ static void cgen_op_set_initial(int op, cgen_ctx_t *ctx) LLVMBuildStructGEP(builder, elemptr, 0, "")); LLVMBuildStore(builder, llvm_int32(size_list.items[i].count), LLVMBuildStructGEP(builder, elemptr, 1, "")); - LLVMBuildStore(builder, resolution, + LLVMBuildStore(builder, size_list.items[i].resolution, LLVMBuildStructGEP(builder, elemptr, 2, "")); } diff --git a/src/lower.c b/src/lower.c index 7d871944..2041c583 100644 --- a/src/lower.c +++ b/src/lower.c @@ -4267,6 +4267,48 @@ static void lower_var_decl(tree_t decl) emit_store(value, var); } +static bool lower_resolution_func(type_t type, vcode_res_fn_t **data, + size_t *max_elems) +{ + if (type_is_array(type)) + return lower_resolution_func(type_elem(type), data, max_elems); + else if (type_kind(type) == T_SUBTYPE && type_has_resolution(type)) { + ident_t rfunc = lower_mangle_func(tree_ref(type_resolution(type)), + vcode_unit_context()); + vcode_type_t rtype = lower_type(type); + + if (*data == NULL) { + *data = xmalloc(sizeof(vcode_res_fn_t) + sizeof(vcode_res_elem_t)); + (*data)->count = 1; + *max_elems = 1; + } + else if ((*data)->count == *max_elems) { + *max_elems *= 4; + const size_t newsz = + sizeof(vcode_res_fn_t) + *max_elems * sizeof(vcode_res_elem_t); + *data = xrealloc(*data, newsz); + (*data)->count++; + } + + (*data)->element[(*data)->count - 1].name = rfunc; + (*data)->element[(*data)->count - 1].type = rtype; + + return true; + } + else if (type_is_record(type)) { + const int nfields = type_fields(type); + for (int i = 0; i < nfields; i++) { + type_t ftype = tree_type(type_field(type, i)); + if (!lower_resolution_func(ftype, data, max_elems)) + return false; + } + + return true; + } + else + return false; +} + static void lower_signal_decl(tree_t decl) { int nnets = tree_nets(decl); @@ -4329,28 +4371,11 @@ static void lower_signal_decl(tree_t decl) init_reg = lower_array_data(init_reg); } - ident_t rfunc = NULL; - vcode_type_t rtype = VCODE_INVALID_TYPE; - - type_t rbase = type; - while (type_is_array(rbase) - && (type_kind(rbase) != T_SUBTYPE - || !type_has_resolution(rbase))) - rbase = type_elem(rbase); - - if (type_kind(rbase) == T_SUBTYPE && type_has_resolution(rbase)) { - rfunc = lower_mangle_func(tree_ref(type_resolution(rbase)), - vcode_unit_context()); - rtype = lower_type(rbase); - } - vcode_res_fn_t *resolution = NULL; - if (rfunc != NULL) { - resolution = - xmalloc(sizeof(vcode_res_fn_t) + sizeof(vcode_res_elem_t)); - resolution->count = 1; - resolution->element[0].name = rfunc; - resolution->element[0].type = rtype; + size_t max_elems = 0; + if (!lower_resolution_func(type, &resolution, &max_elems)) { + free(resolution); + resolution = NULL; } emit_set_initial(sig, init_reg, resolution); diff --git a/src/rt/rtkern.c b/src/rt/rtkern.c index aba71c2a..ed89fe13 100644 --- a/src/rt/rtkern.c +++ b/src/rt/rtkern.c @@ -615,7 +615,7 @@ void _set_initial(int32_t nid, const uint8_t *values, RT_ASSERT(tree_kind(decl) == T_SIGNAL_DECL); TRACE("_set_initial %s values=%s nparts=%d", name, - fmt_values(values, size_list[0].count * size_list[1].size), nparts); + fmt_values(values, size_list[0].count * size_list[0].size), nparts); int total_size = 0; for (int i = 0; i < nparts; i++) diff --git a/test/regress/gold/issue202.txt b/test/regress/gold/issue202.txt new file mode 100644 index 00000000..41c3a08b --- /dev/null +++ b/test/regress/gold/issue202.txt @@ -0,0 +1,4 @@ +0ms+0: Report Note: 'U' +0ms+0: Report Note: 'U''U' +0ms+1: Report Note: 'X' +0ms+1: Report Note: 'X''0' diff --git a/test/regress/issue202.vhd b/test/regress/issue202.vhd new file mode 100644 index 00000000..d3fc516b --- /dev/null +++ b/test/regress/issue202.vhd @@ -0,0 +1,34 @@ +library ieee; +use ieee.std_logic_1164.all; + +entity issue202 is +end entity; + +architecture a of issue202 is + type rec_t is record + field : std_logic; + field2 : std_logic_vector(1 downto 0); + end record; + + signal sig : rec_t; +begin + + p1 : process + begin + sig <= ('0', "0Z"); + wait; + end process; + + p2 : process + begin + sig <= ('1', "10"); + wait; + end process; + + monitor : process (sig) + begin + report std_logic'image(sig.field); + report std_logic'image(sig.field2(1)) & std_logic'image(sig.field2(0)); + end process; + +end architecture; diff --git a/test/regress/testlist.txt b/test/regress/testlist.txt index 062d89b7..a0bdeaec 100644 --- a/test/regress/testlist.txt +++ b/test/regress/testlist.txt @@ -343,3 +343,4 @@ issue369 normal issue293 normal issue340 normal issue348 normal,2008 +issue202 normal diff --git a/tools/ghdl.sh b/tools/ghdl.sh index b0bc03ae..3156cc55 100755 --- a/tools/ghdl.sh +++ b/tools/ghdl.sh @@ -1,4 +1,5 @@ #!/bin/sh mkdir -p .ghdl ghdl -a --std=02 --workdir=.ghdl ../test/regress/$1.vhd -ghdl --elab-run --std=02 --workdir=.ghdl -o .ghdl/$1 $1 +ghdl -e --std=02 --workdir=.ghdl -o .ghdl/$1 $1 +ghdl -r --std=02 --workdir=.ghdl $1 -- 2.39.2