summary refs log tree commit diff stats
path: root/results/classifier/118/all/2372
diff options
context:
space:
mode:
authorChristian Krinitsin <mail@krinitsin.com>2025-06-16 16:59:00 +0000
committerChristian Krinitsin <mail@krinitsin.com>2025-06-16 16:59:33 +0000
commit9aba81d8eb048db908c94a3c40c25a5fde0caee6 (patch)
treeb765e7fb5e9a3c2143c68b0414e0055adb70e785 /results/classifier/118/all/2372
parentb89a938452613061c0f1f23e710281cf5c83cb29 (diff)
downloademulator-bug-study-9aba81d8eb048db908c94a3c40c25a5fde0caee6.tar.gz
emulator-bug-study-9aba81d8eb048db908c94a3c40c25a5fde0caee6.zip
add 18th iteration of classifier
Diffstat (limited to 'results/classifier/118/all/2372')
-rw-r--r--results/classifier/118/all/2372139
1 files changed, 139 insertions, 0 deletions
diff --git a/results/classifier/118/all/2372 b/results/classifier/118/all/2372
new file mode 100644
index 00000000..888e356b
--- /dev/null
+++ b/results/classifier/118/all/2372
@@ -0,0 +1,139 @@
+graphic: 0.975
+semantic: 0.973
+architecture: 0.965
+virtual: 0.951
+performance: 0.948
+permissions: 0.947
+assembly: 0.946
+device: 0.939
+debug: 0.939
+peripherals: 0.934
+hypervisor: 0.934
+TCG: 0.930
+files: 0.930
+socket: 0.930
+arm: 0.929
+network: 0.922
+PID: 0.912
+register: 0.908
+ppc: 0.903
+vnc: 0.901
+kernel: 0.887
+boot: 0.887
+risc-v: 0.886
+user-level: 0.882
+VMM: 0.864
+mistranslation: 0.862
+i386: 0.824
+KVM: 0.808
+x86: 0.802
+
+A bug in AArch64 UMOPA/UMOPS (4-way) instruction
+Description of problem:
+umopa computes the multiplication of two matrices in the source registers and accumulates the result to the destination register. A source register’s element size is 16 bits, while a destination register’s element size is 64 bits in case of the 4-way variant of this instruction. Before performing matrix multiplication, each element should be zero-extended to a 64-bit element.
+
+However, the current implementation of the helper function fails to convert the element type correctly. Below is the helper function implementation:
+```
+// target/arm/tcg/sme_helper.c
+#define DEF_IMOP_64(NAME, NTYPE, MTYPE) \
+static uint64_t NAME(uint64_t n, uint64_t m, uint64_t a, uint8_t p, bool neg) \
+{                                                                           \
+    uint64_t sum = 0;                                                       \
+    /* Apply P to N as a mask, making the inactive elements 0. */           \
+    n &= expand_pred_h(p);                                                  \
+    sum += (NTYPE)(n >> 0) * (MTYPE)(m >> 0);                               \
+    sum += (NTYPE)(n >> 16) * (MTYPE)(m >> 16);                             \
+    sum += (NTYPE)(n >> 32) * (MTYPE)(m >> 32);                             \
+    sum += (NTYPE)(n >> 48) * (MTYPE)(m >> 48);                             \
+    return neg ? a - sum : a + sum;                                         \
+}
+
+DEF_IMOP_64(umopa_d, uint16_t, uint16_t)
+```
+When the multiplication is performed, each element, such as `(NTYPE)(n >> 0)`, is automatically converted to `int32_t`, so the computation result has a type `int32_t`. The result is then converted to `uint64_t`, and it is added to `sum`. It seems the elements should be casted to `uint64_t` **before** performing the multiplication.
+Steps to reproduce:
+1. Write `test.c`.
+```
+#include <stdio.h>
+
+char i_P1[4] = { 0xff, 0xff, 0xff, 0xff };
+char i_P5[4] = { 0xff, 0xff, 0xff, 0xff };
+char i_Z0[32] = { // Set only the first element as non-zero
+    0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+    0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+    0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+    0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+};
+char i_Z20[32] = { // Set only the first element as non-zero
+    0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+    0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+    0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+    0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+};
+char i_ZA2H[128] = { 0x0, };
+char o_ZA2H[128];
+
+void __attribute__ ((noinline)) show_state() {
+    for (int i = 0; i < 8; i++) {
+        for (int j = 0; j < 16; j++) {
+            printf("%02x ", o_ZA2H[16*i+j]);
+        }
+        printf("\n");
+    }
+}
+
+void __attribute__ ((noinline)) run() {
+    __asm__ (
+        ".arch armv9.3-a+sme\n"
+        "smstart\n"
+        "adrp x29, i_P1\n"
+        "add x29, x29, :lo12:i_P1\n"
+        "ldr p1, [x29]\n"
+        "adrp x29, i_P5\n"
+        "add x29, x29, :lo12:i_P5\n"
+        "ldr p5, [x29]\n"
+        "adrp x29, i_Z0\n"
+        "add x29, x29, :lo12:i_Z0\n"
+        "ldr z0, [x29]\n"
+        "adrp x29, i_Z20\n"
+        "add x29, x29, :lo12:i_Z20\n"
+        "ldr z20, [x29]\n"
+        "adrp x29, i_ZA2H\n"
+        "add x29, x29, :lo12:i_ZA2H\n"
+        "mov x15, 0\n"
+        "ld1d {za2h.d[w15, 0]}, p1, [x29]\n"
+        "add x29, x29, 32\n"
+        "ld1d {za2h.d[w15, 1]}, p1, [x29]\n"
+        "add x29, x29, 32\n"
+        "mov x15, 2\n"
+        "ld1d {za2h.d[w15, 0]}, p1, [x29]\n"
+        "add x29, x29, 32\n"
+        "ld1d {za2h.d[w15, 1]}, p1, [x29]\n"
+        ".inst 0xa1f43402\n" // umopa   za2.d, p5/m, p1/m, z0.h, z20.h
+        "adrp x29, o_ZA2H\n"
+        "add x29, x29, :lo12:o_ZA2H\n"
+        "mov x15, 0\n"
+        "st1d {za2h.d[w15, 0]}, p1, [x29]\n"
+        "add x29, x29, 32\n"
+        "st1d {za2h.d[w15, 1]}, p1, [x29]\n"
+        "add x29, x29, 32\n"
+        "mov x15, 2\n"
+        "st1d {za2h.d[w15, 0]}, p1, [x29]\n"
+        "add x29, x29, 32\n"
+        "st1d {za2h.d[w15, 1]}, p1, [x29]\n"
+        "smstop\n"
+        ".arch armv8-a\n"
+    );
+}
+
+int main(int argc, char **argv) {
+    run();
+    show_state();
+    return 0;
+}
+```
+2. Compile `test.bin` using this command: `aarch64-linux-gnu-gcc-12 -O2 -no-pie ./test.c -o ./test.bin`.
+3. Run `QEMU` using this command: `qemu-aarch64 -L /usr/aarch64-linux-gnu/ -cpu max,sme256=on ./test.bin`.
+4. The program, runs on top of the buggy QEMU, prints the first 8 bytes of `ZA2H` as `01 00 fe ff ff ff ff ff`. It should print `01 00 fe ff 00 00 00 00` after the bug is fixed.
+Additional information:
+