diff options
Diffstat (limited to 'results/classifier/118/all/618')
| -rw-r--r-- | results/classifier/118/all/618 | 125 |
1 files changed, 125 insertions, 0 deletions
diff --git a/results/classifier/118/all/618 b/results/classifier/118/all/618 new file mode 100644 index 00000000..39cb9402 --- /dev/null +++ b/results/classifier/118/all/618 @@ -0,0 +1,125 @@ +TCG: 0.915 +hypervisor: 0.913 +architecture: 0.905 +ppc: 0.902 +graphic: 0.894 +performance: 0.888 +device: 0.888 +debug: 0.888 +risc-v: 0.887 +vnc: 0.886 +assembly: 0.886 +arm: 0.885 +peripherals: 0.880 +user-level: 0.879 +semantic: 0.874 +KVM: 0.870 +mistranslation: 0.869 +files: 0.868 +PID: 0.865 +permissions: 0.861 +kernel: 0.855 +socket: 0.855 +virtual: 0.853 +register: 0.850 +VMM: 0.831 +boot: 0.824 +x86: 0.815 +network: 0.777 +i386: 0.750 + +overflow condition code determined incorrectly after subtraction on s390x +Description of problem: +Paul Eggert found this bug, just by taking a look at the file `qemu/target/s390x/tcg/cc_helper.c`. + +The following program +[foo.c](/uploads/c1f425684fd661c4437950d7d8ddf31d/foo.c) +``` +#include <stdio.h> + +int overflow_32 (int x, int y) +{ + int sum; + return __builtin_sub_overflow (x, y, &sum); +} + +int overflow_64 (long long x, long long y) +{ + long sum; + return __builtin_sub_overflow (x, y, &sum); +} + +int a1 = 0; +int b1 = -2147483648; +long long a2 = 0L; +long long b2 = -9223372036854775808L; + +int main () +{ + { + int a = a1; + int b = b1; + printf ("a = 0x%x, b = 0x%x\n", a, b); + printf ("no_overflow = %d\n", ! overflow_32 (a, b)); + } + { + long long a = a2; + long long b = b2; + printf ("a = 0x%llx, b = 0x%llx\n", a, b); + printf ("no_overflow = %d\n", ! overflow_64 (a, b)); + } +} +``` +should print +``` +a = 0x0, b = 0x80000000 +no_overflow = 0 +a = 0x0, b = 0x8000000000000000 +no_overflow = 0 +``` +However, when compiled as an s390x program and executed through qemu 6.1.0 (Linux user-mode), it prints 'no_overflow = 1' twice. +``` +$ s390x-linux-gnu-gcc-10 --version +s390x-linux-gnu-gcc-10 (Ubuntu 10.3.0-1ubuntu1~20.04) 10.3.0 +``` + +``` +$ s390x-linux-gnu-gcc-10 -static foo.c +$ ~/inst-qemu/6.1.0/bin/qemu-s390x a.out +a = 0x0, b = 0x80000000 +no_overflow = 1 +a = 0x0, b = 0x8000000000000000 +no_overflow = 1 +``` + +``` +$ s390x-linux-gnu-gcc-10 -O2 -static foo.c +$ ~/inst-qemu/6.1.0/bin/qemu-s390x a.out +a = 0x0, b = 0x80000000 +no_overflow = 1 +a = 0x0, b = 0x8000000000000000 +no_overflow = 1 +``` + +The code generated by 's390x-linux-gnu-gcc-10 -O2' makes use of the 'o' (overflow / ones) condition code: +``` +overflow_64: + lgr %r1,%r2 ;; copy a into %r1 + lghi %r2,0 + sgr %r1,%r3 ;; subtract b from a + bnor %r14 ;; if no overflow, return %r2 = 0 + lghi %r2,1 + br %r14 ;; otherwise, return %r2 = 1 +``` + +The condition code and the overflow bit are defined in the z/Architecture Principles of Operation (POP) http://publibfi.boulder.ibm.com/epubs/pdf/dz9zr011.pdf page 7-5 / 7-6 / 7-388 : "In mathematical terms, signed addition and subtraction produce a fixed-point overflow when the result is outside the range of representation for signed binary integers." + +I conclude that the bug is in QEMU: QEMU does not set the overflow condition code correctly. +Steps to reproduce: +[foo.static.s390x](/uploads/e4b79b019db590f3a4b13cac41e57ba6/foo.static.s390x) +(the result of "s390x-linux-gnu-gcc-10 -static -O2 foo.c -o foo.static.s390x") + +1. `qemu-s390x foo.static.s390x` +Additional information: +The attached patch fixes it. +[0002-s390x-Fix-determination-of-overflow-condition-code-a.patch](/uploads/8d414f84fe0ed36bf07bd28f5e7836ab/0002-s390x-Fix-determination-of-overflow-condition-code-a.patch) |