mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-27 14:54:52 +02:00
8333334: C2: Make result of Node::dominates
more precise to enhance scalar replacement
Reviewed-by: chagedorn, kvn, thartmann
This commit is contained in:
parent
69bd227e6c
commit
965dd1acd0
6 changed files with 236 additions and 50 deletions
|
@ -1,5 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||||
|
* Copyright (c) 2024, Alibaba Group Holding Limited. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -427,23 +428,31 @@ Node *MemNode::Ideal_common(PhaseGVN *phase, bool can_reshape) {
|
||||||
// Used by MemNode::find_previous_store to prove that the
|
// Used by MemNode::find_previous_store to prove that the
|
||||||
// control input of a memory operation predates (dominates)
|
// control input of a memory operation predates (dominates)
|
||||||
// an allocation it wants to look past.
|
// an allocation it wants to look past.
|
||||||
bool MemNode::all_controls_dominate(Node* dom, Node* sub) {
|
// Returns 'DomResult::Dominate' if all control inputs of 'dom'
|
||||||
if (dom == nullptr || dom->is_top() || sub == nullptr || sub->is_top())
|
// dominate 'sub', 'DomResult::NotDominate' if not,
|
||||||
return false; // Conservative answer for dead code
|
// and 'DomResult::EncounteredDeadCode' if we can't decide due to
|
||||||
|
// dead code, but at the end of IGVN, we know the definite result
|
||||||
|
// once the dead code is cleaned up.
|
||||||
|
Node::DomResult MemNode::maybe_all_controls_dominate(Node* dom, Node* sub) {
|
||||||
|
if (dom == nullptr || dom->is_top() || sub == nullptr || sub->is_top()) {
|
||||||
|
return DomResult::EncounteredDeadCode; // Conservative answer for dead code
|
||||||
|
}
|
||||||
|
|
||||||
// Check 'dom'. Skip Proj and CatchProj nodes.
|
// Check 'dom'. Skip Proj and CatchProj nodes.
|
||||||
dom = dom->find_exact_control(dom);
|
dom = dom->find_exact_control(dom);
|
||||||
if (dom == nullptr || dom->is_top())
|
if (dom == nullptr || dom->is_top()) {
|
||||||
return false; // Conservative answer for dead code
|
return DomResult::EncounteredDeadCode; // Conservative answer for dead code
|
||||||
|
}
|
||||||
|
|
||||||
if (dom == sub) {
|
if (dom == sub) {
|
||||||
// For the case when, for example, 'sub' is Initialize and the original
|
// For the case when, for example, 'sub' is Initialize and the original
|
||||||
// 'dom' is Proj node of the 'sub'.
|
// 'dom' is Proj node of the 'sub'.
|
||||||
return false;
|
return DomResult::NotDominate;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dom->is_Con() || dom->is_Start() || dom->is_Root() || dom == sub)
|
if (dom->is_Con() || dom->is_Start() || dom->is_Root() || dom == sub) {
|
||||||
return true;
|
return DomResult::Dominate;
|
||||||
|
}
|
||||||
|
|
||||||
// 'dom' dominates 'sub' if its control edge and control edges
|
// 'dom' dominates 'sub' if its control edge and control edges
|
||||||
// of all its inputs dominate or equal to sub's control edge.
|
// of all its inputs dominate or equal to sub's control edge.
|
||||||
|
@ -457,16 +466,19 @@ bool MemNode::all_controls_dominate(Node* dom, Node* sub) {
|
||||||
// Get control edge of 'sub'.
|
// Get control edge of 'sub'.
|
||||||
Node* orig_sub = sub;
|
Node* orig_sub = sub;
|
||||||
sub = sub->find_exact_control(sub->in(0));
|
sub = sub->find_exact_control(sub->in(0));
|
||||||
if (sub == nullptr || sub->is_top())
|
if (sub == nullptr || sub->is_top()) {
|
||||||
return false; // Conservative answer for dead code
|
return DomResult::EncounteredDeadCode; // Conservative answer for dead code
|
||||||
|
}
|
||||||
|
|
||||||
assert(sub->is_CFG(), "expecting control");
|
assert(sub->is_CFG(), "expecting control");
|
||||||
|
|
||||||
if (sub == dom)
|
if (sub == dom) {
|
||||||
return true;
|
return DomResult::Dominate;
|
||||||
|
}
|
||||||
|
|
||||||
if (sub->is_Start() || sub->is_Root())
|
if (sub->is_Start() || sub->is_Root()) {
|
||||||
return false;
|
return DomResult::NotDominate;
|
||||||
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
// Check all control edges of 'dom'.
|
// Check all control edges of 'dom'.
|
||||||
|
@ -480,41 +492,47 @@ bool MemNode::all_controls_dominate(Node* dom, Node* sub) {
|
||||||
|
|
||||||
for (uint next = 0; next < dom_list.size(); next++) {
|
for (uint next = 0; next < dom_list.size(); next++) {
|
||||||
Node* n = dom_list.at(next);
|
Node* n = dom_list.at(next);
|
||||||
if (n == orig_sub)
|
if (n == orig_sub) {
|
||||||
return false; // One of dom's inputs dominated by sub.
|
return DomResult::NotDominate; // One of dom's inputs dominated by sub.
|
||||||
|
}
|
||||||
if (!n->is_CFG() && n->pinned()) {
|
if (!n->is_CFG() && n->pinned()) {
|
||||||
// Check only own control edge for pinned non-control nodes.
|
// Check only own control edge for pinned non-control nodes.
|
||||||
n = n->find_exact_control(n->in(0));
|
n = n->find_exact_control(n->in(0));
|
||||||
if (n == nullptr || n->is_top())
|
if (n == nullptr || n->is_top()) {
|
||||||
return false; // Conservative answer for dead code
|
return DomResult::EncounteredDeadCode; // Conservative answer for dead code
|
||||||
|
}
|
||||||
assert(n->is_CFG(), "expecting control");
|
assert(n->is_CFG(), "expecting control");
|
||||||
dom_list.push(n);
|
dom_list.push(n);
|
||||||
} else if (n->is_Con() || n->is_Start() || n->is_Root()) {
|
} else if (n->is_Con() || n->is_Start() || n->is_Root()) {
|
||||||
only_dominating_controls = true;
|
only_dominating_controls = true;
|
||||||
} else if (n->is_CFG()) {
|
} else if (n->is_CFG()) {
|
||||||
if (n->dominates(sub, nlist))
|
DomResult dom_result = n->dominates(sub, nlist);
|
||||||
|
if (dom_result == DomResult::Dominate) {
|
||||||
only_dominating_controls = true;
|
only_dominating_controls = true;
|
||||||
else
|
} else {
|
||||||
return false;
|
return dom_result;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// First, own control edge.
|
// First, own control edge.
|
||||||
Node* m = n->find_exact_control(n->in(0));
|
Node* m = n->find_exact_control(n->in(0));
|
||||||
if (m != nullptr) {
|
if (m != nullptr) {
|
||||||
if (m->is_top())
|
if (m->is_top()) {
|
||||||
return false; // Conservative answer for dead code
|
return DomResult::EncounteredDeadCode; // Conservative answer for dead code
|
||||||
|
}
|
||||||
dom_list.push(m);
|
dom_list.push(m);
|
||||||
}
|
}
|
||||||
// Now, the rest of edges.
|
// Now, the rest of edges.
|
||||||
uint cnt = n->req();
|
uint cnt = n->req();
|
||||||
for (uint i = 1; i < cnt; i++) {
|
for (uint i = 1; i < cnt; i++) {
|
||||||
m = n->find_exact_control(n->in(i));
|
m = n->find_exact_control(n->in(i));
|
||||||
if (m == nullptr || m->is_top())
|
if (m == nullptr || m->is_top()) {
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
dom_list.push(m);
|
dom_list.push(m);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return only_dominating_controls;
|
return only_dominating_controls ? DomResult::Dominate : DomResult::NotDominate;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -726,16 +744,18 @@ Node* MemNode::find_previous_store(PhaseValues* phase) {
|
||||||
} else if (mem->is_Proj() && mem->in(0)->is_Initialize()) {
|
} else if (mem->is_Proj() && mem->in(0)->is_Initialize()) {
|
||||||
InitializeNode* st_init = mem->in(0)->as_Initialize();
|
InitializeNode* st_init = mem->in(0)->as_Initialize();
|
||||||
AllocateNode* st_alloc = st_init->allocation();
|
AllocateNode* st_alloc = st_init->allocation();
|
||||||
if (st_alloc == nullptr)
|
if (st_alloc == nullptr) {
|
||||||
break; // something degenerated
|
break; // something degenerated
|
||||||
|
}
|
||||||
bool known_identical = false;
|
bool known_identical = false;
|
||||||
bool known_independent = false;
|
bool known_independent = false;
|
||||||
if (alloc == st_alloc)
|
if (alloc == st_alloc) {
|
||||||
known_identical = true;
|
known_identical = true;
|
||||||
else if (alloc != nullptr)
|
} else if (alloc != nullptr) {
|
||||||
known_independent = true;
|
known_independent = true;
|
||||||
else if (all_controls_dominate(this, st_alloc))
|
} else if (all_controls_dominate(this, st_alloc)) {
|
||||||
known_independent = true;
|
known_independent = true;
|
||||||
|
}
|
||||||
|
|
||||||
if (known_independent) {
|
if (known_independent) {
|
||||||
// The bases are provably independent: Either they are
|
// The bases are provably independent: Either they are
|
||||||
|
@ -1566,8 +1586,9 @@ bool LoadNode::can_split_through_phi_base(PhaseGVN* phase) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!mem->is_Phi()) {
|
if (!mem->is_Phi()) {
|
||||||
if (!MemNode::all_controls_dominate(mem, base->in(0)))
|
if (!MemNode::all_controls_dominate(mem, base->in(0))) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
} else if (base->in(0) != mem->in(0)) {
|
} else if (base->in(0) != mem->in(0)) {
|
||||||
if (!MemNode::all_controls_dominate(mem, base->in(0))) {
|
if (!MemNode::all_controls_dominate(mem, base->in(0))) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -1658,35 +1679,49 @@ Node* LoadNode::split_through_phi(PhaseGVN* phase, bool ignore_missing_instance_
|
||||||
|
|
||||||
// Select Region to split through.
|
// Select Region to split through.
|
||||||
Node* region;
|
Node* region;
|
||||||
|
DomResult dom_result = DomResult::Dominate;
|
||||||
if (!base_is_phi) {
|
if (!base_is_phi) {
|
||||||
assert(mem->is_Phi(), "sanity");
|
assert(mem->is_Phi(), "sanity");
|
||||||
region = mem->in(0);
|
region = mem->in(0);
|
||||||
// Skip if the region dominates some control edge of the address.
|
// Skip if the region dominates some control edge of the address.
|
||||||
if (!MemNode::all_controls_dominate(address, region))
|
// We will check `dom_result` later.
|
||||||
return nullptr;
|
dom_result = MemNode::maybe_all_controls_dominate(address, region);
|
||||||
} else if (!mem->is_Phi()) {
|
} else if (!mem->is_Phi()) {
|
||||||
assert(base_is_phi, "sanity");
|
assert(base_is_phi, "sanity");
|
||||||
region = base->in(0);
|
region = base->in(0);
|
||||||
// Skip if the region dominates some control edge of the memory.
|
// Skip if the region dominates some control edge of the memory.
|
||||||
if (!MemNode::all_controls_dominate(mem, region))
|
// We will check `dom_result` later.
|
||||||
return nullptr;
|
dom_result = MemNode::maybe_all_controls_dominate(mem, region);
|
||||||
} else if (base->in(0) != mem->in(0)) {
|
} else if (base->in(0) != mem->in(0)) {
|
||||||
assert(base_is_phi && mem->is_Phi(), "sanity");
|
assert(base_is_phi && mem->is_Phi(), "sanity");
|
||||||
if (MemNode::all_controls_dominate(mem, base->in(0))) {
|
dom_result = MemNode::maybe_all_controls_dominate(mem, base->in(0));
|
||||||
|
if (dom_result == DomResult::Dominate) {
|
||||||
region = base->in(0);
|
region = base->in(0);
|
||||||
} else if (MemNode::all_controls_dominate(address, mem->in(0))) {
|
|
||||||
region = mem->in(0);
|
|
||||||
} else {
|
} else {
|
||||||
return nullptr; // complex graph
|
dom_result = MemNode::maybe_all_controls_dominate(address, mem->in(0));
|
||||||
|
if (dom_result == DomResult::Dominate) {
|
||||||
|
region = mem->in(0);
|
||||||
|
}
|
||||||
|
// Otherwise we encountered a complex graph.
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
assert(base->in(0) == mem->in(0), "sanity");
|
assert(base->in(0) == mem->in(0), "sanity");
|
||||||
region = mem->in(0);
|
region = mem->in(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PhaseIterGVN* igvn = phase->is_IterGVN();
|
||||||
|
if (dom_result != DomResult::Dominate) {
|
||||||
|
if (dom_result == DomResult::EncounteredDeadCode) {
|
||||||
|
// There is some dead code which eventually will be removed in IGVN.
|
||||||
|
// Once this is the case, we get an unambiguous dominance result.
|
||||||
|
// Push the node to the worklist again until the dead code is removed.
|
||||||
|
igvn->_worklist.push(this);
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
Node* phi = nullptr;
|
Node* phi = nullptr;
|
||||||
const Type* this_type = this->bottom_type();
|
const Type* this_type = this->bottom_type();
|
||||||
PhaseIterGVN* igvn = phase->is_IterGVN();
|
|
||||||
if (t_oop != nullptr && (t_oop->is_known_instance_field() || load_boxed_values)) {
|
if (t_oop != nullptr && (t_oop->is_known_instance_field() || load_boxed_values)) {
|
||||||
int this_index = C->get_alias_index(t_oop);
|
int this_index = C->get_alias_index(t_oop);
|
||||||
int this_offset = t_oop->offset();
|
int this_offset = t_oop->offset();
|
||||||
|
@ -4571,8 +4606,9 @@ bool InitializeNode::detect_init_independence(Node* value, PhaseGVN* phase) {
|
||||||
// must have preceded the init, or else be equal to the init.
|
// must have preceded the init, or else be equal to the init.
|
||||||
// Even after loop optimizations (which might change control edges)
|
// Even after loop optimizations (which might change control edges)
|
||||||
// a store is never pinned *before* the availability of its inputs.
|
// a store is never pinned *before* the availability of its inputs.
|
||||||
if (!MemNode::all_controls_dominate(n, this))
|
if (!MemNode::all_controls_dominate(n, this)) {
|
||||||
return false; // failed to prove a good control
|
return false; // failed to prove a good control
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check data edges for possible dependencies on 'this'.
|
// Check data edges for possible dependencies on 'this'.
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||||
|
* Copyright (c) 2024, Alibaba Group Holding Limited. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -105,8 +106,12 @@ public:
|
||||||
|
|
||||||
static Node *optimize_simple_memory_chain(Node *mchain, const TypeOopPtr *t_oop, Node *load, PhaseGVN *phase);
|
static Node *optimize_simple_memory_chain(Node *mchain, const TypeOopPtr *t_oop, Node *load, PhaseGVN *phase);
|
||||||
static Node *optimize_memory_chain(Node *mchain, const TypePtr *t_adr, Node *load, PhaseGVN *phase);
|
static Node *optimize_memory_chain(Node *mchain, const TypePtr *t_adr, Node *load, PhaseGVN *phase);
|
||||||
// This one should probably be a phase-specific function:
|
// The following two should probably be phase-specific functions:
|
||||||
static bool all_controls_dominate(Node* dom, Node* sub);
|
static DomResult maybe_all_controls_dominate(Node* dom, Node* sub);
|
||||||
|
static bool all_controls_dominate(Node* dom, Node* sub) {
|
||||||
|
DomResult dom_result = maybe_all_controls_dominate(dom, sub);
|
||||||
|
return dom_result == DomResult::Dominate;
|
||||||
|
}
|
||||||
|
|
||||||
virtual const class TypePtr *adr_type() const; // returns bottom_type of address
|
virtual const class TypePtr *adr_type() const; // returns bottom_type of address
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||||
|
* Copyright (c) 2024, Alibaba Group Holding Limited. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -1249,7 +1250,7 @@ Node* Node::find_exact_control(Node* ctrl) {
|
||||||
// We already know that if any path back to Root or Start reaches 'this',
|
// We already know that if any path back to Root or Start reaches 'this',
|
||||||
// then all paths so, so this is a simple search for one example,
|
// then all paths so, so this is a simple search for one example,
|
||||||
// not an exhaustive search for a counterexample.
|
// not an exhaustive search for a counterexample.
|
||||||
bool Node::dominates(Node* sub, Node_List &nlist) {
|
Node::DomResult Node::dominates(Node* sub, Node_List &nlist) {
|
||||||
assert(this->is_CFG(), "expecting control");
|
assert(this->is_CFG(), "expecting control");
|
||||||
assert(sub != nullptr && sub->is_CFG(), "expecting control");
|
assert(sub != nullptr && sub->is_CFG(), "expecting control");
|
||||||
|
|
||||||
|
@ -1269,12 +1270,15 @@ bool Node::dominates(Node* sub, Node_List &nlist) {
|
||||||
// will either exit through the loop head, or give up.
|
// will either exit through the loop head, or give up.
|
||||||
// (If we get confused, break out and return a conservative 'false'.)
|
// (If we get confused, break out and return a conservative 'false'.)
|
||||||
while (sub != nullptr) {
|
while (sub != nullptr) {
|
||||||
if (sub->is_top()) break; // Conservative answer for dead code.
|
if (sub->is_top()) {
|
||||||
|
// Conservative answer for dead code.
|
||||||
|
return DomResult::EncounteredDeadCode;
|
||||||
|
}
|
||||||
if (sub == dom) {
|
if (sub == dom) {
|
||||||
if (nlist.size() == 0) {
|
if (nlist.size() == 0) {
|
||||||
// No Region nodes except loops were visited before and the EntryControl
|
// No Region nodes except loops were visited before and the EntryControl
|
||||||
// path was taken for loops: it did not walk in a cycle.
|
// path was taken for loops: it did not walk in a cycle.
|
||||||
return true;
|
return DomResult::Dominate;
|
||||||
} else if (met_dom) {
|
} else if (met_dom) {
|
||||||
break; // already met before: walk in a cycle
|
break; // already met before: walk in a cycle
|
||||||
} else {
|
} else {
|
||||||
|
@ -1288,7 +1292,7 @@ bool Node::dominates(Node* sub, Node_List &nlist) {
|
||||||
// Success if we met 'dom' along a path to Start or Root.
|
// Success if we met 'dom' along a path to Start or Root.
|
||||||
// We assume there are no alternative paths that avoid 'dom'.
|
// We assume there are no alternative paths that avoid 'dom'.
|
||||||
// (This assumption is up to the caller to ensure!)
|
// (This assumption is up to the caller to ensure!)
|
||||||
return met_dom;
|
return met_dom ? DomResult::Dominate : DomResult::NotDominate;
|
||||||
}
|
}
|
||||||
Node* up = sub->in(0);
|
Node* up = sub->in(0);
|
||||||
// Normalize simple pass-through regions and projections:
|
// Normalize simple pass-through regions and projections:
|
||||||
|
@ -1319,7 +1323,7 @@ bool Node::dominates(Node* sub, Node_List &nlist) {
|
||||||
if (visited == sub) {
|
if (visited == sub) {
|
||||||
if (visited_twice_already) {
|
if (visited_twice_already) {
|
||||||
// Visited 2 paths, but still stuck in loop body. Give up.
|
// Visited 2 paths, but still stuck in loop body. Give up.
|
||||||
return false;
|
return DomResult::NotDominate;
|
||||||
}
|
}
|
||||||
// The Region node was visited before only once.
|
// The Region node was visited before only once.
|
||||||
// (We will repush with the low bit set, below.)
|
// (We will repush with the low bit set, below.)
|
||||||
|
@ -1362,8 +1366,7 @@ bool Node::dominates(Node* sub, Node_List &nlist) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Did not meet Root or Start node in pred. chain.
|
// Did not meet Root or Start node in pred. chain.
|
||||||
// Conservative answer for dead code.
|
return DomResult::NotDominate;
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------remove_dead_region-----------------------------
|
//------------------------------remove_dead_region-----------------------------
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||||
|
* Copyright (c) 2024, Alibaba Group Holding Limited. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -1107,8 +1108,14 @@ public:
|
||||||
// Skip Proj and CatchProj nodes chains. Check for Null and Top.
|
// Skip Proj and CatchProj nodes chains. Check for Null and Top.
|
||||||
Node* find_exact_control(Node* ctrl);
|
Node* find_exact_control(Node* ctrl);
|
||||||
|
|
||||||
|
// Results of the dominance analysis.
|
||||||
|
enum class DomResult {
|
||||||
|
NotDominate, // 'this' node does not dominate 'sub'.
|
||||||
|
Dominate, // 'this' node dominates or is equal to 'sub'.
|
||||||
|
EncounteredDeadCode // Result is undefined due to encountering dead code.
|
||||||
|
};
|
||||||
// Check if 'this' node dominates or equal to 'sub'.
|
// Check if 'this' node dominates or equal to 'sub'.
|
||||||
bool dominates(Node* sub, Node_List &nlist);
|
DomResult dominates(Node* sub, Node_List &nlist);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool remove_dead_region(PhaseGVN *phase, bool can_reshape);
|
bool remove_dead_region(PhaseGVN *phase, bool can_reshape);
|
||||||
|
|
|
@ -0,0 +1,118 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2024 Alibaba Group Holding Limited. 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.scalarReplacement;
|
||||||
|
|
||||||
|
import compiler.lib.ir_framework.*;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @test
|
||||||
|
* @bug 8333334
|
||||||
|
* @summary Tests that dead barrier control flows do not affect the scalar replacement.
|
||||||
|
* @library /test/lib /
|
||||||
|
* @requires vm.compiler2.enabled
|
||||||
|
* @requires vm.gc.G1
|
||||||
|
* @run driver compiler.c2.irTests.scalarReplacement.ScalarReplacementWithGCBarrierTests
|
||||||
|
*/
|
||||||
|
public class ScalarReplacementWithGCBarrierTests {
|
||||||
|
static class List {
|
||||||
|
public Node head;
|
||||||
|
|
||||||
|
public void push(int value) {
|
||||||
|
Node n = new Node();
|
||||||
|
n.value = value;
|
||||||
|
n.next = head;
|
||||||
|
head = n;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ForceInline
|
||||||
|
public Iter iter() {
|
||||||
|
Iter iter = new Iter();
|
||||||
|
iter.list = this;
|
||||||
|
iter.n = head;
|
||||||
|
iter.sum = 0;
|
||||||
|
return iter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class Node {
|
||||||
|
public int value;
|
||||||
|
public Node next;
|
||||||
|
}
|
||||||
|
|
||||||
|
static class Iter {
|
||||||
|
public List list;
|
||||||
|
public Node n;
|
||||||
|
public Integer sum;
|
||||||
|
|
||||||
|
@ForceInline
|
||||||
|
public boolean next() {
|
||||||
|
int lastSum = sum;
|
||||||
|
while (sum - lastSum < 1000) {
|
||||||
|
while (n != null && n.value < 30) n = n.next;
|
||||||
|
if (n == null) return false;
|
||||||
|
sum += n.value;
|
||||||
|
n = n.next;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final int SIZE = 1000;
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
// Must use G1 GC to ensure there is a pre-barrier
|
||||||
|
// before the first field write.
|
||||||
|
TestFramework.runWithFlags("-XX:+UseG1GC");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Run(test = "testScalarReplacementWithGCBarrier")
|
||||||
|
private void runner() {
|
||||||
|
List list = new List();
|
||||||
|
for (int i = 0; i < SIZE; i++) {
|
||||||
|
list.push(i);
|
||||||
|
}
|
||||||
|
testScalarReplacementWithGCBarrier(list);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allocation of `Iter iter` should be eliminated by scalar replacement, and
|
||||||
|
// the allocation of `Integer sum` can not be eliminated, so there should be
|
||||||
|
// 1 allocation after allocations and locks elimination.
|
||||||
|
//
|
||||||
|
// Before the patch of JDK-8333334, both allocations of `Iter` and `Integer`
|
||||||
|
// could not be eliminated.
|
||||||
|
@Test
|
||||||
|
@IR(phase = { CompilePhase.AFTER_PARSING }, counts = { IRNode.ALLOC, "1" })
|
||||||
|
@IR(phase = { CompilePhase.INCREMENTAL_BOXING_INLINE }, counts = { IRNode.ALLOC, "2" })
|
||||||
|
@IR(phase = { CompilePhase.ITER_GVN_AFTER_ELIMINATION }, counts = { IRNode.ALLOC, "1" })
|
||||||
|
private int testScalarReplacementWithGCBarrier(List list) {
|
||||||
|
Iter iter = list.iter();
|
||||||
|
while (true) {
|
||||||
|
while (iter.next()) {}
|
||||||
|
if (list.head == null) break;
|
||||||
|
list.head = list.head.next;
|
||||||
|
iter.n = list.head;
|
||||||
|
}
|
||||||
|
return iter.sum;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2014, 2022, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2014, 2022, Oracle and/or its affiliates. All rights reserved.
|
||||||
|
* Copyright (c) 2024, Alibaba Group Holding Limited. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -35,6 +36,7 @@ import org.openjdk.jmh.annotations.State;
|
||||||
import org.openjdk.jmh.annotations.Threads;
|
import org.openjdk.jmh.annotations.Threads;
|
||||||
import org.openjdk.jmh.annotations.Warmup;
|
import org.openjdk.jmh.annotations.Warmup;
|
||||||
|
|
||||||
|
import java.util.Enumeration;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
@ -127,6 +129,21 @@ public class Maps {
|
||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Benchmark
|
||||||
|
public int testConcurrentHashMapIterators() {
|
||||||
|
ConcurrentHashMap<Integer, Integer> map = (ConcurrentHashMap<Integer, Integer>) staticMap;
|
||||||
|
int sum = 0;
|
||||||
|
Enumeration it = map.elements();
|
||||||
|
while (it.hasMoreElements()) {
|
||||||
|
sum += (int) it.nextElement();
|
||||||
|
}
|
||||||
|
it = map.keys();
|
||||||
|
while (it.hasMoreElements()) {
|
||||||
|
sum += (int) it.nextElement();
|
||||||
|
}
|
||||||
|
return sum;
|
||||||
|
}
|
||||||
|
|
||||||
private static class SimpleRandom {
|
private static class SimpleRandom {
|
||||||
private final static long multiplier = 0x5DEECE66DL;
|
private final static long multiplier = 0x5DEECE66DL;
|
||||||
private final static long addend = 0xBL;
|
private final static long addend = 0xBL;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue