Skip to content
Permalink
Browse files

8223051: support loops with long (64b) trip counts

Reviewed-by: vlivanov, thartmann, jrose
  • Loading branch information
rwestrel committed Oct 19, 2020
1 parent e9be2db commit e76de189561b94b611630a49ebacde67c1512129
@@ -787,7 +787,13 @@
"Move predicates out of loops based on profiling data") \
\
product(bool, ExpandSubTypeCheckAtParseTime, false, DIAGNOSTIC, \
"Do not use subtype check macro node")
"Do not use subtype check macro node") \
\
develop(uintx, StressLongCountedLoop, 0, \
"if > 0, convert int counted loops to long counted loops" \
"to stress handling of long counted loops: run inner loop" \
"for at most jint_max / StressLongCountedLoop") \
range(0, max_juint) \

// end of C2_FLAGS

@@ -967,6 +967,46 @@ bool CallJavaNode::cmp( const Node &n ) const {
return CallNode::cmp(call) && _method == call._method &&
_override_symbolic_info == call._override_symbolic_info;
}

void CallJavaNode::copy_call_debug_info(PhaseIterGVN* phase, SafePointNode *sfpt) {
// Copy debug information and adjust JVMState information
uint old_dbg_start = sfpt->is_Call() ? sfpt->as_Call()->tf()->domain()->cnt() : (uint)TypeFunc::Parms+1;
uint new_dbg_start = tf()->domain()->cnt();
int jvms_adj = new_dbg_start - old_dbg_start;
assert (new_dbg_start == req(), "argument count mismatch");
Compile* C = phase->C;

// SafePointScalarObject node could be referenced several times in debug info.
// Use Dict to record cloned nodes.
Dict* sosn_map = new Dict(cmpkey,hashkey);
for (uint i = old_dbg_start; i < sfpt->req(); i++) {
Node* old_in = sfpt->in(i);
// Clone old SafePointScalarObjectNodes, adjusting their field contents.
if (old_in != NULL && old_in->is_SafePointScalarObject()) {
SafePointScalarObjectNode* old_sosn = old_in->as_SafePointScalarObject();
bool new_node;
Node* new_in = old_sosn->clone(sosn_map, new_node);
if (new_node) { // New node?
new_in->set_req(0, C->root()); // reset control edge
new_in = phase->transform(new_in); // Register new node.
}
old_in = new_in;
}
add_req(old_in);
}

// JVMS may be shared so clone it before we modify it
set_jvms(sfpt->jvms() != NULL ? sfpt->jvms()->clone_deep(C) : NULL);
for (JVMState *jvms = this->jvms(); jvms != NULL; jvms = jvms->caller()) {
jvms->set_map(this);
jvms->set_locoff(jvms->locoff()+jvms_adj);
jvms->set_stkoff(jvms->stkoff()+jvms_adj);
jvms->set_monoff(jvms->monoff()+jvms_adj);
jvms->set_scloff(jvms->scloff()+jvms_adj);
jvms->set_endoff(jvms->endoff()+jvms_adj);
}
}

#ifdef ASSERT
bool CallJavaNode::validate_symbolic_info() const {
if (method() == NULL) {
@@ -1159,7 +1199,9 @@ Node* SafePointNode::Identity(PhaseGVN* phase) {
if( in(TypeFunc::Control)->is_SafePoint() )
return in(TypeFunc::Control);

if( in(0)->is_Proj() ) {
// Transforming long counted loops requires a safepoint node. Do not
// eliminate a safepoint until loop opts are over.
if (in(0)->is_Proj() && !phase->C->major_progress()) {
Node *n0 = in(0)->in(0);
// Check if he is a call projection (except Leaf Call)
if( n0->is_Catch() ) {
@@ -1332,11 +1374,13 @@ uint SafePointScalarObjectNode::match_edge(uint idx) const {
}

SafePointScalarObjectNode*
SafePointScalarObjectNode::clone(Dict* sosn_map) const {
SafePointScalarObjectNode::clone(Dict* sosn_map, bool& new_node) const {
void* cached = (*sosn_map)[(void*)this];
if (cached != NULL) {
new_node = false;
return (SafePointScalarObjectNode*)cached;
}
new_node = true;
SafePointScalarObjectNode* res = (SafePointScalarObjectNode*)Node::clone();
sosn_map->Insert((void*)this, (void*)res);
return res;
@@ -527,7 +527,7 @@ class SafePointScalarObjectNode: public TypeNode {
// corresponds appropriately to "this" in "new_call". Assumes that
// "sosn_map" is a map, specific to the translation of "s" to "new_call",
// mapping old SafePointScalarObjectNodes to new, to avoid multiple copies.
SafePointScalarObjectNode* clone(Dict* sosn_map) const;
SafePointScalarObjectNode* clone(Dict* sosn_map, bool& new_node) const;

#ifndef PRODUCT
virtual void dump_spec(outputStream *st) const;
@@ -635,6 +635,8 @@ class CallNode : public SafePointNode {

bool is_call_to_arraycopystub() const;

virtual void copy_call_debug_info(PhaseIterGVN* phase, SafePointNode *sfpt) {}

#ifndef PRODUCT
virtual void dump_req(outputStream *st = tty) const;
virtual void dump_spec(outputStream *st) const;
@@ -677,6 +679,7 @@ class CallJavaNode : public CallNode {
bool is_method_handle_invoke() const { return _method_handle_invoke; }
void set_override_symbolic_info(bool f) { _override_symbolic_info = f; }
bool override_symbolic_info() const { return _override_symbolic_info; }
void copy_call_debug_info(PhaseIterGVN* phase, SafePointNode *sfpt);

DEBUG_ONLY( bool validate_symbolic_info() const; )

@@ -3426,6 +3426,7 @@ void Compile::final_graph_reshaping_main_switch(Node* n, Final_Reshape_Counts& f
}
break;
case Op_Loop:
assert(!n->as_Loop()->is_transformed_long_loop(), "should have been turned into a counted loop");
case Op_CountedLoop:
case Op_OuterStripMinedLoop:
if (n->as_Loop()->is_inner_loop()) {
@@ -449,9 +449,13 @@ const Type* ConvL2INode::Value(PhaseGVN* phase) const {
const Type *t = phase->type( in(1) );
if( t == Type::TOP ) return Type::TOP;
const TypeLong *tl = t->is_long();
if (tl->is_con())
if (tl->is_con()) {
// Easy case.
return TypeInt::make((jint)tl->get_con());
}
if (tl->_lo >= min_jint && tl->_hi <= max_jint) {
return TypeInt::make((jint)tl->_lo, (jint)tl->_hi, tl->_widen);
}
return bottom_type();
}

1 comment on commit e76de18

@bridgekeeper

This comment has been minimized.

Copy link

@bridgekeeper bridgekeeper bot commented on e76de18 Oct 19, 2020

Please sign in to comment.