annotate src/share/vm/opto/coalesce.cpp @ 452:00b023ae2d78

6722113: CMS: Incorrect overflow handling during precleaning of Reference lists Summary: When we encounter marking stack overflow during precleaning of Reference lists, we were using the overflow list mechanism, which can cause problems on account of mutating the mark word of the header because of conflicts with mutator accesses and updates of that field. Instead we should use the usual mechanism for overflow handling in concurrent phases, namely dirtying of the card on which the overflowed object lies. Since precleaning effectively does a form of discovered list processing, albeit with discovery enabled, we needed to adjust some code to be correct in the face of interleaved processing and discovery. Reviewed-by: apetrusenko, jcoomes
author ysr
date Thu, 20 Nov 2008 12:27:41 -0800
parents 9ee9cf798b59
children 98cb887364d3
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
0
a61af66fc99e Initial load
duke
parents:
diff changeset
1 /*
337
9ee9cf798b59 6754988: Update copyright year
xdono
parents: 295
diff changeset
2 * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved.
0
a61af66fc99e Initial load
duke
parents:
diff changeset
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
a61af66fc99e Initial load
duke
parents:
diff changeset
4 *
a61af66fc99e Initial load
duke
parents:
diff changeset
5 * This code is free software; you can redistribute it and/or modify it
a61af66fc99e Initial load
duke
parents:
diff changeset
6 * under the terms of the GNU General Public License version 2 only, as
a61af66fc99e Initial load
duke
parents:
diff changeset
7 * published by the Free Software Foundation.
a61af66fc99e Initial load
duke
parents:
diff changeset
8 *
a61af66fc99e Initial load
duke
parents:
diff changeset
9 * This code is distributed in the hope that it will be useful, but WITHOUT
a61af66fc99e Initial load
duke
parents:
diff changeset
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
a61af66fc99e Initial load
duke
parents:
diff changeset
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
a61af66fc99e Initial load
duke
parents:
diff changeset
12 * version 2 for more details (a copy is included in the LICENSE file that
a61af66fc99e Initial load
duke
parents:
diff changeset
13 * accompanied this code).
a61af66fc99e Initial load
duke
parents:
diff changeset
14 *
a61af66fc99e Initial load
duke
parents:
diff changeset
15 * You should have received a copy of the GNU General Public License version
a61af66fc99e Initial load
duke
parents:
diff changeset
16 * 2 along with this work; if not, write to the Free Software Foundation,
a61af66fc99e Initial load
duke
parents:
diff changeset
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
a61af66fc99e Initial load
duke
parents:
diff changeset
18 *
a61af66fc99e Initial load
duke
parents:
diff changeset
19 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
a61af66fc99e Initial load
duke
parents:
diff changeset
20 * CA 95054 USA or visit www.sun.com if you need additional information or
a61af66fc99e Initial load
duke
parents:
diff changeset
21 * have any questions.
a61af66fc99e Initial load
duke
parents:
diff changeset
22 *
a61af66fc99e Initial load
duke
parents:
diff changeset
23 */
a61af66fc99e Initial load
duke
parents:
diff changeset
24
a61af66fc99e Initial load
duke
parents:
diff changeset
25 #include "incls/_precompiled.incl"
a61af66fc99e Initial load
duke
parents:
diff changeset
26 #include "incls/_coalesce.cpp.incl"
a61af66fc99e Initial load
duke
parents:
diff changeset
27
a61af66fc99e Initial load
duke
parents:
diff changeset
28 //=============================================================================
a61af66fc99e Initial load
duke
parents:
diff changeset
29 //------------------------------reset_uf_map-----------------------------------
a61af66fc99e Initial load
duke
parents:
diff changeset
30 void PhaseChaitin::reset_uf_map( uint maxlrg ) {
a61af66fc99e Initial load
duke
parents:
diff changeset
31 _maxlrg = maxlrg;
a61af66fc99e Initial load
duke
parents:
diff changeset
32 // Force the Union-Find mapping to be at least this large
a61af66fc99e Initial load
duke
parents:
diff changeset
33 _uf_map.extend(_maxlrg,0);
a61af66fc99e Initial load
duke
parents:
diff changeset
34 // Initialize it to be the ID mapping.
a61af66fc99e Initial load
duke
parents:
diff changeset
35 for( uint i=0; i<_maxlrg; i++ )
a61af66fc99e Initial load
duke
parents:
diff changeset
36 _uf_map.map(i,i);
a61af66fc99e Initial load
duke
parents:
diff changeset
37 }
a61af66fc99e Initial load
duke
parents:
diff changeset
38
a61af66fc99e Initial load
duke
parents:
diff changeset
39 //------------------------------compress_uf_map--------------------------------
a61af66fc99e Initial load
duke
parents:
diff changeset
40 // Make all Nodes map directly to their final live range; no need for
a61af66fc99e Initial load
duke
parents:
diff changeset
41 // the Union-Find mapping after this call.
a61af66fc99e Initial load
duke
parents:
diff changeset
42 void PhaseChaitin::compress_uf_map_for_nodes( ) {
a61af66fc99e Initial load
duke
parents:
diff changeset
43 // For all Nodes, compress mapping
a61af66fc99e Initial load
duke
parents:
diff changeset
44 uint unique = _names.Size();
a61af66fc99e Initial load
duke
parents:
diff changeset
45 for( uint i=0; i<unique; i++ ) {
a61af66fc99e Initial load
duke
parents:
diff changeset
46 uint lrg = _names[i];
a61af66fc99e Initial load
duke
parents:
diff changeset
47 uint compressed_lrg = Find(lrg);
a61af66fc99e Initial load
duke
parents:
diff changeset
48 if( lrg != compressed_lrg )
a61af66fc99e Initial load
duke
parents:
diff changeset
49 _names.map(i,compressed_lrg);
a61af66fc99e Initial load
duke
parents:
diff changeset
50 }
a61af66fc99e Initial load
duke
parents:
diff changeset
51 }
a61af66fc99e Initial load
duke
parents:
diff changeset
52
a61af66fc99e Initial load
duke
parents:
diff changeset
53 //------------------------------Find-------------------------------------------
a61af66fc99e Initial load
duke
parents:
diff changeset
54 // Straight out of Tarjan's union-find algorithm
a61af66fc99e Initial load
duke
parents:
diff changeset
55 uint PhaseChaitin::Find_compress( uint lrg ) {
a61af66fc99e Initial load
duke
parents:
diff changeset
56 uint cur = lrg;
a61af66fc99e Initial load
duke
parents:
diff changeset
57 uint next = _uf_map[cur];
a61af66fc99e Initial load
duke
parents:
diff changeset
58 while( next != cur ) { // Scan chain of equivalences
a61af66fc99e Initial load
duke
parents:
diff changeset
59 assert( next < cur, "always union smaller" );
a61af66fc99e Initial load
duke
parents:
diff changeset
60 cur = next; // until find a fixed-point
a61af66fc99e Initial load
duke
parents:
diff changeset
61 next = _uf_map[cur];
a61af66fc99e Initial load
duke
parents:
diff changeset
62 }
a61af66fc99e Initial load
duke
parents:
diff changeset
63 // Core of union-find algorithm: update chain of
a61af66fc99e Initial load
duke
parents:
diff changeset
64 // equivalences to be equal to the root.
a61af66fc99e Initial load
duke
parents:
diff changeset
65 while( lrg != next ) {
a61af66fc99e Initial load
duke
parents:
diff changeset
66 uint tmp = _uf_map[lrg];
a61af66fc99e Initial load
duke
parents:
diff changeset
67 _uf_map.map(lrg, next);
a61af66fc99e Initial load
duke
parents:
diff changeset
68 lrg = tmp;
a61af66fc99e Initial load
duke
parents:
diff changeset
69 }
a61af66fc99e Initial load
duke
parents:
diff changeset
70 return lrg;
a61af66fc99e Initial load
duke
parents:
diff changeset
71 }
a61af66fc99e Initial load
duke
parents:
diff changeset
72
a61af66fc99e Initial load
duke
parents:
diff changeset
73 //------------------------------Find-------------------------------------------
a61af66fc99e Initial load
duke
parents:
diff changeset
74 // Straight out of Tarjan's union-find algorithm
a61af66fc99e Initial load
duke
parents:
diff changeset
75 uint PhaseChaitin::Find_compress( const Node *n ) {
a61af66fc99e Initial load
duke
parents:
diff changeset
76 uint lrg = Find_compress(_names[n->_idx]);
a61af66fc99e Initial load
duke
parents:
diff changeset
77 _names.map(n->_idx,lrg);
a61af66fc99e Initial load
duke
parents:
diff changeset
78 return lrg;
a61af66fc99e Initial load
duke
parents:
diff changeset
79 }
a61af66fc99e Initial load
duke
parents:
diff changeset
80
a61af66fc99e Initial load
duke
parents:
diff changeset
81 //------------------------------Find_const-------------------------------------
a61af66fc99e Initial load
duke
parents:
diff changeset
82 // Like Find above, but no path compress, so bad asymptotic behavior
a61af66fc99e Initial load
duke
parents:
diff changeset
83 uint PhaseChaitin::Find_const( uint lrg ) const {
a61af66fc99e Initial load
duke
parents:
diff changeset
84 if( !lrg ) return lrg; // Ignore the zero LRG
a61af66fc99e Initial load
duke
parents:
diff changeset
85 // Off the end? This happens during debugging dumps when you got
a61af66fc99e Initial load
duke
parents:
diff changeset
86 // brand new live ranges but have not told the allocator yet.
a61af66fc99e Initial load
duke
parents:
diff changeset
87 if( lrg >= _maxlrg ) return lrg;
a61af66fc99e Initial load
duke
parents:
diff changeset
88 uint next = _uf_map[lrg];
a61af66fc99e Initial load
duke
parents:
diff changeset
89 while( next != lrg ) { // Scan chain of equivalences
a61af66fc99e Initial load
duke
parents:
diff changeset
90 assert( next < lrg, "always union smaller" );
a61af66fc99e Initial load
duke
parents:
diff changeset
91 lrg = next; // until find a fixed-point
a61af66fc99e Initial load
duke
parents:
diff changeset
92 next = _uf_map[lrg];
a61af66fc99e Initial load
duke
parents:
diff changeset
93 }
a61af66fc99e Initial load
duke
parents:
diff changeset
94 return next;
a61af66fc99e Initial load
duke
parents:
diff changeset
95 }
a61af66fc99e Initial load
duke
parents:
diff changeset
96
a61af66fc99e Initial load
duke
parents:
diff changeset
97 //------------------------------Find-------------------------------------------
a61af66fc99e Initial load
duke
parents:
diff changeset
98 // Like Find above, but no path compress, so bad asymptotic behavior
a61af66fc99e Initial load
duke
parents:
diff changeset
99 uint PhaseChaitin::Find_const( const Node *n ) const {
a61af66fc99e Initial load
duke
parents:
diff changeset
100 if( n->_idx >= _names.Size() ) return 0; // not mapped, usual for debug dump
a61af66fc99e Initial load
duke
parents:
diff changeset
101 return Find_const( _names[n->_idx] );
a61af66fc99e Initial load
duke
parents:
diff changeset
102 }
a61af66fc99e Initial load
duke
parents:
diff changeset
103
a61af66fc99e Initial load
duke
parents:
diff changeset
104 //------------------------------Union------------------------------------------
a61af66fc99e Initial load
duke
parents:
diff changeset
105 // union 2 sets together.
a61af66fc99e Initial load
duke
parents:
diff changeset
106 void PhaseChaitin::Union( const Node *src_n, const Node *dst_n ) {
a61af66fc99e Initial load
duke
parents:
diff changeset
107 uint src = Find(src_n);
a61af66fc99e Initial load
duke
parents:
diff changeset
108 uint dst = Find(dst_n);
a61af66fc99e Initial load
duke
parents:
diff changeset
109 assert( src, "" );
a61af66fc99e Initial load
duke
parents:
diff changeset
110 assert( dst, "" );
a61af66fc99e Initial load
duke
parents:
diff changeset
111 assert( src < _maxlrg, "oob" );
a61af66fc99e Initial load
duke
parents:
diff changeset
112 assert( dst < _maxlrg, "oob" );
a61af66fc99e Initial load
duke
parents:
diff changeset
113 assert( src < dst, "always union smaller" );
a61af66fc99e Initial load
duke
parents:
diff changeset
114 _uf_map.map(dst,src);
a61af66fc99e Initial load
duke
parents:
diff changeset
115 }
a61af66fc99e Initial load
duke
parents:
diff changeset
116
a61af66fc99e Initial load
duke
parents:
diff changeset
117 //------------------------------new_lrg----------------------------------------
a61af66fc99e Initial load
duke
parents:
diff changeset
118 void PhaseChaitin::new_lrg( const Node *x, uint lrg ) {
a61af66fc99e Initial load
duke
parents:
diff changeset
119 // Make the Node->LRG mapping
a61af66fc99e Initial load
duke
parents:
diff changeset
120 _names.extend(x->_idx,lrg);
a61af66fc99e Initial load
duke
parents:
diff changeset
121 // Make the Union-Find mapping an identity function
a61af66fc99e Initial load
duke
parents:
diff changeset
122 _uf_map.extend(lrg,lrg);
a61af66fc99e Initial load
duke
parents:
diff changeset
123 }
a61af66fc99e Initial load
duke
parents:
diff changeset
124
a61af66fc99e Initial load
duke
parents:
diff changeset
125 //------------------------------clone_projs------------------------------------
a61af66fc99e Initial load
duke
parents:
diff changeset
126 // After cloning some rematierialized instruction, clone any MachProj's that
a61af66fc99e Initial load
duke
parents:
diff changeset
127 // follow it. Example: Intel zero is XOR, kills flags. Sparc FP constants
a61af66fc99e Initial load
duke
parents:
diff changeset
128 // use G3 as an address temp.
a61af66fc99e Initial load
duke
parents:
diff changeset
129 int PhaseChaitin::clone_projs( Block *b, uint idx, Node *con, Node *copy, uint &maxlrg ) {
a61af66fc99e Initial load
duke
parents:
diff changeset
130 Block *bcon = _cfg._bbs[con->_idx];
a61af66fc99e Initial load
duke
parents:
diff changeset
131 uint cindex = bcon->find_node(con);
a61af66fc99e Initial load
duke
parents:
diff changeset
132 Node *con_next = bcon->_nodes[cindex+1];
a61af66fc99e Initial load
duke
parents:
diff changeset
133 if( con_next->in(0) != con || con_next->Opcode() != Op_MachProj )
a61af66fc99e Initial load
duke
parents:
diff changeset
134 return false; // No MachProj's follow
a61af66fc99e Initial load
duke
parents:
diff changeset
135
a61af66fc99e Initial load
duke
parents:
diff changeset
136 // Copy kills after the cloned constant
a61af66fc99e Initial load
duke
parents:
diff changeset
137 Node *kills = con_next->clone();
a61af66fc99e Initial load
duke
parents:
diff changeset
138 kills->set_req( 0, copy );
a61af66fc99e Initial load
duke
parents:
diff changeset
139 b->_nodes.insert( idx, kills );
a61af66fc99e Initial load
duke
parents:
diff changeset
140 _cfg._bbs.map( kills->_idx, b );
a61af66fc99e Initial load
duke
parents:
diff changeset
141 new_lrg( kills, maxlrg++ );
a61af66fc99e Initial load
duke
parents:
diff changeset
142 return true;
a61af66fc99e Initial load
duke
parents:
diff changeset
143 }
a61af66fc99e Initial load
duke
parents:
diff changeset
144
a61af66fc99e Initial load
duke
parents:
diff changeset
145 //------------------------------compact----------------------------------------
a61af66fc99e Initial load
duke
parents:
diff changeset
146 // Renumber the live ranges to compact them. Makes the IFG smaller.
a61af66fc99e Initial load
duke
parents:
diff changeset
147 void PhaseChaitin::compact() {
a61af66fc99e Initial load
duke
parents:
diff changeset
148 // Current the _uf_map contains a series of short chains which are headed
a61af66fc99e Initial load
duke
parents:
diff changeset
149 // by a self-cycle. All the chains run from big numbers to little numbers.
a61af66fc99e Initial load
duke
parents:
diff changeset
150 // The Find() call chases the chains & shortens them for the next Find call.
a61af66fc99e Initial load
duke
parents:
diff changeset
151 // We are going to change this structure slightly. Numbers above a moving
a61af66fc99e Initial load
duke
parents:
diff changeset
152 // wave 'i' are unchanged. Numbers below 'j' point directly to their
a61af66fc99e Initial load
duke
parents:
diff changeset
153 // compacted live range with no further chaining. There are no chains or
a61af66fc99e Initial load
duke
parents:
diff changeset
154 // cycles below 'i', so the Find call no longer works.
a61af66fc99e Initial load
duke
parents:
diff changeset
155 uint j=1;
a61af66fc99e Initial load
duke
parents:
diff changeset
156 uint i;
a61af66fc99e Initial load
duke
parents:
diff changeset
157 for( i=1; i < _maxlrg; i++ ) {
a61af66fc99e Initial load
duke
parents:
diff changeset
158 uint lr = _uf_map[i];
a61af66fc99e Initial load
duke
parents:
diff changeset
159 // Ignore unallocated live ranges
a61af66fc99e Initial load
duke
parents:
diff changeset
160 if( !lr ) continue;
a61af66fc99e Initial load
duke
parents:
diff changeset
161 assert( lr <= i, "" );
a61af66fc99e Initial load
duke
parents:
diff changeset
162 _uf_map.map(i, ( lr == i ) ? j++ : _uf_map[lr]);
a61af66fc99e Initial load
duke
parents:
diff changeset
163 }
a61af66fc99e Initial load
duke
parents:
diff changeset
164 if( false ) // PrintOptoCompactLiveRanges
a61af66fc99e Initial load
duke
parents:
diff changeset
165 printf("Compacted %d LRs from %d\n",i-j,i);
a61af66fc99e Initial load
duke
parents:
diff changeset
166 // Now change the Node->LR mapping to reflect the compacted names
a61af66fc99e Initial load
duke
parents:
diff changeset
167 uint unique = _names.Size();
a61af66fc99e Initial load
duke
parents:
diff changeset
168 for( i=0; i<unique; i++ )
a61af66fc99e Initial load
duke
parents:
diff changeset
169 _names.map(i,_uf_map[_names[i]]);
a61af66fc99e Initial load
duke
parents:
diff changeset
170
a61af66fc99e Initial load
duke
parents:
diff changeset
171 // Reset the Union-Find mapping
a61af66fc99e Initial load
duke
parents:
diff changeset
172 reset_uf_map(j);
a61af66fc99e Initial load
duke
parents:
diff changeset
173
a61af66fc99e Initial load
duke
parents:
diff changeset
174 }
a61af66fc99e Initial load
duke
parents:
diff changeset
175
a61af66fc99e Initial load
duke
parents:
diff changeset
176 //=============================================================================
a61af66fc99e Initial load
duke
parents:
diff changeset
177 //------------------------------Dump-------------------------------------------
a61af66fc99e Initial load
duke
parents:
diff changeset
178 #ifndef PRODUCT
a61af66fc99e Initial load
duke
parents:
diff changeset
179 void PhaseCoalesce::dump( Node *n ) const {
a61af66fc99e Initial load
duke
parents:
diff changeset
180 // Being a const function means I cannot use 'Find'
a61af66fc99e Initial load
duke
parents:
diff changeset
181 uint r = _phc.Find(n);
a61af66fc99e Initial load
duke
parents:
diff changeset
182 tty->print("L%d/N%d ",r,n->_idx);
a61af66fc99e Initial load
duke
parents:
diff changeset
183 }
a61af66fc99e Initial load
duke
parents:
diff changeset
184
a61af66fc99e Initial load
duke
parents:
diff changeset
185 //------------------------------dump-------------------------------------------
a61af66fc99e Initial load
duke
parents:
diff changeset
186 void PhaseCoalesce::dump() const {
a61af66fc99e Initial load
duke
parents:
diff changeset
187 // I know I have a block layout now, so I can print blocks in a loop
a61af66fc99e Initial load
duke
parents:
diff changeset
188 for( uint i=0; i<_phc._cfg._num_blocks; i++ ) {
a61af66fc99e Initial load
duke
parents:
diff changeset
189 uint j;
a61af66fc99e Initial load
duke
parents:
diff changeset
190 Block *b = _phc._cfg._blocks[i];
a61af66fc99e Initial load
duke
parents:
diff changeset
191 // Print a nice block header
a61af66fc99e Initial load
duke
parents:
diff changeset
192 tty->print("B%d: ",b->_pre_order);
a61af66fc99e Initial load
duke
parents:
diff changeset
193 for( j=1; j<b->num_preds(); j++ )
a61af66fc99e Initial load
duke
parents:
diff changeset
194 tty->print("B%d ", _phc._cfg._bbs[b->pred(j)->_idx]->_pre_order);
a61af66fc99e Initial load
duke
parents:
diff changeset
195 tty->print("-> ");
a61af66fc99e Initial load
duke
parents:
diff changeset
196 for( j=0; j<b->_num_succs; j++ )
a61af66fc99e Initial load
duke
parents:
diff changeset
197 tty->print("B%d ",b->_succs[j]->_pre_order);
a61af66fc99e Initial load
duke
parents:
diff changeset
198 tty->print(" IDom: B%d/#%d\n", b->_idom ? b->_idom->_pre_order : 0, b->_dom_depth);
a61af66fc99e Initial load
duke
parents:
diff changeset
199 uint cnt = b->_nodes.size();
a61af66fc99e Initial load
duke
parents:
diff changeset
200 for( j=0; j<cnt; j++ ) {
a61af66fc99e Initial load
duke
parents:
diff changeset
201 Node *n = b->_nodes[j];
a61af66fc99e Initial load
duke
parents:
diff changeset
202 dump( n );
a61af66fc99e Initial load
duke
parents:
diff changeset
203 tty->print("\t%s\t",n->Name());
a61af66fc99e Initial load
duke
parents:
diff changeset
204
a61af66fc99e Initial load
duke
parents:
diff changeset
205 // Dump the inputs
a61af66fc99e Initial load
duke
parents:
diff changeset
206 uint k; // Exit value of loop
a61af66fc99e Initial load
duke
parents:
diff changeset
207 for( k=0; k<n->req(); k++ ) // For all required inputs
a61af66fc99e Initial load
duke
parents:
diff changeset
208 if( n->in(k) ) dump( n->in(k) );
a61af66fc99e Initial load
duke
parents:
diff changeset
209 else tty->print("_ ");
a61af66fc99e Initial load
duke
parents:
diff changeset
210 int any_prec = 0;
a61af66fc99e Initial load
duke
parents:
diff changeset
211 for( ; k<n->len(); k++ ) // For all precedence inputs
a61af66fc99e Initial load
duke
parents:
diff changeset
212 if( n->in(k) ) {
a61af66fc99e Initial load
duke
parents:
diff changeset
213 if( !any_prec++ ) tty->print(" |");
a61af66fc99e Initial load
duke
parents:
diff changeset
214 dump( n->in(k) );
a61af66fc99e Initial load
duke
parents:
diff changeset
215 }
a61af66fc99e Initial load
duke
parents:
diff changeset
216
a61af66fc99e Initial load
duke
parents:
diff changeset
217 // Dump node-specific info
a61af66fc99e Initial load
duke
parents:
diff changeset
218 n->dump_spec(tty);
a61af66fc99e Initial load
duke
parents:
diff changeset
219 tty->print("\n");
a61af66fc99e Initial load
duke
parents:
diff changeset
220
a61af66fc99e Initial load
duke
parents:
diff changeset
221 }
a61af66fc99e Initial load
duke
parents:
diff changeset
222 tty->print("\n");
a61af66fc99e Initial load
duke
parents:
diff changeset
223 }
a61af66fc99e Initial load
duke
parents:
diff changeset
224 }
a61af66fc99e Initial load
duke
parents:
diff changeset
225 #endif
a61af66fc99e Initial load
duke
parents:
diff changeset
226
a61af66fc99e Initial load
duke
parents:
diff changeset
227 //------------------------------combine_these_two------------------------------
a61af66fc99e Initial load
duke
parents:
diff changeset
228 // Combine the live ranges def'd by these 2 Nodes. N2 is an input to N1.
a61af66fc99e Initial load
duke
parents:
diff changeset
229 void PhaseCoalesce::combine_these_two( Node *n1, Node *n2 ) {
a61af66fc99e Initial load
duke
parents:
diff changeset
230 uint lr1 = _phc.Find(n1);
a61af66fc99e Initial load
duke
parents:
diff changeset
231 uint lr2 = _phc.Find(n2);
a61af66fc99e Initial load
duke
parents:
diff changeset
232 if( lr1 != lr2 && // Different live ranges already AND
a61af66fc99e Initial load
duke
parents:
diff changeset
233 !_phc._ifg->test_edge_sq( lr1, lr2 ) ) { // Do not interfere
a61af66fc99e Initial load
duke
parents:
diff changeset
234 LRG *lrg1 = &_phc.lrgs(lr1);
a61af66fc99e Initial load
duke
parents:
diff changeset
235 LRG *lrg2 = &_phc.lrgs(lr2);
a61af66fc99e Initial load
duke
parents:
diff changeset
236 // Not an oop->int cast; oop->oop, int->int, AND int->oop are OK.
a61af66fc99e Initial load
duke
parents:
diff changeset
237
a61af66fc99e Initial load
duke
parents:
diff changeset
238 // Now, why is int->oop OK? We end up declaring a raw-pointer as an oop
a61af66fc99e Initial load
duke
parents:
diff changeset
239 // and in general that's a bad thing. However, int->oop conversions only
a61af66fc99e Initial load
duke
parents:
diff changeset
240 // happen at GC points, so the lifetime of the misclassified raw-pointer
a61af66fc99e Initial load
duke
parents:
diff changeset
241 // is from the CheckCastPP (that converts it to an oop) backwards up
a61af66fc99e Initial load
duke
parents:
diff changeset
242 // through a merge point and into the slow-path call, and around the
a61af66fc99e Initial load
duke
parents:
diff changeset
243 // diamond up to the heap-top check and back down into the slow-path call.
a61af66fc99e Initial load
duke
parents:
diff changeset
244 // The misclassified raw pointer is NOT live across the slow-path call,
a61af66fc99e Initial load
duke
parents:
diff changeset
245 // and so does not appear in any GC info, so the fact that it is
a61af66fc99e Initial load
duke
parents:
diff changeset
246 // misclassified is OK.
a61af66fc99e Initial load
duke
parents:
diff changeset
247
a61af66fc99e Initial load
duke
parents:
diff changeset
248 if( (lrg1->_is_oop || !lrg2->_is_oop) && // not an oop->int cast AND
a61af66fc99e Initial load
duke
parents:
diff changeset
249 // Compatible final mask
a61af66fc99e Initial load
duke
parents:
diff changeset
250 lrg1->mask().overlap( lrg2->mask() ) ) {
a61af66fc99e Initial load
duke
parents:
diff changeset
251 // Merge larger into smaller.
a61af66fc99e Initial load
duke
parents:
diff changeset
252 if( lr1 > lr2 ) {
a61af66fc99e Initial load
duke
parents:
diff changeset
253 uint tmp = lr1; lr1 = lr2; lr2 = tmp;
a61af66fc99e Initial load
duke
parents:
diff changeset
254 Node *n = n1; n1 = n2; n2 = n;
a61af66fc99e Initial load
duke
parents:
diff changeset
255 LRG *ltmp = lrg1; lrg1 = lrg2; lrg2 = ltmp;
a61af66fc99e Initial load
duke
parents:
diff changeset
256 }
a61af66fc99e Initial load
duke
parents:
diff changeset
257 // Union lr2 into lr1
a61af66fc99e Initial load
duke
parents:
diff changeset
258 _phc.Union( n1, n2 );
a61af66fc99e Initial load
duke
parents:
diff changeset
259 if (lrg1->_maxfreq < lrg2->_maxfreq)
a61af66fc99e Initial load
duke
parents:
diff changeset
260 lrg1->_maxfreq = lrg2->_maxfreq;
a61af66fc99e Initial load
duke
parents:
diff changeset
261 // Merge in the IFG
a61af66fc99e Initial load
duke
parents:
diff changeset
262 _phc._ifg->Union( lr1, lr2 );
a61af66fc99e Initial load
duke
parents:
diff changeset
263 // Combine register restrictions
a61af66fc99e Initial load
duke
parents:
diff changeset
264 lrg1->AND(lrg2->mask());
a61af66fc99e Initial load
duke
parents:
diff changeset
265 }
a61af66fc99e Initial load
duke
parents:
diff changeset
266 }
a61af66fc99e Initial load
duke
parents:
diff changeset
267 }
a61af66fc99e Initial load
duke
parents:
diff changeset
268
a61af66fc99e Initial load
duke
parents:
diff changeset
269 //------------------------------coalesce_driver--------------------------------
a61af66fc99e Initial load
duke
parents:
diff changeset
270 // Copy coalescing
a61af66fc99e Initial load
duke
parents:
diff changeset
271 void PhaseCoalesce::coalesce_driver( ) {
a61af66fc99e Initial load
duke
parents:
diff changeset
272
a61af66fc99e Initial load
duke
parents:
diff changeset
273 verify();
a61af66fc99e Initial load
duke
parents:
diff changeset
274 // Coalesce from high frequency to low
a61af66fc99e Initial load
duke
parents:
diff changeset
275 for( uint i=0; i<_phc._cfg._num_blocks; i++ )
a61af66fc99e Initial load
duke
parents:
diff changeset
276 coalesce( _phc._blks[i] );
a61af66fc99e Initial load
duke
parents:
diff changeset
277
a61af66fc99e Initial load
duke
parents:
diff changeset
278 }
a61af66fc99e Initial load
duke
parents:
diff changeset
279
a61af66fc99e Initial load
duke
parents:
diff changeset
280 //------------------------------insert_copy_with_overlap-----------------------
a61af66fc99e Initial load
duke
parents:
diff changeset
281 // I am inserting copies to come out of SSA form. In the general case, I am
a61af66fc99e Initial load
duke
parents:
diff changeset
282 // doing a parallel renaming. I'm in the Named world now, so I can't do a
a61af66fc99e Initial load
duke
parents:
diff changeset
283 // general parallel renaming. All the copies now use "names" (live-ranges)
a61af66fc99e Initial load
duke
parents:
diff changeset
284 // to carry values instead of the explicit use-def chains. Suppose I need to
a61af66fc99e Initial load
duke
parents:
diff changeset
285 // insert 2 copies into the same block. They copy L161->L128 and L128->L132.
a61af66fc99e Initial load
duke
parents:
diff changeset
286 // If I insert them in the wrong order then L128 will get clobbered before it
a61af66fc99e Initial load
duke
parents:
diff changeset
287 // can get used by the second copy. This cannot happen in the SSA model;
a61af66fc99e Initial load
duke
parents:
diff changeset
288 // direct use-def chains get me the right value. It DOES happen in the named
a61af66fc99e Initial load
duke
parents:
diff changeset
289 // model so I have to handle the reordering of copies.
a61af66fc99e Initial load
duke
parents:
diff changeset
290 //
a61af66fc99e Initial load
duke
parents:
diff changeset
291 // In general, I need to topo-sort the placed copies to avoid conflicts.
a61af66fc99e Initial load
duke
parents:
diff changeset
292 // Its possible to have a closed cycle of copies (e.g., recirculating the same
a61af66fc99e Initial load
duke
parents:
diff changeset
293 // values around a loop). In this case I need a temp to break the cycle.
a61af66fc99e Initial load
duke
parents:
diff changeset
294 void PhaseAggressiveCoalesce::insert_copy_with_overlap( Block *b, Node *copy, uint dst_name, uint src_name ) {
a61af66fc99e Initial load
duke
parents:
diff changeset
295
a61af66fc99e Initial load
duke
parents:
diff changeset
296 // Scan backwards for the locations of the last use of the dst_name.
a61af66fc99e Initial load
duke
parents:
diff changeset
297 // I am about to clobber the dst_name, so the copy must be inserted
a61af66fc99e Initial load
duke
parents:
diff changeset
298 // after the last use. Last use is really first-use on a backwards scan.
a61af66fc99e Initial load
duke
parents:
diff changeset
299 uint i = b->end_idx()-1;
a61af66fc99e Initial load
duke
parents:
diff changeset
300 while( 1 ) {
a61af66fc99e Initial load
duke
parents:
diff changeset
301 Node *n = b->_nodes[i];
a61af66fc99e Initial load
duke
parents:
diff changeset
302 // Check for end of virtual copies; this is also the end of the
a61af66fc99e Initial load
duke
parents:
diff changeset
303 // parallel renaming effort.
a61af66fc99e Initial load
duke
parents:
diff changeset
304 if( n->_idx < _unique ) break;
a61af66fc99e Initial load
duke
parents:
diff changeset
305 uint idx = n->is_Copy();
a61af66fc99e Initial load
duke
parents:
diff changeset
306 assert( idx || n->is_Con() || n->Opcode() == Op_MachProj, "Only copies during parallel renaming" );
a61af66fc99e Initial load
duke
parents:
diff changeset
307 if( idx && _phc.Find(n->in(idx)) == dst_name ) break;
a61af66fc99e Initial load
duke
parents:
diff changeset
308 i--;
a61af66fc99e Initial load
duke
parents:
diff changeset
309 }
a61af66fc99e Initial load
duke
parents:
diff changeset
310 uint last_use_idx = i;
a61af66fc99e Initial load
duke
parents:
diff changeset
311
a61af66fc99e Initial load
duke
parents:
diff changeset
312 // Also search for any kill of src_name that exits the block.
a61af66fc99e Initial load
duke
parents:
diff changeset
313 // Since the copy uses src_name, I have to come before any kill.
a61af66fc99e Initial load
duke
parents:
diff changeset
314 uint kill_src_idx = b->end_idx();
a61af66fc99e Initial load
duke
parents:
diff changeset
315 // There can be only 1 kill that exits any block and that is
a61af66fc99e Initial load
duke
parents:
diff changeset
316 // the last kill. Thus it is the first kill on a backwards scan.
a61af66fc99e Initial load
duke
parents:
diff changeset
317 i = b->end_idx()-1;
a61af66fc99e Initial load
duke
parents:
diff changeset
318 while( 1 ) {
a61af66fc99e Initial load
duke
parents:
diff changeset
319 Node *n = b->_nodes[i];
a61af66fc99e Initial load
duke
parents:
diff changeset
320 // Check for end of virtual copies; this is also the end of the
a61af66fc99e Initial load
duke
parents:
diff changeset
321 // parallel renaming effort.
a61af66fc99e Initial load
duke
parents:
diff changeset
322 if( n->_idx < _unique ) break;
a61af66fc99e Initial load
duke
parents:
diff changeset
323 assert( n->is_Copy() || n->is_Con() || n->Opcode() == Op_MachProj, "Only copies during parallel renaming" );
a61af66fc99e Initial load
duke
parents:
diff changeset
324 if( _phc.Find(n) == src_name ) {
a61af66fc99e Initial load
duke
parents:
diff changeset
325 kill_src_idx = i;
a61af66fc99e Initial load
duke
parents:
diff changeset
326 break;
a61af66fc99e Initial load
duke
parents:
diff changeset
327 }
a61af66fc99e Initial load
duke
parents:
diff changeset
328 i--;
a61af66fc99e Initial load
duke
parents:
diff changeset
329 }
a61af66fc99e Initial load
duke
parents:
diff changeset
330 // Need a temp? Last use of dst comes after the kill of src?
a61af66fc99e Initial load
duke
parents:
diff changeset
331 if( last_use_idx >= kill_src_idx ) {
a61af66fc99e Initial load
duke
parents:
diff changeset
332 // Need to break a cycle with a temp
a61af66fc99e Initial load
duke
parents:
diff changeset
333 uint idx = copy->is_Copy();
a61af66fc99e Initial load
duke
parents:
diff changeset
334 Node *tmp = copy->clone();
a61af66fc99e Initial load
duke
parents:
diff changeset
335 _phc.new_lrg(tmp,_phc._maxlrg++);
a61af66fc99e Initial load
duke
parents:
diff changeset
336 // Insert new temp between copy and source
a61af66fc99e Initial load
duke
parents:
diff changeset
337 tmp ->set_req(idx,copy->in(idx));
a61af66fc99e Initial load
duke
parents:
diff changeset
338 copy->set_req(idx,tmp);
a61af66fc99e Initial load
duke
parents:
diff changeset
339 // Save source in temp early, before source is killed
a61af66fc99e Initial load
duke
parents:
diff changeset
340 b->_nodes.insert(kill_src_idx,tmp);
a61af66fc99e Initial load
duke
parents:
diff changeset
341 _phc._cfg._bbs.map( tmp->_idx, b );
a61af66fc99e Initial load
duke
parents:
diff changeset
342 last_use_idx++;
a61af66fc99e Initial load
duke
parents:
diff changeset
343 }
a61af66fc99e Initial load
duke
parents:
diff changeset
344
a61af66fc99e Initial load
duke
parents:
diff changeset
345 // Insert just after last use
a61af66fc99e Initial load
duke
parents:
diff changeset
346 b->_nodes.insert(last_use_idx+1,copy);
a61af66fc99e Initial load
duke
parents:
diff changeset
347 }
a61af66fc99e Initial load
duke
parents:
diff changeset
348
a61af66fc99e Initial load
duke
parents:
diff changeset
349 //------------------------------insert_copies----------------------------------
a61af66fc99e Initial load
duke
parents:
diff changeset
350 void PhaseAggressiveCoalesce::insert_copies( Matcher &matcher ) {
a61af66fc99e Initial load
duke
parents:
diff changeset
351 // We do LRGs compressing and fix a liveout data only here since the other
a61af66fc99e Initial load
duke
parents:
diff changeset
352 // place in Split() is guarded by the assert which we never hit.
a61af66fc99e Initial load
duke
parents:
diff changeset
353 _phc.compress_uf_map_for_nodes();
a61af66fc99e Initial load
duke
parents:
diff changeset
354 // Fix block's liveout data for compressed live ranges.
a61af66fc99e Initial load
duke
parents:
diff changeset
355 for(uint lrg = 1; lrg < _phc._maxlrg; lrg++ ) {
a61af66fc99e Initial load
duke
parents:
diff changeset
356 uint compressed_lrg = _phc.Find(lrg);
a61af66fc99e Initial load
duke
parents:
diff changeset
357 if( lrg != compressed_lrg ) {
a61af66fc99e Initial load
duke
parents:
diff changeset
358 for( uint bidx = 0; bidx < _phc._cfg._num_blocks; bidx++ ) {
a61af66fc99e Initial load
duke
parents:
diff changeset
359 IndexSet *liveout = _phc._live->live(_phc._cfg._blocks[bidx]);
a61af66fc99e Initial load
duke
parents:
diff changeset
360 if( liveout->member(lrg) ) {
a61af66fc99e Initial load
duke
parents:
diff changeset
361 liveout->remove(lrg);
a61af66fc99e Initial load
duke
parents:
diff changeset
362 liveout->insert(compressed_lrg);
a61af66fc99e Initial load
duke
parents:
diff changeset
363 }
a61af66fc99e Initial load
duke
parents:
diff changeset
364 }
a61af66fc99e Initial load
duke
parents:
diff changeset
365 }
a61af66fc99e Initial load
duke
parents:
diff changeset
366 }
a61af66fc99e Initial load
duke
parents:
diff changeset
367
a61af66fc99e Initial load
duke
parents:
diff changeset
368 // All new nodes added are actual copies to replace virtual copies.
a61af66fc99e Initial load
duke
parents:
diff changeset
369 // Nodes with index less than '_unique' are original, non-virtual Nodes.
a61af66fc99e Initial load
duke
parents:
diff changeset
370 _unique = C->unique();
a61af66fc99e Initial load
duke
parents:
diff changeset
371
a61af66fc99e Initial load
duke
parents:
diff changeset
372 for( uint i=0; i<_phc._cfg._num_blocks; i++ ) {
a61af66fc99e Initial load
duke
parents:
diff changeset
373 Block *b = _phc._cfg._blocks[i];
a61af66fc99e Initial load
duke
parents:
diff changeset
374 uint cnt = b->num_preds(); // Number of inputs to the Phi
a61af66fc99e Initial load
duke
parents:
diff changeset
375
a61af66fc99e Initial load
duke
parents:
diff changeset
376 for( uint l = 1; l<b->_nodes.size(); l++ ) {
a61af66fc99e Initial load
duke
parents:
diff changeset
377 Node *n = b->_nodes[l];
a61af66fc99e Initial load
duke
parents:
diff changeset
378
a61af66fc99e Initial load
duke
parents:
diff changeset
379 // Do not use removed-copies, use copied value instead
a61af66fc99e Initial load
duke
parents:
diff changeset
380 uint ncnt = n->req();
a61af66fc99e Initial load
duke
parents:
diff changeset
381 for( uint k = 1; k<ncnt; k++ ) {
a61af66fc99e Initial load
duke
parents:
diff changeset
382 Node *copy = n->in(k);
a61af66fc99e Initial load
duke
parents:
diff changeset
383 uint cidx = copy->is_Copy();
a61af66fc99e Initial load
duke
parents:
diff changeset
384 if( cidx ) {
a61af66fc99e Initial load
duke
parents:
diff changeset
385 Node *def = copy->in(cidx);
a61af66fc99e Initial load
duke
parents:
diff changeset
386 if( _phc.Find(copy) == _phc.Find(def) )
a61af66fc99e Initial load
duke
parents:
diff changeset
387 n->set_req(k,def);
a61af66fc99e Initial load
duke
parents:
diff changeset
388 }
a61af66fc99e Initial load
duke
parents:
diff changeset
389 }
a61af66fc99e Initial load
duke
parents:
diff changeset
390
a61af66fc99e Initial load
duke
parents:
diff changeset
391 // Remove any explicit copies that get coalesced.
a61af66fc99e Initial load
duke
parents:
diff changeset
392 uint cidx = n->is_Copy();
a61af66fc99e Initial load
duke
parents:
diff changeset
393 if( cidx ) {
a61af66fc99e Initial load
duke
parents:
diff changeset
394 Node *def = n->in(cidx);
a61af66fc99e Initial load
duke
parents:
diff changeset
395 if( _phc.Find(n) == _phc.Find(def) ) {
a61af66fc99e Initial load
duke
parents:
diff changeset
396 n->replace_by(def);
a61af66fc99e Initial load
duke
parents:
diff changeset
397 n->set_req(cidx,NULL);
a61af66fc99e Initial load
duke
parents:
diff changeset
398 b->_nodes.remove(l);
a61af66fc99e Initial load
duke
parents:
diff changeset
399 l--;
a61af66fc99e Initial load
duke
parents:
diff changeset
400 continue;
a61af66fc99e Initial load
duke
parents:
diff changeset
401 }
a61af66fc99e Initial load
duke
parents:
diff changeset
402 }
a61af66fc99e Initial load
duke
parents:
diff changeset
403
a61af66fc99e Initial load
duke
parents:
diff changeset
404 if( n->is_Phi() ) {
a61af66fc99e Initial load
duke
parents:
diff changeset
405 // Get the chosen name for the Phi
a61af66fc99e Initial load
duke
parents:
diff changeset
406 uint phi_name = _phc.Find( n );
a61af66fc99e Initial load
duke
parents:
diff changeset
407 // Ignore the pre-allocated specials
a61af66fc99e Initial load
duke
parents:
diff changeset
408 if( !phi_name ) continue;
a61af66fc99e Initial load
duke
parents:
diff changeset
409 // Check for mismatch inputs to Phi
a61af66fc99e Initial load
duke
parents:
diff changeset
410 for( uint j = 1; j<cnt; j++ ) {
a61af66fc99e Initial load
duke
parents:
diff changeset
411 Node *m = n->in(j);
a61af66fc99e Initial load
duke
parents:
diff changeset
412 uint src_name = _phc.Find(m);
a61af66fc99e Initial load
duke
parents:
diff changeset
413 if( src_name != phi_name ) {
a61af66fc99e Initial load
duke
parents:
diff changeset
414 Block *pred = _phc._cfg._bbs[b->pred(j)->_idx];
a61af66fc99e Initial load
duke
parents:
diff changeset
415 Node *copy;
a61af66fc99e Initial load
duke
parents:
diff changeset
416 assert(!m->is_Con() || m->is_Mach(), "all Con must be Mach");
a61af66fc99e Initial load
duke
parents:
diff changeset
417 // Rematerialize constants instead of copying them
a61af66fc99e Initial load
duke
parents:
diff changeset
418 if( m->is_Mach() && m->as_Mach()->is_Con() &&
a61af66fc99e Initial load
duke
parents:
diff changeset
419 m->as_Mach()->rematerialize() ) {
a61af66fc99e Initial load
duke
parents:
diff changeset
420 copy = m->clone();
a61af66fc99e Initial load
duke
parents:
diff changeset
421 // Insert the copy in the predecessor basic block
a61af66fc99e Initial load
duke
parents:
diff changeset
422 pred->add_inst(copy);
a61af66fc99e Initial load
duke
parents:
diff changeset
423 // Copy any flags as well
a61af66fc99e Initial load
duke
parents:
diff changeset
424 _phc.clone_projs( pred, pred->end_idx(), m, copy, _phc._maxlrg );
a61af66fc99e Initial load
duke
parents:
diff changeset
425 } else {
a61af66fc99e Initial load
duke
parents:
diff changeset
426 const RegMask *rm = C->matcher()->idealreg2spillmask[m->ideal_reg()];
a61af66fc99e Initial load
duke
parents:
diff changeset
427 copy = new (C) MachSpillCopyNode(m,*rm,*rm);
a61af66fc99e Initial load
duke
parents:
diff changeset
428 // Find a good place to insert. Kinda tricky, use a subroutine
a61af66fc99e Initial load
duke
parents:
diff changeset
429 insert_copy_with_overlap(pred,copy,phi_name,src_name);
a61af66fc99e Initial load
duke
parents:
diff changeset
430 }
a61af66fc99e Initial load
duke
parents:
diff changeset
431 // Insert the copy in the use-def chain
a61af66fc99e Initial load
duke
parents:
diff changeset
432 n->set_req( j, copy );
a61af66fc99e Initial load
duke
parents:
diff changeset
433 _phc._cfg._bbs.map( copy->_idx, pred );
a61af66fc99e Initial load
duke
parents:
diff changeset
434 // Extend ("register allocate") the names array for the copy.
a61af66fc99e Initial load
duke
parents:
diff changeset
435 _phc._names.extend( copy->_idx, phi_name );
a61af66fc99e Initial load
duke
parents:
diff changeset
436 } // End of if Phi names do not match
a61af66fc99e Initial load
duke
parents:
diff changeset
437 } // End of for all inputs to Phi
a61af66fc99e Initial load
duke
parents:
diff changeset
438 } else { // End of if Phi
a61af66fc99e Initial load
duke
parents:
diff changeset
439
a61af66fc99e Initial load
duke
parents:
diff changeset
440 // Now check for 2-address instructions
a61af66fc99e Initial load
duke
parents:
diff changeset
441 uint idx;
a61af66fc99e Initial load
duke
parents:
diff changeset
442 if( n->is_Mach() && (idx=n->as_Mach()->two_adr()) ) {
a61af66fc99e Initial load
duke
parents:
diff changeset
443 // Get the chosen name for the Node
a61af66fc99e Initial load
duke
parents:
diff changeset
444 uint name = _phc.Find( n );
a61af66fc99e Initial load
duke
parents:
diff changeset
445 assert( name, "no 2-address specials" );
a61af66fc99e Initial load
duke
parents:
diff changeset
446 // Check for name mis-match on the 2-address input
a61af66fc99e Initial load
duke
parents:
diff changeset
447 Node *m = n->in(idx);
a61af66fc99e Initial load
duke
parents:
diff changeset
448 if( _phc.Find(m) != name ) {
a61af66fc99e Initial load
duke
parents:
diff changeset
449 Node *copy;
a61af66fc99e Initial load
duke
parents:
diff changeset
450 assert(!m->is_Con() || m->is_Mach(), "all Con must be Mach");
a61af66fc99e Initial load
duke
parents:
diff changeset
451 // At this point it is unsafe to extend live ranges (6550579).
a61af66fc99e Initial load
duke
parents:
diff changeset
452 // Rematerialize only constants as we do for Phi above.
a61af66fc99e Initial load
duke
parents:
diff changeset
453 if( m->is_Mach() && m->as_Mach()->is_Con() &&
a61af66fc99e Initial load
duke
parents:
diff changeset
454 m->as_Mach()->rematerialize() ) {
a61af66fc99e Initial load
duke
parents:
diff changeset
455 copy = m->clone();
a61af66fc99e Initial load
duke
parents:
diff changeset
456 // Insert the copy in the basic block, just before us
a61af66fc99e Initial load
duke
parents:
diff changeset
457 b->_nodes.insert( l++, copy );
a61af66fc99e Initial load
duke
parents:
diff changeset
458 if( _phc.clone_projs( b, l, m, copy, _phc._maxlrg ) )
a61af66fc99e Initial load
duke
parents:
diff changeset
459 l++;
a61af66fc99e Initial load
duke
parents:
diff changeset
460 } else {
a61af66fc99e Initial load
duke
parents:
diff changeset
461 const RegMask *rm = C->matcher()->idealreg2spillmask[m->ideal_reg()];
a61af66fc99e Initial load
duke
parents:
diff changeset
462 copy = new (C) MachSpillCopyNode( m, *rm, *rm );
a61af66fc99e Initial load
duke
parents:
diff changeset
463 // Insert the copy in the basic block, just before us
a61af66fc99e Initial load
duke
parents:
diff changeset
464 b->_nodes.insert( l++, copy );
a61af66fc99e Initial load
duke
parents:
diff changeset
465 }
a61af66fc99e Initial load
duke
parents:
diff changeset
466 // Insert the copy in the use-def chain
a61af66fc99e Initial load
duke
parents:
diff changeset
467 n->set_req(idx, copy );
a61af66fc99e Initial load
duke
parents:
diff changeset
468 // Extend ("register allocate") the names array for the copy.
a61af66fc99e Initial load
duke
parents:
diff changeset
469 _phc._names.extend( copy->_idx, name );
a61af66fc99e Initial load
duke
parents:
diff changeset
470 _phc._cfg._bbs.map( copy->_idx, b );
a61af66fc99e Initial load
duke
parents:
diff changeset
471 }
a61af66fc99e Initial load
duke
parents:
diff changeset
472
a61af66fc99e Initial load
duke
parents:
diff changeset
473 } // End of is two-adr
a61af66fc99e Initial load
duke
parents:
diff changeset
474
a61af66fc99e Initial load
duke
parents:
diff changeset
475 // Insert a copy at a debug use for a lrg which has high frequency
a61af66fc99e Initial load
duke
parents:
diff changeset
476 if( (b->_freq < OPTO_DEBUG_SPLIT_FREQ) && n->is_MachSafePoint() ) {
a61af66fc99e Initial load
duke
parents:
diff changeset
477 // Walk the debug inputs to the node and check for lrg freq
a61af66fc99e Initial load
duke
parents:
diff changeset
478 JVMState* jvms = n->jvms();
a61af66fc99e Initial load
duke
parents:
diff changeset
479 uint debug_start = jvms ? jvms->debug_start() : 999999;
a61af66fc99e Initial load
duke
parents:
diff changeset
480 uint debug_end = jvms ? jvms->debug_end() : 999999;
a61af66fc99e Initial load
duke
parents:
diff changeset
481 for(uint inpidx = debug_start; inpidx < debug_end; inpidx++) {
a61af66fc99e Initial load
duke
parents:
diff changeset
482 // Do not split monitors; they are only needed for debug table
a61af66fc99e Initial load
duke
parents:
diff changeset
483 // entries and need no code.
a61af66fc99e Initial load
duke
parents:
diff changeset
484 if( jvms->is_monitor_use(inpidx) ) continue;
a61af66fc99e Initial load
duke
parents:
diff changeset
485 Node *inp = n->in(inpidx);
a61af66fc99e Initial load
duke
parents:
diff changeset
486 uint nidx = _phc.n2lidx(inp);
a61af66fc99e Initial load
duke
parents:
diff changeset
487 LRG &lrg = lrgs(nidx);
a61af66fc99e Initial load
duke
parents:
diff changeset
488
a61af66fc99e Initial load
duke
parents:
diff changeset
489 // If this lrg has a high frequency use/def
a61af66fc99e Initial load
duke
parents:
diff changeset
490 if( lrg._maxfreq >= OPTO_LRG_HIGH_FREQ ) {
a61af66fc99e Initial load
duke
parents:
diff changeset
491 // If the live range is also live out of this block (like it
a61af66fc99e Initial load
duke
parents:
diff changeset
492 // would be for a fast/slow idiom), the normal spill mechanism
a61af66fc99e Initial load
duke
parents:
diff changeset
493 // does an excellent job. If it is not live out of this block
a61af66fc99e Initial load
duke
parents:
diff changeset
494 // (like it would be for debug info to uncommon trap) splitting
a61af66fc99e Initial load
duke
parents:
diff changeset
495 // the live range now allows a better allocation in the high
a61af66fc99e Initial load
duke
parents:
diff changeset
496 // frequency blocks.
a61af66fc99e Initial load
duke
parents:
diff changeset
497 // Build_IFG_virtual has converted the live sets to
a61af66fc99e Initial load
duke
parents:
diff changeset
498 // live-IN info, not live-OUT info.
a61af66fc99e Initial load
duke
parents:
diff changeset
499 uint k;
a61af66fc99e Initial load
duke
parents:
diff changeset
500 for( k=0; k < b->_num_succs; k++ )
a61af66fc99e Initial load
duke
parents:
diff changeset
501 if( _phc._live->live(b->_succs[k])->member( nidx ) )
a61af66fc99e Initial load
duke
parents:
diff changeset
502 break; // Live in to some successor block?
a61af66fc99e Initial load
duke
parents:
diff changeset
503 if( k < b->_num_succs )
a61af66fc99e Initial load
duke
parents:
diff changeset
504 continue; // Live out; do not pre-split
a61af66fc99e Initial load
duke
parents:
diff changeset
505 // Split the lrg at this use
a61af66fc99e Initial load
duke
parents:
diff changeset
506 const RegMask *rm = C->matcher()->idealreg2spillmask[inp->ideal_reg()];
a61af66fc99e Initial load
duke
parents:
diff changeset
507 Node *copy = new (C) MachSpillCopyNode( inp, *rm, *rm );
a61af66fc99e Initial load
duke
parents:
diff changeset
508 // Insert the copy in the use-def chain
a61af66fc99e Initial load
duke
parents:
diff changeset
509 n->set_req(inpidx, copy );
a61af66fc99e Initial load
duke
parents:
diff changeset
510 // Insert the copy in the basic block, just before us
a61af66fc99e Initial load
duke
parents:
diff changeset
511 b->_nodes.insert( l++, copy );
a61af66fc99e Initial load
duke
parents:
diff changeset
512 // Extend ("register allocate") the names array for the copy.
a61af66fc99e Initial load
duke
parents:
diff changeset
513 _phc.new_lrg( copy, _phc._maxlrg++ );
a61af66fc99e Initial load
duke
parents:
diff changeset
514 _phc._cfg._bbs.map( copy->_idx, b );
a61af66fc99e Initial load
duke
parents:
diff changeset
515 //tty->print_cr("Split a debug use in Aggressive Coalesce");
a61af66fc99e Initial load
duke
parents:
diff changeset
516 } // End of if high frequency use/def
a61af66fc99e Initial load
duke
parents:
diff changeset
517 } // End of for all debug inputs
a61af66fc99e Initial load
duke
parents:
diff changeset
518 } // End of if low frequency safepoint
a61af66fc99e Initial load
duke
parents:
diff changeset
519
a61af66fc99e Initial load
duke
parents:
diff changeset
520 } // End of if Phi
a61af66fc99e Initial load
duke
parents:
diff changeset
521
a61af66fc99e Initial load
duke
parents:
diff changeset
522 } // End of for all instructions
a61af66fc99e Initial load
duke
parents:
diff changeset
523 } // End of for all blocks
a61af66fc99e Initial load
duke
parents:
diff changeset
524 }
a61af66fc99e Initial load
duke
parents:
diff changeset
525
a61af66fc99e Initial load
duke
parents:
diff changeset
526 //=============================================================================
a61af66fc99e Initial load
duke
parents:
diff changeset
527 //------------------------------coalesce---------------------------------------
a61af66fc99e Initial load
duke
parents:
diff changeset
528 // Aggressive (but pessimistic) copy coalescing of a single block
a61af66fc99e Initial load
duke
parents:
diff changeset
529
a61af66fc99e Initial load
duke
parents:
diff changeset
530 // The following coalesce pass represents a single round of aggressive
a61af66fc99e Initial load
duke
parents:
diff changeset
531 // pessimistic coalesce. "Aggressive" means no attempt to preserve
a61af66fc99e Initial load
duke
parents:
diff changeset
532 // colorability when coalescing. This occasionally means more spills, but
a61af66fc99e Initial load
duke
parents:
diff changeset
533 // it also means fewer rounds of coalescing for better code - and that means
a61af66fc99e Initial load
duke
parents:
diff changeset
534 // faster compiles.
a61af66fc99e Initial load
duke
parents:
diff changeset
535
a61af66fc99e Initial load
duke
parents:
diff changeset
536 // "Pessimistic" means we do not hit the fixed point in one pass (and we are
a61af66fc99e Initial load
duke
parents:
diff changeset
537 // reaching for the least fixed point to boot). This is typically solved
a61af66fc99e Initial load
duke
parents:
diff changeset
538 // with a few more rounds of coalescing, but the compiler must run fast. We
a61af66fc99e Initial load
duke
parents:
diff changeset
539 // could optimistically coalescing everything touching PhiNodes together
a61af66fc99e Initial load
duke
parents:
diff changeset
540 // into one big live range, then check for self-interference. Everywhere
a61af66fc99e Initial load
duke
parents:
diff changeset
541 // the live range interferes with self it would have to be split. Finding
a61af66fc99e Initial load
duke
parents:
diff changeset
542 // the right split points can be done with some heuristics (based on
a61af66fc99e Initial load
duke
parents:
diff changeset
543 // expected frequency of edges in the live range). In short, it's a real
a61af66fc99e Initial load
duke
parents:
diff changeset
544 // research problem and the timeline is too short to allow such research.
a61af66fc99e Initial load
duke
parents:
diff changeset
545 // Further thoughts: (1) build the LR in a pass, (2) find self-interference
a61af66fc99e Initial load
duke
parents:
diff changeset
546 // in another pass, (3) per each self-conflict, split, (4) split by finding
a61af66fc99e Initial load
duke
parents:
diff changeset
547 // the low-cost cut (min-cut) of the LR, (5) edges in the LR are weighted
a61af66fc99e Initial load
duke
parents:
diff changeset
548 // according to the GCM algorithm (or just exec freq on CFG edges).
a61af66fc99e Initial load
duke
parents:
diff changeset
549
a61af66fc99e Initial load
duke
parents:
diff changeset
550 void PhaseAggressiveCoalesce::coalesce( Block *b ) {
a61af66fc99e Initial load
duke
parents:
diff changeset
551 // Copies are still "virtual" - meaning we have not made them explicitly
a61af66fc99e Initial load
duke
parents:
diff changeset
552 // copies. Instead, Phi functions of successor blocks have mis-matched
a61af66fc99e Initial load
duke
parents:
diff changeset
553 // live-ranges. If I fail to coalesce, I'll have to insert a copy to line
a61af66fc99e Initial load
duke
parents:
diff changeset
554 // up the live-ranges. Check for Phis in successor blocks.
a61af66fc99e Initial load
duke
parents:
diff changeset
555 uint i;
a61af66fc99e Initial load
duke
parents:
diff changeset
556 for( i=0; i<b->_num_succs; i++ ) {
a61af66fc99e Initial load
duke
parents:
diff changeset
557 Block *bs = b->_succs[i];
a61af66fc99e Initial load
duke
parents:
diff changeset
558 // Find index of 'b' in 'bs' predecessors
a61af66fc99e Initial load
duke
parents:
diff changeset
559 uint j=1;
a61af66fc99e Initial load
duke
parents:
diff changeset
560 while( _phc._cfg._bbs[bs->pred(j)->_idx] != b ) j++;
a61af66fc99e Initial load
duke
parents:
diff changeset
561 // Visit all the Phis in successor block
a61af66fc99e Initial load
duke
parents:
diff changeset
562 for( uint k = 1; k<bs->_nodes.size(); k++ ) {
a61af66fc99e Initial load
duke
parents:
diff changeset
563 Node *n = bs->_nodes[k];
a61af66fc99e Initial load
duke
parents:
diff changeset
564 if( !n->is_Phi() ) break;
a61af66fc99e Initial load
duke
parents:
diff changeset
565 combine_these_two( n, n->in(j) );
a61af66fc99e Initial load
duke
parents:
diff changeset
566 }
a61af66fc99e Initial load
duke
parents:
diff changeset
567 } // End of for all successor blocks
a61af66fc99e Initial load
duke
parents:
diff changeset
568
a61af66fc99e Initial load
duke
parents:
diff changeset
569
a61af66fc99e Initial load
duke
parents:
diff changeset
570 // Check _this_ block for 2-address instructions and copies.
a61af66fc99e Initial load
duke
parents:
diff changeset
571 uint cnt = b->end_idx();
a61af66fc99e Initial load
duke
parents:
diff changeset
572 for( i = 1; i<cnt; i++ ) {
a61af66fc99e Initial load
duke
parents:
diff changeset
573 Node *n = b->_nodes[i];
a61af66fc99e Initial load
duke
parents:
diff changeset
574 uint idx;
a61af66fc99e Initial load
duke
parents:
diff changeset
575 // 2-address instructions have a virtual Copy matching their input
a61af66fc99e Initial load
duke
parents:
diff changeset
576 // to their output
a61af66fc99e Initial load
duke
parents:
diff changeset
577 if( n->is_Mach() && (idx = n->as_Mach()->two_adr()) ) {
a61af66fc99e Initial load
duke
parents:
diff changeset
578 MachNode *mach = n->as_Mach();
a61af66fc99e Initial load
duke
parents:
diff changeset
579 combine_these_two( mach, mach->in(idx) );
a61af66fc99e Initial load
duke
parents:
diff changeset
580 }
a61af66fc99e Initial load
duke
parents:
diff changeset
581 } // End of for all instructions in block
a61af66fc99e Initial load
duke
parents:
diff changeset
582 }
a61af66fc99e Initial load
duke
parents:
diff changeset
583
a61af66fc99e Initial load
duke
parents:
diff changeset
584 //=============================================================================
a61af66fc99e Initial load
duke
parents:
diff changeset
585 //------------------------------PhaseConservativeCoalesce----------------------
a61af66fc99e Initial load
duke
parents:
diff changeset
586 PhaseConservativeCoalesce::PhaseConservativeCoalesce( PhaseChaitin &chaitin ) : PhaseCoalesce(chaitin) {
a61af66fc99e Initial load
duke
parents:
diff changeset
587 _ulr.initialize(_phc._maxlrg);
a61af66fc99e Initial load
duke
parents:
diff changeset
588 }
a61af66fc99e Initial load
duke
parents:
diff changeset
589
a61af66fc99e Initial load
duke
parents:
diff changeset
590 //------------------------------verify-----------------------------------------
a61af66fc99e Initial load
duke
parents:
diff changeset
591 void PhaseConservativeCoalesce::verify() {
a61af66fc99e Initial load
duke
parents:
diff changeset
592 #ifdef ASSERT
a61af66fc99e Initial load
duke
parents:
diff changeset
593 _phc.set_was_low();
a61af66fc99e Initial load
duke
parents:
diff changeset
594 #endif
a61af66fc99e Initial load
duke
parents:
diff changeset
595 }
a61af66fc99e Initial load
duke
parents:
diff changeset
596
a61af66fc99e Initial load
duke
parents:
diff changeset
597 //------------------------------union_helper-----------------------------------
a61af66fc99e Initial load
duke
parents:
diff changeset
598 void PhaseConservativeCoalesce::union_helper( Node *lr1_node, Node *lr2_node, uint lr1, uint lr2, Node *src_def, Node *dst_copy, Node *src_copy, Block *b, uint bindex ) {
a61af66fc99e Initial load
duke
parents:
diff changeset
599 // Join live ranges. Merge larger into smaller. Union lr2 into lr1 in the
a61af66fc99e Initial load
duke
parents:
diff changeset
600 // union-find tree
a61af66fc99e Initial load
duke
parents:
diff changeset
601 _phc.Union( lr1_node, lr2_node );
a61af66fc99e Initial load
duke
parents:
diff changeset
602
a61af66fc99e Initial load
duke
parents:
diff changeset
603 // Single-def live range ONLY if both live ranges are single-def.
a61af66fc99e Initial load
duke
parents:
diff changeset
604 // If both are single def, then src_def powers one live range
a61af66fc99e Initial load
duke
parents:
diff changeset
605 // and def_copy powers the other. After merging, src_def powers
a61af66fc99e Initial load
duke
parents:
diff changeset
606 // the combined live range.
295
ea18057223c4 6732194: Data corruption dependent on -server/-client/-Xbatch
never
parents: 0
diff changeset
607 lrgs(lr1)._def = (lrgs(lr1).is_multidef() ||
ea18057223c4 6732194: Data corruption dependent on -server/-client/-Xbatch
never
parents: 0
diff changeset
608 lrgs(lr2).is_multidef() )
0
a61af66fc99e Initial load
duke
parents:
diff changeset
609 ? NodeSentinel : src_def;
a61af66fc99e Initial load
duke
parents:
diff changeset
610 lrgs(lr2)._def = NULL; // No def for lrg 2
a61af66fc99e Initial load
duke
parents:
diff changeset
611 lrgs(lr2).Clear(); // Force empty mask for LRG 2
a61af66fc99e Initial load
duke
parents:
diff changeset
612 //lrgs(lr2)._size = 0; // Live-range 2 goes dead
a61af66fc99e Initial load
duke
parents:
diff changeset
613 lrgs(lr1)._is_oop |= lrgs(lr2)._is_oop;
a61af66fc99e Initial load
duke
parents:
diff changeset
614 lrgs(lr2)._is_oop = 0; // In particular, not an oop for GC info
a61af66fc99e Initial load
duke
parents:
diff changeset
615
a61af66fc99e Initial load
duke
parents:
diff changeset
616 if (lrgs(lr1)._maxfreq < lrgs(lr2)._maxfreq)
a61af66fc99e Initial load
duke
parents:
diff changeset
617 lrgs(lr1)._maxfreq = lrgs(lr2)._maxfreq;
a61af66fc99e Initial load
duke
parents:
diff changeset
618
a61af66fc99e Initial load
duke
parents:
diff changeset
619 // Copy original value instead. Intermediate copies go dead, and
a61af66fc99e Initial load
duke
parents:
diff changeset
620 // the dst_copy becomes useless.
a61af66fc99e Initial load
duke
parents:
diff changeset
621 int didx = dst_copy->is_Copy();
a61af66fc99e Initial load
duke
parents:
diff changeset
622 dst_copy->set_req( didx, src_def );
a61af66fc99e Initial load
duke
parents:
diff changeset
623 // Add copy to free list
a61af66fc99e Initial load
duke
parents:
diff changeset
624 // _phc.free_spillcopy(b->_nodes[bindex]);
a61af66fc99e Initial load
duke
parents:
diff changeset
625 assert( b->_nodes[bindex] == dst_copy, "" );
a61af66fc99e Initial load
duke
parents:
diff changeset
626 dst_copy->replace_by( dst_copy->in(didx) );
a61af66fc99e Initial load
duke
parents:
diff changeset
627 dst_copy->set_req( didx, NULL);
a61af66fc99e Initial load
duke
parents:
diff changeset
628 b->_nodes.remove(bindex);
a61af66fc99e Initial load
duke
parents:
diff changeset
629 if( bindex < b->_ihrp_index ) b->_ihrp_index--;
a61af66fc99e Initial load
duke
parents:
diff changeset
630 if( bindex < b->_fhrp_index ) b->_fhrp_index--;
a61af66fc99e Initial load
duke
parents:
diff changeset
631
a61af66fc99e Initial load
duke
parents:
diff changeset
632 // Stretched lr1; add it to liveness of intermediate blocks
a61af66fc99e Initial load
duke
parents:
diff changeset
633 Block *b2 = _phc._cfg._bbs[src_copy->_idx];
a61af66fc99e Initial load
duke
parents:
diff changeset
634 while( b != b2 ) {
a61af66fc99e Initial load
duke
parents:
diff changeset
635 b = _phc._cfg._bbs[b->pred(1)->_idx];
a61af66fc99e Initial load
duke
parents:
diff changeset
636 _phc._live->live(b)->insert(lr1);
a61af66fc99e Initial load
duke
parents:
diff changeset
637 }
a61af66fc99e Initial load
duke
parents:
diff changeset
638 }
a61af66fc99e Initial load
duke
parents:
diff changeset
639
a61af66fc99e Initial load
duke
parents:
diff changeset
640 //------------------------------compute_separating_interferences---------------
a61af66fc99e Initial load
duke
parents:
diff changeset
641 // Factored code from copy_copy that computes extra interferences from
a61af66fc99e Initial load
duke
parents:
diff changeset
642 // lengthening a live range by double-coalescing.
a61af66fc99e Initial load
duke
parents:
diff changeset
643 uint PhaseConservativeCoalesce::compute_separating_interferences(Node *dst_copy, Node *src_copy, Block *b, uint bindex, RegMask &rm, uint reg_degree, uint rm_size, uint lr1, uint lr2 ) {
a61af66fc99e Initial load
duke
parents:
diff changeset
644
a61af66fc99e Initial load
duke
parents:
diff changeset
645 assert(!lrgs(lr1)._fat_proj, "cannot coalesce fat_proj");
a61af66fc99e Initial load
duke
parents:
diff changeset
646 assert(!lrgs(lr2)._fat_proj, "cannot coalesce fat_proj");
a61af66fc99e Initial load
duke
parents:
diff changeset
647 Node *prev_copy = dst_copy->in(dst_copy->is_Copy());
a61af66fc99e Initial load
duke
parents:
diff changeset
648 Block *b2 = b;
a61af66fc99e Initial load
duke
parents:
diff changeset
649 uint bindex2 = bindex;
a61af66fc99e Initial load
duke
parents:
diff changeset
650 while( 1 ) {
a61af66fc99e Initial load
duke
parents:
diff changeset
651 // Find previous instruction
a61af66fc99e Initial load
duke
parents:
diff changeset
652 bindex2--; // Chain backwards 1 instruction
a61af66fc99e Initial load
duke
parents:
diff changeset
653 while( bindex2 == 0 ) { // At block start, find prior block
a61af66fc99e Initial load
duke
parents:
diff changeset
654 assert( b2->num_preds() == 2, "cannot double coalesce across c-flow" );
a61af66fc99e Initial load
duke
parents:
diff changeset
655 b2 = _phc._cfg._bbs[b2->pred(1)->_idx];
a61af66fc99e Initial load
duke
parents:
diff changeset
656 bindex2 = b2->end_idx()-1;
a61af66fc99e Initial load
duke
parents:
diff changeset
657 }
a61af66fc99e Initial load
duke
parents:
diff changeset
658 // Get prior instruction
a61af66fc99e Initial load
duke
parents:
diff changeset
659 assert(bindex2 < b2->_nodes.size(), "index out of bounds");
a61af66fc99e Initial load
duke
parents:
diff changeset
660 Node *x = b2->_nodes[bindex2];
a61af66fc99e Initial load
duke
parents:
diff changeset
661 if( x == prev_copy ) { // Previous copy in copy chain?
a61af66fc99e Initial load
duke
parents:
diff changeset
662 if( prev_copy == src_copy)// Found end of chain and all interferences
a61af66fc99e Initial load
duke
parents:
diff changeset
663 break; // So break out of loop
a61af66fc99e Initial load
duke
parents:
diff changeset
664 // Else work back one in copy chain
a61af66fc99e Initial load
duke
parents:
diff changeset
665 prev_copy = prev_copy->in(prev_copy->is_Copy());
a61af66fc99e Initial load
duke
parents:
diff changeset
666 } else { // Else collect interferences
a61af66fc99e Initial load
duke
parents:
diff changeset
667 uint lidx = _phc.Find(x);
a61af66fc99e Initial load
duke
parents:
diff changeset
668 // Found another def of live-range being stretched?
a61af66fc99e Initial load
duke
parents:
diff changeset
669 if( lidx == lr1 ) return max_juint;
a61af66fc99e Initial load
duke
parents:
diff changeset
670 if( lidx == lr2 ) return max_juint;
a61af66fc99e Initial load
duke
parents:
diff changeset
671
a61af66fc99e Initial load
duke
parents:
diff changeset
672 // If we attempt to coalesce across a bound def
a61af66fc99e Initial load
duke
parents:
diff changeset
673 if( lrgs(lidx).is_bound() ) {
a61af66fc99e Initial load
duke
parents:
diff changeset
674 // Do not let the coalesced LRG expect to get the bound color
a61af66fc99e Initial load
duke
parents:
diff changeset
675 rm.SUBTRACT( lrgs(lidx).mask() );
a61af66fc99e Initial load
duke
parents:
diff changeset
676 // Recompute rm_size
a61af66fc99e Initial load
duke
parents:
diff changeset
677 rm_size = rm.Size();
a61af66fc99e Initial load
duke
parents:
diff changeset
678 //if( rm._flags ) rm_size += 1000000;
a61af66fc99e Initial load
duke
parents:
diff changeset
679 if( reg_degree >= rm_size ) return max_juint;
a61af66fc99e Initial load
duke
parents:
diff changeset
680 }
a61af66fc99e Initial load
duke
parents:
diff changeset
681 if( rm.overlap(lrgs(lidx).mask()) ) {
a61af66fc99e Initial load
duke
parents:
diff changeset
682 // Insert lidx into union LRG; returns TRUE if actually inserted
a61af66fc99e Initial load
duke
parents:
diff changeset
683 if( _ulr.insert(lidx) ) {
a61af66fc99e Initial load
duke
parents:
diff changeset
684 // Infinite-stack neighbors do not alter colorability, as they
a61af66fc99e Initial load
duke
parents:
diff changeset
685 // can always color to some other color.
a61af66fc99e Initial load
duke
parents:
diff changeset
686 if( !lrgs(lidx).mask().is_AllStack() ) {
a61af66fc99e Initial load
duke
parents:
diff changeset
687 // If this coalesce will make any new neighbor uncolorable,
a61af66fc99e Initial load
duke
parents:
diff changeset
688 // do not coalesce.
a61af66fc99e Initial load
duke
parents:
diff changeset
689 if( lrgs(lidx).just_lo_degree() )
a61af66fc99e Initial load
duke
parents:
diff changeset
690 return max_juint;
a61af66fc99e Initial load
duke
parents:
diff changeset
691 // Bump our degree
a61af66fc99e Initial load
duke
parents:
diff changeset
692 if( ++reg_degree >= rm_size )
a61af66fc99e Initial load
duke
parents:
diff changeset
693 return max_juint;
a61af66fc99e Initial load
duke
parents:
diff changeset
694 } // End of if not infinite-stack neighbor
a61af66fc99e Initial load
duke
parents:
diff changeset
695 } // End of if actually inserted
a61af66fc99e Initial load
duke
parents:
diff changeset
696 } // End of if live range overlaps
a61af66fc99e Initial load
duke
parents:
diff changeset
697 } // End of else collect intereferences for 1 node
a61af66fc99e Initial load
duke
parents:
diff changeset
698 } // End of while forever, scan back for intereferences
a61af66fc99e Initial load
duke
parents:
diff changeset
699 return reg_degree;
a61af66fc99e Initial load
duke
parents:
diff changeset
700 }
a61af66fc99e Initial load
duke
parents:
diff changeset
701
a61af66fc99e Initial load
duke
parents:
diff changeset
702 //------------------------------update_ifg-------------------------------------
a61af66fc99e Initial load
duke
parents:
diff changeset
703 void PhaseConservativeCoalesce::update_ifg(uint lr1, uint lr2, IndexSet *n_lr1, IndexSet *n_lr2) {
a61af66fc99e Initial load
duke
parents:
diff changeset
704 // Some original neighbors of lr1 might have gone away
a61af66fc99e Initial load
duke
parents:
diff changeset
705 // because the constrained register mask prevented them.
a61af66fc99e Initial load
duke
parents:
diff changeset
706 // Remove lr1 from such neighbors.
a61af66fc99e Initial load
duke
parents:
diff changeset
707 IndexSetIterator one(n_lr1);
a61af66fc99e Initial load
duke
parents:
diff changeset
708 uint neighbor;
a61af66fc99e Initial load
duke
parents:
diff changeset
709 LRG &lrg1 = lrgs(lr1);
a61af66fc99e Initial load
duke
parents:
diff changeset
710 while ((neighbor = one.next()) != 0)
a61af66fc99e Initial load
duke
parents:
diff changeset
711 if( !_ulr.member(neighbor) )
a61af66fc99e Initial load
duke
parents:
diff changeset
712 if( _phc._ifg->neighbors(neighbor)->remove(lr1) )
a61af66fc99e Initial load
duke
parents:
diff changeset
713 lrgs(neighbor).inc_degree( -lrg1.compute_degree(lrgs(neighbor)) );
a61af66fc99e Initial load
duke
parents:
diff changeset
714
a61af66fc99e Initial load
duke
parents:
diff changeset
715
a61af66fc99e Initial load
duke
parents:
diff changeset
716 // lr2 is now called (coalesced into) lr1.
a61af66fc99e Initial load
duke
parents:
diff changeset
717 // Remove lr2 from the IFG.
a61af66fc99e Initial load
duke
parents:
diff changeset
718 IndexSetIterator two(n_lr2);
a61af66fc99e Initial load
duke
parents:
diff changeset
719 LRG &lrg2 = lrgs(lr2);
a61af66fc99e Initial load
duke
parents:
diff changeset
720 while ((neighbor = two.next()) != 0)
a61af66fc99e Initial load
duke
parents:
diff changeset
721 if( _phc._ifg->neighbors(neighbor)->remove(lr2) )
a61af66fc99e Initial load
duke
parents:
diff changeset
722 lrgs(neighbor).inc_degree( -lrg2.compute_degree(lrgs(neighbor)) );
a61af66fc99e Initial load
duke
parents:
diff changeset
723
a61af66fc99e Initial load
duke
parents:
diff changeset
724 // Some neighbors of intermediate copies now interfere with the
a61af66fc99e Initial load
duke
parents:
diff changeset
725 // combined live range.
a61af66fc99e Initial load
duke
parents:
diff changeset
726 IndexSetIterator three(&_ulr);
a61af66fc99e Initial load
duke
parents:
diff changeset
727 while ((neighbor = three.next()) != 0)
a61af66fc99e Initial load
duke
parents:
diff changeset
728 if( _phc._ifg->neighbors(neighbor)->insert(lr1) )
a61af66fc99e Initial load
duke
parents:
diff changeset
729 lrgs(neighbor).inc_degree( lrg1.compute_degree(lrgs(neighbor)) );
a61af66fc99e Initial load
duke
parents:
diff changeset
730 }
a61af66fc99e Initial load
duke
parents:
diff changeset
731
a61af66fc99e Initial load
duke
parents:
diff changeset
732 //------------------------------record_bias------------------------------------
a61af66fc99e Initial load
duke
parents:
diff changeset
733 static void record_bias( const PhaseIFG *ifg, int lr1, int lr2 ) {
a61af66fc99e Initial load
duke
parents:
diff changeset
734 // Tag copy bias here
a61af66fc99e Initial load
duke
parents:
diff changeset
735 if( !ifg->lrgs(lr1)._copy_bias )
a61af66fc99e Initial load
duke
parents:
diff changeset
736 ifg->lrgs(lr1)._copy_bias = lr2;
a61af66fc99e Initial load
duke
parents:
diff changeset
737 if( !ifg->lrgs(lr2)._copy_bias )
a61af66fc99e Initial load
duke
parents:
diff changeset
738 ifg->lrgs(lr2)._copy_bias = lr1;
a61af66fc99e Initial load
duke
parents:
diff changeset
739 }
a61af66fc99e Initial load
duke
parents:
diff changeset
740
a61af66fc99e Initial load
duke
parents:
diff changeset
741 //------------------------------copy_copy--------------------------------------
a61af66fc99e Initial load
duke
parents:
diff changeset
742 // See if I can coalesce a series of multiple copies together. I need the
a61af66fc99e Initial load
duke
parents:
diff changeset
743 // final dest copy and the original src copy. They can be the same Node.
a61af66fc99e Initial load
duke
parents:
diff changeset
744 // Compute the compatible register masks.
a61af66fc99e Initial load
duke
parents:
diff changeset
745 bool PhaseConservativeCoalesce::copy_copy( Node *dst_copy, Node *src_copy, Block *b, uint bindex ) {
a61af66fc99e Initial load
duke
parents:
diff changeset
746
a61af66fc99e Initial load
duke
parents:
diff changeset
747 if( !dst_copy->is_SpillCopy() ) return false;
a61af66fc99e Initial load
duke
parents:
diff changeset
748 if( !src_copy->is_SpillCopy() ) return false;
a61af66fc99e Initial load
duke
parents:
diff changeset
749 Node *src_def = src_copy->in(src_copy->is_Copy());
a61af66fc99e Initial load
duke
parents:
diff changeset
750 uint lr1 = _phc.Find(dst_copy);
a61af66fc99e Initial load
duke
parents:
diff changeset
751 uint lr2 = _phc.Find(src_def );
a61af66fc99e Initial load
duke
parents:
diff changeset
752
a61af66fc99e Initial load
duke
parents:
diff changeset
753 // Same live ranges already?
a61af66fc99e Initial load
duke
parents:
diff changeset
754 if( lr1 == lr2 ) return false;
a61af66fc99e Initial load
duke
parents:
diff changeset
755
a61af66fc99e Initial load
duke
parents:
diff changeset
756 // Interfere?
a61af66fc99e Initial load
duke
parents:
diff changeset
757 if( _phc._ifg->test_edge_sq( lr1, lr2 ) ) return false;
a61af66fc99e Initial load
duke
parents:
diff changeset
758
a61af66fc99e Initial load
duke
parents:
diff changeset
759 // Not an oop->int cast; oop->oop, int->int, AND int->oop are OK.
a61af66fc99e Initial load
duke
parents:
diff changeset
760 if( !lrgs(lr1)._is_oop && lrgs(lr2)._is_oop ) // not an oop->int cast
a61af66fc99e Initial load
duke
parents:
diff changeset
761 return false;
a61af66fc99e Initial load
duke
parents:
diff changeset
762
a61af66fc99e Initial load
duke
parents:
diff changeset
763 // Coalescing between an aligned live range and a mis-aligned live range?
a61af66fc99e Initial load
duke
parents:
diff changeset
764 // No, no! Alignment changes how we count degree.
a61af66fc99e Initial load
duke
parents:
diff changeset
765 if( lrgs(lr1)._fat_proj != lrgs(lr2)._fat_proj )
a61af66fc99e Initial load
duke
parents:
diff changeset
766 return false;
a61af66fc99e Initial load
duke
parents:
diff changeset
767
a61af66fc99e Initial load
duke
parents:
diff changeset
768 // Sort; use smaller live-range number
a61af66fc99e Initial load
duke
parents:
diff changeset
769 Node *lr1_node = dst_copy;
a61af66fc99e Initial load
duke
parents:
diff changeset
770 Node *lr2_node = src_def;
a61af66fc99e Initial load
duke
parents:
diff changeset
771 if( lr1 > lr2 ) {
a61af66fc99e Initial load
duke
parents:
diff changeset
772 uint tmp = lr1; lr1 = lr2; lr2 = tmp;
a61af66fc99e Initial load
duke
parents:
diff changeset
773 lr1_node = src_def; lr2_node = dst_copy;
a61af66fc99e Initial load
duke
parents:
diff changeset
774 }
a61af66fc99e Initial load
duke
parents:
diff changeset
775
a61af66fc99e Initial load
duke
parents:
diff changeset
776 // Check for compatibility of the 2 live ranges by
a61af66fc99e Initial load
duke
parents:
diff changeset
777 // intersecting their allowed register sets.
a61af66fc99e Initial load
duke
parents:
diff changeset
778 RegMask rm = lrgs(lr1).mask();
a61af66fc99e Initial load
duke
parents:
diff changeset
779 rm.AND(lrgs(lr2).mask());
a61af66fc99e Initial load
duke
parents:
diff changeset
780 // Number of bits free
a61af66fc99e Initial load
duke
parents:
diff changeset
781 uint rm_size = rm.Size();
a61af66fc99e Initial load
duke
parents:
diff changeset
782
a61af66fc99e Initial load
duke
parents:
diff changeset
783 // If we can use any stack slot, then effective size is infinite
a61af66fc99e Initial load
duke
parents:
diff changeset
784 if( rm.is_AllStack() ) rm_size += 1000000;
a61af66fc99e Initial load
duke
parents:
diff changeset
785 // Incompatible masks, no way to coalesce
a61af66fc99e Initial load
duke
parents:
diff changeset
786 if( rm_size == 0 ) return false;
a61af66fc99e Initial load
duke
parents:
diff changeset
787
a61af66fc99e Initial load
duke
parents:
diff changeset
788 // Another early bail-out test is when we are double-coalescing and the
a61af66fc99e Initial load
duke
parents:
diff changeset
789 // 2 copies are seperated by some control flow.
a61af66fc99e Initial load
duke
parents:
diff changeset
790 if( dst_copy != src_copy ) {
a61af66fc99e Initial load
duke
parents:
diff changeset
791 Block *src_b = _phc._cfg._bbs[src_copy->_idx];
a61af66fc99e Initial load
duke
parents:
diff changeset
792 Block *b2 = b;
a61af66fc99e Initial load
duke
parents:
diff changeset
793 while( b2 != src_b ) {
a61af66fc99e Initial load
duke
parents:
diff changeset
794 if( b2->num_preds() > 2 ){// Found merge-point
a61af66fc99e Initial load
duke
parents:
diff changeset
795 _phc._lost_opp_cflow_coalesce++;
a61af66fc99e Initial load
duke
parents:
diff changeset
796 // extra record_bias commented out because Chris believes it is not
a61af66fc99e Initial load
duke
parents:
diff changeset
797 // productive. Since we can record only 1 bias, we want to choose one
a61af66fc99e Initial load
duke
parents:
diff changeset
798 // that stands a chance of working and this one probably does not.
a61af66fc99e Initial load
duke
parents:
diff changeset
799 //record_bias( _phc._lrgs, lr1, lr2 );
a61af66fc99e Initial load
duke
parents:
diff changeset
800 return false; // To hard to find all interferences
a61af66fc99e Initial load
duke
parents:
diff changeset
801 }
a61af66fc99e Initial load
duke
parents:
diff changeset
802 b2 = _phc._cfg._bbs[b2->pred(1)->_idx];
a61af66fc99e Initial load
duke
parents:
diff changeset
803 }
a61af66fc99e Initial load
duke
parents:
diff changeset
804 }
a61af66fc99e Initial load
duke
parents:
diff changeset
805
a61af66fc99e Initial load
duke
parents:
diff changeset
806 // Union the two interference sets together into '_ulr'
a61af66fc99e Initial load
duke
parents:
diff changeset
807 uint reg_degree = _ulr.lrg_union( lr1, lr2, rm_size, _phc._ifg, rm );
a61af66fc99e Initial load
duke
parents:
diff changeset
808
a61af66fc99e Initial load
duke
parents:
diff changeset
809 if( reg_degree >= rm_size ) {
a61af66fc99e Initial load
duke
parents:
diff changeset
810 record_bias( _phc._ifg, lr1, lr2 );
a61af66fc99e Initial load
duke
parents:
diff changeset
811 return false;
a61af66fc99e Initial load
duke
parents:
diff changeset
812 }
a61af66fc99e Initial load
duke
parents:
diff changeset
813
a61af66fc99e Initial load
duke
parents:
diff changeset
814 // Now I need to compute all the interferences between dst_copy and
a61af66fc99e Initial load
duke
parents:
diff changeset
815 // src_copy. I'm not willing visit the entire interference graph, so
a61af66fc99e Initial load
duke
parents:
diff changeset
816 // I limit my search to things in dst_copy's block or in a straight
a61af66fc99e Initial load
duke
parents:
diff changeset
817 // line of previous blocks. I give up at merge points or when I get
a61af66fc99e Initial load
duke
parents:
diff changeset
818 // more interferences than my degree. I can stop when I find src_copy.
a61af66fc99e Initial load
duke
parents:
diff changeset
819 if( dst_copy != src_copy ) {
a61af66fc99e Initial load
duke
parents:
diff changeset
820 reg_degree = compute_separating_interferences(dst_copy, src_copy, b, bindex, rm, rm_size, reg_degree, lr1, lr2 );
a61af66fc99e Initial load
duke
parents:
diff changeset
821 if( reg_degree == max_juint ) {
a61af66fc99e Initial load
duke
parents:
diff changeset
822 record_bias( _phc._ifg, lr1, lr2 );
a61af66fc99e Initial load
duke
parents:
diff changeset
823 return false;
a61af66fc99e Initial load
duke
parents:
diff changeset
824 }
a61af66fc99e Initial load
duke
parents:
diff changeset
825 } // End of if dst_copy & src_copy are different
a61af66fc99e Initial load
duke
parents:
diff changeset
826
a61af66fc99e Initial load
duke
parents:
diff changeset
827
a61af66fc99e Initial load
duke
parents:
diff changeset
828 // ---- THE COMBINED LRG IS COLORABLE ----
a61af66fc99e Initial load
duke
parents:
diff changeset
829
a61af66fc99e Initial load
duke
parents:
diff changeset
830 // YEAH - Now coalesce this copy away
a61af66fc99e Initial load
duke
parents:
diff changeset
831 assert( lrgs(lr1).num_regs() == lrgs(lr2).num_regs(), "" );
a61af66fc99e Initial load
duke
parents:
diff changeset
832
a61af66fc99e Initial load
duke
parents:
diff changeset
833 IndexSet *n_lr1 = _phc._ifg->neighbors(lr1);
a61af66fc99e Initial load
duke
parents:
diff changeset
834 IndexSet *n_lr2 = _phc._ifg->neighbors(lr2);
a61af66fc99e Initial load
duke
parents:
diff changeset
835
a61af66fc99e Initial load
duke
parents:
diff changeset
836 // Update the interference graph
a61af66fc99e Initial load
duke
parents:
diff changeset
837 update_ifg(lr1, lr2, n_lr1, n_lr2);
a61af66fc99e Initial load
duke
parents:
diff changeset
838
a61af66fc99e Initial load
duke
parents:
diff changeset
839 _ulr.remove(lr1);
a61af66fc99e Initial load
duke
parents:
diff changeset
840
a61af66fc99e Initial load
duke
parents:
diff changeset
841 // Uncomment the following code to trace Coalescing in great detail.
a61af66fc99e Initial load
duke
parents:
diff changeset
842 //
a61af66fc99e Initial load
duke
parents:
diff changeset
843 //if (false) {
a61af66fc99e Initial load
duke
parents:
diff changeset
844 // tty->cr();
a61af66fc99e Initial load
duke
parents:
diff changeset
845 // tty->print_cr("#######################################");
a61af66fc99e Initial load
duke
parents:
diff changeset
846 // tty->print_cr("union %d and %d", lr1, lr2);
a61af66fc99e Initial load
duke
parents:
diff changeset
847 // n_lr1->dump();
a61af66fc99e Initial load
duke
parents:
diff changeset
848 // n_lr2->dump();
a61af66fc99e Initial load
duke
parents:
diff changeset
849 // tty->print_cr("resulting set is");
a61af66fc99e Initial load
duke
parents:
diff changeset
850 // _ulr.dump();
a61af66fc99e Initial load
duke
parents:
diff changeset
851 //}
a61af66fc99e Initial load
duke
parents:
diff changeset
852
a61af66fc99e Initial load
duke
parents:
diff changeset
853 // Replace n_lr1 with the new combined live range. _ulr will use
a61af66fc99e Initial load
duke
parents:
diff changeset
854 // n_lr1's old memory on the next iteration. n_lr2 is cleared to
a61af66fc99e Initial load
duke
parents:
diff changeset
855 // send its internal memory to the free list.
a61af66fc99e Initial load
duke
parents:
diff changeset
856 _ulr.swap(n_lr1);
a61af66fc99e Initial load
duke
parents:
diff changeset
857 _ulr.clear();
a61af66fc99e Initial load
duke
parents:
diff changeset
858 n_lr2->clear();
a61af66fc99e Initial load
duke
parents:
diff changeset
859
a61af66fc99e Initial load
duke
parents:
diff changeset
860 lrgs(lr1).set_degree( _phc._ifg->effective_degree(lr1) );
a61af66fc99e Initial load
duke
parents:
diff changeset
861 lrgs(lr2).set_degree( 0 );
a61af66fc99e Initial load
duke
parents:
diff changeset
862
a61af66fc99e Initial load
duke
parents:
diff changeset
863 // Join live ranges. Merge larger into smaller. Union lr2 into lr1 in the
a61af66fc99e Initial load
duke
parents:
diff changeset
864 // union-find tree
a61af66fc99e Initial load
duke
parents:
diff changeset
865 union_helper( lr1_node, lr2_node, lr1, lr2, src_def, dst_copy, src_copy, b, bindex );
a61af66fc99e Initial load
duke
parents:
diff changeset
866 // Combine register restrictions
a61af66fc99e Initial load
duke
parents:
diff changeset
867 lrgs(lr1).set_mask(rm);
a61af66fc99e Initial load
duke
parents:
diff changeset
868 lrgs(lr1).compute_set_mask_size();
a61af66fc99e Initial load
duke
parents:
diff changeset
869 lrgs(lr1)._cost += lrgs(lr2)._cost;
a61af66fc99e Initial load
duke
parents:
diff changeset
870 lrgs(lr1)._area += lrgs(lr2)._area;
a61af66fc99e Initial load
duke
parents:
diff changeset
871
a61af66fc99e Initial load
duke
parents:
diff changeset
872 // While its uncommon to successfully coalesce live ranges that started out
a61af66fc99e Initial load
duke
parents:
diff changeset
873 // being not-lo-degree, it can happen. In any case the combined coalesced
a61af66fc99e Initial load
duke
parents:
diff changeset
874 // live range better Simplify nicely.
a61af66fc99e Initial load
duke
parents:
diff changeset
875 lrgs(lr1)._was_lo = 1;
a61af66fc99e Initial load
duke
parents:
diff changeset
876
a61af66fc99e Initial load
duke
parents:
diff changeset
877 // kinda expensive to do all the time
a61af66fc99e Initial load
duke
parents:
diff changeset
878 //tty->print_cr("warning: slow verify happening");
a61af66fc99e Initial load
duke
parents:
diff changeset
879 //_phc._ifg->verify( &_phc );
a61af66fc99e Initial load
duke
parents:
diff changeset
880 return true;
a61af66fc99e Initial load
duke
parents:
diff changeset
881 }
a61af66fc99e Initial load
duke
parents:
diff changeset
882
a61af66fc99e Initial load
duke
parents:
diff changeset
883 //------------------------------coalesce---------------------------------------
a61af66fc99e Initial load
duke
parents:
diff changeset
884 // Conservative (but pessimistic) copy coalescing of a single block
a61af66fc99e Initial load
duke
parents:
diff changeset
885 void PhaseConservativeCoalesce::coalesce( Block *b ) {
a61af66fc99e Initial load
duke
parents:
diff changeset
886 // Bail out on infrequent blocks
a61af66fc99e Initial load
duke
parents:
diff changeset
887 if( b->is_uncommon(_phc._cfg._bbs) )
a61af66fc99e Initial load
duke
parents:
diff changeset
888 return;
a61af66fc99e Initial load
duke
parents:
diff changeset
889 // Check this block for copies.
a61af66fc99e Initial load
duke
parents:
diff changeset
890 for( uint i = 1; i<b->end_idx(); i++ ) {
a61af66fc99e Initial load
duke
parents:
diff changeset
891 // Check for actual copies on inputs. Coalesce a copy into its
a61af66fc99e Initial load
duke
parents:
diff changeset
892 // input if use and copy's input are compatible.
a61af66fc99e Initial load
duke
parents:
diff changeset
893 Node *copy1 = b->_nodes[i];
a61af66fc99e Initial load
duke
parents:
diff changeset
894 uint idx1 = copy1->is_Copy();
a61af66fc99e Initial load
duke
parents:
diff changeset
895 if( !idx1 ) continue; // Not a copy
a61af66fc99e Initial load
duke
parents:
diff changeset
896
a61af66fc99e Initial load
duke
parents:
diff changeset
897 if( copy_copy(copy1,copy1,b,i) ) {
a61af66fc99e Initial load
duke
parents:
diff changeset
898 i--; // Retry, same location in block
a61af66fc99e Initial load
duke
parents:
diff changeset
899 PhaseChaitin::_conserv_coalesce++; // Collect stats on success
a61af66fc99e Initial load
duke
parents:
diff changeset
900 continue;
a61af66fc99e Initial load
duke
parents:
diff changeset
901 }
a61af66fc99e Initial load
duke
parents:
diff changeset
902
a61af66fc99e Initial load
duke
parents:
diff changeset
903 /* do not attempt pairs. About 1/2 of all pairs can be removed by
a61af66fc99e Initial load
duke
parents:
diff changeset
904 post-alloc. The other set are too few to bother.
a61af66fc99e Initial load
duke
parents:
diff changeset
905 Node *copy2 = copy1->in(idx1);
a61af66fc99e Initial load
duke
parents:
diff changeset
906 uint idx2 = copy2->is_Copy();
a61af66fc99e Initial load
duke
parents:
diff changeset
907 if( !idx2 ) continue;
a61af66fc99e Initial load
duke
parents:
diff changeset
908 if( copy_copy(copy1,copy2,b,i) ) {
a61af66fc99e Initial load
duke
parents:
diff changeset
909 i--; // Retry, same location in block
a61af66fc99e Initial load
duke
parents:
diff changeset
910 PhaseChaitin::_conserv_coalesce_pair++; // Collect stats on success
a61af66fc99e Initial load
duke
parents:
diff changeset
911 continue;
a61af66fc99e Initial load
duke
parents:
diff changeset
912 }
a61af66fc99e Initial load
duke
parents:
diff changeset
913 */
a61af66fc99e Initial load
duke
parents:
diff changeset
914 }
a61af66fc99e Initial load
duke
parents:
diff changeset
915 }