Skip to content
This repository has been archived by the owner on Feb 2, 2023. It is now read-only.

Commit

Permalink
Browse files Browse the repository at this point in the history
8282045: When loop strip mining fails, safepoints are removed from lo…
…op anyway

Backport-of: 2c5d266f9f20005bc2a6c30dcaa95b059ea59d74
  • Loading branch information
TobiHartmann committed Apr 6, 2022
1 parent 0389833 commit a65922b
Show file tree
Hide file tree
Showing 3 changed files with 178 additions and 38 deletions.
82 changes: 44 additions & 38 deletions src/hotspot/share/opto/loopnode.cpp
Expand Up @@ -690,8 +690,7 @@ SafePointNode* PhaseIdealLoop::find_safepoint(Node* back_control, Node* x, Ideal

Node* mem = safepoint->in(TypeFunc::Memory);

// We can only use that safepoint if there's not side effect
// between the backedge and the safepoint.
// We can only use that safepoint if there's no side effect between the backedge and the safepoint.

// mm is used for book keeping
MergeMemNode* mm = NULL;
Expand Down Expand Up @@ -1624,16 +1623,6 @@ bool PhaseIdealLoop::is_counted_loop(Node* x, IdealLoopTree*&loop, BasicType iv_
return false;
}

if (x->in(LoopNode::LoopBackControl)->Opcode() == Op_SafePoint &&
((iv_bt == T_INT && LoopStripMiningIter != 0) ||
iv_bt == T_LONG)) {
// Leaving the safepoint on the backedge and creating a
// CountedLoop will confuse optimizations. We can't move the
// safepoint around because its jvm state wouldn't match a new
// location. Give up on that loop.
return false;
}

Node* iftrue = back_control;
uint iftrue_op = iftrue->Opcode();
Node* iff = iftrue->in(0);
Expand Down Expand Up @@ -1862,6 +1851,37 @@ bool PhaseIdealLoop::is_counted_loop(Node* x, IdealLoopTree*&loop, BasicType iv_
}
}

Node* sfpt = NULL;
if (loop->_child == NULL) {
sfpt = find_safepoint(back_control, x, loop);
} else {
sfpt = iff->in(0);
if (sfpt->Opcode() != Op_SafePoint) {
sfpt = NULL;
}
}

if (x->in(LoopNode::LoopBackControl)->Opcode() == Op_SafePoint) {
Node* backedge_sfpt = x->in(LoopNode::LoopBackControl);
if (((iv_bt == T_INT && LoopStripMiningIter != 0) ||
iv_bt == T_LONG) &&
sfpt == NULL) {
// Leaving the safepoint on the backedge and creating a
// CountedLoop will confuse optimizations. We can't move the
// safepoint around because its jvm state wouldn't match a new
// location. Give up on that loop.
return false;
}
if (is_deleteable_safept(backedge_sfpt)) {
lazy_replace(backedge_sfpt, iftrue);
if (loop->_safepts != NULL) {
loop->_safepts->yank(backedge_sfpt);
}
loop->_tail = iftrue;
}
}


#ifdef ASSERT
if (iv_bt == T_INT &&
!x->as_Loop()->is_loop_nest_inner_loop() &&
Expand Down Expand Up @@ -1900,18 +1920,6 @@ bool PhaseIdealLoop::is_counted_loop(Node* x, IdealLoopTree*&loop, BasicType iv_
}
set_subtree_ctrl(adjusted_limit, false);

if (iv_bt == T_INT && LoopStripMiningIter == 0) {
// Check for SafePoint on backedge and remove
Node *sfpt = x->in(LoopNode::LoopBackControl);
if (sfpt->Opcode() == Op_SafePoint && is_deleteable_safept(sfpt)) {
lazy_replace( sfpt, iftrue );
if (loop->_safepts != NULL) {
loop->_safepts->yank(sfpt);
}
loop->_tail = iftrue;
}
}

// Build a canonical trip test.
// Clone code, as old values may be in use.
incr = incr->clone();
Expand Down Expand Up @@ -1983,13 +1991,11 @@ bool PhaseIdealLoop::is_counted_loop(Node* x, IdealLoopTree*&loop, BasicType iv_
assert(iff->outcnt() == 0, "should be dead now");
lazy_replace( iff, le ); // fix 'get_ctrl'

Node *sfpt2 = le->in(0);

Node* entry_control = init_control;
bool strip_mine_loop = iv_bt == T_INT &&
LoopStripMiningIter > 1 &&
loop->_child == NULL &&
sfpt2->Opcode() == Op_SafePoint &&
sfpt != NULL &&
!loop->_has_call;
IdealLoopTree* outer_ilt = NULL;
if (strip_mine_loop) {
Expand All @@ -2015,30 +2021,30 @@ bool PhaseIdealLoop::is_counted_loop(Node* x, IdealLoopTree*&loop, BasicType iv_

if (iv_bt == T_INT && (LoopStripMiningIter == 0 || strip_mine_loop)) {
// Check for immediately preceding SafePoint and remove
if (sfpt2->Opcode() == Op_SafePoint && (LoopStripMiningIter != 0 || is_deleteable_safept(sfpt2))) {
if (sfpt != NULL && (LoopStripMiningIter != 0 || is_deleteable_safept(sfpt))) {
if (strip_mine_loop) {
Node* outer_le = outer_ilt->_tail->in(0);
Node* sfpt = sfpt2->clone();
sfpt->set_req(0, iffalse);
outer_le->set_req(0, sfpt);
Node* sfpt_clone = sfpt->clone();
sfpt_clone->set_req(0, iffalse);
outer_le->set_req(0, sfpt_clone);

Node* polladdr = sfpt->in(TypeFunc::Parms);
Node* polladdr = sfpt_clone->in(TypeFunc::Parms);
if (polladdr != nullptr && polladdr->is_Load()) {
// Polling load should be pinned outside inner loop.
Node* new_polladdr = polladdr->clone();
new_polladdr->set_req(0, iffalse);
_igvn.register_new_node_with_optimizer(new_polladdr, polladdr);
set_ctrl(new_polladdr, iffalse);
sfpt->set_req(TypeFunc::Parms, new_polladdr);
sfpt_clone->set_req(TypeFunc::Parms, new_polladdr);
}
// When this code runs, loop bodies have not yet been populated.
const bool body_populated = false;
register_control(sfpt, outer_ilt, iffalse, body_populated);
set_idom(outer_le, sfpt, dom_depth(sfpt));
register_control(sfpt_clone, outer_ilt, iffalse, body_populated);
set_idom(outer_le, sfpt_clone, dom_depth(sfpt_clone));
}
lazy_replace( sfpt2, sfpt2->in(TypeFunc::Control));
lazy_replace(sfpt, sfpt->in(TypeFunc::Control));
if (loop->_safepts != NULL) {
loop->_safepts->yank(sfpt2);
loop->_safepts->yank(sfpt);
}
}
}
Expand Down Expand Up @@ -3666,7 +3672,7 @@ void IdealLoopTree::counted_loop( PhaseIdealLoop *phase ) {
if (_head->is_CountedLoop() ||
phase->is_counted_loop(_head, loop, T_INT)) {

if (LoopStripMiningIter == 0 || (LoopStripMiningIter > 1 && _child == NULL)) {
if (LoopStripMiningIter == 0 || _head->as_CountedLoop()->is_strip_mined()) {
// Indicate we do not need a safepoint here
_has_sfpt = 1;
}
Expand Down
@@ -0,0 +1,132 @@
/*
* Copyright (c) 2022, Red Hat, Inc. 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.
*/

package compiler.c2.irTests;

import compiler.lib.ir_framework.*;

/*
* @test
* @bug 8282045
* @summary When loop strip mining fails, safepoints are removed from loop anyway
* @library /test/lib /
* @run driver compiler.c2.irTests.TestStripMiningDropsSafepoint
*/

public class TestStripMiningDropsSafepoint {
public static void main(String[] args) {
TestFramework.runWithFlags("-XX:+UseCountedLoopSafepoints", "-XX:LoopStripMiningIter=1000", "-XX:LoopMaxUnroll=1", "-XX:-RangeCheckElimination");
TestFramework.runWithFlags("-XX:+UseCountedLoopSafepoints", "-XX:LoopStripMiningIter=1000", "-XX:LoopMaxUnroll=1", "-XX:-RangeCheckElimination", "-XX:-PartialPeelLoop");
}

@Test
@IR(applyIf = { "PartialPeelLoop", "true" }, counts = { IRNode.COUNTEDLOOP, "1", IRNode.OUTERSTRIPMINEDLOOP, "1", IRNode.SAFEPOINT, "1" })
private static void test1(int[] dst, int[] src) {
// Partial peel is applied. No side effect between exit and
// safepoint.
for (int i = 0; ; ) {
// prevent ciTypeFlow from cloning head
synchronized (new Object()) {}
i++;
if (i >= src.length) {
break;
}
dst[i] = src[i];
if (i / 2 >= 2000) {
break;
}
}
}

@Run(test = "test1")
private static void test1_runner() {
int[] array1 = new int[1000];
int[] array2 = new int[10000];
test1(array1, array1);
test1(array2, array2);
}

@Test
@IR(applyIf = { "PartialPeelLoop", "true" }, counts = { IRNode.COUNTEDLOOP, "1", IRNode.SAFEPOINT, "1" })
@IR(applyIf = { "PartialPeelLoop", "true" }, failOn = { IRNode.OUTERSTRIPMINEDLOOP })
private static void test2(int[] dst, int[] src) {
// Partial peel is applied. Some side effect between exit and
// safepoint.
int v = src[0];
for (int i = 0; ; ) {
synchronized (new Object()) {}
dst[i] = v;
i++;
if (i >= src.length) {
break;
}
v = src[i];
if (i / 2 >= 2000) {
break;
}
}
}

@Run(test = "test2")
private static void test2_runner() {
int[] array1 = new int[1000];
int[] array2 = new int[10000];
test2(array1, array1);
test2(array2, array2);
}

@Test
@IR(applyIf = { "PartialPeelLoop", "false" }, counts = { IRNode.COUNTEDLOOP, "1", IRNode.OUTERSTRIPMINEDLOOP, "1", IRNode.SAFEPOINT, "1" })
private static void test3(int[] dst, int[] src) {
int v = src[0];
for (int i = 0; ; ) {
synchronized (new Object()) {}
dst[i] = v;
int inc = test3_helper(2);
v = src[i];
i += (inc / 2);
if (i >= src.length) {
break;
}
for (int j = 0; j < 10; j++) {
}
// safepoint on backedge
}
}

private static int test3_helper(int stop) {
int i = 1;
do {
synchronized (new Object()) {}
i *= 2;
} while (i < stop);
return i;
}

@Run(test = "test3")
private static void test3_runner() {
int[] array1 = new int[1000];
test3(array1, array1);
test3_helper(10);
}
}
2 changes: 2 additions & 0 deletions test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java
Expand Up @@ -113,6 +113,7 @@ public class IRNode {
public static final String LOOP = START + "Loop" + MID + END;
public static final String COUNTEDLOOP = START + "CountedLoop\\b" + MID + END;
public static final String COUNTEDLOOP_MAIN = START + "CountedLoop\\b" + MID + "main" + END;
public static final String OUTERSTRIPMINEDLOOP = START + "OuterStripMinedLoop\\b" + MID + END;

public static final String CALL = START + "Call.*Java" + MID + END;
public static final String CALL_OF_METHOD = COMPOSITE_PREFIX + START + "Call.*Java" + MID + IS_REPLACED + " " + END;
Expand All @@ -132,6 +133,7 @@ public class IRNode {

public static final String SCOPE_OBJECT = "(.*# ScObj.*" + END;
public static final String MEMBAR = START + "MemBar" + MID + END;
public static final String SAFEPOINT = START + "SafePoint" + MID + END;

public static final String AND_I = START + "AndI" + MID + END;
public static final String AND_L = START + "AndL" + MID + END;
Expand Down

1 comment on commit a65922b

@openjdk-notifier
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.