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>
This commit is contained in:
Juha Riihimäki 2009-10-24 15:19:05 +03:00 committed by Aurelien Jarno
parent 71b3c3dea2
commit ca9a32e4f3
1 changed files with 18 additions and 14 deletions

View File

@ -4096,7 +4096,7 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
int pairwise; int pairwise;
int u; int u;
int n; int n;
uint32_t imm; uint32_t imm, mask;
TCGv tmp, tmp2, tmp3, tmp4, tmp5; TCGv tmp, tmp2, tmp3, tmp4, tmp5;
TCGv_i64 tmp64; TCGv_i64 tmp64;
@ -4624,31 +4624,35 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
switch (size) { switch (size) {
case 0: case 0:
if (op == 4) if (op == 4)
imm = 0xff >> -shift; mask = 0xff >> -shift;
else else
imm = (uint8_t)(0xff << shift); mask = (uint8_t)(0xff << shift);
imm |= imm << 8; mask |= mask << 8;
imm |= imm << 16; mask |= mask << 16;
break; break;
case 1: case 1:
if (op == 4) if (op == 4)
imm = 0xffff >> -shift; mask = 0xffff >> -shift;
else else
imm = (uint16_t)(0xffff << shift); mask = (uint16_t)(0xffff << shift);
imm |= imm << 16; mask |= mask << 16;
break; break;
case 2: case 2:
if (op == 4) if (shift < -31 || shift > 31) {
imm = 0xffffffffu >> -shift; mask = 0;
else } else {
imm = 0xffffffffu << shift; if (op == 4)
mask = 0xffffffffu >> -shift;
else
mask = 0xffffffffu << shift;
}
break; break;
default: default:
abort(); abort();
} }
tmp2 = neon_load_reg(rd, pass); tmp2 = neon_load_reg(rd, pass);
tcg_gen_andi_i32(tmp, tmp, imm); tcg_gen_andi_i32(tmp, tmp, mask);
tcg_gen_andi_i32(tmp2, tmp2, ~imm); tcg_gen_andi_i32(tmp2, tmp2, ~mask);
tcg_gen_or_i32(tmp, tmp, tmp2); tcg_gen_or_i32(tmp, tmp, tmp2);
dead_tmp(tmp2); dead_tmp(tmp2);
} }