From 5311c0cd385e1a1c7f25579ef092482a68c335d9 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Fri, 19 Jun 2026 12:33:31 -0700 Subject: [PATCH] vvp: Add opcode for unary real minus Currently the vvp target emits unary real minus as `0.0 - value`. This is not the same operation for all real values. It loses the negative zero result for `-(+0.0)` and does not reliably flip the sign bit for NaN values whose bits are visible through `$realtobits`. Add `%neg/wr` and use it for unary real minus. This performs a direct negation of the real stack value, so zero, NaN and infinity all use the same operation as unary minus instead of a binary subtraction from zero. Signed-off-by: Lars-Peter Clausen --- Documentation/developer/guide/vvp/opcodes.rst | 4 ++++ tgt-vvp/eval_real.c | 3 +-- vvp/codes.h | 1 + vvp/compile.cc | 1 + vvp/vthread.cc | 9 +++++++++ 5 files changed, 16 insertions(+), 2 deletions(-) diff --git a/Documentation/developer/guide/vvp/opcodes.rst b/Documentation/developer/guide/vvp/opcodes.rst index dd7e6cffc..3303e8b50 100644 --- a/Documentation/developer/guide/vvp/opcodes.rst +++ b/Documentation/developer/guide/vvp/opcodes.rst @@ -812,6 +812,10 @@ result is pushed back on the vec4 stack. This opcode multiplies two real words together. +* %neg/wr + +This opcode negates the real value on top of the real stack. + * %nand Perform the bitwise NAND of two vec4 vectors, and push the result. Each diff --git a/tgt-vvp/eval_real.c b/tgt-vvp/eval_real.c index 0c685624f..1a996b814 100644 --- a/tgt-vvp/eval_real.c +++ b/tgt-vvp/eval_real.c @@ -453,9 +453,8 @@ static void draw_unary_real(ivl_expr_t expr) } if (ivl_expr_opcode(expr) == '-') { - fprintf(vvp_out, " %%pushi/real 0, 0; load 0.0\n"); draw_eval_real(sube); - fprintf(vvp_out, " %%sub/wr;\n"); + fprintf(vvp_out, " %%neg/wr;\n"); return; } diff --git a/vvp/codes.h b/vvp/codes.h index 94a4f26b5..00594e1f0 100644 --- a/vvp/codes.h +++ b/vvp/codes.h @@ -164,6 +164,7 @@ extern bool of_MOD_WR(vthread_t thr, vvp_code_t code); extern bool of_MUL(vthread_t thr, vvp_code_t code); extern bool of_MULI(vthread_t thr, vvp_code_t code); extern bool of_MUL_WR(vthread_t thr, vvp_code_t code); +extern bool of_NEG_WR(vthread_t thr, vvp_code_t code); extern bool of_NAND(vthread_t thr, vvp_code_t code); extern bool of_NANDR(vthread_t thr, vvp_code_t code); extern bool of_NEW_COBJ(vthread_t thr, vvp_code_t code); diff --git a/vvp/compile.cc b/vvp/compile.cc index d41c19d72..fa5391717 100644 --- a/vvp/compile.cc +++ b/vvp/compile.cc @@ -219,6 +219,7 @@ static const struct opcode_table_s opcode_table[] = { { "%muli", of_MULI, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} }, { "%nand", of_NAND, 0, {OA_NONE, OA_NONE, OA_NONE} }, { "%nand/r", of_NANDR, 0, {OA_NONE, OA_NONE, OA_NONE} }, + { "%neg/wr", of_NEG_WR, 0, {OA_NONE, OA_NONE, OA_NONE} }, { "%new/cobj", of_NEW_COBJ, 1, {OA_VPI_PTR,OA_NONE, OA_NONE} }, { "%new/darray",of_NEW_DARRAY,2, {OA_BIT1, OA_STRING,OA_NONE} }, { "%noop", of_NOOP, 0, {OA_NONE, OA_NONE, OA_NONE} }, diff --git a/vvp/vthread.cc b/vvp/vthread.cc index 98cd41a99..2b171111f 100644 --- a/vvp/vthread.cc +++ b/vvp/vthread.cc @@ -4288,6 +4288,15 @@ bool of_MOD_WR(vthread_t thr, vvp_code_t) return true; } +/* + * %neg/wr + */ +bool of_NEG_WR(vthread_t thr, vvp_code_t) +{ + thr->poke_real(0, -thr->peek_real(0)); + return true; +} + /* * %pad/s */