Unit is too big to compile with big combinational circuit
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
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;
...
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.
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.
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.