Repository navigation
Floating constants folded as the target computes them - #381
Merged
Merged
Conversation
fmul was decoded as an X-form instruction with FRB, but it is A-form with FRA and FRC, as the assembler (mach/powerpc/as/mach3.c) encodes it: a multiply with FRC other than f0 stopped the emulator with "unimplemented instruction", and one that matched computed FRA * FRB. The single-precision fadds, fsubs, fmuls and fdivs (opcode 59) were missing. They compute in double and round to float, which is exact for these operations. No test multiplied or did float arithmetic at run time on linuxppc before tests/plat/floats/constfold. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The front ends fold float constants with flt_arith, on 64-bit mantissas, and the back end rounds the result to the target type only at the end. To make that rounding exact, the operations now keep what does not fit as a sticky lowest bit (rounding to odd): the bits shifted out of the smaller operand of flt_add/flt_sub, the lower half of flt_mul's 128-bit product (was rounded half-up at 64 bits), flt_div's remainder (was dropped). flt_rnd(e, bits, emin) rounds to bits bits, to nearest and ties to even, with fewer bits below 2^emin as in a subnormal number. With operands rounded by flt_rnd, the result rounded by flt_rnd to the same precision is what IEEE arithmetic gives. Test: modules/src/flt_arith/ieeetest.c, part of all: 1,580,135 random double and float operations (subnormal results, exact results and ties included) against the host's IEEE arithmetic. The old add, mul and div give 3, 24 and 38 wrong results. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Float constants were kept and folded with flt_arith's 64-bit mantissa and rounded to the target type only when written out, so a folded constant could differ from the same computation at run time: 11-39% of folded + - * / results were 1 ulp off (0.1 + 0.2 gave the double nearest 0.3, not 0.30000000000000004). A float constant also kept 64 bits: (double)0.1f was the double 0.1, and 0.1f == 0.1 was true. Now every float constant is rounded to its type with flt_rnd(): a literal, a folded result, an integer converted to a floating type, and a conversion between floating types (which only changed the type). A 4-byte type is IEEE single and an 8-byte type IEEE double, subnormal numbers included. For a target whose floating point is not IEEE, the new -Vm<n> gives the mantissa bits of an 8-byte type; pdpv7 uses -Vm56. flt_str2flt scaled the digits by multiplying with reciprocal powers of ten, which is not exact; with flt_mul's sticky bit even "1.0" came out as more than 1, and an exact tie like 9007199254740993.0 rounded the wrong way. Negative exponents now divide by the exact powers 10^0 to 10^27, and digits that do not fit in 64 bits set the sticky bit instead of being dropped. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Folded floating constants compared with the same expressions computed at run time from volatile operands, and with exact values: + - * / of double and float, float precision of float constants ((double)0.1f, 0.1f == 0.1), 0.1 + 0.2 == 0.30000000000000004, ties rounded to even (9007199254740993.0, 16777217.0f, (float)16777217L) and subnormal results. In the floats set. With the compiler before the two previous commits, 20 of its 26 checks fail. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
maarten-boot
added a commit
to maarten-boot/ack
that referenced
this pull request
Oct 30, 2026
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Owner
|
Merged; thanks! |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
folds them at that precision and rounds to the target type only when it writes
them out. A folded constant could then differ from the same computation at
run time: in a probe of 300 random pairs, 11-39% of folded
+ - * /results(double and float) were 1 ulp off.
0.1 + 0.2gave the double nearest 0.3,not
0.30000000000000004. A float constant also kept 64 bits, so(double)0.1fwas the double 0.1 and0.1f == 0.1was true.sticky lowest bit (round to odd): the bits shifted out of the smaller operand
in add/sub, the lower half of mul's 128-bit product (was rounded half-up),
div's remainder (was dropped). New
flt_rnd(e, bits, emin)rounds tobitsbits, to nearest and ties to even, with subnormal numbers below
2^emin.With operands and result rounded by
flt_rnd, a result is what IEEEarithmetic gives. Documented in
flt_arith.3.flt_rnd(): a literal, a folded result, an integer converted to a floatingtype, and a conversion between floating types. A 4-byte type is IEEE single
and an 8-byte type IEEE double, subnormal numbers included. For targets
without IEEE floating point, the new
-Vm<n>gives the mantissa bits of an8-byte type; pdpv7 (PDP-11 floating point, 56 bits) uses
-Vm56. Documentedin
cemcom.ansi.1.with reciprocal powers of ten, which is not exact; with the sticky bit even
1.0came out as slightly more than 1, and an exact tie like9007199254740993.0rounded the wrong way. It now divides by the exact powers10^0 to 10^27, and digits that do not fit in 64 bits set the sticky bit
instead of being dropped. (A literal with more than 19 significant digits that
is exactly a tie is still judged on its first 19 digits.)
modules/src/flt_arith/ieeetest.c, rulemodules/src/flt_arith+test, partof
all(not on Windows): 1,580,135 random double and float operations(subnormal results, exact results and ties included) against the host's
IEEE arithmetic. The old add, mul and div give 3, 24 and 38 wrong results.
tests/plat/floats/constfold,e,.cin the floats set (run on linuxppc):folded constants compared with the same expressions computed at run time,
and with exact values:
+ - * /of double and float, float precision offloat constants,
0.1 + 0.2 == 0.30000000000000004, ties rounded to evenand subnormal results. With the compiler before this PR, 20 of its 26
checks fail. Operands are plain globals, not volatile: the powerpc ncg
table has no pattern for the
nopcemcom.ansi emits after a volatileaccess (a separate fix).
multiplies, or does single-precision arithmetic, at run time on linuxppc,
and the emulator (
plat/linuxppc/emu/instructions.dat) could not run it.fmulwas decoded as X-form with FRB, but it is A-form with FRA and FRC(as the assembler,
mach/powerpc/as/mach3.c, encodes it): any multiplywith FRC not f0 stopped with "unimplemented instruction", and one that
matched computed FRA × FRB.
fadds,fsubs,fmulsandfdivs(opcode 59) were missing; they compute in double and round to float,
which is exact for these operations.
float_cst(h/con_float) still roundshalf-up when it converts the constant text; the constants it now gets are
already rounded, so that has no effect on IEEE targets. The Modula-2 front end
folds with flt_arith too and is not changed here.
🤖 Generated with Claude Code