Skip to content

Commit 2701ce2

Browse files
committed
8380191: [lworld] [BACKOUT] OptimizePtrCompare is too conservative
Reviewed-by: dcubed
1 parent 329029d commit 2701ce2

4 files changed

Lines changed: 35 additions & 260 deletions

File tree

src/hotspot/share/opto/escape.cpp

Lines changed: 32 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -1586,39 +1586,6 @@ void ConnectionGraph::add_objload_to_connection_graph(Node *n, Unique_Node_List
15861586
}
15871587
}
15881588

1589-
void ConnectionGraph::add_proj(Node* n, Unique_Node_List* delayed_worklist) {
1590-
if (n->as_Proj()->_con == TypeFunc::Parms && n->in(0)->is_Call() && n->in(0)->as_Call()->returns_pointer()) {
1591-
add_local_var_and_edge(n, PointsToNode::NoEscape, n->in(0), delayed_worklist);
1592-
} else if (n->in(0)->is_LoadFlat()) {
1593-
// Treat LoadFlat outputs similar to a call return value
1594-
add_local_var_and_edge(n, PointsToNode::NoEscape, n->in(0), delayed_worklist);
1595-
} else if (n->as_Proj()->_con >= TypeFunc::Parms && n->in(0)->is_Call() && n->bottom_type()->isa_ptr()) {
1596-
CallNode* call = n->in(0)->as_Call();
1597-
assert(call->tf()->returns_inline_type_as_fields(), "");
1598-
ciMethod* meth = n->in(0)->as_CallJava()->method();
1599-
BCEscapeAnalyzer* call_analyzer = (meth != nullptr) ? meth->get_bcea() : nullptr;
1600-
const TypeTuple* d = call->tf()->domain_sig();
1601-
uint i = d->cnt();
1602-
if (call_analyzer != nullptr) {
1603-
for (i = TypeFunc::Parms; i < d->cnt(); i++) {
1604-
if (d->field_at(i)->isa_ptr() != nullptr &&
1605-
call_analyzer->is_arg_returned(i - TypeFunc::Parms)) {
1606-
break;
1607-
}
1608-
}
1609-
}
1610-
if (n->as_Proj()->_con == TypeFunc::Parms || i >= d->cnt() || !scalarized_arg_with_compatible_return(call->as_CallJava(), i)) {
1611-
// either:
1612-
// - not an argument returned
1613-
// - the returned buffer for a returned scalarized argument
1614-
// - an incompatible returned scalarized argument
1615-
add_local_var_and_edge(n, PointsToNode::NoEscape, n->in(0), delayed_worklist);
1616-
} else {
1617-
add_local_var(n, PointsToNode::NoEscape);
1618-
}
1619-
}
1620-
}
1621-
16221589
// Populate Connection Graph with PointsTo nodes and create simple
16231590
// connection graph edges.
16241591
void ConnectionGraph::add_node_to_connection_graph(Node *n, Unique_Node_List *delayed_worklist) {
@@ -1782,7 +1749,15 @@ void ConnectionGraph::add_node_to_connection_graph(Node *n, Unique_Node_List *de
17821749
break;
17831750
case Op_Proj: {
17841751
// we are only interested in the oop result projection from a call
1785-
add_proj(n, delayed_worklist);
1752+
if (n->as_Proj()->_con >= TypeFunc::Parms && n->in(0)->is_Call() &&
1753+
(n->in(0)->as_Call()->returns_pointer() || n->bottom_type()->isa_ptr())) {
1754+
assert((n->as_Proj()->_con == TypeFunc::Parms && n->in(0)->as_Call()->returns_pointer()) ||
1755+
n->in(0)->as_Call()->tf()->returns_inline_type_as_fields(), "what kind of oop return is it?");
1756+
add_local_var_and_edge(n, PointsToNode::NoEscape, n->in(0), delayed_worklist);
1757+
} else if (n->as_Proj()->_con >= TypeFunc::Parms && n->in(0)->is_LoadFlat() && igvn->type(n)->isa_ptr()) {
1758+
// Treat LoadFlat outputs similar to a call return value
1759+
add_local_var_and_edge(n, PointsToNode::NoEscape, n->in(0), delayed_worklist);
1760+
}
17861761
break;
17871762
}
17881763
case Op_Rethrow: // Exception object escapes
@@ -1952,7 +1927,15 @@ void ConnectionGraph::add_final_edges(Node *n) {
19521927
break;
19531928
}
19541929
case Op_Proj: {
1955-
add_proj(n, nullptr);
1930+
if (n->in(0)->is_Call()) {
1931+
// we are only interested in the oop result projection from a call
1932+
assert((n->as_Proj()->_con == TypeFunc::Parms && n->in(0)->as_Call()->returns_pointer()) ||
1933+
n->in(0)->as_Call()->tf()->returns_inline_type_as_fields(), "what kind of oop return is it?");
1934+
add_local_var_and_edge(n, PointsToNode::NoEscape, n->in(0), nullptr);
1935+
} else if (n->in(0)->is_LoadFlat()) {
1936+
// Treat LoadFlat outputs similar to a call return value
1937+
add_local_var_and_edge(n, PointsToNode::NoEscape, n->in(0), nullptr);
1938+
}
19561939
break;
19571940
}
19581941
case Op_Rethrow: // Exception object escapes
@@ -2146,8 +2129,6 @@ class DomainIterator : public StackObj {
21462129
uint _i_domain_cc;
21472130
int _i_sig_cc;
21482131
uint _depth;
2149-
uint _first_field_pos;
2150-
const bool _is_static;
21512132

21522133
void next_helper() {
21532134
if (_sig_cc == nullptr) {
@@ -2156,22 +2137,14 @@ class DomainIterator : public StackObj {
21562137
BasicType prev_bt = _i_sig_cc > 0 ? _sig_cc->at(_i_sig_cc-1)._bt : T_ILLEGAL;
21572138
while (_i_sig_cc < _sig_cc->length()) {
21582139
BasicType bt = _sig_cc->at(_i_sig_cc)._bt;
2159-
assert(bt != T_VOID || _sig_cc->at(_i_sig_cc-1)._bt == prev_bt, "incorrect prev bt");
2140+
assert(bt != T_VOID || _sig_cc->at(_i_sig_cc-1)._bt == prev_bt, "");
21602141
if (bt == T_METADATA) {
2161-
if (_depth == 0) {
2162-
_first_field_pos = _i_domain_cc;
2163-
}
21642142
_depth++;
21652143
} else if (bt == T_VOID && (prev_bt != T_LONG && prev_bt != T_DOUBLE)) {
21662144
_depth--;
21672145
if (_depth == 0) {
21682146
_i_domain++;
21692147
}
2170-
} else if (bt == T_BOOLEAN && prev_bt == T_METADATA && (_is_static || _i_domain > 0) && _sig_cc->at(_i_sig_cc)._offset == -1) {
2171-
assert(_sig_cc->at(_i_sig_cc)._null_marker, "null marker expected right after T_METADATA");
2172-
assert(_depth == 1, "only root value null marker");
2173-
_i_domain_cc++;
2174-
_first_field_pos = _i_domain_cc;
21752148
} else {
21762149
return;
21772150
}
@@ -2189,9 +2162,7 @@ class DomainIterator : public StackObj {
21892162
_i_domain(TypeFunc::Parms),
21902163
_i_domain_cc(TypeFunc::Parms),
21912164
_i_sig_cc(0),
2192-
_depth(0),
2193-
_first_field_pos(0),
2194-
_is_static(call->method()->is_static()) {
2165+
_depth(0) {
21952166
next_helper();
21962167
}
21972168

@@ -2226,11 +2197,6 @@ class DomainIterator : public StackObj {
22262197
const Type* current_domain_cc() const {
22272198
return _domain_cc->field_at(_i_domain_cc);
22282199
}
2229-
2230-
uint first_field_pos() const {
2231-
assert(_first_field_pos >= TypeFunc::Parms, "not yet updated?");
2232-
return _first_field_pos;
2233-
}
22342200
};
22352201

22362202
void ConnectionGraph::add_call_node(CallNode* call) {
@@ -2342,25 +2308,21 @@ void ConnectionGraph::add_call_node(CallNode* call) {
23422308
add_java_object(call, PointsToNode::NoEscape);
23432309
set_not_scalar_replaceable(ptnode_adr(call_idx) NOT_PRODUCT(COMMA "is result of call"));
23442310
} else {
2311+
bool ret_arg = false;
23452312
// Determine whether any arguments are returned.
2346-
const TypeTuple* d = call->tf()->domain_sig();
2347-
uint i = TypeFunc::Parms;
2348-
for (; i < d->cnt(); i++) {
2349-
if (d->field_at(i)->isa_ptr() != nullptr &&
2350-
call_analyzer->is_arg_returned(i - TypeFunc::Parms)) {
2313+
for (DomainIterator di(call->as_CallJava()); di.has_next(); di.next()) {
2314+
uint arg = di.i_domain() - TypeFunc::Parms;
2315+
if (di.current_domain_cc()->isa_ptr() != nullptr &&
2316+
call_analyzer->is_arg_returned(arg) &&
2317+
!meth->is_scalarized_arg(arg)) {
2318+
ret_arg = true;
23512319
break;
23522320
}
23532321
}
2354-
// For non scalarized argument/return: add_proj() adds an edge between the return projection and the call,
2355-
// process_call_arguments() adds an edge between the call and the argument
2356-
// For scalarized argument/return: process_call_arguments() adds an edge between a call projection for a field
2357-
// and the argument input to the call for that field. An edge is added between the projection for the returned
2358-
// buffer and the call.
2359-
if (i < d->cnt() && !scalarized_arg_with_compatible_return(call->as_CallJava(), i)) {
2360-
// returns non scalarized argument or incompatible return
2322+
if (ret_arg) {
23612323
add_local_var(call, PointsToNode::ArgEscape);
23622324
} else {
2363-
// Returns unknown object or scalarized argument being returned
2325+
// Returns unknown object.
23642326
map_ideal_node(call, phantom_obj);
23652327
}
23662328
}
@@ -2373,16 +2335,6 @@ void ConnectionGraph::add_call_node(CallNode* call) {
23732335
}
23742336
}
23752337

2376-
// Check that the return type is compatible with the type of the argument being returned i.e. that there's no cast that
2377-
// fails in the method
2378-
bool ConnectionGraph::scalarized_arg_with_compatible_return(CallJavaNode* call, uint k) {
2379-
ciMethod* meth = call->method();
2380-
BCEscapeAnalyzer* call_analyzer = meth->get_bcea();
2381-
assert(call_analyzer->is_arg_returned(k - TypeFunc::Parms), "only for returned arg");
2382-
return meth->is_scalarized_arg(k - TypeFunc::Parms) &&
2383-
call->tf()->domain_sig()->field_at(k)->meet(TypePtr::NULL_PTR)->higher_equal(call->tf()->range_sig()->field_at(TypeFunc::Parms));
2384-
}
2385-
23862338
void ConnectionGraph::process_call_arguments(CallNode *call) {
23872339
bool is_arraycopy = false;
23882340
switch (call->Opcode()) {
@@ -2575,27 +2527,11 @@ void ConnectionGraph::process_call_arguments(CallNode *call) {
25752527
const Type* at = di.current_domain_cc();
25762528
Node* arg = call->in(di.i_domain_cc());
25772529
PointsToNode* arg_ptn = ptnode_adr(arg->_idx);
2578-
assert(!call_analyzer->is_arg_returned(k) || !scalarized_arg_with_compatible_return(call->as_CallJava(), di.i_domain()) ||
2579-
call->proj_out_or_null(di.i_domain_cc() - di.first_field_pos() + TypeFunc::Parms + 1) == nullptr ||
2580-
_igvn->type(call->proj_out_or_null(di.i_domain_cc() - di.first_field_pos() + TypeFunc::Parms + 1)) == at,
2581-
"scalarized return and scalarized argument should match");
25822530
if (at->isa_ptr() != nullptr &&
2583-
call_analyzer->is_arg_returned(k)) {
2531+
call_analyzer->is_arg_returned(k) &&
2532+
!meth->is_scalarized_arg(k)) {
25842533
// The call returns arguments.
2585-
if (scalarized_arg_with_compatible_return(call->as_CallJava(), di.i_domain())) {
2586-
ProjNode* res_proj = call->proj_out_or_null(di.i_domain_cc() - di.first_field_pos() + TypeFunc::Parms + 1);
2587-
if (res_proj != nullptr) {
2588-
assert(_igvn->type(res_proj)->isa_ptr(), "scalarized return and scalarized argument should match");
2589-
if (res_proj->_con != TypeFunc::Parms) {
2590-
// add an edge between the result projection for a field and the argument projection for the same argument field
2591-
PointsToNode* proj_ptn = ptnode_adr(res_proj->_idx);
2592-
add_edge(proj_ptn, arg_ptn);
2593-
if (!call_analyzer->is_return_local()) {
2594-
add_edge(proj_ptn, phantom_obj);
2595-
}
2596-
}
2597-
}
2598-
} else if (call_ptn != nullptr) { // Is call's result used?
2534+
if (call_ptn != nullptr) { // Is call's result used?
25992535
assert(call_ptn->is_LocalVar(), "node should be registered");
26002536
assert(arg_ptn != nullptr, "node should be registered");
26012537
add_edge(call_ptn, arg_ptn);

src/hotspot/share/opto/escape.hpp

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -665,8 +665,6 @@ class ConnectionGraph: public ArenaObj {
665665
// Utility function for nodes that load an object
666666
void add_objload_to_connection_graph(Node* n, Unique_Node_List* delayed_worklist);
667667

668-
void add_proj(Node* n, Unique_Node_List* delayed_worklist);
669-
670668
// Add LocalVar node and edge if possible
671669
void add_local_var_and_edge(Node* n, PointsToNode::EscapeState es, Node* to,
672670
Unique_Node_List *delayed_worklist) {
@@ -692,8 +690,6 @@ class ConnectionGraph: public ArenaObj {
692690
void add_to_congraph_unsafe_access(Node* n, uint opcode, Unique_Node_List* delayed_worklist);
693691
bool add_final_edges_unsafe_access(Node* n, uint opcode);
694692

695-
bool scalarized_arg_with_compatible_return(CallJavaNode* call, uint k);
696-
697693
#ifndef PRODUCT
698694
static int _no_escape_counter;
699695
static int _arg_escape_counter;

test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -653,11 +653,6 @@ public static void callLeafNoFpOfMethodNodes(String irNodePlaceholder, String ca
653653
beforeMatchingNameRegex(CMP_N, "CmpN");
654654
}
655655

656-
public static final String CMP_P_OR_N = PREFIX + "CMP_P_OR_N" + POSTFIX;
657-
static {
658-
beforeMatchingNameRegex(CMP_P_OR_N, "Cmp(P|N)");
659-
}
660-
661656
public static final String CMP_LT_MASK = PREFIX + "CMP_LT_MASK" + POSTFIX;
662657
static {
663658
beforeMatchingNameRegex(CMP_LT_MASK, "CmpLTMask");

0 commit comments

Comments
 (0)