From 93341d440d10bd0968ad7b5cd3f4144a94631839 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Sun, 3 Mar 2024 17:50:13 +0000 Subject: [PATCH] Always look up 'instance_name and 'path_name dynamically --- src/common.c | 2 + src/common.h | 2 + src/elab.c | 5 + src/jit/jit-dump.c | 2 +- src/jit/jit-exits.c | 52 ++++++ src/jit/jit-irgen.c | 17 ++ src/jit/jit-priv.h | 1 + src/lower.c | 358 +++++++++++++++++---------------------- src/object.c | 21 ++- src/object.h | 4 +- src/parse.c | 5 +- src/rt/reflect.c | 2 +- src/sem.c | 18 +- src/tree.c | 10 ++ src/tree.h | 11 +- src/vcode.c | 23 ++- src/vcode.h | 2 + test/regress/attr20.vhd | 8 +- test/regress/issue38.vhd | 1 + 19 files changed, 325 insertions(+), 219 deletions(-) diff --git a/src/common.c b/src/common.c index 6e4e053e..ce480e85 100644 --- a/src/common.c +++ b/src/common.c @@ -1084,6 +1084,8 @@ void intern_strings(void) id_cache[W_NVC_VERILOG] = ident_new("NVC.VERILOG"); id_cache[W_NVC_PSL_SUPPORT] = ident_new("NVC.PSL_SUPPORT"); id_cache[W_SHAPE] = ident_new("shape"); + id_cache[W_INSTANCE_NAME] = ident_new("instance_name"); + id_cache[W_PATH_NAME] = ident_new("path_name"); id_cache[W_IEEE_LOGIC_VECTOR] = ident_new("IEEE.STD_LOGIC_1164.STD_LOGIC_VECTOR"); diff --git a/src/common.h b/src/common.h index 2f6c4423..f23081f1 100644 --- a/src/common.h +++ b/src/common.h @@ -246,6 +246,8 @@ typedef enum { W_NEVER_WAITS, W_NVC_VERILOG, W_SHAPE, + W_INSTANCE_NAME, + W_PATH_NAME, NUM_WELL_KNOWN } well_known_t; diff --git a/src/elab.c b/src/elab.c index 669f1baa..4ae56c2f 100644 --- a/src/elab.c +++ b/src/elab.c @@ -245,12 +245,17 @@ static tree_t elab_copy(tree_t t, const elab_ctx_t *ctx) } APUSH(roots, t); // Architecture must be processed last + tree_global_flags_t gflags = 0; + for (int i = 0; i < roots.count; i++) + gflags |= tree_global_flags(roots.items[i]); + new_instance(roots.items, roots.count, ctx->dotted, ctx->prefix, ARRAY_LEN(ctx->prefix)); tree_t copy = roots.items[roots.count - 1]; ACLEAR(roots); + tree_set_global_flags(copy, gflags); return copy; } diff --git a/src/jit/jit-dump.c b/src/jit/jit-dump.c index 79480de6..f44fc828 100644 --- a/src/jit/jit-dump.c +++ b/src/jit/jit-dump.c @@ -88,7 +88,7 @@ const char *jit_exit_name(jit_exit_t exit) "CLEAR_EVENT", "IMPLICIT_EVENT", "ENTER_STATE", "REFLECT_VALUE", "REFLECT_SUBTYPE", "FUNCTION_TRIGGER", "ADD_TRIGGER", "TRANSFER_SIGNAL", "PORT_CONVERSION", "CONVERT_IN", "CONVERT_OUT", "BIND_FOREIGN", - "OR_TRIGGER", + "OR_TRIGGER", "CMP_TRIGGER", "INSTANCE_NAME", }; assert(exit < ARRAY_LEN(names)); return names[exit]; diff --git a/src/jit/jit-exits.c b/src/jit/jit-exits.c index 1f461efe..4f18c953 100644 --- a/src/jit/jit-exits.c +++ b/src/jit/jit-exits.c @@ -344,6 +344,48 @@ void x_func_wait(void) jit_msg(NULL, DIAG_FATAL, "cannot wait inside function call"); } +void x_instance_name(attr_kind_t kind, text_buf_t *tb) +{ + assert(kind == ATTR_INSTANCE_NAME || kind == ATTR_PATH_NAME); + + jit_stack_trace_t *trace = jit_stack_trace(); + for (int i = 0; i < trace->count; i++) { + tree_t where = tree_from_object(trace->frames[i].object); + if (where == NULL) + continue; + + switch (tree_kind(where)) { + case T_BLOCK: + { + tree_t hier = tree_decl(where, 0); + assert(tree_kind(hier) == T_HIER); + + if (kind == ATTR_PATH_NAME) + tb_istr(tb, tree_ident(hier)); + else + tb_istr(tb, tree_ident2(hier)); + } + return; + + case T_PACKAGE: + case T_PACK_BODY: + case T_PACK_INST: + { + tb_append(tb, ':'); + tb_istr(tb, tree_ident(primary_unit_of(where))); + tb_replace(tb, '.', ':'); + tb_downcase(tb); + } + return; + + default: + break; + } + } + + fatal_trace("cannot get instance name"); +} + //////////////////////////////////////////////////////////////////////////////// // Entry point from interpreter or JIT compiled code @@ -1020,6 +1062,16 @@ void __nvc_do_exit(jit_exit_t which, jit_anchor_t *anchor, jit_scalar_t *args, } break; + case JIT_EXIT_INSTANCE_NAME: + { + const attr_kind_t kind = args[0].integer; + + LOCAL_TEXT_BUF tb = tb_new(); + x_instance_name(kind, tb); + ffi_return_string(tb_get(tb), args, tlab); + } + break; + default: fatal_trace("unhandled exit %s", jit_exit_name(which)); } diff --git a/src/jit/jit-irgen.c b/src/jit/jit-irgen.c index 0f0812a3..09a2303d 100644 --- a/src/jit/jit-irgen.c +++ b/src/jit/jit-irgen.c @@ -3511,6 +3511,20 @@ static void irgen_op_bind_foreign(jit_irgen_t *g, int op) macro_reexec(g); } +static void irgen_op_instance_name(jit_irgen_t *g, int op) +{ + irgen_send_args(g, op, 0); + + macro_exit(g, JIT_EXIT_INSTANCE_NAME); + + vcode_reg_t result = vcode_get_result(op); + + const int slots = irgen_slots_for_type(vcode_reg_type(result)); + g->map[result] = j_recv(g, 0); + for (int i = 1; i < slots; i++) + j_recv(g, i); +} + static void irgen_block(jit_irgen_t *g, vcode_block_t block) { vcode_select_block(block); @@ -3906,6 +3920,9 @@ static void irgen_block(jit_irgen_t *g, vcode_block_t block) case VCODE_OP_BIND_FOREIGN: irgen_op_bind_foreign(g, i); break; + case VCODE_OP_INSTANCE_NAME: + irgen_op_instance_name(g, i); + break; default: fatal_trace("cannot generate JIT IR for vcode op %s", vcode_op_string(op)); diff --git a/src/jit/jit-priv.h b/src/jit/jit-priv.h index 43b456fa..737410c3 100644 --- a/src/jit/jit-priv.h +++ b/src/jit/jit-priv.h @@ -167,6 +167,7 @@ typedef enum { JIT_EXIT_BIND_FOREIGN, JIT_EXIT_OR_TRIGGER, JIT_EXIT_CMP_TRIGGER, + JIT_EXIT_INSTANCE_NAME, } jit_exit_t; typedef uint16_t jit_reg_t; diff --git a/src/lower.c b/src/lower.c index 2da3c233..8ecf10ec 100644 --- a/src/lower.c +++ b/src/lower.c @@ -1258,17 +1258,10 @@ static void get_hierarchical_name(text_buf_t *tb, lower_unit_t *lu, { switch (tree_kind(lu->container)) { case T_BLOCK: - { - tree_t hier = tree_decl(lu->container, 0); - assert(tree_kind(hier) == T_HIER); - - if (which == ATTR_PATH_NAME) - tb_istr(tb, tree_ident(hier)); - else - tb_istr(tb, tree_ident2(hier)); - - tb_append(tb, ':'); - } + case T_PACK_BODY: + case T_PACKAGE: + case T_PACK_INST: + tb_append(tb, ':'); break; case T_PROC_BODY: @@ -1286,16 +1279,6 @@ static void get_hierarchical_name(text_buf_t *tb, lower_unit_t *lu, tb_downcase(tb); break; - case T_PACK_BODY: - case T_PACKAGE: - case T_PACK_INST: - tb_append(tb, ':'); - tb_istr(tb, tree_ident(primary_unit_of(lu->container))); - tb_append(tb, ':'); - tb_replace(tb, '.', ':'); - tb_downcase(tb); - break; - case T_PROCESS: get_hierarchical_name(tb, lu->parent, which); @@ -1311,9 +1294,9 @@ static void get_hierarchical_name(text_buf_t *tb, lower_unit_t *lu, if (standard() < STD_19) { get_hierarchical_name(tb, lu->parent, which); tb_istr(tb, tree_ident(lu->container)); - tb_append(tb, ':'); tb_downcase(tb); } + tb_append(tb, ':'); break; default: @@ -1321,57 +1304,12 @@ static void get_hierarchical_name(text_buf_t *tb, lower_unit_t *lu, } } -static vcode_reg_t lower_dynamic_name_attr(lower_unit_t *lu, const char *suffix, - attr_kind_t which) -{ - assert(standard() >= STD_19); - - ident_t var_name = - ident_new(which == ATTR_PATH_NAME ? "path_name" : "instance_name"); - - int hops = 0; - vcode_var_t var = lower_search_vcode_obj(var_name, lu, &hops); - assert(var != VCODE_INVALID_VAR); - - vcode_reg_t ptr_reg = emit_var_upref(hops, var); - vcode_reg_t array_reg = emit_load_indirect(ptr_reg); - - if (suffix[0] == '\0') - return array_reg; - - vcode_type_t ctype = vtype_char(); - vcode_type_t voffset = vtype_offset(); - - const size_t suffix_len = strlen(suffix); - vcode_reg_t chars[suffix_len]; - - for (int j = 0; j < suffix_len; j++) - chars[j] = emit_const(ctype, suffix[j]); - - vcode_type_t str_type = vtype_carray(suffix_len, ctype, ctype); - vcode_reg_t suffix_reg = emit_const_array(str_type, chars, suffix_len); - - vcode_reg_t prefix_len_reg = emit_uarray_len(array_reg, 0); - vcode_reg_t suffix_len_reg = emit_const(voffset, suffix_len); - vcode_reg_t total_len_reg = emit_add(prefix_len_reg, suffix_len_reg); - vcode_reg_t mem_reg = emit_alloc(ctype, ctype, total_len_reg); - vcode_reg_t suffix_ptr_reg = emit_array_ref(mem_reg, prefix_len_reg); - - emit_copy(mem_reg, emit_unwrap(array_reg), prefix_len_reg); - emit_copy(suffix_ptr_reg, emit_address_of(suffix_reg), suffix_len_reg); - - vcode_dim_t dim0 = { - .left = emit_const(voffset, 1), - .right = total_len_reg, - .dir = emit_const(vtype_bool(), RANGE_TO) - }; - return emit_wrap(mem_reg, &dim0, 1); -} - -static vcode_reg_t lower_name_attr(lower_unit_t *lu, tree_t ref, +static vcode_reg_t lower_name_attr(lower_unit_t *lu, tree_t decl, attr_kind_t which) { - tree_t decl = tree_ref(ref); + LOCAL_TEXT_BUF tb = tb_new(); + lower_unit_t *scope = lu; + int extra_hops = 0; switch (tree_kind(decl)) { case T_PACK_BODY: @@ -1379,115 +1317,45 @@ static vcode_reg_t lower_name_attr(lower_unit_t *lu, tree_t ref, // Fall-through case T_PACKAGE: case T_PACK_INST: - { - LOCAL_TEXT_BUF tb = tb_new(); - tb_append(tb, ':'); - tb_istr(tb, tree_ident(decl)); - tb_append(tb, ':'); - tb_replace(tb, '.', ':'); - tb_downcase(tb); - return lower_wrap_string(tb_get(tb)); - } + tb_append(tb, ':'); + tb_istr(tb, tree_ident(decl)); + tb_append(tb, ':'); + tb_replace(tb, '.', ':'); + tb_downcase(tb); + return lower_wrap_string(tb_get(tb)); case T_INSTANCE: - { - ident_t dname = tree_ident(decl); - lower_unit_t *it; - for (it = lu; it != NULL; it = it->parent) { - if (tree_ident(it->container) == dname) - break; - } - - if (it == NULL) - fatal_trace("cannot find instance %s", istr(tree_ident(decl))); - - LOCAL_TEXT_BUF tb = tb_new(); - get_hierarchical_name(tb, it, which); - return lower_wrap_string(tb_get(tb)); - } + tb_append(tb, ':'); + tb_istr(tb, tree_ident(decl)); + tb_downcase(tb); + break; case T_BLOCK: case T_ENTITY: case T_ARCH: - { - ident_t dname = tree_ident(decl); - lower_unit_t *it; - for (it = lu; it != NULL; it = it->parent) { - if (tree_kind(it->container) != T_BLOCK) - continue; - - tree_t hier = tree_decl(it->container, 0); - assert(tree_kind(hier) == T_HIER); - - tree_t unit = tree_ref(hier); - if (unit == decl || tree_ident(unit) == dname) - break; - else if (tree_ident(primary_unit_of(unit)) == dname) - break; - } - - if (it == NULL) - fatal_trace("cannot find %s %s", tree_kind_str(tree_kind(decl)), - istr(tree_ident(decl))); - - LOCAL_TEXT_BUF tb = tb_new(); - get_hierarchical_name(tb, it, which); - return lower_wrap_string(tb_get(tb)); - } - - case T_PROCESS: - { - lower_unit_t *scope = lu; - while (tree_kind(scope->container) != T_BLOCK) - scope = scope->parent; - - LOCAL_TEXT_BUF tb = tb_new(); - get_hierarchical_name(tb, scope, which); - - if (!(tree_flags(decl) & TREE_F_SYNTHETIC_NAME)) - tb_istr(tb, tree_ident(decl)); - - tb_append(tb, ':'); - tb_downcase(tb); - return lower_wrap_string(tb_get(tb)); - } - case T_PROT_DECL: - { - ident_t id = type_ident(tree_type(decl)); - - if (standard() >= STD_19) { - // LCS-2016-032 dynamic name inside protected body - for (lower_unit_t *it = lu; it != NULL; it = it->parent) { - if (it->name == id) - return lower_dynamic_name_attr(lu, "", which); - } - } + tb_append(tb, ':'); + break; - LOCAL_TEXT_BUF tb = tb_new(); - tb_append(tb, ':'); - tb_istr(tb, id); - tb_replace(tb, '.', ':'); - tb_downcase(tb); - return lower_wrap_string(tb_get(tb)); - } + case T_PROCESS: + tb_append(tb, ':'); + tb_istr(tb, tree_ident(decl)); + tb_append(tb, ':'); + tb_downcase(tb); + break; case T_PROC_DECL: case T_FUNC_DECL: case T_PROC_BODY: case T_FUNC_BODY: - { - lower_unit_t *scope = lu; - while (scope && tree_ident2(decl) != scope->name) - scope = scope->parent; - - if (scope == NULL) - fatal_at(tree_loc(decl), "cannot get hierachical name"); - - LOCAL_TEXT_BUF tb = tb_new(); - get_hierarchical_name(tb, scope, which); - return lower_wrap_string(tb_get(tb)); + for (; scope != NULL; scope = scope->parent, extra_hops++) { + if (decl == scope->container // Work around object copying bug + || tree_ident(decl) == tree_ident(scope->container)) { + get_hierarchical_name(tb, scope, which); + break; + } } + break; case T_VAR_DECL: case T_SIGNAL_DECL: @@ -1497,41 +1365,88 @@ static vcode_reg_t lower_name_attr(lower_unit_t *lu, tree_t ref, case T_GENERIC_DECL: case T_PARAM_DECL: { - LOCAL_TEXT_BUF tb = tb_new(); - tree_t container; - int hops, obj = lower_search_vcode_obj(decl, lu, &hops); - - if (obj == -1 && is_package((container = tree_container(decl)))) { - tb_append(tb, ':'); - tb_istr(tb, tree_ident(primary_unit_of(container))); - tb_replace(tb, '.', ':'); - tb_append(tb, ':'); - tb_istr(tb, tree_ident(decl)); - tb_downcase(tb); - - return lower_wrap_string(tb_get(tb)); - } - else if (obj == -1) - fatal_at(tree_loc(decl), "cannot get hierachical name"); - else { - lower_unit_t *scope = lu; - for (; hops--; scope = scope->parent); + int obj = lower_search_vcode_obj(decl, lu, &extra_hops); + if (obj != -1) { + for (int i = 0; i < extra_hops; i++, scope = scope->parent); get_hierarchical_name(tb, scope, which); + tb_istr(tb, tree_ident(decl)); tb_downcase(tb); - - if (tb_get(tb)[0] == ':') - return lower_wrap_string(tb_get(tb)); - else - return lower_dynamic_name_attr(lu, tb_get(tb), which); } + else + scope = NULL; } + break; default: fatal_trace("cannot handle decl kind %s in lower_name_attr", tree_kind_str(tree_kind(decl))); } + + if (scope == NULL) { + tree_t container = tree_container(decl); + if (is_package((container))) { + tb_append(tb, ':'); + tb_istr(tb, tree_ident(primary_unit_of(container))); + tb_append(tb, ':'); + tb_replace(tb, '.', ':'); + tb_istr(tb, tree_ident(decl)); + if (is_container(decl) || is_subprogram(decl)) + tb_append(tb, ':'); + tb_downcase(tb); + + return lower_wrap_string(tb_get(tb)); + } + + fatal_at(tree_loc(decl), "cannot get hierachical name"); + } + + ident_t var_name = + well_known(which == ATTR_PATH_NAME ? W_PATH_NAME : W_INSTANCE_NAME); + + int hops = 0; + vcode_var_t var = lower_search_vcode_obj(var_name, scope, &hops); + assert(var != VCODE_INVALID_VAR); + + vcode_reg_t array_reg; + if (hops + extra_hops == 0) + array_reg = emit_load(var); + else { + vcode_reg_t ptr_reg = emit_var_upref(hops + extra_hops, var); + array_reg = emit_load_indirect(ptr_reg); + } + + if (tb_len(tb) == 0) + return array_reg; + + vcode_type_t ctype = vtype_char(); + vcode_type_t voffset = vtype_offset(); + + const size_t suffix_len = tb_len(tb); + vcode_reg_t chars[suffix_len]; + + for (int j = 0; j < suffix_len; j++) + chars[j] = emit_const(ctype, tb_get(tb)[j]); + + vcode_type_t str_type = vtype_carray(suffix_len, ctype, ctype); + vcode_reg_t suffix_reg = emit_const_array(str_type, chars, suffix_len); + + vcode_reg_t prefix_len_reg = emit_uarray_len(array_reg, 0); + vcode_reg_t suffix_len_reg = emit_const(voffset, suffix_len); + vcode_reg_t total_len_reg = emit_add(prefix_len_reg, suffix_len_reg); + vcode_reg_t mem_reg = emit_alloc(ctype, ctype, total_len_reg); + vcode_reg_t suffix_ptr_reg = emit_array_ref(mem_reg, prefix_len_reg); + + emit_copy(mem_reg, emit_unwrap(array_reg), prefix_len_reg); + emit_copy(suffix_ptr_reg, emit_address_of(suffix_reg), suffix_len_reg); + + vcode_dim_t dim0 = { + .left = emit_const(voffset, 1), + .right = total_len_reg, + .dir = emit_const(vtype_bool(), RANGE_TO) + }; + return emit_wrap(mem_reg, &dim0, 1); } static vcode_reg_t lower_arith(tree_t fcall, subprogram_kind_t kind, @@ -4482,7 +4397,7 @@ static vcode_reg_t lower_protected_init(lower_unit_t *lu, type_t type, tb_append(tb, ':'); tb_downcase(tb); - names[i] = lower_wrap_string(tb_get(tb)); + names[i] = lower_name_attr(lu, decl ?: lu->container, which[i]); } } @@ -5048,10 +4963,11 @@ static vcode_reg_t lower_attr_ref(lower_unit_t *lu, tree_t expr) case ATTR_PATH_NAME: if (lu->mode == LOWER_THUNK) { vcode_type_t vchar = vtype_char(); - return emit_undefined(vtype_uarray(1, vchar, vchar), vchar); + vcode_type_t vstring = vtype_uarray(1, vchar, vchar); + return emit_undefined(vstring, vchar); } else - return lower_name_attr(lu, name, predef); + return lower_name_attr(lu, tree_ref(name), predef); case ATTR_SIMPLE_NAME: { @@ -9779,21 +9695,27 @@ static void lower_protected_body(lower_unit_t *lu, object_t *obj) if (standard() >= STD_19) { // LCS-2016-032 requires dynamic 'PATH_NAME and 'INSTANCE_NAME for // protected type - ident_t path_i = ident_new("path_name"); - ident_t inst_i = ident_new("instance_name"); + ident_t path_i = well_known(W_PATH_NAME); + ident_t inst_i = well_known(W_INSTANCE_NAME); vcode_type_t vchar = vtype_char(); vcode_type_t vstring = vtype_uarray(1, vchar, vchar); vcode_reg_t path_reg = emit_param(vstring, vchar, path_i); vcode_reg_t inst_reg = emit_param(vstring, vchar, inst_i); - vcode_var_t path_var = emit_var(vstring, vchar, path_i, VAR_CONST); - lower_put_vcode_obj(path_i, path_var, lu); - emit_store(path_reg, path_var); + const tree_global_flags_t gflags = tree_global_flags(body); - vcode_var_t inst_var = emit_var(vstring, vchar, inst_i, VAR_CONST); - lower_put_vcode_obj(inst_i, inst_var, lu); - emit_store(inst_reg, inst_var); + if (gflags & TREE_GF_INSTANCE_NAME) { + vcode_var_t path_var = emit_var(vstring, vchar, path_i, VAR_CONST); + lower_put_vcode_obj(path_i, path_var, lu); + emit_store(path_reg, path_var); + } + + if (gflags & TREE_GF_PATH_NAME) { + vcode_var_t inst_var = emit_var(vstring, vchar, inst_i, VAR_CONST); + lower_put_vcode_obj(inst_i, inst_var, lu); + emit_store(inst_reg, inst_var); + } lower_decls(lu, tree_primary(body)); } @@ -12616,6 +12538,21 @@ static bool lower_push_package_scope(tree_t pack) return false; } +static void lower_cache_instance_name(lower_unit_t *lu, attr_kind_t which) +{ + ident_t name = + well_known(which == ATTR_INSTANCE_NAME ? W_INSTANCE_NAME : W_PATH_NAME); + + vcode_type_t vchar = vtype_char(); + vcode_type_t vstring = vtype_uarray(1, vchar, vchar); + vcode_var_t var = emit_var(vstring, vchar, name, VAR_CONST); + vcode_reg_t kind_reg = emit_const(vtype_offset(), which); + vcode_reg_t str_reg = emit_instance_name(kind_reg); + emit_store(str_reg, var); + + lower_put_vcode_obj(name, var, lu); +} + static void lower_pack_body(lower_unit_t *lu, object_t *obj) { tree_t body = tree_from_object(obj); @@ -12630,6 +12567,15 @@ static void lower_pack_body(lower_unit_t *lu, object_t *obj) emit_package_init(ieee_support, VCODE_INVALID_REG); } + tree_global_flags_t gflags = tree_global_flags(body); + gflags |= tree_global_flags(pack); + + if (gflags & TREE_GF_INSTANCE_NAME) + lower_cache_instance_name(lu, ATTR_INSTANCE_NAME); + + if (gflags & TREE_GF_PATH_NAME) + lower_cache_instance_name(lu, ATTR_PATH_NAME); + lower_dependencies(lu, body); const bool has_scope = @@ -12872,6 +12818,16 @@ lower_unit_t *lower_instance(unit_registry_t *ur, lower_unit_t *parent, if (lu->cover != NULL) cover_ignore_from_pragmas(lu->cover, unit); + tree_global_flags_t gflags = tree_global_flags(unit); + if (primary != NULL) + gflags |= tree_global_flags(primary); + + if (gflags & TREE_GF_INSTANCE_NAME) + lower_cache_instance_name(lu, ATTR_INSTANCE_NAME); + + if (gflags & TREE_GF_PATH_NAME) + lower_cache_instance_name(lu, ATTR_PATH_NAME); + lower_dependencies(lu, block); lower_generics(lu, block, primary); lower_ports(lu, ds, block); diff --git a/src/object.c b/src/object.c index aba1bdd3..648b1860 100644 --- a/src/object.c +++ b/src/object.c @@ -41,13 +41,12 @@ typedef struct _object_arena { void *base; void *alloc; void *limit; - bool frozen; - bool has_locus; uint32_t *forward; mark_mask_t *mark_bits; size_t mark_sz; size_t mark_low; size_t mark_high; + uint32_t flags; generation_t generation; arena_key_t key; arena_array_t deps; @@ -55,6 +54,8 @@ typedef struct _object_arena { obj_src_t source; vhdl_standard_t std; uint32_t checksum; + bool frozen; + bool has_locus; } object_arena_t; #ifndef __SANITIZE_ADDRESS__ @@ -197,6 +198,16 @@ bool arena_frozen(object_arena_t *arena) return arena->frozen; } +uint32_t arena_flags(object_arena_t *arena) +{ + return arena->flags; +} + +void arena_set_flags(object_arena_t *arena, uint32_t flags) +{ + arena->flags |= flags; +} + object_arena_t *object_arena(object_t *object) { return __object_arena(object); @@ -388,7 +399,7 @@ static void check_frozen_object_fault(int sig, void *addr, } } -void object_one_time_init(void) +static void object_one_time_init(void) { INIT_ONCE({ extern object_class_t tree_object; @@ -405,7 +416,7 @@ void object_one_time_init(void) // Increment this each time a incompatible change is made to // the on-disk format not expressed in the object items table - const uint32_t format_fudge = 37; + const uint32_t format_fudge = 38; format_digest += format_fudge * UINT32_C(2654435761); @@ -840,6 +851,7 @@ void object_write(object_t *root, fbuf_t *f, ident_wr_ctx_t ident_ctx, fatal_trace("arena %s must be frozen before writing to disk", istr(object_arena_name(arena))); + fbuf_put_uint(f, arena->flags); fbuf_put_uint(f, arena->key); ident_write(object_arena_name(arena), ident_ctx); @@ -964,6 +976,7 @@ object_t *object_read(fbuf_t *f, object_load_fn_t loader_fn, object_arena_t *arena = object_arena_new(size, std); arena->source = OBJ_DISK; + arena->flags = fbuf_get_uint(f); arena_key_t key = fbuf_get_uint(f); ident_t name = ident_read(ident_ctx); diff --git a/src/object.h b/src/object.h index 759a3f25..9246c23a 100644 --- a/src/object.h +++ b/src/object.h @@ -1,5 +1,5 @@ // -// Copyright (C) 2013-2022 Nick Gasson +// Copyright (C) 2013-2024 Nick Gasson // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -244,6 +244,8 @@ size_t object_arena_default_size(void); object_t *arena_root(object_arena_t *arena); void arena_set_checksum(object_arena_t *arena, uint32_t checksum); bool arena_frozen(object_arena_t *arena); +uint32_t arena_flags(object_arena_t *arena); +void arena_set_flags(object_arena_t *arena, uint32_t flags); void object_write(object_t *object, fbuf_t *f, ident_wr_ctx_t ident_ctx, loc_wr_ctx_t *loc_ctx); diff --git a/src/parse.c b/src/parse.c index 5862d7a5..b3f14e07 100644 --- a/src/parse.c +++ b/src/parse.c @@ -2507,6 +2507,8 @@ static void package_body_deferred_instantiation(tree_t pack, tree_t container) // generic-mapped subprogram body occurs at the end of the package // body corresponding to the enclosing package declaration + assert(standard() >= STD_08); + const int ndecls = tree_decls(pack); for (int i = 0; i < ndecls; i++) { tree_t decl = tree_decl(pack, i); @@ -7024,6 +7026,7 @@ static tree_t p_subprogram_instantiation_declaration(void) else { // Will be instantiated at end of package body tree_set_ref(inst, decl); + tree_set_global_flags(inst, TREE_GF_DEFERRED_INST); } } else @@ -12828,7 +12831,7 @@ static tree_t p_package_body(tree_t unit) p_package_body_declarative_part(body); - if (standard() >= STD_08 && pack != NULL) + if (pack != NULL && (tree_global_flags(pack) & TREE_GF_DEFERRED_INST)) package_body_deferred_instantiation(pack, body); pop_scope(nametab); diff --git a/src/rt/reflect.c b/src/rt/reflect.c index 197b6672..bb61d5fe 100644 --- a/src/rt/reflect.c +++ b/src/rt/reflect.c @@ -411,7 +411,7 @@ static ffi_uarray_t *get_string(const char *str) static internal_cache_pt *get_cache(void *context) { // This will break if the package layout ever changes - internal_cache_pt *pt = *(internal_cache_pt **)(context + sizeof(void *)); + internal_cache_pt *pt = *(internal_cache_pt **)(context + 7*sizeof(void *)); assert(pt->f_canary1 == 0xdeadbeef); assert(pt->f_canary2 == 0xcafebabe); assert(pt->context == context); diff --git a/src/sem.c b/src/sem.c index 4aa29c3c..621ebab7 100644 --- a/src/sem.c +++ b/src/sem.c @@ -1064,6 +1064,9 @@ static bool sem_check_var_decl(tree_t t, nametab_t *tab) } } + if (type_is_protected(type) && standard() >= STD_19) + tree_set_global_flags(t, TREE_GF_INSTANCE_NAME | TREE_GF_PATH_NAME); + return true; } @@ -4044,6 +4047,11 @@ static bool sem_check_attr_ref(tree_t t, bool allow_range, nametab_t *tab) return false; } + if (predef == ATTR_INSTANCE_NAME) + tree_set_global_flags(t, TREE_GF_INSTANCE_NAME); + else if (predef == ATTR_PATH_NAME) + tree_set_global_flags(t, TREE_GF_PATH_NAME); + switch (predef) { case ATTR_RANGE: case ATTR_REVERSE_RANGE: @@ -5920,9 +5928,13 @@ static bool sem_check_new(tree_t t, nametab_t *tab) else if (type_is_incomplete(type)) sem_error(t, "incomplete type %s found in allocator expression", type_pp(type)); - else if (has_initial && type_is_protected(type)) - sem_error(t, "protected type %s cannot have initial value", - type_pp(type)); + else if (type_is_protected(type)) { + if (has_initial) + sem_error(t, "protected type %s cannot have initial value", + type_pp(type)); + else if (standard() >= STD_19) + tree_set_global_flags(t, TREE_GF_INSTANCE_NAME | TREE_GF_PATH_NAME); + } type_t designated = type_designated(access_type); diff --git a/src/tree.c b/src/tree.c index 26672529..5048cc9e 100644 --- a/src/tree.c +++ b/src/tree.c @@ -1395,3 +1395,13 @@ tree_t tree_from_object(object_t *obj) else return NULL; } + +tree_global_flags_t tree_global_flags(tree_t t) +{ + return arena_flags(object_arena(&(t->object))); +} + +void tree_set_global_flags(tree_t t, tree_global_flags_t flags) +{ + arena_set_flags(object_arena(&(t->object)), flags); +} diff --git a/src/tree.h b/src/tree.h index 89a49bfb..723037c9 100644 --- a/src/tree.h +++ b/src/tree.h @@ -1,5 +1,5 @@ // -// Copyright (C) 2011-2023 Nick Gasson +// Copyright (C) 2011-2024 Nick Gasson // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -414,6 +414,12 @@ typedef enum { TREE_F_SEQ_BLOCK = (1 << 25), } tree_flags_t; +typedef enum { + TREE_GF_INSTANCE_NAME = (1 << 0), + TREE_GF_PATH_NAME = (1 << 1), + TREE_GF_DEFERRED_INST = (1 << 2), +} tree_global_flags_t; + tree_t tree_new(tree_kind_t kind); tree_kind_t tree_kind(tree_t t); void tree_change_kind(tree_t t, tree_kind_t kind); @@ -624,4 +630,7 @@ int tree_stable_compar(const void *pa, const void *pb); object_t *tree_to_object(tree_t t); tree_t tree_from_object(object_t *obj); +tree_global_flags_t tree_global_flags(tree_t t); +void tree_set_global_flags(tree_t t, tree_global_flags_t flags); + #endif // _TREE_H diff --git a/src/vcode.c b/src/vcode.c index 27ffffcc..5df2ed25 100644 --- a/src/vcode.c +++ b/src/vcode.c @@ -966,7 +966,7 @@ const char *vcode_op_string(vcode_op_t op) "trap exp", "implicit event", "enter state", "reflect value", "reflect subtype", "function trigger", "add trigger", "transfer signal", "port conversion", "convert in", "convert out", "bind foreign", - "or trigger", "cmp trigger" + "or trigger", "cmp trigger", "instance name", }; if ((unsigned)op >= ARRAY_LEN(strs)) return "???"; @@ -2318,6 +2318,15 @@ void vcode_dump_with_mark(int mark_op, vcode_dump_fn_t callback, void *arg) } } break; + + case VCODE_OP_INSTANCE_NAME: + { + col += vcode_dump_reg(op->result); + col += color_printf(" := %s ", vcode_op_string(op->kind)); + col += vcode_dump_reg(op->args.items[0]); + vcode_dump_result_type(col, op); + } + break; } if (j == mark_op && i == old_block) @@ -6005,6 +6014,18 @@ void emit_bind_foreign(vcode_reg_t spec, vcode_reg_t length, vcode_reg_t locus) "locus argument to bind foreign value must be a debug locus"); } +vcode_reg_t emit_instance_name(vcode_reg_t kind) +{ + op_t *op = vcode_add_op(VCODE_OP_INSTANCE_NAME); + vcode_add_arg(op, kind); + + VCODE_ASSERT(vcode_reg_kind(kind) == VCODE_TYPE_OFFSET, + "kind argument to instance name must be offset"); + + vcode_type_t vchar = vtype_char(); + return (op->result = vcode_add_reg(vtype_uarray(1, vchar, vchar))); +} + void vcode_walk_dependencies(vcode_unit_t vu, vcode_dep_fn_t fn, void *ctx) { vcode_select_unit(vu); diff --git a/src/vcode.h b/src/vcode.h index 76652fa5..9ace6c0c 100644 --- a/src/vcode.h +++ b/src/vcode.h @@ -166,6 +166,7 @@ typedef enum { VCODE_OP_BIND_FOREIGN, VCODE_OP_OR_TRIGGER, VCODE_OP_CMP_TRIGGER, + VCODE_OP_INSTANCE_NAME, } vcode_op_t; typedef enum { @@ -527,5 +528,6 @@ vcode_reg_t emit_port_conversion(vcode_reg_t driving, vcode_reg_t effective); void emit_convert_in(vcode_reg_t conv, vcode_reg_t nets, vcode_reg_t count); void emit_convert_out(vcode_reg_t conv, vcode_reg_t nets, vcode_reg_t count); void emit_bind_foreign(vcode_reg_t spec, vcode_reg_t length, vcode_reg_t locus); +vcode_reg_t emit_instance_name(vcode_reg_t kind); #endif // _VCODE_H diff --git a/test/regress/attr20.vhd b/test/regress/attr20.vhd index 44728554..394d10fa 100644 --- a/test/regress/attr20.vhd +++ b/test/regress/attr20.vhd @@ -59,9 +59,9 @@ package body P is -- C'PATH_NAME = ":lib:p:c" procedure check (p, i, s : string) is begin - assert IncCounter'path_name = p report IncCounter'path_name; - assert IncCounter'instance_name = i report IncCounter'instance_name; - assert IncPt1'path_name = s report IncPt1'path_name; + assert IncCounter'path_name = p report IncCounter'path_name & " != " & p; + assert IncCounter'instance_name = i report IncCounter'instance_name & " != " & i; + assert IncPt1'path_name = s report IncPt1'path_name & " != " & s; end procedure; end protected body IncPt1; @@ -131,8 +131,6 @@ begin archinc.check(":top:e:archinc:inccounter", ":top(top):e@e(a):archinc:inccounter", ":top:e:archinc:"); - - assert incpt1'path_name = ":lib:p:incpt1"; wait; end process p1; diff --git a/test/regress/issue38.vhd b/test/regress/issue38.vhd index 7b653ea2..65f8d76c 100644 --- a/test/regress/issue38.vhd +++ b/test/regress/issue38.vhd @@ -25,6 +25,7 @@ architecture a of issue38 is begin assert g'instance_name = ":issue38(a):g:"; assert g'path_name = ":issue38:g:"; + assert f'instance_name = ":work:p:f:" report f'instance_name; return 0; end function g; begin -- 2.39.2