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
49 changes: 47 additions & 2 deletions src/hotspot/share/opto/loopnode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -632,7 +632,7 @@ static bool no_side_effect_since_safepoint(Compile* C, Node* x, Node* mem, Merge
SafePointNode* safepoint = nullptr;
for (DUIterator_Fast imax, i = x->fast_outs(imax); i < imax; i++) {
Node* u = x->fast_out(i);
if (u->is_Phi() && u->bottom_type() == Type::MEMORY) {
if (u->is_memory_phi()) {
Node* m = u->in(LoopNode::LoopBackControl);
if (u->adr_type() == TypePtr::BOTTOM) {
if (m->is_MergeMem() && mem->is_MergeMem()) {
Expand Down Expand Up @@ -2655,7 +2655,7 @@ void OuterStripMinedLoopNode::fix_sunk_stores(CountedLoopEndNode* inner_cle, Loo
#ifdef ASSERT
for (DUIterator_Fast jmax, j = inner_cl->fast_outs(jmax); j < jmax; j++) {
Node* uu = inner_cl->fast_out(j);
if (uu->is_Phi() && uu->bottom_type() == Type::MEMORY) {
if (uu->is_memory_phi()) {
if (uu->adr_type() == igvn->C->get_adr_type(igvn->C->get_alias_index(u->adr_type()))) {
assert(phi == uu, "what's that phi?");
} else if (uu->adr_type() == TypePtr::BOTTOM) {
Expand Down Expand Up @@ -5701,6 +5701,51 @@ Node* CountedLoopNode::is_canonical_loop_entry() {
return res ? cmpzm->in(input) : nullptr;
}

// Find pre loop end from main loop. Returns nullptr if none.
CountedLoopEndNode* CountedLoopNode::find_pre_loop_end() {
assert(is_main_loop(), "Can only find pre-loop from main-loop");
// The loop cannot be optimized if the graph shape at the loop entry is
// inappropriate.
if (is_canonical_loop_entry() == nullptr) {
return nullptr;
}

Node* p_f = skip_assertion_predicates_with_halt()->in(0)->in(0);
if (!p_f->is_IfFalse() || !p_f->in(0)->is_CountedLoopEnd()) {
return nullptr;
}
CountedLoopEndNode* pre_end = p_f->in(0)->as_CountedLoopEnd();
CountedLoopNode* loop_node = pre_end->loopnode();
if (loop_node == nullptr || !loop_node->is_pre_loop()) {
return nullptr;
}
return pre_end;
}

CountedLoopNode* CountedLoopNode::pre_loop_head() const {
assert(is_main_loop(), "Only main loop has pre loop");
assert(_pre_loop_end != nullptr && _pre_loop_end->loopnode() != nullptr,
"should find head from pre loop end");
return _pre_loop_end->loopnode();
}

CountedLoopEndNode* CountedLoopNode::pre_loop_end() {
#ifdef ASSERT
assert(is_main_loop(), "Only main loop has pre loop");
assert(_pre_loop_end != nullptr, "should be set when fetched");
Node* found_pre_end = find_pre_loop_end();
assert(_pre_loop_end == found_pre_end && _pre_loop_end == pre_loop_head()->loopexit(),
"should find the pre loop end and must be the same result");
#endif
return _pre_loop_end;
}

void CountedLoopNode::set_pre_loop_end(CountedLoopEndNode* pre_loop_end) {
assert(is_main_loop(), "Only main loop has pre loop");
assert(pre_loop_end, "must be valid");
_pre_loop_end = pre_loop_end;
}

//------------------------------get_late_ctrl----------------------------------
// Compute latest legal control.
Node *PhaseIdealLoop::get_late_ctrl( Node *n, Node *early ) {
Expand Down
10 changes: 7 additions & 3 deletions src/hotspot/share/opto/loopnode.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -232,14 +232,14 @@ class CountedLoopNode : public BaseCountedLoopNode {
// vector mapped unroll factor here
int _slp_maximum_unroll_factor;

// The eventual count of vectorizable packs in slp
int _slp_vector_pack_count;
// Cached CountedLoopEndNode of pre loop for main loops
CountedLoopEndNode* _pre_loop_end;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it safe to cached this node? What happens if the node were ever to be replaced?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, we need to access it via pre_loop_end() which has asserts that check the consistency. Ok.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We just have to make sure that this field is never accessed directly. What happens if people start using it elsewhere?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The field is already private. What else do you think we can do to further protect it?


public:
CountedLoopNode(Node *entry, Node *backedge)
: BaseCountedLoopNode(entry, backedge), _main_idx(0), _trip_count(max_juint),
_unrolled_count_log2(0), _node_count_before_unroll(0),
_slp_maximum_unroll_factor(0), _slp_vector_pack_count(0) {
_slp_maximum_unroll_factor(0), _pre_loop_end(nullptr) {
init_class_id(Class_CountedLoop);
// Initialize _trip_count to the largest possible value.
// Will be reset (lower) if the loop's trip count is known.
Expand Down Expand Up @@ -330,6 +330,10 @@ class CountedLoopNode : public BaseCountedLoopNode {
}

Node* is_canonical_loop_entry();
CountedLoopEndNode* find_pre_loop_end();
CountedLoopNode* pre_loop_head() const;
CountedLoopEndNode* pre_loop_end();
void set_pre_loop_end(CountedLoopEndNode* pre_loop_end);

#ifndef PRODUCT
virtual void dump_spec(outputStream *st) const;
Expand Down
3 changes: 3 additions & 0 deletions src/hotspot/share/opto/node.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -1219,6 +1219,9 @@ class Node {
// Whether this is a memory-writing machine node.
bool is_memory_writer() const { return is_Mach() && bottom_type()->has_memory(); }

// Whether this is a memory phi node
bool is_memory_phi() const { return is_Phi() && bottom_type() == Type::MEMORY; }

//----------------- Printing, etc
#ifndef PRODUCT
public:
Expand Down
Loading