muldiv64() has 7 users across all architectures, and is limited to time
handling functions.  Therefore, move it's declaration out of lib.h into a
dedicated header.

Rename the library function to generic_muldiv64(), as x86 is going to provide
an arch_muldiv64() in a subsequent change.

Explain what the function does, including the limitations; x86's version will
suffer a divide error rather than truncate the result to 64 bits.

Annotate it with attr_const, not that this allows the optimiser to improve any
of Xen's current users.  Add one selftest to check the internal precision,
putting it in bitops.c for want of any better place to locate it.

Signed-off-by: Andrew Cooper <[email protected]>
---
CC: Jan Beulich <[email protected]>
CC: Roger Pau MonnĂ© <[email protected]>
CC: Stefano Stabellini <[email protected]>
CC: Julien Grall <[email protected]>
CC: Volodymyr Babchuk <[email protected]>
CC: Bertrand Marquis <[email protected]>
CC: Michal Orzel <[email protected]>
CC: Oleksii Kurochko <[email protected]>

The reason the selftest can't go in lib/muldiv64.c is because doing so would
exclude the test when the arch variant is used.
---
 xen/arch/arm/time.c               |  2 +-
 xen/arch/riscv/include/asm/time.h |  4 ++--
 xen/arch/x86/emul-i8254.c         |  2 +-
 xen/arch/x86/time.c               |  2 +-
 xen/common/bitops.c               | 12 ++++++++++++
 xen/include/xen/lib.h             |  2 --
 xen/include/xen/muldiv.h          | 18 ++++++++++++++++++
 xen/lib/muldiv64.c                |  5 ++---
 8 files changed, 37 insertions(+), 10 deletions(-)
 create mode 100644 xen/include/xen/muldiv.h

diff --git a/xen/arch/arm/time.c b/xen/arch/arm/time.c
index 03dc5b51a890..7d8b9c0032c1 100644
--- a/xen/arch/arm/time.c
+++ b/xen/arch/arm/time.c
@@ -16,8 +16,8 @@
 #include <xen/event.h>
 #include <xen/init.h>
 #include <xen/irq.h>
-#include <xen/lib.h>
 #include <xen/mm.h>
+#include <xen/muldiv.h>
 #include <xen/notifier.h>
 #include <xen/sched.h>
 #include <xen/sched.h>
diff --git a/xen/arch/riscv/include/asm/time.h 
b/xen/arch/riscv/include/asm/time.h
index 63bdd471ccac..34e46353cce5 100644
--- a/xen/arch/riscv/include/asm/time.h
+++ b/xen/arch/riscv/include/asm/time.h
@@ -3,8 +3,8 @@
 #define ASM__RISCV__TIME_H
 
 #include <xen/bug.h>
-#include <xen/lib.h>
-#include <xen/types.h>
+#include <xen/muldiv.h>
+
 #include <asm/csr.h>
 
 /* Clock cycles count at Xen startup */
diff --git a/xen/arch/x86/emul-i8254.c b/xen/arch/x86/emul-i8254.c
index c16ed0bead87..5e90a14a5957 100644
--- a/xen/arch/x86/emul-i8254.c
+++ b/xen/arch/x86/emul-i8254.c
@@ -25,8 +25,8 @@
  */
 
 #include <xen/errno.h>
-#include <xen/lib.h>
 #include <xen/mm.h>
+#include <xen/muldiv.h>
 #include <xen/sched.h>
 #include <xen/trace.h>
 #include <xen/xmalloc.h>
diff --git a/xen/arch/x86/time.c b/xen/arch/x86/time.c
index 1aeb144c837a..c6323143eaf8 100644
--- a/xen/arch/x86/time.c
+++ b/xen/arch/x86/time.c
@@ -17,7 +17,7 @@
 #include <xen/init.h>
 #include <xen/irq.h>
 #include <xen/keyhandler.h>
-#include <xen/lib.h>
+#include <xen/muldiv.h>
 #include <xen/param.h>
 #include <xen/pci_ids.h>
 #include <xen/sched.h>
diff --git a/xen/common/bitops.c b/xen/common/bitops.c
index 14e6265037f1..1ed88c966cfd 100644
--- a/xen/common/bitops.c
+++ b/xen/common/bitops.c
@@ -247,3 +247,15 @@ static void __init __constructor test_bitops(void)
     test_multiple_bits_set();
     test_hweight();
 }
+
+#include <xen/muldiv.h>
+
+/* Not a bitop, but here in lieu of any any better location */
+static void __init __constructor test_muldiv64(void)
+{
+    uint64_t res = muldiv64(0xffffffffffffffffULL,
+                            HIDE(0xffffffffU),
+                            HIDE(0xffffffffU));
+    if ( res != 0xffffffffffffffffULL )
+        panic("muldiv64(), expecting -1ULL, got 0x%"PRIx64"\n", res);
+}
diff --git a/xen/include/xen/lib.h b/xen/include/xen/lib.h
index 559e87636c02..bb0fd446b484 100644
--- a/xen/include/xen/lib.h
+++ b/xen/include/xen/lib.h
@@ -136,8 +136,6 @@ unsigned long long simple_strtoull(
 
 unsigned long long parse_size_and_unit(const char *s, const char **ps);
 
-uint64_t muldiv64(uint64_t a, uint32_t b, uint32_t c);
-
 /*
  * A slightly more typesafe variant of cmpxchg() when the entities dealt with
  * are pointers.
diff --git a/xen/include/xen/muldiv.h b/xen/include/xen/muldiv.h
new file mode 100644
index 000000000000..8ed2c68caf84
--- /dev/null
+++ b/xen/include/xen/muldiv.h
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef XEN_MULDIV_H
+#define XEN_MULDIV_H
+
+#include <xen/stdint.h>
+
+uint64_t attr_const generic_muldiv64(uint64_t a, uint32_t b, uint32_t c);
+
+/*
+ * Calculate a * b / c using at least 96-bit internal precision.  The
+ * behaviour is undefined if the end result does not fit in a uint64_t.
+ */
+static inline uint64_t attr_const muldiv64(uint64_t a, uint32_t b, uint32_t c)
+{
+    return generic_muldiv64(a, b, c);
+}
+
+#endif /* XEN_MULDIV_H */
diff --git a/xen/lib/muldiv64.c b/xen/lib/muldiv64.c
index f281578c09a4..5e6db1b2f4d2 100644
--- a/xen/lib/muldiv64.c
+++ b/xen/lib/muldiv64.c
@@ -1,7 +1,6 @@
-#include <xen/lib.h>
+#include <xen/muldiv.h>
 
-/* Compute with 96 bit intermediate result: (a*b)/c */
-uint64_t muldiv64(uint64_t a, uint32_t b, uint32_t c)
+uint64_t generic_muldiv64(uint64_t a, uint32_t b, uint32_t c)
 {
 #ifdef CONFIG_X86
     asm ( "mulq %1; divq %2" : "+a" (a)
-- 
2.39.5


Reply via email to