ae8f0cb95e7cf455c111410aa6296e8454691598
[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
30 # include "irnode.h"
31 # include "irprog.h"
32 # include "xmalloc.h"
33 # include "irmemwalk.h"
34
35 # include "pto_debug.h"
36 # include "pto_init.h"
37
38 # include "ecg.h"
39
40 /* Local Defines: */
41
42 /* Local Data Types: */
43 typedef struct pto_env_str {
44   int ctx_idx;
45 } pto_env_t;
46
47
48 /* Local Variables: */
49
50 /* Debug only: */
51 char *spaces = NULL;
52
53 /* Local Prototypes: */
54 static void pto_call (ir_graph*, ir_node*, pto_env_t*);
55
56 /* ===================================================
57    Local Implementation:
58    =================================================== */
59
60 /* Propagation of PTO values */
61 static pto_t *get_pto_proj (ir_node *proj)
62 {
63   ir_node *proj_in = get_Proj_pred (proj);
64   const long proj_proj = get_Proj_proj (proj);
65   const opcode in_op = get_irn_opcode (proj_in);
66   pto_t *in_pto = NULL;
67   pto_t *proj_pto = get_node_pto (proj);
68
69   ir_node *proj_in_in = NULL;
70
71   switch (in_op) {
72   case (iro_Start):             /* ProjT (Start) */
73     assert (0 && "pto from ProjT(Start) requested");
74
75     return (NULL);
76   case (iro_Proj):              /* ProjT (Start), ProjT (Call) */
77     proj_in_in = get_Proj_pred (proj_in);
78     const opcode in_in_op = get_irn_opcode (proj_in_in);
79     const long proj_in_proj = get_Proj_proj (proj_in);
80
81     assert ((pn_Start_T_args == proj_in_proj) ||
82             (pn_Call_T_result == proj_in_proj));
83
84     switch (in_in_op) {
85     case (iro_Start):           /* ProjArg (ProjT (Start)) */
86       /* then the pto value must have been set to the node */
87       assert (proj_pto);
88
89       return (proj_pto);
90     case (iro_Call):            /* ProjV (ProjT (Call)) */
91       if (NULL != proj_pto) {
92         return (proj_pto);
93       } else {
94         in_pto = get_node_pto (proj_in);
95         set_node_pto (proj, in_pto);
96
97         return (in_pto);
98       }
99     default: assert (0 && "Proj(Proj(?))");
100     }
101     /* done with case (in_op == iro_Proj) */
102
103   case (iro_Load):              /* ProjV (Load) */
104     assert (pn_Load_res == proj_proj);
105     /* FALLTHROUGH */
106   case (iro_Call):              /* ProjT (Call) */
107     /* FALLTHROUGH */
108   case (iro_Alloc):             /* ProjV (Alloc) */
109     if (NULL != proj_pto) {
110       return (proj_pto);
111     } else {
112       in_pto = get_node_pto (proj_in);
113       assert (in_pto);
114
115       set_node_pto (proj, in_pto);
116       return (in_pto);
117     }
118   default:
119     fprintf (stderr, "%s: not handled: proj (%s[%li])\n",
120              __FUNCTION__,
121              get_op_name (get_irn_op (proj_in)),
122              get_irn_node_nr (proj_in));
123     assert (0 && "Proj(?)");
124   }
125
126 }
127
128 static pto_t *get_pto_phi (ir_node *phi)
129 {
130   return (NULL);
131 }
132
133 static pto_t *get_pto_sel (ir_node *sel)
134 {
135   pto_t *pto = get_node_pto (sel);
136
137   if (NULL == pto) {
138     ir_node *in = get_Sel_ptr (sel);
139
140     pto = get_node_pto (in);
141     set_node_pto (sel, pto);
142   }
143
144   return (pto);
145 }
146
147 static pto_t *get_pto_ret (ir_node *ret)
148 {
149   pto_t *pto = get_node_pto (ret);
150
151   if (NULL == pto) {
152     ir_node *in = get_Return_res (ret, 0);
153
154     pto = get_node_pto (in);
155     set_node_pto (ret, pto);
156   }
157
158   return (pto);
159 }
160
161
162 /* Dispatch to propagate PTO values */
163 static pto_t *get_pto (ir_node *node)
164 {
165   const opcode op = get_irn_opcode (node);
166
167   switch (op) {
168   case (iro_Cast):   return (get_pto (get_Cast_op (node)));
169   case (iro_Proj):   return (get_pto_proj (node));
170   case (iro_Phi):    return (get_pto_phi (node));
171   case (iro_Sel):    return (get_pto_sel (node));
172   case (iro_Return): return (get_pto_ret (node));
173
174   default:
175     /* stopgap measure */
176     fprintf (stderr, "%s: not handled: node[%li].op = %s\n",
177              __FUNCTION__,
178              get_irn_node_nr (node),
179              get_op_name (get_irn_op (node)));
180     assert (0 && "something not handled");
181
182   }
183 }
184
185
186 /* Actions for the nodes: */
187 static void pto_load (ir_node *load, pto_env_t *pto_env)
188 {
189   /* perform load */
190   DBGPRINT (0, (stdout, "%s (%s[%li]): pto = %p\n", __FUNCTION__, OPNAME (load), OPNUM (load), (void*) get_node_pto (load)));
191
192   ir_node *ptr = get_Load_ptr (load);
193   pto_t *ptr_pto = get_pto (ptr);
194
195   DBGPRINT (0, (stdout, "%s (%s[%li]): ptr = %p\n", __FUNCTION__, OPNAME (ptr), OPNUM (ptr), (void*) ptr_pto));
196 }
197
198 static void pto_store (ir_node *store, pto_env_t *pto_env)
199 {
200   /* perform store */
201   DBGPRINT (0, (stdout, "%s (%s[%li]) (no pto)\n", __FUNCTION__,
202                 OPNAME (store), OPNUM (store)));
203 }
204
205 static void pto_method (ir_node *call, pto_env_t *pto_env)
206 {
207   DBGPRINT (0, (stdout, "%s:%i (%s[%li]): pto = %p\n",
208                 __FUNCTION__, __LINE__, OPNAME (call), OPNUM (call), (void*) get_node_pto (call)));
209
210   callEd_info_t *callEd_info = ecg_get_callEd_info (call);
211
212   int i = 0;
213   while (NULL != callEd_info) {
214     DBGPRINT (0, (stdout, "%s:%i (%s[%li]), graph %i\n",
215                   __FUNCTION__, __LINE__, OPNAME (call), OPNUM (call), i ++));
216
217     /* dike this out until we do procedure arguments and return
218        values */
219     if (0) {
220       pto_call (callEd_info->callEd, call, pto_env);
221     }
222
223     callEd_info = callEd_info->prev;
224   }
225 }
226
227
228 /* Continue PTO for one of the graphs called at a Call */
229 static void pto_call (ir_graph *graph, ir_node *call, pto_env_t *pto_env)
230 {
231   /* perform call */
232   DBGPRINT (0, (stdout, "%s:%i (%s[%li])\n",
233                 __FUNCTION__, __LINE__, OPNAME (call), OPNUM (call)));
234
235   /* only for debugging stuff: */
236   entity *ent = get_irg_entity (graph);
237   const char *ent_name = (char*) get_entity_name (ent);
238   const char *own_name = (char*) get_type_name (get_entity_owner (ent));
239
240   if (! get_irg_is_mem_visited (graph)) {
241     graph_info_t *ginfo = ecg_get_info (graph);
242
243     /* Save CTX */
244     int ctx_idx = find_ctx_idx (call, ginfo, get_curr_ctx ());
245     ctx_info_t *call_ctx = get_ctx (ginfo, ctx_idx);
246     ctx_info_t *old_ctx = set_curr_ctx (call_ctx);
247     DBGPRINT (1, (stdout, "%s>CTX: ", -- spaces));
248     DBGEXE (1, ecg_print_ctx (call_ctx, stdout));
249
250     /* Todo: Compute Arguments */
251
252     /* Initialise Alloc Names and Node values (nope, done in pto_graph ()) */
253     /* pto_reset_graph_pto (graph, ctx_idx); */
254
255     /* Visit/Iterate Graph */
256     pto_graph (graph, ctx_idx);
257
258     /* Restore CTX */
259     set_curr_ctx (old_ctx);
260
261     DBGPRINT (1, (stdout, "%s<CTX: ", spaces ++));
262     DBGEXE (1, ecg_print_ctx (call_ctx, stdout));
263
264     /* Don't need to reset alloc names unless we handle recursion here  */
265
266
267     /* Get Return Value from Graph */
268   } else {
269     DBGPRINT (0, (stdout, "%s: recursion into \"%s.%s\"\n",
270                   __FUNCTION__, own_name, ent_name));
271   }
272
273   /* Todo: Set 'Unknown' Value as Return Value when the graph is not
274      known */
275 }
276
277 static void pto_raise (ir_node *raise, pto_env_t *pto_env)
278 {
279   /* perform raise */
280   DBGPRINT (0, (stdout, "%s (%s[%li]): pto = %p\n", __FUNCTION__,
281                 OPNAME (raise), OPNUM (raise), (void*) get_node_pto (raise)));
282 }
283
284 static void pto_end_block (ir_node *end_block, pto_env_t *pto_env)
285 {
286   /* perform end block */
287   DBGPRINT (0, (stdout, "%s (%s[%li]): pto = %p\n", __FUNCTION__,
288                 OPNAME (end_block), OPNUM (end_block),
289                 (void*) get_node_pto (end_block)));
290 }
291
292 /* Perform the appropriate action on the given node */
293 static void pto_node_node (ir_node *node, pto_env_t *pto_env)
294 {
295   const opcode op = get_irn_opcode (node);
296
297   switch (op) {
298   case (iro_Start): /* nothing */ break;
299   case (iro_Load):
300     pto_load (node, pto_env);
301     break;
302
303   case (iro_Store):
304     pto_store (node, pto_env);
305     break;
306
307   case (iro_Call):
308     pto_method (node, pto_env);
309     break;
310
311   case (iro_Raise):
312     pto_raise (node, pto_env);
313     break;
314
315   case (iro_Return):
316     /* nothing to do */
317     break;
318
319   case (iro_Alloc):
320     /* nothing to do */
321     break;
322
323   case (iro_Block):
324     pto_end_block (node, pto_env);
325     break;
326
327   case (iro_Phi):
328     /* must be a PhiM */
329     assert (mode_M == get_irn_mode (node));
330     /* nothing to do */
331     break;
332
333     /* uninteresting stuff: */
334   case (iro_Div):
335   case (iro_Quot):
336   case (iro_Mod):
337   case (iro_DivMod): /* nothing to do */ break;
338
339   default:
340     /* stopgap measure */
341     fprintf (stderr, "%s: not handled: node[%li].op = %s\n",
342              __FUNCTION__,
343              get_irn_node_nr (node),
344              get_op_name (get_irn_op (node)));
345     assert (0 && "something not handled");
346   }
347
348
349
350 }
351
352
353 /* Callback function to execute in pre-order */
354 static void pto_node_pre (ir_node *node, void *env)
355 {
356   /* nothing */
357 }
358
359 /* Callback function to execute in post-order */
360 static void pto_node_post (ir_node *node, void *env)
361 {
362   pto_env_t *pto_env = (pto_env_t*) env;
363
364   pto_node_node (node, pto_env);
365 }
366
367 /* Perform a single pass over the given graph */
368 static void pto_graph_pass (ir_graph *graph, void *pto_env)
369 {
370   entity *ent = get_irg_entity (graph);
371   const char *ent_name = (char*) get_entity_name (ent);
372   const char *own_name = (char*) get_type_name (get_entity_owner (ent));
373   HERE3 ("start", own_name, ent_name);
374
375   irg_walk_mem (graph, pto_node_pre, pto_node_post, pto_env);
376
377   HERE3 ("end  ", own_name, ent_name);
378 }
379
380
381 /* ===================================================
382    Exported Implementation:
383    =================================================== */
384 /* Main loop: Initialise and iterate over the given graph */
385 void pto_graph (ir_graph *graph, int ctx_idx)
386 {
387   pto_env_t *pto_env = xmalloc (sizeof (pto_env_t));
388   pto_env->ctx_idx = ctx_idx;
389
390   /* HERE ("start"); */
391
392   DBGPRINT (0, (stdout, "%s: start for ctx %i\n",
393                 __FUNCTION__,
394                 ctx_idx));
395
396   /* todo: pto_reset_graph_pto */
397   pto_reset_graph_pto (graph, ctx_idx);
398
399   /* todo (here): iterate, obey 'changed' attribute */
400   pto_graph_pass (graph, pto_env);
401
402   memset (pto_env, 0x00, sizeof (pto_env_t));
403   free (pto_env);
404   HERE ("end");
405 }
406
407 /* Set the PTO value for the given non-alloc node */
408 void set_node_pto (ir_node *node, pto_t *pto)
409 {
410   assert (iro_Alloc != get_irn_opcode (node));
411
412   set_irn_link (node, (void*) pto);
413 }
414
415 /*Get the PTO value for the given non-alloc node */
416 pto_t *get_node_pto (ir_node *node)
417 {
418   assert (iro_Alloc != get_irn_opcode (node));
419
420   return ((pto_t*) get_irn_link (node));
421 }
422
423 /* Set the PTO value for the given alloc node */
424 void set_alloc_pto (ir_node *alloc, alloc_pto_t *alloc_pto)
425 {
426   assert (iro_Alloc == get_irn_opcode (alloc));
427
428   set_irn_link (alloc, (void*) alloc_pto);
429 }
430
431 /*Get the current PTO value for the given alloc node */
432 pto_t *get_alloc_pto (ir_node *alloc)
433 {
434   alloc_pto_t *alloc_pto = (alloc_pto_t*) get_irn_link (alloc);
435
436   assert (iro_Alloc == get_irn_opcode (alloc));
437
438   return (alloc_pto -> curr_pto);
439 }
440
441 \f
442 /*
443   $Log$
444   Revision 1.3  2004/11/24 14:53:55  liekweg
445   Bugfixes
446
447   Revision 1.2  2004/11/20 21:21:56  liekweg
448   Finalise initialisation
449
450   Revision 1.1  2004/11/18 16:37:34  liekweg
451   rewritten
452
453
454 */