Skip to content

Subtle ABI mismatch in bundled SoftFloat library #833

Description

@gottfriedleibniz

The bundled SoftFloat64.lib defines bool as an int, following the definition in platform.h.in. This can lead to unexpected behavior in Hercules, as the upper bits of the int may remain uncleared as MSVC/clang-cl compiles bool as a one-byte type.

I first encountered this while compiling Hercules with clang-cl (versions 20.1.8 and 22.1.3) and running the test suite. For example:

Begin: "runtest -d $(DEV)\hyperion\tests\ -v quiet -64" ...

On:     Fri 04/17/2026  at 21:38:08 PM

Variable $platform           set to "Windows"
>>>>> line  2018: Received unexpected wait state:  0002000000000000 0000000000000BAD
Test "bfp-004-cvttolog":  0 OK compares.  One failure.
>>>>> line  2123: Received unexpected wait state:  0002000000000000 0000000000000BAD
Test "bfp-005-cvttolog64":  0 OK compares.  One failure.
>>>>> line  2291: Received unexpected wait state:  0002000000000000 0000000000000BAD
Test "bfp-006-cvttofix":  0 OK compares.  One failure.
>>>>> line  2456: Received unexpected wait state:  0002000000000000 0000000000000BAD
Test "bfp-007-cvttofix64":  0 OK compares.  One failure.
Did 305 tests.  4 failed; 301 OK

Investigating Test "bfp-004-cvttolog", I found that some failures were caused by f64_to_ui32 (in CLFDBR) setting the inexact bit in softfloat_exceptionFlags, even though it should have been suppressed. For reference, here is the (dis)assembly for f64_to_ui32 in SoftFloat64.lib:

.text:0000000000000034    mov     edi, r8d
...
.text:000000000000005D    mov     r9d, edi ;// 'bool' exact
.text:0000000000000060    movzx   r8d, sil ;// uint_fast8_t roundingMode
.text:0000000000000064    mov     rdx, rax ;// uint_fast64_t sig
.text:0000000000000067    mov     ecx, ebx ;// 'bool' sign
.text:0000000000000069    call    softfloat_roundToUI32

Jumping to softfloat_roundToUI32:

.text:0000000000000020    mov     ebx, r9d
// ...
.text:0000000000000109    test    ebx, ebx
.text:000000000000010B    jz      short loc_113

If bool were defined as a single byte, it is expected those two parameters would be setup with movzx ecx * and movzx r9d * for the softfloat_roundToUI32 call and the test would be 8-bit (or something isomorphic/functionally-equivalent).

In investigating why this bug has been dormant for so long I have provided the relevant snippets from:

Hercules (clang-cl 20.1.8):

.text:00000000000041A1    test    r14d, 400h ;// Multiple bytes packed in one register
.text:00000000000041A8    setz    r8b        ;// x86-64 does not automatically clear the upper bits of the register
.text:00000000000041AC    mov     rcx, rdi
.text:00000000000041AF    call    f64_to_ui32

Hercules (MSVC 19.51.36231):

.text:0000000000002F52    movzx   r8d, r12b ;// All higher bits of R8 are cleared!
.text:0000000000002F5B    shr     r8b, 2
// ...
.text:0000000000002F62    not     r8b
.text:0000000000002F65    and     r8b, 1
// ...
.text:0000000000002F6D    call    f64_to_ui32

This isn’t urgent; just a reminder to update the bool definition when dependencies are next bumped or recompiled.

Metadata

Metadata

Assignees

Labels

OngoingIssue is long-term. Variant of IN PROGRESS: it's being worked on but maybe not at this exact moment.Researching...The issue is being looked into or additional information is being gathered/located.

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions