2 * Author: Daniel Grund, Sebastian Hack, Matthias Braun
4 * Copyright: (c) Universitaet Karlsruhe
5 * Licence: This file protected by GPL - GNU GENERAL PUBLIC LICENSE.
17 #include "iredges_t.h"
18 #include "irbackedge_t.h"
27 #include "unionfind.h"
31 #include "besched_t.h"
35 #include "bechordal_t.h"
36 #include "bejavacoal.h"
37 #include "benodesets.h"
38 #include "bespilloptions.h"
39 #include "bestatevent.h"
41 // only rematerialise when costs are less than REMAT_COST_LIMIT
42 // TODO determine a good value here...
43 #define REMAT_COST_LIMIT 10
45 typedef struct _reloader_t reloader_t;
50 ir_node *rematted_node;
51 int allow_remat; /**< the node may be rematted instead of reloaded if global remat option is on */
54 typedef struct _spill_info_t {
55 /** the value that should get spilled */
56 ir_node *spilled_node;
57 /** list of places where the value should get reloaded */
58 reloader_t *reloaders;
60 /** the spill node, or a PhiM node */
62 /** if we had the value of a phi spilled before but not the phi itself then
63 * this field contains the spill for the phi value */
66 /** the register class in which the reload should be placed */
67 const arch_register_class_t *reload_cls;
71 const arch_env_t *arch_env;
75 int spill_cost; /**< the cost of a single spill node */
76 int reload_cost; /**< the cost of a reload node */
77 set *spills; /**< all spill_info_t's, which must be placed */
78 pset *mem_phis; /**< set of all special spilled phis. allocated and freed separately */
80 DEBUG_ONLY(firm_dbg_module_t *dbg;)
84 * Compare two spill infos.
86 static int cmp_spillinfo(const void *x, const void *y, size_t size) {
87 const spill_info_t *xx = x;
88 const spill_info_t *yy = y;
89 return xx->spilled_node != yy->spilled_node;
93 * Returns spill info for a specific value (returns NULL if the info doesn't
96 static spill_info_t *find_spillinfo(const spill_env_t *env, ir_node *value) {
98 int hash = nodeset_hash(value);
100 info.spilled_node = value;
102 return set_find(env->spills, &info, sizeof(info), hash);
106 * Returns spill info for a specific value (the value that is to be spilled)
108 static spill_info_t *get_spillinfo(const spill_env_t *env, ir_node *value) {
109 spill_info_t info, *res;
110 int hash = nodeset_hash(value);
112 info.spilled_node = value;
113 res = set_find(env->spills, &info, sizeof(info), hash);
116 info.reloaders = NULL;
118 info.old_spill = NULL;
119 info.reload_cls = NULL;
120 res = set_insert(env->spills, &info, sizeof(info), hash);
127 /* Sets the debug module of a spill environment. */
128 void be_set_spill_env_dbg_module(spill_env_t *env, firm_dbg_module_t *dbg) {
133 /* Creates a new spill environment. */
134 spill_env_t *be_new_spill_env(be_irg_t *birg) {
135 spill_env_t *env = xmalloc(sizeof(env[0]));
136 env->spills = new_set(cmp_spillinfo, 1024);
137 env->irg = be_get_birg_irg(birg);
139 env->arch_env = birg->main_env->arch_env;
140 env->mem_phis = pset_new_ptr_default();
141 // TODO, ask backend about costs..., or even ask backend whether we should
144 env->reload_cost = 5;
145 obstack_init(&env->obst);
149 /* Deletes a spill environment. */
150 void be_delete_spill_env(spill_env_t *env) {
151 del_set(env->spills);
152 del_pset(env->mem_phis);
153 obstack_free(&env->obst, NULL);
159 * | _ \| | __ _ ___ ___ | _ \ ___| | ___ __ _ __| |___
160 * | |_) | |/ _` |/ __/ _ \ | |_) / _ \ |/ _ \ / _` |/ _` / __|
161 * | __/| | (_| | (_| __/ | _ < __/ | (_) | (_| | (_| \__ \
162 * |_| |_|\__,_|\___\___| |_| \_\___|_|\___/ \__,_|\__,_|___/
166 void be_add_remat(spill_env_t *env, ir_node *to_spill, ir_node *before, ir_node *rematted_node) {
167 spill_info_t *spill_info;
168 reloader_t *reloader;
170 spill_info = get_spillinfo(env, to_spill);
172 /* add the remat information */
173 reloader = obstack_alloc(&env->obst, sizeof(reloader[0]));
174 reloader->next = spill_info->reloaders;
175 reloader->reloader = before;
176 reloader->rematted_node = rematted_node;
177 reloader->allow_remat = 1;
179 spill_info->reloaders = reloader;
181 DBG((env->dbg, LEVEL_1, "creating spillinfo for %+F, will be rematerialized before %+F\n",
185 void be_add_reload(spill_env_t *env, ir_node *to_spill, ir_node *before,
186 const arch_register_class_t *reload_cls, int allow_remat)
191 info = get_spillinfo(env, to_spill);
193 if (is_Phi(to_spill)) {
196 /* create spillinfos for the phi arguments */
197 for (i = 0, arity = get_irn_arity(to_spill); i < arity; ++i) {
198 ir_node *arg = get_irn_n(to_spill, i);
199 get_spillinfo(env, arg);
203 // hackery... sometimes the morgan algo spilled the value of a phi,
204 // the belady algo decides later to spill the whole phi, then sees the
205 // spill node and adds a reload for that spill node, problem is the
206 // reload gets attach to that same spill (and is totally unnecessary)
207 if (info->old_spill != NULL &&
208 (before == info->old_spill || value_dominates(before, info->old_spill)))
210 printf("spilledphi hack was needed...\n");
211 before = sched_next(info->old_spill);
216 /* put reload into list */
217 rel = obstack_alloc(&env->obst, sizeof(rel[0]));
218 rel->next = info->reloaders;
219 rel->reloader = before;
220 rel->rematted_node = NULL;
221 rel->allow_remat = allow_remat;
223 info->reloaders = rel;
224 assert(info->reload_cls == NULL || info->reload_cls == reload_cls);
225 info->reload_cls = reload_cls;
227 DBG((env->dbg, LEVEL_1, "creating spillinfo for %+F, will be reloaded before %+F, may%s be rematerialized\n",
228 to_spill, before, allow_remat ? "" : " not"));
231 static ir_node *get_reload_insertion_point(ir_node *block, int pos) {
232 ir_node *predblock, *last;
234 /* simply add the reload to the beginning of the block if we only have 1 predecessor
235 * (we don't need to check for phis as there can't be any in a block with only 1 pred)
237 if(get_Block_n_cfgpreds(block) == 1) {
238 assert(!is_Phi(sched_first(block)));
239 return sched_first(block);
242 /* We have to reload the value in pred-block */
243 predblock = get_Block_cfgpred_block(block, pos);
244 last = sched_last(predblock);
246 /* we might have projs and keepanys behind the jump... */
247 while(is_Proj(last) || be_is_Keep(last)) {
248 last = sched_prev(last);
249 assert(!sched_is_end(last));
253 last = sched_next(last);
254 // last node must be a cfop, only exception is the start block
255 assert(last == get_irg_start_block(get_irn_irg(block)));
258 // add the reload before the (cond-)jump
262 void be_add_reload_on_edge(spill_env_t *env, ir_node *to_spill, ir_node *block, int pos,
263 const arch_register_class_t *reload_cls, int allow_remat)
265 ir_node *before = get_reload_insertion_point(block, pos);
266 be_add_reload(env, to_spill, before, reload_cls, allow_remat);
269 void be_spill_phi(spill_env_t *env, ir_node *node) {
273 assert(is_Phi(node));
275 pset_insert_ptr(env->mem_phis, node);
277 // create spillinfos for the phi arguments
278 spill = get_spillinfo(env, node);
279 for(i = 0, arity = get_irn_arity(node); i < arity; ++i) {
280 ir_node *arg = get_irn_n(node, i);
281 get_spillinfo(env, arg);
284 // if we had a spill for the phi value before, then remove this spill from
285 // schedule, as we will remove it in the insert spill/reload phase
286 if(spill->spill != NULL && !is_Phi(spill->spill)) {
287 assert(spill->old_spill == NULL);
288 spill->old_spill = spill->spill;
295 * / ___|_ __ ___ __ _| |_ ___ / ___| _ __ (_) | |___
296 * | | | '__/ _ \/ _` | __/ _ \ \___ \| '_ \| | | / __|
297 * | |___| | | __/ (_| | || __/ ___) | |_) | | | \__ \
298 * \____|_| \___|\__,_|\__\___| |____/| .__/|_|_|_|___/
303 * Schedules a node after an instruction. (That is the place after all projs and phis
304 * that are scheduled after the instruction)
305 * This function also skips phi nodes at the beginning of a block
307 static void sched_add_after_insn(ir_node *sched_after, ir_node *node) {
308 ir_node *next = sched_next(sched_after);
309 while(is_Proj(next) || is_Phi(next)) {
310 next = sched_next(next);
312 assert(next != NULL);
314 if(sched_is_end(next)) {
315 sched_add_after(sched_last(get_nodes_block(sched_after)), node);
317 sched_add_before(next, node);
324 * @param senv the spill environment
325 * @param irn the node that should be spilled
326 * @param ctx_irn an user of the spilled node
328 * @return a be_Spill node
330 static void spill_irn(spill_env_t *env, spill_info_t *spillinfo) {
331 optimization_state_t opt;
332 ir_node *to_spill = spillinfo->spilled_node;
334 DBG((env->dbg, LEVEL_1, "spilling %+F ... ", to_spill));
336 /* Trying to spill an already spilled value, no need for a new spill
337 * node then, we can simply connect to the same one for this reload
339 * (although rematerialization code should handle most of these cases
340 * this can still happen when spilling Phis)
342 if (be_is_Reload(to_spill)) {
343 spillinfo->spill = get_irn_n(to_spill, be_pos_Reload_mem);
344 DB((env->dbg, LEVEL_1, "skip reload, using existing spill %+F\n", spillinfo->spill));
348 if (arch_irn_is(env->arch_env, to_spill, dont_spill)) {
349 assert(0 && "Attempt to spill a node marked 'dont_spill'");
353 We switch on optimizations here to get CSE. This is needed as some backends
354 have some extra spill phases and we want to make use of those spills instead
355 of creating new ones.
357 save_optimization_state(&opt);
359 spillinfo->spill = be_spill(env->arch_env, to_spill);
360 restore_optimization_state(&opt);
361 if (! sched_is_scheduled(spillinfo->spill)) {
362 DB((env->dbg, LEVEL_1, "add spill %+F after %+F\n", spillinfo->spill, to_spill));
363 sched_add_after_insn(to_spill, spillinfo->spill);
366 DB((env->dbg, LEVEL_1, "re-using spill %+F after %+F\n", spillinfo->spill, to_spill));
370 static void spill_node(spill_env_t *env, spill_info_t *spillinfo);
373 * If the first usage of a Phi result would be out of memory
374 * there is no sense in allocating a register for it.
375 * Thus we spill it and all its operands to the same spill slot.
376 * Therefore the phi/dataB becomes a phi/Memory
378 * @param senv the spill environment
379 * @param phi the Phi node that should be spilled
380 * @param ctx_irn an user of the spilled node
382 static void spill_phi(spill_env_t *env, spill_info_t *spillinfo) {
383 ir_node *phi = spillinfo->spilled_node;
385 int arity = get_irn_arity(phi);
386 ir_node *block = get_nodes_block(phi);
391 DBG((env->dbg, LEVEL_1, "spilling Phi %+F:\n", phi));
392 /* build a new PhiM */
393 ins = alloca(sizeof(ir_node*) * arity);
394 for(i = 0; i < arity; ++i) {
395 ins[i] = get_irg_bad(env->irg);
397 spillinfo->spill = new_r_Phi(env->irg, block, arity, ins, mode_M);
399 for(i = 0; i < arity; ++i) {
400 ir_node *arg = get_irn_n(phi, i);
401 spill_info_t *arg_info = get_spillinfo(env, arg);
403 spill_node(env, arg_info);
405 set_irn_n(spillinfo->spill, i, arg_info->spill);
407 DBG((env->dbg, LEVEL_1, "... done spilling Phi %+F\n", phi));
409 // rewire reloads from old_spill to phi
410 if (spillinfo->old_spill != NULL) {
411 const ir_edge_t *edge, *next;
412 ir_node *old_spill = spillinfo->old_spill;
414 DBG((env->dbg, LEVEL_1, "old spill found, rewiring reloads:\n"));
416 foreach_out_edge_safe(old_spill, edge, next) {
417 ir_node *reload = get_edge_src_irn(edge);
418 int pos = get_edge_src_pos(edge);
420 DBG((env->dbg, LEVEL_1, "\tset input %d of %+F to %+F\n", pos, reload, spillinfo->spill));
422 assert(be_is_Reload(reload) || is_Phi(reload));
423 set_irn_n(reload, pos, spillinfo->spill);
425 DBG((env->dbg, LEVEL_1, "\tset input of %+F to BAD\n", old_spill));
426 set_irn_n(old_spill, be_pos_Spill_val, new_Bad());
427 //sched_remove(old_spill);
428 spillinfo->old_spill = NULL;
435 * @param senv the spill environment
436 * @param to_spill the node that should be spilled
438 static void spill_node(spill_env_t *env, spill_info_t *spillinfo) {
441 // the node should be tagged for spilling already...
442 if(spillinfo->spill != NULL)
445 to_spill = spillinfo->spilled_node;
446 assert(sched_is_scheduled(to_spill) && "Node to be spilled must be scheduled!");
447 if (is_Phi(to_spill) && pset_find_ptr(env->mem_phis, spillinfo->spilled_node)) {
448 spill_phi(env, spillinfo);
450 spill_irn(env, spillinfo);
457 * | _ \ ___ _ __ ___ __ _| |_ ___ _ __(_) __ _| (_)_______
458 * | |_) / _ \ '_ ` _ \ / _` | __/ _ \ '__| |/ _` | | |_ / _ \
459 * | _ < __/ | | | | | (_| | || __/ | | | (_| | | |/ / __/
460 * |_| \_\___|_| |_| |_|\__,_|\__\___|_| |_|\__,_|_|_/___\___|
465 * Tests whether value @p arg is available before node @p reloader
466 * @returns 1 if value is available, 0 otherwise
468 static int is_value_available(spill_env_t *env, ir_node *arg, ir_node *reloader) {
469 if(is_Unknown(arg) || arg == new_NoMem())
475 if(arg == get_irg_frame(env->irg))
478 // hack for now (happens when command should be inserted at end of block)
479 if(is_Block(reloader)) {
484 * Ignore registers are always available
486 if(arch_irn_is(env->arch_env, arg, ignore)) {
491 /* the following test does not work while spilling,
492 * because the liveness info is not adapted yet to the effects of the
493 * additional spills/reloads.
496 /* we want to remat before the insn reloader
497 * thus an arguments is alive if
498 * - it interferes with the reloaders result
499 * - or it is (last-) used by reloader itself
501 if (values_interfere(env->birg->lv, reloader, arg)) {
505 arity = get_irn_arity(reloader);
506 for (i = 0; i < arity; ++i) {
507 ir_node *rel_arg = get_irn_n(reloader, i);
517 * Checks whether the node can principally be rematerialized
519 static int is_remat_node(spill_env_t *env, ir_node *node) {
520 const arch_env_t *arch_env = env->arch_env;
522 assert(!be_is_Spill(node));
524 if(arch_irn_is(arch_env, node, rematerializable)) {
528 if(be_is_StackParam(node))
535 * Check if a node is rematerializable. This tests for the following conditions:
537 * - The node itself is rematerializable
538 * - All arguments of the node are available or also rematerialisable
539 * - The costs for the rematerialisation operation is less or equal a limit
541 * Returns the costs needed for rematerialisation or something
542 * > REMAT_COST_LIMIT if remat is not possible.
544 static int check_remat_conditions_costs(spill_env_t *env, ir_node *spilled, ir_node *reloader, int parentcosts) {
549 if(!is_remat_node(env, spilled))
550 return REMAT_COST_LIMIT;
552 if(be_is_Reload(spilled)) {
555 costs += arch_get_op_estimated_cost(env->arch_env, spilled);
557 if(parentcosts + costs >= REMAT_COST_LIMIT) {
558 return REMAT_COST_LIMIT;
562 for(i = 0, arity = get_irn_arity(spilled); i < arity; ++i) {
563 ir_node *arg = get_irn_n(spilled, i);
565 if(is_value_available(env, arg, reloader))
568 // we have to rematerialize the argument as well...
570 /* we only support rematerializing 1 argument at the moment,
571 * so that we don't have to care about register pressure
573 return REMAT_COST_LIMIT;
577 costs += check_remat_conditions_costs(env, arg, reloader, parentcosts + costs);
578 if(parentcosts + costs >= REMAT_COST_LIMIT)
579 return REMAT_COST_LIMIT;
585 static int check_remat_conditions(spill_env_t *env, ir_node *spilled, ir_node *reloader) {
586 int costs = check_remat_conditions_costs(env, spilled, reloader, 0);
588 return costs < REMAT_COST_LIMIT;
592 * Re-materialize a node.
594 * @param senv the spill environment
595 * @param spilled the node that was spilled
596 * @param reloader a irn that requires a reload
598 static ir_node *do_remat(spill_env_t *env, ir_node *spilled, ir_node *reloader) {
604 if(is_Block(reloader)) {
607 bl = get_nodes_block(reloader);
610 ins = alloca(get_irn_arity(spilled) * sizeof(ins[0]));
611 for(i = 0, arity = get_irn_arity(spilled); i < arity; ++i) {
612 ir_node *arg = get_irn_n(spilled, i);
614 if(is_value_available(env, arg, reloader)) {
617 ins[i] = do_remat(env, arg, reloader);
621 /* create a copy of the node */
622 res = new_ir_node(get_irn_dbg_info(spilled), env->irg, bl,
624 get_irn_mode(spilled),
625 get_irn_arity(spilled),
627 copy_node_attr(spilled, res);
628 new_backedge_info(res);
631 DBG((env->dbg, LEVEL_1, "Insert remat %+F of %+F before reloader %+F\n", res, spilled, reloader));
633 /* insert in schedule */
634 sched_add_before(reloader, res);
639 int be_get_reload_costs(spill_env_t *env, ir_node *to_spill, ir_node *before) {
640 spill_info_t *spill_info;
643 // is the node rematerializable?
644 int costs = check_remat_conditions_costs(env, to_spill, before, 0);
645 if(costs < REMAT_COST_LIMIT)
649 // do we already have a spill?
650 spill_info = find_spillinfo(env, to_spill);
651 if(spill_info != NULL && spill_info->spill != NULL)
652 return env->reload_cost;
654 return env->spill_cost + env->reload_cost;
657 int be_get_reload_costs_on_edge(spill_env_t *env, ir_node *to_spill, ir_node *block, int pos) {
658 ir_node *before = get_reload_insertion_point(block, pos);
659 return be_get_reload_costs(env, to_spill, before);
664 * |_ _|_ __ ___ ___ _ __| |_ | _ \ ___| | ___ __ _ __| |___
665 * | || '_ \/ __|/ _ \ '__| __| | |_) / _ \ |/ _ \ / _` |/ _` / __|
666 * | || | | \__ \ __/ | | |_ | _ < __/ | (_) | (_| | (_| \__ \
667 * |___|_| |_|___/\___|_| \__| |_| \_\___|_|\___/ \__,_|\__,_|___/
671 void be_insert_spills_reloads(spill_env_t *env) {
672 const arch_env_t *arch_env = env->arch_env;
678 /* process each spilled node */
679 for (si = set_first(env->spills); si; si = set_next(env->spills)) {
681 ir_mode *mode = get_irn_mode(si->spilled_node);
682 pset *values = pset_new_ptr(16);
684 DBG((env->dbg, LEVEL_1, "\nhandling all reloaders of %+F:\n", si->spilled_node));
686 /* go through all reloads for this spill */
687 for (rld = si->reloaders; rld; rld = rld->next) {
690 if (rld->rematted_node != NULL) {
691 new_val = rld->rematted_node;
693 sched_add_before(rld->reloader, new_val);
695 else if (be_do_remats && rld->allow_remat && check_remat_conditions(env, si->spilled_node, rld->reloader)) {
696 new_val = do_remat(env, si->spilled_node, rld->reloader);
700 /* make sure we have a spill */
701 if (si->spill == NULL) {
706 /* create a reload */
707 new_val = be_reload(arch_env, si->reload_cls, rld->reloader, mode, si->spill);
711 DBG((env->dbg, LEVEL_1, " %+F of %+F before %+F\n", new_val, si->spilled_node, rld->reloader));
712 pset_insert_ptr(values, new_val);
715 if (pset_count(values) > 0) {
716 /* introduce copies, rewire the uses */
717 pset_insert_ptr(values, si->spilled_node);
718 be_ssa_constr_set_ignore(env->birg->dom_front, env->birg->lv, values, env->mem_phis);
723 si->reloaders = NULL;
726 #ifdef FIRM_STATISTICS
727 if (be_stat_ev_is_active()) {
728 be_stat_ev("spill_spills", spills);
729 be_stat_ev("spill_reloads", reloads);
730 be_stat_ev("spill_remats", remats);
732 #endif /* FIRM_STATISTICS */
734 be_remove_dead_nodes_from_schedule(env->irg);
735 //be_liveness_recompute(env->birg->lv);
736 be_invalidate_liveness(env->birg);