[v3,1/2] sim: riscv: fix a divw division by -1 bug

Message ID AS8P193MB12856D9B5F6C39CA3193E045E4DF2@AS8P193MB1285.EURP193.PROD.OUTLOOK.COM
State New
Headers
Series [v3,1/2] sim: riscv: fix a divw division by -1 bug |

Checks

Context Check Description
linaro-tcwg-bot/tcwg_gdb_build--master-aarch64 success Build passed
linaro-tcwg-bot/tcwg_gdb_build--master-arm success Build passed
linaro-tcwg-bot/tcwg_gdb_check--master-arm success Test passed
linaro-tcwg-bot/tcwg_gdb_check--master-aarch64 success Test passed

Commit Message

Bernd Edlinger July 5, 2024, 9:08 a.m. UTC
  There is a bug in divw for riscv64 target
with dividing by -1, the result was always 0,
when it should in fact be sign-extended -dividend.
It did not affect the rv32 target, because
these instructions are rv64 only.
Since 1 << 31 is an integer overflow this avoids
an undefined behaviour bug at the same time.

This caused test failures in the gcc testsuite like:

FAIL: gcc.c-torture/execute/arith-rand-ll.c   -O0  execution test
FAIL: gcc.c-torture/execute/arith-rand-ll.c   -O1  execution test
FAIL: gcc.c-torture/execute/arith-rand-ll.c   -O2  execution test
FAIL: gcc.c-torture/execute/arith-rand-ll.c   -O3  execution test
FAIL: gcc.c-torture/execute/arith-rand.c   -O0  execution test
FAIL: gcc.c-torture/execute/arith-rand.c   -O1  execution test
FAIL: gcc.c-torture/execute/arith-rand.c   -O2  execution test
FAIL: gcc.c-torture/execute/arith-rand.c   -O3  execution test
...
---
 sim/riscv/sim-main.c            |  2 +-
 sim/testsuite/riscv/allinsn.exp | 17 ++++++++++++++++-
 sim/testsuite/riscv/divw.s      | 31 +++++++++++++++++++++++++++++++
 3 files changed, 48 insertions(+), 2 deletions(-)
 create mode 100644 sim/testsuite/riscv/divw.s

v2: added a test case
v3: the target architecture detection code added with v2
    caused timeouts when running the testsuite with other
    targets, therefore added a check that "sim/riscv/run"
    exists before trying to execute it
  

Patch

diff --git a/sim/riscv/sim-main.c b/sim/riscv/sim-main.c
index 74729a1a3b2..2b8a800232e 100644
--- a/sim/riscv/sim-main.c
+++ b/sim/riscv/sim-main.c
@@ -724,7 +724,7 @@  execute_m (SIM_CPU *cpu, unsigned_word iw, const struct riscv_opcode *op)
 		  rd_name, rs1_name, rs2_name, rd_name, rs1_name, rs2_name);
       RISCV_ASSERT_RV64 (cpu, "insn: %s", op->name);
       if (EXTEND32 (riscv_cpu->regs[rs2]) == -1)
-	tmp = 1 << 31;
+	tmp = EXTEND32 (-(uint32_t) riscv_cpu->regs[rs1]);
       else if (EXTEND32 (riscv_cpu->regs[rs2]))
 	tmp = EXTEND32 (riscv_cpu->regs[rs1]) / EXTEND32 (riscv_cpu->regs[rs2]);
       else
diff --git a/sim/testsuite/riscv/allinsn.exp b/sim/testsuite/riscv/allinsn.exp
index 9d454039467..51e3e101a64 100644
--- a/sim/testsuite/riscv/allinsn.exp
+++ b/sim/testsuite/riscv/allinsn.exp
@@ -3,7 +3,22 @@ 
 sim_init
 
 # all machines
-set all_machs "riscv32 riscv64"
+set all_machs ""
+
+if [file exists $sim_path] {
+  remote_spawn host "$sim_path --model RV32GC --help"
+  set result [remote_wait host 240]
+  set return_code [lindex $result 0]
+  if { $return_code == 0 } {
+    set all_machs "$all_machs riscv32"
+  }
+  remote_spawn host "$sim_path --model RV64GC --help"
+  set result [remote_wait host 240]
+  set return_code [lindex $result 0]
+  if { $return_code == 0 } {
+    set all_machs "$all_machs riscv64"
+  }
+}
 
 foreach src [lsort [glob -nocomplain $srcdir/$subdir/*.s]] {
     # If we're only testing specific files and this isn't one of them, skip it.
diff --git a/sim/testsuite/riscv/divw.s b/sim/testsuite/riscv/divw.s
new file mode 100644
index 00000000000..ed130358607
--- /dev/null
+++ b/sim/testsuite/riscv/divw.s
@@ -0,0 +1,31 @@ 
+# Basic divw tests.
+# mach: riscv64
+# sim(riscv64): --model RV64GC
+# ld(riscv64): -m elf64lriscv
+# as(riscv64): -march=rv64gc
+
+.include "testutils.inc"
+
+	.macro test_divw  dividend, divisor, answer
+	# Setup inputs.
+	li	a1, \dividend
+	li	a2, \divisor
+
+	# Do the divide.
+	divw	a3, a1, a2
+
+	# Check answer is correct.
+	li	a4, \answer
+	bne	a3, a4, test_failed
+	.endm
+
+
+	start
+
+	test_divw	1, -1, -1
+	test_divw	6, 2, 3
+
+	pass
+
+test_failed:
+	fail