JDK-8286638 : C2: CmpU needs to do more precise over/underflow analysis
  • Type: Bug
  • Component: hotspot
  • Sub-Component: compiler
  • Affected Version: 17,18,19
  • Priority: P2
  • Status: Closed
  • Resolution: Fixed
  • Submitted: 2022-05-12
  • Updated: 2022-07-12
  • Resolved: 2022-05-16
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 17 JDK 19
17.0.5-oracleFixed 19 b23Fixed
Related Reports
Duplicate :  
Relates :  
Relates :  
Description
Was originally from bug JDK-8283466 that reported multiple domination asserts.
Creating a separate bug because it is not related to all other issue, was only triggered with the ConvI2L refactoring JDK-8230382.

Original Bug Reproducer:

$ build/linux-x86_64-server-fastdebug/images/jdk/bin/java -cp 0029/ -Xmx512m -XX:+UnlockDiagnosticVMOptions -XX:+StressIGVN -Xcomp -XX:CompileOnly=Test -XX:-TieredCompilation Test
CompileCommand: compileonly Test.* bool compileonly = true
# To suppress the following error report, specify this argument
# after -XX: or in .hotspotrc: SuppressErrorAt=/gcm.cpp:766
#
# A fatal error has been detected by the Java Runtime Environment:
#
# Internal Error (/home/shade/trunks/jdk/src/hotspot/share/opto/gcm.cpp:766), pid=3733508, tid=3733521
# assert(!LCA_orig->dominates(pred_block) || early->dominates(pred_block)) failed: early is high enough
#
# JRE version: OpenJDK Runtime Environment (19.0) (fastdebug build 19-internal-adhoc.shade.jdk)
# Java VM: OpenJDK 64-Bit Server VM (fastdebug 19-internal-adhoc.shade.jdk, compiled mode, sharing, compressed oops, compressed class ptrs, g1 gc, linux-amd64)
# Problematic frame:
# V [libjvm.so+0xdd1fe5] PhaseCFG::insert_anti_dependences(Block*, Node*, bool)+0x18a5


Copied analysis from comments in JDK-8283466?:

Scenario:
type i: [minint...0]
access to c[i-1]

Range-check:
int index = AddI(i, -1)
-> type index: [minint-1 ... -1] -> underflow -> int
CmpU(index, c.size()) [lt] -> checks index>=0 and index<c.size()
Consequence: range-check cannot statically determine that the access is never ok.
Sad, because we can manually tell that the range [minint-1 ... -1] should not pass the range check.

Data-flow:
long index = ConvI2L( AddI(i, -1) )
-> type of ConvI2L: [0...maxint-1]
-> why do we know this? Because this is before an array access. We assume range-check guarantees index in range [0...c.size()-1], and c.size()<=maxint.
Then there is a push_thru_add, and we get:
long index = AddL( ConvI2L(i), -1)
-> type of new ConvI2L: [1...maxint-1] - because we correct the lo by 1 for the add. Somehow we do not adjust hi, in my opinion it should now be maxint, to correct by 1.
Consequence: if hi is maxint or maxint-1, there is no overflow.
Then, we statically detect that:
type i: [minint...0]
type ConvI2L: [1...maxint-1]
-> filter results in TOP -> data-flow is eliminated sucessfully.

Result in the end:
data-flow collapses, while control-flow (range-check) does not collapse. This leads to issues described above.

With the help of [~thartmann], we tracked it to CmpUNode::Value.
There, we analyze if the in1 is an AddI.
We detect that this AddI may have 2 ranges:
tr1: int:<=-1:www
tr2: int:max (underflow: minint-1)

We then check how these ranges compare to in2:
t2: int:>=0

For this we compute:
const Type* cmp1 = sub(tr1, t2); -> TypeInt::CC_GT = [1]
const Type* cmp2 = sub(tr2, t2); -> TypeInt::CC_GE = [0...1]

But then, we only do something with this result if cmp1 == cmp2.
https://github.com/openjdk/jdk/blame/master/src/hotspot/share/opto/subnode.cpp#L832

However, I wonder if we can not just take the union of cmp1 and cmp2, which would be [0...1] = [GE]
Then, the output node [655 Bool] checks for [lt], which we could know is never true.
We could conclude that the Range-check never passes.
This would then also kill the control-flow, in parallel to the data-flow that is already killed with ConvI2L.

Implementation:
const TypeInt* cmp1 = sub(tr1, t2)->is_int();
const TypeInt* cmp2 = sub(tr2, t2)->is_int();
// compute union, so that cmp handles all possible results from the two cases
return cmp1->meet(cmp2);
Comments
New added compiler/rangechecks/TestRangeCheckCmpUUnderflow.java test passed in JDK 19 ATR.
12-07-2022

Fix request [17u] I backport this for parity with 17.0.5-oracle. A C2 fix we should take. Clean backport. Test passes, but also without the fix. SAP nightly testing passed.
22-06-2022

A pull request was submitted for review. URL: https://git.openjdk.org/jdk17u-dev/pull/486 Date: 2022-06-21 15:42:50 +0000
21-06-2022

A pull request was submitted for review. URL: https://git.openjdk.org/jdk18u/pull/168 Date: 2022-06-21 08:26:59 +0000
21-06-2022

ILW = crash in compiler; reproduces with stress flags; disable compilation = HMM = P2
16-05-2022

[~dlong] Yes, it seems to affect product build. JDK-19 build 22. I use the regression test I have just integrated: jdk-19-22-linux-x64/bin/java -XX:+UnlockDiagnosticVMOptions -XX:+StressIGVN -Xcomp -XX:-TieredCompilation -XX:CompileCommand=compileonly,compiler.rangechecks.TestRangeCheckCmpUUnderflow::* -XX:RepeatCompilation=300 TestRangeCheckCmpUUnderflow.java # # A fatal error has been detected by the Java Runtime Environment: # # SIGSEGV (0xb) at pc=0x00007fa6403e0868, pid=2592964, tid=2592977 # # JRE version: Java(TM) SE Runtime Environment (19.0+22) (build 19-ea+22-1598) # Java VM: Java HotSpot(TM) 64-Bit Server VM (19-ea+22-1598, compiled mode, sharing, compressed oops, compressed class ptrs, g1 gc, linux-amd64) # Problematic frame: # V [libjvm.so+0x455868] OopFlow::build_oop_map(Node*, int, PhaseRegAlloc*, int*)+0x108 # # Core dump will be written. Default location: /scratch/empeter/core.2592964 # # An error report file with more information is saved as: # /scratch/empeter/hs_err_pid2592964.log # # Compiler replay data is saved as: # /scratch/empeter/replay_pid2592964.log # # If you would like to submit a bug report, please visit: # https://bugreport.java.com/bugreport/crash.jsp #
16-05-2022

Changeset: 2d34acfe Author: Emanuel Peter <emanuel.peter@oracle.com> Committer: Tobias Hartmann <thartmann@openjdk.org> Date: 2022-05-16 07:21:30 +0000 URL: https://git.openjdk.java.net/jdk/commit/2d34acfec908e6cdfb8e920b54d5b932029e4bac
16-05-2022

Does this affect product builds?
14-05-2022

A pull request was submitted for review. URL: https://git.openjdk.java.net/jdk/pull/8679 Date: 2022-05-12 12:29:22 +0000
12-05-2022