nvc icon indicating copy to clipboard operation
nvc copied to clipboard

Unit is too big to compile with big combinational circuit

Open tmeissner opened this issue 4 months ago • 4 comments

This seems quite similar to #1200

We have a GCM unit which includes a galois multiplier function consisting big combinational logic of round about 16.000 lines of AND / XOR gates. When elaborating the unit, we get a unit ... is too big to compile error, even with the --precompile elaboration option. Unfortunately, the code can't be shared here. Note that the function hasn't any signals, it consists of a intermediate variable to hold the result and returns it at the end. The two input parameters and the return value are of type std_logic_vectors of length 128.

What could we do to dive deeper into the problem or to help to debug this?

$ nvc --version
nvc 1.18-devel (1.17.0.r38.g40bf5548) (Using LLVM 14.0.6)
Copyright (C) 2011-2025  Nick Gasson

tmeissner avatar Aug 04 '25 13:08 tmeissner

Are you able to share a small part of the function or something that has a similar structure? Presumably it's a lot of repeating code like this?

x = a and b;
x = a xor x;
...

nickg avatar Aug 09 '25 10:08 nickg

The unit is a combinatorical implementation of a mastrovito-multiplier looking similar to:

function mul_gf_2exp128(a, b : in std_logic_vector(127 downto 0)) return std_logic_vector is
    variable v_c : std_logic_vector(127 downto 0);
begin
    v_c(0) :=((a(0)) and b(0)) xor
            ((a(127)) and b(1)) xor
            ((a(126)) and b(2)) xor ...

    v_c(1) :=((a(1)) and b(0)) xor
            ((a(0) xor a(127)) and b(1)) xor
            ((a(126) xor a(127)) and b(2)) xor ...
    ....
    return v_c;

end mul_gf_2exp128;

The function consists of 16386 AND and 40705 XOR gates.

I'll try to derive a MWE if I have time.

tmeissner avatar Sep 23 '25 15:09 tmeissner

Hello, I derived a MWE for this issue. Running nvc -M 32m -a test1258.vhd -e test1258 -r Gives the follwing error: ** Fatal: unit WORK.TEST1258.MY_HUGE_FUNCTION(VV)V is too big to compile This error can be reproduced in version 1.18.0

It seems that the error is invoked in this funtion in ./src/jit/jit-irgen.c line 199: static jit_reg_t irgen_alloc_reg(jit_irgen_t *g)

But for now I cannot understand where the g->next_reg of jit_irgen_t is allocated.

test1258.vhd

gottschalkm avatar Oct 06 '25 08:10 gottschalkm

Hi @gottschalkm and @tmeissner ,

to fix this issue, you can redefine jit_reg_t to uint32_t and JIT_REG_INVALID to UINT32_MAX. You can find both in src/jit/jit_priv.h.

The structs jit_value_t and jit_ir_t do have some memory layout asserts around them, and the changes above do not corrupt them on my platform. I am not sure it is the case everywhere. I don't know if @nickg would like to apply the simple fix.

Maybe there is some optimization reason behind using uint16_t ?

From users point of view, having at most 2 ^ 16 expressions / values / instances within a single scope / module is not sufficient. Modern designs often have tens of millions of gates. If netlists are flattened, this can lead to hundreds of millions (or bilions) of possible jit_reg_t in a single unit.

Blebowski avatar Nov 10 '25 20:11 Blebowski