C2 compiler incorrectly optimizes float expression 0 - (0 - f) to f, violating IEEE 754 signed zero semantics

XMLWordPrintable

      ADDITIONAL SYSTEM INFORMATION :
      Software:
          System Software Overview:
            System Version: Ubuntu 22.04.4 LTS
            Kernel Version: 4.15.0-45-generic
            Boot Volume: overlay
            Boot Mode: Legacy BIOS
            Computer Name: 899309ef3feb
            User Name: root
            Time since boot: 21 weeks, 2 days, 6 hours, 47 minutes

      Hardware:
          Hardware Overview:
            Model: Unknown
            Model Identifier: Unknown
            Chip: Intel(R) Xeon(R) CPU E5-2640 v4 @ 2.40GHz
            Total Number of Cores: 40 (10 physical x 2 logical)
            Memory: 125Gi
            System Firmware Version: Unknown

      A DESCRIPTION OF THE PROBLEM :
      I have encountered a bug where the C2 JIT compiler performs an incorrect algebraic simplification for floating-point subtraction, leading to a violation of IEEE 754 semantics regarding signed zeros.
      Mathematically, the expression 0 - (0 - x) equals x. However, in IEEE 754 floating-point arithmetic, this identity does not hold when x is -0.0.
      Given f = -0.0f:
      Inner expression: 0.0f - (-0.0f) results in +0.0f.
      Outer expression: 0.0f - (+0.0f) results in +0.0f.
      Therefore, the expected result is positive zero (0.0f, raw bits 0).
      However, when the code is executed frequently enough to trigger C2 compilation, the JVM returns negative zero (-0.0f, raw bits 0x80000000 / -2147483648).
      This suggests that the C2 optimizer is applying an identity transformation (likely folding 0 - (0 - val) to val) without checking for the special case of signed zero, which is required by the Java Language Specification.

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      1. Compile the attached source code Test.java.
      2. Run it with java -Xcomp Test.

      ---------- BEGIN SOURCE ----------
      class Test {
          static float testFloat(float f) {
              return ((Float) (0 - (0 - f)));
          }

          public static void main(String[] args) {
              for (int k = 0; k < 101; k++) {
                  for (int i = 0; i < 10000; i++) {
                      int floatRes = Float.floatToIntBits(testFloat(((float) (-0.0))));
                      if (floatRes != 0) {
                          throw new RuntimeException("Invalid result: " + ((long) (floatRes)));
                      }
                  }
              }
          }
      }
      ---------- END SOURCE ----------

      FREQUENCY :
      ALWAYS

            Assignee:
            Unassigned
            Reporter:
            Webbug Group
            Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

              Created:
              Updated: