8256823: C2 compilation fails with "assert(isShiftCount(imm8 >> 1)) failed: illegal shift count"

Reviewed-by: vlivanov, kvn, chagedorn
This commit is contained in:
Tobias Hartmann 2020-11-24 16:52:13 +00:00
parent 3b3e90ecad
commit 1c4c99eae2
5 changed files with 181 additions and 66 deletions

View File

@ -4905,7 +4905,7 @@ void Assembler::ret(int imm16) {
}
void Assembler::roll(Register dst, int imm8) {
assert(isShiftCount(imm8 >> 1), "illegal shift count");
assert(isShiftCount(imm8), "illegal shift count");
int encode = prefix_and_encode(dst->encoding());
if (imm8 == 1) {
emit_int16((unsigned char)0xD1, (0xC0 | encode));
@ -4920,7 +4920,7 @@ void Assembler::roll(Register dst) {
}
void Assembler::rorl(Register dst, int imm8) {
assert(isShiftCount(imm8 >> 1), "illegal shift count");
assert(isShiftCount(imm8), "illegal shift count");
int encode = prefix_and_encode(dst->encoding());
if (imm8 == 1) {
emit_int16((unsigned char)0xD1, (0xC8 | encode));

View File

@ -767,22 +767,22 @@ Node* OrINode::Ideal(PhaseGVN* phase, bool can_reshape) {
int ropcode = in(2)->Opcode();
if (Matcher::match_rule_supported(Op_RotateLeft) &&
lopcode == Op_LShiftI && ropcode == Op_URShiftI && in(1)->in(1) == in(2)->in(1)) {
Node* lshift = in(1)->in(2);
Node* rshift = in(2)->in(2);
Node* shift = rotate_shift(phase, lshift, rshift, 0x1F);
if (shift != NULL) {
return new RotateLeftNode(in(1)->in(1), shift, TypeInt::INT);
}
return NULL;
Node* lshift = in(1)->in(2);
Node* rshift = in(2)->in(2);
Node* shift = rotate_shift(phase, lshift, rshift, 0x1F);
if (shift != NULL) {
return new RotateLeftNode(in(1)->in(1), shift, TypeInt::INT);
}
return NULL;
}
if (Matcher::match_rule_supported(Op_RotateRight) &&
lopcode == Op_URShiftI && ropcode == Op_LShiftI && in(1)->in(1) == in(2)->in(1)) {
Node *rshift = in(1)->in(2);
Node *lshift = in(2)->in(2);
Node* shift = rotate_shift(phase, rshift, lshift, 0x1F);
if (shift != NULL) {
return new RotateRightNode(in(1)->in(1), shift, TypeInt::INT);
}
Node* rshift = in(1)->in(2);
Node* lshift = in(2)->in(2);
Node* shift = rotate_shift(phase, rshift, lshift, 0x1F);
if (shift != NULL) {
return new RotateRightNode(in(1)->in(1), shift, TypeInt::INT);
}
}
return NULL;
}

View File

@ -637,35 +637,44 @@ Node *AndLNode::Ideal(PhaseGVN *phase, bool can_reshape) {
//=============================================================================
static int getShiftCon(PhaseGVN *phase, Node *shiftNode, int retVal) {
const Type *t = phase->type(shiftNode->in(2));
if (t == Type::TOP) return retVal; // Right input is dead.
const TypeInt *t2 = t->isa_int();
if (!t2 || !t2->is_con()) return retVal; // Right input is a constant.
return t2->get_con();
static bool const_shift_count(PhaseGVN* phase, Node* shiftNode, int* count) {
const TypeInt* tcount = phase->type(shiftNode->in(2))->isa_int();
if (tcount != NULL && tcount->is_con()) {
*count = tcount->get_con();
return true;
}
return false;
}
static int maskShiftAmount(PhaseGVN *phase, Node *shiftNode, int nBits) {
int shift = getShiftCon(phase, shiftNode, 0);
int maskedShift = shift & (nBits - 1);
if (maskedShift == 0) return 0; // Let Identity() handle 0 shift count.
if (shift != maskedShift) {
shiftNode->set_req(2, phase->intcon(maskedShift)); // Replace shift count with masked value.
PhaseIterGVN* igvn = phase->is_IterGVN();
if (igvn) {
igvn->rehash_node_delayed(shiftNode);
static int maskShiftAmount(PhaseGVN* phase, Node* shiftNode, int nBits) {
int count = 0;
if (const_shift_count(phase, shiftNode, &count)) {
int maskedShift = count & (nBits - 1);
if (maskedShift == 0) {
// Let Identity() handle 0 shift count.
return 0;
}
}
return maskedShift;
if (count != maskedShift) {
shiftNode->set_req(2, phase->intcon(maskedShift)); // Replace shift count with masked value.
PhaseIterGVN* igvn = phase->is_IterGVN();
if (igvn) {
igvn->rehash_node_delayed(shiftNode);
}
}
return maskedShift;
}
return 0;
}
//------------------------------Identity---------------------------------------
Node* LShiftINode::Identity(PhaseGVN* phase) {
return ((getShiftCon(phase, this, -1) & (BitsPerJavaInteger - 1)) == 0) ? in(1) : this;
int count = 0;
if (const_shift_count(phase, this, &count) && (count & (BitsPerJavaInteger - 1)) == 0) {
// Shift by a multiple of 32 does nothing
return in(1);
}
return this;
}
//------------------------------Ideal------------------------------------------
@ -773,7 +782,12 @@ const Type* LShiftINode::Value(PhaseGVN* phase) const {
//=============================================================================
//------------------------------Identity---------------------------------------
Node* LShiftLNode::Identity(PhaseGVN* phase) {
return ((getShiftCon(phase, this, -1) & (BitsPerJavaLong - 1)) == 0) ? in(1) : this;
int count = 0;
if (const_shift_count(phase, this, &count) && (count & (BitsPerJavaLong - 1)) == 0) {
// Shift by a multiple of 64 does nothing
return in(1);
}
return this;
}
//------------------------------Ideal------------------------------------------
@ -878,26 +892,30 @@ const Type* LShiftLNode::Value(PhaseGVN* phase) const {
//=============================================================================
//------------------------------Identity---------------------------------------
Node* RShiftINode::Identity(PhaseGVN* phase) {
int shift = getShiftCon(phase, this, -1);
if (shift == -1) return this;
if ((shift & (BitsPerJavaInteger - 1)) == 0) return in(1);
// Check for useless sign-masking
if (in(1)->Opcode() == Op_LShiftI &&
in(1)->req() == 3 &&
in(1)->in(2) == in(2)) {
shift &= BitsPerJavaInteger-1; // semantics of Java shifts
// Compute masks for which this shifting doesn't change
int lo = (-1 << (BitsPerJavaInteger - ((uint)shift)-1)); // FFFF8000
int hi = ~lo; // 00007FFF
const TypeInt *t11 = phase->type(in(1)->in(1))->isa_int();
if (!t11) return this;
// Does actual value fit inside of mask?
if (lo <= t11->_lo && t11->_hi <= hi) {
return in(1)->in(1); // Then shifting is a nop
int count = 0;
if (const_shift_count(phase, this, &count)) {
if ((count & (BitsPerJavaInteger - 1)) == 0) {
// Shift by a multiple of 32 does nothing
return in(1);
}
// Check for useless sign-masking
if (in(1)->Opcode() == Op_LShiftI &&
in(1)->req() == 3 &&
in(1)->in(2) == in(2)) {
count &= BitsPerJavaInteger-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();
if (t11 == NULL) {
return this;
}
// Does actual value fit inside of mask?
if (lo <= t11->_lo && t11->_hi <= hi) {
return in(1)->in(1); // Then shifting is a nop
}
}
}
return this;
}
@ -1082,8 +1100,11 @@ const Type* RShiftLNode::Value(PhaseGVN* phase) const {
//=============================================================================
//------------------------------Identity---------------------------------------
Node* URShiftINode::Identity(PhaseGVN* phase) {
int shift = getShiftCon(phase, this, -1);
if ((shift & (BitsPerJavaInteger - 1)) == 0) return in(1);
int count = 0;
if (const_shift_count(phase, this, &count) && (count & (BitsPerJavaInteger - 1)) == 0) {
// Shift by a multiple of 32 does nothing
return in(1);
}
// Check for "((x << LogBytesPerWord) + (wordSize-1)) >> LogBytesPerWord" which is just "x".
// Happens during new-array length computation.
@ -1266,7 +1287,12 @@ const Type* URShiftINode::Value(PhaseGVN* phase) const {
//=============================================================================
//------------------------------Identity---------------------------------------
Node* URShiftLNode::Identity(PhaseGVN* phase) {
return ((getShiftCon(phase, this, -1) & (BitsPerJavaLong - 1)) == 0) ? in(1) : this;
int count = 0;
if (const_shift_count(phase, this, &count) && (count & (BitsPerJavaLong - 1)) == 0) {
// Shift by a multiple of 64 does nothing
return in(1);
}
return this;
}
//------------------------------Ideal------------------------------------------
@ -1444,6 +1470,21 @@ uint MulAddS2INode::hash() const {
//------------------------------Rotate Operations ------------------------------
Node* RotateLeftNode::Identity(PhaseGVN* phase) {
const Type* t1 = phase->type(in(1));
if (t1 == Type::TOP) {
return this;
}
int count = 0;
assert(t1->isa_int() || t1->isa_long(), "Unexpected type");
int mask = (t1->isa_int() ? BitsPerJavaInteger : BitsPerJavaLong) - 1;
if (const_shift_count(phase, this, &count) && (count & mask) == 0) {
// Rotate by a multiple of 32/64 does nothing
return in(1);
}
return this;
}
const Type* RotateLeftNode::Value(PhaseGVN* phase) const {
const Type* t1 = phase->type(in(1));
const Type* t2 = phase->type(in(2));
@ -1460,11 +1501,10 @@ const Type* RotateLeftNode::Value(PhaseGVN* phase) const {
if (r1 == TypeInt::ZERO) {
return TypeInt::ZERO;
}
// Shift by zero does nothing
// Rotate by zero does nothing
if (r2 == TypeInt::ZERO) {
return r1;
}
if (r1->is_con() && r2->is_con()) {
int shift = r2->get_con() & (BitsPerJavaInteger - 1); // semantics of Java shifts
return TypeInt::make((r1->get_con() << shift) | (r1->get_con() >> (32 - shift)));
@ -1479,11 +1519,10 @@ const Type* RotateLeftNode::Value(PhaseGVN* phase) const {
if (r1 == TypeLong::ZERO) {
return TypeLong::ZERO;
}
// Shift by zero does nothing
// Rotate by zero does nothing
if (r2 == TypeInt::ZERO) {
return r1;
}
if (r1->is_con() && r2->is_con()) {
int shift = r2->get_con() & (BitsPerJavaLong - 1); // semantics of Java shifts
return TypeLong::make((r1->get_con() << shift) | (r1->get_con() >> (64 - shift)));
@ -1508,6 +1547,21 @@ Node* RotateLeftNode::Ideal(PhaseGVN *phase, bool can_reshape) {
return NULL;
}
Node* RotateRightNode::Identity(PhaseGVN* phase) {
const Type* t1 = phase->type(in(1));
if (t1 == Type::TOP) {
return this;
}
int count = 0;
assert(t1->isa_int() || t1->isa_long(), "Unexpected type");
int mask = (t1->isa_int() ? BitsPerJavaInteger : BitsPerJavaLong) - 1;
if (const_shift_count(phase, this, &count) && (count & mask) == 0) {
// Rotate by a multiple of 32/64 does nothing
return in(1);
}
return this;
}
const Type* RotateRightNode::Value(PhaseGVN* phase) const {
const Type* t1 = phase->type(in(1));
const Type* t2 = phase->type(in(2));
@ -1524,7 +1578,7 @@ const Type* RotateRightNode::Value(PhaseGVN* phase) const {
if (r1 == TypeInt::ZERO) {
return TypeInt::ZERO;
}
// Shift by zero does nothing
// Rotate by zero does nothing
if (r2 == TypeInt::ZERO) {
return r1;
}
@ -1533,7 +1587,6 @@ const Type* RotateRightNode::Value(PhaseGVN* phase) const {
return TypeInt::make((r1->get_con() >> shift) | (r1->get_con() << (32 - shift)));
}
return TypeInt::INT;
} else {
assert(t1->isa_long(), "Type must be a long");
const TypeLong* r1 = t1->is_long();
@ -1542,7 +1595,7 @@ const Type* RotateRightNode::Value(PhaseGVN* phase) const {
if (r1 == TypeLong::ZERO) {
return TypeLong::ZERO;
}
// Shift by zero does nothing
// Rotate by zero does nothing
if (r2 == TypeInt::ZERO) {
return r1;
}

View File

@ -220,6 +220,7 @@ class RotateLeftNode : public TypeNode {
init_req(2, in2);
}
virtual int Opcode() const;
virtual Node* Identity(PhaseGVN* phase);
virtual const Type* Value(PhaseGVN* phase) const;
virtual Node* Ideal(PhaseGVN* phase, bool can_reshape);
};
@ -232,6 +233,7 @@ class RotateRightNode : public TypeNode {
init_req(2, in2);
}
virtual int Opcode() const;
virtual Node* Identity(PhaseGVN* phase);
virtual const Type* Value(PhaseGVN* phase) const;
};

View File

@ -23,7 +23,7 @@
/**
* @test
* @bug 8248830
* @bug 8248830 8256823
* @summary Support for scalar rotates ([Integer/Long].rotate[Left/Right]).
* @library /test/lib
* @requires vm.compiler2.enabled
@ -280,6 +280,62 @@ public class TestRotate {
verify("Constant long rotateRight pattern = 129", res2 , ref_long_ror_shift_M129[index]);
}
public static void test_rol_int_zero(int val) {
// Count is known to be zero only after loop opts
int count = 42;
for (int i = 0; i < 4; i++) {
if ((i % 2) == 0) {
count = 0;
}
}
int res = Integer.rotateLeft(val, count);
if (res != val) {
throw new RuntimeException("test_rol_int_zero failed: " + res + " != " + val);
}
}
public static void test_rol_long_zero(long val) {
// Count is known to be zero only after loop opts
int count = 42;
for (int i = 0; i < 4; i++) {
if ((i % 2) == 0) {
count = 0;
}
}
long res = Long.rotateLeft(val, count);
if (res != val) {
throw new RuntimeException("test_rol_long_zero failed: " + res + " != " + val);
}
}
public static void test_ror_int_zero(int val) {
// Count is known to be zero only after loop opts
int count = 42;
for (int i = 0; i < 4; i++) {
if ((i % 2) == 0) {
count = 0;
}
}
int res = Integer.rotateRight(val, count);
if (res != val) {
throw new RuntimeException("test_ror_int_zero failed: " + res + " != " + val);
}
}
public static void test_ror_long_zero(long val) {
// Count is known to be zero only after loop opts
int count = 42;
for (int i = 0; i < 4; i++) {
if ((i % 2) == 0) {
count = 0;
}
}
long res = Long.rotateRight(val, count);
if (res != val) {
throw new RuntimeException("test_ror_long_zero failed: " + res + " != " + val);
}
}
public static void main(String args[]) throws Exception {
rand = new Random(8248830);
@ -300,6 +356,10 @@ public class TestRotate {
test_rol_long_const(test_long[j], j);
test_ror_long_const(test_long[j], j);
}
test_rol_int_zero(i);
test_rol_long_zero(i);
test_ror_int_zero(i);
test_ror_long_zero(i);
}
System.out.println("test status : PASS");
} catch (Exception e) {