mirror of
https://github.com/openjdk/jdk.git
synced 2025-09-21 03:24:38 +02:00
6747051: Improve code and implicit null check generation for compressed oops
Push DecodeN node below the Null check to the non-null path to use the mach node without 0 test. Reviewed-by: rasbold, never
This commit is contained in:
parent
4b1e242299
commit
b15796424e
6 changed files with 209 additions and 32 deletions
|
@ -2075,6 +2075,44 @@ static void final_graph_reshaping_impl( Node *n, Final_Reshape_Counts &fpu ) {
|
|||
}
|
||||
|
||||
#ifdef _LP64
|
||||
case Op_CastPP:
|
||||
if (n->in(1)->is_DecodeN() && UseImplicitNullCheckForNarrowOop) {
|
||||
Compile* C = Compile::current();
|
||||
Node* in1 = n->in(1);
|
||||
const Type* t = n->bottom_type();
|
||||
Node* new_in1 = in1->clone();
|
||||
new_in1->as_DecodeN()->set_type(t);
|
||||
|
||||
if (!Matcher::clone_shift_expressions) {
|
||||
//
|
||||
// x86, ARM and friends can handle 2 adds in addressing mode
|
||||
// and Matcher can fold a DecodeN node into address by using
|
||||
// a narrow oop directly and do implicit NULL check in address:
|
||||
//
|
||||
// [R12 + narrow_oop_reg<<3 + offset]
|
||||
// NullCheck narrow_oop_reg
|
||||
//
|
||||
// On other platforms (Sparc) we have to keep new DecodeN node and
|
||||
// use it to do implicit NULL check in address:
|
||||
//
|
||||
// decode_not_null narrow_oop_reg, base_reg
|
||||
// [base_reg + offset]
|
||||
// NullCheck base_reg
|
||||
//
|
||||
// Pin the new DecodeN node to non-null path on these patforms (Sparc)
|
||||
// to keep the information to which NULL check the new DecodeN node
|
||||
// corresponds to use it as value in implicit_null_check().
|
||||
//
|
||||
new_in1->set_req(0, n->in(0));
|
||||
}
|
||||
|
||||
n->subsume_by(new_in1);
|
||||
if (in1->outcnt() == 0) {
|
||||
in1->disconnect_inputs(NULL);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case Op_CmpP:
|
||||
// Do this transformation here to preserve CmpPNode::sub() and
|
||||
// other TypePtr related Ideal optimizations (for example, ptr nullness).
|
||||
|
@ -2094,24 +2132,44 @@ static void final_graph_reshaping_impl( Node *n, Final_Reshape_Counts &fpu ) {
|
|||
} else if (in2->Opcode() == Op_ConP) {
|
||||
const Type* t = in2->bottom_type();
|
||||
if (t == TypePtr::NULL_PTR && UseImplicitNullCheckForNarrowOop) {
|
||||
if (Matcher::clone_shift_expressions) {
|
||||
// x86, ARM and friends can handle 2 adds in addressing mode.
|
||||
// Decode a narrow oop and do implicit NULL check in address
|
||||
// [R12 + narrow_oop_reg<<3 + offset]
|
||||
new_in2 = ConNode::make(C, TypeNarrowOop::NULL_PTR);
|
||||
} else {
|
||||
// Don't replace CmpP(o ,null) if 'o' is used in AddP
|
||||
// to generate implicit NULL check on Sparc where
|
||||
// narrow oops can't be used in address.
|
||||
uint i = 0;
|
||||
for (; i < in1->outcnt(); i++) {
|
||||
if (in1->raw_out(i)->is_AddP())
|
||||
break;
|
||||
}
|
||||
if (i >= in1->outcnt()) {
|
||||
new_in2 = ConNode::make(C, TypeNarrowOop::NULL_PTR);
|
||||
}
|
||||
}
|
||||
new_in2 = ConNode::make(C, TypeNarrowOop::NULL_PTR);
|
||||
//
|
||||
// This transformation together with CastPP transformation above
|
||||
// will generated code for implicit NULL checks for compressed oops.
|
||||
//
|
||||
// The original code after Optimize()
|
||||
//
|
||||
// LoadN memory, narrow_oop_reg
|
||||
// decode narrow_oop_reg, base_reg
|
||||
// CmpP base_reg, NULL
|
||||
// CastPP base_reg // NotNull
|
||||
// Load [base_reg + offset], val_reg
|
||||
//
|
||||
// after these transformations will be
|
||||
//
|
||||
// LoadN memory, narrow_oop_reg
|
||||
// CmpN narrow_oop_reg, NULL
|
||||
// decode_not_null narrow_oop_reg, base_reg
|
||||
// Load [base_reg + offset], val_reg
|
||||
//
|
||||
// and the uncommon path (== NULL) will use narrow_oop_reg directly
|
||||
// since narrow oops can be used in debug info now (see the code in
|
||||
// final_graph_reshaping_walk()).
|
||||
//
|
||||
// At the end the code will be matched to
|
||||
// on x86:
|
||||
//
|
||||
// Load_narrow_oop memory, narrow_oop_reg
|
||||
// Load [R12 + narrow_oop_reg<<3 + offset], val_reg
|
||||
// NullCheck narrow_oop_reg
|
||||
//
|
||||
// and on sparc:
|
||||
//
|
||||
// Load_narrow_oop memory, narrow_oop_reg
|
||||
// decode_not_null narrow_oop_reg, base_reg
|
||||
// Load [base_reg + offset], val_reg
|
||||
// NullCheck base_reg
|
||||
//
|
||||
} else if (t->isa_oopptr()) {
|
||||
new_in2 = ConNode::make(C, t->make_narrowoop());
|
||||
}
|
||||
|
@ -2128,6 +2186,49 @@ static void final_graph_reshaping_impl( Node *n, Final_Reshape_Counts &fpu ) {
|
|||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case Op_DecodeN:
|
||||
assert(!n->in(1)->is_EncodeP(), "should be optimized out");
|
||||
break;
|
||||
|
||||
case Op_EncodeP: {
|
||||
Node* in1 = n->in(1);
|
||||
if (in1->is_DecodeN()) {
|
||||
n->subsume_by(in1->in(1));
|
||||
} else if (in1->Opcode() == Op_ConP) {
|
||||
Compile* C = Compile::current();
|
||||
const Type* t = in1->bottom_type();
|
||||
if (t == TypePtr::NULL_PTR) {
|
||||
n->subsume_by(ConNode::make(C, TypeNarrowOop::NULL_PTR));
|
||||
} else if (t->isa_oopptr()) {
|
||||
n->subsume_by(ConNode::make(C, t->make_narrowoop()));
|
||||
}
|
||||
}
|
||||
if (in1->outcnt() == 0) {
|
||||
in1->disconnect_inputs(NULL);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case Op_Phi:
|
||||
if (n->as_Phi()->bottom_type()->isa_narrowoop()) {
|
||||
// The EncodeP optimization may create Phi with the same edges
|
||||
// for all paths. It is not handled well by Register Allocator.
|
||||
Node* unique_in = n->in(1);
|
||||
assert(unique_in != NULL, "");
|
||||
uint cnt = n->req();
|
||||
for (uint i = 2; i < cnt; i++) {
|
||||
Node* m = n->in(i);
|
||||
assert(m != NULL, "");
|
||||
if (unique_in != m)
|
||||
unique_in = NULL;
|
||||
}
|
||||
if (unique_in != NULL) {
|
||||
n->subsume_by(unique_in);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
#endif
|
||||
|
||||
case Op_ModI:
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue