From ecb8716785e3050e4cb4cc3b5c327844abf44fd5 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Sat, 14 Aug 2021 12:14:04 +0800 Subject: [PATCH] Inch closer to record nirvana --- src/cgen.c | 2 + src/lower.c | 38 +++++++++--- src/rt/rtkern.c | 122 +++++++++++++++++++------------------- test/regress/record14.vhd | 4 +- 4 files changed, 94 insertions(+), 72 deletions(-) diff --git a/src/cgen.c b/src/cgen.c index ba29423d..546379ff 100644 --- a/src/cgen.c +++ b/src/cgen.c @@ -2798,6 +2798,7 @@ static void cgen_op_init_signal(int op, cgen_ctx_t *ctx) LLVMBuildExtractValue(builder, sigptr, 0, "shared"), LLVMBuildExtractValue(builder, sigptr, 1, "offset"), cgen_get_arg(op, 2, ctx), + cgen_get_arg(op, 3, ctx), llvm_void_cast(cgen_pointer_to_arg_data(op, 1, ctx)) }; LLVMBuildCall(builder, llvm_fn("_init_signal"), args, ARRAY_LEN(args), ""); @@ -3786,6 +3787,7 @@ static LLVMValueRef cgen_support_fn(const char *name) LLVMPointerType(llvm_signal_shared_struct(), 0), LLVMInt32Type(), LLVMInt32Type(), + LLVMInt32Type(), llvm_void_ptr(), }; fn = LLVMAddFunction(module, "_init_signal", diff --git a/src/lower.c b/src/lower.c index 72981ca7..1b187941 100644 --- a/src/lower.c +++ b/src/lower.c @@ -2849,8 +2849,15 @@ static vcode_reg_t lower_record_sub_aggregate(tree_t value, type_t type, return lower_record_aggregate(value, true, true, ctx); else if (type_is_scalar(type)) return lower_reify_expr(value); - else - return lower_expr(value, ctx); + else { + vcode_reg_t value_reg = lower_expr(value, ctx); + if (vcode_reg_kind(value_reg) == VCODE_TYPE_UARRAY) { + // This is necessary if the value is used as an initialiser for + // a process or procedure variable + vcode_heap_allocate(value_reg); + } + return value_reg; + } } static vcode_reg_t lower_record_aggregate(tree_t expr, bool nest, @@ -4966,8 +4973,8 @@ static bool lower_resolution_func(type_t type, vcode_res_fn_t **data, return false; } -static void lower_record_sub_signals(type_t type, vcode_reg_t subsig, - vcode_reg_t init_reg) +static vcode_reg_t lower_record_sub_signals(type_t type, vcode_reg_t subsig, + vcode_reg_t init_reg) { const int nfields = type_fields(type); for (int i = 0; i < nfields; i++) { @@ -4975,15 +4982,28 @@ static void lower_record_sub_signals(type_t type, vcode_reg_t subsig, vcode_reg_t field_reg = emit_record_ref(init_reg, i); if (type_is_record(ft)) - lower_record_sub_signals(ft, subsig, init_reg); + subsig = lower_record_sub_signals(ft, subsig, field_reg); else { - vcode_reg_t size_reg = emit_const(vtype_offset(), byte_width(ft)); - vcode_reg_t count_reg = emit_const(vtype_offset(), 1); + vcode_reg_t count_reg; + if (type_is_array(ft)) { + if (!lower_const_bounds(ft)) { + field_reg = emit_load_indirect(field_reg); + count_reg = lower_array_total_len(ft, field_reg); + field_reg = lower_array_data(field_reg); + } + else + count_reg = lower_array_total_len(ft, field_reg); + } + else + count_reg = emit_const(vtype_offset(), 1); + + vcode_reg_t size_reg = emit_const(vtype_offset(), byte_width(ft)); emit_init_signal(subsig, field_reg, count_reg, size_reg, NULL); - if (i + 1 < nfields) - subsig = emit_add(subsig, count_reg); + subsig = emit_add(subsig, count_reg); } } + + return subsig; } static void lower_signal_decl(tree_t decl) diff --git a/src/rt/rtkern.c b/src/rt/rtkern.c index 7ec91ad8..e6458408 100644 --- a/src/rt/rtkern.c +++ b/src/rt/rtkern.c @@ -790,12 +790,12 @@ int64_t _link_generic_s(const char *name) DLLEXPORT void _init_signal(sig_shared_t *ss, uint32_t offset, uint32_t count, - const uint8_t *values) + uint32_t size, const uint8_t *values) { rt_signal_t *s = container_of(ss, rt_signal_t, shared); - TRACE("_init_signal %s values=%s count=%d", istr(e_path(s->enode)), - fmt_values(values, s->size * s->width), count); + TRACE("_init_signal %s+%d values=%s count=%d", istr(e_path(s->enode)), + offset, fmt_values(values, count * size), count); unsigned index = rt_signal_nexus_index(s, offset); while (count > 0) { @@ -1812,6 +1812,62 @@ static unsigned rt_count_scopes(e_node_t e) return sum; } +static void rt_setup_signal(e_node_t e, rt_signal_t *s, unsigned *total_mem) +{ + s->enode = e; + s->width = e_width(e); + s->n_nexus = e_nexuses(e); + s->nexus = xmalloc_array(s->n_nexus, sizeof(rt_nexus_t*)); + s->flags = 0; + + *total_mem += s->n_nexus * sizeof(rt_nexus_t*); + + const e_flags_t flags = e_flags(e); + + unsigned offset = 0; + for (int j = 0; j < s->n_nexus; j++) { + rt_nexus_t *n = &(nexuses[e_pos(e_nexus(e, j))]); + s->nexus[j] = n; + + unsigned o; + for (o = 0; o < n->n_signals; o++) { + if (e_signal(n->enode, o) == e) + break; + } + + if (o == n->n_signals) + fatal_trace("signal %s missing in nexus %s", istr(e_path(e)), + istr(e_ident(n->enode))); + + assert(n->signals[o] == NULL); + n->signals[o] = s; + n->offsets[o] = offset; + + offset += n->width * n->size; + + if (flags & E_F_LAST_VALUE) { + n->flags |= NET_F_LAST_VALUE; + + if (n->last_value == NULL) + n->last_value = xcalloc_array(n->width, n->size); + } + } + + s->size = offset; + + if (flags & E_F_CONTIGUOUS) + s->shared.resolved.displaced = s->nexus[0]->resolved; + else { + s->shared.resolved.displaced = xcalloc(s->size); + s->flags |= NET_F_OWNS_MEM; + } + + if (flags & E_F_LAST_VALUE) { + s->shared.last_value.displaced = xcalloc(s->size); + s->flags |= NET_F_LAST_VALUE; + } +} + static void rt_setup_scopes_recur(e_node_t e, rt_scope_t *parent, unsigned *next_scope, unsigned *total_mem) @@ -1857,64 +1913,8 @@ static void rt_setup_scopes_recur(e_node_t e, rt_scope_t *parent, } } - for (int i = 0; i < nsignals; i++) { - e_node_t s = e_signal(e, i); - - rt_signal_t *r = &(scope->signals[i]); - r->enode = s; - r->width = e_width(s); - r->n_nexus = e_nexuses(s); - r->nexus = xmalloc_array(r->n_nexus, sizeof(rt_nexus_t*)); - r->flags = 0; - - *total_mem += r->n_nexus * sizeof(rt_nexus_t*); - - const e_flags_t flags = e_flags(s); - - unsigned offset = 0; - for (int j = 0; j < r->n_nexus; j++) { - rt_nexus_t *n = &(nexuses[e_pos(e_nexus(s, j))]); - r->nexus[j] = n; - - unsigned o; - for (o = 0; o < n->n_signals; o++) { - if (e_signal(n->enode, o) == s) - break; - } - - if (o == n->n_signals) - fatal_trace("signal %s missing in nexus %s", istr(e_path(s)), - istr(e_ident(n->enode))); - - assert(n->signals[o] == NULL); - n->signals[o] = r; - n->offsets[o] = offset; - - offset += n->width * n->size; - - if (flags & E_F_LAST_VALUE) { - n->flags |= NET_F_LAST_VALUE; - - if (n->last_value == NULL) - n->last_value = xcalloc_array(n->width, n->size); - } - - // TODO: doesn't work with records but this is only used for debug - r->size = n->size; - } - - if (flags & E_F_CONTIGUOUS) - r->shared.resolved.displaced = r->nexus[0]->resolved; - else { - r->shared.resolved.displaced = xcalloc_array(r->width, r->size); - r->flags |= NET_F_OWNS_MEM; - } - - if (flags & E_F_LAST_VALUE) { - r->shared.last_value.displaced = xcalloc_array(r->width, r->size); - r->flags |= NET_F_LAST_VALUE; - } - } + for (int i = 0; i < nsignals; i++) + rt_setup_signal(e_signal(e, i), &(scope->signals[i]), total_mem); } const int nscopes = e_scopes(e); diff --git a/test/regress/record14.vhd b/test/regress/record14.vhd index a859ba9d..b385f7d9 100644 --- a/test/regress/record14.vhd +++ b/test/regress/record14.vhd @@ -35,7 +35,7 @@ architecture test of sub is return r.z; end function; - signal s : rec; + signal s : rec := (1, (1 to N => '0'), 2); signal s2 : rec2; begin @@ -48,7 +48,7 @@ begin assert func(r.y) = N; - assert s = (0, (1 to N => '0'), 0); + assert s = (1, (1 to N => '0'), 2); s.y(1) <= '1'; wait for 1 ns; assert s.y = (1 => '1', 2 to 4 => '0'); -- 2.39.2