aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2011-03-11 10:09:58 +0000
committerAurelien Jarno <aurelien@aurel32.net>2011-03-22 07:56:08 +0100
commite1d177b922f52569e900e96d611caa09655bdec9 (patch)
treecc59ba99ea1a52d258c442da47aaa646d8fef3e5
parentdb6e2e65adddfcdc3f81026df7fd490e13813e8a (diff)
target-arm: Set Q bit for overflow in SMUAD and SMLAD
SMUAD and SMLAD are supposed to set the Q bit if the addition of the two 16x16 multiply products and optional accumulator overflows considered as a signed value. However we were only doing this check for the addition of the accumulator, not when adding the products, with the effect that we were mishandling the edge case where both inputs are 0x80008000. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
-rw-r--r--target-arm/translate.c16
1 files changed, 12 insertions, 4 deletions
diff --git a/target-arm/translate.c b/target-arm/translate.c
index 0afdbfbbcf..2351c318e3 100644
--- a/target-arm/translate.c
+++ b/target-arm/translate.c
@@ -7038,11 +7038,15 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
if (insn & (1 << 5))
gen_swap_half(tmp2);
gen_smul_dual(tmp, tmp2);
- /* This addition cannot overflow. */
if (insn & (1 << 6)) {
+ /* This subtraction cannot overflow. */
tcg_gen_sub_i32(tmp, tmp, tmp2);
} else {
- tcg_gen_add_i32(tmp, tmp, tmp2);
+ /* This addition cannot overflow 32 bits;
+ * however it may overflow considered as a signed
+ * operation, in which case we must set the Q flag.
+ */
+ gen_helper_add_setq(tmp, tmp, tmp2);
}
tcg_temp_free_i32(tmp2);
if (insn & (1 << 22)) {
@@ -7860,11 +7864,15 @@ static int disas_thumb2_insn(CPUState *env, DisasContext *s, uint16_t insn_hw1)
if (op)
gen_swap_half(tmp2);
gen_smul_dual(tmp, tmp2);
- /* This addition cannot overflow. */
if (insn & (1 << 22)) {
+ /* This subtraction cannot overflow. */
tcg_gen_sub_i32(tmp, tmp, tmp2);
} else {
- tcg_gen_add_i32(tmp, tmp, tmp2);
+ /* This addition cannot overflow 32 bits;
+ * however it may overflow considered as a signed
+ * operation, in which case we must set the Q flag.
+ */
+ gen_helper_add_setq(tmp, tmp, tmp2);
}
tcg_temp_free_i32(tmp2);
if (rs != 15)