Added Exception marking support --flo
[libfirm] / ir / st / exc.c
1 /* Copyright (c) 2002 by Universität Karlsruhe (TH).  All Rights Reserved */
2 //
3 // Time-stamp: <02/03/04 17:24:07 liekweg>
4 //
5
6 /***
7    NAME
8      exc
9    PURPOSE
10      Helper functions for exceptions
11    NOTES
12      not quite complete
13    HISTORY
14      liekweg - Mar 4, 2002: Created.
15    CVS:
16      $Id$
17 ***/
18
19 # include "exc.h"
20 # include "st.h"
21 # include "irop.h"
22 # include "irouts.h"
23
24 # include <bool.h>
25
26 /*
27   Return true iff (block b is a handler entry AND a dominates b) OR
28   (b has a CFG successor that is both a handler entry AND is dominated
29   by a)
30 */
31 static bool has_handler (ir_graph *graph, ir_node *b, ir_node *a)
32 {
33   int i         = 0;
34   int n         = get_irn_n_outs (b);
35   ir_node *succ = 0;
36
37   assert (0 && "Wrongly implemented");
38   // must check for _immediate_ dominance !!!
39
40   if (is_handler_entry (graph, b) && dominates (graph, a, b))
41         return (true);
42
43   for (i = 0; i < n; i ++)
44         {
45           succ = get_irn_out (b, i);
46
47           if (has_handler (graph, succ, a))
48                 return (true);
49         }
50
51   return (false);
52 }
53
54 /*
55   Return true iff the given node represents an exception jump
56 */
57 static bool is_exc_jmp (ir_node *node)
58 {
59   ir_op *op = get_irn_op (node);
60
61   // Proj_X (Load), Proj_X (Sto), Proj_X (Div_Int),
62   // Proj_X (Raise), Proj_X (Call), Proj_X (Alloc)
63   if (op == op_Proj)
64         {
65           op = get_irn_op (get_Proj_pred (node));
66
67           // ToDo: Check for proper Proj attr?!?
68           if ((op == op_Load) || (op == op_Store)  ||
69                   (op == op_Div ) || (op == op_Raise)  ||
70                   (op == op_Call) || (op == op_Alloc))
71                 return (true);
72         }
73   else
74         {
75           return (false);
76         }
77 }
78
79 /*
80 Return true iff the given node represents a normal cfg jump
81 */
82 static bool is_cfg_jmp (ir_node *node)
83 {
84   ir_op *op = get_irn_op (node);
85
86   if (op == op_Proj)
87         {
88           op = get_irn_op (get_Proj_pred (node));
89
90           // Proj_X (Proj_Cmp (Cond))
91           if (op_Proj == op)
92                 return (true);                  /* check for op == op_Cmp and op == op_Cond */
93         }
94
95   return (false);
96 }
97
98 /*
99  Return true iff a new exception region must be left upon entry of this block.
100
101  If all CFG preds of this block are exception jumps, then we must
102  return true.
103 */
104 bool is_handler_entry (ir_graph *graph, ir_node *block)
105 {
106   bool is_entry = true;
107   int  i        = 0;
108   int  n        = get_irn_arity (block);
109   ir_node *node = 0;
110   ir_op* op     = op_Bad;
111
112   if (exc_invalid == get_Block_exc (block))
113         {
114           for (i = 0; (i < n) && is_entry; i ++)
115                 if (is_exc_jmp (get_irn_n (block, i)))
116                   continue;
117                 else
118                   is_entry = false;
119
120           if (true == is_entry)
121                 set_Block_exc (block, exc_entry);
122         }
123
124   return (exc_entry == get_Block_exc (block));
125 }
126
127 /*
128  Return true iff a new exception region must be started upon entry of this block.
129
130  If this block immediately dominates a handler entry, we must return true.
131 */
132 bool is_region_entry  (ir_graph *graph, ir_node *block)
133 {
134   assert (0 && "Not implemented");
135
136   if (exc_invalid == get_Block_exc (block))
137         {
138           int i         = 0;
139           int n         = get_irn_n_outs (block);
140           ir_node *succ = 0;
141
142           bool no_handler = true;
143
144           for (i = 0; (i < n) && no_handler; i ++)
145                 {
146                   succ = get_irn_out (block, i);
147
148                   if (has_handler (graph, succ, block))
149                         no_handler = false;
150                 }
151
152           if (false == no_handler)
153                 set_Block_exc (block, exc_region);
154         }
155
156   return (exc_region == get_Block_exc (block));
157
158   return (TRUE);
159 }
160
161 /*
162  Return true iff this block is part of handler code.
163
164  If this block is dominated by a block for which {@link
165  is_handler_entry} is true, then this block is part of the handler.
166 */
167 bool is_handler_block (ir_graph *graph, ir_node *block)
168 {
169   assert (0 && "Not implemented");
170
171   if (exc_invalid == get_Block_exc (block))
172         {
173           bool no_handler = true;
174           dom_env_t *env  = get_dom_env (graph, block);
175           int block_index = env->index_a;
176           bs_t block_mask = 0x00000001 << block_index;
177           int n_blocks    = env->dt->n_blocks;
178           int i           = 0;
179
180           for (i = 0; (i < n_blocks) && no_handler; i ++)
181                 if (0 != (env->dt->masks [i] & block_mask)) /* if dominator */
182                   if (is_handler_entry (graph, env->dt->blocks [i])) /* is handler entry */
183                         no_handler = false;
184
185           delete_dom_env (env);
186
187           if (false == no_handler)
188                 set_Block_exc (block, exc_handler);
189         }
190
191   return (exc_handler == get_Block_exc (block));
192 }
193
194 /*
195  Return true iff a new exception region must be left upon exit of the
196  non-exception blocks among the CFG predecessors of this block.
197
198  If this block has CFG predecessors that are partly handler blocks and
199  partly normal blocks, then we must return true.
200 */
201 bool is_cont_entry    (ir_graph *graph, ir_node *block)
202 {
203   assert (0 && "Not implemented");
204
205   if (exc_invalid == get_Block_exc (block))
206         {
207           bool has_exc = false;         /* wether we have exception cfg predecessors */
208           bool has_cfg = false;         /* wether we have normal cfg predecessors */
209
210           int i = 0;
211           int n = get_irn_arity (block);
212
213           ir_node *pred = 0;
214
215           for (i = 0; (i < n) && (!has_exc && !has_cfg); i ++)
216                 {
217                   pred = get_irn_n (block, i);
218
219                   if (is_exc_jmp (pred))
220                         has_exc = true;
221                   else if (is_cfg_jmp (pred))
222                         has_cfg = true;
223                 }
224
225           if (has_cfg && has_exc)
226                 set_Block_exc (block, exc_cont);
227         }
228
229   return (exc_cont == get_Block_exc (block));
230 }