mirror of
https://github.com/openjdk/jdk.git
synced 2026-01-28 12:09:14 +00:00
8349361: C2: RShiftL should support all applicable transformations that RShiftI does
Reviewed-by: epeter, chagedorn, jkarthikeyan
This commit is contained in:
parent
eef6aefc21
commit
79bffe2f28
@ -225,6 +225,18 @@ MulNode* MulNode::make(Node* in1, Node* in2, BasicType bt) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
MulNode* MulNode::make_and(Node* in1, Node* in2, BasicType bt) {
|
||||
switch (bt) {
|
||||
case T_INT:
|
||||
return new AndINode(in1, in2);
|
||||
case T_LONG:
|
||||
return new AndLNode(in1, in2);
|
||||
default:
|
||||
fatal("Not implemented for %s", type2name(bt));
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
//=============================================================================
|
||||
//------------------------------Ideal------------------------------------------
|
||||
@ -949,7 +961,7 @@ static bool const_shift_count(PhaseGVN* phase, Node* shiftNode, int* count) {
|
||||
return false;
|
||||
}
|
||||
|
||||
static int maskShiftAmount(PhaseGVN* phase, Node* shiftNode, int nBits) {
|
||||
static int maskShiftAmount(PhaseGVN* phase, Node* shiftNode, uint nBits) {
|
||||
int count = 0;
|
||||
if (const_shift_count(phase, shiftNode, &count)) {
|
||||
int maskedShift = count & (nBits - 1);
|
||||
@ -1378,29 +1390,42 @@ const Type* LShiftLNode::Value(PhaseGVN* phase) const {
|
||||
return TypeLong::make( (jlong)r1->get_con() << (jint)shift );
|
||||
}
|
||||
|
||||
RShiftNode* RShiftNode::make(Node* in1, Node* in2, BasicType bt) {
|
||||
switch (bt) {
|
||||
case T_INT:
|
||||
return new RShiftINode(in1, in2);
|
||||
case T_LONG:
|
||||
return new RShiftLNode(in1, in2);
|
||||
default:
|
||||
fatal("Not implemented for %s", type2name(bt));
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
//=============================================================================
|
||||
//------------------------------Identity---------------------------------------
|
||||
Node* RShiftINode::Identity(PhaseGVN* phase) {
|
||||
Node* RShiftNode::IdentityIL(PhaseGVN* phase, BasicType bt) {
|
||||
int count = 0;
|
||||
if (const_shift_count(phase, this, &count)) {
|
||||
if ((count & (BitsPerJavaInteger - 1)) == 0) {
|
||||
// Shift by a multiple of 32 does nothing
|
||||
if ((count & (bits_per_java_integer(bt) - 1)) == 0) {
|
||||
// Shift by a multiple of 32/64 does nothing
|
||||
return in(1);
|
||||
}
|
||||
// Check for useless sign-masking
|
||||
if (in(1)->Opcode() == Op_LShiftI &&
|
||||
if (in(1)->Opcode() == Op_LShift(bt) &&
|
||||
in(1)->req() == 3 &&
|
||||
in(1)->in(2) == in(2)) {
|
||||
count &= BitsPerJavaInteger-1; // semantics of Java shifts
|
||||
count &= bits_per_java_integer(bt) - 1; // semantics of Java shifts
|
||||
// Compute masks for which this shifting doesn't change
|
||||
int lo = (-1 << (BitsPerJavaInteger - ((uint)count)-1)); // FFFF8000
|
||||
int hi = ~lo; // 00007FFF
|
||||
const TypeInt* t11 = phase->type(in(1)->in(1))->isa_int();
|
||||
jlong lo = (CONST64(-1) << (bits_per_java_integer(bt) - ((uint)count)-1)); // FFFF8000
|
||||
jlong hi = ~lo; // 00007FFF
|
||||
const TypeInteger* t11 = phase->type(in(1)->in(1))->isa_integer(bt);
|
||||
if (t11 == nullptr) {
|
||||
return this;
|
||||
}
|
||||
// Does actual value fit inside of mask?
|
||||
if (lo <= t11->_lo && t11->_hi <= hi) {
|
||||
if (lo <= t11->lo_as_long() && t11->hi_as_long() <= hi) {
|
||||
return in(1)->in(1); // Then shifting is a nop
|
||||
}
|
||||
}
|
||||
@ -1408,39 +1433,62 @@ Node* RShiftINode::Identity(PhaseGVN* phase) {
|
||||
return this;
|
||||
}
|
||||
|
||||
//------------------------------Ideal------------------------------------------
|
||||
Node *RShiftINode::Ideal(PhaseGVN *phase, bool can_reshape) {
|
||||
Node* RShiftINode::Identity(PhaseGVN* phase) {
|
||||
return IdentityIL(phase, T_INT);
|
||||
}
|
||||
|
||||
Node* RShiftNode::IdealIL(PhaseGVN* phase, bool can_reshape, BasicType bt) {
|
||||
// Inputs may be TOP if they are dead.
|
||||
const TypeInt *t1 = phase->type(in(1))->isa_int();
|
||||
if (!t1) return nullptr; // Left input is an integer
|
||||
const TypeInt *t3; // type of in(1).in(2)
|
||||
int shift = maskShiftAmount(phase, this, BitsPerJavaInteger);
|
||||
const TypeInteger* t1 = phase->type(in(1))->isa_integer(bt);
|
||||
if (t1 == nullptr) {
|
||||
return NodeSentinel; // Left input is an integer
|
||||
}
|
||||
int shift = maskShiftAmount(phase, this, bits_per_java_integer(bt));
|
||||
if (shift == 0) {
|
||||
return nullptr;
|
||||
return NodeSentinel;
|
||||
}
|
||||
|
||||
// Check for (x & 0xFF000000) >> 24, whose mask can be made smaller.
|
||||
// and convert to (x >> 24) & (0xFF000000 >> 24) = x >> 24
|
||||
// Such expressions arise normally from shift chains like (byte)(x >> 24).
|
||||
const Node *mask = in(1);
|
||||
if( mask->Opcode() == Op_AndI &&
|
||||
(t3 = phase->type(mask->in(2))->isa_int()) &&
|
||||
t3->is_con() ) {
|
||||
Node *x = mask->in(1);
|
||||
jint maskbits = t3->get_con();
|
||||
// Convert to "(x >> shift) & (mask >> shift)"
|
||||
Node *shr_nomask = phase->transform( new RShiftINode(mask->in(1), in(2)) );
|
||||
return new AndINode(shr_nomask, phase->intcon( maskbits >> shift));
|
||||
const Node* and_node = in(1);
|
||||
if (and_node->Opcode() != Op_And(bt)) {
|
||||
return nullptr;
|
||||
}
|
||||
const TypeInteger* mask_t = phase->type(and_node->in(2))->isa_integer(bt);
|
||||
if (mask_t != nullptr && mask_t->is_con()) {
|
||||
jlong maskbits = mask_t->get_con_as_long(bt);
|
||||
// Convert to "(x >> shift) & (mask >> shift)"
|
||||
Node* shr_nomask = phase->transform(RShiftNode::make(and_node->in(1), in(2), bt));
|
||||
return MulNode::make_and(shr_nomask, phase->integercon(maskbits >> shift, bt), bt);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Node* RShiftINode::Ideal(PhaseGVN* phase, bool can_reshape) {
|
||||
Node* progress = IdealIL(phase, can_reshape, T_INT);
|
||||
if (progress == NodeSentinel) {
|
||||
return nullptr;
|
||||
}
|
||||
if (progress != nullptr) {
|
||||
return progress;
|
||||
}
|
||||
int shift = maskShiftAmount(phase, this, BitsPerJavaInteger);
|
||||
assert(shift != 0, "handled by IdealIL");
|
||||
|
||||
// Check for "(short[i] <<16)>>16" which simply sign-extends
|
||||
const Node *shl = in(1);
|
||||
if( shl->Opcode() != Op_LShiftI ) return nullptr;
|
||||
if (shl->Opcode() != Op_LShiftI) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if( shift == 16 &&
|
||||
(t3 = phase->type(shl->in(2))->isa_int()) &&
|
||||
t3->is_con(16) ) {
|
||||
const TypeInt* left_shift_t = phase->type(shl->in(2))->isa_int();
|
||||
if (left_shift_t == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
if (shift == 16 && left_shift_t->is_con(16)) {
|
||||
Node *ld = shl->in(1);
|
||||
if( ld->Opcode() == Op_LoadS ) {
|
||||
if (ld->Opcode() == Op_LoadS) {
|
||||
// Sign extension is just useless here. Return a RShiftI of zero instead
|
||||
// returning 'ld' directly. We cannot return an old Node directly as
|
||||
// that is the job of 'Identity' calls and Identity calls only work on
|
||||
@ -1458,9 +1506,7 @@ Node *RShiftINode::Ideal(PhaseGVN *phase, bool can_reshape) {
|
||||
}
|
||||
|
||||
// Check for "(byte[i] <<24)>>24" which simply sign-extends
|
||||
if( shift == 24 &&
|
||||
(t3 = phase->type(shl->in(2))->isa_int()) &&
|
||||
t3->is_con(24) ) {
|
||||
if (shift == 24 && left_shift_t->is_con(24)) {
|
||||
Node *ld = shl->in(1);
|
||||
if (ld->Opcode() == Op_LoadB) {
|
||||
// Sign extension is just useless here
|
||||
@ -1473,46 +1519,66 @@ Node *RShiftINode::Ideal(PhaseGVN *phase, bool can_reshape) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
//------------------------------Value------------------------------------------
|
||||
// A RShiftINode shifts its input2 right by input1 amount.
|
||||
const Type* RShiftINode::Value(PhaseGVN* phase) const {
|
||||
const Type *t1 = phase->type( in(1) );
|
||||
const Type *t2 = phase->type( in(2) );
|
||||
const Type* RShiftNode::ValueIL(PhaseGVN* phase, BasicType bt) const {
|
||||
const Type* t1 = phase->type(in(1));
|
||||
const Type* t2 = phase->type(in(2));
|
||||
// Either input is TOP ==> the result is TOP
|
||||
if( t1 == Type::TOP ) return Type::TOP;
|
||||
if( t2 == Type::TOP ) return Type::TOP;
|
||||
if (t1 == Type::TOP) {
|
||||
return Type::TOP;
|
||||
}
|
||||
if (t2 == Type::TOP) {
|
||||
return Type::TOP;
|
||||
}
|
||||
|
||||
// Left input is ZERO ==> the result is ZERO.
|
||||
if( t1 == TypeInt::ZERO ) return TypeInt::ZERO;
|
||||
if (t1 == TypeInteger::zero(bt)) {
|
||||
return TypeInteger::zero(bt);
|
||||
}
|
||||
// Shift by zero does nothing
|
||||
if( t2 == TypeInt::ZERO ) return t1;
|
||||
if (t2 == TypeInt::ZERO) {
|
||||
return t1;
|
||||
}
|
||||
|
||||
// Either input is BOTTOM ==> the result is BOTTOM
|
||||
if (t1 == Type::BOTTOM || t2 == Type::BOTTOM)
|
||||
return TypeInt::INT;
|
||||
if (t1 == Type::BOTTOM || t2 == Type::BOTTOM) {
|
||||
return TypeInteger::bottom(bt);
|
||||
}
|
||||
|
||||
const TypeInt *r1 = t1->is_int(); // Handy access
|
||||
const TypeInt *r2 = t2->is_int(); // Handy access
|
||||
const TypeInteger* r1 = t1->isa_integer(bt);
|
||||
const TypeInt* r2 = t2->isa_int();
|
||||
|
||||
// If the shift is a constant, just shift the bounds of the type.
|
||||
// For example, if the shift is 31, we just propagate sign bits.
|
||||
// For example, if the shift is 31/63, we just propagate sign bits.
|
||||
if (!r1->is_con() && r2->is_con()) {
|
||||
uint shift = r2->get_con();
|
||||
shift &= BitsPerJavaInteger-1; // semantics of Java shifts
|
||||
// Shift by a multiple of 32 does nothing:
|
||||
if (shift == 0) return t1;
|
||||
shift &= bits_per_java_integer(bt) - 1; // semantics of Java shifts
|
||||
// Shift by a multiple of 32/64 does nothing:
|
||||
if (shift == 0) {
|
||||
return t1;
|
||||
}
|
||||
// Calculate reasonably aggressive bounds for the result.
|
||||
// This is necessary if we are to correctly type things
|
||||
// like (x<<24>>24) == ((byte)x).
|
||||
jint lo = (jint)r1->_lo >> (jint)shift;
|
||||
jint hi = (jint)r1->_hi >> (jint)shift;
|
||||
jlong lo = r1->lo_as_long() >> (jint)shift;
|
||||
jlong hi = r1->hi_as_long() >> (jint)shift;
|
||||
assert(lo <= hi, "must have valid bounds");
|
||||
const TypeInt* ti = TypeInt::make(lo, hi, MAX2(r1->_widen,r2->_widen));
|
||||
#ifdef ASSERT
|
||||
if (bt == T_INT) {
|
||||
jint lo_verify = checked_cast<jint>(r1->lo_as_long()) >> (jint)shift;
|
||||
jint hi_verify = checked_cast<jint>(r1->hi_as_long()) >> (jint)shift;
|
||||
assert((checked_cast<jint>(lo) == lo_verify) && (checked_cast<jint>(hi) == hi_verify), "inconsistent");
|
||||
}
|
||||
#endif
|
||||
const TypeInteger* ti = TypeInteger::make(lo, hi, MAX2(r1->_widen,r2->_widen), bt);
|
||||
#ifdef ASSERT
|
||||
// Make sure we get the sign-capture idiom correct.
|
||||
if (shift == BitsPerJavaInteger-1) {
|
||||
if (r1->_lo >= 0) assert(ti == TypeInt::ZERO, ">>31 of + is 0");
|
||||
if (r1->_hi < 0) assert(ti == TypeInt::MINUS_1, ">>31 of - is -1");
|
||||
if (shift == bits_per_java_integer(bt) - 1) {
|
||||
if (r1->lo_as_long() >= 0) {
|
||||
assert(ti == TypeInteger::zero(bt), ">>31/63 of + is 0");
|
||||
}
|
||||
if (r1->hi_as_long() < 0) {
|
||||
assert(ti == TypeInteger::minus_1(bt), ">>31/63 of - is -1");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return ti;
|
||||
@ -1520,89 +1586,42 @@ const Type* RShiftINode::Value(PhaseGVN* phase) const {
|
||||
|
||||
if (!r1->is_con() || !r2->is_con()) {
|
||||
// If the left input is non-negative the result must also be non-negative, regardless of what the right input is.
|
||||
if (r1->_lo >= 0) {
|
||||
return TypeInt::make(0, r1->_hi, MAX2(r1->_widen, r2->_widen));
|
||||
if (r1->lo_as_long() >= 0) {
|
||||
return TypeInteger::make(0, r1->hi_as_long(), MAX2(r1->_widen, r2->_widen), bt);
|
||||
}
|
||||
|
||||
// Conversely, if the left input is negative then the result must be negative.
|
||||
if (r1->_hi <= -1) {
|
||||
return TypeInt::make(r1->_lo, -1, MAX2(r1->_widen, r2->_widen));
|
||||
if (r1->hi_as_long() <= -1) {
|
||||
return TypeInteger::make(r1->lo_as_long(), -1, MAX2(r1->_widen, r2->_widen), bt);
|
||||
}
|
||||
|
||||
return TypeInt::INT;
|
||||
return TypeInteger::bottom(bt);
|
||||
}
|
||||
|
||||
// Signed shift right
|
||||
return TypeInt::make(r1->get_con() >> (r2->get_con() & 31));
|
||||
return TypeInteger::make(r1->get_con_as_long(bt) >> (r2->get_con() & (bits_per_java_integer(bt) - 1)), bt);
|
||||
}
|
||||
|
||||
const Type* RShiftINode::Value(PhaseGVN* phase) const {
|
||||
return ValueIL(phase, T_INT);
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//------------------------------Identity---------------------------------------
|
||||
Node* RShiftLNode::Identity(PhaseGVN* phase) {
|
||||
const TypeInt *ti = phase->type(in(2))->isa_int(); // Shift count is an int.
|
||||
return (ti && ti->is_con() && (ti->get_con() & (BitsPerJavaLong - 1)) == 0) ? in(1) : this;
|
||||
return IdentityIL(phase, T_LONG);
|
||||
}
|
||||
|
||||
Node* RShiftLNode::Ideal(PhaseGVN *phase, bool can_reshape) {
|
||||
Node* progress = IdealIL(phase, can_reshape, T_LONG);
|
||||
if (progress == NodeSentinel) {
|
||||
return nullptr;
|
||||
}
|
||||
return progress;
|
||||
}
|
||||
|
||||
//------------------------------Value------------------------------------------
|
||||
// A RShiftLNode shifts its input2 right by input1 amount.
|
||||
const Type* RShiftLNode::Value(PhaseGVN* phase) const {
|
||||
const Type *t1 = phase->type( in(1) );
|
||||
const Type *t2 = phase->type( in(2) );
|
||||
// Either input is TOP ==> the result is TOP
|
||||
if( t1 == Type::TOP ) return Type::TOP;
|
||||
if( t2 == Type::TOP ) return Type::TOP;
|
||||
|
||||
// Left input is ZERO ==> the result is ZERO.
|
||||
if( t1 == TypeLong::ZERO ) return TypeLong::ZERO;
|
||||
// Shift by zero does nothing
|
||||
if( t2 == TypeInt::ZERO ) return t1;
|
||||
|
||||
// Either input is BOTTOM ==> the result is BOTTOM
|
||||
if (t1 == Type::BOTTOM || t2 == Type::BOTTOM)
|
||||
return TypeLong::LONG;
|
||||
|
||||
const TypeLong *r1 = t1->is_long(); // Handy access
|
||||
const TypeInt *r2 = t2->is_int (); // Handy access
|
||||
|
||||
// If the shift is a constant, just shift the bounds of the type.
|
||||
// For example, if the shift is 63, we just propagate sign bits.
|
||||
if (!r1->is_con() && r2->is_con()) {
|
||||
uint shift = r2->get_con();
|
||||
shift &= (2*BitsPerJavaInteger)-1; // semantics of Java shifts
|
||||
// Shift by a multiple of 64 does nothing:
|
||||
if (shift == 0) return t1;
|
||||
// Calculate reasonably aggressive bounds for the result.
|
||||
// This is necessary if we are to correctly type things
|
||||
// like (x<<24>>24) == ((byte)x).
|
||||
jlong lo = (jlong)r1->_lo >> (jlong)shift;
|
||||
jlong hi = (jlong)r1->_hi >> (jlong)shift;
|
||||
assert(lo <= hi, "must have valid bounds");
|
||||
const TypeLong* tl = TypeLong::make(lo, hi, MAX2(r1->_widen,r2->_widen));
|
||||
#ifdef ASSERT
|
||||
// Make sure we get the sign-capture idiom correct.
|
||||
if (shift == (2*BitsPerJavaInteger)-1) {
|
||||
if (r1->_lo >= 0) assert(tl == TypeLong::ZERO, ">>63 of + is 0");
|
||||
if (r1->_hi < 0) assert(tl == TypeLong::MINUS_1, ">>63 of - is -1");
|
||||
}
|
||||
#endif
|
||||
return tl;
|
||||
}
|
||||
|
||||
if (!r1->is_con() || !r2->is_con()) {
|
||||
// If the left input is non-negative the result must also be non-negative, regardless of what the right input is.
|
||||
if (r1->_lo >= 0) {
|
||||
return TypeLong::make(0, r1->_hi, MAX2(r1->_widen, r2->_widen));
|
||||
}
|
||||
|
||||
// Conversely, if the left input is negative then the result must be negative.
|
||||
if (r1->_hi <= -1) {
|
||||
return TypeLong::make(r1->_lo, -1, MAX2(r1->_widen, r2->_widen));
|
||||
}
|
||||
|
||||
return TypeLong::LONG;
|
||||
}
|
||||
|
||||
return TypeLong::make(r1->get_con() >> (r2->get_con() & 63));
|
||||
return ValueIL(phase, T_LONG);
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
|
||||
@ -82,6 +82,7 @@ public:
|
||||
virtual int min_opcode() const = 0;
|
||||
|
||||
static MulNode* make(Node* in1, Node* in2, BasicType bt);
|
||||
static MulNode* make_and(Node* in1, Node* in2, BasicType bt);
|
||||
|
||||
protected:
|
||||
Node* AndIL_sum_and_mask(PhaseGVN* phase, BasicType bt);
|
||||
@ -318,28 +319,42 @@ class RotateRightNode : public TypeNode {
|
||||
virtual const Type* Value(PhaseGVN* phase) const;
|
||||
};
|
||||
|
||||
|
||||
class RShiftNode : public Node {
|
||||
public:
|
||||
RShiftNode(Node* in1, Node* in2) : Node(nullptr, in1, in2) {}
|
||||
Node* IdealIL(PhaseGVN* phase, bool can_reshape, BasicType bt);
|
||||
Node* IdentityIL(PhaseGVN* phase, BasicType bt);
|
||||
const Type* ValueIL(PhaseGVN* phase, BasicType bt) const;
|
||||
static RShiftNode* make(Node* in1, Node* in2, BasicType bt);
|
||||
};
|
||||
|
||||
//------------------------------RShiftINode------------------------------------
|
||||
// Signed shift right
|
||||
class RShiftINode : public Node {
|
||||
class RShiftINode : public RShiftNode {
|
||||
public:
|
||||
RShiftINode( Node *in1, Node *in2 ) : Node(nullptr,in1,in2) {}
|
||||
RShiftINode(Node* in1, Node* in2) : RShiftNode(in1, in2) {}
|
||||
virtual int Opcode() const;
|
||||
virtual Node* Identity(PhaseGVN* phase);
|
||||
virtual Node *Ideal(PhaseGVN *phase, bool can_reshape);
|
||||
|
||||
virtual Node* Ideal(PhaseGVN* phase, bool can_reshape);
|
||||
virtual const Type* Value(PhaseGVN* phase) const;
|
||||
const Type *bottom_type() const { return TypeInt::INT; }
|
||||
|
||||
const Type* bottom_type() const { return TypeInt::INT; }
|
||||
virtual uint ideal_reg() const { return Op_RegI; }
|
||||
};
|
||||
|
||||
//------------------------------RShiftLNode------------------------------------
|
||||
// Signed shift right
|
||||
class RShiftLNode : public Node {
|
||||
class RShiftLNode : public RShiftNode {
|
||||
public:
|
||||
RShiftLNode( Node *in1, Node *in2 ) : Node(nullptr,in1,in2) {}
|
||||
RShiftLNode(Node* in1, Node* in2) : RShiftNode(in1,in2) {}
|
||||
virtual int Opcode() const;
|
||||
virtual Node* Identity(PhaseGVN* phase);
|
||||
virtual Node* Ideal(PhaseGVN *phase, bool can_reshape);
|
||||
|
||||
virtual const Type* Value(PhaseGVN* phase) const;
|
||||
const Type *bottom_type() const { return TypeLong::LONG; }
|
||||
const Type* bottom_type() const { return TypeLong::LONG; }
|
||||
virtual uint ideal_reg() const { return Op_RegL; }
|
||||
};
|
||||
|
||||
|
||||
@ -2064,6 +2064,7 @@ public:
|
||||
}
|
||||
|
||||
Op_IL(Add)
|
||||
Op_IL(And)
|
||||
Op_IL(Sub)
|
||||
Op_IL(Mul)
|
||||
Op_IL(URShift)
|
||||
|
||||
@ -1611,10 +1611,10 @@ void PhaseIterGVN::add_users_of_use_to_worklist(Node* n, Node* use, Unique_Node_
|
||||
use->visit_uses(push_the_uses_to_worklist, is_boundary);
|
||||
}
|
||||
// If changed LShift inputs, check RShift users for useless sign-ext
|
||||
if( use_op == Op_LShiftI ) {
|
||||
if (use_op == Op_LShiftI || use_op == Op_LShiftL) {
|
||||
for (DUIterator_Fast i2max, i2 = use->fast_outs(i2max); i2 < i2max; i2++) {
|
||||
Node* u = use->fast_out(i2);
|
||||
if (u->Opcode() == Op_RShiftI)
|
||||
if (u->Opcode() == Op_RShiftI || u->Opcode() == Op_RShiftL)
|
||||
worklist.push(u);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1699,6 +1699,10 @@ const TypeInteger* TypeInteger::make(jlong lo, jlong hi, int w, BasicType bt) {
|
||||
return TypeLong::make(lo, hi, w);
|
||||
}
|
||||
|
||||
const TypeInteger* TypeInteger::make(jlong con, BasicType bt) {
|
||||
return make(con, con, WidenMin, bt);
|
||||
}
|
||||
|
||||
jlong TypeInteger::get_con_as_long(BasicType bt) const {
|
||||
if (bt == T_INT) {
|
||||
return is_int()->get_con();
|
||||
|
||||
@ -606,6 +606,7 @@ public:
|
||||
virtual short widen_limit() const { return _widen; }
|
||||
|
||||
static const TypeInteger* make(jlong lo, jlong hi, int w, BasicType bt);
|
||||
static const TypeInteger* make(jlong con, BasicType bt);
|
||||
|
||||
static const TypeInteger* bottom(BasicType type);
|
||||
static const TypeInteger* zero(BasicType type);
|
||||
|
||||
@ -27,7 +27,7 @@ import compiler.lib.ir_framework.*;
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8320330
|
||||
* @bug 8320330 8349361
|
||||
* @summary Test that RShiftINode optimizations are being performed as expected.
|
||||
* @library /test/lib /
|
||||
* @run driver compiler.c2.irTests.RShiftINodeIdealizationTests
|
||||
@ -37,7 +37,7 @@ public class RShiftINodeIdealizationTests {
|
||||
TestFramework.run();
|
||||
}
|
||||
|
||||
@Run(test = { "test1", "test2", "test3", "test4" })
|
||||
@Run(test = { "test1", "test2", "test3", "test4", "test5", "test6", "test7", "test8", "test9", "test10" })
|
||||
public void runMethod() {
|
||||
int a = RunInfo.getRandom().nextInt();
|
||||
int b = RunInfo.getRandom().nextInt();
|
||||
@ -56,6 +56,10 @@ public class RShiftINodeIdealizationTests {
|
||||
assertResult(max, min);
|
||||
assertResult(min, min);
|
||||
assertResult(max, max);
|
||||
assertResult(test7Min, b);
|
||||
assertResult(test7Max, b);
|
||||
assertResult(test7Min-1, b);
|
||||
assertResult(test7Max+1, b);
|
||||
}
|
||||
|
||||
@DontCompile
|
||||
@ -64,6 +68,15 @@ public class RShiftINodeIdealizationTests {
|
||||
Asserts.assertEQ(((x & 127) >> y) >= 0 ? 0 : 1, test2(x, y));
|
||||
Asserts.assertEQ(((-(x & 127) - 1) >> y) >= 0 ? 0 : 1, test3(x, y));
|
||||
Asserts.assertEQ((x >> 30) > 4 ? 0 : 1, test4(x, y));
|
||||
Asserts.assertEQ((x & test5Mask) >> test5Shift, test5(x));
|
||||
Asserts.assertEQ(x, test6(x));
|
||||
int x7 = Integer.max(Integer.min(x, test7Max), test7Min);
|
||||
Asserts.assertEQ(((x7 << test7Shift) >> test7Shift), test7(x));
|
||||
int x8 = Integer.max(Integer.min(x, test7Max+1), test7Min);
|
||||
Asserts.assertEQ((x8 << test7Shift) >> test7Shift, test8(x));
|
||||
int x9 = Integer.max(Integer.min(x, test7Max), test7Min-1);
|
||||
Asserts.assertEQ((x9 << test7Shift) >> test7Shift, test9(x));
|
||||
Asserts.assertEQ((x7 << test7Shift) >> test10Shift, test10(x));
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -89,4 +102,67 @@ public class RShiftINodeIdealizationTests {
|
||||
public int test4(int x, int y) {
|
||||
return (x >> 30) > 4 ? 0 : 1;
|
||||
}
|
||||
|
||||
final static int test5Shift = RunInfo.getRandom().nextInt(1, 32);
|
||||
final static int test5Mask = -1 << test5Shift;
|
||||
|
||||
@Test
|
||||
@IR(counts = { IRNode.RSHIFT_I, "1" })
|
||||
@IR(failOn = { IRNode.AND_I })
|
||||
public int test5(int x) {
|
||||
return (x & test5Mask) >> test5Shift;
|
||||
}
|
||||
|
||||
final static int test6Shift = RunInfo.getRandom().nextInt(Integer.MAX_VALUE / 32) * 32 ;
|
||||
|
||||
@Test
|
||||
@IR(failOn = { IRNode.RSHIFT_I })
|
||||
public int test6(int x) {
|
||||
return (x >> test6Shift);
|
||||
}
|
||||
|
||||
|
||||
// test that (x << shift) >> shift) is a nop if upper bits of x
|
||||
// that are shifted left and then right + one bit are all ones or
|
||||
// zeroes. For instance:
|
||||
// shift = 15, min = 0xffff0000, max=0x0000ffff
|
||||
// min << shift = 0x80000000, (min << shift) >> shift = 0xffff0000
|
||||
// (min+1) << shift = 0x80008000, ((min+1) << shift) >> shift = 0xffff0001
|
||||
// (max-1) << shift = 0x7fff0000, ((max-1) << shift) >> shift = 0x0000fffe
|
||||
// max << shift = 0x7fff8000, (min << shift) >> shift = 0x0000ffff
|
||||
// But:
|
||||
// (min-1) << shift = 7fff8000, ((min-1) << shift) >> shift = 0x0000ffff != 0xfffeffff
|
||||
// (max+1) << shift = 0x80000000, ((max+1) << shift) >> shift = 0xffff0000 != 0x00010000
|
||||
final static int test7Shift = RunInfo.getRandom().nextInt(1, 32);
|
||||
final static int test7Min = -1 << (32 - test7Shift - 1);
|
||||
final static int test7Max = ~test7Min;
|
||||
|
||||
@Test
|
||||
@IR(failOn = { IRNode.RSHIFT_I, IRNode.LSHIFT_I })
|
||||
public int test7(int x) {
|
||||
x = Integer.max(Integer.min(x, test7Max), test7Min);
|
||||
return ((x << test7Shift) >> test7Shift);
|
||||
}
|
||||
|
||||
@Test
|
||||
@IR(counts = { IRNode.RSHIFT_I, "1", IRNode.LSHIFT_I, "1" })
|
||||
public int test8(int x) {
|
||||
x = Integer.max(Integer.min(x, test7Max+1), test7Min);
|
||||
return ((x << test7Shift) >> test7Shift);
|
||||
}
|
||||
|
||||
@Test
|
||||
@IR(counts = { IRNode.RSHIFT_I, "1", IRNode.LSHIFT_I, "1" })
|
||||
public int test9(int x) {
|
||||
x = Integer.max(Integer.min(x, test7Max), test7Min-1);
|
||||
return ((x << test7Shift) >> test7Shift);
|
||||
}
|
||||
|
||||
final static int test10Shift = RunInfo.getRandom().nextInt(32);
|
||||
|
||||
@Test
|
||||
public int test10(int x) {
|
||||
x = Integer.max(Integer.min(x, test7Max), test7Min);
|
||||
return ((x << test7Shift) >> test10Shift);
|
||||
}
|
||||
}
|
||||
|
||||
@ -27,7 +27,7 @@ import compiler.lib.ir_framework.*;
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8320330
|
||||
* @bug 8320330 8349361
|
||||
* @summary Test that RShiftLNode optimizations are being performed as expected.
|
||||
* @library /test/lib /
|
||||
* @run driver compiler.c2.irTests.RShiftLNodeIdealizationTests
|
||||
@ -37,7 +37,7 @@ public class RShiftLNodeIdealizationTests {
|
||||
TestFramework.run();
|
||||
}
|
||||
|
||||
@Run(test = { "test1", "test2", "test3", "test4" })
|
||||
@Run(test = { "test1", "test2", "test3", "test4", "test5", "test6", "test7", "test8", "test9", "test10" })
|
||||
public void runMethod() {
|
||||
long a = RunInfo.getRandom().nextLong();
|
||||
long b = RunInfo.getRandom().nextLong();
|
||||
@ -56,6 +56,10 @@ public class RShiftLNodeIdealizationTests {
|
||||
assertResult(max, min);
|
||||
assertResult(min, min);
|
||||
assertResult(max, max);
|
||||
assertResult(test7Min, b);
|
||||
assertResult(test7Max, b);
|
||||
assertResult(test7Min-1, b);
|
||||
assertResult(test7Max+1, b);
|
||||
}
|
||||
|
||||
@DontCompile
|
||||
@ -64,6 +68,15 @@ public class RShiftLNodeIdealizationTests {
|
||||
Asserts.assertEQ(((x & 127) >> y) >= 0 ? 0L : 1L, test2(x, y));
|
||||
Asserts.assertEQ(((-(x & 127) - 1) >> y) >= 0 ? 0L : 1L, test3(x, y));
|
||||
Asserts.assertEQ((x >> 62) > 4 ? 0L : 1L, test4(x, y));
|
||||
Asserts.assertEQ((x & test5Mask) >> test5Shift, test5(x));
|
||||
Asserts.assertEQ(x, test6(x));
|
||||
long x7 = Long.max(Long.min(x, test7Max), test7Min);
|
||||
Asserts.assertEQ(((x7 << test7Shift) >> test7Shift), test7(x));
|
||||
long x8 = Long.max(Long.min(x, test7Max+1), test7Min);
|
||||
Asserts.assertEQ((x8 << test7Shift) >> test7Shift, test8(x));
|
||||
long x9 = Long.max(Long.min(x, test7Max), test7Min-1);
|
||||
Asserts.assertEQ((x9 << test7Shift) >> test7Shift, test9(x));
|
||||
Asserts.assertEQ(((x7 << test7Shift) >> test10Shift), test10(x));
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -89,4 +102,55 @@ public class RShiftLNodeIdealizationTests {
|
||||
public long test4(long x, long y) {
|
||||
return (x >> 62) > 4 ? 0L : 1L;
|
||||
}
|
||||
|
||||
final static int test5Shift = RunInfo.getRandom().nextInt(1, 64);
|
||||
final static long test5Mask = -1L << test5Shift;
|
||||
|
||||
@Test
|
||||
@IR(counts = { IRNode.RSHIFT_L, "1" })
|
||||
@IR(failOn = { IRNode.AND_L })
|
||||
public long test5(long x) {
|
||||
return (x & test5Mask) >> test5Shift;
|
||||
}
|
||||
|
||||
final static int test6Shift = RunInfo.getRandom().nextInt(Integer.MAX_VALUE / 64) * 64 ;
|
||||
|
||||
@Test
|
||||
@IR(failOn = { IRNode.RSHIFT_L })
|
||||
public long test6(long x) {
|
||||
return (x >> test6Shift);
|
||||
}
|
||||
|
||||
// See comment in RShiftINodeIdealizationTests
|
||||
final static int test7Shift = RunInfo.getRandom().nextInt(1, 64);
|
||||
final static long test7Min = -1L << (64 - test7Shift - 1);
|
||||
final static long test7Max = ~test7Min;
|
||||
|
||||
@Test
|
||||
@IR(failOn = { IRNode.RSHIFT_L, IRNode.LSHIFT_L })
|
||||
public long test7(long x) {
|
||||
x = Long.max(Long.min(x, test7Max), test7Min);
|
||||
return ((x << test7Shift) >> test7Shift);
|
||||
}
|
||||
|
||||
@Test
|
||||
@IR(counts = { IRNode.RSHIFT_L, "1", IRNode.LSHIFT_L, "1" })
|
||||
public long test8(long x) {
|
||||
x = Long.max(Long.min(x, test7Max+1), test7Min);
|
||||
return ((x << test7Shift) >> test7Shift);
|
||||
}
|
||||
|
||||
@Test
|
||||
@IR(counts = { IRNode.RSHIFT_L, "1", IRNode.LSHIFT_L, "1" })
|
||||
public long test9(long x) {
|
||||
x = Long.max(Long.min(x, test7Max), test7Min-1);
|
||||
return ((x << test7Shift) >> test7Shift);
|
||||
}
|
||||
|
||||
final static int test10Shift = RunInfo.getRandom().nextInt(64);
|
||||
@Test
|
||||
public long test10(long x) {
|
||||
x = Long.max(Long.min(x, test7Max), test7Min);
|
||||
return ((x << test7Shift) >> test10Shift);
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user