besched: Change sched_foreach_from(sched_next(x), y) to sched_foreach_after(x, y).
[libfirm] / ir / be / bestate.c
1 /*
2  * This file is part of libFirm.
3  * Copyright (C) 2012 University of Karlsruhe.
4  */
5
6 /**
7  * @file
8  * @brief       Handles state switching. This is basically the belady spill
9  *              algorithm optimized for the 1-register case.
10  * @author      Matthias Braun
11  * @date        26.03.2007
12  */
13 #include "config.h"
14
15 #include "bestate.h"
16
17 #include "obst.h"
18 #include "irgraph_t.h"
19 #include "irnode_t.h"
20 #include "irgwalk.h"
21 #include "irloop.h"
22 #include "iredges_t.h"
23 #include "ircons_t.h"
24 #include "irgmod.h"
25 #include "irnodeset.h"
26 #include "irnodehashmap.h"
27 #include "cpset.h"
28
29 #include "bearch.h"
30 #include "beirg.h"
31 #include "beuses.h"
32 #include "besched.h"
33 #include "belive_t.h"
34 #include "bemodule.h"
35 #include "benode.h"
36 #include "beirgmod.h"
37 #include "bespillutil.h"
38 #include "bessaconstr.h"
39
40 DEBUG_ONLY(static firm_dbg_module_t *dbg = NULL;)
41
42 typedef struct spill_info_t {
43         struct spill_info_t *next;
44         ir_node *value;
45         ir_node *spill;
46         ir_node **reloads;
47 } spill_info_t;
48
49 typedef struct minibelady_env_t {
50         struct obstack         obst;
51         const arch_register_t *reg;
52         const be_lv_t         *lv;
53         void                  *func_env;
54         create_reload_func     create_reload;
55         create_spill_func      create_spill;
56         spill_info_t          *spills;
57         ir_nodehashmap_t       spill_infos;
58
59         be_uses_t             *uses;           /**< env for the next-use magic */
60 } minibelady_env_t;
61
62 typedef struct block_info_t {
63         ir_node *start_state;
64         ir_node *end_state;
65 } block_info_t;
66
67 static inline block_info_t *new_block_info(struct obstack *obst, ir_node *block)
68 {
69         block_info_t *res = OALLOCZ(obst, block_info_t);
70
71         assert(is_Block(block));
72         set_irn_link(block, res);
73         mark_irn_visited(block);
74
75         return res;
76 }
77
78 static inline block_info_t *get_block_info(ir_node *block)
79 {
80         assert(irn_visited(block));
81         return (block_info_t*) get_irn_link(block);
82 }
83
84 static inline spill_info_t *create_spill_info(minibelady_env_t *env, ir_node *state)
85 {
86         spill_info_t *spill_info = OALLOCZ(&env->obst, spill_info_t);
87         spill_info->value = state;
88         spill_info->reloads = NEW_ARR_F(ir_node*, 0);
89
90         ir_nodehashmap_insert(&env->spill_infos, state, spill_info);
91         //ir_fprintf(stderr, "Insert %+F -> %p\n", state, spill_info);
92
93         spill_info->next = env->spills;
94         env->spills = spill_info;
95
96         return spill_info;
97 }
98
99 static inline spill_info_t *get_spill_info(minibelady_env_t *env, const ir_node *node)
100 {
101         spill_info_t *spill_info = ir_nodehashmap_get(spill_info_t, &env->spill_infos, node);
102         //ir_fprintf(stderr, "Get %+F -> %p\n", node, spill_info);
103         return spill_info;
104 }
105
106 static spill_info_t *create_spill(minibelady_env_t *env, ir_node *state, int force)
107 {
108         spill_info_t *spill_info;
109         ir_node *next;
110         ir_node *after;
111
112         spill_info = get_spill_info(env, state);
113         if (spill_info == NULL) {
114                 spill_info = create_spill_info(env, state);
115         } else if (spill_info->spill != NULL) {
116                 return spill_info;
117         }
118
119         if (sched_is_scheduled(state)) {
120                 next = state;
121                 do {
122                         after = next;
123                         next = sched_next(after);
124                 } while (is_Phi(next) || be_is_Keep(next));
125         } else {
126                 after = state;
127         }
128         spill_info->spill = env->create_spill(env->func_env, state, force, after);
129
130         return spill_info;
131 }
132
133 static void create_reload(minibelady_env_t *env, ir_node *state,
134                           ir_node *before, ir_node *last_state)
135 {
136         spill_info_t *spill_info = create_spill(env, state, 0);
137         ir_node *spill = spill_info->spill;
138         ir_node *reload;
139
140         reload = env->create_reload(env->func_env, state, spill, before,
141                                     last_state);
142         ARR_APP1(ir_node*, spill_info->reloads, reload);
143 }
144
145 static void spill_phi(minibelady_env_t *env, ir_node *phi)
146 {
147         ir_graph     *irg           = get_irn_irg(phi);
148         ir_node      *block         = get_nodes_block(phi);
149         int           arity         = get_irn_arity(phi);
150         ir_node     **phi_in        = ALLOCAN(ir_node*, arity);
151         ir_node      *dummy         = new_r_Dummy(irg, mode_M);
152         ir_node      *spill_to_kill = NULL;
153         spill_info_t *spill_info;
154         int           i;
155
156         /* does a spill exist for the phis value? */
157         spill_info = get_spill_info(env, phi);
158         if (spill_info != NULL) {
159                 spill_to_kill = spill_info->spill;
160         } else {
161                 spill_info = create_spill_info(env, phi);
162         }
163
164         /* create a new phi-M with bad preds */
165         for (i = 0; i < arity; ++i) {
166                 phi_in[i] = dummy;
167         }
168
169         DBG((dbg, LEVEL_2, "\tcreate Phi-M for %+F\n", phi));
170
171         /* create a Phi-M */
172         spill_info->spill = be_new_Phi(block, arity, phi_in, mode_M,
173                                        arch_no_register_req);
174         sched_add_after(block, spill_info->spill);
175
176         if (spill_to_kill != NULL) {
177                 exchange(spill_to_kill, spill_info->spill);
178                 sched_remove(spill_to_kill);
179         }
180
181         /* create spills for the phi values */
182         for (i = 0; i < arity; ++i) {
183                 ir_node *in = get_irn_n(phi, i);
184                 spill_info_t *pred_spill = create_spill(env, in, 1);
185                 set_irn_n(spill_info->spill, i, pred_spill->spill);
186         }
187 }
188
189 static void belady(minibelady_env_t *env, ir_node *block);
190
191 /**
192  * Collects all values live-in at block @p block and all phi results in this
193  * block.
194  * Then it adds the best values (at most n_regs) to the blocks start_workset.
195  * The phis among the remaining values get spilled: Introduce pseudo-copies of
196  * their args to break interference and make it possible to spill them to the
197  * same spill slot.
198  */
199 static block_info_t *compute_block_start_state(minibelady_env_t *env, ir_node *block)
200 {
201         block_info_t  *block_info;
202         be_next_use_t  next_use;
203         ir_loop       *loop;
204         ir_node       *best_starter, *first;
205         int            n_cfgpreds;
206         unsigned       best_time;
207         int            outer_loop_allowed;
208
209         /* Create the block info for this block. */
210         block_info = new_block_info(&env->obst, block);
211         n_cfgpreds = get_Block_n_cfgpreds(block);
212
213         /* no cfgpred -> no value active */
214         if (n_cfgpreds == 0) {
215                 block_info->start_state = NULL;
216                 return block_info;
217         }
218
219         /* for 1 pred only: simply take the the end-state of the pred */
220         if (n_cfgpreds == 1) {
221                 ir_node *pred_block = get_Block_cfgpred_block(block, 0);
222                 block_info_t *pred_info;
223
224                 /* process pred block */
225                 belady(env, pred_block);
226
227                 pred_info = get_block_info(pred_block);
228
229                 DBG((dbg, LEVEL_2, "Taking end state from %+F: %+F\n", pred_block, pred_info->end_state));
230                 block_info->start_state = pred_info->end_state;
231                 return block_info;
232         }
233
234         /* Collect all values living at start of block */
235         DBG((dbg, LEVEL_2, "Living at start of %+F:\n", block));
236         first = sched_first(block);
237         loop = get_irn_loop(block);
238         best_starter = NULL;
239         best_time = USES_INFINITY;
240         outer_loop_allowed = 1;
241
242         /* check all Phis first */
243         sched_foreach(block, node) {
244                 if (!is_Phi(node))
245                         break;
246                 if (arch_get_irn_register(node) != env->reg)
247                         continue;
248
249                 DBG((dbg, LEVEL_2, "\t...checking %+F\n", node));
250                 next_use = be_get_next_use(env->uses, first, node, 0);
251
252                 if (USES_IS_INFINITE(next_use.time)) {
253                         DBG((dbg, LEVEL_2, "\tnot taken (dead)\n"));
254                         continue;
255                 }
256
257                 if (next_use.outermost_loop >= get_loop_depth(loop)) {
258                         if (outer_loop_allowed || next_use.time < best_time) {
259                                 DBG((dbg, LEVEL_2, "\ttaken (%u, loop %d)\n", next_use.time,
260                                      next_use.outermost_loop));
261
262                                 if (best_starter != NULL) {
263                                         /* spill the phi as it is not used */
264                                         spill_phi(env, best_starter);
265                                 }
266                                 best_starter = node;
267                                 best_time = next_use.time;
268                                 outer_loop_allowed = 0;
269                         }
270                 } else {
271                         if (outer_loop_allowed && next_use.time < best_time) {
272                                 DBG((dbg, LEVEL_2, "\ttaken (%u, loop %d)\n", next_use.time,
273                                      next_use.outermost_loop));
274                                 if (best_starter != NULL) {
275                                         /* spill the phi as it is not used */
276                                         spill_phi(env, best_starter);
277                                 }
278                                 best_starter = node;
279                                 best_time = next_use.time;
280                         }
281                 }
282
283                 if (best_starter != node) {
284                         /* spill the phi as it is not used */
285                         spill_phi(env, best_starter);
286                 }
287         }
288
289         /* check all Live-Ins */
290         be_lv_foreach_cls(env->lv, block, be_lv_state_in, env->reg->reg_class, node) {
291                 if (arch_get_irn_register(node) != env->reg)
292                         continue;
293
294                 DBG((dbg, LEVEL_2, "\t...checking %+F\n", node));
295                 next_use = be_get_next_use(env->uses, first, node, 0);
296
297                 if (USES_IS_INFINITE(next_use.time)) {
298                         DBG((dbg, LEVEL_2, "\tnot taken (dead)\n"));
299                         continue;
300                 }
301
302                 if (next_use.outermost_loop >= get_loop_depth(loop)) {
303                         if (outer_loop_allowed || next_use.time < best_time) {
304                                 DBG((dbg, LEVEL_2, "\ttaken (%u, loop %d)\n", next_use.time,
305                                      next_use.outermost_loop));
306
307                                 if (best_starter != NULL && is_Phi(best_starter)) {
308                                         /* spill the phi as it is not used */
309                                         spill_phi(env, best_starter);
310                                 }
311                                 best_starter = node;
312                                 best_time = next_use.time;
313                                 outer_loop_allowed = 0;
314                         }
315                 } else {
316                         if (outer_loop_allowed && next_use.time < best_time) {
317                                 DBG((dbg, LEVEL_2, "\ttaken (%u, loop %d)\n", next_use.time,
318                                      next_use.outermost_loop));
319                                 if (best_starter != NULL && is_Phi(best_starter)) {
320                                         /* spill the phi as it is not used */
321                                         spill_phi(env, best_starter);
322                                 }
323                                 best_starter = node;
324                                 best_time = next_use.time;
325                         }
326                 }
327         }
328
329         block_info->start_state = best_starter;
330
331         return block_info;
332 }
333
334 /**
335  * For the given block @p block, decide for each values
336  * whether it is used from a register or is reloaded
337  * before the use.
338  */
339 static void belady(minibelady_env_t *env, ir_node *block)
340 {
341         ir_node *current_state;
342         block_info_t *block_info;
343
344         /* Don't do a block twice */
345         if (irn_visited(block))
346                 return;
347
348         /* compute value to start with */
349         block_info = compute_block_start_state(env, block);
350
351         /* get the starting workset for this block */
352         DBG((dbg, LEVEL_3, "\n"));
353         DBG((dbg, LEVEL_3, "Decide for %+F\n", block));
354
355         current_state = block_info->start_state;
356         DBG((dbg, LEVEL_3, "Start value: %+F\n", current_state));
357
358         /* process the block from start to end */
359         DBG((dbg, LEVEL_3, "Processing...\n"));
360
361         sched_foreach(block, node) {
362                 int i, arity;
363                 ir_node *need_val = NULL;
364
365                 /* Phis are no real instr (see insert_starters()) */
366                 if (is_Phi(node))
367                         continue;
368
369                 /* check which state is desired for the node */
370                 arity = get_irn_arity(node);
371                 for (i = 0; i < arity; ++i) {
372                         const arch_register_t *reg;
373                         ir_node *in = get_irn_n(node, i);
374
375                         if (!mode_is_data(get_irn_mode(in)))
376                                 continue;
377
378                         reg = arch_get_irn_register(in);
379                         if (reg == env->reg) {
380                                 assert(need_val == NULL);
381                                 need_val = in;
382                                 DBG((dbg, LEVEL_3, "\t... need state %+F\n", need_val));
383                         }
384                 }
385                 /* create a reload to match state if necessary */
386                 if (need_val != NULL && need_val != current_state) {
387                         ir_node *before = node;
388                         DBG((dbg, LEVEL_3, "\t... reloading %+F\n", need_val));
389                         create_reload(env, need_val, before, current_state);
390                         current_state = need_val;
391                 }
392
393                 DBG((dbg, LEVEL_3, "  ...%+F\n", node));
394
395                 /* record state changes by the node */
396                 be_foreach_value(node, value,
397                         if (!mode_is_data(get_irn_mode(value)))
398                                 continue;
399                         arch_register_t const *const reg = arch_get_irn_register(value);
400                         if (reg != env->reg)
401                                 continue;
402                         current_state = value;
403                         DBG((dbg, LEVEL_3, "\t... current_state <- %+F\n", current_state));
404                 );
405         }
406
407         /* Remember end-workset for this block */
408         block_info->end_state = current_state;
409         DBG((dbg, LEVEL_3, "End value for %+F: %+F\n", block, current_state));
410 }
411
412 static void belady_walker(ir_node *block, void *data)
413 {
414         belady((minibelady_env_t*) data, block);
415 }
416
417 /**
418  * We must adapt the live-outs to the live-ins at each block-border.
419  */
420 static void fix_block_borders(ir_node *block, void *data)
421 {
422         minibelady_env_t *env = (minibelady_env_t*)data;
423         int i;
424         int arity;
425         block_info_t *block_info;
426
427         DBG((dbg, LEVEL_3, "\n"));
428
429         block_info = get_block_info(block);
430
431         DBG((dbg, LEVEL_3, "Fixing %+F (needs %+F)\n", block,
432              block_info->start_state));
433
434         /* process all pred blocks */
435         arity = get_irn_arity(block);
436         for (i = 0; i < arity; ++i) {
437                 ir_node      *pred       = get_Block_cfgpred_block(block, i);
438                 block_info_t *pred_info  = get_block_info(pred);
439                 ir_node      *need_state = block_info->start_state;
440
441                 if (need_state == NULL)
442                         continue;
443
444                 if (is_Phi(need_state) && get_nodes_block(need_state) == block) {
445                         need_state = get_irn_n(need_state, i);
446                 }
447
448                 DBG((dbg, LEVEL_3, "  Pred %+F (ends in %+F, we need %+F)\n", pred,
449                      pred_info->end_state, need_state));
450
451                 if (pred_info->end_state != need_state) {
452                         DBG((dbg, LEVEL_3, "  Creating reload for %+F\n", need_state));
453                         ir_node *const insert_point = be_get_end_of_block_insertion_point(pred);
454                         create_reload(env, need_state, insert_point, pred_info->end_state);
455                 }
456         }
457 }
458
459 void be_assure_state(ir_graph *irg, const arch_register_t *reg, void *func_env,
460                      create_spill_func create_spill,
461                      create_reload_func create_reload)
462 {
463         minibelady_env_t env;
464         spill_info_t *info;
465         be_lv_t *lv = be_get_irg_liveness(irg);
466
467         be_assure_live_sets(irg);
468         assure_loopinfo(irg);
469
470         obstack_init(&env.obst);
471         env.reg           = reg;
472         env.func_env      = func_env;
473         env.create_spill  = create_spill;
474         env.create_reload = create_reload;
475         env.lv            = be_get_irg_liveness(irg);
476         env.uses          = be_begin_uses(irg, env.lv);
477         env.spills        = NULL;
478         ir_nodehashmap_init(&env.spill_infos);
479
480         assure_doms(irg);
481         ir_reserve_resources(irg, IR_RESOURCE_IRN_VISITED | IR_RESOURCE_IRN_LINK);
482         inc_irg_visited(irg);
483
484         /* process blocks */
485         irg_block_walk_graph(irg, NULL, belady_walker, &env);
486
487         /* fix block end_states that don't match the next blocks start_state */
488         irg_block_walk_graph(irg, fix_block_borders, NULL, &env);
489
490         ir_free_resources(irg, IR_RESOURCE_IRN_VISITED | IR_RESOURCE_IRN_LINK);
491
492         /* reconstruct ssa-form */
493         info = env.spills;
494         while (info != NULL) {
495                 be_ssa_construction_env_t senv;
496                 size_t i, len;
497                 ir_node **phis;
498
499                 be_ssa_construction_init(&senv, irg);
500                 if (sched_is_scheduled(info->value))
501                         be_ssa_construction_add_copy(&senv, info->value);
502                 be_ssa_construction_add_copies(&senv,
503                                                info->reloads, ARR_LEN(info->reloads));
504                 be_ssa_construction_fix_users(&senv, info->value);
505
506                 if (lv != NULL) {
507                         be_ssa_construction_update_liveness_phis(&senv, lv);
508
509                         be_liveness_update(lv, info->value);
510                         len = ARR_LEN(info->reloads);
511                         for (i = 0; i < len; ++i) {
512                                 ir_node *reload = info->reloads[i];
513                                 be_liveness_update(lv, reload);
514                         }
515                 }
516
517                 phis = be_ssa_construction_get_new_phis(&senv);
518
519                 /* set register requirements for phis */
520                 len = ARR_LEN(phis);
521                 for (i = 0; i < len; ++i) {
522                         ir_node *phi = phis[i];
523                         arch_set_irn_register(phi, env.reg);
524                 }
525                 be_ssa_construction_destroy(&senv);
526
527                 info = info->next;
528         }
529
530         /* some nodes might be dead now. */
531         be_remove_dead_nodes_from_schedule(irg);
532
533         ir_nodehashmap_destroy(&env.spill_infos);
534         be_end_uses(env.uses);
535         obstack_free(&env.obst, NULL);
536 }
537
538 BE_REGISTER_MODULE_CONSTRUCTOR(be_init_state)
539 void be_init_state(void)
540 {
541         FIRM_DBG_REGISTER(dbg, "firm.be.state");
542 }