- implemented ia32_ClimbFrame() pseudo-instruction
[libfirm] / ir / ana / irouts.c
1 /*
2  * Copyright (C) 1995-2008 University of Karlsruhe.  All right reserved.
3  *
4  * This file is part of libFirm.
5  *
6  * This file may be distributed and/or modified under the terms of the
7  * GNU General Public License version 2 as published by the Free Software
8  * Foundation and appearing in the file LICENSE.GPL included in the
9  * packaging of this file.
10  *
11  * Licensees holding valid libFirm Professional Edition licenses may use
12  * this file in accordance with the libFirm Commercial License.
13  * Agreement provided with the Software.
14  *
15  * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
16  * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE.
18  */
19
20 /**
21  * @file
22  * @brief    Compute and access out edges (also called def-use edges).
23  * @author   Goetz Lindenmaier, Michael Beck
24  * @date     1.2002
25  * @version  $Id$
26  */
27 #include "config.h"
28
29 #include <string.h>
30
31 #include "xmalloc.h"
32 #include "irouts.h"
33 #include "irnode_t.h"
34 #include "irgraph_t.h"
35 #include "irprog_t.h"
36 #include "irgwalk.h"
37 #include "irtools.h"
38 #include "irprintf.h"
39 #include "error.h"
40
41 #ifdef DEBUG_libfirm
42 /* Note:  ir_node.out_valid and ir_graph.n_outs are only present when DEBUG_libfirm is defined */
43 /* Accesses to out_valid and n_outs are fenced out to avoid breakage
44    when compiling with neither DEBUG_libfirm or NDEBUG defined */
45 #endif /* defined DEBUG_libfirm */
46
47 /*--------------------------------------------------------------------*/
48 /** Accessing the out datastructures                                 **/
49 /*--------------------------------------------------------------------*/
50
51 #ifdef DEBUG_libfirm
52 /** Clear the outs of a node */
53 static void reset_outs(ir_node *node, void *unused) {
54         (void) unused;
55         node->out       = NULL;
56         node->out_valid = 0;
57 }
58 #endif
59
60 int get_irn_outs_computed(const ir_node *node)
61 {
62         return node->out != NULL;
63 }
64
65 /* returns the number of successors of the node: */
66 int get_irn_n_outs(const ir_node *node) {
67         assert(node && node->kind == k_ir_node);
68 #ifdef DEBUG_libfirm
69         /* assert(node->out_valid); */
70 #endif /* defined DEBUG_libfirm */
71         /* we misuse the first for the size info of the out array */
72         return node->out[0].pos;
73 }
74
75 /* Access successor n */
76 ir_node *get_irn_out(const ir_node *def, int pos) {
77         assert(pos >= 0 && pos < get_irn_n_outs(def));
78 #ifdef DEBUG_libfirm
79         /* assert(def->out_valid); */
80 #endif /* defined DEBUG_libfirm */
81         return def->out[pos+1].use;
82 }
83
84 /* Access successor n */
85 ir_node *get_irn_out_ex(const ir_node *def, int pos, int *in_pos) {
86         assert(pos >= 0 && pos < get_irn_n_outs(def));
87 #ifdef DEBUG_libfirm
88         /* assert(def->out_valid); */
89 #endif /* defined DEBUG_libfirm */
90         *in_pos = def->out[pos+1].pos;
91         return def->out[pos+1].use;
92 }
93
94 void set_irn_out(ir_node *def, int pos, ir_node *use, int in_pos) {
95         assert(def && use);
96         assert(pos >= 0 && pos < get_irn_n_outs(def));
97 #ifdef DEBUG_libfirm
98         def->out_valid = 1;          /* assume that this function is used correctly */
99 #endif /* defined DEBUG_libfirm */
100         def->out[pos+1].use = use;
101         def->out[pos+1].pos = in_pos;
102 }
103
104 /* Return the number of control flow successors, ignore keep-alives. */
105 int get_Block_n_cfg_outs(const ir_node *bl) {
106         int i, n_cfg_outs = 0;
107         assert(bl && is_Block(bl));
108 #ifdef DEBUG_libfirm
109         assert(bl->out_valid);
110 #endif /* defined DEBUG_libfirm */
111         for (i = 1; i <= bl->out[0].pos; ++i) {
112                 ir_node *succ = bl->out[i].use;
113                 if (get_irn_mode(succ) == mode_X && !is_End(succ))
114                         n_cfg_outs += succ->out[0].pos;
115         }
116         return n_cfg_outs;
117 }
118
119 /* Return the number of control flow successors, honor keep-alives. */
120 int get_Block_n_cfg_outs_ka(const ir_node *bl) {
121         int i, n_cfg_outs = 0;
122         assert(bl && is_Block(bl));
123 #ifdef DEBUG_libfirm
124         assert(bl->out_valid);
125 #endif /* defined DEBUG_libfirm */
126         for (i = 1; i <= bl->out[0].pos; ++i) {
127                 ir_node *succ = bl->out[i].use;
128                 if (get_irn_mode(succ) == mode_X) {
129
130                         if (is_End(succ)) {
131                                 /* ignore End if we are in the Endblock */
132                                 if (get_nodes_block(succ) == bl)
133                                         continue;
134                                 else /* count Keep-alive as one */
135                                         n_cfg_outs += 1;
136                         } else
137                                 n_cfg_outs += succ->out[0].pos;
138                 }
139         }
140         return n_cfg_outs;
141 }
142
143 /* Access predecessor n, ignore keep-alives. */
144 ir_node *get_Block_cfg_out(const ir_node *bl, int pos) {
145         int i;
146         assert(bl && is_Block(bl));
147 #ifdef DEBUG_libfirm
148         assert(bl->out_valid);
149 #endif /* defined DEBUG_libfirm */
150         for (i = 1; i <= bl->out[0].pos; ++i) {
151                 ir_node *succ = bl->out[i].use;
152                 if (get_irn_mode(succ) == mode_X && !is_End(succ)) {
153                         int n_outs = succ->out[0].pos;
154                         if (pos < n_outs)
155                                 return succ->out[pos + 1].use;
156                         else
157                                 pos -= n_outs;
158                 }
159         }
160         return NULL;
161 }
162
163 /* Access predecessor n, honor keep-alives. */
164 ir_node *get_Block_cfg_out_ka(const ir_node *bl, int pos) {
165         int i, n_outs;
166         assert(bl && is_Block(bl));
167 #ifdef DEBUG_libfirm
168         assert (bl->out_valid);
169 #endif /* defined DEBUG_libfirm */
170         for (i = 1; i <= bl->out[0].pos; ++i) {
171                 ir_node *succ = bl->out[i].use;
172                 if (get_irn_mode(succ) == mode_X) {
173                         if (is_End(succ)) {
174                                 ir_node *end_bl = get_nodes_block(succ);
175                                 if (end_bl == bl) {
176                                         /* ignore End if we are in the Endblock */
177                                         continue;
178                                 }
179                                 if (pos == 0) {
180                                         /* handle keep-alive here: return the Endblock instead of the End node */
181                                         return end_bl;
182                                 } else
183                                         --pos;
184                         } else {
185                                 n_outs = succ->out[0].pos;
186                                 if (pos < n_outs)
187                                         return succ->out[pos + 1].use;
188                                 else
189                                         pos -= n_outs;
190                         }
191                 }
192         }
193         return NULL;
194 }
195
196 static void irg_out_walk_2(ir_node *node, irg_walk_func *pre,
197             irg_walk_func *post, void *env) {
198         int     i, n;
199         ir_node *succ;
200
201         assert(node);
202         assert(get_irn_visited(node) < get_irg_visited(current_ir_graph));
203
204         set_irn_visited(node, get_irg_visited(current_ir_graph));
205
206         if (pre) pre(node, env);
207
208         for (i = 0, n = get_irn_n_outs(node); i < n; ++i) {
209                 succ = get_irn_out(node, i);
210                 if (get_irn_visited(succ) < get_irg_visited(current_ir_graph))
211                         irg_out_walk_2(succ, pre, post, env);
212         }
213
214         if (post) post(node, env);
215 }
216
217 void irg_out_walk(ir_node *node,
218                   irg_walk_func *pre, irg_walk_func *post,
219                   void *env) {
220         assert(node);
221         if (get_irg_outs_state(current_ir_graph) != outs_none) {
222                 inc_irg_visited (current_ir_graph);
223                 irg_out_walk_2(node, pre, post, env);
224         }
225 }
226
227 static void irg_out_block_walk2(ir_node *bl,
228                                 irg_walk_func *pre, irg_walk_func *post,
229                                 void *env) {
230         int i, n;
231
232         if (!Block_block_visited(bl)) {
233                 mark_Block_block_visited(bl);
234
235                 if (pre)
236                         pre(bl, env);
237
238                 for (i = 0, n =  get_Block_n_cfg_outs(bl); i < n; ++i) {
239                         /* find the corresponding predecessor block. */
240                         ir_node *pred = get_Block_cfg_out(bl, i);
241                         /* recursion */
242                         irg_out_block_walk2(pred, pre, post, env);
243                 }
244
245                 if (post)
246                         post(bl, env);
247         }
248 }
249
250 /* Walks only over Block nodes in the graph.  Has it's own visited
251    flag, so that it can be interleaved with the other walker.         */
252 void irg_out_block_walk(ir_node *node,
253                         irg_walk_func *pre, irg_walk_func *post,
254                         void *env) {
255
256         assert(is_Block(node) || (get_irn_mode(node) == mode_X));
257
258         inc_irg_block_visited(current_ir_graph);
259
260         if (get_irn_mode(node) == mode_X) {
261                 int i, n;
262
263                 for (i = 0, n = get_irn_n_outs(node); i < n; ++i) {
264                         ir_node *succ = get_irn_out(node, i);
265                         if (get_irn_visited(succ) < get_irg_visited(current_ir_graph))
266                                 irg_out_walk_2(succ, pre, post, env);
267                 }
268         }
269         else {
270                 irg_out_block_walk2(node, pre, post, env);
271         }
272 }
273
274 /*--------------------------------------------------------------------*/
275 /** Building and Removing the out datastructure                      **/
276 /**                                                                  **/
277 /** The outs of a graph are allocated in a single, large array.      **/
278 /** This allows to allocate and deallocate the memory for the outs   **/
279 /** on demand.  The large array is separated into many small ones    **/
280 /** for each node.  Only a single field to reference the out array   **/
281 /** is stored in each node and a field referencing the large out     **/
282 /** array in irgraph.  The 0 field of each out array contains the    **/
283 /** size of this array.  This saves memory in the irnodes themselves.**/
284 /** The construction does two passes over the graph.  The first pass **/
285 /** counts the overall number of outs and the outs of each node.  It **/
286 /** stores the outs of each node in the out reference of the node.   **/
287 /** Then the large array is allocated.  The second iteration chops   **/
288 /** the large array into smaller parts, sets the out edges and       **/
289 /** recounts the out edges.                                          **/
290 /** Removes Tuple nodes!                                             **/
291 /*--------------------------------------------------------------------*/
292
293
294 /** Returns the amount of out edges for not yet visited successors. */
295 static int _count_outs(ir_node *n) {
296         int start, i, res, irn_arity;
297
298         mark_irn_visited(n);
299         n->out = INT_TO_PTR(1);     /* Space for array size. */
300
301         start = is_Block(n) ? 0 : -1;
302         irn_arity = get_irn_arity(n);
303         res = irn_arity - start + 1;  /* --1 or --0; 1 for array size. */
304
305         for (i = start; i < irn_arity; ++i) {
306                 /* Optimize Tuples.  They annoy if walking the cfg. */
307                 ir_node *pred         = get_irn_n(n, i);
308                 ir_node *skipped_pred = skip_Tuple(pred);
309
310                 if (skipped_pred != pred) {
311                         set_irn_n(n, i, skipped_pred);
312                 }
313
314                 /* count Def-Use edges for predecessors */
315                 if (!irn_visited(skipped_pred))
316                         res += _count_outs(skipped_pred);
317
318                 /*count my Def-Use edges */
319                 skipped_pred->out = INT_TO_PTR(PTR_TO_INT(skipped_pred->out) + 1);
320         }
321         return res;
322 }
323
324
325 /** Returns the amount of out edges for not yet visited successors.
326  *  This version handles some special nodes like irg_frame, irg_args etc.
327  */
328 static int count_outs(ir_graph *irg) {
329         ir_node *n;
330         int     i, res;
331
332         inc_irg_visited(irg);
333         res = _count_outs(get_irg_end(irg));
334
335         /* Now handle anchored nodes. We need the out count of those
336            even if they are not visible. */
337         for (i = anchor_last - 1; i >= 0; --i) {
338                 n = get_irg_anchor(irg, i);
339                 if (!irn_visited_else_mark(n)) {
340                         n->out = INT_TO_PTR(1);
341                         ++res;
342                 }
343         }
344         return res;
345 }
346
347 /**
348  * Enter memory for the outs to a node.
349  *
350  * @param use    current node
351  * @param free   current free address in the chunk allocated for the outs
352  *
353  * @return The next free address
354  */
355 static ir_def_use_edge *_set_out_edges(ir_node *use, ir_def_use_edge *free) {
356         int     n_outs, start, i, irn_arity, pos;
357
358         mark_irn_visited(use);
359
360         /* Allocate my array */
361         n_outs = PTR_TO_INT(use->out);
362         use->out = free;
363 #ifdef DEBUG_libfirm
364         use->out_valid = 1;
365 #endif /* defined DEBUG_libfirm */
366         free += n_outs;
367         /* We count the successors again, the space will be sufficient.
368            We use this counter to remember the position for the next back
369            edge. */
370         use->out[0].pos = 0;
371
372         start = is_Block(use) ? 0 : -1;
373         irn_arity = get_irn_arity(use);
374
375         for (i = start; i < irn_arity; ++i) {
376                 ir_node *def = get_irn_n(use, i);
377
378                 /* Recursion */
379                 if (!irn_visited(def))
380                         free = _set_out_edges(def, free);
381
382                 /* Remember this Def-Use edge */
383                 pos = def->out[0].pos + 1;
384                 def->out[pos].use = use;
385                 def->out[pos].pos = i;
386
387                 /* increase the number of Def-Use edges so far */
388                 def->out[0].pos = pos;
389         }
390         return free;
391 }
392
393 /**
394  * Enter memory for the outs to a node. Handles special nodes
395  *
396  * @param irg    the graph
397  * @param free   current free address in the chunk allocated for the outs
398  *
399  * @return The next free address
400  */
401 static ir_def_use_edge *set_out_edges(ir_graph *irg, ir_def_use_edge *free) {
402         ir_node *n;
403         int     i, n_outs;
404
405         inc_irg_visited(irg);
406         free = _set_out_edges(get_irg_end(irg), free);
407
408         /* handle anchored nodes */
409         for (i = anchor_last - 1; i >= 0; --i) {
410                 n = get_irg_anchor(irg, i);
411                 if (!irn_visited_else_mark(n)) {
412                         n_outs = PTR_TO_INT(n->out);
413                         n->out = free;
414 #ifdef DEBUG_libfirm
415                         n->out_valid = 1;
416 #endif /* defined DEBUG_libfirm */
417                         free += n_outs;
418                 }
419         }
420
421         return free;
422 }
423
424
425 /**
426  * We want that the out of ProjX from Start contains the next block at
427  * position 0, the Start block at position 1.  This is necessary for
428  * the out block walker.
429  */
430 static inline void fix_start_proj(ir_graph *irg) {
431         ir_node *startbl = get_irg_start_block(irg);
432
433         if (get_Block_n_cfg_outs(startbl)) {
434                 ir_node *proj = get_irg_initial_exec(irg);
435                 ir_node *irn;
436                 int     block_pos, other_pos;
437
438                 if (get_irn_n_outs(proj) == 2) {
439                         if (get_irn_out_ex(proj, 0, &block_pos) == startbl) {
440                                 irn = get_irn_out_ex(proj, 1, &other_pos);
441                                 set_irn_out(proj, 0, irn, other_pos);
442                                 set_irn_out(proj, 1, startbl, block_pos);
443                         }
444                 } else {
445                         assert(get_irg_phase_state(irg) == phase_backend);
446                 }
447         }
448 }
449
450 /* compute the outs for a given graph */
451 void compute_irg_outs(ir_graph *irg) {
452         ir_graph        *rem = current_ir_graph;
453         int             n_out_edges = 0;
454         ir_def_use_edge *end = NULL;         /* Only for debugging */
455
456         current_ir_graph = irg;
457
458         /* Update graph state */
459         assert(get_irg_phase_state(current_ir_graph) != phase_building);
460
461         if (current_ir_graph->outs_state != outs_none)
462                 free_irg_outs(current_ir_graph);
463
464         /* This first iteration counts the overall number of out edges and the
465            number of out edges for each node. */
466         n_out_edges = count_outs(irg);
467
468         /* allocate memory for all out edges. */
469         irg->outs = XMALLOCNZ(ir_def_use_edge, n_out_edges);
470 #ifdef DEBUG_libfirm
471         irg->n_outs = n_out_edges;
472 #endif /* defined DEBUG_libfirm */
473
474         /* The second iteration splits the irg->outs array into smaller arrays
475            for each node and writes the back edges into this array. */
476         end = set_out_edges(irg, irg->outs);
477
478         /* Check how much memory we have used */
479         assert (end == (irg->outs + n_out_edges));
480
481         /* We want that the out of ProjX from Start contains the next block at
482            position 0, the Start block at position 1.  This is necessary for
483            code placement (place_early() ONLY if started GCSE on graphs with dead blocks) */
484         fix_start_proj(irg);
485
486         current_ir_graph->outs_state = outs_consistent;
487         current_ir_graph = rem;
488 }
489
490 void assure_irg_outs(ir_graph *irg) {
491         if (get_irg_outs_state(irg) != outs_consistent)
492                 compute_irg_outs(irg);
493 }
494
495 void compute_irp_outs(void) {
496         int i;
497         for (i = get_irp_n_irgs() -1; i >= 0; --i)
498                 compute_irg_outs(get_irp_irg(i));
499 }
500
501 void free_irp_outs(void) {
502         int i;
503         for (i = get_irp_n_irgs() -1; i >= 0; --i)
504                 free_irg_outs(get_irp_irg(i));
505 }
506
507
508 /*------------------------------------------------------------*
509  *  This computes the outedges for in interprocedural graph.  *
510  *  There is one quirk:                                       *
511  *  The number of the outedges for each node is saved in      *
512  *  the first member of the ir_node** array. Maybe we should  *
513  *  change this to make it more portable...                   *
514  *------------------------------------------------------------*/
515
516
517 #ifdef INTERPROCEDURAL_VIEW
518 /**
519  * Inits the number of outedges for each node
520  * before counting.
521  */
522 static void init_count(ir_node * node, void *env) {
523         (void) env;
524         node->out = (ir_node **) 1; /* 1 for the array size */
525 }
526
527
528 /**
529  * Adjusts the out edge count for its predecessors
530  * and adds the current arity to the overall count,
531  * which is saved in "env"
532  */
533 static void node_arity_count(ir_node * node, void * env) {
534         int *anz = (int *) env, arity, n_outs, i, start;
535         ir_node *succ;
536
537         arity = get_irn_arity(node);
538         start = (is_Block(node)) ? 0 : -1;
539
540         n_outs = 1 + arity + (-start);  // ((is_Block(node)) ? 0 : 1);   // Why + 1??
541         *anz += n_outs;
542
543         for(i = start; i < arity; i++) {
544                 succ = get_irn_n(node, i);
545                 succ->out = (ir_node **)INT_TO_PTR(PTR_TO_INT(succ->out) + 1);
546         }
547 }
548
549 /*
550  * Inits all nodes for setting the outedges
551  * Returns the overall count of edges
552  */
553 int count_ip_outs(void) {
554         int res = 0;
555
556         cg_walk(init_count, node_arity_count, &res);
557
558         return(res);
559 }
560
561 static int dummy_count = 0, global_count; /* Only for debugging */
562
563 /**
564  * For each node: Sets the pointer to array
565  * in which the outedges are written later.
566  * The current array start is transported in env
567  */
568 static void set_array_pointer(ir_node *node, void *env) {
569         int n_outs;
570         ir_node ***free = (ir_node ***) env;
571
572         /* Allocate my array */
573         n_outs = PTR_TO_INT(node->out);  /* We wrote the count here in count_ip_outs */
574         dummy_count += n_outs;
575         assert(dummy_count <= global_count && "More outedges than initially counted!");
576         node -> out = *free;
577         *free = &((*free)[n_outs]);
578         /* We count the successors again, the space will be sufficient.
579            We use this counter to remember the position for the next back
580            edge. */
581         node -> out[0] = (ir_node *) 0;
582 }
583
584
585 /**
586  * Adds an outedge from the predecessor to the
587  * current node.
588  */
589 static void set_out_pointer(ir_node * node, void *env) {
590         int i, arity = get_irn_arity(node);
591         ir_node *succ;
592         int start = (!is_Block(node)) ? -1 : 0;
593         (void) env;
594
595         for (i = start; i < arity; ++i) {
596                 succ = get_irn_n(node, i);
597                 succ->out[get_irn_n_outs(succ)+1] = node;
598                 succ->out[0] = INT_TO_PTR(get_irn_n_outs(succ) + 1);
599         }
600 }
601
602
603 /*
604  * Sets the outedges for all nodes.
605  */
606 void set_ip_outs(void) {
607         ir_node **outedge_array = get_irp_ip_outedges();
608         cg_walk(set_array_pointer, set_out_pointer, (void *) &outedge_array);
609 }
610
611
612
613 /*
614  * Counts the outedges, allocates memory to save the
615  * outedges and fills this outedge array in interprocedural
616  * view!
617  */
618 void compute_ip_outs(void) {
619         int n_out_edges;
620         ir_node **out_edges;
621
622         assert(get_irp_ip_view_state() == ip_view_valid &&
623          "Cannot construct outs for invalid ip view.");
624
625         if (irp->outs_state != outs_none) {
626                 free_ip_outs();
627         }
628
629         global_count = n_out_edges = count_ip_outs();
630         out_edges    = XMALLOCNZ(ir_node*, n_out_edges);
631         set_irp_ip_outedges(out_edges);
632         set_ip_outs();
633 }
634
635 void free_ip_outs(void) {
636         ir_node **out_edges = get_irp_ip_outedges();
637         if (out_edges != NULL) {
638                 free(out_edges);
639                 set_irp_ip_outedges(NULL);
640         }
641         irp->outs_state = outs_none;
642 }
643 #endif
644
645
646 void free_irg_outs(ir_graph *irg) {
647         /*   current_ir_graph->outs_state = outs_none; */
648         irg->outs_state = outs_none;
649
650         if (irg->outs) {
651 #ifdef DEBUG_libfirm
652                 memset(irg->outs, 0, irg->n_outs);
653 #endif /* defined DEBUG_libfirm */
654                 free(irg->outs);
655                 irg->outs = NULL;
656 #ifdef DEBUG_libfirm
657                 irg->n_outs = 0;
658 #endif /* defined DEBUG_libfirm */
659         }
660
661 #ifdef DEBUG_libfirm
662         /* when debugging, *always* reset all nodes' outs!  irg->outs might
663            have been lying to us */
664         irg_walk_graph (irg, reset_outs, NULL, NULL);
665 #endif /* defined DEBUG_libfirm */
666 }
667
668 static void check_out_edges(ir_node *irn, void *env) {
669         int i, j, pos;
670         int *pError = env;
671         int error = *pError;
672         int last = is_Block(irn) ? 0 : -1;
673
674         /* check forward: every input must have an out edge */
675         for (i = get_irn_arity(irn) - 1; i >= last; --i) {
676                 ir_node *pred = get_irn_n(irn, i);
677
678                 for (j = get_irn_n_outs(pred) - 1; j >= 0; --j) {
679                         ir_node *user = get_irn_out_ex(pred, j, &pos);
680
681                         if (user == irn && pos == i) {
682                                 break;
683                         }
684                 }
685                 if (j < 0) {
686                         ir_fprintf(stderr, "Missing out edge from %+F input %d to %+F", irn, i, pred);
687                         ++error;
688                 }
689         }
690
691         /* checking backward */
692         for (i = get_irn_n_outs(irn) - 1; i >= 0; --i) {
693                 ir_node *user = get_irn_out_ex(irn, i, &pos);
694
695                 if (get_irn_n(user, pos) != irn) {
696                         ir_fprintf(stderr, "Spurious out edge from %+F output %d to %+F", irn, i, user);
697                         ++error;
698                 }
699         }
700         *pError = error;
701 }
702
703 /* verify outs edges. */
704 void verify_outs(ir_graph *irg) {
705         int errors = 0;
706         irg_walk_graph(irg, NULL, check_out_edges, &errors);
707         if (errors > 0)
708                 panic("Out edges are corrupt");
709 }