From a4ba942cdb867726cd38082d7c8db3737134474a Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Sat, 3 Feb 2024 10:41:44 +0000 Subject: [PATCH] Fix incorrect effective value with inout port conversion --- src/jit/jit-exits.c | 11 +++++--- src/jit/jit-exits.h | 3 +- src/jit/jit-irgen.c | 20 +++++++++++--- src/lower.c | 2 +- src/rt/model.c | 58 +++++++++++++++++++++++++++++++-------- src/rt/structs.h | 3 +- src/vcode.c | 15 ++++++++-- src/vcode.h | 2 +- test/regress/conv13.vhd | 33 ++++++++++++++++++++++ test/regress/testlist.txt | 1 + 10 files changed, 122 insertions(+), 26 deletions(-) create mode 100644 test/regress/conv13.vhd diff --git a/src/jit/jit-exits.c b/src/jit/jit-exits.c index d285abf6..057bf0c9 100644 --- a/src/jit/jit-exits.c +++ b/src/jit/jit-exits.c @@ -999,12 +999,15 @@ void __nvc_do_exit(jit_exit_t which, jit_anchor_t *anchor, jit_scalar_t *args, case JIT_EXIT_PORT_CONVERSION: { - jit_handle_t handle = args[0].integer; - void *context = args[1].pointer; + jit_handle_t handle1 = args[0].integer; + void *context1 = args[1].pointer; + jit_handle_t handle2 = args[2].integer; + void *context2 = args[3].pointer; if (jit_has_runtime(thread->jit)) { - ffi_closure_t closure = { handle, context }; - args[0].pointer = x_port_conversion(&closure); + ffi_closure_t driving = { handle1, context1 }; + ffi_closure_t effective = { handle2, context2 }; + args[0].pointer = x_port_conversion(&driving, &effective); } else args[0].pointer = NULL; // Called during constant folding diff --git a/src/jit/jit-exits.h b/src/jit/jit-exits.h index cd394cbb..392a38b0 100644 --- a/src/jit/jit-exits.h +++ b/src/jit/jit-exits.h @@ -94,7 +94,8 @@ void *x_reflect_subtype(void *context, tree_t where, const jit_scalar_t *bounds); void *x_function_trigger(const ffi_closure_t *closure); void x_add_trigger(void *ptr); -void *x_port_conversion(const ffi_closure_t *closure); +void *x_port_conversion(const ffi_closure_t *driving, + const ffi_closure_t *effective); void x_convert_in(void *ptr, sig_shared_t *ss, uint32_t offset, int32_t count); void x_convert_out(void *ptr, sig_shared_t *ss, uint32_t offset, int32_t count); diff --git a/src/jit/jit-irgen.c b/src/jit/jit-irgen.c index ddce2289..54102158 100644 --- a/src/jit/jit-irgen.c +++ b/src/jit/jit-irgen.c @@ -3461,11 +3461,23 @@ static void irgen_op_add_trigger(jit_irgen_t *g, int op) static void irgen_op_port_conversion(jit_irgen_t *g, int op) { - jit_value_t closure = irgen_get_arg(g, op, 0); - jit_value_t context = jit_value_from_reg(jit_value_as_reg(closure) + 1); + jit_value_t closure1 = irgen_get_arg(g, op, 0); + jit_value_t context1 = jit_value_from_reg(jit_value_as_reg(closure1) + 1); - j_send(g, 0, closure); - j_send(g, 1, context); + jit_value_t closure2, context2; + if (vcode_count_args(op) > 1) { + closure2 = irgen_get_arg(g, op, 1); + context2 = jit_value_from_reg(jit_value_as_reg(closure2) + 1); + } + else { + closure2 = jit_value_from_handle(JIT_HANDLE_INVALID); + context2 = jit_value_from_int64(0); + } + + j_send(g, 0, closure1); + j_send(g, 1, context1); + j_send(g, 2, closure2); + j_send(g, 3, context2); macro_exit(g, JIT_EXIT_PORT_CONVERSION); g->map[vcode_get_result(op)] = j_recv(g, 0); diff --git a/src/lower.c b/src/lower.c index 1f48492f..936bf37a 100644 --- a/src/lower.c +++ b/src/lower.c @@ -11703,7 +11703,7 @@ static void lower_port_map(lower_unit_t *lu, tree_t block, tree_t map, type_t dst_type = mode == PORT_IN ? name_type : value_type; if (conv_func != VCODE_INVALID_REG) { - vcode_reg_t conv_reg = emit_port_conversion(conv_func); + vcode_reg_t conv_reg = emit_port_conversion(conv_func, in_conv); lower_convert_signal(lu, dst_reg, dst_type, conv_reg, emit_convert_out); lower_convert_signal(lu, src_reg, src_type, diff --git a/src/rt/model.c b/src/rt/model.c index 03e69857..d893337b 100644 --- a/src/rt/model.c +++ b/src/rt/model.c @@ -1700,7 +1700,7 @@ static void copy_sub_signal_sources(rt_scope_t *scope, void *buf, int stride) copy_sub_signal_sources(s, buf, stride); } -static void *call_conversion(rt_conv_func_t *cf, value_fn_t fn) +static void *convert_driving(rt_conv_func_t *cf) { rt_model_t *m = get_model(); @@ -1713,20 +1713,49 @@ static void *call_conversion(rt_conv_func_t *cf, value_fn_t fn) for (int i = 0; i < cf->ninputs; i++) { rt_nexus_t *n = cf->inputs[i]; memcpy(cf->inbuf + n->signal->offset + n->offset, - (*fn)(n), n->size * n->width); + driving_value(n), n->size * n->width); } TRACE("call conversion function %s insz=%zu outsz=%zu", - istr(jit_get_name(m->jit, cf->closure.handle)), cf->insz, cf->outsz); + istr(jit_get_name(m->jit, cf->driving.handle)), cf->insz, cf->outsz); - jit_scalar_t context = { .pointer = cf->closure.context }; - if (!jit_try_call_packed(m->jit, cf->closure.handle, context, + jit_scalar_t context = { .pointer = cf->driving.context }; + if (!jit_try_call_packed(m->jit, cf->driving.handle, context, cf->inbuf, cf->insz, cf->outbuf, cf->outsz)) m->force_stop = true; return cf->outbuf; } +static void *convert_effective(rt_conv_func_t *cf) +{ + rt_model_t *m = get_model(); + + if (unlikely(cf->inbuf == NULL)) + cf->inbuf = static_alloc(m, cf->insz); + + if (unlikely(cf->outbuf == NULL)) + cf->outbuf = static_alloc(m, cf->outsz); + + for (rt_source_t *o = cf->outputs; + o != NULL && o->u.port.conv_func == cf; + o = o->chain_output) { + rt_nexus_t *n = o->u.port.output; + memcpy(cf->inbuf + n->signal->offset + n->offset, + nexus_effective(n), n->size * n->width); + } + + TRACE("call conversion function %s insz=%zu outsz=%zu", + istr(jit_get_name(m->jit, cf->effective.handle)), cf->insz, cf->outsz); + + jit_scalar_t context = { .pointer = cf->effective.context }; + if (!jit_try_call_packed(m->jit, cf->effective.handle, context, + cf->outbuf, cf->outsz, cf->inbuf, cf->insz)) + m->force_stop = true; + + return cf->inbuf; +} + static void *source_value(rt_nexus_t *nexus, rt_source_t *src) { switch (src->tag) { @@ -1740,7 +1769,7 @@ static void *source_value(rt_nexus_t *nexus, rt_source_t *src) if (likely(src->u.port.conv_func == NULL)) return driving_value(src->u.port.input); else - return call_conversion(src->u.port.conv_func, driving_value) + return convert_driving(src->u.port.conv_func) + nexus->signal->offset + nexus->offset; case SOURCE_FORCING: @@ -1893,7 +1922,7 @@ static void *driving_value(rt_nexus_t *nexus) if (likely(s->u.port.conv_func == NULL)) return driving_value(s->u.port.input); else - return call_conversion(s->u.port.conv_func, driving_value) + return convert_driving(s->u.port.conv_func) + nexus->signal->offset + nexus->offset; case SOURCE_FORCING: @@ -1943,7 +1972,8 @@ static const void *effective_value(rt_nexus_t *nexus) if (likely(s->u.port.conv_func == NULL)) return effective_value(s->u.port.output); else - return nexus_effective(nexus); + return convert_effective(s->u.port.conv_func) + + nexus->signal->offset + nexus->offset; } } } @@ -4224,15 +4254,21 @@ void x_add_trigger(void *ptr) obj->trigger = ptr; } -void *x_port_conversion(const ffi_closure_t *closure) +void *x_port_conversion(const ffi_closure_t *driving, + const ffi_closure_t *effective) { rt_model_t *m = get_model(); TRACE("port conversion %s context %p", - istr(jit_get_name(m->jit, closure->handle)), closure->context); + istr(jit_get_name(m->jit, driving->handle)), driving->context); + + if (effective->handle != JIT_HANDLE_INVALID) + TRACE("effective value conversion %s context %p", + istr(jit_get_name(m->jit, effective->handle)), effective->context); rt_conv_func_t *cf = static_alloc(m, sizeof(rt_conv_func_t)); - cf->closure = *closure; + cf->driving = *driving; + cf->effective = *effective; cf->ninputs = 0; cf->maxinputs = 0; cf->outputs = NULL; diff --git a/src/rt/structs.h b/src/rt/structs.h index 11027339..379b7d24 100644 --- a/src/rt/structs.h +++ b/src/rt/structs.h @@ -104,7 +104,8 @@ typedef struct { } rt_driver_t; typedef struct { - ffi_closure_t closure; + ffi_closure_t driving; + ffi_closure_t effective; unsigned ninputs; unsigned maxinputs; rt_nexus_t **inputs; diff --git a/src/vcode.c b/src/vcode.c index 1f456d2c..9979bd93 100644 --- a/src/vcode.c +++ b/src/vcode.c @@ -2287,6 +2287,10 @@ void vcode_dump_with_mark(int mark_op, vcode_dump_fn_t callback, void *arg) col += vcode_dump_reg(op->result); col += color_printf(" := %s ", vcode_op_string(op->kind)); col += vcode_dump_reg(op->args.items[0]); + if (op->args.count > 1) { + col += printf(" effective "); + col += vcode_dump_reg(op->args.items[1]); + } vcode_dump_result_type(col, op); } break; @@ -5926,12 +5930,17 @@ void emit_add_trigger(vcode_reg_t trigger) "add trigger argument must be trigger"); } -vcode_reg_t emit_port_conversion(vcode_reg_t closure) +vcode_reg_t emit_port_conversion(vcode_reg_t driving, vcode_reg_t effective) { op_t *op = vcode_add_op(VCODE_OP_PORT_CONVERSION); - vcode_add_arg(op, closure); + vcode_add_arg(op, driving); + if (effective != VCODE_INVALID_REG && effective != driving) + vcode_add_arg(op, effective); - VCODE_ASSERT(vcode_reg_kind(closure) == VCODE_TYPE_CLOSURE, + VCODE_ASSERT(vcode_reg_kind(driving) == VCODE_TYPE_CLOSURE, + "port conversion argument must be a closure"); + VCODE_ASSERT(effective == VCODE_INVALID_REG + || vcode_reg_kind(effective) == VCODE_TYPE_CLOSURE, "port conversion argument must be a closure"); return (op->result = vcode_add_reg(vtype_conversion())); diff --git a/src/vcode.h b/src/vcode.h index 24c1faeb..9eb6ac10 100644 --- a/src/vcode.h +++ b/src/vcode.h @@ -528,7 +528,7 @@ vcode_reg_t emit_reflect_subtype(ident_t ptype, vcode_reg_t context, vcode_reg_t locus, vcode_reg_t bounds); vcode_reg_t emit_function_trigger(vcode_reg_t closure); void emit_add_trigger(vcode_reg_t trigger); -vcode_reg_t emit_port_conversion(vcode_reg_t closure); +vcode_reg_t emit_port_conversion(vcode_reg_t driving, vcode_reg_t effective); void emit_convert_in(vcode_reg_t conv, vcode_reg_t nets, vcode_reg_t count); void emit_convert_out(vcode_reg_t conv, vcode_reg_t nets, vcode_reg_t count); diff --git a/test/regress/conv13.vhd b/test/regress/conv13.vhd new file mode 100644 index 00000000..629b432c --- /dev/null +++ b/test/regress/conv13.vhd @@ -0,0 +1,33 @@ +entity conv13 is +end entity; + +architecture test of conv13 is + signal s : integer := 0; +begin + + b1: block is + port ( p : inout real := 0.0 ); + port map ( integer(p) => real(s) ); + begin + inner: process is + begin + p <= 1.0; + wait for 0 ns; + assert p = 1.0; + p <= 1.5; + wait for 0 ns; + assert p = 2.0; + wait; + end process; + end block; + + outer: process is + begin + wait for 0 ns; + assert s = 1; + wait for 0 ns; + assert s = 2; + wait; + end process; + +end architecture; diff --git a/test/regress/testlist.txt b/test/regress/testlist.txt index 01149319..77ddc1f4 100644 --- a/test/regress/testlist.txt +++ b/test/regress/testlist.txt @@ -933,3 +933,4 @@ issue843 normal,2008 bounds43 fail,gold signal35 normal,2008 comp3 normal +conv13 normal -- 2.39.2