mirror of
https://github.com/openjdk/jdk.git
synced 2026-01-28 12:09:14 +00:00
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:
parent
523a4efe1c
commit
991097b7bf
@ -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;
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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));
|
||||
|
||||
1081
src/hotspot/share/opto/rangeinference.cpp
Normal file
1081
src/hotspot/share/opto/rangeinference.cpp
Normal file
File diff suppressed because it is too large
Load Diff
198
src/hotspot/share/opto/rangeinference.hpp
Normal file
198
src/hotspot/share/opto/rangeinference.hpp
Normal 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
|
||||
@ -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);
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
166
src/hotspot/share/utilities/intn_t.hpp
Normal file
166
src/hotspot/share/utilities/intn_t.hpp
Normal 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
|
||||
214
test/hotspot/gtest/opto/test_rangeinference.cpp
Normal file
214
test/hotspot/gtest/opto/test_rangeinference.cpp
Normal 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>();
|
||||
}
|
||||
70
test/hotspot/gtest/utilities/test_intn_t.cpp
Normal file
70
test/hotspot/gtest/utilities/test_intn_t.cpp
Normal 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>();
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user