JDK-8175916 : JEP 306: Restore Always-Strict Floating-Point Semantics
  • Type: JEP
  • Component: specification
  • Sub-Component: language
  • Priority: P4
  • Status: Closed
  • Resolution: Delivered
  • Fix Versions: 17
  • Submitted: 2017-02-27
  • Updated: 2024-01-03
  • Resolved: 2021-07-23
Related Reports
Relates :  
Relates :  
Relates :  
Relates :  
Relates :  
Sub Tasks
JDK-8269649 :  
Description
Summary
-------


Make floating-point operations consistently strict, rather than have both strict floating-point semantics (`strictfp`) and subtly different default floating-point semantics. This will restore the original floating-point semantics to the language and VM, matching the semantics before the introduction of strict and default floating-point modes in Java SE 1.2.

Goals
-----

- Ease development of numerically-sensitive libraries, including `java.lang.Math` and `java.lang.StrictMath`.

- Provide more regularity in a tricky aspect of the platform.

Non-Goals
---------

It is not a goal to define any sort of "fast-fp" or "loose-fp" (c.f. [JSR 84: Floating Point Extensions](https://jcp.org/en/jsr/detail?id=84)).

Motivation
----------

The impetus for changing the default floating-point semantics of the platform in the late 1990's stemmed from a bad interaction between the original Java language and JVM semantics and some unfortunate peculiarities of the x87 floating-point co-processor instruction set of the popular x86 architecture. Matching the exact floating-point semantics in all cases, including subnormal operands and results, required large overheads of additional instructions. Matching the results in the absence of overflow or underflow could be achieved with much less overhead and that is roughly what is allowed by the revised default floating-point semantics introduced in Java SE 1.2.

However, the SSE2 (Streaming SIMD Extensions 2) extensions, shipped in Pentium 4 and later processors starting circa 2001, could support strict JVM floating-point operations in a straightforward manner without undue overhead.

Since Intel and AMD have both long supported SSE2 and later extensions which allow natural support for strict floating-point semantics, the technical motivation for having a default floating-point semantics different than strict is no longer present.

Description
-----------

The interfaces this JEP would modify include the Java Language Specification in its coverage of floating-point expressions (see [JLS](https://docs.oracle.com/javase/specs/jls/se16/html/index.html) sections 4.2.3 *Floating-Point Types, Formats, and Values*, 5.1.13 *Value Set Conversion, 15.4 *FP-strict Expressions*, many small updates to other sections later in chapter 15) and similar sections of the Java Virtual Machine Specification  ([JVMS](https://docs.oracle.com/javase/specs/jvms/se16/html/index.html) 2.3.2 *Floating-Point Types, Values Sets, and Values*, section 2.8.2 *Floating-Point Modes*, 2.8.3 *Value Set Conversion*, and many small updates to individual floating-point instructions). The concepts of value sets and value set conversion would be removed from the JLS and JVMS.
Implementation changes in the JDK would include updating the HotSpot virtual machine to never run in a floating-point mode which allowed the extended exponent value set (such a mode is mandated to be present for `strictfp` operations) and updating `javac` to issue new lint warnings to unnecessary use of the `strictfp` modifier.

Testing
-------

All existing numerical tests would remain valid with this change since this change always uses one of the currently allowable modes of operation.

Existing Java source tests using `strictfp` could be replicated without the modifier. 

Risks and Assumptions
---------------------

The proposed specification changes are low-risk, mostly deleting text and updating the floating-point overviews in JLS and JVMS. The platform's original semantics are restored and strict-only was always an allowable implementation option. Therefore, there is negligible behavior compatibility risk from the changes in this JEP. Even on platforms where non-strict execution could occur, there was no idiom to force non-strict evaluation. To be robust, code always has to be able to work if executed strictly, which will again be the only option.

Comments
Integrated with the trio of changesets: https://git.openjdk.java.net/jdk/commit/0ae4ceb413a7ea92a41cd55cd338f866098eb9b4 https://git.openjdk.java.net/jdk/commit/8624cb53cdf34555ca76ed8ea89878b6e54cd769 https://git.openjdk.java.net/jdk/commit/cb7128b58e02fa0a8dd69e9a9bdd587aa8052d73
03-06-2021

@Volker, your reading of the JEP is correct; it is not allowed today for the JVM to transform (a*b + c) into an fma and it would continue to not be allowed after this JEP. When the fma intrinsics went in, I checked to make sure the matching was done to aggressively. Supporting fma other than by calling the fma method directly would be a fine topic to consider, but is out of scope for this JEP. A talk I'm giving at JVMLS this year will mention fma and other possible future directions.
27-07-2017

This looks good but it also means we won't be able to optimize "a*b+c" behind the scenes (i.e. by the JIT) into a fused multiply and add because that might be "too accurate". I've done a quick check and at least C2 doesn't seem to do such optimizations. There's a single instructions which matches a multiply plus an add node on x86_32 but it is only for 'UseSSE<=1' and it translates into a multiply instruction followed by an add instructions which should be safe: instruct addDPR_mulDPR_reg(regDPR src2, regDPR src1, regDPR src0) %{ predicate( UseSSE<=1 ); match(Set src2 (AddD (MulD src0 src1) src2)); format %{ "FLD $src0\t# ===MACRO3d===\n\t" "DMUL ST,$src1\n\t" "DADDp $src2,ST" %} ins_cost(250); opcode(0xDD); /* LoadD DD /0 */ ins_encode( Push_Reg_FPR(src0), FMul_ST_reg(src1), FAddP_reg_ST(src2) );
27-07-2017

This could use a pithier title. How about "Always-Strict Floating Point"? The Summary is pretty long. Please consider moving the detailed JLS/JVMS references to a different section.
26-07-2017