mirror of
https://github.com/openjdk/jdk.git
synced 2025-09-20 19:14:38 +02:00
8039298: assert(base == NULL || t_adr->isa_rawptr() || !phase->type(base)->higher_equal(TypePtr::NULL_PTR))
Convert the assert into the runtime check to skip IGVN optimizations for problematic memory nodes. Eliminate dead nodes more aggressively. Reviewed-by: twisti, iveresov
This commit is contained in:
parent
3e18a6f16d
commit
c909ac41de
5 changed files with 38 additions and 28 deletions
|
@ -704,6 +704,7 @@ Compile::Compile( ciEnv* ci_env, C2Compiler* compiler, ciMethod* target, int osr
|
||||||
#endif
|
#endif
|
||||||
set_print_inlining(PrintInlining || method()->has_option("PrintInlining") NOT_PRODUCT( || PrintOptoInlining));
|
set_print_inlining(PrintInlining || method()->has_option("PrintInlining") NOT_PRODUCT( || PrintOptoInlining));
|
||||||
set_print_intrinsics(PrintIntrinsics || method()->has_option("PrintIntrinsics"));
|
set_print_intrinsics(PrintIntrinsics || method()->has_option("PrintIntrinsics"));
|
||||||
|
set_has_irreducible_loop(true); // conservative until build_loop_tree() reset it
|
||||||
|
|
||||||
if (ProfileTraps RTM_OPT_ONLY( || UseRTMLocking )) {
|
if (ProfileTraps RTM_OPT_ONLY( || UseRTMLocking )) {
|
||||||
// Make sure the method being compiled gets its own MDO,
|
// Make sure the method being compiled gets its own MDO,
|
||||||
|
@ -988,6 +989,8 @@ Compile::Compile( ciEnv* ci_env,
|
||||||
set_print_assembly(PrintFrameConverterAssembly);
|
set_print_assembly(PrintFrameConverterAssembly);
|
||||||
set_parsed_irreducible_loop(false);
|
set_parsed_irreducible_loop(false);
|
||||||
#endif
|
#endif
|
||||||
|
set_has_irreducible_loop(false); // no loops
|
||||||
|
|
||||||
CompileWrapper cw(this);
|
CompileWrapper cw(this);
|
||||||
Init(/*AliasLevel=*/ 0);
|
Init(/*AliasLevel=*/ 0);
|
||||||
init_tf((*generator)());
|
init_tf((*generator)());
|
||||||
|
@ -1158,7 +1161,7 @@ StartNode* Compile::start() const {
|
||||||
if( start->is_Start() )
|
if( start->is_Start() )
|
||||||
return start->as_Start();
|
return start->as_Start();
|
||||||
}
|
}
|
||||||
ShouldNotReachHere();
|
fatal("Did not find Start node!");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -319,6 +319,7 @@ class Compile : public Phase {
|
||||||
bool _trace_opto_output;
|
bool _trace_opto_output;
|
||||||
bool _parsed_irreducible_loop; // True if ciTypeFlow detected irreducible loops during parsing
|
bool _parsed_irreducible_loop; // True if ciTypeFlow detected irreducible loops during parsing
|
||||||
#endif
|
#endif
|
||||||
|
bool _has_irreducible_loop; // Found irreducible loops
|
||||||
// JSR 292
|
// JSR 292
|
||||||
bool _has_method_handle_invokes; // True if this method has MethodHandle invokes.
|
bool _has_method_handle_invokes; // True if this method has MethodHandle invokes.
|
||||||
RTMState _rtm_state; // State of Restricted Transactional Memory usage
|
RTMState _rtm_state; // State of Restricted Transactional Memory usage
|
||||||
|
@ -604,6 +605,8 @@ class Compile : public Phase {
|
||||||
void set_parsed_irreducible_loop(bool z) { _parsed_irreducible_loop = z; }
|
void set_parsed_irreducible_loop(bool z) { _parsed_irreducible_loop = z; }
|
||||||
int _in_dump_cnt; // Required for dumping ir nodes.
|
int _in_dump_cnt; // Required for dumping ir nodes.
|
||||||
#endif
|
#endif
|
||||||
|
bool has_irreducible_loop() const { return _has_irreducible_loop; }
|
||||||
|
void set_has_irreducible_loop(bool z) { _has_irreducible_loop = z; }
|
||||||
|
|
||||||
// JSR 292
|
// JSR 292
|
||||||
bool has_method_handle_invokes() const { return _has_method_handle_invokes; }
|
bool has_method_handle_invokes() const { return _has_method_handle_invokes; }
|
||||||
|
|
|
@ -267,9 +267,9 @@ bool PhaseIdealLoop::is_counted_loop( Node *x, IdealLoopTree *loop ) {
|
||||||
|
|
||||||
// Counted loop head must be a good RegionNode with only 3 not NULL
|
// Counted loop head must be a good RegionNode with only 3 not NULL
|
||||||
// control input edges: Self, Entry, LoopBack.
|
// control input edges: Self, Entry, LoopBack.
|
||||||
if (x->in(LoopNode::Self) == NULL || x->req() != 3)
|
if (x->in(LoopNode::Self) == NULL || x->req() != 3 || loop->_irreducible) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
Node *init_control = x->in(LoopNode::EntryControl);
|
Node *init_control = x->in(LoopNode::EntryControl);
|
||||||
Node *back_control = x->in(LoopNode::LoopBackControl);
|
Node *back_control = x->in(LoopNode::LoopBackControl);
|
||||||
if (init_control == NULL || back_control == NULL) // Partially dead
|
if (init_control == NULL || back_control == NULL) // Partially dead
|
||||||
|
@ -1523,7 +1523,7 @@ bool IdealLoopTree::beautify_loops( PhaseIdealLoop *phase ) {
|
||||||
|
|
||||||
// If I have one hot backedge, peel off myself loop.
|
// If I have one hot backedge, peel off myself loop.
|
||||||
// I better be the outermost loop.
|
// I better be the outermost loop.
|
||||||
if( _head->req() > 3 ) {
|
if (_head->req() > 3 && !_irreducible) {
|
||||||
split_outer_loop( phase );
|
split_outer_loop( phase );
|
||||||
result = true;
|
result = true;
|
||||||
|
|
||||||
|
@ -2939,6 +2939,7 @@ int PhaseIdealLoop::build_loop_tree_impl( Node *n, int pre_order ) {
|
||||||
return pre_order;
|
return pre_order;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
C->set_has_irreducible_loop(_has_irreducible_loops);
|
||||||
}
|
}
|
||||||
|
|
||||||
// This Node might be a decision point for loops. It is only if
|
// This Node might be a decision point for loops. It is only if
|
||||||
|
|
|
@ -308,33 +308,16 @@ Node *MemNode::Ideal_common(PhaseGVN *phase, bool can_reshape) {
|
||||||
int alias_idx = phase->C->get_alias_index(t_adr->is_ptr());
|
int alias_idx = phase->C->get_alias_index(t_adr->is_ptr());
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef ASSERT
|
|
||||||
Node* base = NULL;
|
Node* base = NULL;
|
||||||
if (address->is_AddP())
|
if (address->is_AddP()) {
|
||||||
base = address->in(AddPNode::Base);
|
base = address->in(AddPNode::Base);
|
||||||
|
}
|
||||||
if (base != NULL && phase->type(base)->higher_equal(TypePtr::NULL_PTR) &&
|
if (base != NULL && phase->type(base)->higher_equal(TypePtr::NULL_PTR) &&
|
||||||
!t_adr->isa_rawptr()) {
|
!t_adr->isa_rawptr()) {
|
||||||
// Note: raw address has TOP base and top->higher_equal(TypePtr::NULL_PTR) is true.
|
// Note: raw address has TOP base and top->higher_equal(TypePtr::NULL_PTR) is true.
|
||||||
Compile* C = phase->C;
|
// Skip this node optimization if its address has TOP base.
|
||||||
tty->cr();
|
return NodeSentinel; // caller will return NULL
|
||||||
tty->print_cr("===== NULL+offs not RAW address =====");
|
|
||||||
if (C->is_dead_node(this->_idx)) tty->print_cr("'this' is dead");
|
|
||||||
if ((ctl != NULL) && C->is_dead_node(ctl->_idx)) tty->print_cr("'ctl' is dead");
|
|
||||||
if (C->is_dead_node(mem->_idx)) tty->print_cr("'mem' is dead");
|
|
||||||
if (C->is_dead_node(address->_idx)) tty->print_cr("'address' is dead");
|
|
||||||
if (C->is_dead_node(base->_idx)) tty->print_cr("'base' is dead");
|
|
||||||
tty->cr();
|
|
||||||
base->dump(1);
|
|
||||||
tty->cr();
|
|
||||||
this->dump(2);
|
|
||||||
tty->print("this->adr_type(): "); adr_type()->dump(); tty->cr();
|
|
||||||
tty->print("phase->type(address): "); t_adr->dump(); tty->cr();
|
|
||||||
tty->print("phase->type(base): "); phase->type(address)->dump(); tty->cr();
|
|
||||||
tty->cr();
|
|
||||||
}
|
}
|
||||||
assert(base == NULL || t_adr->isa_rawptr() ||
|
|
||||||
!phase->type(base)->higher_equal(TypePtr::NULL_PTR), "NULL+offs not RAW address?");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Avoid independent memory operations
|
// Avoid independent memory operations
|
||||||
Node* old_mem = mem;
|
Node* old_mem = mem;
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
#include "memory/allocation.inline.hpp"
|
#include "memory/allocation.inline.hpp"
|
||||||
#include "opto/cfgnode.hpp"
|
#include "opto/cfgnode.hpp"
|
||||||
#include "opto/connode.hpp"
|
#include "opto/connode.hpp"
|
||||||
|
#include "opto/loopnode.hpp"
|
||||||
#include "opto/machnode.hpp"
|
#include "opto/machnode.hpp"
|
||||||
#include "opto/matcher.hpp"
|
#include "opto/matcher.hpp"
|
||||||
#include "opto/node.hpp"
|
#include "opto/node.hpp"
|
||||||
|
@ -1263,6 +1264,7 @@ static void kill_dead_code( Node *dead, PhaseIterGVN *igvn ) {
|
||||||
|
|
||||||
Node *top = igvn->C->top();
|
Node *top = igvn->C->top();
|
||||||
nstack.push(dead);
|
nstack.push(dead);
|
||||||
|
bool has_irreducible_loop = igvn->C->has_irreducible_loop();
|
||||||
|
|
||||||
while (nstack.size() > 0) {
|
while (nstack.size() > 0) {
|
||||||
dead = nstack.pop();
|
dead = nstack.pop();
|
||||||
|
@ -1277,14 +1279,32 @@ static void kill_dead_code( Node *dead, PhaseIterGVN *igvn ) {
|
||||||
assert (!use->is_Con(), "Control for Con node should be Root node.");
|
assert (!use->is_Con(), "Control for Con node should be Root node.");
|
||||||
use->set_req(0, top); // Cut dead edge to prevent processing
|
use->set_req(0, top); // Cut dead edge to prevent processing
|
||||||
nstack.push(use); // the dead node again.
|
nstack.push(use); // the dead node again.
|
||||||
|
} else if (!has_irreducible_loop && // Backedge could be alive in irreducible loop
|
||||||
|
use->is_Loop() && !use->is_Root() && // Don't kill Root (RootNode extends LoopNode)
|
||||||
|
use->in(LoopNode::EntryControl) == dead) { // Dead loop if its entry is dead
|
||||||
|
use->set_req(LoopNode::EntryControl, top); // Cut dead edge to prevent processing
|
||||||
|
use->set_req(0, top); // Cut self edge
|
||||||
|
nstack.push(use);
|
||||||
} else { // Else found a not-dead user
|
} else { // Else found a not-dead user
|
||||||
|
// Dead if all inputs are top or null
|
||||||
|
bool dead_use = !use->is_Root(); // Keep empty graph alive
|
||||||
for (uint j = 1; j < use->req(); j++) {
|
for (uint j = 1; j < use->req(); j++) {
|
||||||
if (use->in(j) == dead) { // Turn all dead inputs into TOP
|
Node* in = use->in(j);
|
||||||
|
if (in == dead) { // Turn all dead inputs into TOP
|
||||||
use->set_req(j, top);
|
use->set_req(j, top);
|
||||||
|
} else if (in != NULL && !in->is_top()) {
|
||||||
|
dead_use = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (dead_use) {
|
||||||
|
if (use->is_Region()) {
|
||||||
|
use->set_req(0, top); // Cut self edge
|
||||||
|
}
|
||||||
|
nstack.push(use);
|
||||||
|
} else {
|
||||||
igvn->_worklist.push(use);
|
igvn->_worklist.push(use);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// Refresh the iterator, since any number of kills might have happened.
|
// Refresh the iterator, since any number of kills might have happened.
|
||||||
k = dead->last_outs(kmin);
|
k = dead->last_outs(kmin);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue