8230382: Clean up ConvI2L, CastII and CastLL::Ideal methods

Reviewed-by: thartmann, roland
This commit is contained in:
Emanuel Peter 2022-02-28 12:13:35 +00:00 committed by Tobias Hartmann
parent efd3967b54
commit 06cadb36e0
2 changed files with 82 additions and 90 deletions
src/hotspot/share/opto

@ -194,6 +194,40 @@ void ConstraintCastNode::dump_spec(outputStream *st) const {
const Type* CastIINode::Value(PhaseGVN* phase) const {
const Type *res = ConstraintCastNode::Value(phase);
if (res == Type::TOP) {
return Type::TOP;
}
assert(res->isa_int(), "res must be int");
// Similar to ConvI2LNode::Value() for the same reasons
// see if we can remove type assertion after loop opts
// But here we have to pay extra attention:
// Do not narrow the type of range check dependent CastIINodes to
// avoid corruption of the graph if a CastII is replaced by TOP but
// the corresponding range check is not removed.
if (!_range_check_dependency && phase->C->post_loop_opts_phase()) {
const TypeInt* this_type = res->is_int();
const TypeInt* in_type = phase->type(in(1))->isa_int();
if (in_type != NULL &&
(in_type->_lo != this_type->_lo ||
in_type->_hi != this_type->_hi)) {
jint lo1 = this_type->_lo;
jint hi1 = this_type->_hi;
int w1 = this_type->_widen;
if (lo1 >= 0) {
// Keep a range assertion of >=0.
lo1 = 0; hi1 = max_jint;
} else if (hi1 < 0) {
// Keep a range assertion of <0.
lo1 = min_jint; hi1 = -1;
} else {
lo1 = min_jint; hi1 = max_jint;
}
res = TypeInt::make(MAX2(in_type->_lo, lo1),
MIN2(in_type->_hi, hi1),
MAX2((int)in_type->_widen, w1));
}
}
// Try to improve the type of the CastII if we recognize a CmpI/If
// pattern.
@ -248,7 +282,6 @@ const Type* CastIINode::Value(PhaseGVN* phase) const {
t = TypeInt::make(lo_int, hi_int, Type::WidenMax);
res = res->filter_speculative(t);
return res;
}
}
@ -274,8 +307,11 @@ Node *CastIINode::Ideal(PhaseGVN *phase, bool can_reshape) {
if (progress != NULL) {
return progress;
}
PhaseIterGVN *igvn = phase->is_IterGVN();
if (can_reshape && !_range_check_dependency && !phase->C->post_loop_opts_phase()) {
// makes sure we run ::Value to potentially remove type assertion after loop opts
phase->C->record_for_post_loop_opts_igvn(this);
}
PhaseIterGVN* igvn = phase->is_IterGVN();
const TypeInt* this_type = this->type()->is_int();
Node* z = in(1);
const TypeInteger* rx = NULL;
@ -300,43 +336,6 @@ Node *CastIINode::Ideal(PhaseGVN *phase, bool can_reshape) {
default: ShouldNotReachHere();
}
}
// Similar to ConvI2LNode::Ideal() for the same reasons
// Do not narrow the type of range check dependent CastIINodes to
// avoid corruption of the graph if a CastII is replaced by TOP but
// the corresponding range check is not removed.
if (can_reshape && !_range_check_dependency) {
if (phase->C->post_loop_opts_phase()) {
const TypeInt* this_type = this->type()->is_int();
const TypeInt* in_type = phase->type(in(1))->isa_int();
if (in_type != NULL && this_type != NULL &&
(in_type->_lo != this_type->_lo ||
in_type->_hi != this_type->_hi)) {
jint lo1 = this_type->_lo;
jint hi1 = this_type->_hi;
int w1 = this_type->_widen;
if (lo1 >= 0) {
// Keep a range assertion of >=0.
lo1 = 0; hi1 = max_jint;
} else if (hi1 < 0) {
// Keep a range assertion of <0.
lo1 = min_jint; hi1 = -1;
} else {
lo1 = min_jint; hi1 = max_jint;
}
const TypeInt* wtype = TypeInt::make(MAX2(in_type->_lo, lo1),
MIN2(in_type->_hi, hi1),
MAX2((int)in_type->_widen, w1));
if (wtype != type()) {
set_type(wtype);
return this;
}
}
} else {
phase->C->record_for_post_loop_opts_igvn(this);
}
}
return NULL;
}

@ -252,12 +252,47 @@ Node* ConvI2FNode::Identity(PhaseGVN* phase) {
//------------------------------Value------------------------------------------
const Type* ConvI2LNode::Value(PhaseGVN* phase) const {
const Type *t = phase->type( in(1) );
if( t == Type::TOP ) return Type::TOP;
if (t == Type::TOP) {
return Type::TOP;
}
const TypeInt *ti = t->is_int();
const Type* tl = TypeLong::make(ti->_lo, ti->_hi, ti->_widen);
// Join my declared type against my incoming type.
tl = tl->filter(_type);
return tl;
if (!tl->isa_long()) {
return tl;
}
const TypeLong* this_type = tl->is_long();
// Do NOT remove this node's type assertion until no more loop ops can happen.
if (phase->C->post_loop_opts_phase()) {
const TypeInt* in_type = phase->type(in(1))->isa_int();
if (in_type != NULL &&
(in_type->_lo != this_type->_lo ||
in_type->_hi != this_type->_hi)) {
// Although this WORSENS the type, it increases GVN opportunities,
// because I2L nodes with the same input will common up, regardless
// of slightly differing type assertions. Such slight differences
// arise routinely as a result of loop unrolling, so this is a
// post-unrolling graph cleanup. Choose a type which depends only
// on my input. (Exception: Keep a range assertion of >=0 or <0.)
jlong lo1 = this_type->_lo;
jlong hi1 = this_type->_hi;
int w1 = this_type->_widen;
if (lo1 >= 0) {
// Keep a range assertion of >=0.
lo1 = 0; hi1 = max_jint;
} else if (hi1 < 0) {
// Keep a range assertion of <0.
lo1 = min_jint; hi1 = -1;
} else {
lo1 = min_jint; hi1 = max_jint;
}
return TypeLong::make(MAX2((jlong)in_type->_lo, lo1),
MIN2((jlong)in_type->_hi, hi1),
MAX2((int)in_type->_widen, w1));
}
}
return this_type;
}
static inline bool long_ranges_overlap(jlong lo1, jlong hi1,
@ -359,52 +394,10 @@ bool Compile::push_thru_add(PhaseGVN* phase, Node* z, const TypeInteger* tz, con
//------------------------------Ideal------------------------------------------
Node *ConvI2LNode::Ideal(PhaseGVN *phase, bool can_reshape) {
PhaseIterGVN *igvn = phase->is_IterGVN();
const TypeLong* this_type = this->type()->is_long();
Node* this_changed = NULL;
if (igvn != NULL) {
// Do NOT remove this node's type assertion until no more loop ops can happen.
if (phase->C->post_loop_opts_phase()) {
const TypeInt* in_type = phase->type(in(1))->isa_int();
if (in_type != NULL && this_type != NULL &&
(in_type->_lo != this_type->_lo ||
in_type->_hi != this_type->_hi)) {
// Although this WORSENS the type, it increases GVN opportunities,
// because I2L nodes with the same input will common up, regardless
// of slightly differing type assertions. Such slight differences
// arise routinely as a result of loop unrolling, so this is a
// post-unrolling graph cleanup. Choose a type which depends only
// on my input. (Exception: Keep a range assertion of >=0 or <0.)
jlong lo1 = this_type->_lo;
jlong hi1 = this_type->_hi;
int w1 = this_type->_widen;
if (lo1 != (jint)lo1 ||
hi1 != (jint)hi1 ||
lo1 > hi1) {
// Overflow leads to wraparound, wraparound leads to range saturation.
lo1 = min_jint; hi1 = max_jint;
} else if (lo1 >= 0) {
// Keep a range assertion of >=0.
lo1 = 0; hi1 = max_jint;
} else if (hi1 < 0) {
// Keep a range assertion of <0.
lo1 = min_jint; hi1 = -1;
} else {
lo1 = min_jint; hi1 = max_jint;
}
const TypeLong* wtype = TypeLong::make(MAX2((jlong)in_type->_lo, lo1),
MIN2((jlong)in_type->_hi, hi1),
MAX2((int)in_type->_widen, w1));
if (wtype != type()) {
set_type(wtype);
// Note: this_type still has old type value, for the logic below.
this_changed = this;
}
}
} else {
phase->C->record_for_post_loop_opts_igvn(this);
}
if (can_reshape && !phase->C->post_loop_opts_phase()) {
// makes sure we run ::Value to potentially remove type assertion after loop opts
phase->C->record_for_post_loop_opts_igvn(this);
}
#ifdef _LP64
// Convert ConvI2L(AddI(x, y)) to AddL(ConvI2L(x), ConvI2L(y))
@ -428,7 +421,7 @@ Node *ConvI2LNode::Ideal(PhaseGVN *phase, bool can_reshape) {
// possible before the I2L conversion, because 32-bit math is cheaper.
// There's no common reason to "leak" a constant offset through the I2L.
// Addressing arithmetic will not absorb it as part of a 64-bit AddL.
PhaseIterGVN* igvn = phase->is_IterGVN();
Node* z = in(1);
const TypeInteger* rx = NULL;
const TypeInteger* ry = NULL;
@ -437,7 +430,7 @@ Node *ConvI2LNode::Ideal(PhaseGVN *phase, bool can_reshape) {
// Postpone this optimization to iterative GVN, where we can handle deep
// AddI chains without an exponential number of recursive Ideal() calls.
phase->record_for_igvn(this);
return this_changed;
return NULL;
}
int op = z->Opcode();
Node* x = z->in(1);
@ -453,7 +446,7 @@ Node *ConvI2LNode::Ideal(PhaseGVN *phase, bool can_reshape) {
}
#endif //_LP64
return this_changed;
return NULL;
}
//=============================================================================