diff mbox series

[1/6] target/arm: Fix SVE signed division vs x86 overflow exception

Message ID 20180629001538.11415-2-richard.henderson@linaro.org
State New
Headers show
Series target/arm SVE updates | expand

Commit Message

Richard Henderson June 29, 2018, 12:15 a.m. UTC
We already check for the same condition within the normal integer
sdiv and sdiv64 helpers.  Use a slightly different formation that
does not require deducing the expression type.

Fixes: f97cfd596ed
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>

---
 target/arm/sve_helper.c | 16 +++++++++++-----
 1 file changed, 11 insertions(+), 5 deletions(-)

-- 
2.17.1

Comments

Philippe Mathieu-Daudé June 29, 2018, 12:42 a.m. UTC | #1
On 06/28/2018 09:15 PM, Richard Henderson wrote:
> We already check for the same condition within the normal integer

> sdiv and sdiv64 helpers.  Use a slightly different formation that

> does not require deducing the expression type.

> 

> Fixes: f97cfd596ed

> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>


Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>


> ---

>  target/arm/sve_helper.c | 16 +++++++++++-----

>  1 file changed, 11 insertions(+), 5 deletions(-)

> 

> diff --git a/target/arm/sve_helper.c b/target/arm/sve_helper.c

> index 790cbacd14..7d7fc90566 100644

> --- a/target/arm/sve_helper.c

> +++ b/target/arm/sve_helper.c

> @@ -369,7 +369,13 @@ void HELPER(NAME)(void *vd, void *vn, void *vm, void *vg, uint32_t desc) \

>  #define DO_MIN(N, M)  ((N) >= (M) ? (M) : (N))

>  #define DO_ABD(N, M)  ((N) >= (M) ? (N) - (M) : (M) - (N))

>  #define DO_MUL(N, M)  (N * M)

> -#define DO_DIV(N, M)  (M ? N / M : 0)

> +

> +/* The zero divisor case is architectural; the -1 divisor case works

> + * around the x86 INT_MIN / -1 overflow exception without having to

> + * deduce the minimum integer for the type of the expression.

> + */

> +#define DO_SDIV(N, M) (unlikely(M == 0) ? 0 : unlikely(M == -1) ? -N : N / M)

> +#define DO_UDIV(N, M) (unlikely(M == 0) ? 0 : N / M)

>  

>  DO_ZPZZ(sve_and_zpzz_b, uint8_t, H1, DO_AND)

>  DO_ZPZZ(sve_and_zpzz_h, uint16_t, H1_2, DO_AND)

> @@ -477,11 +483,11 @@ DO_ZPZZ(sve_umulh_zpzz_h, uint16_t, H1_2, do_mulh_h)

>  DO_ZPZZ(sve_umulh_zpzz_s, uint32_t, H1_4, do_mulh_s)

>  DO_ZPZZ_D(sve_umulh_zpzz_d, uint64_t, do_umulh_d)

>  

> -DO_ZPZZ(sve_sdiv_zpzz_s, int32_t, H1_4, DO_DIV)

> -DO_ZPZZ_D(sve_sdiv_zpzz_d, int64_t, DO_DIV)

> +DO_ZPZZ(sve_sdiv_zpzz_s, int32_t, H1_4, DO_SDIV)

> +DO_ZPZZ_D(sve_sdiv_zpzz_d, int64_t, DO_SDIV)

>  

> -DO_ZPZZ(sve_udiv_zpzz_s, uint32_t, H1_4, DO_DIV)

> -DO_ZPZZ_D(sve_udiv_zpzz_d, uint64_t, DO_DIV)

> +DO_ZPZZ(sve_udiv_zpzz_s, uint32_t, H1_4, DO_UDIV)

> +DO_ZPZZ_D(sve_udiv_zpzz_d, uint64_t, DO_UDIV)

>  

>  /* Note that all bits of the shift are significant

>     and not modulo the element size.  */

>
Peter Maydell June 29, 2018, 8:29 a.m. UTC | #2
On 29 June 2018 at 01:15, Richard Henderson
<richard.henderson@linaro.org> wrote:
> We already check for the same condition within the normal integer

> sdiv and sdiv64 helpers.  Use a slightly different formation that

> does not require deducing the expression type.

>

> Fixes: f97cfd596ed

> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>

> ---

>  target/arm/sve_helper.c | 16 +++++++++++-----

>  1 file changed, 11 insertions(+), 5 deletions(-)

>

> diff --git a/target/arm/sve_helper.c b/target/arm/sve_helper.c

> index 790cbacd14..7d7fc90566 100644

> --- a/target/arm/sve_helper.c

> +++ b/target/arm/sve_helper.c

> @@ -369,7 +369,13 @@ void HELPER(NAME)(void *vd, void *vn, void *vm, void *vg, uint32_t desc) \

>  #define DO_MIN(N, M)  ((N) >= (M) ? (M) : (N))

>  #define DO_ABD(N, M)  ((N) >= (M) ? (N) - (M) : (M) - (N))

>  #define DO_MUL(N, M)  (N * M)

> -#define DO_DIV(N, M)  (M ? N / M : 0)

> +

> +/* The zero divisor case is architectural; the -1 divisor case works

> + * around the x86 INT_MIN / -1 overflow exception without having to

> + * deduce the minimum integer for the type of the expression.

> + */


It works around INT_MIN / -1 being C undefined behaviour: the
need to special-case this is not x86-specific... The required
answer for Arm is just as architectural as the required answer
for division-by-zero (which is also C UB).

> +#define DO_SDIV(N, M) (unlikely(M == 0) ? 0 : unlikely(M == -1) ? -N : N / M)

> +#define DO_UDIV(N, M) (unlikely(M == 0) ? 0 : N / M)

>

>  DO_ZPZZ(sve_and_zpzz_b, uint8_t, H1, DO_AND)

>  DO_ZPZZ(sve_and_zpzz_h, uint16_t, H1_2, DO_AND)

> @@ -477,11 +483,11 @@ DO_ZPZZ(sve_umulh_zpzz_h, uint16_t, H1_2, do_mulh_h)

>  DO_ZPZZ(sve_umulh_zpzz_s, uint32_t, H1_4, do_mulh_s)

>  DO_ZPZZ_D(sve_umulh_zpzz_d, uint64_t, do_umulh_d)

>

> -DO_ZPZZ(sve_sdiv_zpzz_s, int32_t, H1_4, DO_DIV)

> -DO_ZPZZ_D(sve_sdiv_zpzz_d, int64_t, DO_DIV)

> +DO_ZPZZ(sve_sdiv_zpzz_s, int32_t, H1_4, DO_SDIV)

> +DO_ZPZZ_D(sve_sdiv_zpzz_d, int64_t, DO_SDIV)

>

> -DO_ZPZZ(sve_udiv_zpzz_s, uint32_t, H1_4, DO_DIV)

> -DO_ZPZZ_D(sve_udiv_zpzz_d, uint64_t, DO_DIV)

> +DO_ZPZZ(sve_udiv_zpzz_s, uint32_t, H1_4, DO_UDIV)

> +DO_ZPZZ_D(sve_udiv_zpzz_d, uint64_t, DO_UDIV)

>

>  /* Note that all bits of the shift are significant

>     and not modulo the element size.  */


Other than quibbling about the comment,
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>


thanks
-- PMM
Peter Maydell June 29, 2018, 9:10 a.m. UTC | #3
On 29 June 2018 at 09:29, Peter Maydell <peter.maydell@linaro.org> wrote:
> On 29 June 2018 at 01:15, Richard Henderson

> <richard.henderson@linaro.org> wrote:

>> We already check for the same condition within the normal integer

>> sdiv and sdiv64 helpers.  Use a slightly different formation that

>> does not require deducing the expression type.

>>

>> Fixes: f97cfd596ed

>> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>

>> ---

>>  target/arm/sve_helper.c | 16 +++++++++++-----

>>  1 file changed, 11 insertions(+), 5 deletions(-)

>>

>> diff --git a/target/arm/sve_helper.c b/target/arm/sve_helper.c

>> index 790cbacd14..7d7fc90566 100644

>> --- a/target/arm/sve_helper.c

>> +++ b/target/arm/sve_helper.c

>> @@ -369,7 +369,13 @@ void HELPER(NAME)(void *vd, void *vn, void *vm, void *vg, uint32_t desc) \

>>  #define DO_MIN(N, M)  ((N) >= (M) ? (M) : (N))

>>  #define DO_ABD(N, M)  ((N) >= (M) ? (N) - (M) : (M) - (N))

>>  #define DO_MUL(N, M)  (N * M)

>> -#define DO_DIV(N, M)  (M ? N / M : 0)

>> +

>> +/* The zero divisor case is architectural; the -1 divisor case works

>> + * around the x86 INT_MIN / -1 overflow exception without having to

>> + * deduce the minimum integer for the type of the expression.

>> + */

>

> It works around INT_MIN / -1 being C undefined behaviour: the

> need to special-case this is not x86-specific... The required

> answer for Arm is just as architectural as the required answer

> for division-by-zero (which is also C UB).


Suggested revised comment text:

/* We must avoid the C undefined behaviour cases: division by
 * zero and signed division of INT_MIN by -1. Both of these
 * have architecturally defined required results for Arm.
 * We special case all signed divisions by -1 to avoid having
 * to deduce the minimum integer for the type involved.
 */

?

thanks
-- PMM
Richard Henderson June 29, 2018, 2:43 p.m. UTC | #4
On 06/29/2018 02:10 AM, Peter Maydell wrote:
> Suggested revised comment text:

> 

> /* We must avoid the C undefined behaviour cases: division by

>  * zero and signed division of INT_MIN by -1. Both of these

>  * have architecturally defined required results for Arm.

>  * We special case all signed divisions by -1 to avoid having

>  * to deduce the minimum integer for the type involved.

>  */

> 

> ?


I'm happy with that.


r~
diff mbox series

Patch

diff --git a/target/arm/sve_helper.c b/target/arm/sve_helper.c
index 790cbacd14..7d7fc90566 100644
--- a/target/arm/sve_helper.c
+++ b/target/arm/sve_helper.c
@@ -369,7 +369,13 @@  void HELPER(NAME)(void *vd, void *vn, void *vm, void *vg, uint32_t desc) \
 #define DO_MIN(N, M)  ((N) >= (M) ? (M) : (N))
 #define DO_ABD(N, M)  ((N) >= (M) ? (N) - (M) : (M) - (N))
 #define DO_MUL(N, M)  (N * M)
-#define DO_DIV(N, M)  (M ? N / M : 0)
+
+/* The zero divisor case is architectural; the -1 divisor case works
+ * around the x86 INT_MIN / -1 overflow exception without having to
+ * deduce the minimum integer for the type of the expression.
+ */
+#define DO_SDIV(N, M) (unlikely(M == 0) ? 0 : unlikely(M == -1) ? -N : N / M)
+#define DO_UDIV(N, M) (unlikely(M == 0) ? 0 : N / M)
 
 DO_ZPZZ(sve_and_zpzz_b, uint8_t, H1, DO_AND)
 DO_ZPZZ(sve_and_zpzz_h, uint16_t, H1_2, DO_AND)
@@ -477,11 +483,11 @@  DO_ZPZZ(sve_umulh_zpzz_h, uint16_t, H1_2, do_mulh_h)
 DO_ZPZZ(sve_umulh_zpzz_s, uint32_t, H1_4, do_mulh_s)
 DO_ZPZZ_D(sve_umulh_zpzz_d, uint64_t, do_umulh_d)
 
-DO_ZPZZ(sve_sdiv_zpzz_s, int32_t, H1_4, DO_DIV)
-DO_ZPZZ_D(sve_sdiv_zpzz_d, int64_t, DO_DIV)
+DO_ZPZZ(sve_sdiv_zpzz_s, int32_t, H1_4, DO_SDIV)
+DO_ZPZZ_D(sve_sdiv_zpzz_d, int64_t, DO_SDIV)
 
-DO_ZPZZ(sve_udiv_zpzz_s, uint32_t, H1_4, DO_DIV)
-DO_ZPZZ_D(sve_udiv_zpzz_d, uint64_t, DO_DIV)
+DO_ZPZZ(sve_udiv_zpzz_s, uint32_t, H1_4, DO_UDIV)
+DO_ZPZZ_D(sve_udiv_zpzz_d, uint64_t, DO_UDIV)
 
 /* Note that all bits of the shift are significant
    and not modulo the element size.  */