mirror of
https://github.com/openjdk/jdk.git
synced 2025-09-17 17:44:40 +02:00
8296545: C2 Blackholes should allow load optimizations
Reviewed-by: kvn, vlivanov
This commit is contained in:
parent
dea2161f06
commit
eab0ada3a1
7 changed files with 168 additions and 43 deletions
|
@ -39,6 +39,7 @@
|
||||||
#include "opto/narrowptrnode.hpp"
|
#include "opto/narrowptrnode.hpp"
|
||||||
#include "opto/mulnode.hpp"
|
#include "opto/mulnode.hpp"
|
||||||
#include "opto/phaseX.hpp"
|
#include "opto/phaseX.hpp"
|
||||||
|
#include "opto/regalloc.hpp"
|
||||||
#include "opto/regmask.hpp"
|
#include "opto/regmask.hpp"
|
||||||
#include "opto/runtime.hpp"
|
#include "opto/runtime.hpp"
|
||||||
#include "opto/subnode.hpp"
|
#include "opto/subnode.hpp"
|
||||||
|
@ -2814,3 +2815,25 @@ void NeverBranchNode::format( PhaseRegAlloc *ra_, outputStream *st) const {
|
||||||
st->print("%s", Name());
|
st->print("%s", Name());
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef PRODUCT
|
||||||
|
void BlackholeNode::format(PhaseRegAlloc* ra, outputStream* st) const {
|
||||||
|
st->print("blackhole ");
|
||||||
|
bool first = true;
|
||||||
|
for (uint i = 0; i < req(); i++) {
|
||||||
|
Node* n = in(i);
|
||||||
|
if (n != NULL && OptoReg::is_valid(ra->get_reg_first(n))) {
|
||||||
|
if (first) {
|
||||||
|
first = false;
|
||||||
|
} else {
|
||||||
|
st->print(", ");
|
||||||
|
}
|
||||||
|
char buf[128];
|
||||||
|
ra->dump_register(n, buf);
|
||||||
|
st->print("%s", buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
st->cr();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -47,6 +47,7 @@ class PCTableNode;
|
||||||
class JumpNode;
|
class JumpNode;
|
||||||
class CatchNode;
|
class CatchNode;
|
||||||
class NeverBranchNode;
|
class NeverBranchNode;
|
||||||
|
class BlackholeNode;
|
||||||
class ProjNode;
|
class ProjNode;
|
||||||
class CProjNode;
|
class CProjNode;
|
||||||
class IfTrueNode;
|
class IfTrueNode;
|
||||||
|
@ -604,4 +605,28 @@ public:
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//------------------------------BlackholeNode----------------------------
|
||||||
|
// Blackhole all arguments. This node would survive through the compiler
|
||||||
|
// the effects on its arguments, and would be finally matched to nothing.
|
||||||
|
class BlackholeNode : public MultiNode {
|
||||||
|
public:
|
||||||
|
BlackholeNode(Node* ctrl) : MultiNode(1) {
|
||||||
|
init_req(TypeFunc::Control, ctrl);
|
||||||
|
}
|
||||||
|
virtual int Opcode() const;
|
||||||
|
virtual uint ideal_reg() const { return 0; } // not matched in the AD file
|
||||||
|
virtual const Type* bottom_type() const { return TypeTuple::MEMBAR; }
|
||||||
|
|
||||||
|
const RegMask &in_RegMask(uint idx) const {
|
||||||
|
// Fake the incoming arguments mask for blackholes: accept all registers
|
||||||
|
// and all stack slots. This would avoid any redundant register moves
|
||||||
|
// for blackhole inputs.
|
||||||
|
return RegMask::All;
|
||||||
|
}
|
||||||
|
#ifndef PRODUCT
|
||||||
|
virtual void format(PhaseRegAlloc* ra, outputStream* st) const;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
#endif // SHARE_OPTO_CFGNODE_HPP
|
#endif // SHARE_OPTO_CFGNODE_HPP
|
||||||
|
|
|
@ -7841,8 +7841,15 @@ bool LibraryCallKit::inline_blackhole() {
|
||||||
assert(callee()->is_empty(), "Should have been checked before: only empty methods here");
|
assert(callee()->is_empty(), "Should have been checked before: only empty methods here");
|
||||||
assert(callee()->holder()->is_loaded(), "Should have been checked before: only methods for loaded classes here");
|
assert(callee()->holder()->is_loaded(), "Should have been checked before: only methods for loaded classes here");
|
||||||
|
|
||||||
|
// Blackhole node pinches only the control, not memory. This allows
|
||||||
|
// the blackhole to be pinned in the loop that computes blackholed
|
||||||
|
// values, but have no other side effects, like breaking the optimizations
|
||||||
|
// across the blackhole.
|
||||||
|
|
||||||
|
Node* bh = _gvn.transform(new BlackholeNode(control()));
|
||||||
|
set_control(_gvn.transform(new ProjNode(bh, TypeFunc::Control)));
|
||||||
|
|
||||||
// Bind call arguments as blackhole arguments to keep them alive
|
// Bind call arguments as blackhole arguments to keep them alive
|
||||||
Node* bh = insert_mem_bar(Op_Blackhole);
|
|
||||||
uint nargs = callee()->arg_size();
|
uint nargs = callee()->arg_size();
|
||||||
for (uint i = 0; i < nargs; i++) {
|
for (uint i = 0; i < nargs; i++) {
|
||||||
bh->add_req(argument(i));
|
bh->add_req(argument(i));
|
||||||
|
|
|
@ -3261,7 +3261,6 @@ MemBarNode* MemBarNode::make(Compile* C, int opcode, int atp, Node* pn) {
|
||||||
case Op_MemBarCPUOrder: return new MemBarCPUOrderNode(C, atp, pn);
|
case Op_MemBarCPUOrder: return new MemBarCPUOrderNode(C, atp, pn);
|
||||||
case Op_OnSpinWait: return new OnSpinWaitNode(C, atp, pn);
|
case Op_OnSpinWait: return new OnSpinWaitNode(C, atp, pn);
|
||||||
case Op_Initialize: return new InitializeNode(C, atp, pn);
|
case Op_Initialize: return new InitializeNode(C, atp, pn);
|
||||||
case Op_Blackhole: return new BlackholeNode(C, atp, pn);
|
|
||||||
default: ShouldNotReachHere(); return NULL;
|
default: ShouldNotReachHere(); return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3501,26 +3500,6 @@ MemBarNode* MemBarNode::leading_membar() const {
|
||||||
return mb;
|
return mb;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef PRODUCT
|
|
||||||
void BlackholeNode::format(PhaseRegAlloc* ra, outputStream* st) const {
|
|
||||||
st->print("blackhole ");
|
|
||||||
bool first = true;
|
|
||||||
for (uint i = 0; i < req(); i++) {
|
|
||||||
Node* n = in(i);
|
|
||||||
if (n != NULL && OptoReg::is_valid(ra->get_reg_first(n))) {
|
|
||||||
if (first) {
|
|
||||||
first = false;
|
|
||||||
} else {
|
|
||||||
st->print(", ");
|
|
||||||
}
|
|
||||||
char buf[128];
|
|
||||||
ra->dump_register(n, buf);
|
|
||||||
st->print("%s", buf);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
st->cr();
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//===========================InitializeNode====================================
|
//===========================InitializeNode====================================
|
||||||
// SUMMARY:
|
// SUMMARY:
|
||||||
|
|
|
@ -1296,26 +1296,6 @@ public:
|
||||||
virtual int Opcode() const;
|
virtual int Opcode() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
//------------------------------BlackholeNode----------------------------
|
|
||||||
// Blackhole all arguments. This node would survive through the compiler
|
|
||||||
// the effects on its arguments, and would be finally matched to nothing.
|
|
||||||
class BlackholeNode : public MemBarNode {
|
|
||||||
public:
|
|
||||||
BlackholeNode(Compile* C, int alias_idx, Node* precedent)
|
|
||||||
: MemBarNode(C, alias_idx, precedent) {}
|
|
||||||
virtual int Opcode() const;
|
|
||||||
virtual uint ideal_reg() const { return 0; } // not matched in the AD file
|
|
||||||
const RegMask &in_RegMask(uint idx) const {
|
|
||||||
// Fake the incoming arguments mask for blackholes: accept all registers
|
|
||||||
// and all stack slots. This would avoid any redundant register moves
|
|
||||||
// for blackhole inputs.
|
|
||||||
return RegMask::All;
|
|
||||||
}
|
|
||||||
#ifndef PRODUCT
|
|
||||||
virtual void format(PhaseRegAlloc* ra, outputStream* st) const;
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
// Isolation of object setup after an AllocateNode and before next safepoint.
|
// Isolation of object setup after an AllocateNode and before next safepoint.
|
||||||
// (See comment in memnode.cpp near InitializeNode::InitializeNode for semantics.)
|
// (See comment in memnode.cpp near InitializeNode::InitializeNode for semantics.)
|
||||||
class InitializeNode: public MemBarNode {
|
class InitializeNode: public MemBarNode {
|
||||||
|
|
|
@ -1565,7 +1565,7 @@
|
||||||
declare_c2_type(MemBarVolatileNode, MemBarNode) \
|
declare_c2_type(MemBarVolatileNode, MemBarNode) \
|
||||||
declare_c2_type(MemBarCPUOrderNode, MemBarNode) \
|
declare_c2_type(MemBarCPUOrderNode, MemBarNode) \
|
||||||
declare_c2_type(OnSpinWaitNode, MemBarNode) \
|
declare_c2_type(OnSpinWaitNode, MemBarNode) \
|
||||||
declare_c2_type(BlackholeNode, MemBarNode) \
|
declare_c2_type(BlackholeNode, MultiNode) \
|
||||||
declare_c2_type(InitializeNode, MemBarNode) \
|
declare_c2_type(InitializeNode, MemBarNode) \
|
||||||
declare_c2_type(ThreadLocalNode, Node) \
|
declare_c2_type(ThreadLocalNode, Node) \
|
||||||
declare_c2_type(Opaque1Node, Node) \
|
declare_c2_type(Opaque1Node, Node) \
|
||||||
|
|
|
@ -0,0 +1,111 @@
|
||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @test
|
||||||
|
* @bug 8296545
|
||||||
|
* @requires vm.compiler2.enabled
|
||||||
|
* @summary Blackholes should allow load optimizations
|
||||||
|
* @library /test/lib /
|
||||||
|
* @run driver compiler.c2.irTests.blackhole.BlackholeLoadOptoTest
|
||||||
|
*/
|
||||||
|
|
||||||
|
package compiler.c2.irTests.blackhole;
|
||||||
|
|
||||||
|
import compiler.lib.ir_framework.*;
|
||||||
|
import jdk.test.lib.Asserts;
|
||||||
|
|
||||||
|
public class BlackholeLoadOptoTest {
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
TestFramework.runWithFlags(
|
||||||
|
"-XX:+UnlockExperimentalVMOptions",
|
||||||
|
"-XX:CompileThreshold=100",
|
||||||
|
"-XX:-TieredCompilation",
|
||||||
|
"-XX:CompileCommand=blackhole,compiler.c2.irTests.blackhole.BlackholeLoadOptoTest::blackhole",
|
||||||
|
"-XX:CompileCommand=dontinline,compiler.c2.irTests.blackhole.BlackholeLoadOptoTest::dontinline"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int x, y;
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Negative test: check that dangling expressions are eliminated
|
||||||
|
*/
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@IR(failOn = {IRNode.LOAD_I, IRNode.MUL_I})
|
||||||
|
static void testNothing() {
|
||||||
|
int r1 = x * y;
|
||||||
|
int r2 = x * y;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Run(test = "testNothing")
|
||||||
|
static void runNothing() {
|
||||||
|
testNothing();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Auxiliary test: check that dontinline method does break optimizations
|
||||||
|
*/
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@IR(counts = {IRNode.LOAD_I, "4"})
|
||||||
|
@IR(counts = {IRNode.MUL_I, "2"})
|
||||||
|
static void testDontline() {
|
||||||
|
int r1 = x * y;
|
||||||
|
dontinline(r1);
|
||||||
|
int r2 = x * y;
|
||||||
|
dontinline(r2);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void dontinline(int x) {}
|
||||||
|
|
||||||
|
@Run(test = "testDontline")
|
||||||
|
static void runDontinline() {
|
||||||
|
testDontline();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Positive test: check that blackhole does not break optimizations
|
||||||
|
*/
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@IR(counts = {IRNode.LOAD_I, "2"})
|
||||||
|
@IR(counts = {IRNode.MUL_I, "1"})
|
||||||
|
static void testBlackholed() {
|
||||||
|
int r1 = x * y;
|
||||||
|
blackhole(r1);
|
||||||
|
int r2 = x * y;
|
||||||
|
blackhole(r2);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void blackhole(int x) {}
|
||||||
|
|
||||||
|
@Run(test = "testBlackholed")
|
||||||
|
static void runBlackholed() {
|
||||||
|
testBlackholed();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue