Repository navigation
Use x87 fsqrt for rounded square roots on 32-bit MSVC - #64
Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## develop #64 +/- ##
===========================================
+ Coverage 82.41% 82.51% +0.10%
===========================================
Files 23 23
Lines 995 1001 +6
Branches 409 410 +1
===========================================
+ Hits 820 826 +6
Misses 167 167
Partials 8 8
Continue to review full report in Codecov by Harness.
🚀 New features to boost your workflow:
|
| template<class T> inline T sqrt_rounded(const T& x) | ||
| { BOOST_NUMERIC_INTERVAL_using_math(sqrt); return sqrt(x); } | ||
|
|
||
| #if defined(_MSC_VER) && defined(_M_IX86) |
There was a problem hiding this comment.
I think, you need to check for the _M_IX86_FP value here and select between x87 and SSE2 implementations. Otherwise, you're forcing x87 when the rest of the program is using SSE2. You can use SSE2 intrinsics to calculate the sqrt. And we should probably add separate CI jobs for 32-bit x86 with /arch:IA32 and /arch:SSE2.
Also, since you're working around a standard library issue, you probably need to check BOOST_DINKUMWARE_STDLIB here.
There was a problem hiding this comment.
About BOOST_DINKUMWARE_STDLIB - I read it needs to applied when using the c++ stdlib, but here it was using the C Runtime? there was a clang windows failure as well?
There was a problem hiding this comment.
Yes, BOOST_DINKUMWARE_STDLIB indicates Microsoft's C++ standard library. We don't have a macro specifically for the C standard library, C++ library is the closest we have. The idea is that if there is a compiler that uses the same C runtime but does not pretend to be MSVC then it should be also affected. However, to my knowledge, all compilers using MS's C++ standard library do pretend as MSVC. MinGW gcc, which uses libstdc++ and some parts of MS's C runtime, appears to be passing in CI. I think, this is because it directly generates x87 and SSE instructions for sqrt instead of the C library calls. So this point is probably moot.
Select by _M_IX86_FP: _mm_sqrt_ss for float with /arch:SSE or higher, _mm_sqrt_sd for double with /arch:SSE2 or higher, and x87 fsqrt otherwise, so the square root runs on the same unit as the rest of the arithmetic.
| __asm fld v | ||
| __asm fsqrt | ||
| __asm fstp v |
There was a problem hiding this comment.
It is better to use an asm block here, i.e.:
__asm
{
...
}
Otherwise, the compiler may reorder the individual __asm statements and the surrounding code and potentially clobber the FPU stack in between the instructions.
Same for the double version.
On 32-bit Windows the Microsoft runtime's
sqrtrounds to nearest whatever the rounding mode, sosqrt_downandsqrt_upreturn the same value, andsqrtof a point interval can miss the true root. The mode itself is set correctly: arithmetic follows it, and so do the x87fsqrtand SSE2sqrtsdinstructions. 64-bit Windows is not affected.On 32-bit MSVC and clang-cl,
rounded_arith_stdandrounded_arith_oppnow compute the rounded square roots withfsqrt, asmsvc_rounding_control.hppalready does forrintwithfrndint. Other platforms callsqrtas before.test/sqrt_rounding.cppcheckssqrt_downandsqrt_upof both policies forfloatanddouble, and forlong doublewhere it has the format ofdouble(as with MSVC).For a non-square the two ends must differ; for an exact square both must be the exact root. x87
long doubleis skipped here because of a separate ordering bug, which #61handles. The same runtime bug is why the MSVC jobs fail on #61.I also probed the other rounded operations that go through the runtime or a compiler helper - they all seem fine