diff options
author | Paolo Bonzini <pbonzini@redhat.com> | 2020-11-23 07:17:47 -0500 |
---|---|---|
committer | Paolo Bonzini <pbonzini@redhat.com> | 2020-12-10 12:14:49 -0500 |
commit | 75b208c28316095c4685e8596ceb9e3f656592e2 (patch) | |
tree | b5ecca206a49e734a405ac1b5da1bcf963016552 | |
parent | 379e9eaed497a2e09b5985e1e15967d7bfea8296 (diff) |
target/i386: fix operand order for PDEP and PEXT
For PDEP and PEXT, the mask is provided in the memory (mod+r/m)
operand, and therefore is loaded in s->T0 by gen_ldst_modrm.
The source is provided in the second source operand (VEX.vvvv)
and therefore is loaded in s->T1. Fix the order in which
they are passed to the helpers.
Reported-by: Lenard Szolnoki <blog@lenardszolnoki.com>
Analyzed-by: Lenard Szolnoki <blog@lenardszolnoki.com>
Fixes: https://bugs.launchpad.net/qemu/+bug/1605123
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
-rw-r--r-- | target/i386/translate.c | 8 | ||||
-rw-r--r-- | tests/tcg/i386/Makefile.target | 3 | ||||
-rw-r--r-- | tests/tcg/i386/test-i386-bmi2.c | 42 |
3 files changed, 49 insertions, 4 deletions
diff --git a/target/i386/translate.c b/target/i386/translate.c index 4c57307e42..e8f5f5803a 100644 --- a/target/i386/translate.c +++ b/target/i386/translate.c @@ -3936,14 +3936,14 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b, } ot = mo_64_32(s->dflag); gen_ldst_modrm(env, s, modrm, ot, OR_TMP0, 0); - /* Note that by zero-extending the mask operand, we + /* Note that by zero-extending the source operand, we automatically handle zero-extending the result. */ if (ot == MO_64) { tcg_gen_mov_tl(s->T1, cpu_regs[s->vex_v]); } else { tcg_gen_ext32u_tl(s->T1, cpu_regs[s->vex_v]); } - gen_helper_pdep(cpu_regs[reg], s->T0, s->T1); + gen_helper_pdep(cpu_regs[reg], s->T1, s->T0); break; case 0x2f5: /* pext Gy, By, Ey */ @@ -3954,14 +3954,14 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b, } ot = mo_64_32(s->dflag); gen_ldst_modrm(env, s, modrm, ot, OR_TMP0, 0); - /* Note that by zero-extending the mask operand, we + /* Note that by zero-extending the source operand, we automatically handle zero-extending the result. */ if (ot == MO_64) { tcg_gen_mov_tl(s->T1, cpu_regs[s->vex_v]); } else { tcg_gen_ext32u_tl(s->T1, cpu_regs[s->vex_v]); } - gen_helper_pext(cpu_regs[reg], s->T0, s->T1); + gen_helper_pext(cpu_regs[reg], s->T1, s->T0); break; case 0x1f6: /* adcx Gy, Ey */ diff --git a/tests/tcg/i386/Makefile.target b/tests/tcg/i386/Makefile.target index a66232a67d..ad187cb2c9 100644 --- a/tests/tcg/i386/Makefile.target +++ b/tests/tcg/i386/Makefile.target @@ -18,6 +18,9 @@ test-i386-pcmpistri: CFLAGS += -msse4.2 run-test-i386-pcmpistri: QEMU_OPTS += -cpu max run-plugin-test-i386-pcmpistri-%: QEMU_OPTS += -cpu max +run-test-i386-bmi2: QEMU_OPTS += -cpu max +run-plugin-test-i386-bmi2-%: QEMU_OPTS += -cpu max + # # hello-i386 is a barebones app # diff --git a/tests/tcg/i386/test-i386-bmi2.c b/tests/tcg/i386/test-i386-bmi2.c new file mode 100644 index 0000000000..935a4d2a73 --- /dev/null +++ b/tests/tcg/i386/test-i386-bmi2.c @@ -0,0 +1,42 @@ +/* See if various BMI2 instructions give expected results */ +#include <assert.h> +#include <stdint.h> + +int main(int argc, char *argv[]) { + uint64_t ehlo = 0x202020204f4c4845ull; + uint64_t mask = 0xa080800302020001ull; + uint32_t result32; + +#ifdef __x86_64 + uint64_t result64; + + /* 64 bits */ + asm volatile ("pextq %2, %1, %0" : "=r"(result64) : "r"(ehlo), "m"(mask)); + assert(result64 == 133); + + asm volatile ("pdepq %2, %1, %0" : "=r"(result64) : "r"(result64), "m"(mask)); + assert(result64 == (ehlo & mask)); + + asm volatile ("pextq %2, %1, %0" : "=r"(result64) : "r"(-1ull), "m"(mask)); + assert(result64 == 511); /* mask has 9 bits set */ + + asm volatile ("pdepq %2, %1, %0" : "=r"(result64) : "r"(-1ull), "m"(mask)); + assert(result64 == mask); +#endif + + /* 32 bits */ + asm volatile ("pextl %2, %k1, %k0" : "=r"(result32) : "r"((uint32_t) ehlo), "m"(mask)); + assert(result32 == 5); + + asm volatile ("pdepl %2, %k1, %k0" : "=r"(result32) : "r"(result32), "m"(mask)); + assert(result32 == (uint32_t)(ehlo & mask)); + + asm volatile ("pextl %2, %k1, %k0" : "=r"(result32) : "r"(-1ull), "m"(mask)); + assert(result32 == 7); /* mask has 3 bits set */ + + asm volatile ("pdepl %2, %k1, %k0" : "=r"(result32) : "r"(-1ull), "m"(mask)); + assert(result32 == (uint32_t)mask); + + return 0; +} + |