Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
116 changes: 76 additions & 40 deletions src/hotspot/share/opto/memnode.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/*
* 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.
*
* This code is free software; you can redistribute it and/or modify it
Expand Down Expand Up @@ -427,23 +428,31 @@ Node *MemNode::Ideal_common(PhaseGVN *phase, bool can_reshape) {
// Used by MemNode::find_previous_store to prove that the
// control input of a memory operation predates (dominates)
// an allocation it wants to look past.
bool MemNode::all_controls_dominate(Node* dom, Node* sub) {
if (dom == nullptr || dom->is_top() || sub == nullptr || sub->is_top())
return false; // Conservative answer for dead code
// Returns 'DomResult::Dominate' if all control inputs of 'dom'
// dominate 'sub', 'DomResult::NotDominate' if not,
// 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.
dom = dom->find_exact_control(dom);
if (dom == nullptr || dom->is_top())
return false; // Conservative answer for dead code
if (dom == nullptr || dom->is_top()) {
return DomResult::EncounteredDeadCode; // Conservative answer for dead code
}

if (dom == sub) {
// For the case when, for example, 'sub' is Initialize and the original
// 'dom' is Proj node of the 'sub'.
return false;
return DomResult::NotDominate;
}

if (dom->is_Con() || dom->is_Start() || dom->is_Root() || dom == sub)
return true;
if (dom->is_Con() || dom->is_Start() || dom->is_Root() || dom == sub) {
return DomResult::Dominate;
}

// 'dom' dominates 'sub' if its control edge and control edges
// of all its inputs dominate or equal to sub's control edge.
Expand All @@ -457,16 +466,19 @@ bool MemNode::all_controls_dominate(Node* dom, Node* sub) {
// Get control edge of 'sub'.
Node* orig_sub = sub;
sub = sub->find_exact_control(sub->in(0));
if (sub == nullptr || sub->is_top())
return false; // Conservative answer for dead code
if (sub == nullptr || sub->is_top()) {
return DomResult::EncounteredDeadCode; // Conservative answer for dead code
}

assert(sub->is_CFG(), "expecting control");

if (sub == dom)
return true;
if (sub == dom) {
return DomResult::Dominate;
}

if (sub->is_Start() || sub->is_Root())
return false;
if (sub->is_Start() || sub->is_Root()) {
return DomResult::NotDominate;
}

{
// Check all control edges of 'dom'.
Expand All @@ -480,41 +492,47 @@ bool MemNode::all_controls_dominate(Node* dom, Node* sub) {

for (uint next = 0; next < dom_list.size(); next++) {
Node* n = dom_list.at(next);
if (n == orig_sub)
return false; // One of dom's inputs dominated by sub.
if (n == orig_sub) {
return DomResult::NotDominate; // One of dom's inputs dominated by sub.
}
if (!n->is_CFG() && n->pinned()) {
// Check only own control edge for pinned non-control nodes.
n = n->find_exact_control(n->in(0));
if (n == nullptr || n->is_top())
return false; // Conservative answer for dead code
if (n == nullptr || n->is_top()) {
return DomResult::EncounteredDeadCode; // Conservative answer for dead code
}
assert(n->is_CFG(), "expecting control");
dom_list.push(n);
} else if (n->is_Con() || n->is_Start() || n->is_Root()) {
only_dominating_controls = true;
} 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;
else
return false;
} else {
return dom_result;
}
} else {
// First, own control edge.
Node* m = n->find_exact_control(n->in(0));
if (m != nullptr) {
if (m->is_top())
return false; // Conservative answer for dead code
if (m->is_top()) {
return DomResult::EncounteredDeadCode; // Conservative answer for dead code
}
dom_list.push(m);
}
// Now, the rest of edges.
uint cnt = n->req();
for (uint i = 1; i < cnt; i++) {
m = n->find_exact_control(n->in(i));
if (m == nullptr || m->is_top())
if (m == nullptr || m->is_top()) {
continue;
}
dom_list.push(m);
}
}
}
return only_dominating_controls;
return only_dominating_controls ? DomResult::Dominate : DomResult::NotDominate;
}
}

Expand Down Expand Up @@ -726,16 +744,18 @@ Node* MemNode::find_previous_store(PhaseValues* phase) {
} else if (mem->is_Proj() && mem->in(0)->is_Initialize()) {
InitializeNode* st_init = mem->in(0)->as_Initialize();
AllocateNode* st_alloc = st_init->allocation();
if (st_alloc == nullptr)
if (st_alloc == nullptr) {
break; // something degenerated
}
bool known_identical = false;
bool known_independent = false;
if (alloc == st_alloc)
if (alloc == st_alloc) {
known_identical = true;
else if (alloc != nullptr)
} else if (alloc != nullptr) {
known_independent = true;
else if (all_controls_dominate(this, st_alloc))
} else if (all_controls_dominate(this, st_alloc)) {
known_independent = true;
}

if (known_independent) {
// The bases are provably independent: Either they are
Expand Down Expand Up @@ -1566,8 +1586,9 @@ bool LoadNode::can_split_through_phi_base(PhaseGVN* phase) {
}

if (!mem->is_Phi()) {
if (!MemNode::all_controls_dominate(mem, base->in(0)))
if (!MemNode::all_controls_dominate(mem, base->in(0))) {
return false;
}
} else if (base->in(0) != mem->in(0)) {
if (!MemNode::all_controls_dominate(mem, base->in(0))) {
return false;
Expand Down Expand Up @@ -1658,35 +1679,49 @@ Node* LoadNode::split_through_phi(PhaseGVN* phase, bool ignore_missing_instance_

// Select Region to split through.
Node* region;
DomResult dom_result = DomResult::Dominate;
if (!base_is_phi) {
assert(mem->is_Phi(), "sanity");
region = mem->in(0);
// Skip if the region dominates some control edge of the address.
if (!MemNode::all_controls_dominate(address, region))
return nullptr;
// We will check `dom_result` later.
dom_result = MemNode::maybe_all_controls_dominate(address, region);
} else if (!mem->is_Phi()) {
assert(base_is_phi, "sanity");
region = base->in(0);
// Skip if the region dominates some control edge of the memory.
if (!MemNode::all_controls_dominate(mem, region))
return nullptr;
// We will check `dom_result` later.
dom_result = MemNode::maybe_all_controls_dominate(mem, region);
} else if (base->in(0) != mem->in(0)) {
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);
} else if (MemNode::all_controls_dominate(address, mem->in(0))) {
region = mem->in(0);
} 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 {
assert(base->in(0) == mem->in(0), "sanity");
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;
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)) {
int this_index = C->get_alias_index(t_oop);
int this_offset = t_oop->offset();
Expand Down Expand Up @@ -4566,8 +4601,9 @@ bool InitializeNode::detect_init_independence(Node* value, PhaseGVN* phase) {
// must have preceded the init, or else be equal to the init.
// Even after loop optimizations (which might change control edges)
// 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
}
}

// Check data edges for possible dependencies on 'this'.
Expand Down
9 changes: 7 additions & 2 deletions src/hotspot/share/opto/memnode.hpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/*
* 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.
*
* This code is free software; you can redistribute it and/or modify it
Expand Down Expand Up @@ -105,8 +106,12 @@ class MemNode : public Node {

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);
// This one should probably be a phase-specific function:
static bool all_controls_dominate(Node* dom, Node* sub);
// The following two should probably be phase-specific functions:
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

Expand Down
17 changes: 10 additions & 7 deletions src/hotspot/share/opto/node.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/*
* 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.
*
* This code is free software; you can redistribute it and/or modify it
Expand Down Expand Up @@ -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',
// then all paths so, so this is a simple search for one example,
// 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(sub != nullptr && sub->is_CFG(), "expecting control");

Expand All @@ -1269,12 +1270,15 @@ bool Node::dominates(Node* sub, Node_List &nlist) {
// will either exit through the loop head, or give up.
// (If we get confused, break out and return a conservative 'false'.)
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 (nlist.size() == 0) {
// No Region nodes except loops were visited before and the EntryControl
// path was taken for loops: it did not walk in a cycle.
return true;
return DomResult::Dominate;
} else if (met_dom) {
break; // already met before: walk in a cycle
} else {
Expand All @@ -1288,7 +1292,7 @@ bool Node::dominates(Node* sub, Node_List &nlist) {
// Success if we met 'dom' along a path to Start or Root.
// We assume there are no alternative paths that avoid 'dom'.
// (This assumption is up to the caller to ensure!)
return met_dom;
return met_dom ? DomResult::Dominate : DomResult::NotDominate;
}
Node* up = sub->in(0);
// Normalize simple pass-through regions and projections:
Expand Down Expand Up @@ -1319,7 +1323,7 @@ bool Node::dominates(Node* sub, Node_List &nlist) {
if (visited == sub) {
if (visited_twice_already) {
// Visited 2 paths, but still stuck in loop body. Give up.
return false;
return DomResult::NotDominate;
}
// The Region node was visited before only once.
// (We will repush with the low bit set, below.)
Expand Down Expand Up @@ -1362,8 +1366,7 @@ bool Node::dominates(Node* sub, Node_List &nlist) {
}

// Did not meet Root or Start node in pred. chain.
// Conservative answer for dead code.
return false;
return DomResult::NotDominate;
}

//------------------------------remove_dead_region-----------------------------
Expand Down
9 changes: 8 additions & 1 deletion src/hotspot/share/opto/node.hpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/*
* 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.
*
* This code is free software; you can redistribute it and/or modify it
Expand Down Expand Up @@ -1105,8 +1106,14 @@ class Node {
// Skip Proj and CatchProj nodes chains. Check for Null and Top.
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'.
bool dominates(Node* sub, Node_List &nlist);
DomResult dominates(Node* sub, Node_List &nlist);

protected:
bool remove_dead_region(PhaseGVN *phase, bool can_reshape);
Expand Down
Loading