From c107abe247e451bf7f328bd3d5e623ae6f424f0e Mon Sep 17 00:00:00 2001 From: Alex Date: Sun, 10 Jul 2022 02:10:17 +0300 Subject: [PATCH] math: Use intrinsic functions for 64-bit rescale on MSVC. --- libs/kimath/src/math/util.cpp | 37 ++++++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/libs/kimath/src/math/util.cpp b/libs/kimath/src/math/util.cpp index b7ed10604e..4e9ccba34b 100644 --- a/libs/kimath/src/math/util.cpp +++ b/libs/kimath/src/math/util.cpp @@ -3,6 +3,7 @@ * * Copyright (c) 2005 Michael Niedermayer * Copyright (C) CERN + * Copyright (C) 2022 KiCad Developers, see AUTHORS.txt for contributors. * @author Tomasz Wlostowski * * This program is free software; you can redistribute it and/or @@ -29,6 +30,11 @@ #include #include +#ifdef _MSC_VER +#include +#include +#endif + // Fix compatibility with wxWidgets version < 3.1.4 #ifndef wxASCII_STR #define wxASCII_STR(s) wxString::FromAscii(s) @@ -65,13 +71,42 @@ int rescale( int aNumerator, int aValue, int aDenominator ) template<> int64_t rescale( int64_t aNumerator, int64_t aValue, int64_t aDenominator ) { -#ifdef __SIZEOF_INT128__ +#if defined( _M_X64 ) && ( _MSC_VER >= 1920 ) + int64_t productHi; + uint64_t productLo = static_cast( _mul128( aNumerator, aValue, &productHi ) ); + + int64_t r = ( ( productHi < 0 ) ^ ( aDenominator < 0 ) ) ? -aDenominator / 2 : aDenominator / 2; + + uint64_t rLo = static_cast( r ); + int64_t rHi = r < 0 ? -1ll : 0ll; + + productLo += rLo; + productHi += rHi + ( productLo < rLo ); + + __try + { + int64_t remainder; + int64_t result = _div128( productHi, productLo, aDenominator, &remainder ); + + return result; + } + __except( ( GetExceptionCode() == EXCEPTION_INT_OVERFLOW ) ? EXCEPTION_EXECUTE_HANDLER + : EXCEPTION_CONTINUE_SEARCH ) + { + kimathLogDebug( "Overflow in rescale (%lld * %lld + %lld) / %lld", aNumerator, aValue, r, + aDenominator ); + } + + return 0; + +#elif defined( __SIZEOF_INT128__ ) __int128_t numerator = (__int128_t) aNumerator * (__int128_t) aValue; if( ( numerator < 0 ) ^ ( aDenominator < 0 ) ) return ( numerator - aDenominator / 2 ) / aDenominator; else return ( numerator + aDenominator / 2 ) / aDenominator; + #else int64_t r = 0; int64_t sign = ( ( aNumerator < 0 ) ? -1 : 1 ) * ( aDenominator < 0 ? -1 : 1 ) *