nickg / nvc

VHDL compiler and simulator
https://www.nickg.me.uk/nvc/
GNU General Public License v3.0
631 stars 77 forks source link

** Fatal: dst argument to map signal is not a signal #843

Closed smaslovski closed 8 months ago

smaslovski commented 8 months ago

Hi,

I've found that NVC crashes at elaboration stage with the vhdl code given futher below. Here is the complete crash report:

$ nvc --std=08 -a bug1.vhd   
$ nvc --std=08 -e tb

Name       WORK.TB.FFT_INST.STAGE_N.EVEN_FFT
Kind       instance
Context    WORK.TB.FFT_INST.STAGE_N
Blocks     10
Registers  128
Types      36
  WORK.FFT_PKG.DATA_TYPE                {[32] : 0..8, [32] : 0..8}
  WORK.FFT_PKG.DATA_TYPE$               {$<0..8>, $<0..8>}
Variables  6
  POW                                   // -2^31..2^31-1 => 0..2^31-1, constant
  DIM                                   // -2^31..2^31-1 => 1..2^31-1, constant
  W                                     // [*] : WORK.FFT_PKG.DATA_TYPE{} => WORK.FFT_PKG.DATA_TYPE{}, constant
  Y                                     // [*] : WORK.FFT_PKG.DATA_TYPE${}, signal
  X                                     // [*] : WORK.FFT_PKG.DATA_TYPE${}, signal
  i9                                    // #, temp
Begin
   0: r0 := package init STD.STANDARD   // P<STD.STANDARD>
      r1 := package init WORK.FFT_PKG   // P<WORK.FFT_PKG>
      r2 := package init IEEE.FLOAT_PKG // P<IEEE.FLOAT_PKG>
      r3 := const 1                     // -2^31..2^31-1 => 1
      r4 := const 0                     // -2^31..2^31-1 => 0
      r5 := const 2147483647            // -2^31..2^31-1 => 2^31-1
      r6 := const 0                     // 0..1 => 0
      POW := store r3
      r7 := const 2                     // -2^31..2^31-1 => 2
      DIM := store r7
      r8 := var upref 2, W              // @<[*] : WORK.FFT_PKG.DATA_TYPE{}> => WORK.FFT_PKG.DATA_TYPE{}
      r9 := load indirect r8            // [*] : WORK.FFT_PKG.DATA_TYPE{} => WORK.FFT_PKG.DATA_TYPE{}
      r10 := fcall WORK.FFT_PKG.EVEN_ELEM(24WORK.FFT_PKG.DATA_VECTOR)24WORK.FFT_PKG.DATA_VECTOR r1, r9 // [*] : WORK.FFT_PKG.DATA_TYPE{} => WORK.FFT_PKG.DATA_TYPE{}
      W := store r10
      r11 := var upref 1, EVEN          // @<[*] : WORK.FFT_PKG.DATA_TYPE${}> => WORK.FFT_PKG.DATA_TYPE{}
      r12 := load indirect r11          // [*] : WORK.FFT_PKG.DATA_TYPE${} => WORK.FFT_PKG.DATA_TYPE{}
      r13 := load DIM                   // -2^31..2^31-1 => 1..2^31-1
      r14 := debug locus WORK.TB.elab-763 // D<>
      r15 := sub r13 - r3               // -2^31..2^31-1 => 0..2147483646
      r16 := null                       // @<WORK.FFT_PKG.DATA_TYPE{}>
      r17 := wrap r16 [r4 r15 r6]       // [*] : WORK.FFT_PKG.DATA_TYPE{}
      r18 := debug locus WORK.TB.elab-1393 // D<>
      r19 := range length left r4 right r15 dir r6 // #
      r20 := uarray len r12 dim 0       // #
      length check left r19 == right r20 locus r18
      r21 := unwrap r12                 // @<WORK.FFT_PKG.DATA_TYPE${}> => WORK.FFT_PKG.DATA_TYPE${}
      r22 := wrap r21 [r4 r15 r6]       // [*] : WORK.FFT_PKG.DATA_TYPE${}
      Y := store r22
      r23 := debug locus WORK.TB.elab-721 // D<>
      r24 := index X                    // @<[*] : WORK.FFT_PKG.DATA_TYPE${}> => [*] : WORK.FFT_PKG.DATA_TYPE${}
      r25 := alloc r19                  // @<WORK.FFT_PKG.DATA_TYPE${}> => WORK.FFT_PKG.DATA_TYPE{}
      r26 := wrap r25 [r4 r15 r6]       // [*] : WORK.FFT_PKG.DATA_TYPE${}
      r24 := store indirect r26
      r27 := const 0                    // # => 0
      i9 := store r27
      r28 := debug locus WORK.TB.elab-759 // D<>
      push scope locus r28
      jump 1
   1: r29 := load i9                    // #
      r30 := cmp r29 == r19
      cond r30 then 3 else 2
   2: r31 := array ref r25 offset r29   // @<WORK.FFT_PKG.DATA_TYPE${}> => WORK.FFT_PKG.DATA_TYPE{}
      r32 := array ref r16 offset r29   // @<WORK.FFT_PKG.DATA_TYPE{}>
      r33 := debug locus WORK.TB.elab-759 // D<>
      push scope locus r33
      r34 := record ref r32 field 0     // @<0..8> => 0..8
      r35 := record ref r31 field 0     // @<$<0..8>> => $<0..8>
      r36 := const 0                    // # => 0
      r37 := const 9                    // # => 9
      r38 := link package IEEE.STD_LOGIC_1164 // P<IEEE.STD_LOGIC_1164>
      r39 := closure IEEE.STD_LOGIC_1164.RESOLVED(Y)U context r38 // C<0..8>
      r40 := resolution wrapper r39 ileft r36 nlits r37 // R<0..8>
      r41 := const 1                    // # => 1
      r42 := const 32                   // # => 32
      r43 := debug locus WORK.FFT_PKG+30 // D<>
      r44 := const 0                    // 0..8 => 0
      r45 := init signal count r42 size r41 value r44 flags r36 locus r43 offset r34 // $<0..8>
      resolve signal r45 resolution r40
      r35 := store indirect r45
      r46 := record ref r32 field 1     // @<0..8> => 0..8
      r47 := record ref r31 field 1     // @<$<0..8>> => $<0..8>
      r48 := debug locus WORK.FFT_PKG+33 // D<>
      r49 := init signal count r42 size r41 value r44 flags r36 locus r48 offset r46 // $<0..8>
      resolve signal r49 resolution r40
      r47 := store indirect r49
      pop scope
      r50 := add r29 + r41              // # => -9223372036854775807..2^63-1
      i9 := store r50
      jump 1
   3: pop scope
      r51 := const 0                    // -2^31..2^31-1 => 0
      r52 := load DIM                   // -2^31..2^31-1 => 1..2^31-1
      r53 := const 1                    // -2^31..2^31-1 => 1
      r54 := debug locus WORK.TB.elab-763 // D<>
      r55 := sub r52 - r53              // -2^31..2^31-1 => 0..2147483646
      r56 := const 0                    // 0..1 => 0
      r57 := null                       // @<WORK.FFT_PKG.DATA_TYPE{}>
      r58 := wrap r57 [r51 r55 r56]     // [*] : WORK.FFT_PKG.DATA_TYPE{}
      r59 := debug locus WORK.TB.elab-763 // D<>
      r60 := range length left r51 right r55 dir r56 // #
      r61 := const 0                    // 0..8 => 0
      r62 := const [r61]*32             // [32] : 0..8 => 0..8
      r63 := const {r62,r62}            // WORK.FFT_PKG.DATA_TYPE{}
      r64 := address of r63             // @<WORK.FFT_PKG.DATA_TYPE{}>
      r65 := alloc r60                  // @<WORK.FFT_PKG.DATA_TYPE{}> => WORK.FFT_PKG.DATA_TYPE{}
      r66 := const 0                    // # => 0
      i9 := store r66
      r67 := cmp r60 == r66
      cond r67 then 5 else 4
   4: r68 := load i9                    // #
      r69 := array ref r65 offset r68   // @<WORK.FFT_PKG.DATA_TYPE{}> => WORK.FFT_PKG.DATA_TYPE{}
      r69 := copy r64
      r70 := const 1                    // # => 1
      r71 := add r68 + r70              // # => -9223372036854775807..2^63-1
      i9 := store r71
      r72 := cmp r71 == r60
      cond r72 then 5 else 4
   5: r73 := load Y                     // [*] : WORK.FFT_PKG.DATA_TYPE${}
      r74 := debug locus WORK.TB.elab-785 // D<>
      r75 := const 0                    // -2^31..2^31-1 => 0
      r76 := load DIM                   // -2^31..2^31-1 => 1..2^31-1
      r77 := const 1                    // -2^31..2^31-1 => 1
      r78 := debug locus WORK.TB.elab-763 // D<>
      r79 := sub r76 - r77              // -2^31..2^31-1 => 0..2147483646
      r80 := const 0                    // 0..1 => 0
      r81 := null                       // @<WORK.FFT_PKG.DATA_TYPE{}>
      r82 := wrap r81 [r75 r79 r80]     // [*] : WORK.FFT_PKG.DATA_TYPE{}
      r83 := range length left r75 right r79 dir r80 // #
      r84 := uarray len r73 dim 0       // #
      length check left r83 == right r84 locus r74
      r85 := const 0                    // # => 0
      i9 := store r85
      r86 := debug locus WORK.TB.elab-763 // D<>
      r87 := cmp r83 == r85
      cond r87 then 7 else 6
   6: r88 := load i9                    // #
      r89 := array ref r65 offset r88   // @<WORK.FFT_PKG.DATA_TYPE{}> => WORK.FFT_PKG.DATA_TYPE{}
      r90 := unwrap r73                 // @<WORK.FFT_PKG.DATA_TYPE${}> => WORK.FFT_PKG.DATA_TYPE${}
      r91 := array ref r90 offset r88   // @<WORK.FFT_PKG.DATA_TYPE${}> => WORK.FFT_PKG.DATA_TYPE${}
      r92 := record ref r89 field 0     // @<0..8> => 0..8
      r93 := record ref r91 field 0     // @<$<0..8>> => $<0..8>
      r94 := load indirect r93          // $<0..8>
      r95 := const 32                   // # => 32
      map const r92 to r94 count r95
      r96 := record ref r89 field 1     // @<0..8> => 0..8
      r97 := record ref r91 field 1     // @<$<0..8>> => $<0..8>
      r98 := load indirect r97          // $<0..8>
      map const r96 to r98 count r95
      r99 := const 1                    // # => 1
      r100 := add r88 + r99             // # => -9223372036854775807..2^63-1
      i9 := store r100
      r101 := cmp r100 == r83
      cond r101 then 7 else 6
   7: r102 := var upref 2, X            // @<[*] : WORK.FFT_PKG.DATA_TYPE${}> => [*] : WORK.FFT_PKG.DATA_TYPE${}
      r103 := load indirect r102        // [*] : WORK.FFT_PKG.DATA_TYPE${}
      r104 := index X                   // @<[*] : WORK.FFT_PKG.DATA_TYPE${}> => [*] : WORK.FFT_PKG.DATA_TYPE${}
      r105 := context upref 0           // P<WORK.TB.FFT_INST.STAGE_N.EVEN_FFT>
      r106 := closure WORK.TB.FFT_INST.STAGE_N.EVEN_FFT.wrap_WORK.FFT_PKG.EVEN_ELEM(24WORK.FFT_PKG.DATA_VECTOR)24WORK.FFT_PKG.DATA_VECTOR.X context r105 // C<@<WORK.FFT_PKG.DATA_TYPE{}>>
      r107 := const 0                   // -2^31..2^31-1 => 0
      r108 := load DIM                  // -2^31..2^31-1 => 1..2^31-1
      r109 := const 1                   // -2^31..2^31-1 => 1
      r110 := debug locus WORK.TB.elab-721 // D<>
      r111 := sub r108 - r109           // -2^31..2^31-1 => 0..2147483646
      r112 := const 0                   // 0..1 => 0
      r113 := null                      // @<WORK.FFT_PKG.DATA_TYPE{}>
      r114 := wrap r113 [r107 r111 r112] // [*] : WORK.FFT_PKG.DATA_TYPE{}
      r115 := range length left r107 right r111 dir r112 // #
      r116 := debug locus WORK.TB.elab-1390 // D<>
      r117 := const 0                   // # => 0
      i9 := store r117
      r118 := uarray len r103 dim 0     // #
      r119 := unwrap r103               // @<WORK.FFT_PKG.DATA_TYPE${}> => WORK.FFT_PKG.DATA_TYPE${}
      r120 := cmp r118 == r117
      cond r120 then 9 else 8
   8: r121 := load i9                   // #
      r122 := array ref r119 offset r121 // @<WORK.FFT_PKG.DATA_TYPE${}> => WORK.FFT_PKG.DATA_TYPE${}
      r123 := record ref r122 field 0   // @<$<0..8>> => $<0..8>
      r124 := load indirect r123        // $<0..8>
      r125 := const 32                  // # => 32
      r126 := load indirect r104        // [*] : WORK.FFT_PKG.DATA_TYPE${}
      r127 := unwrap r126               // @<WORK.FFT_PKG.DATA_TYPE${}> => WORK.FFT_PKG.DATA_TYPE${}
      map signal r124 to r127 src count r125 dst count r115 conv r106    <----
   9: Empty basic block

** Fatal: dst argument to map signal is not a signal
[0x56436ad39f5f] ../src/diag.c:1016 diag_femit
[0x56436ac85f2f] ../src/util.c:585 fatal_trace
[0x56436ad29259] ../src/vcode.c:4761 emit_map_signal
[0x56436acfbb89] ../src/lower.c:913 lower_for_each_field.lto_priv.0
[0x56436acfba9a] ../src/lower.c:892 lower_for_each_field.lto_priv.0
[0x56436ad175b8] ../src/lower.c:11458 lower_map_signal.lto_priv.0
[0x56436ad17b05] ../src/lower.c:11720 lower_port_map.lto_priv.0
[0x56436acd9a59] ../src/lower.c:12113 lower_instance
[0x56436acd9a59] ../src/lower.c:1126 elab_lower.lto_priv.0
[0x56436acdda6f] ../src/elab.c:1346 elab_instance.lto_priv.0
[0x56436ace136b] ../src/elab.c:1662 elab_stmts.lto_priv.0
[0x56436ace2016] ../src/elab.c:1720 elab_stmts.lto_priv.0
[0x56436acdda87] ../src/elab.c:1348 elab_instance.lto_priv.0
[0x56436ace136b] ../src/elab.c:1662 elab_stmts.lto_priv.0
[0x56436ace31b2] ../src/elab.c:1835 elab_top_level.lto_priv.0
[0x56436ac7e9fc] ../src/elab.c:1904 elab
[0x56436ac7e9fc] ../src/elab.c:457 elaborate
[0x56436ac800d3] ../src/nvc.c:1909 process_command
[0x56436ac7a80e] ../src/nvc.c:2047 main

Please report this bug at https://github.com/nickg/nvc/issues

Here is the affected code:

library ieee;
use ieee.math_real.all;
use ieee.float_pkg.all;

package fft_pkg is
  subtype num_type is float32;
  type data_type is record
    re, im : num_type;
  end record;
  type data_vector is array (natural range <>) of data_type;
  function "+" (a, b : data_type) return data_type;
  function "*" (a, b : data_type) return data_type;
  function even_elem(x : data_vector) return data_vector;
  function odd_elem(x : data_vector) return data_vector;
  function weight(n : positive) return data_vector;
end package fft_pkg;

package body fft_pkg is
  function "+" (a, b : data_type) return data_type is
  begin
    return data_type'(a.re + b.re, a.im + b.im);
  end function;

  function "*" (a, b : data_type) return data_type is
  begin
    return data_type'(a.re*b.re - a.im*b.im, a.re*b.im + a.im*b.re);
  end function;

  function even_elem(x : data_vector) return data_vector is
    variable res : data_vector (0 to x'length/2-1);
  begin
    for i in res'range loop
      res(i) := x(2*i);
    end loop;
    return res;
  end function;

  function odd_elem(x : data_vector) return data_vector is
    variable res : data_vector (0 to x'length/2-1);
  begin
    for i in res'range loop
      res(i) := x(2*i+1);
    end loop;
    return res;
  end function;

  function weight(n : positive) return data_vector is
    variable w : data_vector (0 to n-1);
    variable omega : real;
  begin
    omega := math_2_pi/real(n);
    for k in w'range loop
      w(k) := data_type'(to_float(cos(omega*real(k))), to_float(-sin(omega*real(k))));
    end loop;
    return w;
  end function;
end package body fft_pkg;

library ieee;
use ieee.float_pkg.all;
use work.fft_pkg.all;

entity fft is
  generic (
    POW : natural;
    DIM : positive := 2**POW;
    w: data_vector (0 to DIM-1) := weight(DIM));
  port (
    x : in  data_vector (0 to DIM-1);
    y : out data_vector (0 to DIM-1));
end entity fft;

architecture recursive of fft is
begin
  stage_n :
  if POW > 0 generate
    subtype half_array is data_vector (0 to DIM/2-1);
    signal even, odd : half_array;
    alias w_b : half_array is w(0 to DIM/2-1);
    alias w_t : half_array is w(DIM/2 to DIM-1);
  begin
    even_fft :
      entity fft
        generic map (
          POW => POW-1, w => even_elem(w))
        port map (
          x => even_elem(x), y => even);
    odd_fft :
      entity fft
        generic map (
          POW => POW-1, w => even_elem(w))
        port map (
          x => odd_elem(x), y => odd);
    butterfly :
    process (all) is
    begin
      for i in half_array'range loop
        y(i)       <= even(i) + odd(i) * w_b(i);
        y(i+DIM/2) <= even(i) + odd(i) * w_t(i);
      end loop;
    end process;
  end generate stage_n;
  stage_0 :
  if POW = 0 generate
    y <= x;
  end generate stage_0;
end architecture recursive;

library ieee;
use ieee.math_real.all;
use ieee.math_complex.all;
use ieee.fixed_float_types.all;
use ieee.float_pkg.all;
use work.fft_pkg.all;

entity tb is
end entity tb;

architecture test of tb is
  constant POW : natural := 2;
  constant DIM : positive := 2**POW;
  signal x, y : data_vector (0 to DIM-1) := (others => data_type'(to_float(0.0), to_float(0.0)));
  type complex_vector is array (0 to DIM-1) of complex;
  constant stimul : complex_vector := ((0.0, 0.0), ( 1.0, 1.0), ( 2.0,  2.0), (3.0,  3.0));
  constant result : complex_vector := ((6.0, 6.0), (-4.0, 0.0), (-2.0, -2.0), (0.0, -4.0));
  constant abstol : real := 1.0e-6;
begin
  fft_inst :
    entity work.fft(recursive)
      generic map (POW => POW)
      port map (x => x, y => y);
  test_proc :
    process is
      alias s is to_string [integer return string];
      alias s is to_string [real return string];
    begin
      for i in x'range loop
        x(i) <= data_type'(to_float(stimul(i).re), to_float(stimul(i).im));
      end loop;
      wait for 1 ps;
      for i in y'range loop
        assert abs(to_real(y(i).re) - result(i).re) < abstol and abs(to_real(y(i).im) - result(i).im) < abstol
          report "Inconsistent result detected: y(" & s(i) & ") = (" & s(to_real(y(i).re)) & "," & s(to_real(y(i).im)) & ")"  severity failure;
      end loop;
      wait;
    end process;
end architecture test;

BR, Stanislav

smaslovski commented 8 months ago

To add more to this report, I can tell that the crash does not appear if the code of fft module is changed as follows:

architecture recursive of fft is
begin
  stage_n :
  if POW > 0 generate
    subtype half_array is data_vector (0 to DIM/2-1);
    signal x_e, x_o, even, odd : half_array;
    alias w_b : half_array is w(0 to DIM/2-1);
    alias w_t : half_array is w(DIM/2 to DIM-1);
  begin
    x_e <= even_elem(x);
    even_fft :
      entity fft
        generic map (
          POW => POW-1, w => even_elem(w))
        port map (
          x => x_e, y => even);
    x_o <= odd_elem(x);
    odd_fft :
      entity fft
        generic map (
          POW => POW-1, w => even_elem(w))
        port map (
          x => x_o, y => odd);
    butterfly:
    process (all) is
    begin
      for i in half_array'range loop
        y(i)       <= even(i) + odd(i) * w_b(i);
        y(i+DIM/2) <= even(i) + odd(i) * w_t(i);
      end loop;
    end process;
  end generate stage_n;
  stage_0 :
  if POW = 0 generate
    y <= x;
  end generate stage_0;
end architecture recursive;

In principle, it should be possible to achieve the same result just by adding "inertial" keyword before the function calls in the port map association lists. However, it seems that NVC does not know about such syntax, although it is a part of VHDL 2008 stantard.

BR, Stanislav

nickg commented 8 months ago

I've fixed the crash above and also added support for inertial in port maps.