hotspot/src/share/vm/opto/matcher.cpp
Print this page
rev 611 : Merge
@@ -1,10 +1,10 @@
#ifdef USE_PRAGMA_IDENT_SRC
#pragma ident "@(#)matcher.cpp 1.388 07/09/28 10:33:13 JVM"
#endif
/*
- * Copyright 1997-2007 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright 1997-2008 Sun Microsystems, Inc. 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.
@@ -31,11 +31,11 @@
OptoReg::Name OptoReg::c_frame_pointer;
const int Matcher::base2reg[Type::lastype] = {
- Node::NotAMachineReg,0,0, Op_RegI, Op_RegL, 0,
+ Node::NotAMachineReg,0,0, Op_RegI, Op_RegL, 0, Op_RegN,
Node::NotAMachineReg, Node::NotAMachineReg, /* tuple, array */
Op_RegP, Op_RegP, Op_RegP, Op_RegP, Op_RegP, Op_RegP, /* the pointers */
0, 0/*abio*/,
Op_RegP /* Return address */, 0, /* the memories */
Op_RegF, Op_RegF, Op_RegF, Op_RegD, Op_RegD, Op_RegD,
@@ -52,12 +52,13 @@
//---------------------------Matcher-------------------------------------------
Matcher::Matcher( Node_List &proj_list ) :
PhaseTransform( Phase::Ins_Select ),
#ifdef ASSERT
_old2new_map(C->comp_arena()),
+ _new2old_map(C->comp_arena()),
#endif
- _shared_constants(C->comp_arena()),
+ _shared_nodes(C->comp_arena()),
_reduceOp(reduceOp), _leftOp(leftOp), _rightOp(rightOp),
_swallowed(swallowed),
_begin_inst_chain_rule(_BEGIN_INST_CHAIN_RULE),
_end_inst_chain_rule(_END_INST_CHAIN_RULE),
_must_clone(must_clone), _proj_list(proj_list),
@@ -71,20 +72,23 @@
_shared(&_states_arena),
_dontcare(&_states_arena) {
C->set_matcher(this);
idealreg2spillmask[Op_RegI] = NULL;
+ idealreg2spillmask[Op_RegN] = NULL;
idealreg2spillmask[Op_RegL] = NULL;
idealreg2spillmask[Op_RegF] = NULL;
idealreg2spillmask[Op_RegD] = NULL;
idealreg2spillmask[Op_RegP] = NULL;
idealreg2debugmask[Op_RegI] = NULL;
+ idealreg2debugmask[Op_RegN] = NULL;
idealreg2debugmask[Op_RegL] = NULL;
idealreg2debugmask[Op_RegF] = NULL;
idealreg2debugmask[Op_RegD] = NULL;
idealreg2debugmask[Op_RegP] = NULL;
+ debug_only(_mem_node = NULL;) // Ideal memory node consumed by mach node
}
//------------------------------warp_incoming_stk_arg------------------------
// This warps a VMReg into an OptoReg::Name
OptoReg::Name Matcher::warp_incoming_stk_arg( VMReg reg ) {
@@ -270,11 +274,11 @@
// _shared[_idx] is cleared is guaranteed to not be shared, and thus
// can be a valid interior of some tree.
find_shared( C->root() );
find_shared( C->top() );
- C->print_method("Before Matching", 2);
+ C->print_method("Before Matching");
// Swap out to old-space; emptying new-space
Arena *old = C->node_arena()->move_contents(C->old_arena());
// Save debug and profile information for nodes in old space:
@@ -367,21 +371,23 @@
// Disallow any debug info in outgoing argument areas by setting the
// initial mask accordingly.
void Matcher::init_first_stack_mask() {
// Allocate storage for spill masks as masks for the appropriate load type.
- RegMask *rms = (RegMask*)C->comp_arena()->Amalloc_D(sizeof(RegMask)*10);
- idealreg2spillmask[Op_RegI] = &rms[0];
- idealreg2spillmask[Op_RegL] = &rms[1];
- idealreg2spillmask[Op_RegF] = &rms[2];
- idealreg2spillmask[Op_RegD] = &rms[3];
- idealreg2spillmask[Op_RegP] = &rms[4];
- idealreg2debugmask[Op_RegI] = &rms[5];
- idealreg2debugmask[Op_RegL] = &rms[6];
- idealreg2debugmask[Op_RegF] = &rms[7];
- idealreg2debugmask[Op_RegD] = &rms[8];
- idealreg2debugmask[Op_RegP] = &rms[9];
+ RegMask *rms = (RegMask*)C->comp_arena()->Amalloc_D(sizeof(RegMask)*12);
+ idealreg2spillmask[Op_RegN] = &rms[0];
+ idealreg2spillmask[Op_RegI] = &rms[1];
+ idealreg2spillmask[Op_RegL] = &rms[2];
+ idealreg2spillmask[Op_RegF] = &rms[3];
+ idealreg2spillmask[Op_RegD] = &rms[4];
+ idealreg2spillmask[Op_RegP] = &rms[5];
+ idealreg2debugmask[Op_RegN] = &rms[6];
+ idealreg2debugmask[Op_RegI] = &rms[7];
+ idealreg2debugmask[Op_RegL] = &rms[8];
+ idealreg2debugmask[Op_RegF] = &rms[9];
+ idealreg2debugmask[Op_RegD] = &rms[10];
+ idealreg2debugmask[Op_RegP] = &rms[11];
OptoReg::Name i;
// At first, start with the empty mask
C->FIRST_STACK_mask().Clear();
@@ -400,10 +406,14 @@
// Finally, set the "infinite stack" bit.
C->FIRST_STACK_mask().set_AllStack();
// Make spill masks. Registers for their class, plus FIRST_STACK_mask.
+#ifdef _LP64
+ *idealreg2spillmask[Op_RegN] = *idealreg2regmask[Op_RegN];
+ idealreg2spillmask[Op_RegN]->OR(C->FIRST_STACK_mask());
+#endif
*idealreg2spillmask[Op_RegI] = *idealreg2regmask[Op_RegI];
idealreg2spillmask[Op_RegI]->OR(C->FIRST_STACK_mask());
*idealreg2spillmask[Op_RegL] = *idealreg2regmask[Op_RegL];
idealreg2spillmask[Op_RegL]->OR(C->FIRST_STACK_mask());
*idealreg2spillmask[Op_RegF] = *idealreg2regmask[Op_RegF];
@@ -414,10 +424,11 @@
idealreg2spillmask[Op_RegP]->OR(C->FIRST_STACK_mask());
// Make up debug masks. Any spill slot plus callee-save registers.
// Caller-save registers are assumed to be trashable by the various
// inline-cache fixup routines.
+ *idealreg2debugmask[Op_RegN]= *idealreg2spillmask[Op_RegN];
*idealreg2debugmask[Op_RegI]= *idealreg2spillmask[Op_RegI];
*idealreg2debugmask[Op_RegL]= *idealreg2spillmask[Op_RegL];
*idealreg2debugmask[Op_RegF]= *idealreg2spillmask[Op_RegF];
*idealreg2debugmask[Op_RegD]= *idealreg2spillmask[Op_RegD];
*idealreg2debugmask[Op_RegP]= *idealreg2spillmask[Op_RegP];
@@ -429,10 +440,11 @@
for( i=OptoReg::Name(0); i<OptoReg::Name(_last_Mach_Reg); i = OptoReg::add(i,1) ) {
// registers the caller has to save do not work
if( _register_save_policy[i] == 'C' ||
_register_save_policy[i] == 'A' ||
(_register_save_policy[i] == 'E' && exclude_soe) ) {
+ idealreg2debugmask[Op_RegN]->Remove(i);
idealreg2debugmask[Op_RegI]->Remove(i); // Exclude save-on-call
idealreg2debugmask[Op_RegL]->Remove(i); // registers from debug
idealreg2debugmask[Op_RegF]->Remove(i); // masks
idealreg2debugmask[Op_RegD]->Remove(i);
idealreg2debugmask[Op_RegP]->Remove(i);
@@ -662,19 +674,25 @@
const TypePtr* atp = TypePtr::BOTTOM;
// Share frame pointer while making spill ops
set_shared(fp);
// Compute generic short-offset Loads
+#ifdef _LP64
+ MachNode *spillCP = match_tree(new (C, 3) LoadNNode(NULL,mem,fp,atp,TypeInstPtr::BOTTOM));
+#endif
MachNode *spillI = match_tree(new (C, 3) LoadINode(NULL,mem,fp,atp));
MachNode *spillL = match_tree(new (C, 3) LoadLNode(NULL,mem,fp,atp));
MachNode *spillF = match_tree(new (C, 3) LoadFNode(NULL,mem,fp,atp));
MachNode *spillD = match_tree(new (C, 3) LoadDNode(NULL,mem,fp,atp));
MachNode *spillP = match_tree(new (C, 3) LoadPNode(NULL,mem,fp,atp,TypeInstPtr::BOTTOM));
assert(spillI != NULL && spillL != NULL && spillF != NULL &&
spillD != NULL && spillP != NULL, "");
// Get the ADLC notion of the right regmask, for each basic type.
+#ifdef _LP64
+ idealreg2regmask[Op_RegN] = &spillCP->out_RegMask();
+#endif
idealreg2regmask[Op_RegI] = &spillI->out_RegMask();
idealreg2regmask[Op_RegL] = &spillL->out_RegMask();
idealreg2regmask[Op_RegF] = &spillF->out_RegMask();
idealreg2regmask[Op_RegD] = &spillD->out_RegMask();
idealreg2regmask[Op_RegP] = &spillP->out_RegMask();
@@ -729,10 +747,11 @@
}
}
if (nidx == Compile::AliasIdxBot && midx == Compile::AliasIdxTop) {
switch (n->Opcode()) {
case Op_StrComp:
+ case Op_AryEq:
case Op_MemBarVolatile:
case Op_MemBarCPUOrder: // %%% these ideals should have narrower adr_type?
nidx = Compile::AliasIdxTop;
nat = NULL;
break;
@@ -818,14 +837,20 @@
if (m == NULL) { Matcher::soft_match_failure(); return NULL; }
} else { // Nothing the matcher cares about
if( n->is_Proj() && n->in(0)->is_Multi()) { // Projections?
// Convert to machine-dependent projection
m = n->in(0)->as_Multi()->match( n->as_Proj(), this );
+#ifdef ASSERT
+ _new2old_map.map(m->_idx, n);
+#endif
if (m->in(0) != NULL) // m might be top
- collect_null_checks(m);
+ collect_null_checks(m, n);
} else { // Else just a regular 'ol guy
m = n->clone(); // So just clone into new-space
+#ifdef ASSERT
+ _new2old_map.map(m->_idx, n);
+#endif
// Def-Use edges will be added incrementally as Uses
// of this node are matched.
assert(m->outcnt() == 0, "no Uses of this clone yet");
}
}
@@ -865,15 +890,18 @@
// Monitor boxes are also represented directly.
for (i = cnt - 1; i >= debug_cnt; --i) { // For all debug inputs do
Node *m = n->in(i); // Get input
int op = m->Opcode();
assert((op == Op_BoxLock) == jvms->is_monitor_use(i), "boxes only at monitor sites");
- if( op == Op_ConI || op == Op_ConP ||
+ if( op == Op_ConI || op == Op_ConP || op == Op_ConN ||
op == Op_ConF || op == Op_ConD || op == Op_ConL
// || op == Op_BoxLock // %%%% enable this and remove (+++) in chaitin.cpp
) {
m = m->clone();
+#ifdef ASSERT
+ _new2old_map.map(m->_idx, n);
+#endif
mstack.push(m, Post_Visit, n, i); // Don't neet to visit
mstack.push(m->in(0), Visit, m, 0);
} else {
mstack.push(m, Visit, n, i);
}
@@ -1137,11 +1165,14 @@
LabelRootDepth = 0;
// StoreNodes require their Memory input to match any LoadNodes
Node *mem = n->is_Store() ? n->in(MemNode::Memory) : (Node*)1 ;
-
+#ifdef ASSERT
+ Node* save_mem_node = _mem_node;
+ _mem_node = n->is_Store() ? (Node*)n : NULL;
+#endif
// State object for root node of match tree
// Allocate it on _states_arena - stack allocation can cause stack overflow.
State *s = new (&_states_arena) State;
s->_kids[0] = NULL;
s->_kids[1] = NULL;
@@ -1170,17 +1201,18 @@
}
// Reduce input tree based upon the state labels to machine Nodes
MachNode *m = ReduceInst( s, s->_rule[mincost], mem );
#ifdef ASSERT
_old2new_map.map(n->_idx, m);
+ _new2old_map.map(m->_idx, (Node*)n);
#endif
// Add any Matcher-ignored edges
uint cnt = n->req();
uint start = 1;
if( mem != (Node*)1 ) start = MemNode::Memory+1;
- if( n->Opcode() == Op_AddP ) {
+ if( n->is_AddP() ) {
assert( mem == (Node*)1, "" );
start = AddPNode::Base+1;
}
for( i = start; i < cnt; i++ ) {
if( !n->match_edge(i) ) {
@@ -1189,10 +1221,11 @@
else
m->add_req( n->in(i) );
}
}
+ debug_only( _mem_node = save_mem_node; )
return m;
}
//------------------------------match_into_reg---------------------------------
@@ -1204,11 +1237,11 @@
const Type *t = m->bottom_type();
if( t->singleton() ) {
// Never force constants into registers. Allow them to match as
// constants or registers. Copies of the same value will share
- // the same register. See find_shared_constant.
+ // the same register. See find_shared_node.
return false;
} else { // Not a constant
// Stop recursion if they have different Controls.
// Slot 0 of constants is not really a Control.
if( control && m->in(0) && control != m->in(0) ) {
@@ -1228,10 +1261,15 @@
break; // m->in(0)? If so, we can use it
}
if( j == max_scan ) // No post-domination before scan end?
return true; // Then break the match tree up
}
+ if (m->is_DecodeN() && Matcher::clone_shift_expressions) {
+ // These are commonly used in address expressions and can
+ // efficiently fold into them on X64 in some cases.
+ return false;
+ }
}
// Not forceably cloning. If shared, put it into a register.
return shared;
}
@@ -1346,17 +1384,20 @@
// Con nodes reduced using the same rule can share their MachNode
// which reduces the number of copies of a constant in the final
// program. The register allocator is free to split uses later to
// split live ranges.
-MachNode* Matcher::find_shared_constant(Node* leaf, uint rule) {
- if (!leaf->is_Con()) return NULL;
+MachNode* Matcher::find_shared_node(Node* leaf, uint rule) {
+ if (!leaf->is_Con() && !leaf->is_DecodeN()) return NULL;
// See if this Con has already been reduced using this rule.
- if (_shared_constants.Size() <= leaf->_idx) return NULL;
- MachNode* last = (MachNode*)_shared_constants.at(leaf->_idx);
+ if (_shared_nodes.Size() <= leaf->_idx) return NULL;
+ MachNode* last = (MachNode*)_shared_nodes.at(leaf->_idx);
if (last != NULL && rule == last->rule()) {
+ // Don't expect control change for DecodeN
+ if (leaf->is_DecodeN())
+ return last;
// Get the new space root.
Node* xroot = new_node(C->root());
if (xroot == NULL) {
// This shouldn't happen give the order of matching.
return NULL;
@@ -1398,22 +1439,24 @@
// Build the operand, place it inside the instruction
// Call ReduceOper.
MachNode *Matcher::ReduceInst( State *s, int rule, Node *&mem ) {
assert( rule >= NUM_OPERANDS, "called with operand rule" );
- MachNode* shared_con = find_shared_constant(s->_leaf, rule);
- if (shared_con != NULL) {
- return shared_con;
+ MachNode* shared_node = find_shared_node(s->_leaf, rule);
+ if (shared_node != NULL) {
+ return shared_node;
}
// Build the object to represent this state & prepare for recursive calls
MachNode *mach = s->MachNodeGenerator( rule, C );
mach->_opnds[0] = s->MachOperGenerator( _reduceOp[rule], C );
assert( mach->_opnds[0] != NULL, "Missing result operand" );
Node *leaf = s->_leaf;
// Check for instruction or instruction chain rule
if( rule >= _END_INST_CHAIN_RULE || rule < _BEGIN_INST_CHAIN_RULE ) {
+ assert(C->node_arena()->contains(s->_leaf) || !has_new_node(s->_leaf),
+ "duplicating node that's already been matched");
// Instruction
mach->add_req( leaf->in(0) ); // Set initial control
// Reduce interior of complex instruction
ReduceInst_Interior( s, rule, mem, mach, 1 );
} else {
@@ -1421,15 +1464,44 @@
mach->add_req(0); // Set initial control to none
ReduceInst_Chain_Rule( s, rule, mem, mach );
}
// If a Memory was used, insert a Memory edge
- if( mem != (Node*)1 )
+ if( mem != (Node*)1 ) {
mach->ins_req(MemNode::Memory,mem);
+#ifdef ASSERT
+ // Verify adr type after matching memory operation
+ const MachOper* oper = mach->memory_operand();
+ if (oper != NULL && oper != (MachOper*)-1 &&
+ mach->adr_type() != TypeRawPtr::BOTTOM) { // non-direct addressing mode
+ // It has a unique memory operand. Find corresponding ideal mem node.
+ Node* m = NULL;
+ if (leaf->is_Mem()) {
+ m = leaf;
+ } else {
+ m = _mem_node;
+ assert(m != NULL && m->is_Mem(), "expecting memory node");
+ }
+ const Type* mach_at = mach->adr_type();
+ // DecodeN node consumed by an address may have different type
+ // then its input. Don't compare types for such case.
+ if (m->adr_type() != mach_at && m->in(MemNode::Address)->is_AddP() &&
+ m->in(MemNode::Address)->in(AddPNode::Address)->is_DecodeN()) {
+ mach_at = m->adr_type();
+ }
+ if (m->adr_type() != mach_at) {
+ m->dump();
+ tty->print_cr("mach:");
+ mach->dump(1);
+ }
+ assert(m->adr_type() == mach_at, "matcher should not change adr type");
+ }
+#endif
+ }
// If the _leaf is an AddP, insert the base edge
- if( leaf->Opcode() == Op_AddP )
+ if( leaf->is_AddP() )
mach->ins_req(AddPNode::Base,leaf->in(AddPNode::Base));
uint num_proj = _proj_list.size();
// Perform any 1-to-many expansions required
@@ -1440,10 +1512,13 @@
ex->in(1)->set_req(0, C->root());
// Remove old node from the graph
for( uint i=0; i<mach->req(); i++ ) {
mach->set_req(i,NULL);
}
+#ifdef ASSERT
+ _new2old_map.map(ex->_idx, s->_leaf);
+#endif
}
// PhaseChaitin::fixup_spills will sometimes generate spill code
// via the matcher. By the time, nodes have been wired into the CFG,
// and any further nodes generated by expand rules will be left hanging
@@ -1453,13 +1528,13 @@
if (_allocation_started) {
guarantee(ex == mach, "no expand rules during spill generation");
guarantee(_proj_list.size() == num_proj, "no allocation during spill generation");
}
- if (leaf->is_Con()) {
+ if (leaf->is_Con() || leaf->is_DecodeN()) {
// Record the con for sharing
- _shared_constants.map(leaf->_idx, ex);
+ _shared_nodes.map(leaf->_idx, ex);
}
return ex;
}
@@ -1486,20 +1561,23 @@
} else {
// Chain from the result of an instruction
assert( newrule >= _LAST_MACH_OPER, "Do NOT chain from internal operand");
mach->_opnds[1] = s->MachOperGenerator( _reduceOp[catch_op], C );
Node *mem1 = (Node*)1;
+ debug_only(Node *save_mem_node = _mem_node;)
mach->add_req( ReduceInst(s, newrule, mem1) );
+ debug_only(_mem_node = save_mem_node;)
}
return;
}
uint Matcher::ReduceInst_Interior( State *s, int rule, Node *&mem, MachNode *mach, uint num_opnds ) {
if( s->_leaf->is_Load() ) {
Node *mem2 = s->_leaf->in(MemNode::Memory);
assert( mem == (Node*)1 || mem == mem2, "multiple Memories being matched at once?" );
+ debug_only( if( mem == (Node*)1 ) _mem_node = s->_leaf;)
mem = mem2;
}
if( s->_leaf->in(0) != NULL && s->_leaf->req() > 1) {
if( mach->in(0) == NULL )
mach->set_req(0, s->_leaf->in(0));
@@ -1539,11 +1617,13 @@
} else {
// instruction --> call build operand( ) to catch result
// --> ReduceInst( newrule )
mach->_opnds[num_opnds++] = s->MachOperGenerator( _reduceOp[catch_op], C );
Node *mem1 = (Node*)1;
+ debug_only(Node *save_mem_node = _mem_node;)
mach->add_req( ReduceInst( newstate, newrule, mem1 ) );
+ debug_only(_mem_node = save_mem_node;)
}
}
assert( mach->_opnds[num_opnds-1], "" );
}
return num_opnds;
@@ -1570,10 +1650,11 @@
}
if( s->_leaf->is_Load() ) {
assert( mem == (Node*)1, "multiple Memories being matched at once?" );
mem = s->_leaf->in(MemNode::Memory);
+ debug_only(_mem_node = s->_leaf;)
}
if( s->_leaf->in(0) && s->_leaf->req() > 1) {
if( !mach->in(0) )
mach->set_req(0,s->_leaf->in(0));
else {
@@ -1594,11 +1675,13 @@
} else { // Child is a new instruction
// Reduce the instruction, and add a direct pointer from this
// machine instruction to the newly reduced one.
Node *mem1 = (Node*)1;
+ debug_only(Node *save_mem_node = _mem_node;)
mach->add_req( ReduceInst( kid, newrule, mem1 ) );
+ debug_only(_mem_node = save_mem_node;)
}
}
}
@@ -1648,10 +1731,11 @@
switch( n->Opcode() ) { // Handle some opcodes special
case Op_Phi: // Treat Phis as shared roots
case Op_Parm:
case Op_Proj: // All handled specially during matching
+ case Op_SafePointScalarObject:
set_shared(n);
set_dontcare(n);
break;
case Op_If:
case Op_CountedLoopEnd:
@@ -1693,20 +1777,29 @@
case Op_Jump:
mstack.push(n->in(1), Visit); // Switch Value
mstack.push(n->in(0), Pre_Visit); // Visit Control input
continue; // while (mstack.is_nonempty())
case Op_StrComp:
+ case Op_AryEq:
set_shared(n); // Force result into register (it will be anyways)
break;
case Op_ConP: { // Convert pointers above the centerline to NUL
TypeNode *tn = n->as_Type(); // Constants derive from type nodes
const TypePtr* tp = tn->type()->is_ptr();
if (tp->_ptr == TypePtr::AnyNull) {
tn->set_type(TypePtr::NULL_PTR);
}
break;
}
+ case Op_ConN: { // Convert narrow pointers above the centerline to NUL
+ TypeNode *tn = n->as_Type(); // Constants derive from type nodes
+ const TypePtr* tp = tn->type()->make_ptr();
+ if (tp && tp->_ptr == TypePtr::AnyNull) {
+ tn->set_type(TypeNarrowOop::NULL_PTR);
+ }
+ break;
+ }
case Op_Binary: // These are introduced in the Post_Visit state.
ShouldNotReachHere();
break;
case Op_StoreB: // Do match these, despite no ideal reg
case Op_StoreC:
@@ -1714,10 +1807,11 @@
case Op_StoreD:
case Op_StoreF:
case Op_StoreI:
case Op_StoreL:
case Op_StoreP:
+ case Op_StoreN:
case Op_Store16B:
case Op_Store8B:
case Op_Store4B:
case Op_Store8C:
case Op_Store4C:
@@ -1736,13 +1830,15 @@
case Op_LoadC:
case Op_LoadD:
case Op_LoadF:
case Op_LoadI:
case Op_LoadKlass:
+ case Op_LoadNKlass:
case Op_LoadL:
case Op_LoadS:
case Op_LoadP:
+ case Op_LoadN:
case Op_LoadRange:
case Op_LoadD_unaligned:
case Op_LoadL_unaligned:
case Op_Load16B:
case Op_Load8B:
@@ -1786,17 +1882,23 @@
continue; // for(int i = ...)
}
// Clone addressing expressions as they are "free" in most instructions
if( mem_op && i == MemNode::Address && mop == Op_AddP ) {
+ if (m->in(AddPNode::Base)->Opcode() == Op_DecodeN) {
+ // Bases used in addresses must be shared but since
+ // they are shared through a DecodeN they may appear
+ // to have a single use so force sharing here.
+ set_shared(m->in(AddPNode::Base)->in(1));
+ }
Node *off = m->in(AddPNode::Offset);
if( off->is_Con() ) {
set_visited(m); // Flag as visited now
Node *adr = m->in(AddPNode::Address);
// Intel, ARM and friends can handle 2 adds in addressing mode
- if( clone_shift_expressions && adr->Opcode() == Op_AddP &&
+ if( clone_shift_expressions && adr->is_AddP() &&
// AtomicAdd is not an addressing expression.
// Cheap to find it by looking for screwy base.
!adr->in(AddPNode::Base)->is_top() ) {
set_visited(adr); // Flag as visited now
Node *shift = adr->in(AddPNode::Offset);
@@ -1850,14 +1952,16 @@
mstack.pop(); // Remove node from stack
// Now hack a few special opcodes
switch( n->Opcode() ) { // Handle some opcodes special
case Op_StorePConditional:
+ case Op_StoreIConditional:
case Op_StoreLConditional:
case Op_CompareAndSwapI:
case Op_CompareAndSwapL:
- case Op_CompareAndSwapP: { // Convert trinary to binary-tree
+ case Op_CompareAndSwapP:
+ case Op_CompareAndSwapN: { // Convert trinary to binary-tree
Node *newval = n->in(MemNode::ValueIn );
Node *oldval = n->in(LoadStoreNode::ExpectedIn);
Node *pair = new (C, 3) BinaryNode( oldval, newval );
n->set_req(MemNode::ValueIn,pair);
n->del_req(LoadStoreNode::ExpectedIn);
@@ -1865,10 +1969,11 @@
}
case Op_CMoveD: // Convert trinary to binary-tree
case Op_CMoveF:
case Op_CMoveI:
case Op_CMoveL:
+ case Op_CMoveN:
case Op_CMoveP: {
// Restructure into a binary tree for Matching. It's possible that
// we could move this code up next to the graph reshaping for IfNodes
// or vice-versa, but I do not want to debug this for Ladybird.
// 10/2/2000 CNC.
@@ -1899,34 +2004,64 @@
//---------------------------collect_null_checks-------------------------------
// Find null checks in the ideal graph; write a machine-specific node for
// it. Used by later implicit-null-check handling. Actually collects
// either an IfTrue or IfFalse for the common NOT-null path, AND the ideal
// value being tested.
-void Matcher::collect_null_checks( Node *proj ) {
+void Matcher::collect_null_checks( Node *proj, Node *orig_proj ) {
Node *iff = proj->in(0);
if( iff->Opcode() == Op_If ) {
// During matching If's have Bool & Cmp side-by-side
BoolNode *b = iff->in(1)->as_Bool();
Node *cmp = iff->in(2);
- if( cmp->Opcode() == Op_CmpP ) {
- if( cmp->in(2)->bottom_type() == TypePtr::NULL_PTR ) {
+ int opc = cmp->Opcode();
+ if (opc != Op_CmpP && opc != Op_CmpN) return;
+ const Type* ct = cmp->in(2)->bottom_type();
+ if (ct == TypePtr::NULL_PTR ||
+ (opc == Op_CmpN && ct == TypeNarrowOop::NULL_PTR)) {
+
+ bool push_it = false;
if( proj->Opcode() == Op_IfTrue ) {
extern int all_null_checks_found;
all_null_checks_found++;
if( b->_test._test == BoolTest::ne ) {
- _null_check_tests.push(proj);
- _null_check_tests.push(cmp->in(1));
+ push_it = true;
}
} else {
assert( proj->Opcode() == Op_IfFalse, "" );
if( b->_test._test == BoolTest::eq ) {
+ push_it = true;
+ }
+ }
+ if( push_it ) {
_null_check_tests.push(proj);
- _null_check_tests.push(cmp->in(1));
+ Node* val = cmp->in(1);
+#ifdef _LP64
+ if (UseCompressedOops && !Matcher::clone_shift_expressions &&
+ val->bottom_type()->isa_narrowoop()) {
+ //
+ // Look for DecodeN node which should be pinned to orig_proj.
+ // On platforms (Sparc) which can not handle 2 adds
+ // in addressing mode we have to keep a DecodeN node and
+ // use it to do implicit NULL check in address.
+ //
+ // DecodeN node was pinned to non-null path (orig_proj) during
+ // CastPP transformation in final_graph_reshaping_impl().
+ //
+ uint cnt = orig_proj->outcnt();
+ for (uint i = 0; i < orig_proj->outcnt(); i++) {
+ Node* d = orig_proj->raw_out(i);
+ if (d->is_DecodeN() && d->in(1) == val) {
+ val = d;
+ val->set_req(0, NULL); // Unpin now.
+ break;
}
}
}
+#endif
+ _null_check_tests.push(val);
+ }
}
}
}
//---------------------------validate_null_checks------------------------------
@@ -2038,10 +2173,11 @@
if (xop == Op_MemBarVolatile ||
xop == Op_FastLock ||
xop == Op_CompareAndSwapL ||
xop == Op_CompareAndSwapP ||
+ xop == Op_CompareAndSwapN ||
xop == Op_CompareAndSwapI)
return true;
if (x->is_MemBar()) {
// We must retain this membar if there is an upcoming volatile