Renamed get_Cond_defaultProj() to get_Cond_default_proj() for consistency. Added...
[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                         irg_out_block_walk2(succ, pre, post, env);
266                 }
267         }
268         else {
269                 irg_out_block_walk2(node, pre, post, env);
270         }
271 }
272
273 /*--------------------------------------------------------------------*/
274 /** Building and Removing the out datastructure                      **/
275 /**                                                                  **/
276 /** The outs of a graph are allocated in a single, large array.      **/
277 /** This allows to allocate and deallocate the memory for the outs   **/
278 /** on demand.  The large array is separated into many small ones    **/
279 /** for each node.  Only a single field to reference the out array   **/
280 /** is stored in each node and a field referencing the large out     **/
281 /** array in irgraph.  The 0 field of each out array contains the    **/
282 /** size of this array.  This saves memory in the irnodes themselves.**/
283 /** The construction does two passes over the graph.  The first pass **/
284 /** counts the overall number of outs and the outs of each node.  It **/
285 /** stores the outs of each node in the out reference of the node.   **/
286 /** Then the large array is allocated.  The second iteration chops   **/
287 /** the large array into smaller parts, sets the out edges and       **/
288 /** recounts the out edges.                                          **/
289 /** Removes Tuple nodes!                                             **/
290 /*--------------------------------------------------------------------*/
291
292
293 /** Returns the amount of out edges for not yet visited successors. */
294 static int _count_outs(ir_node *n) {
295         int start, i, res, irn_arity;
296
297         mark_irn_visited(n);
298         n->out = INT_TO_PTR(1);     /* Space for array size. */
299
300         start = is_Block(n) ? 0 : -1;
301         irn_arity = get_irn_arity(n);
302         res = irn_arity - start + 1;  /* --1 or --0; 1 for array size. */
303
304         for (i = start; i < irn_arity; ++i) {
305                 /* Optimize Tuples.  They annoy if walking the cfg. */
306                 ir_node *pred         = get_irn_n(n, i);
307                 ir_node *skipped_pred = skip_Tuple(pred);
308
309                 if (skipped_pred != pred) {
310                         set_irn_n(n, i, skipped_pred);
311                 }
312
313                 /* count Def-Use edges for predecessors */
314                 if (!irn_visited(skipped_pred))
315                         res += _count_outs(skipped_pred);
316
317                 /*count my Def-Use edges */
318                 skipped_pred->out = INT_TO_PTR(PTR_TO_INT(skipped_pred->out) + 1);
319         }
320         return res;
321 }
322
323
324 /** Returns the amount of out edges for not yet visited successors.
325  *  This version handles some special nodes like irg_frame, irg_args etc.
326  */
327 static int count_outs(ir_graph *irg) {
328         ir_node *n;
329         int     i, res;
330
331         inc_irg_visited(irg);
332         res = _count_outs(get_irg_end(irg));
333
334         /* Now handle anchored nodes. We need the out count of those
335            even if they are not visible. */
336         for (i = anchor_last - 1; i >= 0; --i) {
337                 n = get_irg_anchor(irg, i);
338                 if (!irn_visited_else_mark(n)) {
339                         n->out = INT_TO_PTR(1);
340                         ++res;
341                 }
342         }
343         return res;
344 }
345
346 /**
347  * Enter memory for the outs to a node.
348  *
349  * @param use    current node
350  * @param free   current free address in the chunk allocated for the outs
351  *
352  * @return The next free address
353  */
354 static ir_def_use_edge *_set_out_edges(ir_node *use, ir_def_use_edge *free) {
355         int     n_outs, start, i, irn_arity, pos;
356
357         mark_irn_visited(use);
358
359         /* Allocate my array */
360         n_outs = PTR_TO_INT(use->out);
361         use->out = free;
362 #ifdef DEBUG_libfirm
363         use->out_valid = 1;
364 #endif /* defined DEBUG_libfirm */
365         free += n_outs;
366         /* We count the successors again, the space will be sufficient.
367            We use this counter to remember the position for the next back
368            edge. */
369         use->out[0].pos = 0;
370
371         start = is_Block(use) ? 0 : -1;
372         irn_arity = get_irn_arity(use);
373
374         for (i = start; i < irn_arity; ++i) {
375                 ir_node *def = get_irn_n(use, i);
376
377                 /* Recursion */
378                 if (!irn_visited(def))
379                         free = _set_out_edges(def, free);
380
381                 /* Remember this Def-Use edge */
382                 pos = def->out[0].pos + 1;
383                 def->out[pos].use = use;
384                 def->out[pos].pos = i;
385
386                 /* increase the number of Def-Use edges so far */
387                 def->out[0].pos = pos;
388         }
389         return free;
390 }
391
392 /**
393  * Enter memory for the outs to a node. Handles special nodes
394  *
395  * @param irg    the graph
396  * @param free   current free address in the chunk allocated for the outs
397  *
398  * @return The next free address
399  */
400 static ir_def_use_edge *set_out_edges(ir_graph *irg, ir_def_use_edge *free) {
401         ir_node *n;
402         int     i, n_outs;
403
404         inc_irg_visited(irg);
405         free = _set_out_edges(get_irg_end(irg), free);
406
407         /* handle anchored nodes */
408         for (i = anchor_last - 1; i >= 0; --i) {
409                 n = get_irg_anchor(irg, i);
410                 if (!irn_visited_else_mark(n)) {
411                         n_outs = PTR_TO_INT(n->out);
412                         n->out = free;
413 #ifdef DEBUG_libfirm
414                         n->out_valid = 1;
415 #endif /* defined DEBUG_libfirm */
416                         free += n_outs;
417                 }
418         }
419
420         return free;
421 }
422
423
424 /**
425  * We want that the out of ProjX from Start contains the next block at
426  * position 0, the Start block at position 1.  This is necessary for
427  * the out block walker.
428  */
429 static inline void fix_start_proj(ir_graph *irg) {
430         ir_node *startbl = get_irg_start_block(irg);
431
432         if (get_Block_n_cfg_outs(startbl)) {
433                 ir_node *proj = get_irg_initial_exec(irg);
434                 ir_node *irn;
435                 int     block_pos, other_pos;
436
437                 if (get_irn_n_outs(proj) == 2) {
438                         if (get_irn_out_ex(proj, 0, &block_pos) == startbl) {
439                                 irn = get_irn_out_ex(proj, 1, &other_pos);
440                                 set_irn_out(proj, 0, irn, other_pos);
441                                 set_irn_out(proj, 1, startbl, block_pos);
442                         }
443                 } else {
444                         assert(get_irg_phase_state(irg) == phase_backend);
445                 }
446         }
447 }
448
449 /* compute the outs for a given graph */
450 void compute_irg_outs(ir_graph *irg) {
451         ir_graph        *rem = current_ir_graph;
452         int             n_out_edges = 0;
453         ir_def_use_edge *end = NULL;         /* Only for debugging */
454
455         current_ir_graph = irg;
456
457         /* Update graph state */
458         assert(get_irg_phase_state(current_ir_graph) != phase_building);
459
460         if (current_ir_graph->outs_state != outs_none)
461                 free_irg_outs(current_ir_graph);
462
463         /* This first iteration counts the overall number of out edges and the
464            number of out edges for each node. */
465         n_out_edges = count_outs(irg);
466
467         /* allocate memory for all out edges. */
468         irg->outs = XMALLOCNZ(ir_def_use_edge, n_out_edges);
469 #ifdef DEBUG_libfirm
470         irg->n_outs = n_out_edges;
471 #endif /* defined DEBUG_libfirm */
472
473         /* The second iteration splits the irg->outs array into smaller arrays
474            for each node and writes the back edges into this array. */
475         end = set_out_edges(irg, irg->outs);
476
477         /* Check how much memory we have used */
478         assert (end == (irg->outs + n_out_edges));
479
480         /* We want that the out of ProjX from Start contains the next block at
481            position 0, the Start block at position 1.  This is necessary for
482            code placement (place_early() ONLY if started GCSE on graphs with dead blocks) */
483         fix_start_proj(irg);
484
485         current_ir_graph->outs_state = outs_consistent;
486         current_ir_graph = rem;
487 }
488
489 void assure_irg_outs(ir_graph *irg) {
490         if (get_irg_outs_state(irg) != outs_consistent)
491                 compute_irg_outs(irg);
492 }
493
494 void compute_irp_outs(void) {
495         int i;
496         for (i = get_irp_n_irgs() -1; i >= 0; --i)
497                 compute_irg_outs(get_irp_irg(i));
498 }
499
500 void free_irp_outs(void) {
501         int i;
502         for (i = get_irp_n_irgs() -1; i >= 0; --i)
503                 free_irg_outs(get_irp_irg(i));
504 }
505
506
507 /*------------------------------------------------------------*
508  *  This computes the outedges for in interprocedural graph.  *
509  *  There is one quirk:                                       *
510  *  The number of the outedges for each node is saved in      *
511  *  the first member of the ir_node** array. Maybe we should  *
512  *  change this to make it more portable...                   *
513  *------------------------------------------------------------*/
514
515
516 #ifdef INTERPROCEDURAL_VIEW
517 /**
518  * Inits the number of outedges for each node
519  * before counting.
520  */
521 static void init_count(ir_node * node, void *env) {
522         (void) env;
523         node->out = (ir_node **) 1; /* 1 for the array size */
524 }
525
526
527 /**
528  * Adjusts the out edge count for its predecessors
529  * and adds the current arity to the overall count,
530  * which is saved in "env"
531  */
532 static void node_arity_count(ir_node * node, void * env) {
533         int *anz = (int *) env, arity, n_outs, i, start;
534         ir_node *succ;
535
536         arity = get_irn_arity(node);
537         start = (is_Block(node)) ? 0 : -1;
538
539         n_outs = 1 + arity + (-start);  // ((is_Block(node)) ? 0 : 1);   // Why + 1??
540         *anz += n_outs;
541
542         for(i = start; i < arity; i++) {
543                 succ = get_irn_n(node, i);
544                 succ->out = (ir_node **)INT_TO_PTR(PTR_TO_INT(succ->out) + 1);
545         }
546 }
547
548 /*
549  * Inits all nodes for setting the outedges
550  * Returns the overall count of edges
551  */
552 int count_ip_outs(void) {
553         int res = 0;
554
555         cg_walk(init_count, node_arity_count, &res);
556
557         return(res);
558 }
559
560 static int dummy_count = 0, global_count; /* Only for debugging */
561
562 /**
563  * For each node: Sets the pointer to array
564  * in which the outedges are written later.
565  * The current array start is transported in env
566  */
567 static void set_array_pointer(ir_node *node, void *env) {
568         int n_outs;
569         ir_node ***free = (ir_node ***) env;
570
571         /* Allocate my array */
572         n_outs = PTR_TO_INT(node->out);  /* We wrote the count here in count_ip_outs */
573         dummy_count += n_outs;
574         assert(dummy_count <= global_count && "More outedges than initially counted!");
575         node -> out = *free;
576         *free = &((*free)[n_outs]);
577         /* We count the successors again, the space will be sufficient.
578            We use this counter to remember the position for the next back
579            edge. */
580         node -> out[0] = (ir_node *) 0;
581 }
582
583
584 /**
585  * Adds an outedge from the predecessor to the
586  * current node.
587  */
588 static void set_out_pointer(ir_node * node, void *env) {
589         int i, arity = get_irn_arity(node);
590         ir_node *succ;
591         int start = (!is_Block(node)) ? -1 : 0;
592         (void) env;
593
594         for (i = start; i < arity; ++i) {
595                 succ = get_irn_n(node, i);
596                 succ->out[get_irn_n_outs(succ)+1] = node;
597                 succ->out[0] = INT_TO_PTR(get_irn_n_outs(succ) + 1);
598         }
599 }
600
601
602 /*
603  * Sets the outedges for all nodes.
604  */
605 void set_ip_outs(void) {
606         ir_node **outedge_array = get_irp_ip_outedges();
607         cg_walk(set_array_pointer, set_out_pointer, (void *) &outedge_array);
608 }
609
610
611
612 /*
613  * Counts the outedges, allocates memory to save the
614  * outedges and fills this outedge array in interprocedural
615  * view!
616  */
617 void compute_ip_outs(void) {
618         int n_out_edges;
619         ir_node **out_edges;
620
621         assert(get_irp_ip_view_state() == ip_view_valid &&
622          "Cannot construct outs for invalid ip view.");
623
624         if (irp->outs_state != outs_none) {
625                 free_ip_outs();
626         }
627
628         global_count = n_out_edges = count_ip_outs();
629         out_edges    = XMALLOCNZ(ir_node*, n_out_edges);
630         set_irp_ip_outedges(out_edges);
631         set_ip_outs();
632 }
633
634 void free_ip_outs(void) {
635         ir_node **out_edges = get_irp_ip_outedges();
636         if (out_edges != NULL) {
637                 free(out_edges);
638                 set_irp_ip_outedges(NULL);
639         }
640         irp->outs_state = outs_none;
641 }
642 #endif
643
644
645 void free_irg_outs(ir_graph *irg) {
646         /*   current_ir_graph->outs_state = outs_none; */
647         irg->outs_state = outs_none;
648
649         if (irg->outs) {
650 #ifdef DEBUG_libfirm
651                 memset(irg->outs, 0, irg->n_outs);
652 #endif /* defined DEBUG_libfirm */
653                 free(irg->outs);
654                 irg->outs = NULL;
655 #ifdef DEBUG_libfirm
656                 irg->n_outs = 0;
657 #endif /* defined DEBUG_libfirm */
658         }
659
660 #ifdef DEBUG_libfirm
661         /* when debugging, *always* reset all nodes' outs!  irg->outs might
662            have been lying to us */
663         irg_walk_graph (irg, reset_outs, NULL, NULL);
664 #endif /* defined DEBUG_libfirm */
665 }
666
667 static void check_out_edges(ir_node *irn, void *env) {
668         int i, j, pos;
669         int *pError = env;
670         int error = *pError;
671         int last = is_Block(irn) ? 0 : -1;
672
673         /* check forward: every input must have an out edge */
674         for (i = get_irn_arity(irn) - 1; i >= last; --i) {
675                 ir_node *pred = get_irn_n(irn, i);
676
677                 for (j = get_irn_n_outs(pred) - 1; j >= 0; --j) {
678                         ir_node *user = get_irn_out_ex(pred, j, &pos);
679
680                         if (user == irn && pos == i) {
681                                 break;
682                         }
683                 }
684                 if (j < 0) {
685                         ir_fprintf(stderr, "Missing out edge from %+F input %d to %+F", irn, i, pred);
686                         ++error;
687                 }
688         }
689
690         /* checking backward */
691         for (i = get_irn_n_outs(irn) - 1; i >= 0; --i) {
692                 ir_node *user = get_irn_out_ex(irn, i, &pos);
693
694                 if (get_irn_n(user, pos) != irn) {
695                         ir_fprintf(stderr, "Spurious out edge from %+F output %d to %+F", irn, i, user);
696                         ++error;
697                 }
698         }
699         *pError = error;
700 }
701
702 /* verify outs edges. */
703 void verify_outs(ir_graph *irg) {
704         int errors = 0;
705         irg_walk_graph(irg, NULL, check_out_edges, &errors);
706         if (errors > 0)
707                 panic("Out edges are corrupt");
708 }