From 460342ee1210c6ecc6b94f89678a8882677ddb0a Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Sun, 20 Aug 2023 11:01:31 +0100 Subject: [PATCH] Replace "convstr" opcode with a pure VHDL implementation --- lib/nvc/text_util-body.vhd | 33 +++++++++++++++++++++++++ lib/nvc/text_util.vhd | 2 ++ src/jit/jit-dump.c | 21 ++++++++-------- src/jit/jit-exits.c | 38 ---------------------------- src/jit/jit-exits.h | 2 -- src/jit/jit-irgen.c | 26 ------------------- src/jit/jit-priv.h | 2 -- src/lower.c | 48 +++++++++++++++++++++++++++++++----- src/rt/rt.h | 2 +- src/rt/standard.c | 9 +++++++ src/symbols.txt | 1 + src/vcode.c | 29 +++------------------- src/vcode.h | 2 -- test/regress/gold/image1.txt | 4 +++ test/regress/image1.vhd | 4 +++ test/test_simp.c | 2 +- 16 files changed, 110 insertions(+), 115 deletions(-) diff --git a/lib/nvc/text_util-body.vhd b/lib/nvc/text_util-body.vhd index f1aa1f003..61961beae 100644 --- a/lib/nvc/text_util-body.vhd +++ b/lib/nvc/text_util-body.vhd @@ -395,4 +395,37 @@ package body text_util is return fraction; end if; end function; + + function change_bounds (s : string; l, r : positive) return string is + alias ss : string(l to r) is s; + begin + return ss; + end function; + + function int_to_string (x : t_int64) return string is + variable tmp : t_int64 := x; + variable buf : string(1 to 32); + variable pos : positive := buf'right; + constant zero : natural := character'pos('0'); + begin + loop + buf(pos) := character'val(zero + integer(abs(tmp rem 10))); + pos := pos - 1; + tmp := tmp / 10; + exit when tmp = 0; + end loop; + if x < 0 then + buf(pos) := '-'; + pos := pos - 1; + end if; + return change_bounds(buf(pos + 1 to buf'right), 1, buf'right - pos); + end function; + + function real_to_string (x : real) return string is + function impl (x : real) return string; + attribute foreign of impl : function is "_std_to_string_real"; + begin + return impl(x); + end function; + end package body; diff --git a/lib/nvc/text_util.vhd b/lib/nvc/text_util.vhd index bc82027dd..598e73468 100644 --- a/lib/nvc/text_util.vhd +++ b/lib/nvc/text_util.vhd @@ -37,6 +37,8 @@ package text_util is procedure string_to_int (s : in string; value : out t_int64; used : out natural); function string_to_real (s : string) return real; + function int_to_string (x : t_int64) return string; + function real_to_string (x : real) return string; -- Used to implement 'VALUE for composite types function next_delimiter (s : string; pos : natural) return string; diff --git a/src/jit/jit-dump.c b/src/jit/jit-dump.c index dd97d999c..25097f52d 100644 --- a/src/jit/jit-dump.c +++ b/src/jit/jit-dump.c @@ -67,17 +67,16 @@ const char *jit_exit_name(jit_exit_t exit) { static const char *names[] = { "INDEX_FAIL", "OVERFLOW", "NULL_DEREF", "LENGTH_FAIL", "UNREACHABLE", - "DIV_ZERO", "EXPONENT_FAIL", "REPORT", "ASSERT_FAIL", "INT_TO_STRING", - "REAL_TO_STRING", "RANGE_FAIL", "FUNC_WAIT", "INIT_SIGNAL", - "DRIVE_SIGNAL", "SCHED_WAVEFORM", "SCHED_PROCESS", "TEST_EVENT", - "TEST_ACTIVE", "SCHED_EVENT", "FILE_OPEN", "FILE_CLOSE", - "FILE_READ", "FILE_WRITE", "ENDFILE", "DEBUG_OUT", "ALIAS_SIGNAL", - "MAP_SIGNAL", "MAP_CONST", "RESOLVE_SIGNAL", "LAST_EVENT", - "LAST_ACTIVE", "DISCONNECT", "ELAB_ORDER_FAIL", "FORCE", "RELEASE", - "PUSH_SCOPE", "POP_SCOPE", "IMPLICIT_SIGNAL", "DRIVING", "DRIVING_VALUE", - "CLAIM_TLAB", "COVER_TOGGLE", "PROCESS_INIT", "CLEAR_EVENT", - "IMPLICIT_EVENT", "ENTER_STATE", "REFLECT_VALUE", "REFLECT_SUBTYPE", - "FUNCTION_TRIGGER", "ADD_TRIGGER", + "DIV_ZERO", "EXPONENT_FAIL", "REPORT", "ASSERT_FAIL", "RANGE_FAIL", + "FUNC_WAIT", "INIT_SIGNAL", "DRIVE_SIGNAL", "SCHED_WAVEFORM", + "SCHED_PROCESS", "TEST_EVENT", "TEST_ACTIVE", "SCHED_EVENT", + "FILE_OPEN", "FILE_CLOSE","FILE_READ", "FILE_WRITE", "ENDFILE", + "DEBUG_OUT", "ALIAS_SIGNAL", "MAP_SIGNAL", "MAP_CONST", "RESOLVE_SIGNAL", + "LAST_EVENT", "LAST_ACTIVE", "DISCONNECT", "ELAB_ORDER_FAIL", "FORCE", + "RELEASE", "PUSH_SCOPE", "POP_SCOPE", "IMPLICIT_SIGNAL", "DRIVING", + "DRIVING_VALUE", "CLAIM_TLAB", "COVER_TOGGLE", "PROCESS_INIT", + "CLEAR_EVENT", "IMPLICIT_EVENT", "ENTER_STATE", "REFLECT_VALUE", + "REFLECT_SUBTYPE", "FUNCTION_TRIGGER", "ADD_TRIGGER", }; assert(exit < ARRAY_LEN(names)); return names[exit]; diff --git a/src/jit/jit-exits.c b/src/jit/jit-exits.c index 8c65feae0..cf9692138 100644 --- a/src/jit/jit-exits.c +++ b/src/jit/jit-exits.c @@ -309,18 +309,6 @@ void x_div_zero(tree_t where) jit_msg(tree_loc(where), DIAG_FATAL, "division by zero"); } -ffi_uarray_t x_int_to_string(int64_t value, char *buf, size_t max) -{ - size_t len = checked_sprintf(buf, max, "%"PRIi64, value); - return ffi_wrap(buf, 1, len); -} - -ffi_uarray_t x_real_to_string(double value, char *buf, size_t max) -{ - size_t len = checked_sprintf(buf, max, "%.*g", DBL_DIG, value); - return ffi_wrap(buf, 1, len); -} - void x_elab_order_fail(tree_t where) { assert(tree_kind(where) == T_EXTERNAL_NAME); @@ -601,19 +589,6 @@ void __nvc_do_exit(jit_exit_t which, jit_anchor_t *anchor, jit_scalar_t *args, } break; - case JIT_EXIT_INT_TO_STRING: - { - int64_t value = args[0].integer; - - char *buf = jit_mspace_alloc(28); - - ffi_uarray_t u = x_int_to_string(value, buf, 28); - args[0].pointer = u.ptr; - args[1].integer = u.dims[0].left; - args[2].integer = u.dims[0].length; - } - break; - case JIT_EXIT_ALIAS_SIGNAL: { if (!jit_has_runtime(jit_thread_local()->jit)) @@ -626,19 +601,6 @@ void __nvc_do_exit(jit_exit_t which, jit_anchor_t *anchor, jit_scalar_t *args, } break; - case JIT_EXIT_REAL_TO_STRING: - { - double value = args[0].real; - - char *buf = jit_mspace_alloc(32); - - ffi_uarray_t u = x_real_to_string(value, buf, 32); - args[0].pointer = u.ptr; - args[1].integer = u.dims[0].left; - args[2].integer = u.dims[0].length; - } - break; - case JIT_EXIT_DISCONNECT: { sig_shared_t *shared = args[0].pointer; diff --git a/src/jit/jit-exits.h b/src/jit/jit-exits.h index cce3ca605..98751ae53 100644 --- a/src/jit/jit-exits.h +++ b/src/jit/jit-exits.h @@ -59,8 +59,6 @@ void x_exponent_fail(int64_t value, tree_t where); void x_overflow(int64_t lhs, int64_t rhs, tree_t where); void x_null_deref(tree_t where); void x_div_zero(tree_t where); -ffi_uarray_t x_int_to_string(int64_t value, char *buf, size_t max); -ffi_uarray_t x_real_to_string(double value, char *buf, size_t max); void x_assert_fail(const uint8_t *msg, int32_t msg_len, int8_t severity, int64_t hint_left, int64_t hint_right, int8_t hint_valid, object_t *where); diff --git a/src/jit/jit-irgen.c b/src/jit/jit-irgen.c index eef0b0d5e..54838defa 100644 --- a/src/jit/jit-irgen.c +++ b/src/jit/jit-irgen.c @@ -3267,29 +3267,6 @@ static void irgen_op_active(jit_irgen_t *g, int op) g->map[vcode_get_result(op)] = j_recv(g, 0); } -static void irgen_op_convstr(jit_irgen_t *g, int op) -{ - jit_value_t value = irgen_get_arg(g, op, 0); - - j_send(g, 0, value); - - switch (vcode_reg_kind(vcode_get_arg(op, 0))) { - case VCODE_TYPE_INT: - macro_exit(g, JIT_EXIT_INT_TO_STRING); - break; - case VCODE_TYPE_REAL: - macro_exit(g, JIT_EXIT_REAL_TO_STRING); - break; - default: - vcode_dump_with_mark(op, NULL, NULL); - fatal_trace("invalid type in convstr"); - } - - g->map[vcode_get_result(op)] = j_recv(g, 0); - j_recv(g, 1); // Left - j_recv(g, 2); // Length -} - static void irgen_op_debug_out(jit_irgen_t *g, int op) { jit_value_t value = irgen_get_arg(g, op, 0); @@ -3806,9 +3783,6 @@ static void irgen_block(jit_irgen_t *g, vcode_block_t block) case VCODE_OP_CLEAR_EVENT: irgen_op_clear_event(g, i); break; - case VCODE_OP_CONVSTR: - irgen_op_convstr(g, i); - break; case VCODE_OP_DEBUG_OUT: irgen_op_debug_out(g, i); break; diff --git a/src/jit/jit-priv.h b/src/jit/jit-priv.h index a38bd660d..f23f25485 100644 --- a/src/jit/jit-priv.h +++ b/src/jit/jit-priv.h @@ -122,8 +122,6 @@ typedef enum { JIT_EXIT_EXPONENT_FAIL, JIT_EXIT_REPORT, JIT_EXIT_ASSERT_FAIL, - JIT_EXIT_INT_TO_STRING, - JIT_EXIT_REAL_TO_STRING, JIT_EXIT_RANGE_FAIL, JIT_EXIT_FUNC_WAIT, JIT_EXIT_INIT_SIGNAL, diff --git a/src/lower.c b/src/lower.c index 090ce1643..f38d712fa 100644 --- a/src/lower.c +++ b/src/lower.c @@ -7903,10 +7903,23 @@ static void lower_enum_image_helper(type_t type, vcode_reg_t preg) } } -static void lower_physical_image_helper(type_t type, vcode_reg_t preg) +static void lower_physical_image_helper(lower_unit_t *lu, type_t type, + vcode_reg_t preg) { vcode_type_t vint64 = vtype_int(INT64_MIN, INT64_MAX); - vcode_reg_t num_reg = emit_convstr(emit_cast(vint64, vint64, preg)); + vcode_type_t vchar = vtype_char(); + vcode_type_t vstring = vtype_uarray(1, vchar, vchar); + + vcode_reg_t cast_reg = emit_cast(vint64, vint64, preg); + ident_t conv_fn = + ident_new("NVC.TEXT_UTIL.INT_TO_STRING(21NVC.TEXT_UTIL.T_INT64)S"); + vcode_reg_t conv_args[] = { + lower_context_for_call(lu, conv_fn), + cast_reg + }; + vcode_reg_t num_reg = emit_fcall(conv_fn, vstring, vstring, + VCODE_CC_VHDL, conv_args, 2); + vcode_reg_t num_len = emit_uarray_len(num_reg, 0); const char *unit0 = istr(ident_downcase(tree_ident(type_unit(type, 0)))); @@ -7936,9 +7949,32 @@ static void lower_physical_image_helper(type_t type, vcode_reg_t preg) emit_return(emit_wrap(mem_reg, dims, 1)); } -static void lower_numeric_image_helper(type_t type, vcode_reg_t preg) +static void lower_numeric_image_helper(lower_unit_t *lu, type_t type, + vcode_reg_t preg) { - vcode_reg_t str_reg = emit_convstr(preg); + vcode_type_t vchar = vtype_char(); + vcode_type_t vstring = vtype_uarray(1, vchar, vchar); + + ident_t conv_fn; + vcode_reg_t arg_reg; + + if (type_is_real(type)) { + arg_reg = preg; + conv_fn = ident_new("NVC.TEXT_UTIL.REAL_TO_STRING(R)S"); + } + else { + vcode_type_t vint64 = vtype_int(INT64_MIN, INT64_MAX); + arg_reg = emit_cast(vint64, vint64, preg); + conv_fn = ident_new( + "NVC.TEXT_UTIL.INT_TO_STRING(21NVC.TEXT_UTIL.T_INT64)S"); + } + + vcode_reg_t conv_args[] = { + lower_context_for_call(lu, conv_fn), + arg_reg + }; + vcode_reg_t str_reg = emit_fcall(conv_fn, vstring, vstring, + VCODE_CC_VHDL, conv_args, 2); emit_return(str_reg); } @@ -8224,10 +8260,10 @@ static void lower_image_helper(lower_unit_t *lu, object_t *obj) break; case T_INTEGER: case T_REAL: - lower_numeric_image_helper(type, preg); + lower_numeric_image_helper(lu, type, preg); break; case T_PHYSICAL: - lower_physical_image_helper(type, preg); + lower_physical_image_helper(lu, type, preg); break; case T_RECORD: lower_record_image_helper(lu, type, preg); diff --git a/src/rt/rt.h b/src/rt/rt.h index 6cf01165a..e175aa79e 100644 --- a/src/rt/rt.h +++ b/src/rt/rt.h @@ -23,7 +23,7 @@ #include -#define RT_ABI_VERSION 19 +#define RT_ABI_VERSION 20 #define RT_ALIGN_MASK 0x7 #define RT_MULTITHREADED 0 diff --git a/src/rt/standard.c b/src/rt/standard.c index f30060a04..7e8b0c4e0 100644 --- a/src/rt/standard.c +++ b/src/rt/standard.c @@ -148,6 +148,15 @@ void _std_to_ostring_bit_vec(const uint8_t *vec_ptr, int64_t vec_len, *u = bit_vec_to_string(vec_ptr, vec_len, 3); } +DLLEXPORT +void _std_to_string_real(double value, ffi_uarray_t *u) +{ + const size_t max = 32; + char *buf = jit_mspace_alloc(max); + size_t len = checked_sprintf(buf, max, "%.*g", DBL_DIG, value); + *u = ffi_wrap(buf, 1, len); +} + void _std_standard_init(void) { // Dummy function to force linking diff --git a/src/symbols.txt b/src/symbols.txt index a85e08a83..e7ba3a577 100644 --- a/src/symbols.txt +++ b/src/symbols.txt @@ -6,6 +6,7 @@ _std_standard_now; _std_to_hstring_bit_vec; _std_to_ostring_bit_vec; + _std_to_string_real; _std_to_string_real_digits; _std_to_string_real_format; _std_to_string_time; diff --git a/src/vcode.c b/src/vcode.c index 36569285a..f674267a0 100644 --- a/src/vcode.c +++ b/src/vcode.c @@ -420,10 +420,6 @@ void vcode_heap_allocate(vcode_reg_t reg) // Returns a pointer into the C heap break; - case VCODE_OP_CONVSTR: - // Runtime code allocates in mspace - break; - case VCODE_OP_LOAD: { if (vcode_reg_kind(reg) != VCODE_TYPE_UARRAY) @@ -961,10 +957,9 @@ const char *vcode_op_string(vcode_op_t op) "range length", "exponent check", "zero check", "map const", "resolve signal", "push scope", "pop scope", "alias signal", "trap add", "trap sub", "trap mul", "force", "release", "link instance", - "unreachable", "package init", "canon value", "convstr", - "trap neg", "process init", "clear event", "trap exp", "implicit event", - "enter state", "reflect value", "reflect subtype", "function trigger", - "add trigger", + "unreachable", "package init", "trap neg", "process init", "clear event", + "trap exp", "implicit event", "enter state", "reflect value", + "reflect subtype", "function trigger", "add trigger", }; if ((unsigned)op >= ARRAY_LEN(strs)) return "???"; @@ -1659,7 +1654,6 @@ void vcode_dump_with_mark(int mark_op, vcode_dump_fn_t callback, void *arg) break; case VCODE_OP_NOT: - case VCODE_OP_CONVSTR: { col += vcode_dump_reg(op->result); col += printf(" := %s ", vcode_op_string(op->kind)); @@ -5660,23 +5654,6 @@ vcode_reg_t emit_undefined(vcode_type_t type, vcode_type_t bounds) return op->result; } -vcode_reg_t emit_convstr(vcode_reg_t value) -{ - VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CONVSTR) { - if (other->args.items[0] == value) - return other->result; - } - - op_t *op = vcode_add_op(VCODE_OP_CONVSTR); - vcode_add_arg(op, value); - - VCODE_ASSERT(vtype_is_scalar(vcode_reg_type(value)), - "convstr value must be scalar"); - - vcode_type_t vchar = vtype_char(); - return (op->result = vcode_add_reg(vtype_uarray(1, vchar, vchar))); -} - void emit_debug_info(const loc_t *loc) { if (!loc_invalid_p(loc)) diff --git a/src/vcode.h b/src/vcode.h index 0615e292e..18d169fc2 100644 --- a/src/vcode.h +++ b/src/vcode.h @@ -150,7 +150,6 @@ typedef enum { VCODE_OP_LINK_INSTANCE, VCODE_OP_UNREACHABLE, VCODE_OP_PACKAGE_INIT, - VCODE_OP_CONVSTR, VCODE_OP_TRAP_NEG, VCODE_OP_PROCESS_INIT, VCODE_OP_CLEAR_EVENT, @@ -513,7 +512,6 @@ void emit_push_scope(vcode_reg_t locus, vcode_type_t type); void emit_pop_scope(void); void emit_alias_signal(vcode_reg_t signal, vcode_reg_t locus); void emit_unreachable(vcode_reg_t locus); -vcode_reg_t emit_convstr(vcode_reg_t value); void emit_enter_state(vcode_reg_t state); vcode_reg_t emit_reflect_value(ident_t ptype, vcode_reg_t value, vcode_reg_t context, vcode_reg_t locus, diff --git a/test/regress/gold/image1.txt b/test/regress/gold/image1.txt index 41b568d89..2c3bd63f8 100644 --- a/test/regress/gold/image1.txt +++ b/test/regress/gold/image1.txt @@ -10,3 +10,7 @@ 1010ps+0: Report Note: a 1010ps+0: Report Note: 3 1010ps+0: Report Note: 20 unit_1 +1010ps+0: Report Note: 0 +1010ps+0: Report Note: 10 +1010ps+0: Report Note: -2147483648 +1010ps+0: Report Note: 2147483647 diff --git a/test/regress/image1.vhd b/test/regress/image1.vhd index 839cf4872..52a770af0 100644 --- a/test/regress/image1.vhd +++ b/test/regress/image1.vhd @@ -56,6 +56,10 @@ begin print_enum1(e1); report my_int'image(j); report my_phys'image(2 UNIT_2); + report integer'image(0); + report integer'image(10); + report integer'image(integer'left); + report integer'image(integer'right); wait; end process; diff --git a/test/test_simp.c b/test/test_simp.c index a9101cedc..0b4e60d48 100644 --- a/test/test_simp.c +++ b/test/test_simp.c @@ -341,7 +341,7 @@ START_TEST(test_ffold) fail_unless(folded_b(tree_value(tree_decl(b, 13)), true)); fail_unless(folded_b(tree_value(tree_decl(b, 14)), false)); fail_unless(folded_b(tree_value(tree_decl(b, 15)), true)); - fail_unless(folded_b(tree_value(tree_decl(b, 16)), true)); + fail_if(folded_b(tree_value(tree_decl(b, 16)), true)); // Cannot fold now fail_unless(folded_b(tree_value(tree_decl(b, 17)), true)); fail_unless(folded_b(tree_value(tree_decl(b, 18)), true)); fail_unless(folded_i(tree_value(tree_decl(b, 19)), 80));