Projects
Mega:24.09
openjdk-1.8.0
_service:tar_scm:8305541-C2-Div-Mod-nodes-witho...
Sign Up
Log In
Username
Password
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File _service:tar_scm:8305541-C2-Div-Mod-nodes-without-zero-check-could-be.patch of Package openjdk-1.8.0
From 5a21d735ffa345f956d2c637b4e13f55c907a219 Mon Sep 17 00:00:00 2001 From: wangjiawei <wangjiawei80@huawei.com> Date: Fri, 28 Apr 2023 10:41:14 +0800 Subject: [PATCH 15/15] 8305541: C2 Div/Mod nodes without zero check could be split through iv phi of loop resulting in SIGFPE DTS/AR: DTS2023041008055 Summary: <hotspot> : 8305541: C2 Div/Mod nodes without zero check could be split through iv phi of loop resulting in SIGFPE LLT: NA Patch Type: backport Bug url: https://bugs.openjdk.org/browse/JDK-8305541 --- hotspot/src/share/vm/opto/loopnode.hpp | 4 +- hotspot/src/share/vm/opto/loopopts.cpp | 40 +++++ .../c2/TestSplitDivisionThroughPhi.java | 155 ++++++++++++++++++ 3 files changed, 198 insertions(+), 1 deletion(-) create mode 100644 hotspot/test/compiler/c2/TestSplitDivisionThroughPhi.java diff --git a/hotspot/src/share/vm/opto/loopnode.hpp b/hotspot/src/share/vm/opto/loopnode.hpp index 6f70b5065..f8750e54a 100644 --- a/hotspot/src/share/vm/opto/loopnode.hpp +++ b/hotspot/src/share/vm/opto/loopnode.hpp @@ -1071,7 +1071,9 @@ private: Node *place_near_use( Node *useblock ) const; Node* try_move_store_before_loop(Node* n, Node *n_ctrl); void try_move_store_after_loop(Node* n); - + bool cannot_split_division(const Node* n, const Node* region) const; + static bool is_divisor_counted_loop_phi(const Node* divisor, const Node* loop); + bool loop_phi_backedge_type_contains_zero(const Node* phi_divisor, const Type* zero) const; bool _created_loop_node; public: void set_created_loop_node() { _created_loop_node = true; } diff --git a/hotspot/src/share/vm/opto/loopopts.cpp b/hotspot/src/share/vm/opto/loopopts.cpp index 20bdb1493..28bfcb75b 100644 --- a/hotspot/src/share/vm/opto/loopopts.cpp +++ b/hotspot/src/share/vm/opto/loopopts.cpp @@ -51,6 +51,10 @@ Node *PhaseIdealLoop::split_thru_phi( Node *n, Node *region, int policy ) { return NULL; } + if (cannot_split_division(n, region)) { + return NULL; + } + int wins = 0; assert(!n->is_CFG(), ""); assert(region->is_Region(), ""); @@ -200,6 +204,42 @@ Node *PhaseIdealLoop::split_thru_phi( Node *n, Node *region, int policy ) { return phi; } +// Return true if 'n' is a Div or Mod node (without zero check If node which was removed earlier) with a loop phi divisor +// of a trip-counted (integer or long) loop with a backedge input that could be zero (include zero in its type range). In +// this case, we cannot split the division to the backedge as it could freely float above the loop exit check resulting in +// a division by zero. This situation is possible because the type of an increment node of an iv phi (trip-counter) could +// include zero while the iv phi does not (see PhiNode::Value() for trip-counted loops where we improve types of iv phis). +// We also need to check other loop phis as they could have been created in the same split-if pass when applying +// PhaseIdealLoop::split_thru_phi() to split nodes through an iv phi. +bool PhaseIdealLoop::cannot_split_division(const Node* n, const Node* region) const { + const Type* zero; + switch (n->Opcode()) { + case Op_DivI: + case Op_ModI: + zero = TypeInt::ZERO; + break; + case Op_DivL: + case Op_ModL: + zero = TypeLong::ZERO; + break; + default: + return false; + } + + assert(n->in(0) == NULL, "divisions with zero check should already have bailed out earlier in split-if"); + Node* divisor = n->in(2); + return is_divisor_counted_loop_phi(divisor, region) && + loop_phi_backedge_type_contains_zero(divisor, zero); +} + +bool PhaseIdealLoop::is_divisor_counted_loop_phi(const Node* divisor, const Node* loop) { + return loop->is_CountedLoop() && divisor->is_Phi() && divisor->in(0) == loop; +} + +bool PhaseIdealLoop::loop_phi_backedge_type_contains_zero(const Node* phi_divisor, const Type* zero) const { + return _igvn.type(phi_divisor->in(LoopNode::LoopBackControl))->filter_speculative(zero) != Type::TOP; +} + //------------------------------dominated_by------------------------------------ // Replace the dominated test with an obvious true or false. Place it on the // IGVN worklist for later cleanup. Move control-dependent data Nodes on the diff --git a/hotspot/test/compiler/c2/TestSplitDivisionThroughPhi.java b/hotspot/test/compiler/c2/TestSplitDivisionThroughPhi.java new file mode 100644 index 000000000..0a59783fa --- /dev/null +++ b/hotspot/test/compiler/c2/TestSplitDivisionThroughPhi.java @@ -0,0 +1,155 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, Huawei Technologies Co., Ltd. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 8299259 + * @summary Test various cases of divisions/modulo which should not be split through iv phis. + * @run main/othervm -Xbatch -XX:+UnlockDiagnosticVMOptions -XX:LoopUnrollLimit=0 -XX:+StressGCM + * -XX:CompileCommand=compileonly,TestSplitDivisionThroughPhi::* TestSplitDivisionThroughPhi + */ + +/** + * @test + * @bug 8299259 + * @summary Test various cases of divisions/modulo which should not be split through iv phis. + * @run main/othervm -Xbatch -XX:+UnlockDiagnosticVMOptions -XX:LoopUnrollLimit=0 -XX:+StressGCM + * -XX:CompileCommand=compileonly,TestSplitDivisionThroughPhi::* TestSplitDivisionThroughPhi + */ + + +public class TestSplitDivisionThroughPhi { + static int iFld; + static long lFld; + static boolean flag; + + + public static void main(String[] strArr) { + for (int i = 0; i < 5000; i++) { + testPushDivIThruPhi(); + testPushDivIThruPhiInChain(); + testPushModIThruPhi(); + testPushModIThruPhiInChain(); + testPushDivLThruPhi(); + testPushDivLThruPhiInChain(); + testPushModLThruPhi(); + testPushModLThruPhiInChain(); + } + } + + // Already fixed by JDK-8248552. + static void testPushDivIThruPhi() { + for (int i = 10; i > 1; i -= 2) { + // The Div node is only split in later loop opts phase because the zero divisor check is only removed + // in IGVN after the first loop opts phase. + // + // iv phi i type: [2..10] + // When splitting the DivI through the iv phi, it ends up on the back edge with the trip count decrement + // as input which has type [0..8]. We end up executing a division by zero on the last iteration because + // the DivI it is not pinned to the loop exit test and can freely float above the loop exit check. + iFld = 10 / i; + } + } + + // Same as above but with an additional Mul node between the iv phi and the Div node. Both nodes are split through + // the iv phi in one pass of Split If. + static void testPushDivIThruPhiInChain() { + for (int i = 10; i > 1; i -= 2) { + // Empty one iteration loop which is only removed after split if in first loop opts phase. This prevents + // that the Mul node is already split through the iv phi while the Div node cannot be split yet due to + // the zero divisor check which can only be removed in the IGVN after the first loop opts pass. + for (int j = 0; j < 1; j++) { + } + iFld = 10 / (i * 100); + } + } + + // Already fixed by JDK-8248552. + static void testPushModIThruPhi() { + for (int i = 10; i > 1; i -= 2) { + iFld = 10 / i; + } + } + + // Same as above but with ModI. + static void testPushModIThruPhiInChain() { + for (int i = 10; i > 1; i -= 2) { + for (int j = 0; j < 1; j++) { + } + iFld = 10 / (i * 100); + } + } + + // Long cases only trigger since JDK-8256655. + + // Same as above but with DivL. + static void testPushDivLThruPhi() { + for (long i = 10; i > 1; i -= 2) { + lFld = 10L / i; + + // Loop that is not removed such that we do not transform the outer LongCountedLoop (only done if innermost) + for (int j = 0; j < 10; j++) { + flag = !flag; + } + } + } + + // Same as above but with DivL. + static void testPushDivLThruPhiInChain() { + for (long i = 10; i > 1; i -= 2) { + for (int j = 0; j < 1; j++) { + } + lFld = 10L / (i * 100L); + + for (int j = 0; j < 10; j++) { + flag = !flag; + } + } + } + + // Same as above but with ModL + static void testPushModLThruPhi() { + for (long i = 10; i > 1; i -= 2) { + lFld = 10L % i; + + for (int j = 0; j < 10; j++) { + flag = !flag; + } + } + } + + // Same as above but with ModL + static void testPushModLThruPhiInChain() { + for (long i = 10; i > 1; i -= 2) { + for (int j = 0; j < 1; j++) { + } + lFld = 10L % (i * 100L); + + for (int j = 0; j < 10; j++) { + flag = !flag; + } + } + } +} + -- 2.19.0
Locations
Projects
Search
Status Monitor
Help
Open Build Service
OBS Manuals
API Documentation
OBS Portal
Reporting a Bug
Contact
Mailing List
Forums
Chat (IRC)
Twitter
Open Build Service (OBS)
is an
openSUSE project
.
浙ICP备2022010568号-2