8327109: Refactor data graph cloning used in create_new_if_for_predicate() into separate class
Reviewed-by: epeter, thartmann
This commit is contained in:
parent
a4a5196351
commit
7d8561d56b
@ -215,14 +215,16 @@ IfProjNode* PhaseIdealLoop::create_new_if_for_predicate(ParsePredicateSuccessPro
|
|||||||
|
|
||||||
// Update ctrl and control inputs of all data nodes starting from 'node' to 'new_ctrl' which have 'old_ctrl' as
|
// Update ctrl and control inputs of all data nodes starting from 'node' to 'new_ctrl' which have 'old_ctrl' as
|
||||||
// current ctrl.
|
// current ctrl.
|
||||||
void PhaseIdealLoop::set_ctrl_of_nodes_with_same_ctrl(Node* node, ProjNode* old_ctrl, Node* new_ctrl) {
|
void PhaseIdealLoop::set_ctrl_of_nodes_with_same_ctrl(Node* start_node, ProjNode* old_uncommon_proj,
|
||||||
Unique_Node_List nodes_with_same_ctrl = find_nodes_with_same_ctrl(node, old_ctrl);
|
Node* new_uncommon_proj) {
|
||||||
for (uint j = 0; j < nodes_with_same_ctrl.size(); j++) {
|
ResourceMark rm;
|
||||||
Node* next = nodes_with_same_ctrl[j];
|
const Unique_Node_List nodes_with_same_ctrl = find_nodes_with_same_ctrl(start_node, old_uncommon_proj);
|
||||||
if (next->in(0) == old_ctrl) {
|
for (uint i = 0; i < nodes_with_same_ctrl.size(); i++) {
|
||||||
_igvn.replace_input_of(next, 0, new_ctrl);
|
Node* node = nodes_with_same_ctrl[i];
|
||||||
|
if (node->in(0) == old_uncommon_proj) {
|
||||||
|
_igvn.replace_input_of(node, 0, new_uncommon_proj);
|
||||||
}
|
}
|
||||||
set_ctrl(next, new_ctrl);
|
set_ctrl(node, new_uncommon_proj);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -242,61 +244,31 @@ Unique_Node_List PhaseIdealLoop::find_nodes_with_same_ctrl(Node* node, const Pro
|
|||||||
return nodes_with_same_ctrl;
|
return nodes_with_same_ctrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clone all nodes with the same ctrl as 'old_ctrl' starting from 'node' by following its inputs. Rewire the cloned nodes
|
// Clone all data nodes with a ctrl to the old uncommon projection from `start_node' by following its inputs. Rewire the
|
||||||
// to 'new_ctrl'. Returns the clone of 'node'.
|
// cloned nodes to the new uncommon projection. Returns the clone of the `start_node`.
|
||||||
Node* PhaseIdealLoop::clone_nodes_with_same_ctrl(Node* node, ProjNode* old_ctrl, Node* new_ctrl) {
|
Node* PhaseIdealLoop::clone_nodes_with_same_ctrl(Node* start_node, ProjNode* old_uncommon_proj, Node* new_uncommon_proj) {
|
||||||
|
ResourceMark rm;
|
||||||
DEBUG_ONLY(uint last_idx = C->unique();)
|
DEBUG_ONLY(uint last_idx = C->unique();)
|
||||||
Unique_Node_List nodes_with_same_ctrl = find_nodes_with_same_ctrl(node, old_ctrl);
|
const Unique_Node_List nodes_with_same_ctrl = find_nodes_with_same_ctrl(start_node, old_uncommon_proj);
|
||||||
Dict old_new_mapping = clone_nodes(nodes_with_same_ctrl); // Cloned but not rewired, yet
|
DataNodeGraph data_node_graph(nodes_with_same_ctrl, this);
|
||||||
rewire_cloned_nodes_to_ctrl(old_ctrl, new_ctrl, nodes_with_same_ctrl, old_new_mapping);
|
const OrigToNewHashtable& orig_to_clone = data_node_graph.clone(new_uncommon_proj);
|
||||||
Node* clone_phi_input = static_cast<Node*>(old_new_mapping[node]);
|
fix_cloned_data_node_controls(old_uncommon_proj, new_uncommon_proj, orig_to_clone);
|
||||||
assert(clone_phi_input != nullptr && clone_phi_input->_idx >= last_idx, "must exist and be a proper clone");
|
Node** cloned_node_ptr = orig_to_clone.get(start_node);
|
||||||
return clone_phi_input;
|
assert(cloned_node_ptr != nullptr && (*cloned_node_ptr)->_idx >= last_idx, "must exist and be a proper clone");
|
||||||
|
return *cloned_node_ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clone all the nodes on 'list_to_clone' and return an old->new mapping.
|
// All data nodes with a control input to the uncommon projection in the chain need to be rewired to the new uncommon
|
||||||
Dict PhaseIdealLoop::clone_nodes(const Node_List& list_to_clone) {
|
// projection (could not only be the last data node in the chain but also, for example, a pinned DivNode within the chain).
|
||||||
Dict old_new_mapping(cmpkey, hashkey);
|
void PhaseIdealLoop::fix_cloned_data_node_controls(const ProjNode* old_uncommon_proj, Node* new_uncommon_proj,
|
||||||
for (uint i = 0; i < list_to_clone.size(); i++) {
|
const OrigToNewHashtable& orig_to_clone) {
|
||||||
Node* next = list_to_clone[i];
|
auto orig_clone_action = [&](Node* orig, Node* clone) {
|
||||||
Node* clone = next->clone();
|
if (orig->in(0) == old_uncommon_proj) {
|
||||||
_igvn.register_new_node_with_optimizer(clone);
|
_igvn.replace_input_of(clone, 0, new_uncommon_proj);
|
||||||
old_new_mapping.Insert(next, clone);
|
set_ctrl(clone, new_uncommon_proj);
|
||||||
}
|
|
||||||
return old_new_mapping;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Rewire inputs of the unprocessed cloned nodes (inputs are not updated, yet, and still point to the old nodes) by
|
|
||||||
// using the old_new_mapping.
|
|
||||||
void PhaseIdealLoop::rewire_cloned_nodes_to_ctrl(const ProjNode* old_ctrl, Node* new_ctrl,
|
|
||||||
const Node_List& nodes_with_same_ctrl, const Dict& old_new_mapping) {
|
|
||||||
for (uint i = 0; i < nodes_with_same_ctrl.size(); i++) {
|
|
||||||
Node* next = nodes_with_same_ctrl[i];
|
|
||||||
Node* clone = static_cast<Node*>(old_new_mapping[next]);
|
|
||||||
if (next->in(0) == old_ctrl) {
|
|
||||||
// All data nodes with a control input to the uncommon projection in the chain need to be rewired to the new uncommon
|
|
||||||
// projection (could not only be the last data node in the chain but also, for example, a DivNode within the chain).
|
|
||||||
_igvn.replace_input_of(clone, 0, new_ctrl);
|
|
||||||
set_ctrl(clone, new_ctrl);
|
|
||||||
}
|
}
|
||||||
rewire_inputs_of_clones_to_clones(new_ctrl, clone, old_new_mapping, next);
|
};
|
||||||
}
|
orig_to_clone.iterate_all(orig_clone_action);
|
||||||
}
|
|
||||||
|
|
||||||
// Rewire the inputs of the cloned nodes to the old nodes to the new clones.
|
|
||||||
void PhaseIdealLoop::rewire_inputs_of_clones_to_clones(Node* new_ctrl, Node* clone, const Dict& old_new_mapping,
|
|
||||||
const Node* next) {
|
|
||||||
for (uint i = 1; i < next->req(); i++) {
|
|
||||||
Node* in = next->in(i);
|
|
||||||
if (!in->is_Phi()) {
|
|
||||||
assert(!in->is_CFG(), "must be data node");
|
|
||||||
Node* in_clone = static_cast<Node*>(old_new_mapping[in]);
|
|
||||||
if (in_clone != nullptr) {
|
|
||||||
_igvn.replace_input_of(clone, i, in_clone);
|
|
||||||
set_ctrl(clone, new_ctrl);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
IfProjNode* PhaseIdealLoop::clone_parse_predicate_to_unswitched_loop(ParsePredicateSuccessProj* parse_predicate_proj,
|
IfProjNode* PhaseIdealLoop::clone_parse_predicate_to_unswitched_loop(ParsePredicateSuccessProj* parse_predicate_proj,
|
||||||
|
@ -1343,13 +1343,11 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
// Helper functions for create_new_if_for_predicate()
|
// Helper functions for create_new_if_for_predicate()
|
||||||
void set_ctrl_of_nodes_with_same_ctrl(Node* node, ProjNode* old_ctrl, Node* new_ctrl);
|
void set_ctrl_of_nodes_with_same_ctrl(Node* start_node, ProjNode* old_uncommon_proj, Node* new_uncommon_proj);
|
||||||
Unique_Node_List find_nodes_with_same_ctrl(Node* node, const ProjNode* ctrl);
|
Unique_Node_List find_nodes_with_same_ctrl(Node* node, const ProjNode* ctrl);
|
||||||
Node* clone_nodes_with_same_ctrl(Node* node, ProjNode* old_ctrl, Node* new_ctrl);
|
Node* clone_nodes_with_same_ctrl(Node* start_node, ProjNode* old_uncommon_proj, Node* new_uncommon_proj);
|
||||||
Dict clone_nodes(const Node_List& list_to_clone);
|
void fix_cloned_data_node_controls(const ProjNode* orig, Node* new_uncommon_proj,
|
||||||
void rewire_cloned_nodes_to_ctrl(const ProjNode* old_ctrl, Node* new_ctrl, const Node_List& nodes_with_same_ctrl,
|
const OrigToNewHashtable& orig_to_clone);
|
||||||
const Dict& old_new_mapping);
|
|
||||||
void rewire_inputs_of_clones_to_clones(Node* new_ctrl, Node* clone, const Dict& old_new_mapping, const Node* next);
|
|
||||||
bool has_dominating_loop_limit_check(Node* init_trip, Node* limit, jlong stride_con, BasicType iv_bt,
|
bool has_dominating_loop_limit_check(Node* init_trip, Node* limit, jlong stride_con, BasicType iv_bt,
|
||||||
Node* loop_entry);
|
Node* loop_entry);
|
||||||
|
|
||||||
@ -1882,4 +1880,42 @@ public:
|
|||||||
float to(Node* n);
|
float to(Node* n);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Class to clone a data node graph by taking a list of data nodes. This is done in 2 steps:
|
||||||
|
// 1. Clone the data nodes
|
||||||
|
// 2. Fix the cloned data inputs pointing to the old nodes to the cloned inputs by using an old->new mapping.
|
||||||
|
class DataNodeGraph : public StackObj {
|
||||||
|
PhaseIdealLoop* const _phase;
|
||||||
|
const Unique_Node_List& _data_nodes;
|
||||||
|
OrigToNewHashtable _orig_to_new;
|
||||||
|
|
||||||
|
public:
|
||||||
|
DataNodeGraph(const Unique_Node_List& data_nodes, PhaseIdealLoop* phase)
|
||||||
|
: _phase(phase),
|
||||||
|
_data_nodes(data_nodes),
|
||||||
|
// Use 107 as best guess which is the first resize value in ResizeableResourceHashtable::large_table_sizes.
|
||||||
|
_orig_to_new(107, MaxNodeLimit)
|
||||||
|
{
|
||||||
|
#ifdef ASSERT
|
||||||
|
for (uint i = 0; i < data_nodes.size(); i++) {
|
||||||
|
assert(!data_nodes[i]->is_CFG(), "only data nodes");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
NONCOPYABLE(DataNodeGraph);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void clone(Node* node, Node* new_ctrl);
|
||||||
|
void clone_data_nodes(Node* new_ctrl);
|
||||||
|
void rewire_clones_to_cloned_inputs();
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Clone the provided data node collection and rewire the clones in such a way to create an identical graph copy.
|
||||||
|
// Set 'new_ctrl' as ctrl for the cloned nodes.
|
||||||
|
const OrigToNewHashtable& clone(Node* new_ctrl) {
|
||||||
|
assert(_orig_to_new.number_of_entries() == 0, "should not call this method twice in a row");
|
||||||
|
clone_data_nodes(new_ctrl);
|
||||||
|
rewire_clones_to_cloned_inputs();
|
||||||
|
return _orig_to_new;
|
||||||
|
}
|
||||||
|
};
|
||||||
#endif // SHARE_OPTO_LOOPNODE_HPP
|
#endif // SHARE_OPTO_LOOPNODE_HPP
|
||||||
|
@ -4495,3 +4495,31 @@ void PhaseIdealLoop::move_unordered_reduction_out_of_loop(IdealLoopTree* loop) {
|
|||||||
assert(phi->outcnt() == 1, "accumulator is the only use of phi");
|
assert(phi->outcnt() == 1, "accumulator is the only use of phi");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DataNodeGraph::clone_data_nodes(Node* new_ctrl) {
|
||||||
|
for (uint i = 0; i < _data_nodes.size(); i++) {
|
||||||
|
clone(_data_nodes[i], new_ctrl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clone the given node and set it up properly. Set `new_ctrl` as ctrl.
|
||||||
|
void DataNodeGraph::clone(Node* node, Node* new_ctrl) {
|
||||||
|
Node* clone = node->clone();
|
||||||
|
_phase->igvn().register_new_node_with_optimizer(clone);
|
||||||
|
_orig_to_new.put(node, clone);
|
||||||
|
_phase->set_ctrl(clone, new_ctrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rewire the data inputs of all (unprocessed) cloned nodes, whose inputs are still pointing to the same inputs as their
|
||||||
|
// corresponding orig nodes, to the newly cloned inputs to create a separate cloned graph.
|
||||||
|
void DataNodeGraph::rewire_clones_to_cloned_inputs() {
|
||||||
|
_orig_to_new.iterate_all([&](Node* node, Node* clone) {
|
||||||
|
for (uint i = 1; i < node->req(); i++) {
|
||||||
|
Node** cloned_input = _orig_to_new.get(node->in(i));
|
||||||
|
if (cloned_input != nullptr) {
|
||||||
|
// Input was also cloned -> rewire clone to the cloned input.
|
||||||
|
_phase->igvn().replace_input_of(clone, i, *cloned_input);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
@ -207,6 +207,8 @@ typedef Node** DUIterator_Fast;
|
|||||||
typedef Node** DUIterator_Last;
|
typedef Node** DUIterator_Last;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
typedef ResizeableResourceHashtable<Node*, Node*, AnyObj::RESOURCE_AREA, mtCompiler> OrigToNewHashtable;
|
||||||
|
|
||||||
// Node Sentinel
|
// Node Sentinel
|
||||||
#define NodeSentinel (Node*)-1
|
#define NodeSentinel (Node*)-1
|
||||||
|
|
||||||
|
@ -208,7 +208,7 @@ void ReplacedNodes::apply(Compile* C, Node* ctl) {
|
|||||||
hash_table_size++;
|
hash_table_size++;
|
||||||
}
|
}
|
||||||
// Map from current node to cloned/replaced node
|
// Map from current node to cloned/replaced node
|
||||||
ResizeableResourceHashtable<Node*, Node*, AnyObj::RESOURCE_AREA, mtCompiler> clones(hash_table_size, hash_table_size);
|
OrigToNewHashtable clones(hash_table_size, hash_table_size);
|
||||||
// Record mapping from initial to improved nodes
|
// Record mapping from initial to improved nodes
|
||||||
for (int i = 0; i < _replaced_nodes->length(); i++) {
|
for (int i = 0; i < _replaced_nodes->length(); i++) {
|
||||||
ReplacedNode replaced = _replaced_nodes->at(i);
|
ReplacedNode replaced = _replaced_nodes->at(i);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user