Mercurial > hg > truffle
comparison src/share/vm/opto/memnode.cpp @ 74:2a9af0b9cb1c
6674600: (Escape Analysis) Optimize memory graph for instance's fields
Summary: EA gives opportunite to do more aggressive memory optimizations.
Reviewed-by: never, jrose
author | kvn |
---|---|
date | Thu, 20 Mar 2008 15:11:44 -0700 |
parents | daf38130e60d |
children | de93acbb64fc |
comparison
equal
deleted
inserted
replaced
73:a8880a78d355 | 74:2a9af0b9cb1c |
---|---|
27 // Optimization - Graph Style | 27 // Optimization - Graph Style |
28 | 28 |
29 #include "incls/_precompiled.incl" | 29 #include "incls/_precompiled.incl" |
30 #include "incls/_memnode.cpp.incl" | 30 #include "incls/_memnode.cpp.incl" |
31 | 31 |
32 static Node *step_through_mergemem(PhaseGVN *phase, MergeMemNode *mmem, const TypePtr *tp, const TypePtr *adr_check, outputStream *st); | |
33 | |
32 //============================================================================= | 34 //============================================================================= |
33 uint MemNode::size_of() const { return sizeof(*this); } | 35 uint MemNode::size_of() const { return sizeof(*this); } |
34 | 36 |
35 const TypePtr *MemNode::adr_type() const { | 37 const TypePtr *MemNode::adr_type() const { |
36 Node* adr = in(Address); | 38 Node* adr = in(Address); |
84 } | 86 } |
85 | 87 |
86 extern void print_alias_types(); | 88 extern void print_alias_types(); |
87 | 89 |
88 #endif | 90 #endif |
91 | |
92 Node *MemNode::optimize_simple_memory_chain(Node *mchain, const TypePtr *t_adr, PhaseGVN *phase) { | |
93 const TypeOopPtr *tinst = t_adr->isa_oopptr(); | |
94 if (tinst == NULL || !tinst->is_instance_field()) | |
95 return mchain; // don't try to optimize non-instance types | |
96 uint instance_id = tinst->instance_id(); | |
97 Node *prev = NULL; | |
98 Node *result = mchain; | |
99 while (prev != result) { | |
100 prev = result; | |
101 // skip over a call which does not affect this memory slice | |
102 if (result->is_Proj() && result->as_Proj()->_con == TypeFunc::Memory) { | |
103 Node *proj_in = result->in(0); | |
104 if (proj_in->is_Call()) { | |
105 CallNode *call = proj_in->as_Call(); | |
106 if (!call->may_modify(t_adr, phase)) { | |
107 result = call->in(TypeFunc::Memory); | |
108 } | |
109 } else if (proj_in->is_Initialize()) { | |
110 AllocateNode* alloc = proj_in->as_Initialize()->allocation(); | |
111 // Stop if this is the initialization for the object instance which | |
112 // which contains this memory slice, otherwise skip over it. | |
113 if (alloc != NULL && alloc->_idx != instance_id) { | |
114 result = proj_in->in(TypeFunc::Memory); | |
115 } | |
116 } else if (proj_in->is_MemBar()) { | |
117 result = proj_in->in(TypeFunc::Memory); | |
118 } | |
119 } else if (result->is_MergeMem()) { | |
120 result = step_through_mergemem(phase, result->as_MergeMem(), t_adr, NULL, tty); | |
121 } | |
122 } | |
123 return result; | |
124 } | |
125 | |
126 Node *MemNode::optimize_memory_chain(Node *mchain, const TypePtr *t_adr, PhaseGVN *phase) { | |
127 const TypeOopPtr *t_oop = t_adr->isa_oopptr(); | |
128 bool is_instance = (t_oop != NULL) && t_oop->is_instance_field(); | |
129 PhaseIterGVN *igvn = phase->is_IterGVN(); | |
130 Node *result = mchain; | |
131 result = optimize_simple_memory_chain(result, t_adr, phase); | |
132 if (is_instance && igvn != NULL && result->is_Phi()) { | |
133 PhiNode *mphi = result->as_Phi(); | |
134 assert(mphi->bottom_type() == Type::MEMORY, "memory phi required"); | |
135 const TypePtr *t = mphi->adr_type(); | |
136 if (t == TypePtr::BOTTOM || t == TypeRawPtr::BOTTOM) { | |
137 // clone the Phi with our address type | |
138 result = mphi->split_out_instance(t_adr, igvn); | |
139 } else { | |
140 assert(phase->C->get_alias_index(t) == phase->C->get_alias_index(t_adr), "correct memory chain"); | |
141 } | |
142 } | |
143 return result; | |
144 } | |
89 | 145 |
90 static Node *step_through_mergemem(PhaseGVN *phase, MergeMemNode *mmem, const TypePtr *tp, const TypePtr *adr_check, outputStream *st) { | 146 static Node *step_through_mergemem(PhaseGVN *phase, MergeMemNode *mmem, const TypePtr *tp, const TypePtr *adr_check, outputStream *st) { |
91 uint alias_idx = phase->C->get_alias_index(tp); | 147 uint alias_idx = phase->C->get_alias_index(tp); |
92 Node *mem = mmem; | 148 Node *mem = mmem; |
93 #ifdef ASSERT | 149 #ifdef ASSERT |
264 AllocateNode* alloc = AllocateNode::Ideal_allocation(base, phase); | 320 AllocateNode* alloc = AllocateNode::Ideal_allocation(base, phase); |
265 | 321 |
266 if (offset == Type::OffsetBot) | 322 if (offset == Type::OffsetBot) |
267 return NULL; // cannot unalias unless there are precise offsets | 323 return NULL; // cannot unalias unless there are precise offsets |
268 | 324 |
325 const TypeOopPtr *addr_t = adr->bottom_type()->isa_oopptr(); | |
326 | |
269 intptr_t size_in_bytes = memory_size(); | 327 intptr_t size_in_bytes = memory_size(); |
270 | 328 |
271 Node* mem = in(MemNode::Memory); // start searching here... | 329 Node* mem = in(MemNode::Memory); // start searching here... |
272 | 330 |
273 int cnt = 50; // Cycle limiter | 331 int cnt = 50; // Cycle limiter |
343 if (known_identical) { | 401 if (known_identical) { |
344 // From caller, can_see_stored_value will consult find_captured_store. | 402 // From caller, can_see_stored_value will consult find_captured_store. |
345 return mem; // let caller handle steps (c), (d) | 403 return mem; // let caller handle steps (c), (d) |
346 } | 404 } |
347 | 405 |
406 } else if (addr_t != NULL && addr_t->is_instance_field()) { | |
407 // Can't use optimize_simple_memory_chain() since it needs PhaseGVN. | |
408 if (mem->is_Proj() && mem->in(0)->is_Call()) { | |
409 CallNode *call = mem->in(0)->as_Call(); | |
410 if (!call->may_modify(addr_t, phase)) { | |
411 mem = call->in(TypeFunc::Memory); | |
412 continue; // (a) advance through independent call memory | |
413 } | |
414 } else if (mem->is_Proj() && mem->in(0)->is_MemBar()) { | |
415 mem = mem->in(0)->in(TypeFunc::Memory); | |
416 continue; // (a) advance through independent MemBar memory | |
417 } else if (mem->is_MergeMem()) { | |
418 int alias_idx = phase->C->get_alias_index(adr_type()); | |
419 mem = mem->as_MergeMem()->memory_at(alias_idx); | |
420 continue; // (a) advance through independent MergeMem memory | |
421 } | |
348 } | 422 } |
349 | 423 |
350 // Unless there is an explicit 'continue', we must bail out here, | 424 // Unless there is an explicit 'continue', we must bail out here, |
351 // because 'mem' is an inscrutable memory state (e.g., a call). | 425 // because 'mem' is an inscrutable memory state (e.g., a call). |
352 break; | 426 break; |
1005 if (base != NULL) { | 1079 if (base != NULL) { |
1006 Compile::AliasType* atp = phase->C->alias_type(adr_type()); | 1080 Compile::AliasType* atp = phase->C->alias_type(adr_type()); |
1007 if (is_autobox_object(atp)) { | 1081 if (is_autobox_object(atp)) { |
1008 Node* result = eliminate_autobox(phase); | 1082 Node* result = eliminate_autobox(phase); |
1009 if (result != NULL) return result; | 1083 if (result != NULL) return result; |
1084 } | |
1085 } | |
1086 } | |
1087 | |
1088 Node* mem = in(MemNode::Memory); | |
1089 const TypePtr *addr_t = phase->type(address)->isa_ptr(); | |
1090 | |
1091 if (addr_t != NULL) { | |
1092 // try to optimize our memory input | |
1093 Node* opt_mem = MemNode::optimize_memory_chain(mem, addr_t, phase); | |
1094 if (opt_mem != mem) { | |
1095 set_req(MemNode::Memory, opt_mem); | |
1096 return this; | |
1097 } | |
1098 const TypeOopPtr *t_oop = addr_t->isa_oopptr(); | |
1099 if (can_reshape && opt_mem->is_Phi() && | |
1100 (t_oop != NULL) && t_oop->is_instance_field()) { | |
1101 assert(t_oop->offset() != Type::OffsetBot && t_oop->offset() != Type::OffsetTop, ""); | |
1102 Node *region = opt_mem->in(0); | |
1103 uint cnt = opt_mem->req(); | |
1104 for( uint i = 1; i < cnt; i++ ) { | |
1105 Node *in = opt_mem->in(i); | |
1106 if( in == NULL ) { | |
1107 region = NULL; // Wait stable graph | |
1108 break; | |
1109 } | |
1110 } | |
1111 if (region != NULL) { | |
1112 // Check for loop invariant. | |
1113 if (cnt == 3) { | |
1114 for( uint i = 1; i < cnt; i++ ) { | |
1115 Node *in = opt_mem->in(i); | |
1116 Node* m = MemNode::optimize_memory_chain(in, addr_t, phase); | |
1117 if (m == opt_mem) { | |
1118 set_req(MemNode::Memory, opt_mem->in(cnt - i)); // Skip this phi. | |
1119 return this; | |
1120 } | |
1121 } | |
1122 } | |
1123 // Split through Phi (see original code in loopopts.cpp). | |
1124 assert(phase->C->have_alias_type(addr_t), "instance should have alias type"); | |
1125 const Type* this_type = this->bottom_type(); | |
1126 int this_index = phase->C->get_alias_index(addr_t); | |
1127 int this_offset = addr_t->offset(); | |
1128 int this_iid = addr_t->is_oopptr()->instance_id(); | |
1129 int wins = 0; | |
1130 PhaseIterGVN *igvn = phase->is_IterGVN(); | |
1131 Node *phi = new (igvn->C, region->req()) PhiNode(region, this_type, NULL, this_iid, this_index, this_offset); | |
1132 for( uint i = 1; i < region->req(); i++ ) { | |
1133 Node *x; | |
1134 Node* the_clone = NULL; | |
1135 if( region->in(i) == phase->C->top() ) { | |
1136 x = phase->C->top(); // Dead path? Use a dead data op | |
1137 } else { | |
1138 x = this->clone(); // Else clone up the data op | |
1139 the_clone = x; // Remember for possible deletion. | |
1140 // Alter data node to use pre-phi inputs | |
1141 if( this->in(0) == region ) { | |
1142 x->set_req( 0, region->in(i) ); | |
1143 } else { | |
1144 x->set_req( 0, NULL ); | |
1145 } | |
1146 for( uint j = 1; j < this->req(); j++ ) { | |
1147 Node *in = this->in(j); | |
1148 if( in->is_Phi() && in->in(0) == region ) | |
1149 x->set_req( j, in->in(i) ); // Use pre-Phi input for the clone | |
1150 } | |
1151 } | |
1152 // Check for a 'win' on some paths | |
1153 const Type *t = x->Value(igvn); | |
1154 | |
1155 bool singleton = t->singleton(); | |
1156 | |
1157 // See comments in PhaseIdealLoop::split_thru_phi(). | |
1158 if( singleton && t == Type::TOP ) { | |
1159 singleton &= region->is_Loop() && (i != LoopNode::EntryControl); | |
1160 } | |
1161 | |
1162 if( singleton ) { | |
1163 wins++; | |
1164 x = igvn->makecon(t); | |
1165 } else { | |
1166 // We now call Identity to try to simplify the cloned node. | |
1167 // Note that some Identity methods call phase->type(this). | |
1168 // Make sure that the type array is big enough for | |
1169 // our new node, even though we may throw the node away. | |
1170 // (This tweaking with igvn only works because x is a new node.) | |
1171 igvn->set_type(x, t); | |
1172 Node *y = x->Identity(igvn); | |
1173 if( y != x ) { | |
1174 wins++; | |
1175 x = y; | |
1176 } else { | |
1177 y = igvn->hash_find(x); | |
1178 if( y ) { | |
1179 wins++; | |
1180 x = y; | |
1181 } else { | |
1182 // Else x is a new node we are keeping | |
1183 // We do not need register_new_node_with_optimizer | |
1184 // because set_type has already been called. | |
1185 igvn->_worklist.push(x); | |
1186 } | |
1187 } | |
1188 } | |
1189 if (x != the_clone && the_clone != NULL) | |
1190 igvn->remove_dead_node(the_clone); | |
1191 phi->set_req(i, x); | |
1192 } | |
1193 if( wins > 0 ) { | |
1194 // Record Phi | |
1195 igvn->register_new_node_with_optimizer(phi); | |
1196 return phi; | |
1197 } else { | |
1198 igvn->remove_dead_node(phi); | |
1199 } | |
1010 } | 1200 } |
1011 } | 1201 } |
1012 } | 1202 } |
1013 | 1203 |
1014 // Check for prior store with a different base or offset; make Load | 1204 // Check for prior store with a different base or offset; make Load |