aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKenjiro Nakayama <nakayamakenjiro@gmail.com>2026-08-13 09:23:31 +0900
committerKenjiro Nakayama <nakayamakenjiro@gmail.com>2026-08-13 11:56:29 +0900
commitc88ca1f5d3d910d1b1dc9c5f5fe30f261c078e90 (patch)
tree6825d7e49ea925852e6df6c1e91f798809d07144
parent3e403cfebd94cbff248e7acac5073a7a123c421b (diff)
downloadportable-c88ca1f5d3d910d1b1dc9c5f5fe30f261c078e90.tar.gz
portable-c88ca1f5d3d910d1b1dc9c5f5fe30f261c078e90.tar.bz2
portable-c88ca1f5d3d910d1b1dc9c5f5fe30f261c078e90.zip
cmake: detect the MSVC ARM64 optimizer bug
Run the reproducer when configuring native MSVC ARM64 builds and enable the bn_ct_ne_zero() workaround only when the test fails. Retain the workaround when cross-compiling, where the test cannot be run. Run the check in the Release configuration and report its result so the selected code path is visible in the configure log.
-rw-r--r--CMakeLists.txt91
-rw-r--r--patches/win32_arm64_bn_arch.h.patch5
2 files changed, 94 insertions, 2 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 4b15da9..0a59ddc 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -522,6 +522,97 @@ else()
522 set(ENABLE_ASM false) 522 set(ENABLE_ASM false)
523endif() 523endif()
524 524
525if(MSVC AND HOST_AARCH64 AND NOT CMAKE_CROSSCOMPILING AND
526 CMAKE_HOST_SYSTEM_PROCESSOR MATCHES "(aarch64|arm64|ARM64)")
527 set(BN_CT_TEST_SOURCE "${CMAKE_CURRENT_BINARY_DIR}/bn_ct_test.c")
528 file(WRITE "${BN_CT_TEST_SOURCE}" [=[
529#include <inttypes.h>
530#include <stdint.h>
531#include <stdio.h>
532
533typedef uint64_t BN_ULONG;
534
535#define BN_BITS2 64
536
537static __inline int
538bn_ct_ne_zero(BN_ULONG w)
539{
540 return (w | ~(w - 1)) >> (BN_BITS2 - 1);
541}
542
543static __inline void
544bn_addw(BN_ULONG a, BN_ULONG b, BN_ULONG *out_r1, BN_ULONG *out_r0)
545{
546 BN_ULONG c1, c2, r1, r0;
547
548 c1 = a | b;
549 c2 = a & b;
550 r0 = a + b;
551 r1 = ((c1 & ~r0) | c2) >> (BN_BITS2 - 1);
552
553 *out_r1 = r1;
554 *out_r0 = r0;
555}
556
557static __inline void
558bn_addw_addw(BN_ULONG a, BN_ULONG b, BN_ULONG c, BN_ULONG *out_r1,
559 BN_ULONG *out_r0)
560{
561 BN_ULONG carry, r1, r0;
562
563 bn_addw(a, b, &r1, &r0);
564 bn_addw(r0, c, &carry, &r0);
565 r1 += carry;
566
567 *out_r1 = r1;
568 *out_r0 = r0;
569}
570
571static BN_ULONG
572make_mask(BN_ULONG a, BN_ULONG b, BN_ULONG c, BN_ULONG borrow)
573{
574 BN_ULONG carry, ignored;
575
576 bn_addw_addw(a, b, c, &carry, &ignored);
577
578 return bn_ct_ne_zero(carry) - borrow;
579}
580
581static volatile BN_ULONG input_a = UINT64_MAX;
582static volatile BN_ULONG input_b = 1;
583static volatile BN_ULONG input_c = 0;
584static volatile BN_ULONG input_borrow = 0;
585
586int
587main(void)
588{
589 BN_ULONG actual, expected = 1;
590
591 actual = make_mask(input_a, input_b, input_c, input_borrow);
592 if (actual != expected) {
593 printf("FAIL: expected 0x%016" PRIx64 ", got 0x%016" PRIx64 "\n",
594 expected, actual);
595 return 1;
596 }
597
598 return 0;
599}
600]=])
601 set(BN_CT_SAVED_CONFIGURATION "${CMAKE_TRY_COMPILE_CONFIGURATION}")
602 set(CMAKE_TRY_COMPILE_CONFIGURATION Release)
603 try_run(BN_CT_RUN_RESULT BN_CT_COMPILED
604 "${CMAKE_CURRENT_BINARY_DIR}"
605 "${BN_CT_TEST_SOURCE}")
606 set(CMAKE_TRY_COMPILE_CONFIGURATION "${BN_CT_SAVED_CONFIGURATION}")
607 if(BN_CT_COMPILED AND BN_CT_RUN_RESULT EQUAL 0)
608 message(STATUS "MSVC ARM64 optimizer check passed; workaround disabled")
609 add_definitions(-DMSVC_ARM64_BN_CT_NE_ZERO_WORKS)
610 else()
611 message(STATUS "MSVC ARM64 optimizer check failed; workaround enabled "
612 "(compiled=${BN_CT_COMPILED}, result=${BN_CT_RUN_RESULT})")
613 endif()
614endif()
615
525if(ENABLE_ASM) 616if(ENABLE_ASM)
526 if(CMAKE_C_COMPILER_ABI STREQUAL "ELF") 617 if(CMAKE_C_COMPILER_ABI STREQUAL "ELF")
527 if(HOST_AARCH64) 618 if(HOST_AARCH64)
diff --git a/patches/win32_arm64_bn_arch.h.patch b/patches/win32_arm64_bn_arch.h.patch
index 0d0db42..c8071a8 100644
--- a/patches/win32_arm64_bn_arch.h.patch
+++ b/patches/win32_arm64_bn_arch.h.patch
@@ -1,11 +1,12 @@
1--- crypto/bn/arch/aarch64/bn_arch.h.orig 1--- crypto/bn/arch/aarch64/bn_arch.h.orig
2+++ crypto/bn/arch/aarch64/bn_arch.h 2+++ crypto/bn/arch/aarch64/bn_arch.h
3@@ -20,4 +20,18 @@ 3@@ -20,4 +20,19 @@
4 #ifndef HEADER_BN_ARCH_H 4 #ifndef HEADER_BN_ARCH_H
5 #define HEADER_BN_ARCH_H 5 #define HEADER_BN_ARCH_H
6- 6-
7+/* See pull/1355. */ 7+/* See pull/1355. */
8+#if defined(_MSC_VER) && defined(_M_ARM64) && _MSC_FULL_VER < 195136252 8+#if defined(_MSC_VER) && defined(_M_ARM64) && \
9+ !defined(MSVC_ARM64_BN_CT_NE_ZERO_WORKS)
9+ 10+
10+#include <intrin.h> 11+#include <intrin.h>
11+ 12+