fix initialisation; do correct iteration
[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.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   int ctx_idx;
46   int change;
47 } pto_env_t;
48
49
50 /* Local Variables: */
51
52 /* Debug only: */
53 char *spaces = NULL;
54
55 /* Local Prototypes: */
56 static pto_t *get_pto (ir_node*);
57 static void pto_call (ir_graph*, ir_node*, pto_env_t*);
58 static void pto_raise (ir_node*, pto_env_t*);
59 static void pto_load (ir_node*, pto_env_t*);
60 static void pto_store (ir_node*, pto_env_t*);
61 static void pto_method (ir_node*, pto_env_t*);
62 static void pto_end_block (ir_node*, pto_env_t*);
63
64 /* ===================================================
65    Local Implementation:
66    =================================================== */
67 /* Transfer the actual arguments to the formal arguments */
68 static void set_graph_args (ir_graph *graph, ir_node *call)
69 {
70   assert (iro_Call == get_irn_opcode (call));
71
72   type *meth = get_entity_type (get_irg_entity (graph));
73   ir_node **args = find_irg_args (graph);
74   int n_args = get_Call_n_params (call);
75   int i;
76
77   for (i = 0; i < n_args; i ++) {
78     if (NULL != args [i]) {
79       if (mode_P == get_type_mode (get_method_param_type (meth, i))) {
80         ir_node *call_arg = get_Call_param (call, i);
81         pto_t *pto = get_pto (call_arg);
82         assert (pto);
83         set_node_pto (args [i], pto);
84
85         DBGPRINT (1, (stdout, "%s: arg [%i]: %s[%li] -> %s[%li] (%i)\n",
86                       __FUNCTION__,
87                       i,
88                       OPNAME (call_arg), OPNUM (call_arg),
89                       OPNAME (args [i]), OPNUM (args [i]),
90                       pto->values->id));
91       }
92     }
93   }
94 }
95
96 /* Transfer the graph's result to the call */
97 static int set_graph_result (ir_graph *graph, ir_node *call)
98 {
99   type *tp = get_entity_type (get_irg_entity (graph));
100   int change = FALSE;
101
102   if (0 == get_method_n_ress (tp)) {
103     return (change);
104   }
105
106   tp = get_method_res_type (tp, 0);
107
108   if (mode_P != get_type_mode (tp)) {
109     set_node_pto (call, NULL);
110
111     return (change);
112   }
113
114   ir_node *end_block = get_irg_end_block (graph);
115   pto_t *ret_pto = get_node_pto (end_block);
116
117   pto_t *call_pto = get_node_pto (call);
118
119   assert (call_pto);
120
121   change |= qset_insert_all (call_pto->values, ret_pto->values);
122
123   return (change);
124 }
125
126 /* Propagation of PTO values */
127 static pto_t *get_pto_proj (ir_node *proj)
128 {
129   ir_node *proj_in = get_Proj_pred (proj);
130   const long proj_proj = get_Proj_proj (proj);
131   const opcode in_op = get_irn_opcode (proj_in);
132   pto_t *in_pto = NULL;
133   pto_t *proj_pto = get_node_pto (proj);
134
135   ir_node *proj_in_in = NULL;
136
137   switch (in_op) {
138   case (iro_Start):             /* ProjT (Start) */
139     assert (0 && "pto from ProjT(Start) requested");
140
141     return (NULL);
142   case (iro_Proj):              /* ProjT (Start), ProjT (Call) */
143     proj_in_in = get_Proj_pred (proj_in);
144     const opcode in_in_op = get_irn_opcode (proj_in_in);
145     const long proj_in_proj = get_Proj_proj (proj_in);
146
147     assert ((pn_Start_T_args == proj_in_proj) ||
148             (pn_Call_T_result == proj_in_proj));
149
150     switch (in_in_op) {
151     case (iro_Start):           /* ProjArg (ProjT (Start)) */
152       /* then the pto value must have been set to the node */
153       assert (proj_pto);
154
155       return (proj_pto);
156     case (iro_Call):            /* ProjV (ProjT (Call)) */
157       if (NULL != proj_pto) {
158         return (proj_pto);
159       } else {
160         in_pto = get_pto (proj_in);
161         set_node_pto (proj, in_pto);
162
163         assert (in_pto);
164
165         return (in_pto);
166       }
167     default: assert (0 && "Proj(Proj(?))");
168     }
169     /* done with case (in_op == iro_Proj) */
170
171   case (iro_Load):              /* ProjV (Load) */
172     assert (pn_Load_res == proj_proj);
173     /* FALLTHROUGH */
174   case (iro_Call):              /* ProjT (Call) */
175     /* FALLTHROUGH */
176   case (iro_Alloc):             /* ProjV (Alloc) */
177     if (NULL != proj_pto) {
178       return (proj_pto);
179     } else {
180       in_pto = get_pto (proj_in);
181       assert (in_pto);
182
183       set_node_pto (proj, in_pto);
184       return (in_pto);
185     }
186   default:
187     fprintf (stderr, "%s: not handled: proj (%s[%li])\n",
188              __FUNCTION__,
189              get_op_name (get_irn_op (proj_in)),
190              get_irn_node_nr (proj_in));
191     assert (0 && "Proj(?)");
192   }
193
194 }
195
196 static pto_t *get_pto_phi (ir_node *phi)
197 {
198   assert (mode_P == get_irn_mode (phi));
199
200   pto_t *pto = get_node_pto (phi);
201
202   assert (pto);                 /* must be initialised */
203
204   int n_ins = get_irn_arity (phi);
205   int i;
206
207   for (i = 0; i < n_ins; i ++) {
208     ir_node *in = get_irn_n (phi, i);
209     pto_t *in_pto = get_pto (in);
210
211     assert (in_pto);
212
213     qset_insert_all (pto->values, in_pto->values);
214   }
215
216   return (pto);
217 }
218
219 static pto_t *get_pto_sel (ir_node *sel)
220 {
221   pto_t *pto = get_node_pto (sel);
222
223   if (NULL == pto) {
224     ir_node *in = get_Sel_ptr (sel);
225
226     pto = get_pto (in);
227     set_node_pto (sel, pto);
228   }
229
230   return (pto);
231 }
232
233 static pto_t *get_pto_ret (ir_node *ret)
234 {
235   pto_t *pto = get_node_pto (ret);
236
237   if (NULL == pto) {
238     ir_node *in = get_Return_res (ret, 0);
239
240     pto = get_pto (in);
241     set_node_pto (ret, pto);
242   }
243
244   assert (pto);
245
246   return (pto);
247 }
248
249
250 /* Dispatch to propagate PTO values */
251 static pto_t *get_pto (ir_node *node)
252 {
253   const opcode op = get_irn_opcode (node);
254
255   switch (op) {
256   case (iro_Cast):   return (get_pto (get_Cast_op (node)));
257   case (iro_Proj):   return (get_pto_proj (node));
258   case (iro_Phi):    return (get_pto_phi (node));
259   case (iro_Sel):    return (get_pto_sel (node));
260   case (iro_Alloc):  return (get_alloc_pto (node));
261   case (iro_Return): return (get_pto_ret (node));
262
263   case (iro_Call):              /* FALLTHROUGH */
264   case (iro_Load):              /* FALLTHROUGH */
265   case (iro_Const):             /* FALLTHROUGH */
266   case (iro_SymConst): return (get_node_pto (node));
267
268   default:
269     /* stopgap measure */
270     fprintf (stderr, "%s: not handled: node[%li].op = %s\n",
271              __FUNCTION__,
272              get_irn_node_nr (node),
273              get_op_name (get_irn_op (node)));
274     assert (0 && "something not handled");
275
276   }
277 }
278
279
280 /* Actions for the nodes: */
281 static void pto_load (ir_node *load, pto_env_t *pto_env)
282 {
283   /* perform load */
284   DBGPRINT (2, (stdout, "%s (%s[%li]): pto = %p\n", __FUNCTION__,
285                 OPNAME (load), OPNUM (load), (void*) get_node_pto (load)));
286
287   ir_node *ptr = get_Load_ptr (load);
288
289   if (is_dummy_load_ptr (ptr)) {
290     return;
291   }
292
293   entity *ent = get_ptr_ent (ptr);
294   pto_t *ptr_pto = get_pto (ptr);
295
296   assert (ptr_pto);
297
298   DBGPRINT (1, (stdout, "%s (%s[%li]): ptr = %p\n", __FUNCTION__,
299                 OPNAME (ptr), OPNUM (ptr), (void*) ptr_pto));
300
301   pto_env->change |= mod_load (load, ent, ptr_pto);
302 }
303
304 static void pto_store (ir_node *store, pto_env_t *pto_env)
305 {
306   /* perform store */
307   DBGPRINT (2, (stdout, "%s (%s[%li]) (no pto)\n", __FUNCTION__,
308                 OPNAME (store), OPNUM (store)));
309
310   ir_node *ptr = get_Store_ptr (store);
311   ir_node *val = get_Store_value (store);
312
313   if (mode_P != get_irn_mode (val)) {
314     return;
315   }
316
317   entity *ent = get_ptr_ent (ptr);
318
319   pto_t *ptr_pto = get_pto (ptr);
320   pto_t *val_pto = get_pto (val);
321
322   assert (ptr_pto);
323   assert (val_pto);
324
325   DBGPRINT (1, (stdout, "%s (%s[%li]): ptr_pto = %p\n", __FUNCTION__,
326                 OPNAME (store), OPNUM (store), (void*) ptr_pto));
327   DBGPRINT (1, (stdout, "%s (%s[%li]): val_pto = %p\n", __FUNCTION__,
328                 OPNAME (store), OPNUM (store), (void*) val_pto));
329
330   pto_env->change |= mod_store (store, ent, ptr_pto, val_pto);
331 }
332
333 static void pto_method (ir_node *call, pto_env_t *pto_env)
334 {
335   DBGPRINT (2, (stdout, "%s:%i (%s[%li]): pto = %p\n",
336                 __FUNCTION__, __LINE__, OPNAME (call), OPNUM (call),
337                 (void*) get_node_pto (call)));
338
339   callEd_info_t *callEd_info = ecg_get_callEd_info (call);
340
341   if (NULL == callEd_info) {
342     DBGPRINT (2, (stdout, "%s:%i (%s[%li]), no graph\n",
343                   __FUNCTION__, __LINE__, OPNAME (call), OPNUM (call)));
344   }
345
346   int i = 0;
347   while (NULL != callEd_info) {
348     DBGPRINT (2, (stdout, "%s:%i (%s[%li]), graph %i\n",
349                   __FUNCTION__, __LINE__, OPNAME (call), OPNUM (call), i ++));
350
351     pto_call (callEd_info->callEd, call, pto_env);
352
353     callEd_info = callEd_info->prev;
354   }
355 }
356
357 /* Perform the appropriate action on the given node */
358 static void pto_node_node (ir_node *node, pto_env_t *pto_env)
359 {
360   DBGPRINT (1, (stdout, "%s (%s[%li])\n", __FUNCTION__,
361                 OPNAME (node), OPNUM (node)));
362
363   const opcode op = get_irn_opcode (node);
364
365   switch (op) {
366   case (iro_Start): /* nothing */ break;
367   case (iro_Load):
368     pto_load (node, pto_env);
369     break;
370
371   case (iro_Store):
372     pto_store (node, pto_env);
373     break;
374
375   case (iro_Call):
376     pto_method (node, pto_env);
377     break;
378
379   case (iro_Raise):
380     pto_raise (node, pto_env);
381     break;
382
383   case (iro_Return):
384     /* nothing to do */
385     break;
386
387   case (iro_Alloc):
388     /* nothing to do */
389     break;
390
391   case (iro_Block):
392     pto_end_block (node, pto_env);
393     break;
394
395   case (iro_Phi):
396     /* must be a PhiM */
397     assert (mode_M == get_irn_mode (node));
398     /* nothing to do */
399     break;
400
401     /* uninteresting stuff: */
402   case (iro_Div):
403   case (iro_Quot):
404   case (iro_Mod):
405   case (iro_DivMod): /* nothing to do */ break;
406
407   default:
408     /* stopgap measure */
409     fprintf (stderr, "%s: not handled: node[%li].op = %s\n",
410              __FUNCTION__,
411              get_irn_node_nr (node),
412              get_op_name (get_irn_op (node)));
413     assert (0 && "something not handled");
414   }
415 }
416
417
418 /* Callback function to execute in pre-order */
419 static void pto_node_pre (ir_node *node, void *env)
420 {
421   /* nothing */
422 }
423
424 /* Callback function to execute in post-order */
425 static void pto_node_post (ir_node *node, void *env)
426 {
427   pto_env_t *pto_env = (pto_env_t*) env;
428
429   pto_node_node (node, pto_env);
430 }
431
432 /* Perform a single pass over the given graph */
433 static void pto_graph_pass (ir_graph *graph, void *pto_env)
434 {
435   entity *ent = get_irg_entity (graph);
436   const char *ent_name = (char*) get_entity_name (ent);
437   const char *own_name = (char*) get_type_name (get_entity_owner (ent));
438   /* HERE3 ("start", own_name, ent_name); */
439
440   irg_walk_mem (graph, pto_node_pre, pto_node_post, pto_env);
441
442   /* HERE3 ("end  ", own_name, ent_name); */
443 }
444
445 /* Continue PTO for one of the graphs called at a Call */
446 static void pto_call (ir_graph *graph, ir_node *call, pto_env_t *pto_env)
447 {
448   int change = FALSE;
449
450   /* perform call */
451   DBGPRINT (1, (stdout, "%s:%i (%s[%li])\n",
452                 __FUNCTION__, __LINE__, OPNAME (call), OPNUM (call)));
453
454   /* only for debugging stuff: */
455   entity *ent = get_irg_entity (graph);
456   const char *ent_name = (char*) get_entity_name (ent);
457   const char *own_name = (char*) get_type_name (get_entity_owner (ent));
458
459   if (! get_irg_is_mem_visited (graph)) {
460     graph_info_t *ginfo = ecg_get_info (graph);
461
462     /* Save CTX */
463     int ctx_idx = find_ctx_idx (call, ginfo, get_curr_ctx ());
464     ctx_info_t *call_ctx = get_ctx (ginfo, ctx_idx);
465     ctx_info_t *old_ctx = set_curr_ctx (call_ctx);
466     DBGPRINT (3, (stdout, "%s>CTX: ", -- spaces));
467     DBGEXE (3, ecg_print_ctx (call_ctx, stdout));
468
469     /* Initialise Alloc Names and Node values */
470     pto_reset_graph_pto (graph, ctx_idx);
471
472     /* Compute Arguments */
473     set_graph_args (graph, call);
474
475     /* Visit/Iterate Graph */
476     pto_graph (graph, ctx_idx);
477
478     /* Restore CTX */
479     set_curr_ctx (old_ctx);
480
481     change |= set_graph_result (graph, call);
482
483     DBGPRINT (3, (stdout, "%s<CTX: ", spaces ++));
484     DBGEXE (3, ecg_print_ctx (call_ctx, stdout));
485
486     /* Don't need to reset alloc names unless we handle recursion here  */
487
488
489     /* Get Return Value from Graph */
490   } else {
491     DBGPRINT (2, (stdout, "%s: recursion into \"%s.%s\"\n",
492                   __FUNCTION__, own_name, ent_name));
493   }
494
495   /* Todo: Set 'Unknown' Value as Return Value when the graph is not
496      known */
497
498   pto_env->change |= change;
499 }
500
501 static void pto_raise (ir_node *raise, pto_env_t *pto_env)
502 {
503   /* perform raise */
504   DBGPRINT (2, (stdout, "%s (%s[%li]): pto = %p\n", __FUNCTION__,
505                 OPNAME (raise), OPNUM (raise), (void*) get_node_pto (raise)));
506 }
507
508 static void pto_end_block (ir_node *end_block, pto_env_t *pto_env)
509 {
510   /* perform end block */
511   type *tp = get_entity_type (get_irg_entity (get_irn_irg (end_block)));
512
513   if (0 == get_method_n_ress (tp)) {
514     return;
515   }
516
517   tp = get_method_res_type (tp, 0);
518
519   if (mode_P != get_type_mode (tp)) {
520     return;
521   }
522
523   DBGPRINT (2, (stdout, "%s (%s[%li]): pto = %p\n", __FUNCTION__,
524                 OPNAME (end_block), OPNUM (end_block),
525                 (void*) get_node_pto (end_block)));
526
527   pto_t *end_pto = get_node_pto (end_block);
528
529   assert (end_pto);
530
531   int n_ins = get_irn_arity (end_block);
532   int i;
533   for (i = 0; i < n_ins; i ++) {
534     ir_node *in = get_irn_n (end_block, i);
535
536     if (iro_Return == get_irn_opcode (in)) {
537       pto_t *in_pto = get_pto (in);
538
539       pto_env->change |= qset_insert_all (end_pto->values, in_pto->values);
540     }
541   }
542 }
543
544 /* ===================================================
545    Exported Implementation:
546    =================================================== */
547 /* Main loop: Initialise and iterate over the given graph */
548 void pto_graph (ir_graph *graph, int ctx_idx)
549 {
550   /* Also exported, since we need it in 'pto.c' */
551   pto_env_t *pto_env = xmalloc (sizeof (pto_env_t));
552   pto_env->ctx_idx = ctx_idx;
553   pto_env->change = TRUE;
554
555   /* HERE ("start"); */
556
557   DBGPRINT (2, (stdout, "%s: start for ctx %i\n",
558                 __FUNCTION__,
559                 ctx_idx));
560
561   /* todo (here): iterate, obey 'changed' attribute */
562   int run = 0;
563   while (0 != pto_env->change) {
564     run ++;
565     pto_env->change = FALSE;
566     pto_graph_pass (graph, pto_env);
567   }
568
569   DBGPRINT (1, (stdout, "%s: %i runs on \"%s.%s\"\n",
570                 __FUNCTION__,
571                 run,
572                 get_type_name (get_entity_owner (get_irg_entity (graph))),
573                 get_entity_name (get_irg_entity (graph))));
574
575
576   memset (pto_env, 0x00, sizeof (pto_env_t));
577   free (pto_env);
578   /* HERE ("end"); */
579 }
580
581 /* Set the PTO value for the given non-alloc node */
582 void set_node_pto (ir_node *node, pto_t *pto)
583 {
584   assert (iro_Alloc != get_irn_opcode (node));
585
586   set_irn_link (node, (void*) pto);
587 }
588
589 /*Get the PTO value for the given non-alloc node */
590 pto_t *get_node_pto (ir_node *node)
591 {
592   assert (iro_Alloc != get_irn_opcode (node));
593
594   return ((pto_t*) get_irn_link (node));
595 }
596
597 /* Set the PTO value for the given alloc node */
598 void set_alloc_pto (ir_node *alloc, alloc_pto_t *alloc_pto)
599 {
600   assert (iro_Alloc == get_irn_opcode (alloc));
601
602   assert (alloc_pto);
603
604   set_irn_link (alloc, (void*) alloc_pto);
605 }
606
607 /*Get the current PTO value for the given alloc node */
608 pto_t *get_alloc_pto (ir_node *alloc)
609 {
610   alloc_pto_t *alloc_pto = (alloc_pto_t*) get_irn_link (alloc);
611
612   assert (iro_Alloc == get_irn_opcode (alloc));
613
614   assert (alloc_pto -> curr_pto);
615
616   return (alloc_pto -> curr_pto);
617 }
618
619 \f
620 /*
621   $Log$
622   Revision 1.5  2004/11/30 14:47:54  liekweg
623   fix initialisation; do correct iteration
624
625   Revision 1.4  2004/11/26 15:59:40  liekweg
626   verify pto_{load,store}
627
628   Revision 1.3  2004/11/24 14:53:55  liekweg
629   Bugfixes
630
631   Revision 1.2  2004/11/20 21:21:56  liekweg
632   Finalise initialisation
633
634   Revision 1.1  2004/11/18 16:37:34  liekweg
635   rewritten
636
637
638 */