Skip to main content
missing word
Source Link
Toby Speight
  • 2.1k
  • 1
  • 16
  • 37

Some (all?) Windows GCC builds default to -mlong-double-80, not ABI-compatible with MSVC for long double unless you pass a command-line option. That should tell you something about how rarely long double is used in real code!

(If you're looking at the tables yourself, fbld and fbstp m80bcd are insanely slow because they convert from/to BCD, thus requiring conversion from binary to decimal with division by 10. Nevermind Never mind those, they're always microcoded).

Some (all?) Windows GCC builds default to -mlong-double-80, not ABI-compatible with MSVC for long double unless you a command-line option. That should tell you something about how rarely long double is used in real code!

(If you're looking at the tables yourself, fbld and fbstp m80bcd are insanely slow because they convert from/to BCD, thus requiring conversion from binary to decimal with division by 10. Nevermind those, they're always microcoded).

Some (all?) Windows GCC builds default to -mlong-double-80, not ABI-compatible with MSVC for long double unless you pass a command-line option. That should tell you something about how rarely long double is used in real code!

(If you're looking at the tables yourself, fbld and fbstp m80bcd are insanely slow because they convert from/to BCD, thus requiring conversion from binary to decimal with division by 10. Never mind those, they're always microcoded).

added 286 characters in body
Source Link

But no, none of the major C compilers had an option to force promoting double locals/temporaries to 80-bit even across spill/reload, only keeping them as 80-bit when it was convenient to keep them in registers anyway. (Strict ISO C / IEEE FP semantics require rounding to the actual type on assignment. So not keeping extra precision across statements, only within expressions, even for FLT_EVAL_METHOD == 2. What real compilers do for x87 is already bending that rule, unless you use GCC -std=c11 (implying -fexcess-precision=standard) instead of -std=gnu11, or gcc -ffloat-store)

Note: on x86 Windows (x86 and x64), long double is the same as 64-bit double; GCC targeting Windows can use -mlong-double-64/80/128, but that's not ABI-compatible with other code using long double. The i386 and AMD64 System V ABIs have 80-bit long double.

Some (all?) Windows GCC builds default to -mlong-double-80, not ABI-compatible with MSVC for long double unless you a command-line option. That should tell you something about how rarely long double is used in real code!

But no, none of the major C compilers had an option to force promoting double locals/temporaries to 80-bit even across spill/reload, only keeping them as 80-bit when it was convenient to keep them in registers anyway. (Strict ISO C / IEEE FP semantics require rounding to the actual type on assignment. So not keeping extra precision across statements, only within expressions, even for FLT_EVAL_METHOD == 2. What real compilers do for x87 is already bending that rule, unless you use -std=c11 instead of -std=gnu11, or gcc -ffloat-store)

Note: on x86 Windows, long double is the same as 64-bit double; GCC targeting Windows can use -mlong-double-64/80/128, but that's not ABI-compatible with other code using long double. The i386 and AMD64 System V ABIs have 80-bit long double.

But no, none of the major C compilers had an option to force promoting double locals/temporaries to 80-bit even across spill/reload, only keeping them as 80-bit when it was convenient to keep them in registers anyway. (Strict ISO C / IEEE FP semantics require rounding to the actual type on assignment. So not keeping extra precision across statements, only within expressions, even for FLT_EVAL_METHOD == 2. What real compilers do for x87 is already bending that rule, unless you use GCC -std=c11 (implying -fexcess-precision=standard) instead of -std=gnu11, or gcc -ffloat-store)

Note: on Windows (x86 and x64), long double is the same as 64-bit double; GCC targeting Windows can use -mlong-double-64/80/128, but that's not ABI-compatible with other code using long double. The i386 and AMD64 System V ABIs have 80-bit long double.

Some (all?) Windows GCC builds default to -mlong-double-80, not ABI-compatible with MSVC for long double unless you a command-line option. That should tell you something about how rarely long double is used in real code!

improved formatting, grammar, spelling, it's the 32-bit float that has a 24-bit significand
Source Link

Fun fact: fld m32/m64 can raise / flag an FP exception (#IA) if the source operand is SNaN, but Intel's manual says this can't happen if the source operand is in double extended-precision floating-point format. So it can just stuff the bits into an x87 register without looking at them, unlike fld m32 / m64fld m32/m64 where it has to expand the significand/exponent fields.

  • to 80-bit long double: 64-bit significand precision. The finit default, and normal setting except with MSVC.
  • to 64-bit double: 53-bit significand precision. 32-bit MSVC sets this.
  • to 2432-bit float: 24-bit significandsignificand precision.

Apparently the D3D9 library init function sets x87 precision to 24-bit significand single-precision float, making everything less precise for a speed gain on fdivfdiv/fsqrtfsqrt (and maybe fcos/fsin and other slow microcoded instructions, too.) But x87 precision settings are per-thread, so it matters which thread you call the init function from! (The x87 control word is part of the architectural state that context switches save/restore.)

Of course you can set it back to 64-bit significand with _controlfp_s, so you could usefulusefully use asm, or call a function using long double compiled by GCC, clang, or ICC. But beware the ABI differences: you can only pass it inputs as float, double, or integer, because MSVC won't ever create objects in memory in the 80-bit x87 format.

Fun fact: fld m32/m64 can raise / flag an FP exception (#IA) if the source operand is SNaN, but Intel's manual says this can't happen if the source operand is in double extended-precision floating-point format. So it can just stuff the bits into an x87 register without looking at them, unlike fld m32 / m64 where it has to expand the significand/exponent fields.

  • to 80-bit long double: 64-bit significand precision. The finit default, and normal setting except with MSVC.
  • to 64-bit double: 53-bit significand precision. 32-bit MSVC sets this.
  • to 24-bit float: 24-bit significand precision.

Apparently the D3D9 library init function sets x87 precision to 24-bit significand single-precision float, making everything less precise for a speed gain on fdiv/fsqrt (and maybe fcos/fsin and other slow microcoded instructions, too.) But x87 precision settings are per-thread, so it matters which thread you call the init function from! (The x87 control word is part of the architectural state that context switches save/restore.)

Of course you can set it back to 64-bit significand with _controlfp_s, so you could useful use asm, or call a function using long double compiled by GCC, clang, or ICC. But beware the ABI differences: you can only pass it inputs as float, double, or integer, because MSVC won't ever create objects in memory in the 80-bit x87 format.

Fun fact: fld m32/m64 can raise / flag an FP exception (#IA) if the source operand is SNaN, but Intel's manual says this can't happen if the source operand is in double extended-precision floating-point format. So it can just stuff the bits into an x87 register without looking at them, unlike fld m32/m64 where it has to expand the significand/exponent fields.

  • to 80-bit long double: 64-bit significand precision. The finit default, and normal setting except with MSVC.
  • to 64-bit double: 53-bit significand precision. 32-bit MSVC sets this.
  • to 32-bit float: 24-bit significand precision.

Apparently the D3D9 library init function sets x87 precision to 24-bit significand single-precision float, making everything less precise for a speed gain on fdiv/fsqrt (and maybe fcos/fsin and other slow microcoded instructions, too.) But x87 precision settings are per-thread, so it matters which thread you call the init function from! (The x87 control word is part of the architectural state that context switches save/restore.)

Of course you can set it back to 64-bit significand with _controlfp_s, so you could usefully use asm, or call a function using long double compiled by GCC, clang, or ICC. But beware the ABI differences: you can only pass it inputs as float, double, or integer, because MSVC won't ever create objects in memory in the 80-bit x87 format.

added 615 characters in body
Source Link
Loading
brain fart: pentium and *later*. Also fix list formatting, and add info for 486 and earlier.
Source Link
Loading
expand the TL:DR to cover the "yes, long double" part of the answer.
Source Link
Loading
added 236 characters in body
Source Link
Loading
added 142 characters in body
Source Link
Loading
added 150 characters in body
Source Link
Loading
added 462 characters in body
Source Link
Loading
added 1294 characters in body
Source Link
Loading
added 1294 characters in body
Source Link
Loading
added 1294 characters in body
Source Link
Loading
added 1294 characters in body
Source Link
Loading
Source Link
Loading