Skip to content

Use x87 fsqrt for rounded square roots on 32-bit MSVC - #64

Merged
Lastique merged 3 commits into
boostorg:developfrom
reach2sayan:fix/msvc32-sqrt-only
Oct 23, 2026
Merged

Lastique merged 3 commits into
boostorg:developfrom
reach2sayan:fix/msvc32-sqrt-only

Conversation

@reach2sayan

Copy link
Copy Markdown
Contributor

On 32-bit Windows the Microsoft runtime's sqrt rounds to nearest whatever the rounding mode, so sqrt_down and sqrt_up return the same value, and sqrt of a point interval can miss the true root. The mode itself is set correctly: arithmetic follows it, and so do the x87 fsqrt and SSE2 sqrtsd instructions. 64-bit Windows is not affected.

On 32-bit MSVC and clang-cl, rounded_arith_std and rounded_arith_opp now compute the rounded square roots with fsqrt, as msvc_rounding_control.hpp already does for rint with frndint. Other platforms call sqrt as before.

test/sqrt_rounding.cpp checks sqrt_down and sqrt_up of both policies for float and double, and for long double where it has the format of double (as with MSVC).
For a non-square the two ends must differ; for an exact square both must be the exact root. x87 long double is 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

@codecov

codecov Bot commented Oct 22, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 82.51%. Comparing base (2bb1db2) to head (83f68cd).

Additional details and impacted files

Impacted file tree graph

@@             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              
Files with missing lines Coverage Δ
include/boost/numeric/interval/rounded_arith.hpp 100.00% <100.00%> (ø)

Continue to review full report in Codecov by Harness.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 2bb1db2...83f68cd. Read the comment docs.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

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)

@Lastique Lastique Oct 22, 2026 •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

@reach2sayan reach2sayan Oct 22, 2026 •

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.
Comment on lines +47 to +49
__asm fld v
__asm fsqrt
__asm fstp v

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

@Lastique
Lastique merged commit 7b4f03b into boostorg:develop Oct 23, 2026
63 checks passed
@reach2sayan
reach2sayan deleted the fix/msvc32-sqrt-only branch October 23, 2026 20:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants