fix recursion handling
[libfirm] / ir / ana2 / pto_comp.c
1 /* -*- c -*- */
2
3 /*
4    Project:     libFIRM
5    File name:   ir/ana/pto_comp.c
6    Purpose:     Main Implementation of PTO
7    Author:      Florian
8    Modified by:
9    Created:     Sat Nov 13 19:35:27 CET 2004
10    CVS-ID:      $Id$
11    Copyright:   (c) 1999-2004 Universität Karlsruhe
12    Licence:     This file is protected by the GPL -  GNU GENERAL PUBLIC LICENSE.
13 */
14
15 # ifdef HAVE_CONFIG_H
16 #  include "config.h"
17 # endif
18
19 /*
20   pto_comp: Main Implementation of PTO
21 */
22
23 # include <string.h>            /* for memset */
24
25 # include "pto_comp.h"
26 # include "pto_util.h"
27 # include "pto_name.h"
28 # include "pto_ctx.h"
29 # include "pto_mod.h"
30
31 # include "irnode_t.h"
32 # include "irprog.h"
33 # include "xmalloc.h"
34 # include "irmemwalk.h"
35
36 # include "pto_debug.h"
37 # include "pto_init.h"
38
39 # include "ecg.h"
40
41 /* Local Defines: */
42
43 /* Local Data Types: */
44 typedef struct pto_env_str {
45   struct pto_env_str *enc_env;
46   ir_graph *graph;
47   int ctx_idx;
48   int change;
49 } pto_env_t;
50
51
52 /* Local Variables: */
53
54 /* Debug only: */
55 char *spaces = NULL;
56
57 /* Local Prototypes: */
58 static pto_t *get_pto (ir_node*, pto_env_t*);
59 static void pto_call (ir_graph*, ir_node*, pto_env_t*);
60 static void pto_raise (ir_node*, pto_env_t*);
61 static void pto_load (ir_node*, pto_env_t*);
62 static void pto_store (ir_node*, pto_env_t*);
63 static void pto_method (ir_node*, pto_env_t*);
64 static void pto_end_block (ir_node*, pto_env_t*);
65
66 /* ===================================================
67    Local Implementation:
68    =================================================== */
69 /* Add values of the actual arguments to the formal arguments */
70 static int add_graph_args (ir_graph *graph, ir_node *call, pto_env_t *env)
71 {
72   assert (iro_Call == get_irn_opcode (call));
73
74   int change = FALSE;
75
76   type *meth = get_entity_type (get_irg_entity (graph));
77
78   ir_node **args = get_irg_proj_args (graph);
79   int n_args = get_Call_n_params (call);
80   int i;
81
82   DBGPRINT (1, (stdout, "%s: args of %s[%li] -> 0x%08x\n",
83                 __FUNCTION__, OPNAME (call), OPNUM (call), (void*) graph));
84
85   for (i = 0; i < n_args; i ++) {
86     if (NULL != args [i]) {
87       if (mode_P == get_type_mode (get_method_param_type (meth, i))) {
88         ir_node *call_arg = get_Call_param (call, i);
89         pto_t *arg_pto = get_pto (call_arg, env);
90         pto_t *frm_pto = get_node_pto (args [i]);
91
92         assert (arg_pto);
93         assert (frm_pto);
94
95         change |= qset_insert_all (frm_pto->values, arg_pto->values);
96
97         DBGPRINT (2, (stdout, "%s: arg [%i]: -> %s[%li] (%i) -> %s[%li] (%i)\n",
98                       __FUNCTION__,
99                       i,
100                       OPNAME (call_arg), OPNUM (call_arg),
101                       arg_pto->values->id,
102                       OPNAME (args [i]), OPNUM (args [i]),
103                       frm_pto->values->id));
104       }
105     }
106   }
107
108   return (change);
109 }
110
111 /* Transfer the actual arguments to the formal arguments */
112 static void set_graph_args (ir_graph *graph, ir_node *call, pto_env_t *env)
113 {
114   assert (iro_Call == get_irn_opcode (call));
115
116   type *meth = get_entity_type (get_irg_entity (graph));
117   ir_node **args = get_irg_proj_args (graph);
118
119   int n_args = get_Call_n_params (call);
120   int i;
121
122   for (i = 0; i < n_args; i ++) {
123     if (NULL != args [i]) {
124       if (mode_P == get_type_mode (get_method_param_type (meth, i))) {
125         ir_node *call_arg = get_Call_param (call, i);
126         pto_t *pto = get_pto (call_arg, env);
127         assert (pto);
128         set_node_pto (args [i], pto);
129
130         DBGPRINT (1, (stdout, "%s: arg [%i]: %s[%li] -> %s[%li] (%i)\n",
131                       __FUNCTION__,
132                       i,
133                       OPNAME (call_arg), OPNUM (call_arg),
134                       OPNAME (args [i]), OPNUM (args [i]),
135                       pto->values->id));
136       }
137     }
138   }
139 }
140
141 /* Transfer the graph's result to the call */
142 static int set_graph_result (ir_graph *graph, ir_node *call)
143 {
144   type *tp = get_entity_type (get_irg_entity (graph));
145
146   if (0 == get_method_n_ress (tp)) {
147     return (FALSE);
148   }
149
150   tp = get_method_res_type (tp, 0);
151
152   if (mode_P != get_type_mode (tp)) {
153     set_node_pto (call, NULL);
154
155     return (FALSE);
156   }
157
158   ir_node *end_block = get_irg_end_block (graph);
159   pto_t *ret_pto = get_node_pto (end_block);
160
161   pto_t *call_pto = get_node_pto (call);
162
163   assert (call_pto);
164
165     DBGPRINT (0, (stdout, "%s: before change args\n", __FUNCTION__));
166     DBGEXE (0, pto_print_pto (end_block));
167     DBGEXE (0, pto_print_pto (call));
168
169   int change = qset_insert_all (call_pto->values, ret_pto->values);
170
171   if (change) {
172     DBGPRINT (0, (stdout, "%s: after change args\n", __FUNCTION__));
173     DBGEXE (0, pto_print_pto (end_block));
174     DBGEXE (0, pto_print_pto (call));
175     /* assert (0); */
176   }
177
178   return (change);
179 }
180
181 /* Propagation of PTO values */
182 static pto_t *get_pto_proj (ir_node *proj, pto_env_t *env)
183 {
184   ir_node *proj_in = get_Proj_pred (proj);
185   const long proj_proj = get_Proj_proj (proj);
186   const opcode in_op = get_irn_opcode (proj_in);
187   pto_t *in_pto = NULL;
188   pto_t *proj_pto = NULL; /* get_node_pto (proj); */
189
190   ir_node *proj_in_in = NULL;
191
192   switch (in_op) {
193   case (iro_Start):             /* ProjT (Start) */
194     assert (0 && "pto from ProjT(Start) requested");
195
196     return (NULL);
197   case (iro_Proj):              /* ProjT (Start), ProjT (Call) */
198     proj_in_in = get_Proj_pred (proj_in);
199     const opcode in_in_op = get_irn_opcode (proj_in_in);
200     const long proj_in_proj = get_Proj_proj (proj_in);
201
202     assert ((pn_Start_T_args == proj_in_proj) ||
203             (pn_Call_T_result == proj_in_proj));
204
205     switch (in_in_op) {
206     case (iro_Start):           /* ProjArg (ProjT (Start)) */
207       /* then the pto value must have been set to the node */
208       proj_pto = get_node_pto (proj);
209       assert (proj_pto);
210
211       return (proj_pto);
212     case (iro_Call):            /* ProjV (ProjT (Call)) */
213       if (NULL != proj_pto) {
214         return (proj_pto);
215       } else {
216         in_pto = get_pto (proj_in, env);
217         set_node_pto (proj, in_pto);
218
219         assert (in_pto);
220
221         return (in_pto);
222       }
223     default: assert (0 && "Proj(Proj(?))");
224     }
225     /* done with case (in_op == iro_Proj) */
226
227   case (iro_Load):              /* ProjV (Load) */
228     assert (pn_Load_res == proj_proj);
229     /* FALLTHROUGH */
230   case (iro_Call):              /* ProjT (Call) */
231     /* FALLTHROUGH */
232   case (iro_Alloc):             /* ProjV (Alloc) */
233     if (NULL != proj_pto) {
234       return (proj_pto);
235     } else {
236       in_pto = get_pto (proj_in, env);
237       assert (in_pto);
238
239       set_node_pto (proj, in_pto);
240       return (in_pto);
241     }
242   default:
243     fprintf (stderr, "%s: not handled: proj (%s[%li])\n",
244              __FUNCTION__,
245              get_op_name (get_irn_op (proj_in)),
246              get_irn_node_nr (proj_in));
247     assert (0 && "Proj(?)");
248   }
249
250 }
251
252 static pto_t *get_pto_phi (ir_node *phi, pto_env_t *env)
253 {
254   assert (mode_P == get_irn_mode (phi));
255
256   pto_t *pto = get_node_pto (phi);
257   int change = FALSE;
258
259   assert (pto);                 /* must be initialised */
260
261   int n_ins = get_irn_arity (phi);
262   int i;
263
264   for (i = 0; i < n_ins; i ++) {
265     ir_node *in = get_irn_n (phi, i);
266     pto_t *in_pto = get_pto (in, env);
267
268     assert (in_pto);
269
270     change |= qset_insert_all (pto->values, in_pto->values);
271   }
272
273   env->change |= change;
274
275   return (pto);
276 }
277
278 static pto_t *get_pto_sel (ir_node *sel, pto_env_t *env)
279 {
280   pto_t *pto = NULL; /* get_node_pto (sel); */
281
282   if (NULL == pto) {
283     ir_node *in = get_Sel_ptr (sel);
284
285     pto = get_pto (in, env);
286     set_node_pto (sel, pto);
287   }
288
289   return (pto);
290 }
291
292 static pto_t *get_pto_ret (ir_node *ret, pto_env_t *env)
293 {
294   pto_t *pto = NULL; /* get_node_pto (ret); */
295
296   if (NULL == pto) {
297     ir_node *in = get_Return_res (ret, 0);
298
299     pto = get_pto (in, env);
300     set_node_pto (ret, pto);
301   }
302
303   assert (pto);
304
305   DBGPRINT (9, (stdout, "%s: ", __FUNCTION__));
306   DBGEXE (9, pto_print_pto (ret));
307
308   return (pto);
309 }
310
311
312 /* Dispatch to propagate PTO values */
313 static pto_t *get_pto (ir_node *node, pto_env_t *env)
314 {
315   const opcode op = get_irn_opcode (node);
316
317   DBGPRINT (2, (stdout, "%s (%s[%li])\n", __FUNCTION__,
318                 OPNAME (node), OPNUM (node)));
319
320   switch (op) {
321   case (iro_Cast):   return (get_pto (get_Cast_op (node), env));
322   case (iro_Proj):   return (get_pto_proj  (node, env));
323   case (iro_Phi):    return (get_pto_phi   (node, env));
324   case (iro_Sel):    return (get_pto_sel   (node, env));
325   case (iro_Alloc):  return (get_alloc_pto (node));
326   case (iro_Return): return (get_pto_ret   (node, env));
327
328   case (iro_Call):              /* FALLTHROUGH */
329   case (iro_Load):              /* FALLTHROUGH */
330   case (iro_Const):             /* FALLTHROUGH */
331   case (iro_SymConst):{
332     pto_t *pto = get_node_pto (node);
333
334     assert (pto);
335     return (pto);
336   }
337   default:
338     /* stopgap measure */
339     fprintf (stderr, "%s: not handled: node[%li].op = %s\n",
340              __FUNCTION__,
341              get_irn_node_nr (node),
342              get_op_name (get_irn_op (node)));
343     assert (0 && "something not handled");
344
345   }
346 }
347
348
349 /* Actions for the nodes: */
350 static void pto_load (ir_node *load, pto_env_t *pto_env)
351 {
352   /* perform load */
353   DBGPRINT (2, (stdout, "%s (%s[%li]): pto = 0x%08x\n", __FUNCTION__,
354                 OPNAME (load), OPNUM (load), (void*) get_node_pto (load)));
355
356   ir_node *ptr = get_Load_ptr (load);
357
358   if (is_dummy_load_ptr (ptr)) {
359     return;
360   }
361
362   entity *ent = get_ptr_ent (ptr);
363
364   if (mode_P == get_type_mode (get_entity_type (ent))) {
365     pto_t *ptr_pto = get_pto (ptr, pto_env);
366
367     assert (ptr_pto);
368
369     DBGPRINT (1, (stdout, "%s (%s[%li]): ptr = 0x%08x\n", __FUNCTION__,
370                   OPNAME (ptr), OPNUM (ptr), (void*) ptr_pto));
371
372     pto_env->change |= mod_load (load, ent, ptr_pto);
373   }
374 }
375
376 static void pto_store (ir_node *store, pto_env_t *pto_env)
377 {
378   /* perform store */
379   DBGPRINT (2, (stdout, "%s (%s[%li]) (no pto)\n", __FUNCTION__,
380                 OPNAME (store), OPNUM (store)));
381
382   ir_node *ptr = get_Store_ptr (store);
383   ir_node *val = get_Store_value (store);
384
385   if (mode_P != get_irn_mode (val)) {
386     return;
387   }
388
389   entity *ent = get_ptr_ent (ptr);
390
391   pto_t *ptr_pto = get_pto (ptr, pto_env);
392   pto_t *val_pto = get_pto (val, pto_env);
393
394   assert (ptr_pto);
395   assert (val_pto);
396
397   DBGPRINT (2, (stdout, "%s (%s[%li]): ptr_pto = 0x%08x\n", __FUNCTION__,
398                 OPNAME (ptr), OPNUM (ptr), (void*) ptr_pto));
399   DBGPRINT (2, (stdout, "%s (%s[%li]): val_pto = 0x%08x\n", __FUNCTION__,
400                 OPNAME (val), OPNUM (val), (void*) val_pto));
401
402   pto_env->change |= mod_store (store, ent, ptr_pto, val_pto);
403 }
404
405 static void pto_method (ir_node *call, pto_env_t *pto_env)
406 {
407   DBGPRINT (2, (stdout, "%s:%i (%s[%li]): pto = 0x%08x\n",
408                 __FUNCTION__, __LINE__, OPNAME (call), OPNUM (call),
409                 (void*) get_node_pto (call)));
410
411   callEd_info_t *callEd_info = ecg_get_callEd_info (call);
412
413   if (NULL == callEd_info) {
414     DBGPRINT (2, (stdout, "%s:%i (%s[%li]), no graph\n",
415                   __FUNCTION__, __LINE__, OPNAME (call), OPNUM (call)));
416   }
417
418   int i = 0;
419   while (NULL != callEd_info) {
420     DBGPRINT (2, (stdout, "%s:%i (%s[%li]), graph %i\n",
421                   __FUNCTION__, __LINE__, OPNAME (call), OPNUM (call), i ++));
422
423     pto_call (callEd_info->callEd, call, pto_env);
424
425     callEd_info = callEd_info->prev;
426   }
427 }
428
429 /* Perform the appropriate action on the given node */
430 static void pto_node_node (ir_node *node, pto_env_t *pto_env)
431 {
432   DBGPRINT (1, (stdout, "%s (%s[%li])\n", __FUNCTION__,
433                 OPNAME (node), OPNUM (node)));
434
435   const opcode op = get_irn_opcode (node);
436
437   switch (op) {
438   case (iro_Start): /* nothing */ break;
439   case (iro_Load):
440     pto_load (node, pto_env);
441     break;
442
443   case (iro_Store):
444     pto_store (node, pto_env);
445     break;
446
447   case (iro_Call):
448     pto_method (node, pto_env);
449     break;
450
451   case (iro_Raise):
452     pto_raise (node, pto_env);
453     break;
454
455   case (iro_Return):
456     /* nothing to do */
457     break;
458
459   case (iro_Alloc):
460     /* nothing to do */
461     break;
462
463   case (iro_Block):
464     pto_end_block (node, pto_env);
465     break;
466
467   case (iro_Phi):
468     /* must be a PhiM */
469     assert (mode_M == get_irn_mode (node));
470     /* nothing to do */
471     break;
472
473     /* uninteresting stuff: */
474   case (iro_Div):
475   case (iro_Quot):
476   case (iro_Mod):
477   case (iro_DivMod): /* nothing to do */ break;
478
479   default:
480     /* stopgap measure */
481     fprintf (stderr, "%s: not handled: node[%li].op = %s\n",
482              __FUNCTION__,
483              get_irn_node_nr (node),
484              get_op_name (get_irn_op (node)));
485     assert (0 && "something not handled");
486   }
487 }
488
489
490 /* Callback function to execute in pre-order */
491 static void pto_node_pre (ir_node *node, void *env)
492 {
493   /* nothing */
494 }
495
496 /* Callback function to execute in post-order */
497 static void pto_node_post (ir_node *node, void *env)
498 {
499   pto_env_t *pto_env = (pto_env_t*) env;
500
501   DBGPRINT (999, (stdout, "%s (%s[%li])\n", __FUNCTION__,
502                 OPNAME (node), OPNUM (node)));
503
504   pto_node_node (node, pto_env);
505 }
506
507 /* Perform a single pass over the given graph */
508 static void pto_graph_pass (ir_graph *graph, void *pto_env)
509 {
510   irg_walk_mem (graph, pto_node_pre, pto_node_post, pto_env);
511 }
512
513 /* Continue PTO for one of the graphs called at a Call */
514 static void pto_call (ir_graph *graph, ir_node *call, pto_env_t *pto_env)
515 {
516   int change = FALSE;
517
518   /* only for debugging stuff: */
519   entity *ent = get_irg_entity (graph);
520   const char *ent_name = (char*) get_entity_name (ent);
521   const char *own_name = (char*) get_type_name (get_entity_owner (ent));
522
523   /* perform call */
524   DBGPRINT (2, (stdout, "%s (%s[%li]) to \"%s.%s\"\n",
525                 __FUNCTION__, OPNAME (call), OPNUM (call),
526                 own_name, ent_name));
527
528   if (! get_irg_is_mem_visited (graph)) {
529     /* handle direct call */
530     graph_info_t *ginfo = ecg_get_info (graph);
531
532     /* Save CTX */
533     int ctx_idx = find_ctx_idx (call, ginfo, get_curr_ctx ());
534     ctx_info_t *call_ctx = get_ctx (ginfo, ctx_idx);
535     ctx_info_t *old_ctx = set_curr_ctx (call_ctx);
536
537     DBGPRINT (1, (stdout, "%s>CTX: ", -- spaces));
538     DBGEXE (1, ecg_print_ctx (call_ctx, stdout));
539
540     /* Initialise Alloc Names and Node values */
541     pto_reset_graph_pto (graph, ctx_idx);
542
543     /* Compute Arguments */
544     set_graph_args (graph, call, pto_env);
545
546     /* Visit/Iterate Graph */
547     pto_graph (graph, ctx_idx, pto_env);
548
549     /* Restore CTX */
550     set_curr_ctx (old_ctx);
551
552     /* Get Return Value from Graph */
553     change |= set_graph_result (graph, call);
554
555     DBGPRINT (1, (stdout, "%s<CTX: ", spaces ++));
556     DBGEXE (1, ecg_print_ctx (call_ctx, stdout));
557
558     /* Don't need to reset alloc names unless we handle recursion here  */
559   } else {
560     /* handle recursion */
561     DBGPRINT (0, (stdout, "%s: recursion into \"%s.%s\"\n",
562                   __FUNCTION__, own_name, ent_name));
563     /* Find 'right' enclosing pto_env */
564     pto_env_t *enc_env = pto_env;
565
566     while (graph != enc_env->graph) {
567       enc_env = enc_env->enc_env; /* talk about naming issues here */
568
569       /* since we're in a recursion loop, we *must* find an env for the callEd here: */
570       assert (NULL != enc_env->enc_env);
571     }
572
573     /* Re-Set arguments */
574     int rec_change = add_graph_args (graph, call, pto_env);
575
576       DBGPRINT (1, (stdout, "%s: return  in:", __FUNCTION__));
577       DBGEXE (1, pto_print_pto (get_irg_end_block (graph)));
578
579     if (rec_change) {
580       DBGPRINT (0, (stdout, "%s: change args", __FUNCTION__));
581     }
582
583     rec_change |= set_graph_result (graph, call);
584
585     if (rec_change) {
586       DBGPRINT (0, (stdout, "%s: return out:", __FUNCTION__));
587       DBGEXE (0, pto_print_pto (get_irg_end_block (graph)));
588     }
589
590 # if 0
591     /* appears that we don't need this: */
592     enc_env->change |= rec_change;
593 # endif /* 0 */
594   }
595
596   /* Todo: Set 'Unknown' Value as Return Value when the graph is not
597      known */
598
599   pto_env->change |= change;
600 }
601
602 static void pto_raise (ir_node *raise, pto_env_t *pto_env)
603 {
604   /* perform raise */
605   DBGPRINT (2, (stdout, "%s (%s[%li]): pto = 0x%08x\n", __FUNCTION__,
606                 OPNAME (raise), OPNUM (raise), (void*) get_node_pto (raise)));
607 }
608
609 static void pto_end_block (ir_node *end_block, pto_env_t *pto_env)
610 {
611   /* perform end block */
612   type *tp = get_entity_type (get_irg_entity (get_irn_irg (end_block)));
613
614   if (0 == get_method_n_ress (tp)) {
615     return;
616   }
617
618   tp = get_method_res_type (tp, 0);
619
620   if (mode_P != get_type_mode (tp)) {
621     return;
622   }
623
624   DBGPRINT (2, (stdout, "%s (%s[%li]): pto = 0x%08x\n", __FUNCTION__,
625                 OPNAME (end_block), OPNUM (end_block),
626                 (void*) get_node_pto (end_block)));
627
628   pto_t *end_pto = get_node_pto (end_block);
629
630   assert (end_pto);
631
632   int n_ins = get_irn_arity (end_block);
633   int i;
634   for (i = 0; i < n_ins; i ++) {
635     ir_node *in = get_irn_n (end_block, i);
636
637     if (iro_Return == get_irn_opcode (in)) {
638       pto_t *in_pto = get_pto (in, pto_env);
639
640       pto_env->change |= qset_insert_all (end_pto->values, in_pto->values);
641     }
642   }
643 }
644
645 /* ===================================================
646    Exported Implementation:
647    =================================================== */
648 /* Main loop: Initialise and iterate over the given graph */
649 void pto_graph (ir_graph *graph, int ctx_idx, pto_env_t *enc_env)
650 {
651   /* Also exported, since we need it in 'pto.c' */
652   pto_env_t *pto_env = xmalloc (sizeof (pto_env_t));
653   pto_env->enc_env = enc_env;
654   pto_env->graph   = graph;
655   pto_env->ctx_idx = ctx_idx;
656   pto_env->change  = TRUE;
657
658   /* HERE ("start"); */
659
660   DBGPRINT (2, (stdout, "%s: start for ctx %i\n",
661                 __FUNCTION__,
662                 ctx_idx));
663
664   /* todo (here): iterate, obey 'changed' attribute */
665   int run = 0;
666   while (0 != pto_env->change) {
667     run ++;
668     pto_env->change = FALSE;
669     pto_graph_pass (graph, pto_env);
670   }
671
672   DBGPRINT (1, (stdout, "%s: %i runs on \"%s.%s\"\n",
673                 __FUNCTION__,
674                 run,
675                 get_type_name (get_entity_owner (get_irg_entity (graph))),
676                 get_entity_name (get_irg_entity (graph))));
677
678
679   memset (pto_env, 0x00, sizeof (pto_env_t));
680   free (pto_env);
681   /* HERE ("end"); */
682 }
683
684 /* Set the PTO value for the given non-alloc node */
685 void set_node_pto (ir_node *node, pto_t *pto)
686 {
687   assert (iro_Alloc != get_irn_opcode (node));
688
689   set_irn_link (node, (void*) pto);
690 }
691
692 /*Get the PTO value for the given non-alloc node */
693 pto_t *get_node_pto (ir_node *node)
694 {
695   assert (iro_Alloc != get_irn_opcode (node));
696
697   return ((pto_t*) get_irn_link (node));
698 }
699
700 /* Set the PTO value for the given alloc node */
701 void set_alloc_pto (ir_node *alloc, alloc_pto_t *alloc_pto)
702 {
703   assert (iro_Alloc == get_irn_opcode (alloc));
704
705   assert (alloc_pto);
706
707   set_irn_link (alloc, (void*) alloc_pto);
708 }
709
710 /*Get the current PTO value for the given alloc node */
711 pto_t *get_alloc_pto (ir_node *alloc)
712 {
713   alloc_pto_t *alloc_pto = (alloc_pto_t*) get_irn_link (alloc);
714
715   assert (iro_Alloc == get_irn_opcode (alloc));
716
717   assert (alloc_pto -> curr_pto);
718
719   return (alloc_pto -> curr_pto);
720 }
721
722 \f
723 /*
724   $Log$
725   Revision 1.10  2004/12/20 17:34:35  liekweg
726   fix recursion handling
727
728   Revision 1.9  2004/12/15 13:31:18  liekweg
729   remove debugging stuff
730
731   Revision 1.8  2004/12/15 09:18:18  liekweg
732   pto_name.c
733
734   Revision 1.7  2004/12/06 12:55:06  liekweg
735   actually iterate
736
737   Revision 1.6  2004/12/02 16:17:51  beck
738   fixed config.h include
739
740   Revision 1.5  2004/11/30 14:47:54  liekweg
741   fix initialisation; do correct iteration
742
743   Revision 1.4  2004/11/26 15:59:40  liekweg
744   verify pto_{load,store}
745
746   Revision 1.3  2004/11/24 14:53:55  liekweg
747   Bugfixes
748
749   Revision 1.2  2004/11/20 21:21:56  liekweg
750   Finalise initialisation
751
752   Revision 1.1  2004/11/18 16:37:34  liekweg
753   rewritten
754
755
756 */