Skip to content

Commit 4dcff16

Browse files
committed
Spill excess arguments to temporary storage. Fixes #1036
1 parent 05d55fe commit 4dcff16

File tree

6 files changed

+138
-25
lines changed

6 files changed

+138
-25
lines changed

NEWS.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
- Fixed a crash when `'last_value` is used with record types (#1043).
1818
- Selected names can now be to register value change callbacks with
1919
`vhpi_register_cb` (#1045).
20+
- Removed the limit on the maximum number of parameters that can be
21+
passed to a VHDL subprogram (#1036).
2022
- Several other minor bugs were resolved (#1038).
2123

2224
## Version 1.14.1 - 2024-10-26

src/jit/jit-irgen.c

Lines changed: 75 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -857,17 +857,6 @@ static jit_value_t irgen_get_arg(jit_irgen_t *g, int op, int arg)
857857
return irgen_get_value(g, vcode_get_arg(op, arg));
858858
}
859859

860-
static jit_reg_t irgen_as_reg(jit_irgen_t *g, jit_value_t value)
861-
{
862-
if (value.kind == JIT_VALUE_REG)
863-
return value.reg;
864-
else {
865-
jit_reg_t r = irgen_alloc_reg(g);
866-
j_mov(g, r, value);
867-
return r;
868-
}
869-
}
870-
871860
static jit_value_t irgen_lea(jit_irgen_t *g, jit_value_t addr)
872861
{
873862
switch (addr.kind) {
@@ -887,6 +876,24 @@ static jit_value_t irgen_lea(jit_irgen_t *g, jit_value_t addr)
887876
}
888877
}
889878

879+
static jit_reg_t irgen_as_reg(jit_irgen_t *g, jit_value_t value)
880+
{
881+
switch (value.kind) {
882+
case JIT_VALUE_REG:
883+
return value.reg;
884+
case JIT_ADDR_REG:
885+
case JIT_ADDR_CPOOL:
886+
case JIT_ADDR_ABS:
887+
return jit_value_as_reg(irgen_lea(g, value));
888+
default:
889+
{
890+
jit_reg_t r = irgen_alloc_reg(g);
891+
j_mov(g, r, value);
892+
return r;
893+
}
894+
}
895+
}
896+
890897
static jit_value_t irgen_is_scalar(jit_irgen_t *g, int op, int arg)
891898
{
892899
const vtype_kind_t kind = vcode_reg_kind(vcode_get_arg(op, arg));
@@ -1189,12 +1196,33 @@ static void irgen_send_args(jit_irgen_t *g, int op, int first)
11891196
{
11901197
const int nargs = vcode_count_args(op);
11911198

1199+
jit_value_t spill = { .kind = JIT_VALUE_INVALID };
1200+
int32_t spilloff = 0;
1201+
11921202
for (int i = 0, pslot = first; i < nargs; i++) {
11931203
vcode_reg_t vreg = vcode_get_arg(op, i);
11941204
int slots = irgen_slots_for_type(vcode_reg_type(vreg));
1195-
if (unlikely(pslot + slots >= JIT_MAX_ARGS))
1196-
fatal("call to %s requires more than the maximum supported "
1197-
"%d arguments", istr(vcode_get_func(op)), JIT_MAX_ARGS);
1205+
1206+
if (pslot + slots >= JIT_MAX_ARGS - 1) {
1207+
// Large number of arguments spill to the heap
1208+
if (spill.kind == JIT_VALUE_INVALID) {
1209+
size_t size = slots * sizeof(jit_scalar_t);
1210+
for (int j = i + 1; j < nargs; j++) {
1211+
vcode_type_t vtype = vcode_reg_type(vcode_get_arg(op, j));
1212+
size += irgen_slots_for_type(vtype) * sizeof(jit_scalar_t);
1213+
}
1214+
1215+
spill = macro_lalloc(g, jit_value_from_int64(size));
1216+
j_send(g, JIT_MAX_ARGS - 1, spill);
1217+
pslot = JIT_MAX_ARGS;
1218+
}
1219+
1220+
jit_reg_t base = irgen_as_reg(g, irgen_get_value(g, vreg));
1221+
for (int j = 0; j < slots; j++, spilloff += sizeof(jit_scalar_t)) {
1222+
jit_value_t ptr = jit_addr_from_value(spill, spilloff);
1223+
j_store(g, JIT_SZ_64, jit_value_from_reg(base + j), ptr);
1224+
}
1225+
}
11981226
else if (slots > 1) {
11991227
jit_reg_t base = jit_value_as_reg(irgen_get_value(g, vreg));
12001228
for (int j = 0; j < slots; j++)
@@ -3480,6 +3508,11 @@ static void irgen_op_bind_foreign(jit_irgen_t *g, int op)
34803508
const int nparams = vcode_count_params();
34813509
for (int i = 0; i < nparams; i++) {
34823510
const int slots = irgen_slots_for_type(vcode_param_type(i));
3511+
if (unlikely(pslot + slots >= JIT_MAX_ARGS))
3512+
fatal("foreign subprogram %s requires more than the maximum supported "
3513+
"%d arguments", istr(vcode_unit_name(g->func->unit)),
3514+
JIT_MAX_ARGS);
3515+
34833516
jit_value_t p = irgen_get_value(g, vcode_param_reg(i));
34843517
j_send(g, pslot++, p);
34853518
for (int j = 1; j < slots; j++)
@@ -4007,19 +4040,36 @@ static void irgen_params(jit_irgen_t *g, int first)
40074040
types[first] = FFI_POINTER;
40084041
types[0] = FFI_VOID;
40094042

4043+
jit_value_t spill = { .kind = JIT_VALUE_INVALID };
4044+
int32_t spilloff = 0;
4045+
40104046
const int nparams = vcode_count_params();
40114047
for (int i = 0, pslot = first; i < nparams; i++) {
40124048
vcode_reg_t preg = vcode_param_reg(i);
40134049
vcode_type_t vtype = vcode_param_type(i);
40144050
int slots = irgen_slots_for_type(vtype);
40154051

4016-
if (unlikely(pslot + slots >= JIT_MAX_ARGS))
4017-
fatal("%s requires more than the maximum supported %d arguments",
4018-
istr(g->func->name), JIT_MAX_ARGS);
4052+
if (pslot + slots >= JIT_MAX_ARGS - 1) {
4053+
// Large number of arguments spill to the heap
4054+
if (spill.kind == JIT_VALUE_INVALID) {
4055+
spill = j_recv(g, JIT_MAX_ARGS - 1);
4056+
pslot = JIT_MAX_ARGS;
4057+
}
40194058

4020-
g->map[preg] = j_recv(g, pslot++);
4021-
for (int i = 1; i < slots; i++)
4022-
j_recv(g, pslot++); // Must be contiguous registers
4059+
jit_value_t ptr = jit_addr_from_value(spill, spilloff);
4060+
g->map[preg] = j_load(g, JIT_SZ_64, ptr);
4061+
spilloff += sizeof(jit_scalar_t);
4062+
4063+
for (int i = 1; i < slots; i++, spilloff += sizeof(jit_scalar_t)) {
4064+
jit_value_t ptr = jit_addr_from_value(spill, spilloff);
4065+
j_load(g, JIT_SZ_64, ptr); // Must be contiguous registers
4066+
}
4067+
}
4068+
else {
4069+
g->map[preg] = j_recv(g, pslot++);
4070+
for (int i = 1; i < slots; i++)
4071+
j_recv(g, pslot++); // Must be contiguous registers
4072+
}
40234073

40244074
if (i + first + 1 < ARRAY_LEN(types))
40254075
types[i + first + 1] = irgen_ffi_type(vtype);
@@ -4180,10 +4230,7 @@ void jit_irgen(jit_func_t *f)
41804230
irgen_bind_label(g, cont);
41814231
}
41824232

4183-
const int first_param = irgen_is_procedure(g) || has_jump_table ? 1 : 0;
4184-
if (has_params)
4185-
irgen_params(g, first_param);
4186-
else if (kind == VCODE_UNIT_PROCESS) {
4233+
if (kind == VCODE_UNIT_PROCESS) {
41874234
const ffi_type_t types[] = { FFI_POINTER, FFI_POINTER, FFI_POINTER };
41884235
g->func->spec = ffi_spec_new(types, ARRAY_LEN(types));
41894236
}
@@ -4208,6 +4255,10 @@ void jit_irgen(jit_func_t *f)
42084255
if (has_jump_table)
42094256
irgen_jump_table(g);
42104257

4258+
const int first_param = irgen_is_procedure(g) || has_jump_table ? 1 : 0;
4259+
if (has_params)
4260+
irgen_params(g, first_param);
4261+
42114262
irgen_locals(g);
42124263

42134264
if (g->stateless) {

src/jit/jit-priv.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -356,7 +356,7 @@ typedef struct {
356356

357357
typedef struct _pack_writer pack_writer_t;
358358

359-
#define JIT_MAX_ARGS 100
359+
#define JIT_MAX_ARGS 64
360360

361361
typedef struct _jit_interp jit_interp_t;
362362

src/jit/jit.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ typedef union {
3131
double real;
3232
} jit_scalar_t;
3333

34+
STATIC_ASSERT(sizeof(jit_scalar_t) == 8);
35+
3436
typedef struct {
3537
void *(*init)(jit_t *);
3638
void (*cgen)(jit_t *, jit_handle_t, void *);

test/regress/issue1036.vhd

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
entity issue1036 is
2+
end entity;
3+
4+
architecture test of issue1036 is
5+
6+
type int2d is array (natural range <>, natural range <>) of integer;
7+
8+
procedure many_args
9+
( a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11 : inout bit_vector;
10+
a12, a13, a14, a15, a16, a17, a18, a19 : inout integer;
11+
a20, a21, a22, a23, a24, a25, a26 : inout int2d;
12+
a27 : inout integer;
13+
signal a28 : inout bit_vector ) is
14+
begin
15+
assert a5 = X"05";
16+
assert a11 = X"1010";
17+
assert a25 = (0 => (0 => 42));
18+
assert a26(0, 0) = 99;
19+
assert a27 = 251;
20+
assert a28 = X"f0";
21+
22+
a25(0, 0) := 77;
23+
a26(0, 0) := 55;
24+
a27 := 999;
25+
a28 <= not a28;
26+
wait for 0 ns;
27+
end procedure;
28+
29+
signal s : bit_vector(7 downto 0) := X"f0";
30+
begin
31+
32+
process is
33+
variable v0, v1, v2, v3, v4, v5 : bit_vector(7 downto 0);
34+
variable v6, v7, v8, v9, v10, v11 : bit_vector(15 downto 0);
35+
variable v12, v13, v14, v15, v16, v17, v18, v19 : integer;
36+
variable v20, v21, v22, v23, v24, v25, v26 : int2d(0 to 0, 0 to 0);
37+
variable v27 : integer;
38+
begin
39+
v5 := X"05";
40+
v11 := X"1010";
41+
v25 := (0 => (0 => 42));
42+
v26(0, 0) := 99;
43+
v27 := 251;
44+
45+
many_args(v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11,
46+
v12, v13, v14, v15, v16, v17, v18, v19,
47+
v20, v21, v22, v23, v24, v25, v26, v27, s);
48+
49+
assert v25 = (0 => (0 => 77));
50+
assert v26(0, 0) = 55;
51+
assert v27 = 999;
52+
assert s = X"0f";
53+
54+
wait;
55+
end process;
56+
57+
end architecture;

test/regress/testlist.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1066,3 +1066,4 @@ psl13 fail,gold,psl
10661066
issue1045 normal,vhpi
10671067
issue1044 mixed
10681068
issue1030 wave,2008,dump-arrays
1069+
issue1036 normal

0 commit comments

Comments
 (0)