]> Nick Gasson's Git Repositories - nvc.git/commitdiff
Fix crash with partial association and conversion function master github/master sr.ht/master
authorNick Gasson <nick@nickg.me.uk>
Tue, 18 Feb 2025 08:54:05 +0000 (08:54 +0000)
committerNick Gasson <nick@nickg.me.uk>
Wed, 19 Feb 2025 10:08:22 +0000 (10:08 +0000)
Issue #1161

NEWS.md
src/ident.c
src/ident.h
src/lower.c
src/vlog/vlog-parse.c
src/vlog/vlog-simp.c
test/regress/conv19.vhd [new file with mode: 0644]
test/regress/testlist.txt

diff --git a/NEWS.md b/NEWS.md
index 8f58dbb3c0d9976077b15f912aea831e9b1580be..98999db17b8f295666c089e833e095ecc817ba63 100644 (file)
--- a/NEWS.md
+++ b/NEWS.md
@@ -32,6 +32,8 @@
 - `--ieee-warnings` is now a global option and should be placed before
   the `-r` command.  Passing it to the `-r` command is still supported
   but deprecated and may not take effect in some situations (#1151).
+- Fixed a crash when a partial association in a port map has a
+  conversion function (#1161).
 
 ## Version 1.15.1 - 2025-01-22
 - Fixed a crash when a subprogram is called with too many named arguments
index 8ee7cf5fe6ffff52b955a81ce8901830e754b78b..d7a0a0e6f95281f0d891f8e6cec749f2c8321d9b 100644 (file)
@@ -227,7 +227,8 @@ static ident_t ident_from_bytes(const char *str, hash_state_t hash, size_t len)
             else
                break;
          }
-         else if (id->length == len && memcmp(id->bytes, str, len) == 0)
+         else if (id->length == len && id->hash[0] == hash
+                  && memcmp(id->bytes, str, len) == 0)
             return id;
 
          if (++reprobe == REPROBE_LIMIT) {
@@ -426,10 +427,26 @@ ident_t ident_read(ident_rd_ctx_t ctx)
             fbuf_file_name(ctx->file), index, (int)ctx->cache_sz);
 }
 
-ident_t ident_uniq(const char *prefix)
+ident_t ident_uniq(const char *fmt, ...)
 {
+   va_list ap, ap2;
+   va_start(ap, fmt);
+   va_copy(ap2, ap);
+
+   char buf[64], *prefix = buf;
+   size_t req = vsnprintf(buf, ARRAY_LEN(buf), fmt, ap);
+
+   if (req + 1 > ARRAY_LEN(buf)) {
+      prefix = xmalloc(req + 1);
+      vsnprintf(prefix, req + 1, fmt, ap2);
+   }
+
+   va_end(ap);
+   va_end(ap2);
+
    hash_state_t base_hash = HASH_INIT;
    int len = hash_update(&base_hash, prefix, INT_MAX);
+   assert(len == req);
 
    static volatile int counter = 0;
    char suffix[16] = "";
@@ -441,8 +458,10 @@ ident_t ident_uniq(const char *prefix)
       const size_t len_vec[] = { len, sufflen };
 
       ident_t new = ident_from_byte_vec(hash, true, 2, str_vec, len_vec);
-      if (new != NULL)
+      if (new != NULL) {
+         if (prefix != buf) free(prefix);
          return new;
+      }
 
       checked_sprintf(suffix, sizeof(suffix), "%d", relaxed_add(&counter, 1));
    }
index c6068fbc52dfe57c2c3820f4cc20dc951a74c5a5..98f62fbe9a8d252552fd31e044434b4a7fa620e7 100644 (file)
@@ -25,7 +25,8 @@ ident_t ident_new(const char *str);
 ident_t ident_new_n(const char *str, size_t len);
 
 // Generate a unique identifier with the given prefix.
-ident_t ident_uniq(const char *prefix);
+ident_t ident_uniq(const char *prefix, ...)
+   __attribute__((format(printf, 1, 2)));
 
 ident_t ident_sprintf(const char *fmt, ...)
    __attribute__((format(printf, 1, 2)));
index 4cb4c97cff4249143751baf6af5fe4d5ffb013dd..5ee469200931f12da490586528d421c3a295f6da 100644 (file)
@@ -1959,7 +1959,7 @@ static vcode_var_t lower_temp_var(lower_unit_t *lu, const char *prefix,
    }
 
    if (pos == lu->free_temps.count)
-      return emit_var(vtype, vbounds, ident_uniq(prefix), VAR_TEMP);
+      return emit_var(vtype, vbounds, ident_uniq("%s", prefix), VAR_TEMP);
 
    emit_comment("Reusing temp var %s", istr(vcode_var_name(tmp)));
 
@@ -11754,9 +11754,15 @@ static vcode_reg_t lower_converter(lower_unit_t *parent, tree_t dst, tree_t src,
    vcode_state_t state;
    vcode_state_save(&state);
 
-   ident_t name = ident_sprintf("%s.%s.convert_%s", istr(parent->name),
-                                istr(tree_ident(dst)),
-                                dir == PORT_IN ? "in" : "out");
+   ident_t name;
+   if (tree_kind(dst) == T_PORT_DECL)
+      name = ident_sprintf("%s.%s.convert_%s", istr(parent->name),
+                           istr(tree_ident(dst)),
+                           dir == PORT_IN ? "in" : "out");
+   else
+      name = ident_uniq("%s.%s.convert_%s.part", istr(parent->name),
+                        istr(tree_ident(tree_ref(name_to_ref(dst)))),
+                        dir == PORT_IN ? "in" : "out");
 
    vcode_unit_t vu = emit_function(name, tree_to_object(dst), parent->vunit);
    emit_debug_info(tree_loc(src));
@@ -11998,7 +12004,7 @@ static void lower_convert_signal(lower_unit_t *lu, vcode_reg_t src_reg,
    }
 }
 
-static void lower_inertial_actual(lower_unit_t *parent, tree_t port,
+static void lower_inertial_actual(lower_unit_t *parent, tree_t dst,
                                   type_t type, vcode_reg_t port_reg,
                                   tree_t actual)
 {
@@ -12007,18 +12013,18 @@ static void lower_inertial_actual(lower_unit_t *parent, tree_t port,
 
    assert(standard() >= STD_08);
 
-   LOCAL_TEXT_BUF tb = tb_new();
-   tb_istr(tb, tree_ident(port));
-   tb_cat(tb, "_actual");
-
-   ident_t name = ident_uniq(tb_get(tb));
+   ident_t name;
+   if (tree_kind(dst) == T_PORT_DECL)
+      name = ident_sprintf("%s_actual", istr(tree_ident(dst)));
+   else
+      name = ident_uniq("%s_actual.part", istr(tree_ident(name_to_ref(dst))));
 
    vcode_type_t signal_type = lower_signal_type(type);
    vcode_type_t vbounds = lower_bounds(type);
    vcode_var_t var = emit_var(signal_type, vbounds, name, VAR_SIGNAL);
 
    if (type_is_record(type)) {
-      vcode_reg_t locus = lower_debug_locus(port);
+      vcode_reg_t locus = lower_debug_locus(dst);
       vcode_reg_t ptr_reg = emit_index(var, VCODE_INVALID_REG);
       lower_copy_record(parent, type, ptr_reg, port_reg, locus);
    }
@@ -12098,8 +12104,7 @@ static void lower_port_map(lower_unit_t *lu, tree_t block, tree_t map,
                            vcode_reg_t value_reg)
 {
    vcode_reg_t port_reg = VCODE_INVALID_REG;
-   tree_t port = NULL, view = NULL;
-   type_t name_type = NULL;
+   tree_t view = NULL, name;
    vcode_reg_t out_conv = VCODE_INVALID_REG;
    vcode_reg_t in_conv = VCODE_INVALID_REG;
    tree_t value = tree_value(map);
@@ -12121,8 +12126,7 @@ static void lower_port_map(lower_unit_t *lu, tree_t block, tree_t map,
    switch (tree_subkind(map)) {
    case P_POS:
       {
-         port = tree_port(block, tree_pos(map));
-         name_type = tree_type(port);
+         tree_t port = name = tree_port(block, tree_pos(map));
          mode = tree_subkind(port);
 
          if (mode == PORT_ARRAY_VIEW || mode == PORT_RECORD_VIEW)
@@ -12132,7 +12136,7 @@ static void lower_port_map(lower_unit_t *lu, tree_t block, tree_t map,
          vcode_var_t var = lower_get_var(lu, port, &hops);
          assert(hops == 0);
 
-         if (type_is_homogeneous(name_type))
+         if (type_is_homogeneous(tree_type(port)))
             port_reg = emit_load(var);
          else
             port_reg = emit_index(var, VCODE_INVALID_REG);
@@ -12140,7 +12144,8 @@ static void lower_port_map(lower_unit_t *lu, tree_t block, tree_t map,
       break;
    case P_NAMED:
       {
-         tree_t name = tree_name(map);
+         name = tree_name(map);
+
          const tree_kind_t kind = tree_kind(name);
          if (kind == T_CONV_FUNC || kind == T_TYPE_CONV) {
             tree_t p0 = tree_value(name);
@@ -12149,10 +12154,8 @@ static void lower_port_map(lower_unit_t *lu, tree_t block, tree_t map,
             name = p0;
          }
 
-         port_reg = lower_lvalue(lu, name);
-         port = tree_ref(name_to_ref(name));
+         tree_t port = tree_ref(name_to_ref(name));
          mode = tree_subkind(port);
-         name_type = tree_type(name);
 
          if (mode == PORT_ARRAY_VIEW || mode == PORT_RECORD_VIEW) {
             view = tree_value(port);
@@ -12173,27 +12176,29 @@ static void lower_port_map(lower_unit_t *lu, tree_t block, tree_t map,
                view = tree_value(view);
             }
          }
+
+         port_reg = lower_lvalue(lu, name);
       }
       break;
+   default:
+      should_not_reach_here();
    }
 
-   assert(tree_kind(port) == T_PORT_DECL);
-
    if (value_conv != NULL) {
       // Value has conversion function
-      in_conv = lower_converter(lu, port, value_conv, value, PORT_IN);
+      in_conv = lower_converter(lu, name, value_conv, value, PORT_IN);
       value = value_conv;
    }
 
    if (mode == PORT_ARRAY_VIEW || mode == PORT_RECORD_VIEW) {
       assert(lower_is_signal_ref(value));
-      tree_t view = tree_value(port);
       vcode_reg_t locus = lower_debug_locus(view);
-      lower_for_each_field_2(lu, name_type, tree_type(value), port_reg,
+      lower_for_each_field_2(lu, tree_type(name), tree_type(value), port_reg,
                              value_reg, locus, lower_map_view_field_cb, view);
    }
    else if (lower_is_signal_ref(value)) {
       type_t value_type = tree_type(value);
+      type_t name_type = tree_type(name);
 
       vcode_reg_t src_reg = mode == PORT_IN ? value_reg : port_reg;
       vcode_reg_t dst_reg = mode == PORT_IN ? port_reg : value_reg;
@@ -12213,9 +12218,10 @@ static void lower_port_map(lower_unit_t *lu, tree_t block, tree_t map,
          lower_map_signal(lu, src_reg, dst_reg, src_type, dst_type, map);
    }
    else if (tree_kind(value) == T_INERTIAL)
-      lower_inertial_actual(lu, port, name_type, port_reg, value);
+      lower_inertial_actual(lu, name, tree_type(name), port_reg, value);
    else if (value_reg != VCODE_INVALID_REG) {
       type_t value_type = tree_type(value);
+      type_t name_type = tree_type(name);
       lower_map_signal(lu, value_reg, port_reg, value_type, name_type, map);
    }
 }
index 6bc948429d290da1f90cb543038a0a7fb4430b21..1cab4fe4c3ec0d56f77277c0f0fbd37bb75a3512 100644 (file)
@@ -2096,10 +2096,7 @@ static vlog_node_t p_always_construct(void)
    consume(tALWAYS);
 
    vlog_node_t v = vlog_new(V_ALWAYS);
-
-   char *name LOCAL = xasprintf("__always#line%d", yylloc.first_line);
-   vlog_set_ident(v, ident_uniq(name));
-
+   vlog_set_ident(v, ident_uniq("__always#line%d", yylloc.first_line));
    vlog_add_stmt(v, p_statement());
 
    vlog_set_loc(v, CURRENT_LOC);
@@ -2115,9 +2112,7 @@ static vlog_node_t p_initial_construct(void)
    consume(tINITIAL);
 
    vlog_node_t v = vlog_new(V_INITIAL);
-
-   char *name LOCAL = xasprintf("__initial#line%d", yylloc.first_line);
-   vlog_set_ident(v, ident_uniq(name));
+   vlog_set_ident(v, ident_uniq("__initial#line%d", yylloc.first_line));
 
    vlog_node_t s = p_statement_or_null();
    if (s != NULL)
@@ -2135,9 +2130,7 @@ static vlog_node_t p_net_assignment(void)
 
    vlog_node_t v = vlog_new(V_ASSIGN);
    vlog_set_target(v, p_net_lvalue());
-
-   char *name LOCAL = xasprintf("__assign#line%d", state.last_loc.first_line);
-   vlog_set_ident(v, ident_uniq(name));
+   vlog_set_ident(v, ident_uniq("__assign#line%d", state.last_loc.first_line));
 
    consume(tEQ);
 
index 5b1a45cd79a3ebb88f994e19e2750940f298fe62..53f4917f94ac0714bae83a6b718792e251ef1e7f 100644 (file)
@@ -74,9 +74,7 @@ static vlog_node_t simp_net_decl(vlog_node_t decl, vlog_node_t mod)
       vlog_set_target(a, ref);
       vlog_set_value(a, value);
       vlog_set_loc(a, loc);
-
-      char *name LOCAL = xasprintf("__assign#%s", istr(id));
-      vlog_set_ident(a, ident_uniq(name));
+      vlog_set_ident(a, ident_uniq("__assign#%s", istr(id)));
 
       vlog_add_stmt(mod, a);
    }
diff --git a/test/regress/conv19.vhd b/test/regress/conv19.vhd
new file mode 100644 (file)
index 0000000..db310d2
--- /dev/null
@@ -0,0 +1,53 @@
+entity conv19 is
+end entity;
+
+architecture test of conv19 is
+    type t_rec is record
+        x : integer;
+        y : bit;
+    end record;
+
+    function popcount (v : bit_vector) return natural is
+        variable result : natural;
+    begin
+        for i in v'range loop
+            if v(i) = '1' then
+                result := result + 1;
+            end if;
+        end loop;
+        return result;
+    end function;
+
+    signal s : bit_vector(1 to 3);
+    signal t : bit;
+begin
+
+    b: block is
+        port ( r : t_rec );
+        port map (
+            r.x => popcount(s),
+            r.y => inertial t );
+    begin
+
+        check: process is
+        begin
+            assert r = (0, '0');
+            wait for 0 ns;
+            assert r = (2, '0');
+            wait for 0 ns;
+            assert r = (2, '1');
+            wait for 1 ns;
+            assert r = (1, '1');
+            wait;
+        end process;
+    end block;
+
+    stim: process is
+    begin
+        s <= "101";
+        t <= '1';
+        s <= transport "001" after 1 ns;
+        wait;
+    end process;
+
+end architecture;
index 56c60b5aae8bc8e6b99153433e201a1051ba31b8..71ddc953c4b4d354b0c72cf4db01422524f45abb 100644 (file)
@@ -1102,3 +1102,4 @@ issue1150       normal,psl
 order4          shell
 issue1161       normal,vhpi,2008
 cmdline14       shell
+conv19          normal,2008