Skip to content

Commit e678050

Browse files
author
Quan Anh Mai
committed
8367341: C2: apply KnownBits and unsigned bounds to And / Or operations
Reviewed-by: hgreule, epeter
1 parent 00050f8 commit e678050

File tree

9 files changed

+651
-334
lines changed

9 files changed

+651
-334
lines changed

src/hotspot/share/opto/addnode.cpp

Lines changed: 9 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,8 @@
3131
#include "opto/movenode.hpp"
3232
#include "opto/mulnode.hpp"
3333
#include "opto/phaseX.hpp"
34+
#include "opto/rangeinference.hpp"
3435
#include "opto/subnode.hpp"
35-
#include "opto/utilities/xor.hpp"
3636
#include "runtime/stubRoutines.hpp"
3737

3838
// Portions of code courtesy of Clifford Click
@@ -1011,35 +1011,8 @@ Node* OrINode::Ideal(PhaseGVN* phase, bool can_reshape) {
10111011
// the logical operations the ring's ADD is really a logical OR function.
10121012
// This also type-checks the inputs for sanity. Guaranteed never to
10131013
// be passed a TOP or BOTTOM type, these are filtered out by pre-check.
1014-
const Type *OrINode::add_ring( const Type *t0, const Type *t1 ) const {
1015-
const TypeInt *r0 = t0->is_int(); // Handy access
1016-
const TypeInt *r1 = t1->is_int();
1017-
1018-
// If both args are bool, can figure out better types
1019-
if ( r0 == TypeInt::BOOL ) {
1020-
if ( r1 == TypeInt::ONE) {
1021-
return TypeInt::ONE;
1022-
} else if ( r1 == TypeInt::BOOL ) {
1023-
return TypeInt::BOOL;
1024-
}
1025-
} else if ( r0 == TypeInt::ONE ) {
1026-
if ( r1 == TypeInt::BOOL ) {
1027-
return TypeInt::ONE;
1028-
}
1029-
}
1030-
1031-
// If either input is all ones, the output is all ones.
1032-
// x | ~0 == ~0 <==> x | -1 == -1
1033-
if (r0 == TypeInt::MINUS_1 || r1 == TypeInt::MINUS_1) {
1034-
return TypeInt::MINUS_1;
1035-
}
1036-
1037-
// If either input is not a constant, just return all integers.
1038-
if( !r0->is_con() || !r1->is_con() )
1039-
return TypeInt::INT; // Any integer, but still no symbols.
1040-
1041-
// Otherwise just OR them bits.
1042-
return TypeInt::make( r0->get_con() | r1->get_con() );
1014+
const Type* OrINode::add_ring(const Type* t1, const Type* t2) const {
1015+
return RangeInference::infer_or(t1->is_int(), t2->is_int());
10431016
}
10441017

10451018
//=============================================================================
@@ -1087,22 +1060,8 @@ Node* OrLNode::Ideal(PhaseGVN* phase, bool can_reshape) {
10871060
}
10881061

10891062
//------------------------------add_ring---------------------------------------
1090-
const Type *OrLNode::add_ring( const Type *t0, const Type *t1 ) const {
1091-
const TypeLong *r0 = t0->is_long(); // Handy access
1092-
const TypeLong *r1 = t1->is_long();
1093-
1094-
// If either input is all ones, the output is all ones.
1095-
// x | ~0 == ~0 <==> x | -1 == -1
1096-
if (r0 == TypeLong::MINUS_1 || r1 == TypeLong::MINUS_1) {
1097-
return TypeLong::MINUS_1;
1098-
}
1099-
1100-
// If either input is not a constant, just return all integers.
1101-
if( !r0->is_con() || !r1->is_con() )
1102-
return TypeLong::LONG; // Any integer, but still no symbols.
1103-
1104-
// Otherwise just OR them bits.
1105-
return TypeLong::make( r0->get_con() | r1->get_con() );
1063+
const Type* OrLNode::add_ring(const Type* t1, const Type* t2) const {
1064+
return RangeInference::infer_or(t1->is_long(), t2->is_long());
11061065
}
11071066

11081067
//---------------------------Helper -------------------------------------------
@@ -1189,46 +1148,14 @@ const Type* XorINode::Value(PhaseGVN* phase) const {
11891148
// the logical operations the ring's ADD is really a logical OR function.
11901149
// This also type-checks the inputs for sanity. Guaranteed never to
11911150
// be passed a TOP or BOTTOM type, these are filtered out by pre-check.
1192-
const Type *XorINode::add_ring( const Type *t0, const Type *t1 ) const {
1193-
const TypeInt *r0 = t0->is_int(); // Handy access
1194-
const TypeInt *r1 = t1->is_int();
1195-
1196-
if (r0->is_con() && r1->is_con()) {
1197-
// compute constant result
1198-
return TypeInt::make(r0->get_con() ^ r1->get_con());
1199-
}
1200-
1201-
// At least one of the arguments is not constant
1202-
1203-
if (r0->_lo >= 0 && r1->_lo >= 0) {
1204-
// Combine [r0->_lo, r0->_hi] ^ [r0->_lo, r1->_hi] -> [0, upper_bound]
1205-
jint upper_bound = xor_upper_bound_for_ranges<jint, juint>(r0->_hi, r1->_hi);
1206-
return TypeInt::make(0, upper_bound, MAX2(r0->_widen, r1->_widen));
1207-
}
1208-
1209-
return TypeInt::INT;
1151+
const Type* XorINode::add_ring(const Type* t1, const Type* t2) const {
1152+
return RangeInference::infer_xor(t1->is_int(), t2->is_int());
12101153
}
12111154

12121155
//=============================================================================
12131156
//------------------------------add_ring---------------------------------------
1214-
const Type *XorLNode::add_ring( const Type *t0, const Type *t1 ) const {
1215-
const TypeLong *r0 = t0->is_long(); // Handy access
1216-
const TypeLong *r1 = t1->is_long();
1217-
1218-
if (r0->is_con() && r1->is_con()) {
1219-
// compute constant result
1220-
return TypeLong::make(r0->get_con() ^ r1->get_con());
1221-
}
1222-
1223-
// At least one of the arguments is not constant
1224-
1225-
if (r0->_lo >= 0 && r1->_lo >= 0) {
1226-
// Combine [r0->_lo, r0->_hi] ^ [r0->_lo, r1->_hi] -> [0, upper_bound]
1227-
julong upper_bound = xor_upper_bound_for_ranges<jlong, julong>(r0->_hi, r1->_hi);
1228-
return TypeLong::make(0, upper_bound, MAX2(r0->_widen, r1->_widen));
1229-
}
1230-
1231-
return TypeLong::LONG;
1157+
const Type* XorLNode::add_ring(const Type* t1, const Type* t2) const {
1158+
return RangeInference::infer_xor(t1->is_long(), t2->is_long());
12321159
}
12331160

12341161
Node* XorLNode::Ideal(PhaseGVN* phase, bool can_reshape) {

src/hotspot/share/opto/mulnode.cpp

Lines changed: 5 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
#include "opto/memnode.hpp"
3030
#include "opto/mulnode.hpp"
3131
#include "opto/phaseX.hpp"
32+
#include "opto/rangeinference.hpp"
3233
#include "opto/subnode.hpp"
3334
#include "utilities/powerOfTwo.hpp"
3435

@@ -620,80 +621,14 @@ const Type* MulHiValue(const Type *t1, const Type *t2, const Type *bot) {
620621
return TypeLong::LONG;
621622
}
622623

623-
template<typename IntegerType>
624-
static const IntegerType* and_value(const IntegerType* r0, const IntegerType* r1) {
625-
typedef typename IntegerType::NativeType NativeType;
626-
static_assert(std::is_signed<NativeType>::value, "Native type of IntegerType must be signed!");
627-
628-
int widen = MAX2(r0->_widen, r1->_widen);
629-
630-
// If both types are constants, we can calculate a constant result.
631-
if (r0->is_con() && r1->is_con()) {
632-
return IntegerType::make(r0->get_con() & r1->get_con());
633-
}
634-
635-
// If both ranges are positive, the result will range from 0 up to the hi value of the smaller range. The minimum
636-
// of the two constrains the upper bound because any higher value in the other range will see all zeroes, so it will be masked out.
637-
if (r0->_lo >= 0 && r1->_lo >= 0) {
638-
return IntegerType::make(0, MIN2(r0->_hi, r1->_hi), widen);
639-
}
640-
641-
// If only one range is positive, the result will range from 0 up to that range's maximum value.
642-
// For the operation 'x & C' where C is a positive constant, the result will be in the range [0..C]. With that observation,
643-
// we can say that for any integer c such that 0 <= c <= C will also be in the range [0..C]. Therefore, 'x & [c..C]'
644-
// where c >= 0 will be in the range [0..C].
645-
if (r0->_lo >= 0) {
646-
return IntegerType::make(0, r0->_hi, widen);
647-
}
648-
649-
if (r1->_lo >= 0) {
650-
return IntegerType::make(0, r1->_hi, widen);
651-
}
652-
653-
// At this point, all positive ranges will have already been handled, so the only remaining cases will be negative ranges
654-
// and constants.
655-
656-
assert(r0->_lo < 0 && r1->_lo < 0, "positive ranges should already be handled!");
657-
658-
// As two's complement means that both numbers will start with leading 1s, the lower bound of both ranges will contain
659-
// the common leading 1s of both minimum values. In order to count them with count_leading_zeros, the bits are inverted.
660-
NativeType sel_val = ~MIN2(r0->_lo, r1->_lo);
661-
662-
NativeType min;
663-
if (sel_val == 0) {
664-
// Since count_leading_zeros is undefined at 0, we short-circuit the condition where both ranges have a minimum of -1.
665-
min = -1;
666-
} else {
667-
// To get the number of bits to shift, we count the leading 0-bits and then subtract one, as the sign bit is already set.
668-
int shift_bits = count_leading_zeros(sel_val) - 1;
669-
min = std::numeric_limits<NativeType>::min() >> shift_bits;
670-
}
671-
672-
NativeType max;
673-
if (r0->_hi < 0 && r1->_hi < 0) {
674-
// If both ranges are negative, then the same optimization as both positive ranges will apply, and the smaller hi
675-
// value will mask off any bits set by higher values.
676-
max = MIN2(r0->_hi, r1->_hi);
677-
} else {
678-
// In the case of ranges that cross zero, negative values can cause the higher order bits to be set, so the maximum
679-
// positive value can be as high as the larger hi value.
680-
max = MAX2(r0->_hi, r1->_hi);
681-
}
682-
683-
return IntegerType::make(min, max, widen);
684-
}
685-
686624
//=============================================================================
687625
//------------------------------mul_ring---------------------------------------
688626
// Supplied function returns the product of the inputs IN THE CURRENT RING.
689627
// For the logical operations the ring's MUL is really a logical AND function.
690628
// This also type-checks the inputs for sanity. Guaranteed never to
691629
// be passed a TOP or BOTTOM type, these are filtered out by pre-check.
692-
const Type *AndINode::mul_ring( const Type *t0, const Type *t1 ) const {
693-
const TypeInt* r0 = t0->is_int();
694-
const TypeInt* r1 = t1->is_int();
695-
696-
return and_value<TypeInt>(r0, r1);
630+
const Type* AndINode::mul_ring(const Type* t1, const Type* t2) const {
631+
return RangeInference::infer_and(t1->is_int(), t2->is_int());
697632
}
698633

699634
static bool AndIL_is_zero_element_under_mask(const PhaseGVN* phase, const Node* expr, const Node* mask, BasicType bt);
@@ -822,11 +757,8 @@ Node *AndINode::Ideal(PhaseGVN *phase, bool can_reshape) {
822757
// For the logical operations the ring's MUL is really a logical AND function.
823758
// This also type-checks the inputs for sanity. Guaranteed never to
824759
// be passed a TOP or BOTTOM type, these are filtered out by pre-check.
825-
const Type *AndLNode::mul_ring( const Type *t0, const Type *t1 ) const {
826-
const TypeLong* r0 = t0->is_long();
827-
const TypeLong* r1 = t1->is_long();
828-
829-
return and_value<TypeLong>(r0, r1);
760+
const Type* AndLNode::mul_ring(const Type* t1, const Type* t2) const {
761+
return RangeInference::infer_and(t1->is_long(), t2->is_long());
830762
}
831763

832764
const Type* AndLNode::Value(PhaseGVN* phase) const {

src/hotspot/share/opto/rangeinference.cpp

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@
2525
#include "opto/rangeinference.hpp"
2626
#include "opto/type.hpp"
2727
#include "utilities/intn_t.hpp"
28-
#include "utilities/tuple.hpp"
2928

3029
// If the cardinality of a TypeInt is below this threshold, use min widen, see
3130
// TypeIntPrototype<S, U>::normalize_widen
@@ -688,6 +687,8 @@ template class TypeIntPrototype<intn_t<1>, uintn_t<1>>;
688687
template class TypeIntPrototype<intn_t<2>, uintn_t<2>>;
689688
template class TypeIntPrototype<intn_t<3>, uintn_t<3>>;
690689
template class TypeIntPrototype<intn_t<4>, uintn_t<4>>;
690+
template class TypeIntPrototype<intn_t<5>, uintn_t<5>>;
691+
template class TypeIntPrototype<intn_t<6>, uintn_t<6>>;
691692

692693
// Compute the meet of 2 types. When dual is true, the subset relation in CT is
693694
// reversed. This means that the result of 2 CTs would be the intersection of
@@ -709,10 +710,7 @@ const Type* TypeIntHelper::int_type_xmeet(const CT* i1, const Type* t2) {
709710

710711
if (!i1->_is_dual) {
711712
// meet (a.k.a union)
712-
return CT::make_or_top(TypeIntPrototype<S, U>{{MIN2(i1->_lo, i2->_lo), MAX2(i1->_hi, i2->_hi)},
713-
{MIN2(i1->_ulo, i2->_ulo), MAX2(i1->_uhi, i2->_uhi)},
714-
{i1->_bits._zeros & i2->_bits._zeros, i1->_bits._ones & i2->_bits._ones}},
715-
MAX2(i1->_widen, i2->_widen), false);
713+
return int_type_union(i1, i2);
716714
} else {
717715
// join (a.k.a intersection)
718716
return CT::make_or_top(TypeIntPrototype<S, U>{{MAX2(i1->_lo, i2->_lo), MIN2(i1->_hi, i2->_hi)},

0 commit comments

Comments
 (0)