8277382: make c1 BlockMerger use IR::verify only when necessary

Reviewed-by: thartmann, neliasso
This commit is contained in:
Ludvig Janiuk 2021-11-29 06:41:55 +00:00 committed by Tobias Hartmann
parent 8f9eb620ac
commit c3a7f2f4bc

View File

@ -336,140 +336,135 @@ class BlockMerger: public BlockClosure {
bool try_merge(BlockBegin* block) {
BlockEnd* end = block->end();
if (end->as_Goto() != NULL) {
assert(end->number_of_sux() == 1, "end must have exactly one successor");
// Note: It would be sufficient to check for the number of successors (= 1)
// in order to decide if this block can be merged potentially. That
// would then also include switch statements w/ only a default case.
// However, in that case we would need to make sure the switch tag
// expression is executed if it can produce observable side effects.
// We should probably have the canonicalizer simplifying such switch
// statements and then we are sure we don't miss these merge opportunities
// here (was bug - gri 7/7/99).
BlockBegin* sux = end->default_sux();
if (sux->number_of_preds() == 1 && !sux->is_entry_block() && !end->is_safepoint()) {
// merge the two blocks
if (end->as_Goto() == NULL) return false;
assert(end->number_of_sux() == 1, "end must have exactly one successor");
// Note: It would be sufficient to check for the number of successors (= 1)
// in order to decide if this block can be merged potentially. That
// would then also include switch statements w/ only a default case.
// However, in that case we would need to make sure the switch tag
// expression is executed if it can produce observable side effects.
// We should probably have the canonicalizer simplifying such switch
// statements and then we are sure we don't miss these merge opportunities
// here (was bug - gri 7/7/99).
BlockBegin* sux = end->default_sux();
if (sux->number_of_preds() != 1 || sux->is_entry_block() || end->is_safepoint()) return false;
// merge the two blocks
#ifdef ASSERT
// verify that state at the end of block and at the beginning of sux are equal
// no phi functions must be present at beginning of sux
ValueStack* sux_state = sux->state();
ValueStack* end_state = end->state();
// verify that state at the end of block and at the beginning of sux are equal
// no phi functions must be present at beginning of sux
ValueStack* sux_state = sux->state();
ValueStack* end_state = end->state();
assert(end_state->scope() == sux_state->scope(), "scopes must match");
assert(end_state->stack_size() == sux_state->stack_size(), "stack not equal");
assert(end_state->locals_size() == sux_state->locals_size(), "locals not equal");
assert(end_state->scope() == sux_state->scope(), "scopes must match");
assert(end_state->stack_size() == sux_state->stack_size(), "stack not equal");
assert(end_state->locals_size() == sux_state->locals_size(), "locals not equal");
int index;
Value sux_value;
for_each_stack_value(sux_state, index, sux_value) {
assert(sux_value == end_state->stack_at(index), "stack not equal");
}
for_each_local_value(sux_state, index, sux_value) {
Phi* sux_phi = sux_value->as_Phi();
if (sux_phi != NULL && sux_phi->is_illegal()) continue;
assert(sux_value == end_state->local_at(index), "locals not equal");
}
assert(sux_state->caller_state() == end_state->caller_state(), "caller not equal");
int index;
Value sux_value;
for_each_stack_value(sux_state, index, sux_value) {
assert(sux_value == end_state->stack_at(index), "stack not equal");
}
for_each_local_value(sux_state, index, sux_value) {
Phi* sux_phi = sux_value->as_Phi();
if (sux_phi != NULL && sux_phi->is_illegal()) continue;
assert(sux_value == end_state->local_at(index), "locals not equal");
}
assert(sux_state->caller_state() == end_state->caller_state(), "caller not equal");
#endif
// find instruction before end & append first instruction of sux block
Instruction* prev = end->prev();
Instruction* next = sux->next();
assert(prev->as_BlockEnd() == NULL, "must not be a BlockEnd");
prev->set_next(next);
prev->fixup_block_pointers();
sux->disconnect_from_graph();
block->set_end(sux->end());
// add exception handlers of deleted block, if any
for (int k = 0; k < sux->number_of_exception_handlers(); k++) {
BlockBegin* xhandler = sux->exception_handler_at(k);
block->add_exception_handler(xhandler);
// find instruction before end & append first instruction of sux block
Instruction* prev = end->prev();
Instruction* next = sux->next();
assert(prev->as_BlockEnd() == NULL, "must not be a BlockEnd");
prev->set_next(next);
prev->fixup_block_pointers();
sux->disconnect_from_graph();
block->set_end(sux->end());
// add exception handlers of deleted block, if any
for (int k = 0; k < sux->number_of_exception_handlers(); k++) {
BlockBegin* xhandler = sux->exception_handler_at(k);
block->add_exception_handler(xhandler);
// also substitute predecessor of exception handler
assert(xhandler->is_predecessor(sux), "missing predecessor");
xhandler->remove_predecessor(sux);
if (!xhandler->is_predecessor(block)) {
xhandler->add_predecessor(block);
// also substitute predecessor of exception handler
assert(xhandler->is_predecessor(sux), "missing predecessor");
xhandler->remove_predecessor(sux);
if (!xhandler->is_predecessor(block)) {
xhandler->add_predecessor(block);
}
}
// debugging output
_merge_count++;
if (PrintBlockElimination) {
tty->print_cr("%d. merged B%d & B%d (stack size = %d)",
_merge_count, block->block_id(), sux->block_id(), sux->state()->stack_size());
}
_hir->verify();
If* if_ = block->end()->as_If();
if (if_) {
IfOp* ifop = if_->x()->as_IfOp();
Constant* con = if_->y()->as_Constant();
bool swapped = false;
if (!con || !ifop) {
ifop = if_->y()->as_IfOp();
con = if_->x()->as_Constant();
swapped = true;
}
if (con && ifop) {
Constant* tval = ifop->tval()->as_Constant();
Constant* fval = ifop->fval()->as_Constant();
if (tval && fval) {
// Find the instruction before if_, starting with ifop.
// When if_ and ifop are not in the same block, prev
// becomes NULL In such (rare) cases it is not
// profitable to perform the optimization.
Value prev = ifop;
while (prev != NULL && prev->next() != if_) {
prev = prev->next();
}
}
// debugging output
_merge_count++;
if (PrintBlockElimination) {
tty->print_cr("%d. merged B%d & B%d (stack size = %d)",
_merge_count, block->block_id(), sux->block_id(), sux->state()->stack_size());
}
if (prev != NULL) {
Instruction::Condition cond = if_->cond();
BlockBegin* tsux = if_->tsux();
BlockBegin* fsux = if_->fsux();
if (swapped) {
cond = Instruction::mirror(cond);
}
_hir->verify();
BlockBegin* tblock = tval->compare(cond, con, tsux, fsux);
BlockBegin* fblock = fval->compare(cond, con, tsux, fsux);
if (tblock != fblock && !if_->is_safepoint()) {
If* newif = new If(ifop->x(), ifop->cond(), false, ifop->y(),
tblock, fblock, if_->state_before(), if_->is_safepoint());
newif->set_state(if_->state()->copy());
If* if_ = block->end()->as_If();
if (if_) {
IfOp* ifop = if_->x()->as_IfOp();
Constant* con = if_->y()->as_Constant();
bool swapped = false;
if (!con || !ifop) {
ifop = if_->y()->as_IfOp();
con = if_->x()->as_Constant();
swapped = true;
}
if (con && ifop) {
Constant* tval = ifop->tval()->as_Constant();
Constant* fval = ifop->fval()->as_Constant();
if (tval && fval) {
// Find the instruction before if_, starting with ifop.
// When if_ and ifop are not in the same block, prev
// becomes NULL In such (rare) cases it is not
// profitable to perform the optimization.
Value prev = ifop;
while (prev != NULL && prev->next() != if_) {
prev = prev->next();
assert(prev->next() == if_, "must be guaranteed by above search");
NOT_PRODUCT(newif->set_printable_bci(if_->printable_bci()));
prev->set_next(newif);
block->set_end(newif);
_merge_count++;
if (PrintBlockElimination) {
tty->print_cr("%d. replaced If and IfOp at end of B%d with single If", _merge_count, block->block_id());
}
if (prev != NULL) {
Instruction::Condition cond = if_->cond();
BlockBegin* tsux = if_->tsux();
BlockBegin* fsux = if_->fsux();
if (swapped) {
cond = Instruction::mirror(cond);
}
BlockBegin* tblock = tval->compare(cond, con, tsux, fsux);
BlockBegin* fblock = fval->compare(cond, con, tsux, fsux);
if (tblock != fblock && !if_->is_safepoint()) {
If* newif = new If(ifop->x(), ifop->cond(), false, ifop->y(),
tblock, fblock, if_->state_before(), if_->is_safepoint());
newif->set_state(if_->state()->copy());
assert(prev->next() == if_, "must be guaranteed by above search");
NOT_PRODUCT(newif->set_printable_bci(if_->printable_bci()));
prev->set_next(newif);
block->set_end(newif);
_merge_count++;
if (PrintBlockElimination) {
tty->print_cr("%d. replaced If and IfOp at end of B%d with single If", _merge_count, block->block_id());
}
_hir->verify();
}
}
_hir->verify();
}
}
}
return true;
}
}
return false;
return true;
}
virtual void block_do(BlockBegin* block) {
_hir->verify();
// repeat since the same block may merge again
while (try_merge(block)) {
_hir->verify();
}
while (try_merge(block)) ;
}
};