rsa: add msvc intrinsic for non x64 platforms
authorHubert Kario <hkario@redhat.com>
Wed, 8 Feb 2023 13:13:24 +0000 (14:13 +0100)
committerTomas Mraz <tomas@openssl.org>
Sat, 11 Feb 2023 13:57:16 +0000 (14:57 +0100)
_umul128() is x86_64 (x64) only, while __umulh() works everywhere, but
doesn't generate optimal code on x64

Reviewed-by: Dmitry Belyavskiy <beldmit@gmail.com>
Reviewed-by: Paul Dale <pauli@openssl.org>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/20244)

(cherry picked from commit 075652f224479dad2e64b92e791b296177af8705)

crypto/bn/rsa_sup_mul.c

index acafefd5febf70e1996016b190a6c02dd7e327e1..c027ba411e28085843d403d0d21272bbf7676c7f 100644 (file)
@@ -110,12 +110,34 @@ static ossl_inline void _mul_limb(limb_t *hi, limb_t *lo, limb_t a, limb_t b)
     *lo = (limb_t)t;
 }
 #elif (BN_BYTES == 8) && (defined _MSC_VER)
-/* https://learn.microsoft.com/en-us/cpp/intrinsics/umul128?view=msvc-170 */
+# if defined(_M_X64)
+/*
+ * on x86_64 (x64) we can use the _umul128 intrinsic to get one `mul`
+ * instruction to get both high and low 64 bits of the multiplication.
+ * https://learn.microsoft.com/en-us/cpp/intrinsics/umul128?view=msvc-140
+ */
+#include <intrin.h>
 #pragma intrinsic(_umul128)
 static ossl_inline void _mul_limb(limb_t *hi, limb_t *lo, limb_t a, limb_t b)
 {
     *lo = _umul128(a, b, hi);
 }
+# elif defined(_M_ARM64) || defined (_M_IA64)
+/*
+ * We can't use the __umulh() on x86_64 as then msvc generates two `mul`
+ * instructions; so use this more portable intrinsic on platforms that
+ * don't support _umul128 (like aarch64 (ARM64) or ia64)
+ * https://learn.microsoft.com/en-us/cpp/intrinsics/umulh?view=msvc-140
+ */
+#include <intrin.h>
+static ossl_inline void _mul_limb(limb_t *hi, limb_t *lo, limb_t a, limb_t b)
+{
+    *lo = a * b;
+    *hi = __umulh(a, b);
+}
+# else
+# error Only x64, ARM64 and IA64 supported.
+# endif /* defined(_M_X64) */
 #else
 /*
  * if the compiler doesn't have either a 128bit data type nor a "return