提交 4b295af4 编写于 作者: A asaha

Merge

...@@ -810,6 +810,8 @@ da43260704c28b9f19cb652090ae65c258220fd6 jdk8u72-b31 ...@@ -810,6 +810,8 @@ da43260704c28b9f19cb652090ae65c258220fd6 jdk8u72-b31
c1031a924f2c910fad078838b88a2f0146f2de98 jdk8u74-b01 c1031a924f2c910fad078838b88a2f0146f2de98 jdk8u74-b01
ca9cae9aa9e989bbe6713c91d55c913edeaecce4 jdk8u74-b02 ca9cae9aa9e989bbe6713c91d55c913edeaecce4 jdk8u74-b02
a5b78b56841e97ce00463874f1b7f63c54d84934 jdk8u74-b31 a5b78b56841e97ce00463874f1b7f63c54d84934 jdk8u74-b31
94ec11846b18111e73929b6caa9fbe7262e142c1 jdk8u74-b32
da43260704c28b9f19cb652090ae65c258220fd6 jdk8u72-b31 da43260704c28b9f19cb652090ae65c258220fd6 jdk8u72-b31
c0242ea4bde19d72be5149feda112a39e8c89b0a jdk8u75-b00 c0242ea4bde19d72be5149feda112a39e8c89b0a jdk8u75-b00
ca3b8c8e390ab0540b0cc2e5def869b38e460d86 jdk8u75-b01 ca3b8c8e390ab0540b0cc2e5def869b38e460d86 jdk8u75-b01
...@@ -821,6 +823,7 @@ ca3b8c8e390ab0540b0cc2e5def869b38e460d86 jdk8u75-b01 ...@@ -821,6 +823,7 @@ ca3b8c8e390ab0540b0cc2e5def869b38e460d86 jdk8u75-b01
8c791dd1c24d85ebd18b03d49185c2a25263c129 jdk8u75-b07 8c791dd1c24d85ebd18b03d49185c2a25263c129 jdk8u75-b07
e4a935cb6f7178912fd653e2a9514eadec7935ab jdk8u75-b08 e4a935cb6f7178912fd653e2a9514eadec7935ab jdk8u75-b08
e97c45c377eb8d022cfe24b73737fa312107e0a5 jdk8u75-b09 e97c45c377eb8d022cfe24b73737fa312107e0a5 jdk8u75-b09
d44c7e324682a30e064503ef9582d83a41f4173e jdk8u75-b10
d7b01fb81aa8a5437cb03bc36afe15cf0e55fb89 jdk8u76-b00 d7b01fb81aa8a5437cb03bc36afe15cf0e55fb89 jdk8u76-b00
c1679cc87ba045219169cabb6b9b378c2b5cc578 jdk8u76-b01 c1679cc87ba045219169cabb6b9b378c2b5cc578 jdk8u76-b01
218483967e52b419d885d34af4488a81c5133804 jdk8u76-b02 218483967e52b419d885d34af4488a81c5133804 jdk8u76-b02
...@@ -831,4 +834,5 @@ c1679cc87ba045219169cabb6b9b378c2b5cc578 jdk8u76-b01 ...@@ -831,4 +834,5 @@ c1679cc87ba045219169cabb6b9b378c2b5cc578 jdk8u76-b01
7d1074c74d6000ec8257917ebfcee3fed4249f7d jdk8u76-b07 7d1074c74d6000ec8257917ebfcee3fed4249f7d jdk8u76-b07
392f8722fc513e28f78c5c563d51af7dc8466b29 jdk8u76-b08 392f8722fc513e28f78c5c563d51af7dc8466b29 jdk8u76-b08
3bf0f5b8a892defd0bf9731b4e15926881fcda74 jdk8u76-b09 3bf0f5b8a892defd0bf9731b4e15926881fcda74 jdk8u76-b09
a2b0ee820059a44be558a2d435b7d85ed5a8b63a jdk8u76-b10
b374548dcb4834eb8731a06b52faddd0f10bd45d jdk8u81-b00 b374548dcb4834eb8731a06b52faddd0f10bd45d jdk8u81-b00
...@@ -412,6 +412,13 @@ void Compile::remove_useless_nodes(Unique_Node_List &useful) { ...@@ -412,6 +412,13 @@ void Compile::remove_useless_nodes(Unique_Node_List &useful) {
remove_macro_node(n); remove_macro_node(n);
} }
} }
// Remove useless CastII nodes with range check dependency
for (int i = range_check_cast_count() - 1; i >= 0; i--) {
Node* cast = range_check_cast_node(i);
if (!useful.member(cast)) {
remove_range_check_cast(cast);
}
}
// Remove useless expensive node // Remove useless expensive node
for (int i = C->expensive_count()-1; i >= 0; i--) { for (int i = C->expensive_count()-1; i >= 0; i--) {
Node* n = C->expensive_node(i); Node* n = C->expensive_node(i);
...@@ -1148,6 +1155,7 @@ void Compile::Init(int aliaslevel) { ...@@ -1148,6 +1155,7 @@ void Compile::Init(int aliaslevel) {
_macro_nodes = new(comp_arena()) GrowableArray<Node*>(comp_arena(), 8, 0, NULL); _macro_nodes = new(comp_arena()) GrowableArray<Node*>(comp_arena(), 8, 0, NULL);
_predicate_opaqs = new(comp_arena()) GrowableArray<Node*>(comp_arena(), 8, 0, NULL); _predicate_opaqs = new(comp_arena()) GrowableArray<Node*>(comp_arena(), 8, 0, NULL);
_expensive_nodes = new(comp_arena()) GrowableArray<Node*>(comp_arena(), 8, 0, NULL); _expensive_nodes = new(comp_arena()) GrowableArray<Node*>(comp_arena(), 8, 0, NULL);
_range_check_casts = new(comp_arena()) GrowableArray<Node*>(comp_arena(), 8, 0, NULL);
register_library_intrinsics(); register_library_intrinsics();
} }
...@@ -1876,6 +1884,22 @@ void Compile::cleanup_loop_predicates(PhaseIterGVN &igvn) { ...@@ -1876,6 +1884,22 @@ void Compile::cleanup_loop_predicates(PhaseIterGVN &igvn) {
assert(predicate_count()==0, "should be clean!"); assert(predicate_count()==0, "should be clean!");
} }
void Compile::add_range_check_cast(Node* n) {
assert(n->isa_CastII()->has_range_check(), "CastII should have range check dependency");
assert(!_range_check_casts->contains(n), "duplicate entry in range check casts");
_range_check_casts->append(n);
}
// Remove all range check dependent CastIINodes.
void Compile::remove_range_check_casts(PhaseIterGVN &igvn) {
for (int i = range_check_cast_count(); i > 0; i--) {
Node* cast = range_check_cast_node(i-1);
assert(cast->isa_CastII()->has_range_check(), "CastII should have range check dependency");
igvn.replace_node(cast, cast->in(1));
}
assert(range_check_cast_count() == 0, "should be empty");
}
// StringOpts and late inlining of string methods // StringOpts and late inlining of string methods
void Compile::inline_string_calls(bool parse_time) { void Compile::inline_string_calls(bool parse_time) {
{ {
...@@ -2218,6 +2242,12 @@ void Compile::Optimize() { ...@@ -2218,6 +2242,12 @@ void Compile::Optimize() {
PhaseIdealLoop::verify(igvn); PhaseIdealLoop::verify(igvn);
} }
if (range_check_cast_count() > 0) {
// No more loop optimizations. Remove all range check dependent CastIINodes.
C->remove_range_check_casts(igvn);
igvn.optimize();
}
{ {
NOT_PRODUCT( TracePhase t2("macroExpand", &_t_macroExpand, TimeCompiler); ) NOT_PRODUCT( TracePhase t2("macroExpand", &_t_macroExpand, TimeCompiler); )
PhaseMacroExpand mex(igvn); PhaseMacroExpand mex(igvn);
...@@ -2987,6 +3017,16 @@ void Compile::final_graph_reshaping_impl( Node *n, Final_Reshape_Counts &frc) { ...@@ -2987,6 +3017,16 @@ void Compile::final_graph_reshaping_impl( Node *n, Final_Reshape_Counts &frc) {
#endif #endif
#ifdef ASSERT
case Op_CastII:
// Verify that all range check dependent CastII nodes were removed.
if (n->isa_CastII()->has_range_check()) {
n->dump(3);
assert(false, "Range check dependent CastII node was not removed");
}
break;
#endif
case Op_ModI: case Op_ModI:
if (UseDivMod) { if (UseDivMod) {
// Check if a%b and a/b both exist // Check if a%b and a/b both exist
...@@ -4024,6 +4064,24 @@ void Compile::remove_speculative_types(PhaseIterGVN &igvn) { ...@@ -4024,6 +4064,24 @@ void Compile::remove_speculative_types(PhaseIterGVN &igvn) {
} }
} }
// Convert integer value to a narrowed long type dependent on ctrl (for example, a range check)
Node* Compile::constrained_convI2L(PhaseGVN* phase, Node* value, const TypeInt* itype, Node* ctrl) {
if (ctrl != NULL) {
// Express control dependency by a CastII node with a narrow type.
value = new (phase->C) CastIINode(value, itype, false, true /* range check dependency */);
// Make the CastII node dependent on the control input to prevent the narrowed ConvI2L
// node from floating above the range check during loop optimizations. Otherwise, the
// ConvI2L node may be eliminated independently of the range check, causing the data path
// to become TOP while the control path is still there (although it's unreachable).
value->set_req(0, ctrl);
// Save CastII node to remove it after loop optimizations.
phase->C->add_range_check_cast(value);
value = phase->transform(value);
}
const TypeLong* ltype = TypeLong::make(itype->_lo, itype->_hi, itype->_widen);
return phase->transform(new (phase->C) ConvI2LNode(value, ltype));
}
// Auxiliary method to support randomized stressing/fuzzing. // Auxiliary method to support randomized stressing/fuzzing.
// //
// This method can be called the arbitrary number of times, with current count // This method can be called the arbitrary number of times, with current count
......
...@@ -75,6 +75,7 @@ class SafePointNode; ...@@ -75,6 +75,7 @@ class SafePointNode;
class JVMState; class JVMState;
class Type; class Type;
class TypeData; class TypeData;
class TypeInt;
class TypePtr; class TypePtr;
class TypeOopPtr; class TypeOopPtr;
class TypeFunc; class TypeFunc;
...@@ -334,6 +335,7 @@ class Compile : public Phase { ...@@ -334,6 +335,7 @@ class Compile : public Phase {
GrowableArray<Node*>* _macro_nodes; // List of nodes which need to be expanded before matching. GrowableArray<Node*>* _macro_nodes; // List of nodes which need to be expanded before matching.
GrowableArray<Node*>* _predicate_opaqs; // List of Opaque1 nodes for the loop predicates. GrowableArray<Node*>* _predicate_opaqs; // List of Opaque1 nodes for the loop predicates.
GrowableArray<Node*>* _expensive_nodes; // List of nodes that are expensive to compute and that we'd better not let the GVN freely common GrowableArray<Node*>* _expensive_nodes; // List of nodes that are expensive to compute and that we'd better not let the GVN freely common
GrowableArray<Node*>* _range_check_casts; // List of CastII nodes with a range check dependency
ConnectionGraph* _congraph; ConnectionGraph* _congraph;
#ifndef PRODUCT #ifndef PRODUCT
IdealGraphPrinter* _printer; IdealGraphPrinter* _printer;
...@@ -669,7 +671,7 @@ class Compile : public Phase { ...@@ -669,7 +671,7 @@ class Compile : public Phase {
void set_congraph(ConnectionGraph* congraph) { _congraph = congraph;} void set_congraph(ConnectionGraph* congraph) { _congraph = congraph;}
void add_macro_node(Node * n) { void add_macro_node(Node * n) {
//assert(n->is_macro(), "must be a macro node"); //assert(n->is_macro(), "must be a macro node");
assert(!_macro_nodes->contains(n), " duplicate entry in expand list"); assert(!_macro_nodes->contains(n), "duplicate entry in expand list");
_macro_nodes->append(n); _macro_nodes->append(n);
} }
void remove_macro_node(Node * n) { void remove_macro_node(Node * n) {
...@@ -689,10 +691,23 @@ class Compile : public Phase { ...@@ -689,10 +691,23 @@ class Compile : public Phase {
} }
} }
void add_predicate_opaq(Node * n) { void add_predicate_opaq(Node * n) {
assert(!_predicate_opaqs->contains(n), " duplicate entry in predicate opaque1"); assert(!_predicate_opaqs->contains(n), "duplicate entry in predicate opaque1");
assert(_macro_nodes->contains(n), "should have already been in macro list"); assert(_macro_nodes->contains(n), "should have already been in macro list");
_predicate_opaqs->append(n); _predicate_opaqs->append(n);
} }
// Range check dependent CastII nodes that can be removed after loop optimizations
void add_range_check_cast(Node* n);
void remove_range_check_cast(Node* n) {
if (_range_check_casts->contains(n)) {
_range_check_casts->remove(n);
}
}
Node* range_check_cast_node(int idx) const { return _range_check_casts->at(idx); }
int range_check_cast_count() const { return _range_check_casts->length(); }
// Remove all range check dependent CastIINodes.
void remove_range_check_casts(PhaseIterGVN &igvn);
// remove the opaque nodes that protect the predicates so that the unused checks and // remove the opaque nodes that protect the predicates so that the unused checks and
// uncommon traps will be eliminated from the graph. // uncommon traps will be eliminated from the graph.
void cleanup_loop_predicates(PhaseIterGVN &igvn); void cleanup_loop_predicates(PhaseIterGVN &igvn);
...@@ -1201,6 +1216,9 @@ class Compile : public Phase { ...@@ -1201,6 +1216,9 @@ class Compile : public Phase {
// Definitions of pd methods // Definitions of pd methods
static void pd_compiler2_init(); static void pd_compiler2_init();
// Convert integer value to a narrowed long type dependent on ctrl (for example, a range check)
static Node* constrained_convI2L(PhaseGVN* phase, Node* value, const TypeInt* itype, Node* ctrl);
// Auxiliary method for randomized fuzzing/stressing // Auxiliary method for randomized fuzzing/stressing
static bool randomized_select(int count); static bool randomized_select(int count);
}; };
......
...@@ -535,6 +535,9 @@ void CastIINode::dump_spec(outputStream *st) const { ...@@ -535,6 +535,9 @@ void CastIINode::dump_spec(outputStream *st) const {
if (_carry_dependency) { if (_carry_dependency) {
st->print(" carry dependency"); st->print(" carry dependency");
} }
if (_range_check_dependency) {
st->print(" range check dependency");
}
} }
#endif #endif
...@@ -994,7 +997,8 @@ Node *ConvI2LNode::Ideal(PhaseGVN *phase, bool can_reshape) { ...@@ -994,7 +997,8 @@ Node *ConvI2LNode::Ideal(PhaseGVN *phase, bool can_reshape) {
} }
#ifdef _LP64 #ifdef _LP64
// Convert ConvI2L(AddI(x, y)) to AddL(ConvI2L(x), ConvI2L(y)) , // Convert ConvI2L(AddI(x, y)) to AddL(ConvI2L(x), ConvI2L(y)) or
// ConvI2L(CastII(AddI(x, y))) to AddL(ConvI2L(CastII(x)), ConvI2L(CastII(y))),
// but only if x and y have subranges that cannot cause 32-bit overflow, // but only if x and y have subranges that cannot cause 32-bit overflow,
// under the assumption that x+y is in my own subrange this->type(). // under the assumption that x+y is in my own subrange this->type().
...@@ -1018,6 +1022,13 @@ Node *ConvI2LNode::Ideal(PhaseGVN *phase, bool can_reshape) { ...@@ -1018,6 +1022,13 @@ Node *ConvI2LNode::Ideal(PhaseGVN *phase, bool can_reshape) {
Node* z = in(1); Node* z = in(1);
int op = z->Opcode(); int op = z->Opcode();
Node* ctrl = NULL;
if (op == Op_CastII && z->as_CastII()->has_range_check()) {
// Skip CastII node but save control dependency
ctrl = z->in(0);
z = z->in(1);
op = z->Opcode();
}
if (op == Op_AddI || op == Op_SubI) { if (op == Op_AddI || op == Op_SubI) {
Node* x = z->in(1); Node* x = z->in(1);
Node* y = z->in(2); Node* y = z->in(2);
...@@ -1075,9 +1086,10 @@ Node *ConvI2LNode::Ideal(PhaseGVN *phase, bool can_reshape) { ...@@ -1075,9 +1086,10 @@ Node *ConvI2LNode::Ideal(PhaseGVN *phase, bool can_reshape) {
rylo = -ryhi; rylo = -ryhi;
ryhi = -rylo0; ryhi = -rylo0;
} }
assert(rxlo == (int)rxlo && rxhi == (int)rxhi, "x should not overflow");
Node* cx = phase->transform( new (phase->C) ConvI2LNode(x, TypeLong::make(rxlo, rxhi, widen)) ); assert(rylo == (int)rylo && ryhi == (int)ryhi, "y should not overflow");
Node* cy = phase->transform( new (phase->C) ConvI2LNode(y, TypeLong::make(rylo, ryhi, widen)) ); Node* cx = phase->C->constrained_convI2L(phase, x, TypeInt::make(rxlo, rxhi, widen), ctrl);
Node* cy = phase->C->constrained_convI2L(phase, y, TypeInt::make(rylo, ryhi, widen), ctrl);
switch (op) { switch (op) {
case Op_AddI: return new (phase->C) AddLNode(cx, cy); case Op_AddI: return new (phase->C) AddLNode(cx, cy);
case Op_SubI: return new (phase->C) SubLNode(cx, cy); case Op_SubI: return new (phase->C) SubLNode(cx, cy);
......
...@@ -244,19 +244,31 @@ class CastIINode: public ConstraintCastNode { ...@@ -244,19 +244,31 @@ class CastIINode: public ConstraintCastNode {
private: private:
// Can this node be removed post CCP or does it carry a required dependency? // Can this node be removed post CCP or does it carry a required dependency?
const bool _carry_dependency; const bool _carry_dependency;
// Is this node dependent on a range check?
const bool _range_check_dependency;
protected: protected:
virtual uint cmp( const Node &n ) const; virtual uint cmp( const Node &n ) const;
virtual uint size_of() const; virtual uint size_of() const;
public: public:
CastIINode(Node *n, const Type *t, bool carry_dependency = false) CastIINode(Node *n, const Type *t, bool carry_dependency = false, bool range_check_dependency = false)
: ConstraintCastNode(n,t), _carry_dependency(carry_dependency) {} : ConstraintCastNode(n,t), _carry_dependency(carry_dependency), _range_check_dependency(range_check_dependency) {
init_class_id(Class_CastII);
}
virtual int Opcode() const; virtual int Opcode() const;
virtual uint ideal_reg() const { return Op_RegI; } virtual uint ideal_reg() const { return Op_RegI; }
virtual Node *Identity( PhaseTransform *phase ); virtual Node *Identity( PhaseTransform *phase );
virtual const Type *Value( PhaseTransform *phase ) const; virtual const Type *Value( PhaseTransform *phase ) const;
virtual Node *Ideal_DU_postCCP( PhaseCCP * ); virtual Node *Ideal_DU_postCCP( PhaseCCP * );
const bool has_range_check() {
#ifdef _LP64
return _range_check_dependency;
#else
assert(!_range_check_dependency, "Should not have range check dependency");
return false;
#endif
}
#ifndef PRODUCT #ifndef PRODUCT
virtual void dump_spec(outputStream *st) const; virtual void dump_spec(outputStream *st) const;
#endif #endif
......
...@@ -1645,7 +1645,7 @@ Node* GraphKit::store_oop_to_unknown(Node* ctl, ...@@ -1645,7 +1645,7 @@ Node* GraphKit::store_oop_to_unknown(Node* ctl,
//-------------------------array_element_address------------------------- //-------------------------array_element_address-------------------------
Node* GraphKit::array_element_address(Node* ary, Node* idx, BasicType elembt, Node* GraphKit::array_element_address(Node* ary, Node* idx, BasicType elembt,
const TypeInt* sizetype) { const TypeInt* sizetype, Node* ctrl) {
uint shift = exact_log2(type2aelembytes(elembt)); uint shift = exact_log2(type2aelembytes(elembt));
uint header = arrayOopDesc::base_offset_in_bytes(elembt); uint header = arrayOopDesc::base_offset_in_bytes(elembt);
...@@ -1670,9 +1670,9 @@ Node* GraphKit::array_element_address(Node* ary, Node* idx, BasicType elembt, ...@@ -1670,9 +1670,9 @@ Node* GraphKit::array_element_address(Node* ary, Node* idx, BasicType elembt,
// number. (The prior range check has ensured this.) // number. (The prior range check has ensured this.)
// This assertion is used by ConvI2LNode::Ideal. // This assertion is used by ConvI2LNode::Ideal.
int index_max = max_jint - 1; // array size is max_jint, index is one less int index_max = max_jint - 1; // array size is max_jint, index is one less
if (sizetype != NULL) index_max = sizetype->_hi - 1; if (sizetype != NULL) index_max = sizetype->_hi - 1;
const TypeLong* lidxtype = TypeLong::make(CONST64(0), index_max, Type::WidenMax); const TypeInt* iidxtype = TypeInt::make(0, index_max, Type::WidenMax);
idx = _gvn.transform( new (C) ConvI2LNode(idx, lidxtype) ); idx = C->constrained_convI2L(&_gvn, idx, iidxtype, ctrl);
#endif #endif
Node* scale = _gvn.transform( new (C) LShiftXNode(idx, intcon(shift)) ); Node* scale = _gvn.transform( new (C) LShiftXNode(idx, intcon(shift)) );
return basic_plus_adr(ary, base, scale); return basic_plus_adr(ary, base, scale);
...@@ -3491,10 +3491,6 @@ Node* GraphKit::new_array(Node* klass_node, // array klass (maybe variable) ...@@ -3491,10 +3491,6 @@ Node* GraphKit::new_array(Node* klass_node, // array klass (maybe variable)
Node* initial_slow_cmp = _gvn.transform( new (C) CmpUNode( length, intcon( fast_size_limit ) ) ); Node* initial_slow_cmp = _gvn.transform( new (C) CmpUNode( length, intcon( fast_size_limit ) ) );
Node* initial_slow_test = _gvn.transform( new (C) BoolNode( initial_slow_cmp, BoolTest::gt ) ); Node* initial_slow_test = _gvn.transform( new (C) BoolNode( initial_slow_cmp, BoolTest::gt ) );
if (initial_slow_test->is_Bool()) {
// Hide it behind a CMoveI, or else PhaseIdealLoop::split_up will get sick.
initial_slow_test = initial_slow_test->as_Bool()->as_int_value(&_gvn);
}
// --- Size Computation --- // --- Size Computation ---
// array_size = round_to_heap(array_header + (length << elem_shift)); // array_size = round_to_heap(array_header + (length << elem_shift));
...@@ -3540,13 +3536,35 @@ Node* GraphKit::new_array(Node* klass_node, // array klass (maybe variable) ...@@ -3540,13 +3536,35 @@ Node* GraphKit::new_array(Node* klass_node, // array klass (maybe variable)
Node* lengthx = ConvI2X(length); Node* lengthx = ConvI2X(length);
Node* headerx = ConvI2X(header_size); Node* headerx = ConvI2X(header_size);
#ifdef _LP64 #ifdef _LP64
{ const TypeLong* tllen = _gvn.find_long_type(lengthx); { const TypeInt* tilen = _gvn.find_int_type(length);
if (tllen != NULL && tllen->_lo < 0) { if (tilen != NULL && tilen->_lo < 0) {
// Add a manual constraint to a positive range. Cf. array_element_address. // Add a manual constraint to a positive range. Cf. array_element_address.
jlong size_max = arrayOopDesc::max_array_length(T_BYTE); jlong size_max = fast_size_limit;
if (size_max > tllen->_hi) size_max = tllen->_hi; if (size_max > tilen->_hi) size_max = tilen->_hi;
const TypeLong* tlcon = TypeLong::make(CONST64(0), size_max, Type::WidenMin); const TypeInt* tlcon = TypeInt::make(0, size_max, Type::WidenMin);
lengthx = _gvn.transform( new (C) ConvI2LNode(length, tlcon));
// Only do a narrow I2L conversion if the range check passed.
IfNode* iff = new (C) IfNode(control(), initial_slow_test, PROB_MIN, COUNT_UNKNOWN);
_gvn.transform(iff);
RegionNode* region = new (C) RegionNode(3);
_gvn.set_type(region, Type::CONTROL);
lengthx = new (C) PhiNode(region, TypeLong::LONG);
_gvn.set_type(lengthx, TypeLong::LONG);
// Range check passed. Use ConvI2L node with narrow type.
Node* passed = IfFalse(iff);
region->init_req(1, passed);
// Make I2L conversion control dependent to prevent it from
// floating above the range check during loop optimizations.
lengthx->init_req(1, C->constrained_convI2L(&_gvn, length, tlcon, passed));
// Range check failed. Use ConvI2L with wide type because length may be invalid.
region->init_req(2, IfTrue(iff));
lengthx->init_req(2, ConvI2X(length));
set_control(region);
record_for_igvn(region);
record_for_igvn(lengthx);
} }
} }
#endif #endif
...@@ -3577,6 +3595,11 @@ Node* GraphKit::new_array(Node* klass_node, // array klass (maybe variable) ...@@ -3577,6 +3595,11 @@ Node* GraphKit::new_array(Node* klass_node, // array klass (maybe variable)
Node *mem = reset_memory(); Node *mem = reset_memory();
set_all_memory(mem); // Create new memory state set_all_memory(mem); // Create new memory state
if (initial_slow_test->is_Bool()) {
// Hide it behind a CMoveI, or else PhaseIdealLoop::split_up will get sick.
initial_slow_test = initial_slow_test->as_Bool()->as_int_value(&_gvn);
}
// Create the AllocateArrayNode and its result projections // Create the AllocateArrayNode and its result projections
AllocateArrayNode* alloc AllocateArrayNode* alloc
= new (C) AllocateArrayNode(C, AllocateArrayNode::alloc_type(TypeInt::INT), = new (C) AllocateArrayNode(C, AllocateArrayNode::alloc_type(TypeInt::INT),
......
...@@ -626,7 +626,9 @@ class GraphKit : public Phase { ...@@ -626,7 +626,9 @@ class GraphKit : public Phase {
// Return addressing for an array element. // Return addressing for an array element.
Node* array_element_address(Node* ary, Node* idx, BasicType elembt, Node* array_element_address(Node* ary, Node* idx, BasicType elembt,
// Optional constraint on the array size: // Optional constraint on the array size:
const TypeInt* sizetype = NULL); const TypeInt* sizetype = NULL,
// Optional control dependency (for example, on range check)
Node* ctrl = NULL);
// Return a load of array element at idx. // Return a load of array element at idx.
Node* load_array_element(Node* ctl, Node* ary, Node* idx, const TypeAryPtr* arytype); Node* load_array_element(Node* ctl, Node* ary, Node* idx, const TypeAryPtr* arytype);
......
...@@ -2438,7 +2438,7 @@ bool IdealLoopTree::iteration_split( PhaseIdealLoop *phase, Node_List &old_new ) ...@@ -2438,7 +2438,7 @@ bool IdealLoopTree::iteration_split( PhaseIdealLoop *phase, Node_List &old_new )
//============================================================================= //=============================================================================
// Process all the loops in the loop tree and replace any fill // Process all the loops in the loop tree and replace any fill
// patterns with an intrisc version. // patterns with an intrinsic version.
bool PhaseIdealLoop::do_intrinsify_fill() { bool PhaseIdealLoop::do_intrinsify_fill() {
bool changed = false; bool changed = false;
for (LoopTreeIterator iter(_ltree_root); !iter.done(); iter.next()) { for (LoopTreeIterator iter(_ltree_root); !iter.done(); iter.next()) {
...@@ -2536,8 +2536,9 @@ bool PhaseIdealLoop::match_fill_loop(IdealLoopTree* lpt, Node*& store, Node*& st ...@@ -2536,8 +2536,9 @@ bool PhaseIdealLoop::match_fill_loop(IdealLoopTree* lpt, Node*& store, Node*& st
} }
// Make sure the address expression can be handled. It should be // Make sure the address expression can be handled. It should be
// head->phi * elsize + con. head->phi might have a ConvI2L. // head->phi * elsize + con. head->phi might have a ConvI2L(CastII()).
Node* elements[4]; Node* elements[4];
Node* cast = NULL;
Node* conv = NULL; Node* conv = NULL;
bool found_index = false; bool found_index = false;
int count = store->in(MemNode::Address)->as_AddP()->unpack_offsets(elements, ARRAY_SIZE(elements)); int count = store->in(MemNode::Address)->as_AddP()->unpack_offsets(elements, ARRAY_SIZE(elements));
...@@ -2552,6 +2553,12 @@ bool PhaseIdealLoop::match_fill_loop(IdealLoopTree* lpt, Node*& store, Node*& st ...@@ -2552,6 +2553,12 @@ bool PhaseIdealLoop::match_fill_loop(IdealLoopTree* lpt, Node*& store, Node*& st
conv = value; conv = value;
value = value->in(1); value = value->in(1);
} }
if (value->Opcode() == Op_CastII &&
value->as_CastII()->has_range_check()) {
// Skip range check dependent CastII nodes
cast = value;
value = value->in(1);
}
#endif #endif
if (value != head->phi()) { if (value != head->phi()) {
msg = "unhandled shift in address"; msg = "unhandled shift in address";
...@@ -2564,9 +2571,16 @@ bool PhaseIdealLoop::match_fill_loop(IdealLoopTree* lpt, Node*& store, Node*& st ...@@ -2564,9 +2571,16 @@ bool PhaseIdealLoop::match_fill_loop(IdealLoopTree* lpt, Node*& store, Node*& st
} }
} }
} else if (n->Opcode() == Op_ConvI2L && conv == NULL) { } else if (n->Opcode() == Op_ConvI2L && conv == NULL) {
if (n->in(1) == head->phi()) { conv = n;
n = n->in(1);
if (n->Opcode() == Op_CastII &&
n->as_CastII()->has_range_check()) {
// Skip range check dependent CastII nodes
cast = n;
n = n->in(1);
}
if (n == head->phi()) {
found_index = true; found_index = true;
conv = n;
} else { } else {
msg = "unhandled input to ConvI2L"; msg = "unhandled input to ConvI2L";
} }
...@@ -2625,6 +2639,7 @@ bool PhaseIdealLoop::match_fill_loop(IdealLoopTree* lpt, Node*& store, Node*& st ...@@ -2625,6 +2639,7 @@ bool PhaseIdealLoop::match_fill_loop(IdealLoopTree* lpt, Node*& store, Node*& st
// Address elements are ok // Address elements are ok
if (con) ok.set(con->_idx); if (con) ok.set(con->_idx);
if (shift) ok.set(shift->_idx); if (shift) ok.set(shift->_idx);
if (cast) ok.set(cast->_idx);
if (conv) ok.set(conv->_idx); if (conv) ok.set(conv->_idx);
for (uint i = 0; msg == NULL && i < lpt->_body.size(); i++) { for (uint i = 0; msg == NULL && i < lpt->_body.size(); i++) {
......
...@@ -772,6 +772,9 @@ static bool merge_point_safe(Node* region) { ...@@ -772,6 +772,9 @@ static bool merge_point_safe(Node* region) {
#ifdef _LP64 #ifdef _LP64
if (m->Opcode() == Op_ConvI2L) if (m->Opcode() == Op_ConvI2L)
return false; return false;
if (m->is_CastII() && m->isa_CastII()->has_range_check()) {
return false;
}
#endif #endif
} }
} }
......
...@@ -521,6 +521,11 @@ Node *Node::clone() const { ...@@ -521,6 +521,11 @@ Node *Node::clone() const {
C->add_macro_node(n); C->add_macro_node(n);
if (is_expensive()) if (is_expensive())
C->add_expensive_node(n); C->add_expensive_node(n);
// If the cloned node is a range check dependent CastII, add it to the list.
CastIINode* cast = n->isa_CastII();
if (cast != NULL && cast->has_range_check()) {
C->add_range_check_cast(cast);
}
n->set_idx(C->next_unique()); // Get new unique index as well n->set_idx(C->next_unique()); // Get new unique index as well
debug_only( n->verify_construction() ); debug_only( n->verify_construction() );
...@@ -649,6 +654,11 @@ void Node::destruct() { ...@@ -649,6 +654,11 @@ void Node::destruct() {
if (is_expensive()) { if (is_expensive()) {
compile->remove_expensive_node(this); compile->remove_expensive_node(this);
} }
CastIINode* cast = isa_CastII();
if (cast != NULL && cast->has_range_check()) {
compile->remove_range_check_cast(cast);
}
if (is_SafePoint()) { if (is_SafePoint()) {
as_SafePoint()->delete_replaced_nodes(); as_SafePoint()->delete_replaced_nodes();
} }
...@@ -1344,6 +1354,10 @@ static void kill_dead_code( Node *dead, PhaseIterGVN *igvn ) { ...@@ -1344,6 +1354,10 @@ static void kill_dead_code( Node *dead, PhaseIterGVN *igvn ) {
if (dead->is_expensive()) { if (dead->is_expensive()) {
igvn->C->remove_expensive_node(dead); igvn->C->remove_expensive_node(dead);
} }
CastIINode* cast = dead->isa_CastII();
if (cast != NULL && cast->has_range_check()) {
igvn->C->remove_range_check_cast(cast);
}
igvn->C->record_dead_node(dead->_idx); igvn->C->record_dead_node(dead->_idx);
// Kill all inputs to the dead guy // Kill all inputs to the dead guy
for (uint i=0; i < dead->req(); i++) { for (uint i=0; i < dead->req(); i++) {
......
...@@ -54,6 +54,7 @@ class CallStaticJavaNode; ...@@ -54,6 +54,7 @@ class CallStaticJavaNode;
class CatchNode; class CatchNode;
class CatchProjNode; class CatchProjNode;
class CheckCastPPNode; class CheckCastPPNode;
class CastIINode;
class ClearArrayNode; class ClearArrayNode;
class CmpNode; class CmpNode;
class CodeBuffer; class CodeBuffer;
...@@ -603,6 +604,7 @@ public: ...@@ -603,6 +604,7 @@ public:
DEFINE_CLASS_ID(Type, Node, 2) DEFINE_CLASS_ID(Type, Node, 2)
DEFINE_CLASS_ID(Phi, Type, 0) DEFINE_CLASS_ID(Phi, Type, 0)
DEFINE_CLASS_ID(ConstraintCast, Type, 1) DEFINE_CLASS_ID(ConstraintCast, Type, 1)
DEFINE_CLASS_ID(CastII, ConstraintCast, 0)
DEFINE_CLASS_ID(CheckCastPP, Type, 2) DEFINE_CLASS_ID(CheckCastPP, Type, 2)
DEFINE_CLASS_ID(CMove, Type, 3) DEFINE_CLASS_ID(CMove, Type, 3)
DEFINE_CLASS_ID(SafePointScalarObject, Type, 4) DEFINE_CLASS_ID(SafePointScalarObject, Type, 4)
...@@ -727,6 +729,7 @@ public: ...@@ -727,6 +729,7 @@ public:
DEFINE_CLASS_QUERY(Catch) DEFINE_CLASS_QUERY(Catch)
DEFINE_CLASS_QUERY(CatchProj) DEFINE_CLASS_QUERY(CatchProj)
DEFINE_CLASS_QUERY(CheckCastPP) DEFINE_CLASS_QUERY(CheckCastPP)
DEFINE_CLASS_QUERY(CastII)
DEFINE_CLASS_QUERY(ConstraintCast) DEFINE_CLASS_QUERY(ConstraintCast)
DEFINE_CLASS_QUERY(ClearArray) DEFINE_CLASS_QUERY(ClearArray)
DEFINE_CLASS_QUERY(CMove) DEFINE_CLASS_QUERY(CMove)
......
...@@ -158,7 +158,9 @@ Node* Parse::array_addressing(BasicType type, int vals, const Type* *result2) { ...@@ -158,7 +158,9 @@ Node* Parse::array_addressing(BasicType type, int vals, const Type* *result2) {
// Check for always knowing you are throwing a range-check exception // Check for always knowing you are throwing a range-check exception
if (stopped()) return top(); if (stopped()) return top();
Node* ptr = array_element_address(ary, idx, type, sizetype); // Make array address computation control dependent to prevent it
// from floating above the range check during loop optimizations.
Node* ptr = array_element_address(ary, idx, type, sizetype, control());
if (result2 != NULL) *result2 = elemtype; if (result2 != NULL) *result2 = elemtype;
...@@ -461,9 +463,12 @@ bool Parse::create_jump_tables(Node* key_val, SwitchRange* lo, SwitchRange* hi) ...@@ -461,9 +463,12 @@ bool Parse::create_jump_tables(Node* key_val, SwitchRange* lo, SwitchRange* hi)
#ifdef _LP64 #ifdef _LP64
// Clean the 32-bit int into a real 64-bit offset. // Clean the 32-bit int into a real 64-bit offset.
// Otherwise, the jint value 0 might turn into an offset of 0x0800000000. // Otherwise, the jint value 0 might turn into an offset of 0x0800000000.
const TypeLong* lkeytype = TypeLong::make(CONST64(0), num_cases-1, Type::WidenMin); const TypeInt* ikeytype = TypeInt::make(0, num_cases-1, Type::WidenMin);
key_val = _gvn.transform( new (C) ConvI2LNode(key_val, lkeytype) ); // Make I2L conversion control dependent to prevent it from
// floating above the range check during loop optimizations.
key_val = C->constrained_convI2L(&_gvn, key_val, ikeytype, control());
#endif #endif
// Shift the value by wordsize so we have an index into the table, rather // Shift the value by wordsize so we have an index into the table, rather
// than a switch value // than a switch value
Node *shiftWord = _gvn.MakeConX(wordSize); Node *shiftWord = _gvn.MakeConX(wordSize);
......
...@@ -1339,6 +1339,10 @@ void PhaseIterGVN::remove_globally_dead_node( Node *dead ) { ...@@ -1339,6 +1339,10 @@ void PhaseIterGVN::remove_globally_dead_node( Node *dead ) {
if (dead->is_expensive()) { if (dead->is_expensive()) {
C->remove_expensive_node(dead); C->remove_expensive_node(dead);
} }
CastIINode* cast = dead->isa_CastII();
if (cast != NULL && cast->has_range_check()) {
C->remove_range_check_cast(cast);
}
} }
} // while (_stack.is_nonempty()) } // while (_stack.is_nonempty())
} }
......
...@@ -2388,6 +2388,11 @@ bool SWPointer::scaled_iv(Node* n) { ...@@ -2388,6 +2388,11 @@ bool SWPointer::scaled_iv(Node* n) {
return true; return true;
} }
} else if (opc == Op_ConvI2L) { } else if (opc == Op_ConvI2L) {
if (n->in(1)->Opcode() == Op_CastII &&
n->in(1)->as_CastII()->has_range_check()) {
// Skip range check dependent CastII nodes
n = n->in(1);
}
if (scaled_iv_plus_offset(n->in(1))) { if (scaled_iv_plus_offset(n->in(1))) {
return true; return true;
} }
......
/*
* Copyright (c) 2016, 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.
*/
/*
* @test
* @bug 8078262
* @summary Tests correct dominator information after loop peeling.
* @run main/othervm -Xcomp -XX:CompileCommand=compileonly,TestLoopPeeling::test* TestLoopPeeling
*/
public class TestLoopPeeling {
public int[] array = new int[100];
public static void main(String args[]) {
TestLoopPeeling test = new TestLoopPeeling();
try {
test.testArrayAccess(0, 1);
test.testArrayAllocation(0, 1);
} catch (Exception e) {
// Ignore exceptions
}
}
public void testArrayAccess(int index, int inc) {
int storeIndex = -1;
for (; index < 10; index += inc) {
// This loop invariant check triggers loop peeling because it can
// be moved out of the loop (see 'IdealLoopTree::policy_peeling').
if (inc == 42) return;
// This loop variant usage of LShiftL( ConvI2L( Phi(storeIndex) ) )
// prevents the split if optimization that would otherwise clone the
// LShiftL and ConvI2L nodes and assign them to their corresponding array
// address computation (see 'PhaseIdealLoop::split_if_with_blocks_post').
if (storeIndex > 0 && array[storeIndex] == 42) return;
if (index == 42) {
// This store and the corresponding range check are moved out of the
// loop and both used after old loop and the peeled iteration exit.
// For the peeled iteration, storeIndex is always -1 and the ConvI2L
// is replaced by TOP. However, the range check is not folded because
// we don't do the split if optimization in PhaseIdealLoop2.
// As a result, we have a (dead) control path from the peeled iteration
// to the StoreI but the data path is removed.
array[storeIndex] = 1;
return;
}
storeIndex++;
}
}
public byte[] testArrayAllocation(int index, int inc) {
int allocationCount = -1;
byte[] result;
for (; index < 10; index += inc) {
// This loop invariant check triggers loop peeling because it can
// be moved out of the loop (see 'IdealLoopTree::policy_peeling').
if (inc == 42) return null;
if (index == 42) {
// This allocation and the corresponding size check are moved out of the
// loop and both used after old loop and the peeled iteration exit.
// For the peeled iteration, allocationCount is always -1 and the ConvI2L
// is replaced by TOP. However, the size check is not folded because
// we don't do the split if optimization in PhaseIdealLoop2.
// As a result, we have a (dead) control path from the peeled iteration
// to the allocation but the data path is removed.
result = new byte[allocationCount];
return result;
}
allocationCount++;
}
return null;
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册