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/mulnode.hpp"
|
||||
#include "opto/phaseX.hpp"
|
||||
#include "opto/regalloc.hpp"
|
||||
#include "opto/regmask.hpp"
|
||||
#include "opto/runtime.hpp"
|
||||
#include "opto/subnode.hpp"
|
||||
|
@ -2814,3 +2815,25 @@ void NeverBranchNode::format( PhaseRegAlloc *ra_, outputStream *st) const {
|
|||
st->print("%s", Name());
|
||||
}
|
||||
#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 CatchNode;
|
||||
class NeverBranchNode;
|
||||
class BlackholeNode;
|
||||
class ProjNode;
|
||||
class CProjNode;
|
||||
class IfTrueNode;
|
||||
|
@ -604,4 +605,28 @@ public:
|
|||
#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
|
||||
|
|
|
@ -7841,8 +7841,15 @@ bool LibraryCallKit::inline_blackhole() {
|
|||
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");
|
||||
|
||||
// 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
|
||||
Node* bh = insert_mem_bar(Op_Blackhole);
|
||||
uint nargs = callee()->arg_size();
|
||||
for (uint i = 0; i < nargs; 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_OnSpinWait: return new OnSpinWaitNode(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;
|
||||
}
|
||||
}
|
||||
|
@ -3501,26 +3500,6 @@ MemBarNode* MemBarNode::leading_membar() const {
|
|||
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====================================
|
||||
// SUMMARY:
|
||||
|
|
|
@ -1296,26 +1296,6 @@ public:
|
|||
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.
|
||||
// (See comment in memnode.cpp near InitializeNode::InitializeNode for semantics.)
|
||||
class InitializeNode: public MemBarNode {
|
||||
|
|
|
@ -1565,7 +1565,7 @@
|
|||
declare_c2_type(MemBarVolatileNode, MemBarNode) \
|
||||
declare_c2_type(MemBarCPUOrderNode, MemBarNode) \
|
||||
declare_c2_type(OnSpinWaitNode, MemBarNode) \
|
||||
declare_c2_type(BlackholeNode, MemBarNode) \
|
||||
declare_c2_type(BlackholeNode, MultiNode) \
|
||||
declare_c2_type(InitializeNode, MemBarNode) \
|
||||
declare_c2_type(ThreadLocalNode, 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