Skip to content

Commit c466cdf

Browse files
committed
8299546: C2: MulLNode::mul_ring() wrongly returns bottom type due to casting errors with large numbers
Reviewed-by: iveresov, kvn, qamai
1 parent 55aa122 commit c466cdf

File tree

4 files changed

+1041
-73
lines changed

4 files changed

+1041
-73
lines changed

src/hotspot/share/opto/mulnode.cpp

Lines changed: 106 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -281,44 +281,115 @@ Node *MulINode::Ideal(PhaseGVN *phase, bool can_reshape) {
281281
return res; // Return final result
282282
}
283283

284-
//------------------------------mul_ring---------------------------------------
285-
// Compute the product type of two integer ranges into this node.
286-
const Type *MulINode::mul_ring(const Type *t0, const Type *t1) const {
287-
const TypeInt *r0 = t0->is_int(); // Handy access
288-
const TypeInt *r1 = t1->is_int();
289-
290-
// Fetch endpoints of all ranges
291-
jint lo0 = r0->_lo;
292-
double a = (double)lo0;
293-
jint hi0 = r0->_hi;
294-
double b = (double)hi0;
295-
jint lo1 = r1->_lo;
296-
double c = (double)lo1;
297-
jint hi1 = r1->_hi;
298-
double d = (double)hi1;
299-
300-
// Compute all endpoints & check for overflow
301-
int32_t A = java_multiply(lo0, lo1);
302-
if( (double)A != a*c ) return TypeInt::INT; // Overflow?
303-
int32_t B = java_multiply(lo0, hi1);
304-
if( (double)B != a*d ) return TypeInt::INT; // Overflow?
305-
int32_t C = java_multiply(hi0, lo1);
306-
if( (double)C != b*c ) return TypeInt::INT; // Overflow?
307-
int32_t D = java_multiply(hi0, hi1);
308-
if( (double)D != b*d ) return TypeInt::INT; // Overflow?
309-
310-
if( A < B ) { lo0 = A; hi0 = B; } // Sort range endpoints
311-
else { lo0 = B; hi0 = A; }
312-
if( C < D ) {
313-
if( C < lo0 ) lo0 = C;
314-
if( D > hi0 ) hi0 = D;
315-
} else {
316-
if( D < lo0 ) lo0 = D;
317-
if( C > hi0 ) hi0 = C;
284+
// Classes to perform mul_ring() for MulI/MulLNode.
285+
//
286+
// This class checks if all cross products of the left and right input of a multiplication have the same "overflow value".
287+
// Without overflow/underflow:
288+
// Product is positive? High signed multiplication result: 0
289+
// Product is negative? High signed multiplication result: -1
290+
//
291+
// We normalize these values (see normalize_overflow_value()) such that we get the same "overflow value" by adding 1 if
292+
// the product is negative. This allows us to compare all the cross product "overflow values". If one is different,
293+
// compared to the others, then we know that this multiplication has a different number of over- or underflows compared
294+
// to the others. In this case, we need to use bottom type and cannot guarantee a better type. Otherwise, we can take
295+
// the min und max of all computed cross products as type of this Mul node.
296+
template<typename IntegerType>
297+
class IntegerMulRing {
298+
using NativeType = std::conditional_t<std::is_same<TypeInt, IntegerType>::value, jint, jlong>;
299+
300+
NativeType _lo_left;
301+
NativeType _lo_right;
302+
NativeType _hi_left;
303+
NativeType _hi_right;
304+
NativeType _lo_lo_product;
305+
NativeType _lo_hi_product;
306+
NativeType _hi_lo_product;
307+
NativeType _hi_hi_product;
308+
short _widen_left;
309+
short _widen_right;
310+
311+
static const Type* overflow_type();
312+
static NativeType multiply_high_signed_overflow_value(NativeType x, NativeType y);
313+
314+
// Pre-compute cross products which are used at several places
315+
void compute_cross_products() {
316+
_lo_lo_product = java_multiply(_lo_left, _lo_right);
317+
_lo_hi_product = java_multiply(_lo_left, _hi_right);
318+
_hi_lo_product = java_multiply(_hi_left, _lo_right);
319+
_hi_hi_product = java_multiply(_hi_left, _hi_right);
320+
}
321+
322+
bool cross_products_not_same_overflow() const {
323+
const NativeType lo_lo_high_product = multiply_high_signed_overflow_value(_lo_left, _lo_right);
324+
const NativeType lo_hi_high_product = multiply_high_signed_overflow_value(_lo_left, _hi_right);
325+
const NativeType hi_lo_high_product = multiply_high_signed_overflow_value(_hi_left, _lo_right);
326+
const NativeType hi_hi_high_product = multiply_high_signed_overflow_value(_hi_left, _hi_right);
327+
return lo_lo_high_product != lo_hi_high_product ||
328+
lo_hi_high_product != hi_lo_high_product ||
329+
hi_lo_high_product != hi_hi_high_product;
330+
}
331+
332+
static NativeType normalize_overflow_value(const NativeType x, const NativeType y, NativeType result) {
333+
return java_multiply(x, y) < 0 ? result + 1 : result;
334+
}
335+
336+
public:
337+
IntegerMulRing(const IntegerType* left, const IntegerType* right) : _lo_left(left->_lo), _lo_right(right->_lo),
338+
_hi_left(left->_hi), _hi_right(right->_hi), _widen_left(left->_widen), _widen_right(right->_widen) {
339+
compute_cross_products();
340+
}
341+
342+
// Compute the product type by multiplying the two input type ranges. We take the minimum and maximum of all possible
343+
// values (requires 4 multiplications of all possible combinations of the two range boundary values). If any of these
344+
// multiplications overflows/underflows, we need to make sure that they all have the same number of overflows/underflows
345+
// If that is not the case, we return the bottom type to cover all values due to the inconsistent overflows/underflows).
346+
const Type* compute() const {
347+
if (cross_products_not_same_overflow()) {
348+
return overflow_type();
349+
}
350+
const NativeType min = MIN4(_lo_lo_product, _lo_hi_product, _hi_lo_product, _hi_hi_product);
351+
const NativeType max = MAX4(_lo_lo_product, _lo_hi_product, _hi_lo_product, _hi_hi_product);
352+
return IntegerType::make(min, max, MAX2(_widen_left, _widen_right));
318353
}
319-
return TypeInt::make(lo0, hi0, MAX2(r0->_widen,r1->_widen));
354+
};
355+
356+
357+
template <>
358+
const Type* IntegerMulRing<TypeInt>::overflow_type() {
359+
return TypeInt::INT;
360+
}
361+
362+
template <>
363+
jint IntegerMulRing<TypeInt>::multiply_high_signed_overflow_value(const jint x, const jint y) {
364+
const jlong x_64 = x;
365+
const jlong y_64 = y;
366+
const jlong product = x_64 * y_64;
367+
const jint result = (jint)((uint64_t)product >> 32u);
368+
return normalize_overflow_value(x, y, result);
369+
}
370+
371+
template <>
372+
const Type* IntegerMulRing<TypeLong>::overflow_type() {
373+
return TypeLong::LONG;
320374
}
321375

376+
template <>
377+
jlong IntegerMulRing<TypeLong>::multiply_high_signed_overflow_value(const jlong x, const jlong y) {
378+
const jlong result = multiply_high_signed(x, y);
379+
return normalize_overflow_value(x, y, result);
380+
}
381+
382+
// Compute the product type of two integer ranges into this node.
383+
const Type* MulINode::mul_ring(const Type* type_left, const Type* type_right) const {
384+
const IntegerMulRing<TypeInt> integer_mul_ring(type_left->is_int(), type_right->is_int());
385+
return integer_mul_ring.compute();
386+
}
387+
388+
// Compute the product type of two long ranges into this node.
389+
const Type* MulLNode::mul_ring(const Type* type_left, const Type* type_right) const {
390+
const IntegerMulRing<TypeLong> integer_mul_ring(type_left->is_long(), type_right->is_long());
391+
return integer_mul_ring.compute();
392+
}
322393

323394
//=============================================================================
324395
//------------------------------Ideal------------------------------------------
@@ -377,44 +448,6 @@ Node *MulLNode::Ideal(PhaseGVN *phase, bool can_reshape) {
377448
return res; // Return final result
378449
}
379450

380-
//------------------------------mul_ring---------------------------------------
381-
// Compute the product type of two integer ranges into this node.
382-
const Type *MulLNode::mul_ring(const Type *t0, const Type *t1) const {
383-
const TypeLong *r0 = t0->is_long(); // Handy access
384-
const TypeLong *r1 = t1->is_long();
385-
386-
// Fetch endpoints of all ranges
387-
jlong lo0 = r0->_lo;
388-
double a = (double)lo0;
389-
jlong hi0 = r0->_hi;
390-
double b = (double)hi0;
391-
jlong lo1 = r1->_lo;
392-
double c = (double)lo1;
393-
jlong hi1 = r1->_hi;
394-
double d = (double)hi1;
395-
396-
// Compute all endpoints & check for overflow
397-
jlong A = java_multiply(lo0, lo1);
398-
if( (double)A != a*c ) return TypeLong::LONG; // Overflow?
399-
jlong B = java_multiply(lo0, hi1);
400-
if( (double)B != a*d ) return TypeLong::LONG; // Overflow?
401-
jlong C = java_multiply(hi0, lo1);
402-
if( (double)C != b*c ) return TypeLong::LONG; // Overflow?
403-
jlong D = java_multiply(hi0, hi1);
404-
if( (double)D != b*d ) return TypeLong::LONG; // Overflow?
405-
406-
if( A < B ) { lo0 = A; hi0 = B; } // Sort range endpoints
407-
else { lo0 = B; hi0 = A; }
408-
if( C < D ) {
409-
if( C < lo0 ) lo0 = C;
410-
if( D > hi0 ) hi0 = D;
411-
} else {
412-
if( D < lo0 ) lo0 = D;
413-
if( C > hi0 ) hi0 = C;
414-
}
415-
return TypeLong::make(lo0, hi0, MAX2(r0->_widen,r1->_widen));
416-
}
417-
418451
//=============================================================================
419452
//------------------------------mul_ring---------------------------------------
420453
// Compute the product type of two double ranges into this node.

src/hotspot/share/utilities/globalDefinitions.hpp

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1235,7 +1235,22 @@ inline TYPE NAME (TYPE lhs, jint rhs) { \
12351235

12361236
JAVA_INTEGER_SHIFT_OP(<<, java_shift_left, jint, juint)
12371237
JAVA_INTEGER_SHIFT_OP(<<, java_shift_left, jlong, julong)
1238+
12381239
// For signed shift right, assume C++ implementation >> sign extends.
1240+
//
1241+
// C++14 5.8/3: In the description of "E1 >> E2" it says "If E1 has a signed type
1242+
// and a negative value, the resulting value is implementation-defined."
1243+
//
1244+
// However, C++20 7.6.7/3 further defines integral arithmetic, as part of
1245+
// requiring two's-complement behavior.
1246+
// https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0907r3.html
1247+
// https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1236r1.html
1248+
// The corresponding C++20 text is "Right-shift on signed integral types is an
1249+
// arithmetic right shift, which performs sign-extension."
1250+
//
1251+
// As discussed in the two's complement proposal, all known modern C++ compilers
1252+
// already behave that way. And it is unlikely any would go off and do something
1253+
// different now, with C++20 tightening things up.
12391254
JAVA_INTEGER_SHIFT_OP(>>, java_shift_right, jint, jint)
12401255
JAVA_INTEGER_SHIFT_OP(>>, java_shift_right, jlong, jlong)
12411256
// For >>> use C++ unsigned >>.
@@ -1266,6 +1281,38 @@ SATURATED_INTEGER_OP(+, saturated_add, uint, uint)
12661281

12671282
#undef SATURATED_INTEGER_OP
12681283

1284+
// Taken from rom section 8-2 of Henry S. Warren, Jr., Hacker's Delight (2nd ed.) (Addison Wesley, 2013), 173-174.
1285+
inline uint64_t multiply_high_unsigned(const uint64_t x, const uint64_t y) {
1286+
const uint64_t x1 = x >> 32u;
1287+
const uint64_t x2 = x & 0xFFFFFFFF;
1288+
const uint64_t y1 = y >> 32u;
1289+
const uint64_t y2 = y & 0xFFFFFFFF;
1290+
const uint64_t z2 = x2 * y2;
1291+
const uint64_t t = x1 * y2 + (z2 >> 32u);
1292+
uint64_t z1 = t & 0xFFFFFFFF;
1293+
const uint64_t z0 = t >> 32u;
1294+
z1 += x2 * y1;
1295+
1296+
return x1 * y1 + z0 + (z1 >> 32u);
1297+
}
1298+
1299+
// Taken from java.lang.Math::multiplyHigh which uses the technique from section 8-2 of Henry S. Warren, Jr.,
1300+
// Hacker's Delight (2nd ed.) (Addison Wesley, 2013), 173-174 but adapted for signed longs.
1301+
inline int64_t multiply_high_signed(const int64_t x, const int64_t y) {
1302+
const jlong x1 = java_shift_right((jlong)x, 32);
1303+
const jlong x2 = x & 0xFFFFFFFF;
1304+
const jlong y1 = java_shift_right((jlong)y, 32);
1305+
const jlong y2 = y & 0xFFFFFFFF;
1306+
1307+
const uint64_t z2 = x2 * y2;
1308+
const int64_t t = x1 * y2 + (z2 >> 32u); // Unsigned shift
1309+
int64_t z1 = t & 0xFFFFFFFF;
1310+
const int64_t z0 = java_shift_right((jlong)t, 32);
1311+
z1 += x2 * y1;
1312+
1313+
return x1 * y1 + z0 + java_shift_right((jlong)z1, 32);
1314+
}
1315+
12691316
// Dereference vptr
12701317
// All C++ compilers that we know of have the vtbl pointer in the first
12711318
// word. If there are exceptions, this function needs to be made compiler

0 commit comments

Comments
 (0)