8315066: Add unsigned bounds and known bits to TypeInt/Long

Co-authored-by: Emanuel Peter <epeter@openjdk.org>
Reviewed-by: epeter, kvn, jbhateja
This commit is contained in:
Quan Anh Mai 2025-06-13 01:05:44 +00:00
parent 523a4efe1c
commit 991097b7bf
13 changed files with 2251 additions and 575 deletions

View File

@ -498,7 +498,11 @@ Node* ConstraintCastNode::make_cast_for_type(Node* c, Node* in, const Type* type
Node* ConstraintCastNode::optimize_integer_cast(PhaseGVN* phase, BasicType bt) {
PhaseIterGVN *igvn = phase->is_IterGVN();
const TypeInteger* this_type = this->type()->is_integer(bt);
const TypeInteger* this_type = this->type()->isa_integer(bt);
if (this_type == nullptr) {
return nullptr;
}
Node* z = in(1);
const TypeInteger* rx = nullptr;
const TypeInteger* ry = nullptr;

View File

@ -4521,7 +4521,9 @@ Node* Compile::conv_I2X_index(PhaseGVN* phase, Node* idx, const TypeInt* sizetyp
// number. (The prior range check has ensured this.)
// This assertion is used by ConvI2LNode::Ideal.
int index_max = max_jint - 1; // array size is max_jint, index is one less
if (sizetype != nullptr) index_max = sizetype->_hi - 1;
if (sizetype != nullptr && sizetype->_hi > 0) {
index_max = sizetype->_hi - 1;
}
const TypeInt* iidxtype = TypeInt::make(0, index_max, Type::WidenMax);
idx = constrained_convI2L(phase, idx, iidxtype, ctrl);
#endif

View File

@ -928,8 +928,8 @@ public:
bool copy_node_notes_to(Node* dest, Node* source);
// Workhorse function to sort out the blocked Node_Notes array:
inline Node_Notes* locate_node_notes(GrowableArray<Node_Notes*>* arr,
int idx, bool can_grow = false);
Node_Notes* locate_node_notes(GrowableArray<Node_Notes*>* arr,
int idx, bool can_grow = false);
void grow_node_notes(GrowableArray<Node_Notes*>* arr, int grow_by);

View File

@ -3853,7 +3853,9 @@ Node* GraphKit::new_array(Node* klass_node, // array klass (maybe variable)
if (tilen != nullptr && tilen->_lo < 0) {
// Add a manual constraint to a positive range. Cf. array_element_address.
jint size_max = fast_size_limit;
if (size_max > tilen->_hi) size_max = tilen->_hi;
if (size_max > tilen->_hi && tilen->_hi >= 0) {
size_max = tilen->_hi;
}
const TypeInt* tlcon = TypeInt::make(0, size_max, Type::WidenMin);
// Only do a narrow I2L conversion if the range check passed.

View File

@ -1046,8 +1046,7 @@ bool IfNode::fold_compares_helper(ProjNode* proj, ProjNode* success, ProjNode* f
if (failtype != nullptr) {
const TypeInt* type2 = filtered_int_type(igvn, n, fail);
if (type2 != nullptr) {
failtype = failtype->join(type2)->is_int();
if (failtype->empty()) {
if (failtype->filter(type2) == Type::TOP) {
// previous if determines the result of this if so
// replace Bool with constant
igvn->replace_input_of(this, 1, igvn->intcon(success->_con));

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,198 @@
/*
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#ifndef SHARE_OPTO_RANGEINFERENCE_HPP
#define SHARE_OPTO_RANGEINFERENCE_HPP
#include "utilities/globalDefinitions.hpp"
#include <type_traits>
class outputStream;
class Type;
class TypeInt;
class TypeLong;
// A simple range in the signed or unsigned domain
template <class T>
class RangeInt {
public:
T _lo;
T _hi;
};
/**
* Bits that are known to be 0 or 1. A value v satisfies this constraint iff
* (v & zeros) == 0 && (v & ones) == ones. I.e, any bit that is 1 in zeros must
* be 0 in v, and any bit that is 1 in ones must be 1 in v.
*
* I.e, for each bit position from 0 to sizeof(U) - 1, the corresponding bits
* of zeros, ones and the allowed bit in v must follow:
*
* zeros ones allowed bits
* 0 0 0 or 1
* 1 0 0
* 0 1 1
* 1 1 none (impossible state)
*
* E.g:
* zeros: 00110100
* ones: 10000010
* Then: 10001010 would satisfy the bit constraints
* while: 10011000 would not since the bit at the 4th position violates
* zeros and the bit at the 7th position violates ones
*
* A KnownBits is sane if there is no position at which a bit must be both set
* and unset at the same time. That is (zeros & ones) == 0.
*/
template <class U>
class KnownBits {
static_assert(U(-1) > U(0), "bit info should be unsigned");
public:
U _zeros;
U _ones;
bool is_satisfied_by(U v) const {
return (v & _zeros) == U(0) && (v & _ones) == _ones;
}
};
// All the information needed to construct a TypeInt/TypeLong, the constraints
// here may be arbitrary and need to be canonicalized to construct a
// TypeInt/TypeLong
template <class S, class U>
class TypeIntPrototype {
public:
static_assert(S(-1) < S(0), "");
static_assert(U(-1) > U(0), "");
static_assert(sizeof(S) == sizeof(U), "");
RangeInt<S> _srange;
RangeInt<U> _urange;
KnownBits<U> _bits;
private:
friend class TypeInt;
friend class TypeLong;
template <class T1, class T2>
friend void test_canonicalize_constraints_exhaustive();
template <class T1, class T2>
friend void test_canonicalize_constraints_simple();
template <class T1, class T2>
friend void test_canonicalize_constraints_random();
// A canonicalized version of a TypeIntPrototype, if the prototype represents
// an empty type, _present is false, otherwise, _data is canonical
class CanonicalizedTypeIntPrototype {
public:
bool _present; // whether this is an empty set
TypeIntPrototype<S, U> _data;
bool empty() const {
return !_present;
}
static CanonicalizedTypeIntPrototype make_empty() {
return {false, {}};
}
};
CanonicalizedTypeIntPrototype canonicalize_constraints() const;
int normalize_widen(int w) const;
#ifdef ASSERT
bool contains(S v) const;
void verify_constraints() const;
#endif // ASSERT
};
// Various helper functions for TypeInt/TypeLong operations
class TypeIntHelper {
public:
// Calculate the cardinality of a TypeInt/TypeLong ignoring the bits
// constraints, the return value is the cardinality minus 1 to not overflow
// with the bottom type
template <class S, class U>
static U cardinality_from_bounds(const RangeInt<S>& srange, const RangeInt<U>& urange) {
static_assert(S(-1) < S(0), "");
static_assert(U(-1) > U(0), "");
static_assert(sizeof(S) == sizeof(U), "");
if (U(srange._lo) == urange._lo) {
// srange is the same as urange
assert(U(srange._hi) == urange._hi, "");
// The cardinality is (hi - lo + 1), we return the result minus 1
return urange._hi - urange._lo;
}
// srange intersects with urange in 2 intervals [srange._lo, urange._hi]
// and [urange._lo, srange._hi]
// The cardinality is (uhi - lo + 1) + (hi - ulo + 1), we return the result
// minus 1
return (urange._hi - U(srange._lo)) + (U(srange._hi) - urange._lo) + U(1);
}
template <class CT>
static const Type* int_type_xmeet(const CT* i1, const Type* t2);
template <class CT>
static bool int_type_is_equal(const CT* t1, const CT* t2) {
return t1->_lo == t2->_lo && t1->_hi == t2->_hi &&
t1->_ulo == t2->_ulo && t1->_uhi == t2->_uhi &&
t1->_bits._zeros == t2->_bits._zeros && t1->_bits._ones == t2->_bits._ones;
}
template <class CT>
static bool int_type_is_subset(const CT* super, const CT* sub) {
return super->_lo <= sub->_lo && super->_hi >= sub->_hi &&
super->_ulo <= sub->_ulo && super->_uhi >= sub->_uhi &&
// All bits that are known in super must also be known to be the same
// value in sub, &~ (and not) is the same as a set subtraction on bit
// sets
(super->_bits._zeros &~ sub->_bits._zeros) == 0 && (super->_bits._ones &~ sub->_bits._ones) == 0;
}
template <class CT>
static const Type* int_type_widen(const CT* new_type, const CT* old_type, const CT* limit_type);
template <class CT>
static const Type* int_type_narrow(const CT* new_type, const CT* old_type);
#ifndef PRODUCT
static const char* intname(char* buf, size_t buf_size, jint n);
static const char* uintname(char* buf, size_t buf_size, juint n);
static const char* longname(char* buf, size_t buf_size, jlong n);
static const char* ulongname(char* buf, size_t buf_size, julong n);
template <class U>
static const char* bitname(char* buf, size_t buf_size, U zeros, U ones);
static void int_type_dump(const TypeInt* t, outputStream* st, bool verbose);
static void int_type_dump(const TypeLong* t, outputStream* st, bool verbose);
#endif // PRODUCT
};
#endif // SHARE_OPTO_RANGEINFERENCE_HPP

View File

@ -40,6 +40,7 @@
#include "opto/matcher.hpp"
#include "opto/node.hpp"
#include "opto/opcodes.hpp"
#include "opto/rangeinference.hpp"
#include "opto/runtime.hpp"
#include "opto/type.hpp"
#include "utilities/checkedCast.hpp"
@ -428,7 +429,6 @@ int Type::uhash( const Type *const t ) {
return (int)t->hash();
}
#define SMALLINT ((juint)3) // a value too insignificant to consider widening
#define POSITIVE_INFINITE_F 0x7f800000 // hex representation for IEEE 754 single precision positive infinite
#define POSITIVE_INFINITE_D 0x7ff0000000000000 // hex representation for IEEE 754 double precision positive infinite
@ -487,44 +487,47 @@ void Type::Initialize_shared(Compile* current) {
TypeInt::MAX = TypeInt::make(max_jint); // Int MAX
TypeInt::MIN = TypeInt::make(min_jint); // Int MIN
TypeInt::MINUS_1 = TypeInt::make(-1); // -1
TypeInt::ZERO = TypeInt::make( 0); // 0
TypeInt::ONE = TypeInt::make( 1); // 1
TypeInt::BOOL = TypeInt::make(0,1, WidenMin); // 0 or 1, FALSE or TRUE.
TypeInt::CC = TypeInt::make(-1, 1, WidenMin); // -1, 0 or 1, condition codes
TypeInt::CC_LT = TypeInt::make(-1,-1, WidenMin); // == TypeInt::MINUS_1
TypeInt::CC_GT = TypeInt::make( 1, 1, WidenMin); // == TypeInt::ONE
TypeInt::CC_EQ = TypeInt::make( 0, 0, WidenMin); // == TypeInt::ZERO
TypeInt::CC_LE = TypeInt::make(-1, 0, WidenMin);
TypeInt::CC_GE = TypeInt::make( 0, 1, WidenMin); // == TypeInt::BOOL
TypeInt::BYTE = TypeInt::make(-128,127, WidenMin); // Bytes
TypeInt::UBYTE = TypeInt::make(0, 255, WidenMin); // Unsigned Bytes
TypeInt::CHAR = TypeInt::make(0,65535, WidenMin); // Java chars
TypeInt::SHORT = TypeInt::make(-32768,32767, WidenMin); // Java shorts
TypeInt::POS = TypeInt::make(0,max_jint, WidenMin); // Non-neg values
TypeInt::POS1 = TypeInt::make(1,max_jint, WidenMin); // Positive values
TypeInt::INT = TypeInt::make(min_jint,max_jint, WidenMax); // 32-bit integers
TypeInt::SYMINT = TypeInt::make(-max_jint,max_jint,WidenMin); // symmetric range
TypeInt::TYPE_DOMAIN = TypeInt::INT;
TypeInt::MINUS_1 = TypeInt::make(-1); // -1
TypeInt::ZERO = TypeInt::make( 0); // 0
TypeInt::ONE = TypeInt::make( 1); // 1
TypeInt::BOOL = TypeInt::make( 0, 1, WidenMin); // 0 or 1, FALSE or TRUE.
TypeInt::CC = TypeInt::make(-1, 1, WidenMin); // -1, 0 or 1, condition codes
TypeInt::CC_LT = TypeInt::make(-1,-1, WidenMin); // == TypeInt::MINUS_1
TypeInt::CC_GT = TypeInt::make( 1, 1, WidenMin); // == TypeInt::ONE
TypeInt::CC_EQ = TypeInt::make( 0, 0, WidenMin); // == TypeInt::ZERO
TypeInt::CC_NE = TypeInt::make_or_top(TypeIntPrototype<jint, juint>{{-1, 1}, {1, max_juint}, {0, 1}}, WidenMin)->is_int();
TypeInt::CC_LE = TypeInt::make(-1, 0, WidenMin);
TypeInt::CC_GE = TypeInt::make( 0, 1, WidenMin); // == TypeInt::BOOL
TypeInt::BYTE = TypeInt::make(-128, 127, WidenMin); // Bytes
TypeInt::UBYTE = TypeInt::make(0, 255, WidenMin); // Unsigned Bytes
TypeInt::CHAR = TypeInt::make(0, 65535, WidenMin); // Java chars
TypeInt::SHORT = TypeInt::make(-32768, 32767, WidenMin); // Java shorts
TypeInt::NON_ZERO = TypeInt::make_or_top(TypeIntPrototype<jint, juint>{{min_jint, max_jint}, {1, max_juint}, {0, 0}}, WidenMin)->is_int();
TypeInt::POS = TypeInt::make(0, max_jint, WidenMin); // Non-neg values
TypeInt::POS1 = TypeInt::make(1, max_jint, WidenMin); // Positive values
TypeInt::INT = TypeInt::make(min_jint, max_jint, WidenMax); // 32-bit integers
TypeInt::SYMINT = TypeInt::make(-max_jint, max_jint, WidenMin); // symmetric range
TypeInt::TYPE_DOMAIN = TypeInt::INT;
// CmpL is overloaded both as the bytecode computation returning
// a trinary (-1,0,+1) integer result AND as an efficient long
// a trinary (-1, 0, +1) integer result AND as an efficient long
// compare returning optimizer ideal-type flags.
assert( TypeInt::CC_LT == TypeInt::MINUS_1, "types must match for CmpL to work" );
assert( TypeInt::CC_GT == TypeInt::ONE, "types must match for CmpL to work" );
assert( TypeInt::CC_EQ == TypeInt::ZERO, "types must match for CmpL to work" );
assert( TypeInt::CC_GE == TypeInt::BOOL, "types must match for CmpL to work" );
assert( (juint)(TypeInt::CC->_hi - TypeInt::CC->_lo) <= SMALLINT, "CC is truly small");
assert(TypeInt::CC_LT == TypeInt::MINUS_1, "types must match for CmpL to work" );
assert(TypeInt::CC_GT == TypeInt::ONE, "types must match for CmpL to work" );
assert(TypeInt::CC_EQ == TypeInt::ZERO, "types must match for CmpL to work" );
assert(TypeInt::CC_GE == TypeInt::BOOL, "types must match for CmpL to work" );
TypeLong::MAX = TypeLong::make(max_jlong); // Long MAX
TypeLong::MIN = TypeLong::make(min_jlong); // Long MIN
TypeLong::MINUS_1 = TypeLong::make(-1); // -1
TypeLong::ZERO = TypeLong::make( 0); // 0
TypeLong::ONE = TypeLong::make( 1); // 1
TypeLong::POS = TypeLong::make(0,max_jlong, WidenMin); // Non-neg values
TypeLong::LONG = TypeLong::make(min_jlong,max_jlong,WidenMax); // 64-bit integers
TypeLong::INT = TypeLong::make((jlong)min_jint,(jlong)max_jint,WidenMin);
TypeLong::UINT = TypeLong::make(0,(jlong)max_juint,WidenMin);
TypeLong::TYPE_DOMAIN = TypeLong::LONG;
TypeLong::MAX = TypeLong::make(max_jlong); // Long MAX
TypeLong::MIN = TypeLong::make(min_jlong); // Long MIN
TypeLong::MINUS_1 = TypeLong::make(-1); // -1
TypeLong::ZERO = TypeLong::make( 0); // 0
TypeLong::ONE = TypeLong::make( 1); // 1
TypeLong::NON_ZERO = TypeLong::make_or_top(TypeIntPrototype<jlong, julong>{{min_jlong, max_jlong}, {1, max_julong}, {0, 0}}, WidenMin)->is_long();
TypeLong::POS = TypeLong::make(0, max_jlong, WidenMin); // Non-neg values
TypeLong::NEG = TypeLong::make(min_jlong, -1, WidenMin);
TypeLong::LONG = TypeLong::make(min_jlong, max_jlong, WidenMax); // 64-bit integers
TypeLong::INT = TypeLong::make((jlong)min_jint, (jlong)max_jint,WidenMin);
TypeLong::UINT = TypeLong::make(0, (jlong)max_juint, WidenMin);
TypeLong::TYPE_DOMAIN = TypeLong::LONG;
const Type **fboth =(const Type**)shared_type_arena->AmallocWords(2*sizeof(Type*));
fboth[0] = Type::CONTROL;
@ -1745,218 +1748,124 @@ const TypeInteger* TypeInteger::minus_1(BasicType bt) {
//=============================================================================
// Convenience common pre-built types.
const TypeInt *TypeInt::MAX; // INT_MAX
const TypeInt *TypeInt::MIN; // INT_MIN
const TypeInt *TypeInt::MINUS_1;// -1
const TypeInt *TypeInt::ZERO; // 0
const TypeInt *TypeInt::ONE; // 1
const TypeInt *TypeInt::BOOL; // 0 or 1, FALSE or TRUE.
const TypeInt *TypeInt::CC; // -1,0 or 1, condition codes
const TypeInt *TypeInt::CC_LT; // [-1] == MINUS_1
const TypeInt *TypeInt::CC_GT; // [1] == ONE
const TypeInt *TypeInt::CC_EQ; // [0] == ZERO
const TypeInt *TypeInt::CC_LE; // [-1,0]
const TypeInt *TypeInt::CC_GE; // [0,1] == BOOL (!)
const TypeInt *TypeInt::BYTE; // Bytes, -128 to 127
const TypeInt *TypeInt::UBYTE; // Unsigned Bytes, 0 to 255
const TypeInt *TypeInt::CHAR; // Java chars, 0-65535
const TypeInt *TypeInt::SHORT; // Java shorts, -32768-32767
const TypeInt *TypeInt::POS; // Positive 32-bit integers or zero
const TypeInt *TypeInt::POS1; // Positive 32-bit integers
const TypeInt *TypeInt::INT; // 32-bit integers
const TypeInt *TypeInt::SYMINT; // symmetric range [-max_jint..max_jint]
const TypeInt *TypeInt::TYPE_DOMAIN; // alias for TypeInt::INT
const TypeInt* TypeInt::MAX; // INT_MAX
const TypeInt* TypeInt::MIN; // INT_MIN
const TypeInt* TypeInt::MINUS_1;// -1
const TypeInt* TypeInt::ZERO; // 0
const TypeInt* TypeInt::ONE; // 1
const TypeInt* TypeInt::BOOL; // 0 or 1, FALSE or TRUE.
const TypeInt* TypeInt::CC; // -1,0 or 1, condition codes
const TypeInt* TypeInt::CC_LT; // [-1] == MINUS_1
const TypeInt* TypeInt::CC_GT; // [1] == ONE
const TypeInt* TypeInt::CC_EQ; // [0] == ZERO
const TypeInt* TypeInt::CC_NE;
const TypeInt* TypeInt::CC_LE; // [-1,0]
const TypeInt* TypeInt::CC_GE; // [0,1] == BOOL (!)
const TypeInt* TypeInt::BYTE; // Bytes, -128 to 127
const TypeInt* TypeInt::UBYTE; // Unsigned Bytes, 0 to 255
const TypeInt* TypeInt::CHAR; // Java chars, 0-65535
const TypeInt* TypeInt::SHORT; // Java shorts, -32768-32767
const TypeInt* TypeInt::NON_ZERO;
const TypeInt* TypeInt::POS; // Positive 32-bit integers or zero
const TypeInt* TypeInt::POS1; // Positive 32-bit integers
const TypeInt* TypeInt::INT; // 32-bit integers
const TypeInt* TypeInt::SYMINT; // symmetric range [-max_jint..max_jint]
const TypeInt* TypeInt::TYPE_DOMAIN; // alias for TypeInt::INT
//------------------------------TypeInt----------------------------------------
TypeInt::TypeInt( jint lo, jint hi, int w ) : TypeInteger(Int, w), _lo(lo), _hi(hi) {
TypeInt::TypeInt(const TypeIntPrototype<jint, juint>& t, int widen, bool dual)
: TypeInteger(Int, t.normalize_widen(widen), dual), _lo(t._srange._lo), _hi(t._srange._hi),
_ulo(t._urange._lo), _uhi(t._urange._hi), _bits(t._bits) {
DEBUG_ONLY(t.verify_constraints());
}
//------------------------------make-------------------------------------------
const TypeInt *TypeInt::make( jint lo ) {
return (TypeInt*)(new TypeInt(lo,lo,WidenMin))->hashcons();
}
static int normalize_int_widen( jint lo, jint hi, int w ) {
// Certain normalizations keep us sane when comparing types.
// The 'SMALLINT' covers constants and also CC and its relatives.
if (lo <= hi) {
if (((juint)hi - lo) <= SMALLINT) w = Type::WidenMin;
if (((juint)hi - lo) >= max_juint) w = Type::WidenMax; // TypeInt::INT
} else {
if (((juint)lo - hi) <= SMALLINT) w = Type::WidenMin;
if (((juint)lo - hi) >= max_juint) w = Type::WidenMin; // dual TypeInt::INT
const Type* TypeInt::make_or_top(const TypeIntPrototype<jint, juint>& t, int widen, bool dual) {
auto canonicalized_t = t.canonicalize_constraints();
if (canonicalized_t.empty()) {
return dual ? Type::BOTTOM : Type::TOP;
}
return w;
return (new TypeInt(canonicalized_t._data, widen, dual))->hashcons()->is_int();
}
const TypeInt *TypeInt::make( jint lo, jint hi, int w ) {
w = normalize_int_widen(lo, hi, w);
return (TypeInt*)(new TypeInt(lo,hi,w))->hashcons();
const TypeInt* TypeInt::make(jint con) {
juint ucon = con;
return (new TypeInt(TypeIntPrototype<jint, juint>{{con, con}, {ucon, ucon}, {~ucon, ucon}},
WidenMin, false))->hashcons()->is_int();
}
//------------------------------meet-------------------------------------------
// Compute the MEET of two types. It returns a new Type representation object
// with reference count equal to the number of Types pointing at it.
// Caller should wrap a Types around it.
const Type *TypeInt::xmeet( const Type *t ) const {
// Perform a fast test for common case; meeting the same types together.
if( this == t ) return this; // Meeting same type?
const TypeInt* TypeInt::make(jint lo, jint hi, int widen) {
assert(lo <= hi, "must be legal bounds");
return make_or_top(TypeIntPrototype<jint, juint>{{lo, hi}, {0, max_juint}, {0, 0}}, widen)->is_int();
}
// Currently "this->_base" is a TypeInt
switch (t->base()) { // Switch on original type
case AnyPtr: // Mixing with oops happens when javac
case RawPtr: // reuses local variables
case OopPtr:
case InstPtr:
case AryPtr:
case MetadataPtr:
case KlassPtr:
case InstKlassPtr:
case AryKlassPtr:
case NarrowOop:
case NarrowKlass:
case Long:
case HalfFloatTop:
case HalfFloatCon:
case HalfFloatBot:
case FloatTop:
case FloatCon:
case FloatBot:
case DoubleTop:
case DoubleCon:
case DoubleBot:
case Bottom: // Ye Olde Default
return Type::BOTTOM;
default: // All else is a mistake
typerr(t);
case Top: // No change
const Type* TypeInt::make_or_top(const TypeIntPrototype<jint, juint>& t, int widen) {
return make_or_top(t, widen, false);
}
bool TypeInt::contains(jint i) const {
assert(!_is_dual, "dual types should only be used for join calculation");
juint u = i;
return i >= _lo && i <= _hi &&
u >= _ulo && u <= _uhi &&
_bits.is_satisfied_by(u);
}
bool TypeInt::contains(const TypeInt* t) const {
assert(!_is_dual && !t->_is_dual, "dual types should only be used for join calculation");
return TypeIntHelper::int_type_is_subset(this, t);
}
const Type* TypeInt::xmeet(const Type* t) const {
return TypeIntHelper::int_type_xmeet(this, t);
}
const Type* TypeInt::xdual() const {
return new TypeInt(TypeIntPrototype<jint, juint>{{_lo, _hi}, {_ulo, _uhi}, _bits},
_widen, !_is_dual);
}
const Type* TypeInt::widen(const Type* old, const Type* limit) const {
assert(!_is_dual, "dual types should only be used for join calculation");
return TypeIntHelper::int_type_widen(this, old->isa_int(), limit->isa_int());
}
const Type* TypeInt::narrow(const Type* old) const {
assert(!_is_dual, "dual types should only be used for join calculation");
if (old == nullptr) {
return this;
case Int: // Int vs Int?
break;
}
// Expand covered set
const TypeInt *r = t->is_int();
return make( MIN2(_lo,r->_lo), MAX2(_hi,r->_hi), MAX2(_widen,r->_widen) );
}
//------------------------------xdual------------------------------------------
// Dual: reverse hi & lo; flip widen
const Type *TypeInt::xdual() const {
int w = normalize_int_widen(_hi,_lo, WidenMax-_widen);
return new TypeInt(_hi,_lo,w);
}
//------------------------------widen------------------------------------------
// Only happens for optimistic top-down optimizations.
const Type *TypeInt::widen( const Type *old, const Type* limit ) const {
// Coming from TOP or such; no widening
if( old->base() != Int ) return this;
const TypeInt *ot = old->is_int();
// If new guy is equal to old guy, no widening
if( _lo == ot->_lo && _hi == ot->_hi )
return old;
// If new guy contains old, then we widened
if( _lo <= ot->_lo && _hi >= ot->_hi ) {
// New contains old
// If new guy is already wider than old, no widening
if( _widen > ot->_widen ) return this;
// If old guy was a constant, do not bother
if (ot->_lo == ot->_hi) return this;
// Now widen new guy.
// Check for widening too far
if (_widen == WidenMax) {
int max = max_jint;
int min = min_jint;
if (limit->isa_int()) {
max = limit->is_int()->_hi;
min = limit->is_int()->_lo;
}
if (min < _lo && _hi < max) {
// If neither endpoint is extremal yet, push out the endpoint
// which is closer to its respective limit.
if (_lo >= 0 || // easy common case
((juint)_lo - min) >= ((juint)max - _hi)) {
// Try to widen to an unsigned range type of 31 bits:
return make(_lo, max, WidenMax);
} else {
return make(min, _hi, WidenMax);
}
}
return TypeInt::INT;
}
// Returned widened new guy
return make(_lo,_hi,_widen+1);
}
// If old guy contains new, then we probably widened too far & dropped to
// bottom. Return the wider fellow.
if ( ot->_lo <= _lo && ot->_hi >= _hi )
return old;
//fatal("Integer value range is not subset");
//return this;
return TypeInt::INT;
}
//------------------------------narrow---------------------------------------
// Only happens for pessimistic optimizations.
const Type *TypeInt::narrow( const Type *old ) const {
if (_lo >= _hi) return this; // already narrow enough
if (old == nullptr) return this;
const TypeInt* ot = old->isa_int();
if (ot == nullptr) return this;
jint olo = ot->_lo;
jint ohi = ot->_hi;
// If new guy is equal to old guy, no narrowing
if (_lo == olo && _hi == ohi) return old;
// If old guy was maximum range, allow the narrowing
if (olo == min_jint && ohi == max_jint) return this;
if (_lo < olo || _hi > ohi)
return this; // doesn't narrow; pretty weird
// The new type narrows the old type, so look for a "death march".
// See comments on PhaseTransform::saturate.
juint nrange = (juint)_hi - _lo;
juint orange = (juint)ohi - olo;
if (nrange < max_juint - 1 && nrange > (orange >> 1) + (SMALLINT*2)) {
// Use the new type only if the range shrinks a lot.
// We do not want the optimizer computing 2^31 point by point.
return old;
}
return this;
return TypeIntHelper::int_type_narrow(this, old->isa_int());
}
//-----------------------------filter------------------------------------------
const Type *TypeInt::filter_helper(const Type *kills, bool include_speculative) const {
const Type* TypeInt::filter_helper(const Type* kills, bool include_speculative) const {
assert(!_is_dual, "dual types should only be used for join calculation");
const TypeInt* ft = join_helper(kills, include_speculative)->isa_int();
if (ft == nullptr || ft->empty())
if (ft == nullptr) {
return Type::TOP; // Canonical empty value
}
assert(!ft->_is_dual, "dual types should only be used for join calculation");
if (ft->_widen < this->_widen) {
// Do not allow the value of kill->_widen to affect the outcome.
// The widen bits must be allowed to run freely through the graph.
ft = TypeInt::make(ft->_lo, ft->_hi, this->_widen);
return (new TypeInt(TypeIntPrototype<jint, juint>{{ft->_lo, ft->_hi}, {ft->_ulo, ft->_uhi}, ft->_bits},
this->_widen, false))->hashcons();
}
return ft;
}
//------------------------------eq---------------------------------------------
// Structural equality check for Type representations
bool TypeInt::eq( const Type *t ) const {
const TypeInt *r = t->is_int(); // Handy access
return r->_lo == _lo && r->_hi == _hi && r->_widen == _widen;
bool TypeInt::eq(const Type* t) const {
const TypeInt* r = t->is_int();
return TypeIntHelper::int_type_is_equal(this, r) && _widen == r->_widen && _is_dual == r->_is_dual;
}
//------------------------------hash-------------------------------------------
// Type-specific hashing function.
uint TypeInt::hash(void) const {
return (uint)_lo + (uint)_hi + (uint)_widen + (uint)Type::Int;
return (uint)_lo + (uint)_hi + (uint)_ulo + (uint)_uhi +
(uint)_bits._zeros + (uint)_bits._ones + (uint)_widen + (uint)_is_dual + (uint)Type::Int;
}
//------------------------------is_finite--------------------------------------
@ -1965,267 +1874,126 @@ bool TypeInt::is_finite() const {
return true;
}
//------------------------------dump2------------------------------------------
// Dump TypeInt
#ifndef PRODUCT
static const char* intname(char* buf, size_t buf_size, jint n) {
if (n == min_jint)
return "min";
else if (n < min_jint + 10000)
os::snprintf_checked(buf, buf_size, "min+" INT32_FORMAT, n - min_jint);
else if (n == max_jint)
return "max";
else if (n > max_jint - 10000)
os::snprintf_checked(buf, buf_size, "max-" INT32_FORMAT, max_jint - n);
else
os::snprintf_checked(buf, buf_size, INT32_FORMAT, n);
return buf;
}
void TypeInt::dump2( Dict &d, uint depth, outputStream *st ) const {
char buf[40], buf2[40];
if (_lo == min_jint && _hi == max_jint)
st->print("int");
else if (is_con())
st->print("int:%s", intname(buf, sizeof(buf), get_con()));
else if (_lo == BOOL->_lo && _hi == BOOL->_hi)
st->print("bool");
else if (_lo == BYTE->_lo && _hi == BYTE->_hi)
st->print("byte");
else if (_lo == CHAR->_lo && _hi == CHAR->_hi)
st->print("char");
else if (_lo == SHORT->_lo && _hi == SHORT->_hi)
st->print("short");
else if (_hi == max_jint)
st->print("int:>=%s", intname(buf, sizeof(buf), _lo));
else if (_lo == min_jint)
st->print("int:<=%s", intname(buf, sizeof(buf), _hi));
else
st->print("int:%s..%s", intname(buf, sizeof(buf), _lo), intname(buf2, sizeof(buf2), _hi));
if (_widen != 0 && this != TypeInt::INT)
st->print(":%.*s", _widen, "wwww");
}
#endif
//------------------------------singleton--------------------------------------
// TRUE if Type is a singleton type, FALSE otherwise. Singletons are simple
// constants.
bool TypeInt::singleton(void) const {
return _lo >= _hi;
return _lo == _hi;
}
bool TypeInt::empty(void) const {
return _lo > _hi;
return false;
}
//=============================================================================
// Convenience common pre-built types.
const TypeLong *TypeLong::MAX;
const TypeLong *TypeLong::MIN;
const TypeLong *TypeLong::MINUS_1;// -1
const TypeLong *TypeLong::ZERO; // 0
const TypeLong *TypeLong::ONE; // 1
const TypeLong *TypeLong::POS; // >=0
const TypeLong *TypeLong::LONG; // 64-bit integers
const TypeLong *TypeLong::INT; // 32-bit subrange
const TypeLong *TypeLong::UINT; // 32-bit unsigned subrange
const TypeLong *TypeLong::TYPE_DOMAIN; // alias for TypeLong::LONG
const TypeLong* TypeLong::MAX;
const TypeLong* TypeLong::MIN;
const TypeLong* TypeLong::MINUS_1;// -1
const TypeLong* TypeLong::ZERO; // 0
const TypeLong* TypeLong::ONE; // 1
const TypeLong* TypeLong::NON_ZERO;
const TypeLong* TypeLong::POS; // >=0
const TypeLong* TypeLong::NEG;
const TypeLong* TypeLong::LONG; // 64-bit integers
const TypeLong* TypeLong::INT; // 32-bit subrange
const TypeLong* TypeLong::UINT; // 32-bit unsigned subrange
const TypeLong* TypeLong::TYPE_DOMAIN; // alias for TypeLong::LONG
//------------------------------TypeLong---------------------------------------
TypeLong::TypeLong(jlong lo, jlong hi, int w) : TypeInteger(Long, w), _lo(lo), _hi(hi) {
TypeLong::TypeLong(const TypeIntPrototype<jlong, julong>& t, int widen, bool dual)
: TypeInteger(Long, t.normalize_widen(widen), dual), _lo(t._srange._lo), _hi(t._srange._hi),
_ulo(t._urange._lo), _uhi(t._urange._hi), _bits(t._bits) {
DEBUG_ONLY(t.verify_constraints());
}
//------------------------------make-------------------------------------------
const TypeLong *TypeLong::make( jlong lo ) {
return (TypeLong*)(new TypeLong(lo,lo,WidenMin))->hashcons();
}
static int normalize_long_widen( jlong lo, jlong hi, int w ) {
// Certain normalizations keep us sane when comparing types.
// The 'SMALLINT' covers constants.
if (lo <= hi) {
if (((julong)hi - lo) <= SMALLINT) w = Type::WidenMin;
if (((julong)hi - lo) >= max_julong) w = Type::WidenMax; // TypeLong::LONG
} else {
if (((julong)lo - hi) <= SMALLINT) w = Type::WidenMin;
if (((julong)lo - hi) >= max_julong) w = Type::WidenMin; // dual TypeLong::LONG
const Type* TypeLong::make_or_top(const TypeIntPrototype<jlong, julong>& t, int widen, bool dual) {
auto canonicalized_t = t.canonicalize_constraints();
if (canonicalized_t.empty()) {
return dual ? Type::BOTTOM : Type::TOP;
}
return w;
return (new TypeLong(canonicalized_t._data, widen, dual))->hashcons()->is_long();
}
const TypeLong *TypeLong::make( jlong lo, jlong hi, int w ) {
w = normalize_long_widen(lo, hi, w);
return (TypeLong*)(new TypeLong(lo,hi,w))->hashcons();
const TypeLong* TypeLong::make(jlong con) {
julong ucon = con;
return (new TypeLong(TypeIntPrototype<jlong, julong>{{con, con}, {ucon, ucon}, {~ucon, ucon}},
WidenMin, false))->hashcons()->is_long();
}
const TypeLong* TypeLong::make(jlong lo, jlong hi, int widen) {
assert(lo <= hi, "must be legal bounds");
return make_or_top(TypeIntPrototype<jlong, julong>{{lo, hi}, {0, max_julong}, {0, 0}}, widen)->is_long();
}
//------------------------------meet-------------------------------------------
// Compute the MEET of two types. It returns a new Type representation object
// with reference count equal to the number of Types pointing at it.
// Caller should wrap a Types around it.
const Type *TypeLong::xmeet( const Type *t ) const {
// Perform a fast test for common case; meeting the same types together.
if( this == t ) return this; // Meeting same type?
const Type* TypeLong::make_or_top(const TypeIntPrototype<jlong, julong>& t, int widen) {
return make_or_top(t, widen, false);
}
// Currently "this->_base" is a TypeLong
switch (t->base()) { // Switch on original type
case AnyPtr: // Mixing with oops happens when javac
case RawPtr: // reuses local variables
case OopPtr:
case InstPtr:
case AryPtr:
case MetadataPtr:
case KlassPtr:
case InstKlassPtr:
case AryKlassPtr:
case NarrowOop:
case NarrowKlass:
case Int:
case HalfFloatTop:
case HalfFloatCon:
case HalfFloatBot:
case FloatTop:
case FloatCon:
case FloatBot:
case DoubleTop:
case DoubleCon:
case DoubleBot:
case Bottom: // Ye Olde Default
return Type::BOTTOM;
default: // All else is a mistake
typerr(t);
case Top: // No change
bool TypeLong::contains(jlong i) const {
assert(!_is_dual, "dual types should only be used for join calculation");
julong u = i;
return i >= _lo && i <= _hi &&
u >= _ulo && u <= _uhi &&
_bits.is_satisfied_by(u);
}
bool TypeLong::contains(const TypeLong* t) const {
assert(!_is_dual && !t->_is_dual, "dual types should only be used for join calculation");
return TypeIntHelper::int_type_is_subset(this, t);
}
const Type* TypeLong::xmeet(const Type* t) const {
return TypeIntHelper::int_type_xmeet(this, t);
}
const Type* TypeLong::xdual() const {
return new TypeLong(TypeIntPrototype<jlong, julong>{{_lo, _hi}, {_ulo, _uhi}, _bits},
_widen, !_is_dual);
}
const Type* TypeLong::widen(const Type* old, const Type* limit) const {
assert(!_is_dual, "dual types should only be used for join calculation");
return TypeIntHelper::int_type_widen(this, old->isa_long(), limit->isa_long());
}
const Type* TypeLong::narrow(const Type* old) const {
assert(!_is_dual, "dual types should only be used for join calculation");
if (old == nullptr) {
return this;
case Long: // Long vs Long?
break;
}
// Expand covered set
const TypeLong *r = t->is_long(); // Turn into a TypeLong
return make( MIN2(_lo,r->_lo), MAX2(_hi,r->_hi), MAX2(_widen,r->_widen) );
}
//------------------------------xdual------------------------------------------
// Dual: reverse hi & lo; flip widen
const Type *TypeLong::xdual() const {
int w = normalize_long_widen(_hi,_lo, WidenMax-_widen);
return new TypeLong(_hi,_lo,w);
}
//------------------------------widen------------------------------------------
// Only happens for optimistic top-down optimizations.
const Type *TypeLong::widen( const Type *old, const Type* limit ) const {
// Coming from TOP or such; no widening
if( old->base() != Long ) return this;
const TypeLong *ot = old->is_long();
// If new guy is equal to old guy, no widening
if( _lo == ot->_lo && _hi == ot->_hi )
return old;
// If new guy contains old, then we widened
if( _lo <= ot->_lo && _hi >= ot->_hi ) {
// New contains old
// If new guy is already wider than old, no widening
if( _widen > ot->_widen ) return this;
// If old guy was a constant, do not bother
if (ot->_lo == ot->_hi) return this;
// Now widen new guy.
// Check for widening too far
if (_widen == WidenMax) {
jlong max = max_jlong;
jlong min = min_jlong;
if (limit->isa_long()) {
max = limit->is_long()->_hi;
min = limit->is_long()->_lo;
}
if (min < _lo && _hi < max) {
// If neither endpoint is extremal yet, push out the endpoint
// which is closer to its respective limit.
if (_lo >= 0 || // easy common case
((julong)_lo - min) >= ((julong)max - _hi)) {
// Try to widen to an unsigned range type of 32/63 bits:
if (max >= max_juint && _hi < max_juint)
return make(_lo, max_juint, WidenMax);
else
return make(_lo, max, WidenMax);
} else {
return make(min, _hi, WidenMax);
}
}
return TypeLong::LONG;
}
// Returned widened new guy
return make(_lo,_hi,_widen+1);
}
// If old guy contains new, then we probably widened too far & dropped to
// bottom. Return the wider fellow.
if ( ot->_lo <= _lo && ot->_hi >= _hi )
return old;
// fatal("Long value range is not subset");
// return this;
return TypeLong::LONG;
}
//------------------------------narrow----------------------------------------
// Only happens for pessimistic optimizations.
const Type *TypeLong::narrow( const Type *old ) const {
if (_lo >= _hi) return this; // already narrow enough
if (old == nullptr) return this;
const TypeLong* ot = old->isa_long();
if (ot == nullptr) return this;
jlong olo = ot->_lo;
jlong ohi = ot->_hi;
// If new guy is equal to old guy, no narrowing
if (_lo == olo && _hi == ohi) return old;
// If old guy was maximum range, allow the narrowing
if (olo == min_jlong && ohi == max_jlong) return this;
if (_lo < olo || _hi > ohi)
return this; // doesn't narrow; pretty weird
// The new type narrows the old type, so look for a "death march".
// See comments on PhaseTransform::saturate.
julong nrange = (julong)_hi - _lo;
julong orange = (julong)ohi - olo;
if (nrange < max_julong - 1 && nrange > (orange >> 1) + (SMALLINT*2)) {
// Use the new type only if the range shrinks a lot.
// We do not want the optimizer computing 2^31 point by point.
return old;
}
return this;
return TypeIntHelper::int_type_narrow(this, old->isa_long());
}
//-----------------------------filter------------------------------------------
const Type *TypeLong::filter_helper(const Type *kills, bool include_speculative) const {
const Type* TypeLong::filter_helper(const Type* kills, bool include_speculative) const {
assert(!_is_dual, "dual types should only be used for join calculation");
const TypeLong* ft = join_helper(kills, include_speculative)->isa_long();
if (ft == nullptr || ft->empty())
if (ft == nullptr) {
return Type::TOP; // Canonical empty value
}
assert(!ft->_is_dual, "dual types should only be used for join calculation");
if (ft->_widen < this->_widen) {
// Do not allow the value of kill->_widen to affect the outcome.
// The widen bits must be allowed to run freely through the graph.
ft = TypeLong::make(ft->_lo, ft->_hi, this->_widen);
return (new TypeLong(TypeIntPrototype<jlong, julong>{{ft->_lo, ft->_hi}, {ft->_ulo, ft->_uhi}, ft->_bits},
this->_widen, false))->hashcons();
}
return ft;
}
//------------------------------eq---------------------------------------------
// Structural equality check for Type representations
bool TypeLong::eq( const Type *t ) const {
const TypeLong *r = t->is_long(); // Handy access
return r->_lo == _lo && r->_hi == _hi && r->_widen == _widen;
bool TypeLong::eq(const Type* t) const {
const TypeLong* r = t->is_long();
return TypeIntHelper::int_type_is_equal(this, r) && _widen == r->_widen && _is_dual == r->_is_dual;
}
//------------------------------hash-------------------------------------------
// Type-specific hashing function.
uint TypeLong::hash(void) const {
return (uint)_lo + (uint)_hi + (uint)_widen + (uint)Type::Long;
return (uint)_lo + (uint)_hi + (uint)_ulo + (uint)_uhi +
(uint)_bits._zeros + (uint)_bits._ones + (uint)_widen + (uint)_is_dual + (uint)Type::Long;
}
//------------------------------is_finite--------------------------------------
@ -2234,72 +2002,36 @@ bool TypeLong::is_finite() const {
return true;
}
//------------------------------dump2------------------------------------------
// Dump TypeLong
#ifndef PRODUCT
static const char* longnamenear(jlong x, const char* xname, char* buf, size_t buf_size, jlong n) {
if (n > x) {
if (n >= x + 10000) return nullptr;
os::snprintf_checked(buf, buf_size, "%s+" JLONG_FORMAT, xname, n - x);
} else if (n < x) {
if (n <= x - 10000) return nullptr;
os::snprintf_checked(buf, buf_size, "%s-" JLONG_FORMAT, xname, x - n);
} else {
return xname;
}
return buf;
}
static const char* longname(char* buf, size_t buf_size, jlong n) {
const char* str;
if (n == min_jlong)
return "min";
else if (n < min_jlong + 10000)
os::snprintf_checked(buf, buf_size, "min+" JLONG_FORMAT, n - min_jlong);
else if (n == max_jlong)
return "max";
else if (n > max_jlong - 10000)
os::snprintf_checked(buf, buf_size, "max-" JLONG_FORMAT, max_jlong - n);
else if ((str = longnamenear(max_juint, "maxuint", buf, buf_size, n)) != nullptr)
return str;
else if ((str = longnamenear(max_jint, "maxint", buf, buf_size, n)) != nullptr)
return str;
else if ((str = longnamenear(min_jint, "minint", buf, buf_size, n)) != nullptr)
return str;
else
os::snprintf_checked(buf, buf_size, JLONG_FORMAT, n);
return buf;
}
void TypeLong::dump2( Dict &d, uint depth, outputStream *st ) const {
char buf[80], buf2[80];
if (_lo == min_jlong && _hi == max_jlong)
st->print("long");
else if (is_con())
st->print("long:%s", longname(buf, sizeof(buf), get_con()));
else if (_hi == max_jlong)
st->print("long:>=%s", longname(buf, sizeof(buf), _lo));
else if (_lo == min_jlong)
st->print("long:<=%s", longname(buf, sizeof(buf), _hi));
else
st->print("long:%s..%s", longname(buf, sizeof(buf), _lo), longname(buf2,sizeof(buf2), _hi));
if (_widen != 0 && this != TypeLong::LONG)
st->print(":%.*s", _widen, "wwww");
}
#endif
//------------------------------singleton--------------------------------------
// TRUE if Type is a singleton type, FALSE otherwise. Singletons are simple
// constants
bool TypeLong::singleton(void) const {
return _lo >= _hi;
return _lo == _hi;
}
bool TypeLong::empty(void) const {
return _lo > _hi;
return false;
}
//------------------------------dump2------------------------------------------
#ifndef PRODUCT
void TypeInt::dump2(Dict& d, uint depth, outputStream* st) const {
TypeIntHelper::int_type_dump(this, st, false);
}
void TypeInt::dump_verbose() const {
TypeIntHelper::int_type_dump(this, tty, true);
}
void TypeLong::dump2(Dict& d, uint depth, outputStream* st) const {
TypeIntHelper::int_type_dump(this, st, false);
}
void TypeLong::dump_verbose() const {
TypeIntHelper::int_type_dump(this, tty, true);
}
#endif
//=============================================================================
// Convenience common pre-built types.
const TypeTuple *TypeTuple::IFBOTH; // Return both arms of IF as reachable
@ -2551,10 +2283,15 @@ const Type *TypeAry::xmeet( const Type *t ) const {
typerr(t);
case Array: { // Meeting 2 arrays?
const TypeAry *a = t->is_ary();
const TypeAry* a = t->is_ary();
const Type* size = _size->xmeet(a->_size);
const TypeInt* isize = size->isa_int();
if (isize == nullptr) {
assert(size == Type::TOP || size == Type::BOTTOM, "");
return size;
}
return TypeAry::make(_elem->meet_speculative(a->_elem),
_size->xmeet(a->_size)->is_int(),
_stable && a->_stable);
isize, _stable && a->_stable);
}
case Top:
break;
@ -4984,10 +4721,12 @@ const TypeInt* TypeAryPtr::narrow_size_type(const TypeInt* size) const {
chg = true;
}
// Negative length arrays will produce weird intermediate dead fast-path code
if (lo > hi)
if (lo > hi) {
return TypeInt::ZERO;
if (!chg)
}
if (!chg) {
return size;
}
return TypeInt::make(lo, hi, Type::WidenMin);
}
@ -5152,7 +4891,12 @@ const Type *TypeAryPtr::xmeet_helper(const Type *t) const {
case AryPtr: { // Meeting 2 references?
const TypeAryPtr *tap = t->is_aryptr();
int off = meet_offset(tap->offset());
const TypeAry *tary = _ary->meet_speculative(tap->_ary)->is_ary();
const Type* tm = _ary->meet_speculative(tap->_ary);
const TypeAry* tary = tm->isa_ary();
if (tary == nullptr) {
assert(tm == Type::TOP || tm == Type::BOTTOM, "");
return tm;
}
PTR ptr = meet_ptr(tap->ptr());
int instance_id = meet_instance_id(tap->instance_id());
const TypePtr* speculative = xmeet_speculative(tap);

View File

@ -26,6 +26,8 @@
#define SHARE_OPTO_TYPE_HPP
#include "opto/adlcVMDeps.hpp"
#include "opto/compile.hpp"
#include "opto/rangeinference.hpp"
#include "runtime/handles.hpp"
// Portions of code courtesy of Clifford Click
@ -73,6 +75,9 @@ class TypeAryKlassPtr;
class TypeMetadataPtr;
class VerifyMeet;
template <class T, class U>
class TypeIntPrototype;
//------------------------------Type-------------------------------------------
// Basic Type object, represents a set of primitive Values.
// Types are hash-cons'd into a private class dictionary, so only one of each
@ -284,6 +289,10 @@ public:
virtual float getf() const;
double getd() const;
// This has the same semantics as std::dynamic_cast<TypeClass*>(this)
template <typename TypeClass>
const TypeClass* try_cast() const;
const TypeInt *is_int() const;
const TypeInt *isa_int() const; // Returns null if not an Int
const TypeInteger* is_integer(BasicType bt) const;
@ -594,7 +603,12 @@ public:
class TypeInteger : public Type {
protected:
TypeInteger(TYPES t, int w) : Type(t), _widen(w) {}
TypeInteger(TYPES t, int w, bool dual) : Type(t), _is_dual(dual), _widen(w) {}
// Denote that a set is a dual set.
// Dual sets are only used to compute the join of 2 sets, and not used
// outside.
const bool _is_dual;
public:
const short _widen; // Limit on times we widen this sucker
@ -614,82 +628,240 @@ public:
static const TypeInteger* minus_1(BasicType type);
};
//------------------------------TypeInt----------------------------------------
// Class of integer ranges, the set of integers between a lower bound and an
// upper bound, inclusive.
/**
* Definition:
*
* A TypeInt represents a set of non-empty jint values. A jint v is an element
* of a TypeInt iff:
*
* v >= _lo && v <= _hi &&
* juint(v) >= _ulo && juint(v) <= _uhi &&
* _bits.is_satisfied_by(v)
*
* Multiple sets of parameters can represent the same set.
* E.g: consider 2 TypeInt t1, t2
*
* t1._lo = 2, t1._hi = 7, t1._ulo = 0, t1._uhi = 5, t1._bits._zeros = 0x00000000, t1._bits._ones = 0x1
* t2._lo = 3, t2._hi = 5, t2._ulo = 3, t2._uhi = 5, t2._bits._zeros = 0xFFFFFFF8, t2._bits._ones = 0x1
*
* Then, t1 and t2 both represent the set {3, 5}. We can also see that the
* constraints of t2 are the tightest possible. I.e there exists no TypeInt t3
* which also represents {3, 5} such that any of these would be true:
*
* 1) t3._lo > t2._lo
* 2) t3._hi < t2._hi
* 3) t3._ulo > t2._ulo
* 4) t3._uhi < t2._uhi
* 5) (t3._bits._zeros &~ t2._bis._zeros) != 0
* 6) (t3._bits._ones &~ t2._bits._ones) != 0
*
* The 5-th condition mean that the subtraction of the bitsets represented by
* t3._bits._zeros and t2._bits._zeros is not empty, which means that the
* bits in t3._bits._zeros is not a subset of those in t2._bits._zeros, the
* same applies to _bits._ones
*
* To simplify reasoning about the types in optimizations, we canonicalize
* every TypeInt to its tightest form, already at construction. E.g a TypeInt
* t with t._lo < 0 will definitely contain negative values. It also makes it
* trivial to determine if a TypeInt instance is a subset of another.
*
* Lemmas:
*
* 1. Since every TypeInt instance is non-empty and canonicalized, all the
* bounds must also be elements of such TypeInt. Or else, we can tighten the
* bounds by narrowing it by one, which contradicts the assumption of the
* TypeInt being canonical.
*
* 2.
* 2.1. _lo <= jint(_ulo)
* 2.2. _lo <= _hi
* 2.3. _lo <= jint(_uhi)
* 2.4. _ulo <= juint(_lo)
* 2.5. _ulo <= juint(_hi)
* 2.6. _ulo <= _uhi
* 2.7. _hi >= _lo
* 2.8. _hi >= jint(_ulo)
* 2.9. _hi >= jint(_uhi)
* 2.10. _uhi >= juint(_lo)
* 2.11. _uhi >= _ulo
* 2.12. _uhi >= juint(_hi)
*
* Proof of lemma 2:
*
* 2.1. _lo <= jint(_ulo):
* According the lemma 1, _ulo is an element of the TypeInt, so in the
* signed domain, it must not be less than the smallest element of that
* TypeInt, which is _lo. Which means that _lo <= _ulo in the signed
* domain, or in a more programmatical way, _lo <= jint(_ulo).
* 2.2. _lo <= _hi:
* According the lemma 1, _hi is an element of the TypeInt, so in the
* signed domain, it must not be less than the smallest element of that
* TypeInt, which is _lo. Which means that _lo <= _hi.
*
* The other inequalities can be proved in a similar manner.
*
* 3. Given 2 jint values x, y where either both >= 0 or both < 0. Then:
*
* x <= y iff juint(x) <= juint(y)
* I.e. x <= y in the signed domain iff x <= y in the unsigned domain
*
* 4. Either _lo == jint(_ulo) and _hi == jint(_uhi), or each element of a
* TypeInt lies in either interval [_lo, jint(_uhi)] or [jint(_ulo), _hi]
* (note that these intervals are disjoint in this case).
*
* Proof of lemma 4:
*
* For a TypeInt t, there are 3 possible cases:
*
* a. t._lo >= 0, we have:
*
* 0 <= t_lo <= jint(t._ulo) (lemma 2.1)
* juint(t._lo) <= juint(jint(t._ulo)) (lemma 3)
* == t._ulo (juint(jint(v)) == v with juint v)
* <= juint(t._lo) (lemma 2.4)
*
* Which means that t._lo == jint(t._ulo).
*
* Furthermore,
*
* 0 <= t._lo <= t._hi (lemma 2.2)
* 0 <= t._lo <= jint(t._uhi) (lemma 2.3)
* t._hi >= jint(t._uhi) (lemma 2.9)
*
* juint(t._hi) >= juint(jint(t._uhi)) (lemma 3)
* == t._uhi (juint(jint(v)) == v with juint v)
* >= juint(t._hi) (lemma 2.12)
*
* Which means that t._hi == jint(t._uhi).
* In this case, t._lo == jint(t._ulo) and t._hi == jint(t._uhi)
*
* b. t._hi < 0. Similarly, we can conclude that:
* t._lo == jint(t._ulo) and t._hi == jint(t._uhi)
*
* c. t._lo < 0, t._hi >= 0.
*
* Since t._ulo <= juint(t._hi) (lemma 2.5), we must have jint(t._ulo) >= 0
* because all negative values is larger than all non-negative values in the
* unsigned domain.
*
* Since t._uhi >= juint(t._lo) (lemma 2.10), we must have jint(t._uhi) < 0
* similar to the reasoning above.
*
* In this case, each element of t belongs to either [t._lo, jint(t._uhi)] or
* [jint(t._ulo), t._hi].
*
* Below is an illustration of the TypeInt in this case, the intervals that
* the elements can be in are marked using the = symbol. Note how the
* negative range in the signed domain wrap around in the unsigned domain.
*
* Signed:
* -----lo=========uhi---------0--------ulo==========hi-----
* Unsigned:
* 0--------ulo==========hi----------lo=========uhi---------
*
* This property is useful for our analysis of TypeInt values. Additionally,
* it can be seen that _lo and jint(_uhi) are both < 0 or both >= 0, and the
* same applies to jint(_ulo) and _hi.
*
* We call [_lo, jint(_uhi)] and [jint(_ulo), _hi] "simple intervals". Then,
* a TypeInt consists of 2 simple intervals, each of which has its bounds
* being both >= 0 or both < 0. If both simple intervals lie in the same half
* of the integer domain, they must be the same (i.e _lo == jint(_ulo) and
* _hi == jint(_uhi)). Otherwise, [_lo, jint(_uhi)] must lie in the negative
* half and [jint(_ulo), _hi] must lie in the non-negative half of the signed
* domain (equivalently, [_lo, jint(_uhi)] must lie in the upper half and
* [jint(_ulo), _hi] must lie in the lower half of the unsigned domain).
*/
class TypeInt : public TypeInteger {
TypeInt( jint lo, jint hi, int w );
private:
TypeInt(const TypeIntPrototype<jint, juint>& t, int w, bool dual);
static const Type* make_or_top(const TypeIntPrototype<jint, juint>& t, int widen, bool dual);
friend class TypeIntHelper;
protected:
virtual const Type *filter_helper(const Type *kills, bool include_speculative) const;
virtual const Type* filter_helper(const Type* kills, bool include_speculative) const;
public:
typedef jint NativeType;
virtual bool eq( const Type *t ) const;
virtual bool eq(const Type* t) const;
virtual uint hash() const; // Type specific hashing
virtual bool singleton(void) const; // TRUE if type is a singleton
virtual bool empty(void) const; // TRUE if type is vacuous
const jint _lo, _hi; // Lower bound, upper bound
// A value is in the set represented by this TypeInt if it satisfies all
// the below constraints, see contains(jint)
const jint _lo, _hi; // Lower bound, upper bound in the signed domain
const juint _ulo, _uhi; // Lower bound, upper bound in the unsigned domain
const KnownBits<juint> _bits;
static const TypeInt *make(jint lo);
static const TypeInt* make(jint con);
// must always specify w
static const TypeInt *make(jint lo, jint hi, int w);
static const TypeInt* make(jint lo, jint hi, int widen);
static const Type* make_or_top(const TypeIntPrototype<jint, juint>& t, int widen);
// Check for single integer
bool is_con() const { return _lo==_hi; }
bool is_con() const { return _lo == _hi; }
bool is_con(jint i) const { return is_con() && _lo == i; }
jint get_con() const { assert(is_con(), "" ); return _lo; }
jint get_con() const { assert(is_con(), ""); return _lo; }
// Check if a jint/TypeInt is a subset of this TypeInt (i.e. all elements of the
// argument are also elements of this type)
bool contains(jint i) const;
bool contains(const TypeInt* t) const;
virtual bool is_finite() const; // Has a finite value
virtual bool is_finite() const; // Has a finite value
virtual const Type *xmeet( const Type *t ) const;
virtual const Type *xdual() const; // Compute dual right now.
virtual const Type *widen( const Type *t, const Type* limit_type ) const;
virtual const Type *narrow( const Type *t ) const;
virtual const Type* xmeet(const Type* t) const;
virtual const Type* xdual() const; // Compute dual right now.
virtual const Type* widen(const Type* t, const Type* limit_type) const;
virtual const Type* narrow(const Type* t) const;
virtual jlong hi_as_long() const { return _hi; }
virtual jlong lo_as_long() const { return _lo; }
// Do not kill _widen bits.
// Convenience common pre-built types.
static const TypeInt *MAX;
static const TypeInt *MIN;
static const TypeInt *MINUS_1;
static const TypeInt *ZERO;
static const TypeInt *ONE;
static const TypeInt *BOOL;
static const TypeInt *CC;
static const TypeInt *CC_LT; // [-1] == MINUS_1
static const TypeInt *CC_GT; // [1] == ONE
static const TypeInt *CC_EQ; // [0] == ZERO
static const TypeInt *CC_LE; // [-1,0]
static const TypeInt *CC_GE; // [0,1] == BOOL (!)
static const TypeInt *BYTE;
static const TypeInt *UBYTE;
static const TypeInt *CHAR;
static const TypeInt *SHORT;
static const TypeInt *POS;
static const TypeInt *POS1;
static const TypeInt *INT;
static const TypeInt *SYMINT; // symmetric range [-max_jint..max_jint]
static const TypeInt *TYPE_DOMAIN; // alias for TypeInt::INT
static const TypeInt* MAX;
static const TypeInt* MIN;
static const TypeInt* MINUS_1;
static const TypeInt* ZERO;
static const TypeInt* ONE;
static const TypeInt* BOOL;
static const TypeInt* CC;
static const TypeInt* CC_LT; // [-1] == MINUS_1
static const TypeInt* CC_GT; // [1] == ONE
static const TypeInt* CC_EQ; // [0] == ZERO
static const TypeInt* CC_NE; // [-1, 1]
static const TypeInt* CC_LE; // [-1,0]
static const TypeInt* CC_GE; // [0,1] == BOOL (!)
static const TypeInt* BYTE;
static const TypeInt* UBYTE;
static const TypeInt* CHAR;
static const TypeInt* SHORT;
static const TypeInt* NON_ZERO;
static const TypeInt* POS;
static const TypeInt* POS1;
static const TypeInt* INT;
static const TypeInt* SYMINT; // symmetric range [-max_jint..max_jint]
static const TypeInt* TYPE_DOMAIN; // alias for TypeInt::INT
static const TypeInt *as_self(const Type *t) { return t->is_int(); }
static const TypeInt* as_self(const Type* t) { return t->is_int(); }
#ifndef PRODUCT
virtual void dump2( Dict &d, uint depth, outputStream *st ) const;
virtual void dump2(Dict& d, uint depth, outputStream* st) const;
void dump_verbose() const;
#endif
};
//------------------------------TypeLong---------------------------------------
// Class of long integer ranges, the set of integers between a lower bound and
// an upper bound, inclusive.
// Similar to TypeInt
class TypeLong : public TypeInteger {
TypeLong( jlong lo, jlong hi, int w );
private:
TypeLong(const TypeIntPrototype<jlong, julong>& t, int w, bool dual);
static const Type* make_or_top(const TypeIntPrototype<jlong, julong>& t, int widen, bool dual);
friend class TypeIntHelper;
protected:
// Do not kill _widen bits.
virtual const Type *filter_helper(const Type *kills, bool include_speculative) const;
virtual const Type* filter_helper(const Type* kills, bool include_speculative) const;
public:
typedef jlong NativeType;
virtual bool eq( const Type *t ) const;
@ -697,16 +869,25 @@ public:
virtual bool singleton(void) const; // TRUE if type is a singleton
virtual bool empty(void) const; // TRUE if type is vacuous
public:
const jlong _lo, _hi; // Lower bound, upper bound
// A value is in the set represented by this TypeLong if it satisfies all
// the below constraints, see contains(jlong)
const jlong _lo, _hi; // Lower bound, upper bound in the signed domain
const julong _ulo, _uhi; // Lower bound, upper bound in the unsigned domain
const KnownBits<julong> _bits;
static const TypeLong *make(jlong lo);
static const TypeLong* make(jlong con);
// must always specify w
static const TypeLong *make(jlong lo, jlong hi, int w);
static const TypeLong* make(jlong lo, jlong hi, int widen);
static const Type* make_or_top(const TypeIntPrototype<jlong, julong>& t, int widen);
// Check for single integer
bool is_con() const { return _lo==_hi; }
bool is_con() const { return _lo == _hi; }
bool is_con(jlong i) const { return is_con() && _lo == i; }
jlong get_con() const { assert(is_con(), "" ); return _lo; }
// Check if a jlong/TypeLong is a subset of this TypeLong (i.e. all elements of the
// argument are also elements of this type)
bool contains(jlong i) const;
bool contains(const TypeLong* t) const;
// Check for positive 32-bit value.
int is_positive_int() const { return _lo >= 0 && _hi <= (jlong)max_jint; }
@ -716,27 +897,30 @@ public:
virtual jlong hi_as_long() const { return _hi; }
virtual jlong lo_as_long() const { return _lo; }
virtual const Type *xmeet( const Type *t ) const;
virtual const Type *xdual() const; // Compute dual right now.
virtual const Type *widen( const Type *t, const Type* limit_type ) const;
virtual const Type *narrow( const Type *t ) const;
virtual const Type* xmeet(const Type* t) const;
virtual const Type* xdual() const; // Compute dual right now.
virtual const Type* widen(const Type* t, const Type* limit_type) const;
virtual const Type* narrow(const Type* t) const;
// Convenience common pre-built types.
static const TypeLong *MAX;
static const TypeLong *MIN;
static const TypeLong *MINUS_1;
static const TypeLong *ZERO;
static const TypeLong *ONE;
static const TypeLong *POS;
static const TypeLong *LONG;
static const TypeLong *INT; // 32-bit subrange [min_jint..max_jint]
static const TypeLong *UINT; // 32-bit unsigned [0..max_juint]
static const TypeLong *TYPE_DOMAIN; // alias for TypeLong::LONG
static const TypeLong* MAX;
static const TypeLong* MIN;
static const TypeLong* MINUS_1;
static const TypeLong* ZERO;
static const TypeLong* ONE;
static const TypeLong* NON_ZERO;
static const TypeLong* POS;
static const TypeLong* NEG;
static const TypeLong* LONG;
static const TypeLong* INT; // 32-bit subrange [min_jint..max_jint]
static const TypeLong* UINT; // 32-bit unsigned [0..max_juint]
static const TypeLong* TYPE_DOMAIN; // alias for TypeLong::LONG
// static convenience methods.
static const TypeLong *as_self(const Type *t) { return t->is_long(); }
static const TypeLong* as_self(const Type* t) { return t->is_long(); }
#ifndef PRODUCT
virtual void dump2( Dict &d, uint, outputStream *st ) const;// Specialized per-Type dumping
virtual void dump2(Dict& d, uint, outputStream* st) const;// Specialized per-Type dumping
void dump_verbose() const;
#endif
};
@ -2246,6 +2430,16 @@ inline const TypeLong* Type::cast<TypeLong>() const {
return is_long();
}
template <>
inline const TypeInt* Type::try_cast<TypeInt>() const {
return isa_int();
}
template <>
inline const TypeLong* Type::try_cast<TypeLong>() const {
return isa_long();
}
// ===============================================================
// Things that need to be 64-bits in the 64-bit build but
// 32-bits in the 32-bit build. Done this way to get full

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -25,6 +25,7 @@
#ifndef SHARE_UTILITIES_COUNT_LEADING_ZEROS_HPP
#define SHARE_UTILITIES_COUNT_LEADING_ZEROS_HPP
#include "metaprogramming/enableIf.hpp"
#include "utilities/debug.hpp"
#include "utilities/globalDefinitions.hpp"
@ -36,7 +37,8 @@
// We implement and support variants for 8, 16, 32 and 64 bit integral types.
template <typename T, size_t n> struct CountLeadingZerosImpl;
template <typename T> unsigned count_leading_zeros(T v) {
template <typename T, ENABLE_IF(std::is_arithmetic<T>::value)>
unsigned count_leading_zeros(T v) {
assert(v != 0, "precondition");
return CountLeadingZerosImpl<T, sizeof(T)>::doit(v);
}

View File

@ -0,0 +1,166 @@
/*
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#ifndef SHARE_UTILITIES_INTN_T_HPP
#define SHARE_UTILITIES_INTN_T_HPP
#include "utilities/count_leading_zeros.hpp"
#include <limits>
template <unsigned int nbits>
class uintn_t;
// This class represents a signed integer type with the width of exactly nbits
// bits. Conceptually, nbits == 8 gives a type equivalent to int8_t,
// nbits == 16 gives a type equivalent to int16_t, and so on. This class may be
// used to verify the correctness of an algorithm that is supposed to be
// applicable to all fixed-width integral types. With small nbits, it makes it
// possible to perform an exhaustive test that exercises the algorithm with all
// possible input values.
// Implementation-wise, this class currently only supports 0 < nbits <= 8. Also
// note that this class is implemented so that overflows in alrithmetic
// operations are well-defined and wrap-around.
template <unsigned int nbits>
class intn_t {
static_assert(0 < nbits && nbits <= 8, "should not be larger than char");
private:
// Only the lowest nbits bits are important, operations should act as if it
// sign extends the lowest nbits to an int, performs the calculation on ints,
// then truncates the result to nbits. In practice, we do not need to
// truncate the result, as the lowest nbits will be sign extended in the next
// operations. We can also sign extends the operands sparingly, for example,
// addition or subtraction do not need this sign extension, and we can add or
// subtract the value of _v directly. This is because the lowest nbits bits
// of a sum or a difference only depends on the lowest nbits bits of the
// operands.
uint _v;
constexpr static uint _mask = (1 << nbits) - 1;
friend class uintn_t<nbits>;
public:
explicit constexpr intn_t(int v) : _v(v) {}
constexpr intn_t() : _v(0) {}
constexpr intn_t(const intn_t&) = default;
constexpr intn_t& operator=(const intn_t&) = default;
explicit constexpr intn_t(uintn_t<nbits> v);
// Sign extension
explicit constexpr operator int() const {
int shift = 32 - nbits;
return int(_v << shift) >> shift;
}
constexpr static int min = std::numeric_limits<unsigned int>::max() << (nbits - 1);
constexpr static int max = (1 << (nbits - 1)) - 1;
static_assert(min < max, "");
constexpr bool operator==(intn_t o) const { return (_v & _mask) == (o._v & _mask); }
constexpr bool operator<(intn_t o) const { return int(*this) < int(o); }
constexpr bool operator>(intn_t o) const { return int(*this) > int(o); }
constexpr bool operator<=(intn_t o) const { return int(*this) <= int(o); }
constexpr bool operator>=(intn_t o) const { return int(*this) >= int(o); }
};
template <unsigned int nbits>
unsigned count_leading_zeros(uintn_t<nbits>);
// The unsigned version of intn_t<nbits>
template <unsigned int nbits>
class uintn_t {
static_assert(0 < nbits && nbits <= 8, "should not be larger than char");
private:
// Similar to intn_t<nbits>, the difference is that the operation should act
// as if it zero extends the lowest nbits bits of the operands.
uint _v;
constexpr static uint _mask = (1 << nbits) - 1;
friend class intn_t<nbits>;
friend unsigned count_leading_zeros<nbits>(uintn_t<nbits>);
public:
explicit constexpr uintn_t(int v) : _v(v) {}
constexpr uintn_t() : _v(0) {}
constexpr uintn_t(const uintn_t&) = default;
constexpr uintn_t& operator=(const uintn_t&) = default;
explicit constexpr uintn_t(intn_t<nbits> v) : _v(v._v) {}
// Zero extension
explicit constexpr operator uint() const { return _v & _mask; }
constexpr static int min = 0;
constexpr static int max = _mask;
static_assert(min < max, "");
constexpr bool operator==(uintn_t o) const { return (_v & _mask) == (o._v & _mask); }
constexpr bool operator!=(uintn_t o) const { return (_v & _mask) != (o._v & _mask); }
constexpr bool operator<(uintn_t o) const { return (_v & _mask) < (o._v & _mask); }
constexpr bool operator>(uintn_t o) const { return (_v & _mask) > (o._v & _mask); }
constexpr bool operator<=(uintn_t o) const { return (_v & _mask) <= (o._v & _mask); }
constexpr bool operator>=(uintn_t o) const { return (_v & _mask) >= (o._v & _mask); }
constexpr uintn_t operator+(uintn_t o) const { return uintn_t(_v + o._v); }
constexpr uintn_t operator-(uintn_t o) const { return uintn_t(_v - o._v); }
constexpr uintn_t operator&(uintn_t o) const { return uintn_t(_v & o._v); }
constexpr uintn_t operator|(uintn_t o) const { return uintn_t(_v | o._v); }
constexpr uintn_t operator^(uintn_t o) const { return uintn_t(_v ^ o._v); }
constexpr uintn_t operator>>(unsigned int s) const { return uintn_t((_v & _mask) >> s); }
constexpr uintn_t operator<<(unsigned int s) const { return uintn_t(_v << s); }
constexpr uintn_t operator~() const { return uintn_t(~_v); }
constexpr uintn_t operator-() const { return uintn_t(-_v); }
constexpr uintn_t& operator|=(uintn_t o) { _v |= o._v; return *this; }
};
template <unsigned int nbits>
constexpr intn_t<nbits>::intn_t(uintn_t<nbits> v) : _v(v._v) {}
namespace std {
template <unsigned int nbits>
class numeric_limits<intn_t<nbits>> {
public:
constexpr static intn_t<nbits> min() { return intn_t<nbits>(intn_t<nbits>::min); }
constexpr static intn_t<nbits> max() { return intn_t<nbits>(intn_t<nbits>::max); }
};
template <unsigned int nbits>
class numeric_limits<uintn_t<nbits>> {
public:
constexpr static uintn_t<nbits> min() { return uintn_t<nbits>(uintn_t<nbits>::min); }
constexpr static uintn_t<nbits> max() { return uintn_t<nbits>(uintn_t<nbits>::max); }
};
} // namespace std
template <unsigned int nbits>
inline unsigned count_leading_zeros(uintn_t<nbits> v) {
return count_leading_zeros<unsigned int>(v._v & uintn_t<nbits>::_mask) - (32 - nbits);
}
#endif // SHARE_UTILITIES_INTN_T_HPP

View File

@ -0,0 +1,214 @@
/*
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#include "opto/rangeinference.hpp"
#include "opto/type.hpp"
#include "runtime/os.hpp"
#include "utilities/intn_t.hpp"
#include "unittest.hpp"
template <class U>
static U uniform_random();
template <>
juint uniform_random<juint>() {
return os::random();
}
template <>
julong uniform_random<julong>() {
return (julong(os::random()) << 32) | julong(juint(os::random()));
}
static void test_canonicalize_constraints_trivial() {
ASSERT_FALSE(TypeInt::NON_ZERO->contains(0));
ASSERT_TRUE(TypeInt::NON_ZERO->contains(1));
ASSERT_TRUE(TypeInt::NON_ZERO->contains(-1));
ASSERT_TRUE(TypeInt::CC_NE->contains(-1));
ASSERT_TRUE(TypeInt::CC_NE->contains(1));
ASSERT_FALSE(TypeInt::CC_NE->contains(0));
ASSERT_FALSE(TypeInt::CC_NE->contains(-2));
ASSERT_FALSE(TypeInt::CC_NE->contains(2));
ASSERT_FALSE(TypeLong::NON_ZERO->contains(jlong(0)));
ASSERT_TRUE(TypeLong::NON_ZERO->contains(jlong(1)));
ASSERT_TRUE(TypeLong::NON_ZERO->contains(jlong(-1)));
}
template <class S, class U>
static void test_canonicalize_constraints_exhaustive() {
{
TypeIntPrototype<S, U> t{{S(0), S(0)}, {U(0), U(0)}, {U(-1), U(0)}};
auto new_t = t.canonicalize_constraints();
ASSERT_TRUE(new_t._present);
DEBUG_ONLY(ASSERT_TRUE(t.contains(S(0))));
DEBUG_ONLY(ASSERT_FALSE(t.contains(S(1))));
}
{
TypeIntPrototype<S, U> t{{S(0), S(0)}, {U(1), U(1)}, {U(-1), U(0)}};
auto new_t = t.canonicalize_constraints();
ASSERT_FALSE(new_t._present);
DEBUG_ONLY(ASSERT_FALSE(t.contains(S(0))));
DEBUG_ONLY(ASSERT_FALSE(t.contains(S(1))));
}
{
TypeIntPrototype<S, U> t{{S(S::min), S(S::max)}, {U(U::min), U(U::max)}, {U(0), U(0)}};
auto new_t = t.canonicalize_constraints();
ASSERT_TRUE(new_t._present);
for (int v = S::min; v <= S::max; v++) {
DEBUG_ONLY(ASSERT_TRUE(t.contains(S(v))));
}
}
for (int lo = S::min; lo <= S::max; lo++) {
for (int hi = lo; hi <= S::max; hi++) {
for (int ulo = U::min; ulo <= U::max; ulo++) {
for (int uhi = ulo; uhi <= U::max; uhi++) {
for (int zeros = U::min; zeros <= U::max; zeros++) {
for (int ones = U::min; ones <= U::max; ones++) {
TypeIntPrototype<S, U> t{{S(lo), S(hi)}, {U(ulo), U(uhi)}, {U(zeros), U(ones)}};
auto new_t = t.canonicalize_constraints();
if (new_t._present) {
DEBUG_ONLY(new_t._data.verify_constraints());
}
for (int v = S::min; v <= S::max; v++) {
if (!new_t._present) {
DEBUG_ONLY(ASSERT_FALSE(t.contains(S(v))));
} else {
DEBUG_ONLY(ASSERT_EQ(t.contains(S(v)), new_t._data.contains(S(v))));
}
}
}
}
}
}
}
}
}
template <class S, class U>
static void test_canonicalize_constraints_simple() {
constexpr int parameters = 1000;
for (int i = 0; i < parameters; i++) {
S a = uniform_random<U>();
S b = uniform_random<U>();
{
S lo = MIN2<S>(a, b);
S hi = MAX2<S>(a, b);
TypeIntPrototype<S, U> t{{lo, hi}, {std::numeric_limits<U>::min(), std::numeric_limits<U>::max()},
{0, 0}};
auto new_t = t.canonicalize_constraints();
ASSERT_TRUE(new_t._present);
DEBUG_ONLY(new_t._data.verify_constraints());
ASSERT_EQ(lo, new_t._data._srange._lo);
ASSERT_EQ(hi, new_t._data._srange._hi);
if (U(lo) <= U(hi)) {
ASSERT_EQ(U(lo), new_t._data._urange._lo);
ASSERT_EQ(U(hi), new_t._data._urange._hi);
} else {
ASSERT_EQ(std::numeric_limits<U>::min(), new_t._data._urange._lo);
ASSERT_EQ(std::numeric_limits<U>::max(), new_t._data._urange._hi);
}
}
{
U ulo = MIN2<U>(a, b);
U uhi = MAX2<U>(a, b);
TypeIntPrototype<S, U> t{{std::numeric_limits<S>::min(), std::numeric_limits<S>::max()},
{ulo, uhi}, {0, 0}};
auto new_t = t.canonicalize_constraints();
ASSERT_TRUE(new_t._present);
DEBUG_ONLY(new_t._data.verify_constraints());
ASSERT_EQ(ulo, new_t._data._urange._lo);
ASSERT_EQ(uhi, new_t._data._urange._hi);
if (S(ulo) <= S(uhi)) {
ASSERT_EQ(S(ulo), new_t._data._srange._lo);
ASSERT_EQ(S(uhi), new_t._data._srange._hi);
} else {
ASSERT_EQ(std::numeric_limits<S>::min(), new_t._data._srange._lo);
ASSERT_EQ(std::numeric_limits<S>::max(), new_t._data._srange._hi);
}
}
{
U intersection = a & b;
U zeros = a ^ intersection;
U ones = b ^ intersection;
TypeIntPrototype<S, U> t{{std::numeric_limits<S>::min(), std::numeric_limits<S>::max()},
{std::numeric_limits<U>::min(), std::numeric_limits<U>::max()}, {zeros, ones}};
auto new_t = t.canonicalize_constraints();
ASSERT_TRUE(new_t._present);
DEBUG_ONLY(new_t._data.verify_constraints());
ASSERT_EQ(zeros, new_t._data._bits._zeros);
ASSERT_EQ(ones, new_t._data._bits._ones);
ASSERT_EQ(ones, new_t._data._urange._lo);
ASSERT_EQ(~zeros, new_t._data._urange._hi);
}
}
}
template <class S, class U>
static void test_canonicalize_constraints_random() {
constexpr int samples = 1000;
constexpr int parameters = 1000;
for (int i = 0; i < parameters; i++) {
S s1 = uniform_random<U>();
S s2 = uniform_random<U>();
S lo = MIN2(s1, s2);
S hi = MAX2(s1, s2);
U u1 = uniform_random<U>();
U u2 = uniform_random<U>();
U ulo = MIN2(u1, u2);
U uhi = MAX2(u1, u2);
U b1 = uniform_random<U>();
U b2 = uniform_random<U>();
U intersection = b1 & b2;
U zeros = b1 ^ intersection;
U ones = b2 ^ intersection;
TypeIntPrototype<S, U> t{{lo, hi}, {ulo, uhi}, {zeros, ones}};
auto new_t = t.canonicalize_constraints();
if (new_t._present) {
DEBUG_ONLY(new_t._data.verify_constraints());
}
for (int j = 0; j < samples; j++) {
S v = uniform_random<U>();
if (!new_t._present) {
DEBUG_ONLY(ASSERT_FALSE(t.contains(v)));
} else {
DEBUG_ONLY(ASSERT_EQ(t.contains(v), new_t._data.contains(v)));
}
}
}
}
TEST_VM(opto, canonicalize_constraints) {
test_canonicalize_constraints_trivial();
test_canonicalize_constraints_exhaustive<intn_t<1>, uintn_t<1>>();
test_canonicalize_constraints_exhaustive<intn_t<2>, uintn_t<2>>();
test_canonicalize_constraints_exhaustive<intn_t<3>, uintn_t<3>>();
test_canonicalize_constraints_exhaustive<intn_t<4>, uintn_t<4>>();
test_canonicalize_constraints_simple<jint, juint>();
test_canonicalize_constraints_simple<jlong, julong>();
test_canonicalize_constraints_random<jint, juint>();
test_canonicalize_constraints_random<jlong, julong>();
}

View File

@ -0,0 +1,70 @@
/*
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#include "utilities/intn_t.hpp"
#include "unittest.hpp"
// Sanity tests for off-by-one errors
static_assert(intn_t<1>::min == -1 && intn_t<1>::max == 0, "");
static_assert(intn_t<2>::min == -2 && intn_t<2>::max == 1, "");
static_assert(intn_t<3>::min == -4 && intn_t<3>::max == 3, "");
static_assert(uintn_t<1>::max == 1, "");
static_assert(uintn_t<2>::max == 3, "");
static_assert(uintn_t<3>::max == 7, "");
template <unsigned int nbits>
static void test_intn_t() {
static_assert(std::numeric_limits<intn_t<nbits>>::min() <= intn_t<nbits>(-1) &&
intn_t<nbits>(-1) < intn_t<nbits>(0) &&
intn_t<nbits>(0) <= std::numeric_limits<intn_t<nbits>>::max(), "basic sanity");
constexpr int period = intn_t<nbits>::max - intn_t<nbits>::min + 1;
for (int i = std::numeric_limits<signed char>::min(); i < std::numeric_limits<signed char>::max(); i++) {
ASSERT_EQ(intn_t<nbits>(i), intn_t<nbits>(i + period));
ASSERT_EQ(int(intn_t<nbits>(i)), int(intn_t<nbits>(i + period)));
}
for (int i = intn_t<nbits>::min; i <= intn_t<nbits>::max; i++) {
ASSERT_EQ(i, int(intn_t<nbits>(i)));
if (i > intn_t<nbits>::min) {
ASSERT_TRUE(intn_t<nbits>(i - 1) < intn_t<nbits>(i));
} else {
ASSERT_TRUE(intn_t<nbits>(i - 1) > intn_t<nbits>(i));
}
if (i < intn_t<nbits>::max) {
ASSERT_TRUE(intn_t<nbits>(i) < intn_t<nbits>(i + 1));
} else {
ASSERT_TRUE(intn_t<nbits>(i) > intn_t<nbits>(i + 1));
}
}
}
TEST(utilities, intn_t) {
test_intn_t<1>();
test_intn_t<2>();
test_intn_t<3>();
test_intn_t<4>();
test_intn_t<5>();
test_intn_t<6>();
test_intn_t<7>();
test_intn_t<8>();
}