From: Michael Beck Date: Thu, 14 Jun 2007 16:56:50 +0000 (+0000) Subject: extracted transform framework from the ia32 backend X-Git-Url: http://nsz.repo.hu/git/?a=commitdiff_plain;h=f804035cd7874e073e02b9513bd5e3c3047f861f;p=libfirm extracted transform framework from the ia32 backend [r14503] --- diff --git a/ir/be/betranshlp.c b/ir/be/betranshlp.c new file mode 100644 index 000000000..4acd479f2 --- /dev/null +++ b/ir/be/betranshlp.c @@ -0,0 +1,342 @@ +/* + * 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 be transform helper extracted from the ia32 backend. + * @author Michael Beck + * @date 14.06.2007 + * @version $Id$ + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "pdeq.h" +#include "irop_t.h" +#include "iropt_t.h" +#include "irnode_t.h" +#include "irgraph_t.h" +#include "ircons.h" +#include "irhooks.h" +#include "iredges.h" +#include "irouts.h" +#include "trouts.h" +#include "cgana.h" +#include "debug.h" + +#include "beirg_t.h" +#include "betranshlp.h" + +typedef struct be_transform_env_t { + ir_graph *irg; /**< The irg, the node should be created in */ + int visited; /**< visited count that indicates whether a + node is already transformed */ + waitq *worklist; /**< worklist of nodes that still need to be + transformed */ + ir_node **old_anchors;/**< the list of anchors nodes in the old irg */ +} be_transform_env_t; + + +static be_transform_env_t env; + +void be_set_transformed_node(ir_node *old_node, ir_node *new_node) { + set_irn_link(old_node, new_node); +} + +static INLINE ir_node *be_get_transformed_node(ir_node *old_node) { + assert(irn_visited(old_node)); + return (ir_node*) get_irn_link(old_node); +} + +ir_node *be_get_old_anchor(unsigned anchor) { + return env.old_anchors[anchor]; +} + +void be_duplicate_deps(ir_node *old_node, ir_node *new_node) { + int i; + int deps = get_irn_deps(old_node); + + for (i = 0; i < deps; ++i) { + ir_node *dep = get_irn_dep(old_node, i); + ir_node *new_dep = be_transform_node(dep); + + add_irn_dep(new_node, new_dep); + } +} + +ir_node *be_duplicate_node(ir_node *node) { + ir_node *block = be_transform_node(get_nodes_block(node)); + ir_graph *irg = env.irg; + dbg_info *dbgi = get_irn_dbg_info(node); + ir_mode *mode = get_irn_mode(node); + ir_op *op = get_irn_op(node); + ir_node *new_node; + int i, arity; + + arity = get_irn_arity(node); + if (op->opar == oparity_dynamic) { + new_node = new_ir_node(dbgi, irg, block, op, mode, -1, NULL); + for (i = 0; i < arity; ++i) { + ir_node *in = get_irn_n(node, i); + in = be_transform_node(in); + add_irn_n(new_node, in); + } + } else { + ir_node **ins = alloca(arity * sizeof(ins[0])); + for (i = 0; i < arity; ++i) { + ir_node *in = get_irn_n(node, i); + ins[i] = be_transform_node(in); + } + + new_node = new_ir_node(dbgi, irg, block, op, mode, arity, ins); + } + + copy_node_attr(node, new_node); + be_duplicate_deps(node, new_node); + +#ifdef DEBUG_libfirm + new_node->node_nr = node->node_nr; +#endif + + return new_node; +} + +/** + * Calls transformation function for given node and marks it visited. + */ +ir_node *be_transform_node(ir_node *node) { + ir_node *new_node; + ir_op *op; + + if (irn_visited(node)) { + new_node = be_get_transformed_node(node); + assert(new_node != NULL); + return new_node; + } + + mark_irn_visited(node); + DEBUG_ONLY(be_set_transformed_node(node, NULL)); + + op = get_irn_op(node); + if (op->ops.generic) { + be_transform_func *transform = (be_transform_func *)op->ops.generic; + + new_node = transform(node); + assert(new_node != NULL); + } else { + new_node = be_duplicate_node(node); + } + + be_set_transformed_node(node, new_node); + mark_irn_visited(new_node); + hook_dead_node_elim_subst(current_ir_graph, node, new_node); + return new_node; +} + +/** + * enqueue all inputs into the transform queue. + */ +void be_enqueue_preds(ir_node *node) { + int i, arity; + + /* put the preds in the worklist */ + arity = get_irn_arity(node); + for (i = 0; i < arity; ++i) { + ir_node *pred = get_irn_n(node, i); + pdeq_putr(env.worklist, pred); + } +} + +/** + * Rewire nodes which are potential loops (like Phis) to avoid endless loops. + */ +static void fix_loops(ir_node *node) { + int i, arity; + + if (irn_visited(node)) + return; + + mark_irn_visited(node); + + assert(node_is_in_irgs_storage(env.irg, node)); + + if (! is_Block(node)) { + ir_node *block = get_nodes_block(node); + ir_node *new_block = get_irn_link(block); + + if (new_block != NULL) { + set_nodes_block(node, new_block); + block = new_block; + } + + fix_loops(block); + } + + arity = get_irn_arity(node); + for (i = 0; i < arity; ++i) { + ir_node *in = get_irn_n(node, i); + ir_node *nw = get_irn_link(in); + + if (nw != NULL && nw != in) { + set_irn_n(node, i, nw); + in = nw; + } + + fix_loops(in); + } + + arity = get_irn_deps(node); + for (i = 0; i < arity; ++i) { + ir_node *in = get_irn_dep(node, i); + ir_node *nw = get_irn_link(in); + + if (nw != NULL && nw != in) { + set_irn_dep(node, i, nw); + in = nw; + } + + fix_loops(in); + } +} + +ir_node *be_pre_transform_node(ir_node *place) { + if (place == NULL) + return NULL; + + return be_transform_node(place); +} + +/** + * Transforms all nodes. Deletes the old obstack and creates a new one. + */ +static void transform_nodes(ir_graph *irg, arch_pretrans_nodes *pre_transform, void *cg) { + int i; + ir_node *old_end; + + hook_dead_node_elim(irg, 1); + + inc_irg_visited(irg); + + env.irg = irg; + env.visited = get_irg_visited(irg); + env.worklist = new_waitq(); + env.old_anchors = alloca(anchor_max * sizeof(env.old_anchors[0])); + + old_end = get_irg_end(irg); + + /* put all anchor nodes in the worklist */ + for (i = 0; i < anchor_max; ++i) { + ir_node *anchor = irg->anchors[i]; + + if (anchor == NULL) + continue; + waitq_put(env.worklist, anchor); + + /* remember anchor */ + env.old_anchors[i] = anchor; + /* and set it to NULL to make sure we don't accidently use it */ + irg->anchors[i] = NULL; + } + + /* pre transform some anchors (so they are available in the other transform + * functions) */ + set_irg_bad(irg, be_transform_node(env.old_anchors[anchor_bad])); + set_irg_no_mem(irg, be_transform_node(env.old_anchors[anchor_no_mem])); + set_irg_start_block(irg, be_transform_node(env.old_anchors[anchor_start_block])); + set_irg_start(irg, be_transform_node(env.old_anchors[anchor_start])); + set_irg_frame(irg, be_transform_node(env.old_anchors[anchor_frame])); + + if (pre_transform) + (*pre_transform)(cg); + + /* process worklist (this should transform all nodes in the graph) */ + while (! waitq_empty(env.worklist)) { + ir_node *node = waitq_get(env.worklist); + be_transform_node(node); + } + + /* fix loops and set new anchors*/ + inc_irg_visited(irg); + for (i = 0; i < anchor_max; ++i) { + ir_node *anchor = env.old_anchors[i]; + + if (anchor == NULL) + continue; + + anchor = get_irn_link(anchor); + fix_loops(anchor); + assert(irg->anchors[i] == NULL || irg->anchors[i] == anchor); + irg->anchors[i] = anchor; + } + + del_waitq(env.worklist); + free_End(old_end); + hook_dead_node_elim(irg, 0); +} + +void be_transform_graph(be_irg_t *birg, arch_pretrans_nodes *func, void *cg) +{ + ir_graph *irg = birg->irg; + ir_graph *old_current_ir_graph = current_ir_graph; + int old_interprocedural_view = get_interprocedural_view(); + struct obstack *old_obst = NULL; + struct obstack *new_obst = NULL; + + current_ir_graph = irg; + set_interprocedural_view(0); + + /* most analysis info is wrong after transformation */ + free_callee_info(irg); + free_irg_outs(irg); + free_trouts(); + free_loop_information(irg); + set_irg_doms_inconsistent(irg); + be_invalidate_liveness(birg); + be_invalidate_dom_front(birg); + + /* create a new obstack */ + old_obst = irg->obst; + new_obst = xmalloc(sizeof(*new_obst)); + obstack_init(new_obst); + irg->obst = new_obst; + irg->last_node_idx = 0; + + /* create new value table for CSE */ + del_identities(irg->value_table); + irg->value_table = new_identities(); + + /* do the main transformation */ + transform_nodes(irg, func, cg); + + /* we don't want the globals anchor anymore */ + set_irg_globals(irg, new_r_Bad(irg)); + + /* free the old obstack */ + obstack_free(old_obst, 0); + xfree(old_obst); + + /* restore state */ + current_ir_graph = old_current_ir_graph; + set_interprocedural_view(old_interprocedural_view); + + /* recalculate edges */ + edges_deactivate(irg); + edges_activate(irg); +} diff --git a/ir/be/betranshlp.h b/ir/be/betranshlp.h new file mode 100644 index 000000000..40558804c --- /dev/null +++ b/ir/be/betranshlp.h @@ -0,0 +1,81 @@ +/* + * 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 be transform helper extracted from the ia32 backend. + * @author Matthias Braun, Michael Beck + * @date 14.06.2007 + * @version $Id$ + */ +#ifndef FIRM_BE_BETRANSHLP_H +#define FIRM_BE_BETRANSHLP_H + +#include "firm_types.h" +#include "beirg.h" + +/** + * A callback to pre-transform some nodes before the transformation starts. + */ +typedef void (arch_pretrans_nodes)(void *arch_cg); + +/** + * The type of a transform function. + */ +typedef ir_node *(be_transform_func)(ir_node *node); + +/** + * Returns an old (saved) anchor of the currently tranforming graph. + */ +ir_node *be_get_old_anchor(unsigned anchor); + +/** pre-transform a node */ +ir_node *be_pre_transform_node(ir_node *place); + +/** + * Calls transformation function for given node and marks it visited. + */ +ir_node *be_transform_node(ir_node *node); + +/** + * Duplicate all dependency edges of a node. + */ +void be_duplicate_deps(ir_node *old_node, ir_node *new_node); + +/** + * Duplicate a node during transformation. + */ +ir_node *be_duplicate_node(ir_node *node); + +/** + * Associate an old node with a transformed node. Uses link field. + */ +void be_set_transformed_node(ir_node *old_node, ir_node *new_node); + +/** + * enqueue all inputs into the transform queue. + */ +void be_enqueue_preds(ir_node *node); + +/** + * Transform a graph. Transformers must be registered first. + */ +void be_transform_graph(be_irg_t *birg, arch_pretrans_nodes *func, void *cg_env); + +#endif /* FIRM_BE_BETRANSHLP_H */