properties updated
[libfirm] / ir / be / bespill.c
index 62ffddc..2495cc7 100644 (file)
@@ -1,10 +1,28 @@
+/*
+ * Copyright (C) 1995-2007 University of Karlsruhe.  All right reserved.
+ *
+ * This file is part of libFirm.
+ *
+ * This file may be distributed and/or modified under the terms of the
+ * GNU General Public License version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * Licensees holding valid libFirm Professional Edition licenses may use
+ * this file in accordance with the libFirm Commercial License.
+ * Agreement provided with the Software.
+ *
+ * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE.
+ */
+
 /**
  * @file
+ * @brief       Main spill driver.
  * @author      Daniel Grund, Sebastian Hack, Matthias Braun
  * @date               29.09.2005
  * @version     $Id$
- * Copyright:   (c) Universitaet Karlsruhe
- * Licence:     This file protected by GPL -  GNU GENERAL PUBLIC LICENSE.
  */
 #ifdef HAVE_CONFIG_H
 #include "config.h"
 #include "benodesets.h"
 #include "bespilloptions.h"
 #include "bestatevent.h"
-#include "beirgmod.h"
+#include "bessaconstr.h"
+#include "beirg_t.h"
+#include "beintlive_t.h"
 
-// only rematerialise when costs are less than REMAT_COST_LIMIT
-// TODO determine a good value here...
+/* only rematerialise when costs are less than REMAT_COST_LIMIT */
+/* TODO determine a good value here... */
 #define REMAT_COST_LIMIT       10
 
 typedef struct _reloader_t reloader_t;
@@ -230,12 +250,16 @@ void be_add_reload(spill_env_t *env, ir_node *to_spill, ir_node *before,
                to_spill, before, allow_remat ? "" : " not"));
 }
 
-static ir_node *get_reload_insertion_point(ir_node *block, int pos) {
+/**
+ * Returns the point at which you can insert a node that should be executed
+ * before block @p block when coming from pred @p pos.
+ */
+static ir_node *get_block_insertion_point(ir_node *block, int pos) {
        ir_node *predblock, *last;
 
-       /* simply add the reload to the beginning of the block if we only have 1 predecessor
-        * (we don't need to check for phis as there can't be any in a block with only 1 pred)
-        */
+       /* simply add the reload to the beginning of the block if we only have 1
+        * predecessor. We don't need to check for phis as there can't be any in a
+        * block with only 1 pred. */
        if(get_Block_n_cfgpreds(block) == 1) {
                assert(!is_Phi(sched_first(block)));
                return sched_first(block);
@@ -264,7 +288,7 @@ static ir_node *get_reload_insertion_point(ir_node *block, int pos) {
 void be_add_reload_on_edge(spill_env_t *env, ir_node *to_spill, ir_node *block, int pos,
                const arch_register_class_t *reload_cls, int allow_remat)
 {
-       ir_node *before = get_reload_insertion_point(block, pos);
+       ir_node *before = get_block_insertion_point(block, pos);
        be_add_reload(env, to_spill, before, reload_cls, allow_remat);
 }
 
@@ -302,9 +326,9 @@ void be_spill_phi(spill_env_t *env, ir_node *node) {
  */
 
 /**
- * Schedules a node after an instruction. (That is the place after all projs and phis
- * that are scheduled after the instruction)
- * This function also skips phi nodes at the beginning of a block
+ * Schedules a node after an instruction. That is the place after all projs and
+ * phis that are scheduled after the instruction. This function also skips phi
+ * nodes at the beginning of a block
  */
 static void sched_add_after_insn(ir_node *sched_after, ir_node *node) {
        ir_node *next = sched_next(sched_after);
@@ -338,8 +362,8 @@ static void spill_irn(spill_env_t *env, spill_info_t *spillinfo) {
        /* Trying to spill an already spilled value, no need for a new spill
         * node then, we can simply connect to the same one for this reload
         *
-        * (although rematerialization code should handle most of these cases
-        * this can still happen when spilling Phis)
+        * Normally reloads get simply rematerialized instead of spilled again; this
+        * can happen annyway when the reload is the pred of a phi to spill)
         */
        if (be_is_Reload(to_spill)) {
                spillinfo->spill = get_irn_n(to_spill, be_pos_Reload_mem);
@@ -347,14 +371,20 @@ static void spill_irn(spill_env_t *env, spill_info_t *spillinfo) {
                return;
        }
 
-       if (arch_irn_is(env->arch_env, to_spill, dont_spill)) {
-               assert(0 && "Attempt to spill a node marked 'dont_spill'");
+       assert(!(arch_irn_is(env->arch_env, to_spill, dont_spill)
+                               && "Attempt to spill a node marked 'dont_spill'"));
+
+       /* some backends have virtual noreg/unknown nodes that are not scheduled */
+       if(!sched_is_scheduled(to_spill)) {
+               spillinfo->spill = new_NoMem();
+               return;
        }
 
+
        /*
-               We switch on optimizations here to get CSE. This is needed as some backends
-               have some extra spill phases and we want to make use of those spills instead
-               of creating new ones.
+               We switch on optimizations here to get CSE. This is needed as some
+               backends have some extra spill phases and we want to make use of those
+               spills instead of creating new ones.
        */
        save_optimization_state(&opt);
        set_optimize(1);
@@ -363,8 +393,7 @@ static void spill_irn(spill_env_t *env, spill_info_t *spillinfo) {
        if (! sched_is_scheduled(spillinfo->spill)) {
                DB((env->dbg, LEVEL_1, "add spill %+F after %+F\n", spillinfo->spill, to_spill));
                sched_add_after_insn(to_spill, spillinfo->spill);
-       }
-       else {
+       } else {
                DB((env->dbg, LEVEL_1, "re-using spill %+F after %+F\n", spillinfo->spill, to_spill));
        }
 }
@@ -406,7 +435,7 @@ static void spill_phi(spill_env_t *env, spill_info_t *spillinfo) {
 
                set_irn_n(spillinfo->spill, i, arg_info->spill);
        }
-       DBG((env->dbg, LEVEL_1, "... done spilling Phi %+F\n", phi));
+       DBG((env->dbg, LEVEL_1, "... done spilling Phi %+F, created PhiM %+F\n", phi, spillinfo->spill));
 
        // rewire reloads from old_spill to phi
        if (spillinfo->old_spill != NULL) {
@@ -445,7 +474,7 @@ static void spill_node(spill_env_t *env, spill_info_t *spillinfo) {
                return;
 
        to_spill = spillinfo->spilled_node;
-       assert(sched_is_scheduled(to_spill) && "Node to be spilled must be scheduled!");
+
        if (is_Phi(to_spill) && ir_nodeset_contains(&env->mem_phis, to_spill)) {
                spill_phi(env, spillinfo);
        } else {
@@ -657,7 +686,7 @@ int be_get_reload_costs(spill_env_t *env, ir_node *to_spill, ir_node *before) {
 }
 
 int be_get_reload_costs_on_edge(spill_env_t *env, ir_node *to_spill, ir_node *block, int pos) {
-       ir_node *before = get_reload_insertion_point(block, pos);
+       ir_node *before = get_block_insertion_point(block, pos);
        return be_get_reload_costs(env, to_spill, before);
 }
 
@@ -683,7 +712,7 @@ void be_insert_spills_reloads(spill_env_t *env) {
           spilled phis work correctly */
        foreach_ir_nodeset(&env->mem_phis, node, iter) {
                spill_info_t *info = get_spillinfo(env, node);
-               spill_phi(env, info);
+               spill_node(env, info);
        }
 
        /* process each spilled node */
@@ -697,7 +726,7 @@ void be_insert_spills_reloads(spill_env_t *env) {
 
                /* go through all reloads for this spill */
                for (rld = si->reloaders; rld; rld = rld->next) {
-                       ir_node *copy; /* a reaload is a "copy" of the original value */
+                       ir_node *copy; /* a reload is a "copy" of the original value */
 
                        if (rld->rematted_node != NULL) {
                                copy = rld->rematted_node;
@@ -727,14 +756,25 @@ void be_insert_spills_reloads(spill_env_t *env) {
                /* if we had any reloads or remats, then we need to reconstruct the
                 * SSA form for the spilled value */
                if (ARR_LEN(copies) > 0) {
-                       /* Matze: used mem_phis as ignore uses in the past, I don't see how
-                          one of the mem_phis can be a use of the spilled value...
-                          so I changed this to NULL now */
-                       be_ssa_construction(
-                                       be_get_birg_dom_front(env->birg),
-                                       be_get_birg_liveness(env->birg),
-                                       spilled_node, ARR_LEN(copies), copies,
-                                       NULL, 0);
+                       be_ssa_construction_env_t senv;
+                       /* be_lv_t *lv = be_get_birg_liveness(env->birg); */
+
+                       be_ssa_construction_init(&senv, env->birg);
+                       be_ssa_construction_add_copy(&senv, spilled_node);
+                       be_ssa_construction_add_copies(&senv, copies, ARR_LEN(copies));
+                       be_ssa_construction_fix_users(&senv, spilled_node);
+
+#if 0
+                       /* no need to enable this as long as we invalidate liveness
+                          after this function... */
+                       be_ssa_construction_update_liveness_phis(&senv);
+                       be_liveness_update(spilled_node);
+                       len = ARR_LEN(copies);
+                       for(i = 0; i < len; ++i) {
+                               be_liveness_update(lv, copies[i]);
+                       }
+#endif
+                       be_ssa_construction_destroy(&senv);
                }
 
                DEL_ARR_F(copies);
@@ -750,7 +790,7 @@ void be_insert_spills_reloads(spill_env_t *env) {
 #endif /* FIRM_STATISTICS */
 
        be_remove_dead_nodes_from_schedule(env->irg);
-       /* Matze: In theory be_ssa_construction should take care of the livenes...
+       /* Matze: In theory be_ssa_construction should take care of the liveness...
         * try to disable this again in the future */
        be_invalidate_liveness(env->birg);
 }