Added exc.c exc.h
[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
21 static char* exc_strings [] = {
22   "Invalid",
23   "Normal",
24   "Region Entry",
25   "Handler Entry",
26   "Cont"
27 };
28
29
30 /*
31   Return true iff (block b is a handler entry AND a dominates b) OR
32   (b has a CFG successor that is both a handler entry AND is dominated
33   by a)
34 */
35 static bool has_handler (ir_graph *graph, ir_node *b, ir_node *a)
36 {
37   int i         = 0;
38   int n         = get_irn_n_outs (b);
39   ir_node *succ = 0;
40
41   assert (0 && "Wrongly implemented");
42   // must check for _immediate_ dominance !!!
43
44   if (is_handler_entry (graph, b) && dominates (graph, a, b))
45         return (true);
46
47   for (i = 0; i < n; i ++)
48         {
49           succ = get_irn_out (b, i);
50
51           if (has_handler (graph, succ, a))
52                 return (true);
53         }
54
55   return (false);
56 }
57
58 /*
59   Return true iff the given node represents an exception jump
60 */
61 static bool is_exc_jmp (ir_node *node)
62 {
63   ir_op *op = get_irn_op (node);
64
65   // Proj_X (Load), Proj_X (Sto), Proj_X (Div_Int),
66   // Proj_X (Raise), Proj_X (Call), Proj_X (Alloc)
67   if (op == op_Proj)
68         {
69           op = get_irn_op (get_Proj_pred (node));
70
71           // ToDo: Check for proper Proj attr?!?
72           if ((op == op_Load) || (op == op_Store)  ||
73                   (op == op_Div ) || (op == op_Raise)  ||
74                   (op == op_Call) || (op == op_Alloc))
75                 return (true);
76         }
77   else
78         {
79           return (false);
80         }
81 }
82
83 /*
84 Return true iff the given node represents a normal cfg jump
85 */
86 static bool is_cfg_jmp (ir_node *node)
87 {
88   ir_op *op = get_irn_op (node);
89
90   if (op == op_Proj)
91         {
92           op = get_irn_op (get_Proj_pred (node));
93
94           // Proj_X (Proj_Cmp (Cond))
95           if (op_Proj == op)
96                 return (true);                  /* check for op == op_Cmp and op == op_Cond */
97         }
98
99   return (false);
100 }
101
102 /*
103  Return true iff a new exception region must be left upon entry of this block.
104
105  If all CFG preds of this block are exception jumps, then we must
106  return true.
107 */
108 bool is_handler_entry (ir_graph *graph, ir_node *block)
109 {
110   bool is_entry = true;
111   int  i        = 0;
112   int  n        = get_irn_arity (block);
113   ir_node *node = 0;
114   ir_op* op     = op_Bad;
115
116   if (exc_invalid == get_Block_exc (block))
117         {
118           for (i = 0; (i < n) && is_entry; i ++)
119                 if (is_exc_jmp (get_irn_n (block, i)))
120                   continue;
121                 else
122                   is_entry = false;
123
124           if (true == is_entry)
125                 set_Block_exc (block, exc_handler);
126         }
127
128   return (exc_handler == get_Block_exc (block));
129 }
130
131 /*
132  Return true iff a new exception region must be started upon entry of this block.
133
134  If this block immediately dominates a handler entry, we must return true.
135 */
136 bool is_region_entry  (ir_graph *graph, ir_node *block)
137 {
138   assert (0 && "Not implemented");
139
140   if (exc_invalid == get_Block_exc (block))
141         {
142           int i         = 0;
143           int n         = get_irn_n_outs (block);
144           ir_node *succ = 0;
145
146           bool no_handler = true;
147
148           for (i = 0; (i < n) && no_handler; i ++)
149                 {
150                   succ = get_irn_out (block, i);
151
152                   if (has_handler (graph, succ, block))
153                         no_handler = false;
154                 }
155
156           if (false == no_handler)
157                 set_Block_exc (block, exc_region);
158         }
159
160   return (exc_region == get_Block_exc (block));
161
162   return (TRUE);
163 }
164
165 /*
166  Return true iff this block is part of handler code.
167
168  If this block is dominated by a block for which {@link
169  is_handler_entry} is true, then this block is part of the handler.
170 */
171 bool is_handler_block (ir_graph *graph, ir_node *block)
172 {
173   assert (0 && "Not implemented");
174
175   if (exc_invalid == get_Block_exc (block))
176         {
177           bool no_handler = true;
178           dom_env_t *env  = get_dom_env (graph, block);
179           int block_index = env->index_a;
180           bs_t block_mask = 0x00000001 << block_index;
181           int n_blocks    = env->dt->n_blocks;
182           int i           = 0;
183
184           for (i = 0; (i < n_blocks) && no_handler; i ++)
185                 if (0 != (env->dt->masks [i] & block_mask)) /* if dominator */
186                   if (is_handler_entry (graph, env->dt->blocks [i])) /* is handler entry */
187                         no_handler = false;
188
189           delete_dom_env (env);
190
191           if (false == no_handler)
192                 set_Block_exc (block, exc_handler);
193         }
194
195   return (exc_handler == get_Block_exc (block));
196 }
197
198 /*
199  Return true iff a new exception region must be left upon exit of the
200  non-exception blocks among the CFG predecessors of this block.
201
202  If this block has CFG predecessors that are partly handler blocks and
203  partly normal blocks, then we must return true.
204 */
205 bool is_cont_entry    (ir_graph *graph, ir_node *block)
206 {
207   assert (0 && "Not implemented");
208
209   if (exc_invalid == get_Block_exc (block))
210         {
211           bool has_exc = false;         /* wether we have exception cfg predecessors */
212           bool has_cfg = false;         /* wether we have normal cfg predecessors */
213
214           int i = 0;
215           int n = get_irn_arity (block);
216
217           ir_node *pred = 0;
218
219           for (i = 0; (i < n) && (!has_exc && !has_cfg); i ++)
220                 {
221                   pred = get_irn_n (block, i);
222
223                   if (is_exc_jmp (pred))
224                         has_exc = true;
225                   else if (is_cfg_jmp (pred))
226                         has_cfg = true;
227                 }
228
229           if (has_cfg && has_exc)
230                 set_Block_exc (block, exc_cont);
231         }
232
233   return (exc_cont == get_Block_exc (block));
234 }
235
236 /*
237   Convert a value of type exc_t to a descriptive string.
238   Returns a reference to a statically allocated, constant string.
239 */
240
241 const char *exc_to_string (exc_t exc)
242 {
243   int exc_val = (int) exc;
244
245   assert ((0 <= (int) exc_val) && (exc_val < (int) exc_max));
246
247   return (exc_strings [exc_val]);
248 }