All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH kvm-unit-tests 0/2] fix long division routines for ARM eabi
@ 2021-05-11 17:41 Paolo Bonzini
  2021-05-11 17:41 ` [PATCH kvm-unit-tests 1/2] libcflat: clean up and complete long division routines Paolo Bonzini
  2021-05-11 17:41 ` [PATCH kvm-unit-tests 2/2] arm: add eabi version of 64-bit division functions Paolo Bonzini
  0 siblings, 2 replies; 5+ messages in thread
From: Paolo Bonzini @ 2021-05-11 17:41 UTC (permalink / raw)
  To: kvm; +Cc: Alexandru Elisei

As reported by Alexandru, ARM follows a different convention than
x86 so it needs __aeabi_ldivmod and __aeabi_uldivmod.  Because
it does not use __divdi3 and __moddi3, it also needs __divmoddi4
to build the eabi function upon.

Paolo

Paolo Bonzini (2):
  libcflat: clean up and complete long division routines
  arm: add eabi version of 64-bit division functions

 arm/Makefile.arm  |  1 +
 lib/arm/ldivmod.S | 32 ++++++++++++++++++++++++++++++++
 lib/ldiv32.c      | 28 +++++++++++++++++++++++++---
 3 files changed, 58 insertions(+), 3 deletions(-)
 create mode 100644 lib/arm/ldivmod.S

-- 
2.31.1


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH kvm-unit-tests 1/2] libcflat: clean up and complete long division routines
  2021-05-11 17:41 [PATCH kvm-unit-tests 0/2] fix long division routines for ARM eabi Paolo Bonzini
@ 2021-05-11 17:41 ` Paolo Bonzini
  2021-05-12 10:39   ` Alexandru Elisei
  2021-05-11 17:41 ` [PATCH kvm-unit-tests 2/2] arm: add eabi version of 64-bit division functions Paolo Bonzini
  1 sibling, 1 reply; 5+ messages in thread
From: Paolo Bonzini @ 2021-05-11 17:41 UTC (permalink / raw)
  To: kvm; +Cc: Alexandru Elisei

Avoid possible uninitialized variables on machines where
division by zero does not trap.  Add __divmoddi4, and
do not use 64-bit math unnecessarily in __moddi3 and __divdi3.

Reported-by: Alexandru Elisei <alexandru.elisei@arm.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 lib/ldiv32.c | 28 +++++++++++++++++++++++++---
 1 file changed, 25 insertions(+), 3 deletions(-)

diff --git a/lib/ldiv32.c b/lib/ldiv32.c
index 96f4b35..c39fccd 100644
--- a/lib/ldiv32.c
+++ b/lib/ldiv32.c
@@ -1,6 +1,7 @@
 #include <stdint.h>
 
 extern uint64_t __udivmoddi4(uint64_t num, uint64_t den, uint64_t *p_rem);
+extern int64_t __divmoddi4(int64_t num, int64_t den, int64_t *p_rem);
 extern int64_t __moddi3(int64_t num, int64_t den);
 extern int64_t __divdi3(int64_t num, int64_t den);
 extern uint64_t __udivdi3(uint64_t num, uint64_t den);
@@ -11,8 +12,11 @@ uint64_t __udivmoddi4(uint64_t num, uint64_t den, uint64_t *p_rem)
 	uint64_t quot = 0;
 
 	/* Trigger a division by zero at run time (trick taken from iPXE).  */
-	if (den == 0)
+	if (den == 0) {
+		if (p_rem)
+			*p_rem = 0;
 		return 1/((unsigned)den);
+	}
 
 	if (num >= den) {
 		/* Align den to num to avoid wasting time on leftmost zero bits.  */
@@ -35,9 +39,27 @@ uint64_t __udivmoddi4(uint64_t num, uint64_t den, uint64_t *p_rem)
 	return quot;
 }
 
+int64_t __divmoddi4(int64_t num, int64_t den, int64_t *p_rem)
+{
+	int32_t nmask = num < 0 ? -1 : 0;
+	int32_t qmask = (num ^ den) < 0 ? -1 : 0;
+	uint64_t quot;
+
+	/* Compute absolute values and do an unsigned division.  */
+	num = (num + nmask) ^ nmask;
+	if (den < 0)
+		den = -den;
+
+	/* Copy sign of num^den into quotient, sign of num into remainder.  */
+	quot = (__divmoddi4(num, den, p_rem) + qmask) ^ qmask;
+	if (p_rem)
+		*p_rem = (*p_rem + nmask) ^ nmask;
+	return quot;
+}
+
 int64_t __moddi3(int64_t num, int64_t den)
 {
-	uint64_t mask = num < 0 ? -1 : 0;
+	int32_t mask = num < 0 ? -1 : 0;
 
 	/* Compute absolute values and do an unsigned division.  */
 	num = (num + mask) ^ mask;
@@ -50,7 +72,7 @@ int64_t __moddi3(int64_t num, int64_t den)
 
 int64_t __divdi3(int64_t num, int64_t den)
 {
-	uint64_t mask = (num ^ den) < 0 ? -1 : 0;
+	int32_t mask = (num ^ den) < 0 ? -1 : 0;
 
 	/* Compute absolute values and do an unsigned division.  */
 	if (num < 0)
-- 
2.31.1



^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH kvm-unit-tests 2/2] arm: add eabi version of 64-bit division functions
  2021-05-11 17:41 [PATCH kvm-unit-tests 0/2] fix long division routines for ARM eabi Paolo Bonzini
  2021-05-11 17:41 ` [PATCH kvm-unit-tests 1/2] libcflat: clean up and complete long division routines Paolo Bonzini
@ 2021-05-11 17:41 ` Paolo Bonzini
  1 sibling, 0 replies; 5+ messages in thread
From: Paolo Bonzini @ 2021-05-11 17:41 UTC (permalink / raw)
  To: kvm; +Cc: Alexandru Elisei

eabi prescribes different entry points for 64-bit division on
32-bit platforms.  Implement a wrapper for the GCC-style __divmoddi4
and __udivmoddi4 functions.

Reported-by: Alexandru Elisei <alexandru.elisei@arm.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 arm/Makefile.arm  |  1 +
 lib/arm/ldivmod.S | 32 ++++++++++++++++++++++++++++++++
 2 files changed, 33 insertions(+)
 create mode 100644 lib/arm/ldivmod.S

diff --git a/arm/Makefile.arm b/arm/Makefile.arm
index 687a8ed..3a4cc6b 100644
--- a/arm/Makefile.arm
+++ b/arm/Makefile.arm
@@ -24,6 +24,7 @@ cflatobjs += lib/arm/spinlock.o
 cflatobjs += lib/arm/processor.o
 cflatobjs += lib/arm/stack.o
 cflatobjs += lib/ldiv32.o
+cflatobjs += lib/arm/ldivmod.o
 
 # arm specific tests
 tests =
diff --git a/lib/arm/ldivmod.S b/lib/arm/ldivmod.S
new file mode 100644
index 0000000..de11ac9
--- /dev/null
+++ b/lib/arm/ldivmod.S
@@ -0,0 +1,32 @@
+// EABI ldivmod and uldivmod implementation based on libcompiler-rt
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses.
+
+	.syntax unified
+	.align 2
+	.globl __aeabi_uldivmod
+	.type __aeabi_uldivmod, %function
+__aeabi_uldivmod:
+	push	{r11, lr}
+	sub	sp, sp, #16
+	add	r12, sp, #8
+	str	r12, [sp]                // third argument to __udivmoddi4
+	bl	__udivmoddi4
+	ldr	r2, [sp, #8]             // remainder returned in r2-r3
+	ldr	r3, [sp, #12]
+	add	sp, sp, #16
+	pop	{r11, pc}
+
+	.globl __aeabi_ldivmod
+	.type __aeabi_ldivmod, %function
+__aeabi_ldivmod:
+	push	{r11, lr}
+	sub	sp, sp, #16
+	add	r12, sp, #8
+	str	r12, [sp]                // third argument to __divmoddi4
+	bl	__divmoddi4
+	ldr	r2, [sp, #8]             // remainder returned in r2-r3
+	ldr	r3, [sp, #12]
+	add	sp, sp, #16
+	pop	{r11, pc}
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [PATCH kvm-unit-tests 1/2] libcflat: clean up and complete long division routines
  2021-05-11 17:41 ` [PATCH kvm-unit-tests 1/2] libcflat: clean up and complete long division routines Paolo Bonzini
@ 2021-05-12 10:39   ` Alexandru Elisei
  2021-05-12 10:47     ` Paolo Bonzini
  0 siblings, 1 reply; 5+ messages in thread
From: Alexandru Elisei @ 2021-05-12 10:39 UTC (permalink / raw)
  To: Paolo Bonzini, kvm

Hi Paolo,

Thanks for sending this so quickly!

On 5/11/21 6:41 PM, Paolo Bonzini wrote:
> Avoid possible uninitialized variables on machines where
> division by zero does not trap.  Add __divmoddi4, and

According to the ARM Architecture Reference Manual for ARMv7-A (ARM DDI 0406C.d),
hardware floating point support is optional (page A2-54), so initializing the
remainder to zero in the case of zero division makes sense.

> do not use 64-bit math unnecessarily in __moddi3 and __divdi3.
>
> Reported-by: Alexandru Elisei <alexandru.elisei@arm.com>
> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
> ---
>  lib/ldiv32.c | 28 +++++++++++++++++++++++++---
>  1 file changed, 25 insertions(+), 3 deletions(-)
>
> diff --git a/lib/ldiv32.c b/lib/ldiv32.c
> index 96f4b35..c39fccd 100644
> --- a/lib/ldiv32.c
> +++ b/lib/ldiv32.c
> @@ -1,6 +1,7 @@
>  #include <stdint.h>
>  
>  extern uint64_t __udivmoddi4(uint64_t num, uint64_t den, uint64_t *p_rem);
> +extern int64_t __divmoddi4(int64_t num, int64_t den, int64_t *p_rem);
>  extern int64_t __moddi3(int64_t num, int64_t den);
>  extern int64_t __divdi3(int64_t num, int64_t den);
>  extern uint64_t __udivdi3(uint64_t num, uint64_t den);
> @@ -11,8 +12,11 @@ uint64_t __udivmoddi4(uint64_t num, uint64_t den, uint64_t *p_rem)
>  	uint64_t quot = 0;
>  
>  	/* Trigger a division by zero at run time (trick taken from iPXE).  */
> -	if (den == 0)
> +	if (den == 0) {
> +		if (p_rem)
> +			*p_rem = 0;
>  		return 1/((unsigned)den);
> +	}
>  
>  	if (num >= den) {
>  		/* Align den to num to avoid wasting time on leftmost zero bits.  */
> @@ -35,9 +39,27 @@ uint64_t __udivmoddi4(uint64_t num, uint64_t den, uint64_t *p_rem)
>  	return quot;
>  }
>  
> +int64_t __divmoddi4(int64_t num, int64_t den, int64_t *p_rem)
> +{
> +	int32_t nmask = num < 0 ? -1 : 0;
> +	int32_t qmask = (num ^ den) < 0 ? -1 : 0;
> +	uint64_t quot;
> +
> +	/* Compute absolute values and do an unsigned division.  */
> +	num = (num + nmask) ^ nmask;
> +	if (den < 0)
> +		den = -den;
> +
> +	/* Copy sign of num^den into quotient, sign of num into remainder.  */
> +	quot = (__divmoddi4(num, den, p_rem) + qmask) ^ qmask;

I see no early return statement in the function, it looks to me like the function
will recurse forever. Maybe you wanted to call here __*u*divmoddi4() (emphasis
added) instead?

Other than that, the function looks correct.

Thanks,

Alex

> +	if (p_rem)
> +		*p_rem = (*p_rem + nmask) ^ nmask;
> +	return quot;
> +}
> +
>  int64_t __moddi3(int64_t num, int64_t den)
>  {
> -	uint64_t mask = num < 0 ? -1 : 0;
> +	int32_t mask = num < 0 ? -1 : 0;
>  
>  	/* Compute absolute values and do an unsigned division.  */
>  	num = (num + mask) ^ mask;
> @@ -50,7 +72,7 @@ int64_t __moddi3(int64_t num, int64_t den)
>  
>  int64_t __divdi3(int64_t num, int64_t den)
>  {
> -	uint64_t mask = (num ^ den) < 0 ? -1 : 0;
> +	int32_t mask = (num ^ den) < 0 ? -1 : 0;
>  
>  	/* Compute absolute values and do an unsigned division.  */
>  	if (num < 0)

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH kvm-unit-tests 1/2] libcflat: clean up and complete long division routines
  2021-05-12 10:39   ` Alexandru Elisei
@ 2021-05-12 10:47     ` Paolo Bonzini
  0 siblings, 0 replies; 5+ messages in thread
From: Paolo Bonzini @ 2021-05-12 10:47 UTC (permalink / raw)
  To: Alexandru Elisei, kvm

On 12/05/21 12:39, Alexandru Elisei wrote:
>> +
>> +	/* Copy sign of num^den into quotient, sign of num into remainder.  */
>> +	quot = (__divmoddi4(num, den, p_rem) + qmask) ^ qmask;
> I see no early return statement in the function, it looks to me like the function
> will recurse forever. Maybe you wanted to call here __*u*divmoddi4() (emphasis
> added) instead?

Of course...

Paolo


^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2021-05-12 10:48 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-05-11 17:41 [PATCH kvm-unit-tests 0/2] fix long division routines for ARM eabi Paolo Bonzini
2021-05-11 17:41 ` [PATCH kvm-unit-tests 1/2] libcflat: clean up and complete long division routines Paolo Bonzini
2021-05-12 10:39   ` Alexandru Elisei
2021-05-12 10:47     ` Paolo Bonzini
2021-05-11 17:41 ` [PATCH kvm-unit-tests 2/2] arm: add eabi version of 64-bit division functions Paolo Bonzini

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.