bearch: Disallow passing Projs to get_irn_ops().
[libfirm] / ir / ir / irpass.c
1 /*
2  * This file is part of libFirm.
3  * Copyright (C) 2012 University of Karlsruhe.
4  */
5
6 /**
7  * @file
8  * @brief     Manager for optimization passes.
9  * @author    Michael Beck
10  */
11 #include "config.h"
12
13 #include <string.h>
14 #include "adt/list.h"
15 #include "irpass_t.h"
16 #include "irgraph_t.h"
17 #include "irprog_t.h"
18 #include "irdump.h"
19 #include "irverify.h"
20 #include "ircons.h"
21 #include "xmalloc.h"
22
23 typedef void (*void_pass_func_irg)(ir_graph *irg);
24 typedef int (*int_pass_func_irg)(ir_graph *irg);
25 typedef void (*void_pass_func)(void);
26
27 void ir_graph_pass_mgr_add(ir_graph_pass_manager_t *mgr, ir_graph_pass_t *pass)
28 {
29         list_add_tail(&pass->list, &mgr->passes);
30         ++mgr->n_passes;
31         if (pass->add_to_mgr)
32                 pass->add_to_mgr(pass->context);
33 }
34
35 void ir_prog_pass_mgr_add(ir_prog_pass_manager_t *mgr, ir_prog_pass_t *pass)
36 {
37         list_add_tail(&pass->list, &mgr->passes);
38         ++mgr->n_passes;
39         if (pass->add_to_mgr)
40                 pass->add_to_mgr(pass->context);
41 }
42
43 /**
44  * wrapper for running a graph pass manager as a pass on an irprog
45  * pass manager.
46  */
47 static int run_wrapper(ir_prog *prog, void *ctx)
48 {
49         ir_graph_pass_manager_t *mgr = (ir_graph_pass_manager_t*)ctx;
50
51         (void)prog;
52         return ir_graph_pass_mgr_run(mgr);
53 }
54
55 int ir_prog_no_verify(ir_prog *prog, void *ctx)
56 {
57         (void)prog;
58         (void)ctx;
59         return 0;
60 }
61
62 void ir_prog_no_dump(ir_prog *prog, void *ctx, unsigned idx)
63 {
64         (void)prog;
65         (void)ctx;
66         (void)idx;
67 }
68
69 /**
70  * Term wrapper for a wrapped ir_graph pass manager.
71  */
72 static void term_wrapper(void *context)
73 {
74         ir_graph_pass_manager_t *mgr = (ir_graph_pass_manager_t*)context;
75         term_graph_pass_mgr(mgr);
76 }
77
78 /**
79  * Create a wrapper ir_prog pass for an ir_graph manager.
80  */
81 static ir_prog_pass_t *create_wrapper_pass(ir_graph_pass_manager_t *graph_mgr)
82 {
83         /* create a wrapper pass */
84         ir_prog_pass_t *pass = XMALLOCZ(ir_prog_pass_t);
85
86         pass->kind          = k_ir_prog_pass;
87         pass->run_on_irprog = run_wrapper;
88         pass->context       = graph_mgr;
89         pass->name          = graph_mgr->name;
90
91         /* do not verify nor dump: this is handled by the graph manager */
92         pass->verify_irprog = ir_prog_no_verify;
93         pass->dump_irprog   = ir_prog_no_dump;
94         pass->is_wrapper    = 1;
95
96         pass->add_to_mgr   = NULL;
97         pass->rem_from_mgr = term_wrapper;
98
99         return pass;
100 }
101
102 void ir_prog_pass_mgr_add_graph_pass(
103         ir_prog_pass_manager_t *mgr, ir_graph_pass_t *pass)
104 {
105         ir_graph_pass_manager_t *graph_mgr;
106         ir_prog_pass_t          *wrapper;
107
108         /* check if the last pass is a graph_pass wrapper */
109         if (! list_empty(&mgr->passes)) {
110                 wrapper = list_entry(mgr->passes.prev, ir_prog_pass_t, list);
111                 if (wrapper->is_wrapper) {
112                         graph_mgr = (ir_graph_pass_manager_t*)wrapper->context;
113
114                         ir_graph_pass_mgr_add(graph_mgr, pass);
115                         ++mgr->n_passes;
116                         return;
117                 }
118         }
119
120         /* not found, create a new wrapper */
121         graph_mgr = new_graph_pass_mgr(
122                 "graph_pass_wrapper", mgr->verify_all, mgr->dump_all);
123         graph_mgr->run_idx = mgr->run_idx + mgr->n_passes;
124
125         ir_graph_pass_mgr_add(graph_mgr, pass);
126
127         wrapper = create_wrapper_pass(graph_mgr);
128         ir_prog_pass_mgr_add(mgr, wrapper);
129 }
130
131 void ir_prog_pass_mgr_add_graph_mgr(
132         ir_prog_pass_manager_t *mgr, ir_graph_pass_manager_t *graph_mgr)
133 {
134         ir_prog_pass_t *pass = create_wrapper_pass(graph_mgr);
135
136         if (mgr->dump_all)
137                 graph_mgr->dump_all = 1;
138         if (mgr->verify_all)
139                 graph_mgr->verify_all = 1;
140         graph_mgr->run_idx = mgr->n_passes;
141
142         ir_prog_pass_mgr_add(mgr, pass);
143 }
144
145 int ir_graph_pass_mgr_run(ir_graph_pass_manager_t *mgr)
146 {
147         size_t    i;
148         int       res = 0;
149         ir_graph *rem = current_ir_graph;
150
151         /* on all graphs: beware: number of irgs might be changed */
152         for (i = 0; i < get_irp_n_irgs(); ++i) {
153                 ir_graph *irg = current_ir_graph = get_irp_irg(i);
154                 unsigned idx = mgr->run_idx;
155                 /* run every pass on every graph */
156                 list_for_each_entry(ir_graph_pass_t, pass, &mgr->passes, list) {
157                         int pass_res = pass->run_on_irg(irg, pass->context);
158                         if (pass_res != 0)
159                                 res = 1;
160                         /* verify is necessary */
161                         if (mgr->verify_all) {
162                                 if (pass->verify_irg) {
163                                         pass->verify_irg(irg, pass->context);
164                                 } else {
165                                         irg_verify(irg, 0);
166                                 }
167                         }
168                         /* dump */
169                         if (mgr->dump_all) {
170                                 if (pass->dump_irg) {
171                                         pass->dump_irg(irg, pass->context, idx);
172                                 } else {
173                                         dump_ir_graph(irg, pass->name);
174                                 }
175                         }
176                         ++idx;
177                 }
178         }
179         current_ir_graph = rem;
180         return res;
181 }
182
183 /**
184  * Verify all graphs on the given ir_prog.
185  */
186 static int irp_verify_irgs(void)
187 {
188         int    res = 1;
189         size_t i;
190         size_t n_irgs = get_irp_n_irgs();
191
192         for (i = 0; i < n_irgs; ++i)
193                 res &= irg_verify(get_irp_irg(i), 0);
194         return res;
195 }
196
197 int ir_prog_pass_mgr_run(ir_prog_pass_manager_t *mgr)
198 {
199         int res = 0;
200
201         /* run every pass on every graph */
202         unsigned idx = mgr->run_idx;
203         list_for_each_entry(ir_prog_pass_t, pass, &mgr->passes, list) {
204                 int pass_res = pass->run_on_irprog(irp, pass->context);
205                 if (pass_res != 0)
206                         res = 1;
207                 /* verify is necessary */
208                 if (mgr->verify_all) {
209                         if (pass->verify_irprog) {
210                                 pass->verify_irprog(irp, pass->context);
211                         } else {
212                                 irp_verify_irgs();
213                         }
214                 }
215                 /* dump */
216                 if (mgr->dump_all) {
217                         if (pass->dump_irprog) {
218                                 pass->dump_irprog(irp, pass->context, idx);
219                         } else {
220                                 dump_all_ir_graphs(pass->name);
221                         }
222                 }
223                 if (pass->is_wrapper) {
224                         ir_graph_pass_manager_t *graph_mgr = (ir_graph_pass_manager_t*)pass->context;
225                         idx += graph_mgr->n_passes;
226                 } else
227                         ++idx;
228         }
229         return res;
230 }
231
232 ir_graph_pass_manager_t *new_graph_pass_mgr(
233         const char *name, int verify_all, int dump_all)
234 {
235         ir_graph_pass_manager_t *res = XMALLOCZ(ir_graph_pass_manager_t);
236
237         INIT_LIST_HEAD(&res->passes);
238         res->kind       = k_ir_graph_pass_mgr;
239         res->name       = name;
240         res->run_idx    = 0;
241         res->verify_all = verify_all != 0;
242         res->dump_all   = dump_all   != 0;
243
244         return res;
245 }
246
247 ir_prog_pass_manager_t *new_prog_pass_mgr(
248         const char *name, int verify_all, int dump_all)
249 {
250         ir_prog_pass_manager_t *res = XMALLOCZ(ir_prog_pass_manager_t);
251
252         INIT_LIST_HEAD(&res->passes);
253         res->kind       = k_ir_prog_pass_mgr;
254         res->name       = name;
255         res->run_idx    = 0;
256         res->verify_all = verify_all != 0;
257         res->dump_all   = dump_all   != 0;
258
259         return res;
260 }
261
262 void term_graph_pass_mgr(ir_graph_pass_manager_t *mgr)
263 {
264         list_for_each_entry_safe(ir_graph_pass_t, pass, next, &mgr->passes, list) {
265                 if (pass->rem_from_mgr)
266                         pass->rem_from_mgr(pass->context);
267                 pass->kind = k_BAD;
268                 xfree(pass);
269         }
270         mgr->kind = k_BAD;
271         xfree(mgr);
272 }
273
274 void term_prog_pass_mgr(ir_prog_pass_manager_t *mgr)
275 {
276         list_for_each_entry_safe(ir_prog_pass_t, pass, next, &mgr->passes, list) {
277                 if (pass->rem_from_mgr)
278                         pass->rem_from_mgr(pass->context);
279                 pass->kind = k_BAD;
280                 xfree(pass);
281         }
282         mgr->kind = k_BAD;
283         xfree(mgr);
284 }
285
286 void ir_graph_pass_mgr_set_run_idx(
287         ir_graph_pass_manager_t *mgr, unsigned run_idx)
288 {
289         mgr->run_idx = run_idx;
290 }
291
292 void ir_prog_pass_mgr_set_run_idx(
293         ir_prog_pass_manager_t *mgr, unsigned run_idx)
294 {
295         mgr->run_idx = run_idx;
296 }
297
298 /**
299  * Wrapper for running void function(ir_graph *irg) as an ir_graph pass.
300  */
301 static int void_graph_wrapper(ir_graph *irg, void *context)
302 {
303         void_pass_func_irg function = (void_pass_func_irg)context;
304         function(irg);
305         return 0;
306 }
307
308 ir_graph_pass_t *def_graph_pass(
309         const char *name, void (*function)(ir_graph *irg))
310 {
311         struct ir_graph_pass_t *pass = XMALLOCZ(ir_graph_pass_t);
312
313         pass->kind       = k_ir_graph_pass;
314         pass->run_on_irg = void_graph_wrapper;
315         pass->context    = (void*)function;
316         pass->name       = name;
317
318         INIT_LIST_HEAD(&pass->list);
319
320         return pass;
321 }
322
323 /**
324  * Wrapper for running int function(ir_graph *irg) as an ir_graph pass.
325  */
326 static int int_graph_wrapper(ir_graph *irg, void *context)
327 {
328         int_pass_func_irg function = (int_pass_func_irg)context;
329         return function(irg);
330 }
331
332 ir_graph_pass_t *def_graph_pass_ret(
333                 const char *name, int (*function)(ir_graph *irg))
334 {
335         struct ir_graph_pass_t *pass = XMALLOCZ(ir_graph_pass_t);
336
337         pass->kind       = k_ir_graph_pass;
338         pass->run_on_irg = int_graph_wrapper;
339         pass->context    = (void*)function;
340         pass->name       = name;
341
342         INIT_LIST_HEAD(&pass->list);
343
344         return pass;
345 }
346
347 ir_graph_pass_t *def_graph_pass_constructor(
348         ir_graph_pass_t *pass,
349         const char *name, int (*function)(ir_graph *irg, void *context)) {
350         if (pass == NULL)
351                 pass = XMALLOCZ(ir_graph_pass_t);
352         else
353                 memset(pass, 0, sizeof(ir_graph_pass_t));
354         pass->kind       = k_ir_graph_pass;
355         pass->run_on_irg = function;
356         pass->context    = pass;
357         pass->name       = name;
358
359         INIT_LIST_HEAD(&pass->list);
360
361         return pass;
362 }
363
364 void ir_graph_pass_set_parallel(ir_graph_pass_t *pass, int flag)
365 {
366         pass->run_parallel = flag != 0;
367 }
368
369 /**
370  * Wrapper for running void function(void) as an ir_prog pass.
371  */
372 static int void_prog_wrapper(ir_prog *irp, void *context)
373 {
374         void_pass_func function = (void_pass_func)context;
375
376         (void)irp;
377         function();
378         return 0;
379 }
380
381 ir_prog_pass_t *def_prog_pass(
382         const char *name,
383         void (*function)(void))
384 {
385         struct ir_prog_pass_t *pass = XMALLOCZ(ir_prog_pass_t);
386
387         pass->kind          = k_ir_prog_pass;
388         pass->run_on_irprog = void_prog_wrapper;
389         pass->context       = (void*)function;
390         pass->name          = name;
391
392         INIT_LIST_HEAD(&pass->list);
393
394         return pass;
395 }
396
397 ir_prog_pass_t *def_prog_pass_constructor(
398         ir_prog_pass_t *pass,
399         const char *name,
400         int (*function)(ir_prog *irp, void *context))
401 {
402         if (pass == NULL)
403                 pass = XMALLOCZ(ir_prog_pass_t);
404         else
405                 memset(pass, 0, sizeof(ir_prog_pass_t));
406
407         pass->kind          = k_ir_prog_pass;
408         pass->run_on_irprog = function;
409         pass->context       = pass;
410         pass->name          = name;
411
412         INIT_LIST_HEAD(&pass->list);
413
414         return pass;
415 }
416
417 typedef struct pass_t {
418         ir_prog_pass_t pass;
419         void           *context;
420         void (*function)(void *context);
421 } pass_t;
422
423 /**
424  * Wrapper for the call_function pass.
425  */
426 static int call_function_wrapper(ir_prog *irp, void *context)
427 {
428         pass_t *pass = (pass_t*)context;
429
430         (void)irp;
431         pass->function(pass->context);
432         return 0;
433 }
434
435 ir_prog_pass_t *call_function_pass(
436         const char *name, void (*function)(void *context), void *context) {
437         struct pass_t *pass = XMALLOCZ(struct pass_t);
438
439         def_prog_pass_constructor(
440                 &pass->pass, name ? name : "set_function", call_function_wrapper);
441
442         pass->pass.verify_irprog = ir_prog_no_verify;
443         pass->pass.dump_irprog   = ir_prog_no_dump;
444         pass->pass.context       = pass;
445
446         pass->function = function;
447         pass->context  = context;
448
449         return &pass->pass;
450 }