Mercurial > hg > truffle
annotate src/share/vm/opto/superword.hpp @ 4710:41406797186b
7113012: G1: rename not-fully-young GCs as "mixed"
Summary: Renamed partially-young GCs as mixed and fully-young GCs as young. Change all external output that includes those terms (GC log and GC ergo log) as well as any comments, fields, methods, etc. The changeset also includes very minor code tidying up (added some curly brackets).
Reviewed-by: johnc, brutisso
author | tonyp |
---|---|
date | Fri, 16 Dec 2011 02:14:27 -0500 |
parents | c7b60b601eb4 |
children | 8c92982cbbc4 |
rev | line source |
---|---|
0 | 1 /* |
1972 | 2 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. |
0 | 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
4 * | |
5 * This code is free software; you can redistribute it and/or modify it | |
6 * under the terms of the GNU General Public License version 2 only, as | |
7 * published by the Free Software Foundation. | |
8 * | |
9 * This code is distributed in the hope that it will be useful, but WITHOUT | |
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
12 * version 2 for more details (a copy is included in the LICENSE file that | |
13 * accompanied this code). | |
14 * | |
15 * You should have received a copy of the GNU General Public License version | |
16 * 2 along with this work; if not, write to the Free Software Foundation, | |
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
18 * | |
1552
c18cbe5936b8
6941466: Oracle rebranding changes for Hotspot repositories
trims
parents:
844
diff
changeset
|
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
c18cbe5936b8
6941466: Oracle rebranding changes for Hotspot repositories
trims
parents:
844
diff
changeset
|
20 * or visit www.oracle.com if you need additional information or have any |
c18cbe5936b8
6941466: Oracle rebranding changes for Hotspot repositories
trims
parents:
844
diff
changeset
|
21 * questions. |
0 | 22 */ |
23 | |
1972 | 24 #ifndef SHARE_VM_OPTO_SUPERWORD_HPP |
25 #define SHARE_VM_OPTO_SUPERWORD_HPP | |
26 | |
27 #include "opto/connode.hpp" | |
28 #include "opto/loopnode.hpp" | |
29 #include "opto/node.hpp" | |
30 #include "opto/phaseX.hpp" | |
31 #include "opto/vectornode.hpp" | |
32 #include "utilities/growableArray.hpp" | |
33 | |
0 | 34 // |
35 // S U P E R W O R D T R A N S F O R M | |
36 // | |
37 // SuperWords are short, fixed length vectors. | |
38 // | |
39 // Algorithm from: | |
40 // | |
41 // Exploiting SuperWord Level Parallelism with | |
42 // Multimedia Instruction Sets | |
43 // by | |
44 // Samuel Larsen and Saman Amarasighe | |
45 // MIT Laboratory for Computer Science | |
46 // date | |
47 // May 2000 | |
48 // published in | |
49 // ACM SIGPLAN Notices | |
50 // Proceedings of ACM PLDI '00, Volume 35 Issue 5 | |
51 // | |
52 // Definition 3.1 A Pack is an n-tuple, <s1, ...,sn>, where | |
53 // s1,...,sn are independent isomorphic statements in a basic | |
54 // block. | |
55 // | |
56 // Definition 3.2 A PackSet is a set of Packs. | |
57 // | |
58 // Definition 3.3 A Pair is a Pack of size two, where the | |
59 // first statement is considered the left element, and the | |
60 // second statement is considered the right element. | |
61 | |
62 class SWPointer; | |
63 class OrderedPair; | |
64 | |
65 // ========================= Dependence Graph ===================== | |
66 | |
67 class DepMem; | |
68 | |
69 //------------------------------DepEdge--------------------------- | |
70 // An edge in the dependence graph. The edges incident to a dependence | |
71 // node are threaded through _next_in for incoming edges and _next_out | |
72 // for outgoing edges. | |
73 class DepEdge : public ResourceObj { | |
74 protected: | |
75 DepMem* _pred; | |
76 DepMem* _succ; | |
77 DepEdge* _next_in; // list of in edges, null terminated | |
78 DepEdge* _next_out; // list of out edges, null terminated | |
79 | |
80 public: | |
81 DepEdge(DepMem* pred, DepMem* succ, DepEdge* next_in, DepEdge* next_out) : | |
82 _pred(pred), _succ(succ), _next_in(next_in), _next_out(next_out) {} | |
83 | |
84 DepEdge* next_in() { return _next_in; } | |
85 DepEdge* next_out() { return _next_out; } | |
86 DepMem* pred() { return _pred; } | |
87 DepMem* succ() { return _succ; } | |
88 | |
89 void print(); | |
90 }; | |
91 | |
92 //------------------------------DepMem--------------------------- | |
93 // A node in the dependence graph. _in_head starts the threaded list of | |
94 // incoming edges, and _out_head starts the list of outgoing edges. | |
95 class DepMem : public ResourceObj { | |
96 protected: | |
97 Node* _node; // Corresponding ideal node | |
98 DepEdge* _in_head; // Head of list of in edges, null terminated | |
99 DepEdge* _out_head; // Head of list of out edges, null terminated | |
100 | |
101 public: | |
102 DepMem(Node* node) : _node(node), _in_head(NULL), _out_head(NULL) {} | |
103 | |
104 Node* node() { return _node; } | |
105 DepEdge* in_head() { return _in_head; } | |
106 DepEdge* out_head() { return _out_head; } | |
107 void set_in_head(DepEdge* hd) { _in_head = hd; } | |
108 void set_out_head(DepEdge* hd) { _out_head = hd; } | |
109 | |
110 int in_cnt(); // Incoming edge count | |
111 int out_cnt(); // Outgoing edge count | |
112 | |
113 void print(); | |
114 }; | |
115 | |
116 //------------------------------DepGraph--------------------------- | |
117 class DepGraph VALUE_OBJ_CLASS_SPEC { | |
118 protected: | |
119 Arena* _arena; | |
120 GrowableArray<DepMem*> _map; | |
121 DepMem* _root; | |
122 DepMem* _tail; | |
123 | |
124 public: | |
125 DepGraph(Arena* a) : _arena(a), _map(a, 8, 0, NULL) { | |
126 _root = new (_arena) DepMem(NULL); | |
127 _tail = new (_arena) DepMem(NULL); | |
128 } | |
129 | |
130 DepMem* root() { return _root; } | |
131 DepMem* tail() { return _tail; } | |
132 | |
133 // Return dependence node corresponding to an ideal node | |
134 DepMem* dep(Node* node) { return _map.at(node->_idx); } | |
135 | |
136 // Make a new dependence graph node for an ideal node. | |
137 DepMem* make_node(Node* node); | |
138 | |
139 // Make a new dependence graph edge dprec->dsucc | |
140 DepEdge* make_edge(DepMem* dpred, DepMem* dsucc); | |
141 | |
142 DepEdge* make_edge(Node* pred, Node* succ) { return make_edge(dep(pred), dep(succ)); } | |
143 DepEdge* make_edge(DepMem* pred, Node* succ) { return make_edge(pred, dep(succ)); } | |
144 DepEdge* make_edge(Node* pred, DepMem* succ) { return make_edge(dep(pred), succ); } | |
145 | |
146 void init() { _map.clear(); } // initialize | |
147 | |
148 void print(Node* n) { dep(n)->print(); } | |
149 void print(DepMem* d) { d->print(); } | |
150 }; | |
151 | |
152 //------------------------------DepPreds--------------------------- | |
153 // Iterator over predecessors in the dependence graph and | |
154 // non-memory-graph inputs of ideal nodes. | |
155 class DepPreds : public StackObj { | |
156 private: | |
157 Node* _n; | |
158 int _next_idx, _end_idx; | |
159 DepEdge* _dep_next; | |
160 Node* _current; | |
161 bool _done; | |
162 | |
163 public: | |
164 DepPreds(Node* n, DepGraph& dg); | |
165 Node* current() { return _current; } | |
166 bool done() { return _done; } | |
167 void next(); | |
168 }; | |
169 | |
170 //------------------------------DepSuccs--------------------------- | |
171 // Iterator over successors in the dependence graph and | |
172 // non-memory-graph outputs of ideal nodes. | |
173 class DepSuccs : public StackObj { | |
174 private: | |
175 Node* _n; | |
176 int _next_idx, _end_idx; | |
177 DepEdge* _dep_next; | |
178 Node* _current; | |
179 bool _done; | |
180 | |
181 public: | |
182 DepSuccs(Node* n, DepGraph& dg); | |
183 Node* current() { return _current; } | |
184 bool done() { return _done; } | |
185 void next(); | |
186 }; | |
187 | |
188 | |
189 // ========================= SuperWord ===================== | |
190 | |
191 // -----------------------------SWNodeInfo--------------------------------- | |
192 // Per node info needed by SuperWord | |
193 class SWNodeInfo VALUE_OBJ_CLASS_SPEC { | |
194 public: | |
195 int _alignment; // memory alignment for a node | |
196 int _depth; // Max expression (DAG) depth from block start | |
197 const Type* _velt_type; // vector element type | |
198 Node_List* _my_pack; // pack containing this node | |
199 | |
200 SWNodeInfo() : _alignment(-1), _depth(0), _velt_type(NULL), _my_pack(NULL) {} | |
201 static const SWNodeInfo initial; | |
202 }; | |
203 | |
204 // -----------------------------SuperWord--------------------------------- | |
205 // Transforms scalar operations into packed (superword) operations. | |
206 class SuperWord : public ResourceObj { | |
207 private: | |
208 PhaseIdealLoop* _phase; | |
209 Arena* _arena; | |
210 PhaseIterGVN &_igvn; | |
211 | |
212 enum consts { top_align = -1, bottom_align = -666 }; | |
213 | |
214 GrowableArray<Node_List*> _packset; // Packs for the current block | |
215 | |
216 GrowableArray<int> _bb_idx; // Map from Node _idx to index within block | |
217 | |
218 GrowableArray<Node*> _block; // Nodes in current block | |
219 GrowableArray<Node*> _data_entry; // Nodes with all inputs from outside | |
220 GrowableArray<Node*> _mem_slice_head; // Memory slice head nodes | |
221 GrowableArray<Node*> _mem_slice_tail; // Memory slice tail nodes | |
222 | |
223 GrowableArray<SWNodeInfo> _node_info; // Info needed per node | |
224 | |
225 MemNode* _align_to_ref; // Memory reference that pre-loop will align to | |
226 | |
227 GrowableArray<OrderedPair> _disjoint_ptrs; // runtime disambiguated pointer pairs | |
228 | |
229 DepGraph _dg; // Dependence graph | |
230 | |
231 // Scratch pads | |
232 VectorSet _visited; // Visited set | |
233 VectorSet _post_visited; // Post-visited set | |
234 Node_Stack _n_idx_list; // List of (node,index) pairs | |
235 GrowableArray<Node*> _nlist; // List of nodes | |
236 GrowableArray<Node*> _stk; // Stack of nodes | |
237 | |
238 public: | |
239 SuperWord(PhaseIdealLoop* phase); | |
240 | |
241 void transform_loop(IdealLoopTree* lpt); | |
242 | |
243 // Accessors for SWPointer | |
244 PhaseIdealLoop* phase() { return _phase; } | |
245 IdealLoopTree* lpt() { return _lpt; } | |
246 PhiNode* iv() { return _iv; } | |
247 | |
248 private: | |
249 IdealLoopTree* _lpt; // Current loop tree node | |
250 LoopNode* _lp; // Current LoopNode | |
251 Node* _bb; // Current basic block | |
252 PhiNode* _iv; // Induction var | |
253 | |
254 // Accessors | |
255 Arena* arena() { return _arena; } | |
256 | |
257 Node* bb() { return _bb; } | |
258 void set_bb(Node* bb) { _bb = bb; } | |
259 | |
260 void set_lpt(IdealLoopTree* lpt) { _lpt = lpt; } | |
261 | |
262 LoopNode* lp() { return _lp; } | |
263 void set_lp(LoopNode* lp) { _lp = lp; | |
264 _iv = lp->as_CountedLoop()->phi()->as_Phi(); } | |
265 int iv_stride() { return lp()->as_CountedLoop()->stride_con(); } | |
266 | |
267 int vector_width_in_bytes() { return Matcher::vector_width_in_bytes(); } | |
268 | |
269 MemNode* align_to_ref() { return _align_to_ref; } | |
270 void set_align_to_ref(MemNode* m) { _align_to_ref = m; } | |
271 | |
272 Node* ctrl(Node* n) const { return _phase->has_ctrl(n) ? _phase->get_ctrl(n) : n; } | |
273 | |
274 // block accessors | |
275 bool in_bb(Node* n) { return n != NULL && n->outcnt() > 0 && ctrl(n) == _bb; } | |
276 int bb_idx(Node* n) { assert(in_bb(n), "must be"); return _bb_idx.at(n->_idx); } | |
277 void set_bb_idx(Node* n, int i) { _bb_idx.at_put_grow(n->_idx, i); } | |
278 | |
279 // visited set accessors | |
280 void visited_clear() { _visited.Clear(); } | |
281 void visited_set(Node* n) { return _visited.set(bb_idx(n)); } | |
282 int visited_test(Node* n) { return _visited.test(bb_idx(n)); } | |
283 int visited_test_set(Node* n) { return _visited.test_set(bb_idx(n)); } | |
284 void post_visited_clear() { _post_visited.Clear(); } | |
285 void post_visited_set(Node* n) { return _post_visited.set(bb_idx(n)); } | |
286 int post_visited_test(Node* n) { return _post_visited.test(bb_idx(n)); } | |
287 | |
288 // Ensure node_info contains element "i" | |
289 void grow_node_info(int i) { if (i >= _node_info.length()) _node_info.at_put_grow(i, SWNodeInfo::initial); } | |
290 | |
291 // memory alignment for a node | |
292 int alignment(Node* n) { return _node_info.adr_at(bb_idx(n))->_alignment; } | |
293 void set_alignment(Node* n, int a) { int i = bb_idx(n); grow_node_info(i); _node_info.adr_at(i)->_alignment = a; } | |
294 | |
295 // Max expression (DAG) depth from beginning of the block for each node | |
296 int depth(Node* n) { return _node_info.adr_at(bb_idx(n))->_depth; } | |
297 void set_depth(Node* n, int d) { int i = bb_idx(n); grow_node_info(i); _node_info.adr_at(i)->_depth = d; } | |
298 | |
299 // vector element type | |
300 const Type* velt_type(Node* n) { return _node_info.adr_at(bb_idx(n))->_velt_type; } | |
301 void set_velt_type(Node* n, const Type* t) { int i = bb_idx(n); grow_node_info(i); _node_info.adr_at(i)->_velt_type = t; } | |
302 | |
303 // my_pack | |
304 Node_List* my_pack(Node* n) { return !in_bb(n) ? NULL : _node_info.adr_at(bb_idx(n))->_my_pack; } | |
305 void set_my_pack(Node* n, Node_List* p) { int i = bb_idx(n); grow_node_info(i); _node_info.adr_at(i)->_my_pack = p; } | |
306 | |
307 // methods | |
308 | |
309 // Extract the superword level parallelism | |
310 void SLP_extract(); | |
311 // Find the adjacent memory references and create pack pairs for them. | |
312 void find_adjacent_refs(); | |
313 // Find a memory reference to align the loop induction variable to. | |
314 void find_align_to_ref(Node_List &memops); | |
315 // Can the preloop align the reference to position zero in the vector? | |
316 bool ref_is_alignable(SWPointer& p); | |
317 // Construct dependency graph. | |
318 void dependence_graph(); | |
319 // Return a memory slice (node list) in predecessor order starting at "start" | |
320 void mem_slice_preds(Node* start, Node* stop, GrowableArray<Node*> &preds); | |
605 | 321 // Can s1 and s2 be in a pack with s1 immediately preceding s2 and s1 aligned at "align" |
0 | 322 bool stmts_can_pack(Node* s1, Node* s2, int align); |
323 // Does s exist in a pack at position pos? | |
324 bool exists_at(Node* s, uint pos); | |
325 // Is s1 immediately before s2 in memory? | |
326 bool are_adjacent_refs(Node* s1, Node* s2); | |
327 // Are s1 and s2 similar? | |
328 bool isomorphic(Node* s1, Node* s2); | |
329 // Is there no data path from s1 to s2 or s2 to s1? | |
330 bool independent(Node* s1, Node* s2); | |
331 // Helper for independent | |
332 bool independent_path(Node* shallow, Node* deep, uint dp=0); | |
333 void set_alignment(Node* s1, Node* s2, int align); | |
334 int data_size(Node* s); | |
335 // Extend packset by following use->def and def->use links from pack members. | |
336 void extend_packlist(); | |
337 // Extend the packset by visiting operand definitions of nodes in pack p | |
338 bool follow_use_defs(Node_List* p); | |
339 // Extend the packset by visiting uses of nodes in pack p | |
340 bool follow_def_uses(Node_List* p); | |
341 // Estimate the savings from executing s1 and s2 as a pack | |
342 int est_savings(Node* s1, Node* s2); | |
343 int adjacent_profit(Node* s1, Node* s2); | |
344 int pack_cost(int ct); | |
345 int unpack_cost(int ct); | |
346 // Combine packs A and B with A.last == B.first into A.first..,A.last,B.second,..B.last | |
347 void combine_packs(); | |
348 // Construct the map from nodes to packs. | |
349 void construct_my_pack_map(); | |
350 // Remove packs that are not implemented or not profitable. | |
351 void filter_packs(); | |
352 // Adjust the memory graph for the packed operations | |
353 void schedule(); | |
667 | 354 // Remove "current" from its current position in the memory graph and insert |
355 // it after the appropriate insert points (lip or uip); | |
356 void remove_and_insert(MemNode *current, MemNode *prev, MemNode *lip, Node *uip, Unique_Node_List &schd_before); | |
357 // Within a store pack, schedule stores together by moving out the sandwiched memory ops according | |
358 // to dependence info; and within a load pack, move loads down to the last executed load. | |
0 | 359 void co_locate_pack(Node_List* p); |
360 // Convert packs into vector node operations | |
361 void output(); | |
362 // Create a vector operand for the nodes in pack p for operand: in(opd_idx) | |
3842 | 363 Node* vector_opd(Node_List* p, int opd_idx); |
0 | 364 // Can code be generated for pack p? |
365 bool implemented(Node_List* p); | |
366 // For pack p, are all operands and all uses (with in the block) vector? | |
367 bool profitable(Node_List* p); | |
368 // If a use of pack p is not a vector use, then replace the use with an extract operation. | |
369 void insert_extracts(Node_List* p); | |
370 // Is use->in(u_idx) a vector use? | |
371 bool is_vector_use(Node* use, int u_idx); | |
372 // Construct reverse postorder list of block members | |
373 void construct_bb(); | |
374 // Initialize per node info | |
375 void initialize_bb(); | |
376 // Insert n into block after pos | |
377 void bb_insert_after(Node* n, int pos); | |
378 // Compute max depth for expressions from beginning of block | |
379 void compute_max_depth(); | |
380 // Compute necessary vector element type for expressions | |
381 void compute_vector_element_type(); | |
382 // Are s1 and s2 in a pack pair and ordered as s1,s2? | |
383 bool in_packset(Node* s1, Node* s2); | |
384 // Is s in pack p? | |
385 Node_List* in_pack(Node* s, Node_List* p); | |
386 // Remove the pack at position pos in the packset | |
387 void remove_pack_at(int pos); | |
388 // Return the node executed first in pack p. | |
389 Node* executed_first(Node_List* p); | |
390 // Return the node executed last in pack p. | |
391 Node* executed_last(Node_List* p); | |
392 // Alignment within a vector memory reference | |
393 int memory_alignment(MemNode* s, int iv_adjust_in_bytes); | |
394 // (Start, end] half-open range defining which operands are vector | |
395 void vector_opd_range(Node* n, uint* start, uint* end); | |
396 // Smallest type containing range of values | |
397 static const Type* container_type(const Type* t); | |
398 // Adjust pre-loop limit so that in main loop, a load/store reference | |
399 // to align_to_ref will be a position zero in the vector. | |
400 void align_initial_loop_index(MemNode* align_to_ref); | |
401 // Find pre loop end from main loop. Returns null if none. | |
402 CountedLoopEndNode* get_pre_loop_end(CountedLoopNode *cl); | |
403 // Is the use of d1 in u1 at the same operand position as d2 in u2? | |
404 bool opnd_positions_match(Node* d1, Node* u1, Node* d2, Node* u2); | |
405 void init(); | |
406 | |
407 // print methods | |
408 void print_packset(); | |
409 void print_pack(Node_List* p); | |
410 void print_bb(); | |
411 void print_stmt(Node* s); | |
412 char* blank(uint depth); | |
413 }; | |
414 | |
415 | |
416 //------------------------------SWPointer--------------------------- | |
417 // Information about an address for dependence checking and vector alignment | |
418 class SWPointer VALUE_OBJ_CLASS_SPEC { | |
419 protected: | |
420 MemNode* _mem; // My memory reference node | |
421 SuperWord* _slp; // SuperWord class | |
422 | |
423 Node* _base; // NULL if unsafe nonheap reference | |
424 Node* _adr; // address pointer | |
425 jint _scale; // multipler for iv (in bytes), 0 if no loop iv | |
426 jint _offset; // constant offset (in bytes) | |
427 Node* _invar; // invariant offset (in bytes), NULL if none | |
428 bool _negate_invar; // if true then use: (0 - _invar) | |
429 | |
430 PhaseIdealLoop* phase() { return _slp->phase(); } | |
431 IdealLoopTree* lpt() { return _slp->lpt(); } | |
432 PhiNode* iv() { return _slp->iv(); } // Induction var | |
433 | |
434 bool invariant(Node* n) { | |
435 Node *n_c = phase()->get_ctrl(n); | |
436 return !lpt()->is_member(phase()->get_loop(n_c)); | |
437 } | |
438 | |
439 // Match: k*iv + offset | |
440 bool scaled_iv_plus_offset(Node* n); | |
441 // Match: k*iv where k is a constant that's not zero | |
442 bool scaled_iv(Node* n); | |
443 // Match: offset is (k [+/- invariant]) | |
444 bool offset_plus_k(Node* n, bool negate = false); | |
445 | |
446 public: | |
447 enum CMP { | |
448 Less = 1, | |
449 Greater = 2, | |
450 Equal = 4, | |
451 NotEqual = (Less | Greater), | |
452 NotComparable = (Less | Greater | Equal) | |
453 }; | |
454 | |
455 SWPointer(MemNode* mem, SuperWord* slp); | |
456 // Following is used to create a temporary object during | |
457 // the pattern match of an address expression. | |
458 SWPointer(SWPointer* p); | |
459 | |
460 bool valid() { return _adr != NULL; } | |
461 bool has_iv() { return _scale != 0; } | |
462 | |
463 Node* base() { return _base; } | |
464 Node* adr() { return _adr; } | |
465 int scale_in_bytes() { return _scale; } | |
466 Node* invar() { return _invar; } | |
467 bool negate_invar() { return _negate_invar; } | |
468 int offset_in_bytes() { return _offset; } | |
469 int memory_size() { return _mem->memory_size(); } | |
470 | |
471 // Comparable? | |
472 int cmp(SWPointer& q) { | |
473 if (valid() && q.valid() && | |
474 (_adr == q._adr || _base == _adr && q._base == q._adr) && | |
475 _scale == q._scale && | |
476 _invar == q._invar && | |
477 _negate_invar == q._negate_invar) { | |
478 bool overlap = q._offset < _offset + memory_size() && | |
479 _offset < q._offset + q.memory_size(); | |
480 return overlap ? Equal : (_offset < q._offset ? Less : Greater); | |
481 } else { | |
482 return NotComparable; | |
483 } | |
484 } | |
485 | |
486 bool not_equal(SWPointer& q) { return not_equal(cmp(q)); } | |
487 bool equal(SWPointer& q) { return equal(cmp(q)); } | |
488 bool comparable(SWPointer& q) { return comparable(cmp(q)); } | |
489 static bool not_equal(int cmp) { return cmp <= NotEqual; } | |
490 static bool equal(int cmp) { return cmp == Equal; } | |
491 static bool comparable(int cmp) { return cmp < NotComparable; } | |
492 | |
493 void print(); | |
494 }; | |
495 | |
496 | |
497 //------------------------------OrderedPair--------------------------- | |
498 // Ordered pair of Node*. | |
499 class OrderedPair VALUE_OBJ_CLASS_SPEC { | |
500 protected: | |
501 Node* _p1; | |
502 Node* _p2; | |
503 public: | |
504 OrderedPair() : _p1(NULL), _p2(NULL) {} | |
505 OrderedPair(Node* p1, Node* p2) { | |
506 if (p1->_idx < p2->_idx) { | |
507 _p1 = p1; _p2 = p2; | |
508 } else { | |
509 _p1 = p2; _p2 = p1; | |
510 } | |
511 } | |
512 | |
513 bool operator==(const OrderedPair &rhs) { | |
514 return _p1 == rhs._p1 && _p2 == rhs._p2; | |
515 } | |
516 void print() { tty->print(" (%d, %d)", _p1->_idx, _p2->_idx); } | |
517 | |
518 static const OrderedPair initial; | |
519 }; | |
1972 | 520 |
521 #endif // SHARE_VM_OPTO_SUPERWORD_HPP |