mirror of
https://github.com/openjdk/jdk.git
synced 2026-05-11 14:11:36 +00:00
6869327: Add new C2 flag to keep safepoints in counted loops
Reviewed-by: kvn, shade
This commit is contained in:
parent
4f54e303f3
commit
c64b2175e7
@ -213,6 +213,9 @@
|
||||
notproduct(bool, TraceProfileTripCount, false, \
|
||||
"Trace profile loop trip count information") \
|
||||
\
|
||||
product(bool, UseCountedLoopSafepoints, false, \
|
||||
"Force counted loops to keep a safepoint") \
|
||||
\
|
||||
product(bool, UseLoopPredicate, true, \
|
||||
"Generate a predicate to select fast/slow loop versions") \
|
||||
\
|
||||
|
||||
@ -690,14 +690,16 @@ bool PhaseIdealLoop::is_counted_loop( Node *x, IdealLoopTree *loop ) {
|
||||
|
||||
} // LoopLimitCheck
|
||||
|
||||
// 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);
|
||||
if (!UseCountedLoopSafepoints) {
|
||||
// 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;
|
||||
}
|
||||
loop->_tail = iftrue;
|
||||
}
|
||||
|
||||
// Build a canonical trip test.
|
||||
@ -786,12 +788,14 @@ bool PhaseIdealLoop::is_counted_loop( Node *x, IdealLoopTree *loop ) {
|
||||
lazy_replace( x, l );
|
||||
set_idom(l, init_control, dom_depth(x));
|
||||
|
||||
// Check for immediately preceding SafePoint and remove
|
||||
Node *sfpt2 = le->in(0);
|
||||
if (sfpt2->Opcode() == Op_SafePoint && is_deleteable_safept(sfpt2)) {
|
||||
lazy_replace( sfpt2, sfpt2->in(TypeFunc::Control));
|
||||
if (loop->_safepts != NULL) {
|
||||
loop->_safepts->yank(sfpt2);
|
||||
if (!UseCountedLoopSafepoints) {
|
||||
// Check for immediately preceding SafePoint and remove
|
||||
Node *sfpt2 = le->in(0);
|
||||
if (sfpt2->Opcode() == Op_SafePoint && is_deleteable_safept(sfpt2)) {
|
||||
lazy_replace( sfpt2, sfpt2->in(TypeFunc::Control));
|
||||
if (loop->_safepts != NULL) {
|
||||
loop->_safepts->yank(sfpt2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1813,6 +1817,33 @@ void PhaseIdealLoop::replace_parallel_iv(IdealLoopTree *loop) {
|
||||
}
|
||||
}
|
||||
|
||||
void IdealLoopTree::remove_safepoints(PhaseIdealLoop* phase, bool keep_one) {
|
||||
// Look for a safepoint on the idom-path.
|
||||
Node* keep = NULL;
|
||||
if (keep_one) {
|
||||
// Keep one if possible
|
||||
for (Node* i = tail(); i != _head; i = phase->idom(i)) {
|
||||
if (i->Opcode() == Op_SafePoint && phase->get_loop(i) == this) {
|
||||
keep = i;
|
||||
break; // Found one
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Delete other safepoints in this loop.
|
||||
Node_List* sfpts = _safepts;
|
||||
if (sfpts != NULL) {
|
||||
assert(keep == NULL || keep->Opcode() == Op_SafePoint, "not safepoint");
|
||||
for (uint i = 0; i < sfpts->size(); i++) {
|
||||
Node* n = sfpts->at(i);
|
||||
assert(phase->get_loop(n) == this, "");
|
||||
if (n != keep && phase->is_deleteable_safept(n)) {
|
||||
phase->lazy_replace(n, n->in(TypeFunc::Control));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------counted_loop-----------------------------------
|
||||
// Convert to counted loops where possible
|
||||
void IdealLoopTree::counted_loop( PhaseIdealLoop *phase ) {
|
||||
@ -1824,42 +1855,23 @@ void IdealLoopTree::counted_loop( PhaseIdealLoop *phase ) {
|
||||
|
||||
if (_head->is_CountedLoop() ||
|
||||
phase->is_counted_loop(_head, this)) {
|
||||
_has_sfpt = 1; // Indicate we do not need a safepoint here
|
||||
|
||||
// Look for safepoints to remove.
|
||||
Node_List* sfpts = _safepts;
|
||||
if (sfpts != NULL) {
|
||||
for (uint i = 0; i < sfpts->size(); i++) {
|
||||
Node* n = sfpts->at(i);
|
||||
assert(phase->get_loop(n) == this, "");
|
||||
if (phase->is_deleteable_safept(n)) {
|
||||
phase->lazy_replace(n, n->in(TypeFunc::Control));
|
||||
}
|
||||
}
|
||||
if (!UseCountedLoopSafepoints) {
|
||||
// Indicate we do not need a safepoint here
|
||||
_has_sfpt = 1;
|
||||
}
|
||||
|
||||
// Remove safepoints
|
||||
bool keep_one_sfpt = !(_has_call || _has_sfpt);
|
||||
remove_safepoints(phase, keep_one_sfpt);
|
||||
|
||||
// Look for induction variables
|
||||
phase->replace_parallel_iv(this);
|
||||
|
||||
} else if (_parent != NULL && !_irreducible) {
|
||||
// Not a counted loop.
|
||||
// Look for a safepoint on the idom-path.
|
||||
Node* sfpt = tail();
|
||||
for (; sfpt != _head; sfpt = phase->idom(sfpt)) {
|
||||
if (sfpt->Opcode() == Op_SafePoint && phase->get_loop(sfpt) == this)
|
||||
break; // Found one
|
||||
}
|
||||
// Delete other safepoints in this loop.
|
||||
Node_List* sfpts = _safepts;
|
||||
if (sfpts != NULL && sfpt != _head && sfpt->Opcode() == Op_SafePoint) {
|
||||
for (uint i = 0; i < sfpts->size(); i++) {
|
||||
Node* n = sfpts->at(i);
|
||||
assert(phase->get_loop(n) == this, "");
|
||||
if (n != sfpt && phase->is_deleteable_safept(n)) {
|
||||
phase->lazy_replace(n, n->in(TypeFunc::Control));
|
||||
}
|
||||
}
|
||||
}
|
||||
// Not a counted loop. Keep one safepoint.
|
||||
bool keep_one_sfpt = true;
|
||||
remove_safepoints(phase, keep_one_sfpt);
|
||||
}
|
||||
|
||||
// Recursively
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1998, 2015, Oracle and/or its affiliates. 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
|
||||
@ -429,6 +429,9 @@ public:
|
||||
// encountered.
|
||||
void allpaths_check_safepts(VectorSet &visited, Node_List &stack);
|
||||
|
||||
// Remove safepoints from loop. Optionally keeping one.
|
||||
void remove_safepoints(PhaseIdealLoop* phase, bool keep_one);
|
||||
|
||||
// Convert to counted loops where possible
|
||||
void counted_loop( PhaseIdealLoop *phase );
|
||||
|
||||
|
||||
68
hotspot/test/compiler/loopopts/UseCountedLoopSafepoints.java
Normal file
68
hotspot/test/compiler/loopopts/UseCountedLoopSafepoints.java
Normal file
@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright (c) 2015, Oracle and/or its affiliates. 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 6869327
|
||||
* @summary Test that C2 flag UseCountedLoopSafepoints ensures a safepoint is kept in a CountedLoop
|
||||
* @library /testlibrary
|
||||
* @modules java.base
|
||||
* @run main UseCountedLoopSafepoints
|
||||
*/
|
||||
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
import jdk.test.lib.ProcessTools;
|
||||
import jdk.test.lib.OutputAnalyzer;
|
||||
|
||||
public class UseCountedLoopSafepoints {
|
||||
private static final AtomicLong _num = new AtomicLong(0);
|
||||
|
||||
// Uses the fact that an EnableBiasedLocking vmop will be started
|
||||
// after 500ms, while we are still in the loop. If there is a
|
||||
// safepoint in the counted loop, then we will reach safepoint
|
||||
// very quickly. Otherwise SafepointTimeout will be hit.
|
||||
public static void main (String args[]) throws Exception {
|
||||
if (args.length == 1) {
|
||||
final int loops = Integer.parseInt(args[0]);
|
||||
for (int i = 0; i < loops; i++) {
|
||||
_num.addAndGet(1);
|
||||
}
|
||||
} else {
|
||||
ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
|
||||
"-XX:+IgnoreUnrecognizedVMOptions",
|
||||
"-XX:-TieredCompilation",
|
||||
"-XX:+UseBiasedLocking",
|
||||
"-XX:BiasedLockingStartupDelay=500",
|
||||
"-XX:+SafepointTimeout",
|
||||
"-XX:SafepointTimeoutDelay=2000",
|
||||
"-XX:+UseCountedLoopSafepoints",
|
||||
"UseCountedLoopSafepoints",
|
||||
"2000000000"
|
||||
);
|
||||
OutputAnalyzer output = new OutputAnalyzer(pb.start());
|
||||
output.shouldNotContain("Timeout detected");
|
||||
output.shouldHaveExitValue(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user