From: Michael Beck Date: Thu, 13 Nov 2008 12:23:46 +0000 (+0000) Subject: - a stripped down version of liveness for register pressure estimation (and without... X-Git-Url: http://nsz.repo.hu/git/?a=commitdiff_plain;h=a24fd0c180d302c5ba5e582bdc72d23fd4d024b6;p=libfirm - a stripped down version of liveness for register pressure estimation (and without out edges) [r23621] --- diff --git a/ir/stat/stat_liveness.c b/ir/stat/stat_liveness.c new file mode 100644 index 000000000..95872bfc6 --- /dev/null +++ b/ir/stat/stat_liveness.c @@ -0,0 +1,207 @@ +/* + * Copyright (C) 1995-2008 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 Statistics for Firm, register pressure estimation. + * @author Michael Beck + * @version $Id$ + */ +#include "config.h" +#include "irgwalk.h" +#include "irbitset.h" +#include "irtools.h" +#include "array_t.h" +#include "irnode_t.h" + +typedef struct block_entry_t block_entry_t; +typedef struct environment_t environment_t; + +/** A Block entry. */ +struct block_entry_t { + ir_node **live_ins; /**< The array of live ins. */ + ir_node **live_outs; /**< The array of live outs. */ + ir_node *block; /**< The associated block. */ + block_entry_t *next; /**< Links to the next block entry. */ +}; + +struct environment_t { + struct obstack obst; + block_entry_t *entries; /**< List of all allocated block entries. */ + void *visited; /**< a Bitset to mark visited nodes */ +}; + +static environment_t *env; + +/** + * Get the block entry or allocate one if not yet assigned. + */ +static block_entry_t *get_block_entry(ir_node *block) { + block_entry_t *entry = get_irn_link(block); + + if (entry == NULL) { + entry = obstack_alloc(&env->obst, sizeof(*entry)); + + entry->live_ins = NEW_ARR_F(ir_node *, 0); + entry->live_outs = NEW_ARR_F(ir_node *, 0); + + entry->next = env->entries; + env->entries = entry; + } + return entry; +} + +static void add_entry(ir_node ***arr, ir_node *irn) { + ir_node **list = *arr; + int i; + + for (i = ARR_LEN(list) - 1; i >= 0; --i) { + if (list[i] == irn) { + /* already there */ + return; + } + } + ARR_APP1(ir_node *, *arr, irn); +} + +static void add_live_in(ir_node *block, ir_node *irn) { + block_entry_t *entry = get_block_entry(block); + + add_entry(&entry->live_ins, irn); +} + +static void add_live_out(ir_node *block, ir_node *irn) { + block_entry_t *entry = get_block_entry(block); + + add_entry(&entry->live_outs, irn); +} + +/** + * Mark a node (value) live out at a certain block. Do this also + * transitively, i.e. if the block is not the block of the value's + * definition, all predecessors are also marked live. + * + * @param def The node (value). + * @param block The block to mark the value live out of. + */ +static void live_end_at_block(ir_node *def, ir_node *block) { + add_live_out(block, def); + + if (is_irn_constlike(def)) { + /* do NOT follow Constants further, assume they are + part of instruction or can easily + be rematerialized */ + return; + } + + if (! bitset_contains_irn(env->visited, block)) { + bitset_add_irn(env->visited, block); + + /* + * If this block is not the definition block, we have to go up + * further. + */ + if (get_nodes_block(def) != block) { + int i; + + add_live_in(block, def); + + for (i = get_Block_n_cfgpreds(block) - 1; i >= 0; --i) + live_end_at_block(def, get_Block_cfgpred_block(block, i)); + } + } +} + +/** + * Walker: finds live-outs and calculate live-ins from that. + */ +static void find_live_outs(ir_node *irn, void *ctx) { + ir_mode *mode = get_irn_mode(irn); + ir_node *block, *use_block; + int i; + + /* only data nodes */ + if (! mode_is_datab(mode)) + return; + + block = get_nodes_block(irn); + + for (i = get_irn_arity(irn) - 1; i >= 0; --i) { + ir_node *pred = get_irn_n(irn, i); + + if (mode_is_datab(get_irn_mode(pred))) { + ir_node *def_block = get_nodes_block(pred); + + if (is_Phi(irn)) { + use_block = get_Block_cfgpred_block(block, i); + + /* even if pred is a Const, it MUST be + in a register on block output */ + bitset_clear_all(env->visited); + live_end_at_block(pred, use_block); + + /* The Block has only one live in, the Phi itself */ + add_live_in(block, irn); + } + else if (def_block != use_block) { + /* pred is a live in of our block */ + if (is_irn_constlike(pred)) { + /* ignore Constants, assume they are + part of instruction or can easily + be rematerialized */ + continue; + } + + use_block = block; + add_live_in(use_block, pred); + + bitset_clear_all(env->visited); + for (i = get_Block_n_cfgpreds(use_block); i >= 0; --i) { + ir_node *pred_block = get_Block_cfgpred_block(use_block, i); + live_end_at_block(irn, pred_block); + } + } + } + } +} + +/** + * Calculate the live-in and live out of blocks for datab nodes. + * Use it to estimate register pressure. + */ +void stat_liveness(ir_graph *irg) { + environment_t genv; + block_entry_t *p; + + env = &genv; + + obstack_init(&env->obst); + env->entries = NULL; + env->visited = bitset_obstack_alloc(&env->obst, get_irg_last_idx(irg)); + + irg_block_walk_graph(irg, NULL, firm_clear_link, NULL); + irg_walk_graph(irg, NULL, find_live_outs, NULL); + + for (p = env->entries; p != NULL; p = p->next) { + DEL_ARR_F(p->live_ins); + DEL_ARR_F(p->live_outs); + } + obstack_free(&env->obst, NULL); + env = NULL; +}