Skip to content

Commit

Permalink
8279888: Local variable independently used by multiple loops can inte…
Browse files Browse the repository at this point in the history
…rfere with loop optimizations

Co-authored-by: Claes Redestad <redestad@openjdk.org>
Reviewed-by: thartmann, kvn
  • Loading branch information
rwestrel and cl4es committed Apr 25, 2022
1 parent 4c22a9b commit 32593df
Show file tree
Hide file tree
Showing 9 changed files with 955 additions and 300 deletions.
93 changes: 65 additions & 28 deletions src/hotspot/share/ci/ciTypeFlow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2288,21 +2288,48 @@ ciTypeFlow::Block* ciTypeFlow::clone_loop_head(Loop* lp, StateVector* temp_vecto
assert(!clone->has_pre_order(), "just created");
clone->set_next_pre_order();

// Insert clone after (orig) tail in reverse post order
clone->set_rpo_next(tail->rpo_next());
tail->set_rpo_next(clone);

// tail->head becomes tail->clone
for (SuccIter iter(tail); !iter.done(); iter.next()) {
if (iter.succ() == head) {
iter.set_succ(clone);
// Update predecessor information
head->predecessors()->remove(tail);
clone->predecessors()->append(tail);
// Accumulate profiled count for all backedges that share this loop's head
int total_count = lp->profiled_count();
for (Loop* lp1 = lp->parent(); lp1 != NULL; lp1 = lp1->parent()) {
for (Loop* lp2 = lp1; lp2 != NULL; lp2 = lp2->sibling()) {
if (lp2->head() == head && !lp2->tail()->is_backedge_copy()) {
total_count += lp2->profiled_count();
}
}
}
flow_block(tail, temp_vector, temp_set);
// Have the most frequent ones branch to the clone instead
int count = 0;
int nb = 0;
Block* latest_tail = tail;
bool done = false;
for (Loop* lp1 = lp; lp1 != NULL && !done; lp1 = lp1->parent()) {
for (Loop* lp2 = lp1; lp2 != NULL && !done; lp2 = lp2->sibling()) {
if (lp2->head() == head && !lp2->tail()->is_backedge_copy()) {
count += lp2->profiled_count();
if (lp2->tail()->post_order() < latest_tail->post_order()) {
latest_tail = lp2->tail();
}
nb++;
for (SuccIter iter(lp2->tail()); !iter.done(); iter.next()) {
if (iter.succ() == head) {
iter.set_succ(clone);
// Update predecessor information
head->predecessors()->remove(lp2->tail());
clone->predecessors()->append(lp2->tail());
}
}
flow_block(lp2->tail(), temp_vector, temp_set);
if (total_count == 0 || count > (total_count * .9)) {
done = true;
}
}
}
}
assert(nb >= 1, "at least one new");
clone->set_rpo_next(latest_tail->rpo_next());
latest_tail->set_rpo_next(clone);
if (head == tail) {
assert(nb == 1, "only when the head is not shared");
// For self-loops, clone->head becomes clone->clone
flow_block(clone, temp_vector, temp_set);
for (SuccIter iter(clone); !iter.done(); iter.next()) {
Expand Down Expand Up @@ -2454,23 +2481,29 @@ void ciTypeFlow::PreorderLoops::next() {
}

// If the tail is a branch to the head, retrieve how many times that path was taken from profiling
int ciTypeFlow::profiled_count(ciTypeFlow::Loop* loop) {
ciMethodData* methodData = method()->method_data();
int ciTypeFlow::Loop::profiled_count() {
if (_profiled_count >= 0) {
return _profiled_count;
}
ciMethodData* methodData = outer()->method()->method_data();
if (!methodData->is_mature()) {
_profiled_count = 0;
return 0;
}
ciTypeFlow::Block* tail = loop->tail();
ciTypeFlow::Block* tail = this->tail();
if (tail->control() == -1 || tail->has_trap()) {
_profiled_count = 0;
return 0;
}

ciProfileData* data = methodData->bci_to_data(tail->control());

if (data == NULL || !data->is_JumpData()) {
_profiled_count = 0;
return 0;
}

ciBytecodeStream iter(method());
ciBytecodeStream iter(outer()->method());
iter.reset_to_bci(tail->control());

bool is_an_if = false;
Expand Down Expand Up @@ -2509,21 +2542,25 @@ int ciTypeFlow::profiled_count(ciTypeFlow::Loop* loop) {
GrowableArray<ciTypeFlow::Block*>* succs = tail->successors();

if (!is_an_if) {
assert(((wide ? iter.get_far_dest() : iter.get_dest()) == loop->head()->start()) == (succs->at(ciTypeFlow::GOTO_TARGET) == loop->head()), "branch should lead to loop head");
if (succs->at(ciTypeFlow::GOTO_TARGET) == loop->head()) {
return method()->scale_count(data->as_JumpData()->taken());
assert(((wide ? iter.get_far_dest() : iter.get_dest()) == head()->start()) == (succs->at(ciTypeFlow::GOTO_TARGET) == head()), "branch should lead to loop head");
if (succs->at(ciTypeFlow::GOTO_TARGET) == head()) {
_profiled_count = outer()->method()->scale_count(data->as_JumpData()->taken());
return _profiled_count;
}
} else {
assert((iter.get_dest() == loop->head()->start()) == (succs->at(ciTypeFlow::IF_TAKEN) == loop->head()), "bytecode and CFG not consistent");
assert((tail->limit() == loop->head()->start()) == (succs->at(ciTypeFlow::IF_NOT_TAKEN) == loop->head()), "bytecode and CFG not consistent");
if (succs->at(ciTypeFlow::IF_TAKEN) == loop->head()) {
return method()->scale_count(data->as_JumpData()->taken());
} else if (succs->at(ciTypeFlow::IF_NOT_TAKEN) == loop->head()) {
return method()->scale_count(data->as_BranchData()->not_taken());
assert((iter.get_dest() == head()->start()) == (succs->at(ciTypeFlow::IF_TAKEN) == head()), "bytecode and CFG not consistent");
assert((tail->limit() == head()->start()) == (succs->at(ciTypeFlow::IF_NOT_TAKEN) == head()), "bytecode and CFG not consistent");
if (succs->at(ciTypeFlow::IF_TAKEN) == head()) {
_profiled_count = outer()->method()->scale_count(data->as_JumpData()->taken());
return _profiled_count;
} else if (succs->at(ciTypeFlow::IF_NOT_TAKEN) == head()) {
_profiled_count = outer()->method()->scale_count(data->as_BranchData()->not_taken());
return _profiled_count;
}
}

return 0;
_profiled_count = 0;
return _profiled_count;
}

bool ciTypeFlow::Loop::at_insertion_point(Loop* lp, Loop* current) {
Expand All @@ -2535,8 +2572,8 @@ bool ciTypeFlow::Loop::at_insertion_point(Loop* lp, Loop* current) {
}
// In the case of a shared head, make the most frequent head/tail (as reported by profiling) the inner loop
if (current->head() == lp->head()) {
int lp_count = outer()->profiled_count(lp);
int current_count = outer()->profiled_count(current);
int lp_count = lp->profiled_count();
int current_count = current->profiled_count();
if (current_count < lp_count) {
return true;
} else if (current_count > lp_count) {
Expand Down
7 changes: 4 additions & 3 deletions src/hotspot/share/ci/ciTypeFlow.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -716,6 +716,7 @@ class ciTypeFlow : public ResourceObj {
Block* _tail; // Tail of loop
bool _irreducible;
LocalSet _def_locals;
int _profiled_count;

ciTypeFlow* outer() const { return head()->outer(); }
bool at_insertion_point(Loop* lp, Loop* current);
Expand All @@ -724,7 +725,7 @@ class ciTypeFlow : public ResourceObj {
Loop(Block* head, Block* tail) :
_parent(NULL), _sibling(NULL), _child(NULL),
_head(head), _tail(tail),
_irreducible(false), _def_locals() {}
_irreducible(false), _def_locals(), _profiled_count(-1) {}

Loop* parent() const { return _parent; }
Loop* sibling() const { return _sibling; }
Expand Down Expand Up @@ -760,6 +761,8 @@ class ciTypeFlow : public ResourceObj {

bool is_root() const { return _tail->pre_order() == max_jint; }

int profiled_count();

void print(outputStream* st = tty, int indent = 0) const PRODUCT_RETURN;
};

Expand Down Expand Up @@ -916,8 +919,6 @@ class ciTypeFlow : public ResourceObj {
// Create the block map, which indexes blocks in pre_order.
void map_blocks();

int profiled_count(ciTypeFlow::Loop* loop);

public:
// Perform type inference flow analysis.
void do_flow();
Expand Down
8 changes: 8 additions & 0 deletions src/hotspot/share/opto/c2_globals.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -766,6 +766,14 @@
"for at most jint_max / StressLongCountedLoop") \
range(0, max_juint) \
\
product(bool, DuplicateBackedge, true, DIAGNOSTIC, \
"Transform loop with a merge point into 2 loops if inner loop is" \
"expected to optimize better") \
\
develop(bool, StressDuplicateBackedge, false, \
"Run DuplicateBackedge whenever possible ignoring benefit" \
"analysis") \
\
product(bool, VerifyReceiverTypes, trueInDebug, DIAGNOSTIC, \
"Verify receiver types at runtime") \

Expand Down
Loading

1 comment on commit 32593df

@openjdk-notifier
Copy link

Choose a reason for hiding this comment

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

Please sign in to comment.