aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJuha Riihimäki <juha.riihimaki@nokia.com>2009-10-24 15:19:05 +0300
committerAurelien Jarno <aurelien@aurel32.net>2009-10-27 09:46:26 +0100
commitca9a32e4f3da59f07ae2c68df68d1130e02d4665 (patch)
treea470f736a4016252b83ea01048604fa44ff29fd0
parent71b3c3dea21a310c5df7406cdc1cffc64cf14c18 (diff)
target-arm: fix neon vsri, vshl and vsli ops
Shift by immediate value is incorrectly overwritten by a temporary variable in the processing of NEON vsri, vshl and vsli instructions. This patch has been revised to also include a fix for the special case where the code would previously try to shift an integer value over 31 bits left/right. Signed-off-by: Juha Riihimäki <juha.riihimaki@nokia.com> Acked-by: Laurent Desnogues <laurent.desnogues@gmail.com> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
-rw-r--r--target-arm/translate.c32
1 files changed, 18 insertions, 14 deletions
diff --git a/target-arm/translate.c b/target-arm/translate.c
index 70cf1b268a..ace6c454f8 100644
--- a/target-arm/translate.c
+++ b/target-arm/translate.c
@@ -4096,7 +4096,7 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
int pairwise;
int u;
int n;
- uint32_t imm;
+ uint32_t imm, mask;
TCGv tmp, tmp2, tmp3, tmp4, tmp5;
TCGv_i64 tmp64;
@@ -4624,31 +4624,35 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
switch (size) {
case 0:
if (op == 4)
- imm = 0xff >> -shift;
+ mask = 0xff >> -shift;
else
- imm = (uint8_t)(0xff << shift);
- imm |= imm << 8;
- imm |= imm << 16;
+ mask = (uint8_t)(0xff << shift);
+ mask |= mask << 8;
+ mask |= mask << 16;
break;
case 1:
if (op == 4)
- imm = 0xffff >> -shift;
+ mask = 0xffff >> -shift;
else
- imm = (uint16_t)(0xffff << shift);
- imm |= imm << 16;
+ mask = (uint16_t)(0xffff << shift);
+ mask |= mask << 16;
break;
case 2:
- if (op == 4)
- imm = 0xffffffffu >> -shift;
- else
- imm = 0xffffffffu << shift;
+ if (shift < -31 || shift > 31) {
+ mask = 0;
+ } else {
+ if (op == 4)
+ mask = 0xffffffffu >> -shift;
+ else
+ mask = 0xffffffffu << shift;
+ }
break;
default:
abort();
}
tmp2 = neon_load_reg(rd, pass);
- tcg_gen_andi_i32(tmp, tmp, imm);
- tcg_gen_andi_i32(tmp2, tmp2, ~imm);
+ tcg_gen_andi_i32(tmp, tmp, mask);
+ tcg_gen_andi_i32(tmp2, tmp2, ~mask);
tcg_gen_or_i32(tmp, tmp, tmp2);
dead_tmp(tmp2);
}