/**
* @file
- * @brief modifies schedule so flags dependencies are respected.
- * @author Matthias Braun, Christoph Mallon
+ * @brief Peephole optimisation framework keeps track of which registers contain which values
+ * @author Matthias Braun
* @version $Id$
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
+#include "bepeephole.h"
+
#include "iredges_t.h"
#include "irgwalk.h"
#include "irprintf.h"
#include "besched_t.h"
static const arch_env_t *arch_env;
-static const be_lv_t *lv;
-ir_node ***register_values;
+static be_lv_t *lv;
+ir_node ***register_values;
static void clear_value(ir_node *node)
{
reg_idx = arch_register_get_index(reg);
cls_idx = arch_register_class_index(cls);
+ //assert(register_values[cls_idx][reg_idx] != NULL);
register_values[cls_idx][reg_idx] = NULL;
}
register_values[cls_idx][reg_idx] = node;
}
-static void advance(ir_node *node)
+static void clear_defs(ir_node *node)
{
- int i, arity;
-
/* clear values defined */
if(get_irn_mode(node) == mode_T) {
const ir_edge_t *edge;
} else {
clear_value(node);
}
+}
+
+static void set_uses(ir_node *node)
+{
+ int i, arity;
/* set values used */
arity = get_irn_arity(node);
}
/* walk the block */
- sched_foreach_reverse(block, node) {
+ node = sched_last(block);
+ for( ; !sched_is_begin(node); node = sched_prev(node)) {
+ ir_op *op;
+ peephole_opt_func func;
+
if(is_Phi(node))
break;
- advance(node);
+ clear_defs(node);
+ set_uses(node);
+
+ op = get_irn_op(node);
+ func = (peephole_opt_func) op->ops.generic;
+ if(func != NULL) {
+ ir_node *new_node = func(node);
+ if(new_node != NULL && new_node != node) {
+ be_liveness_remove(lv, node);
+ be_liveness_introduce(lv, new_node);
+ node = new_node;
+ set_uses(node);
+ }
+ }
}
}
irg_block_walk_graph(irg, process_block, NULL, NULL);
}
+
+void be_peephole_init(void)
+{
+ clear_irp_opcodes_generic_func();
+}
+/*
+ * 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 peephole optimisation framework
+ * @author Matthias Braun
+ * @version $Id$
+ */
+
#ifndef BEPEEPHOLE_H
#define BEPEEPHOLE_H
#include "beirg.h"
+#include "bearch_t.h"
extern ir_node ***register_values;
-static inline ir_node *get_value_in_reg(unsigned regclass_idx,
- unsigned register_idx)
+static inline ir_node *be_peephole_get_value(unsigned regclass_idx,
+ unsigned register_idx)
{
return register_values[regclass_idx][register_idx];
}
+static inline ir_node *be_peephole_get_reg_value(const arch_register_t *reg)
+{
+ unsigned regclass_idx = arch_register_class_index(arch_register_get_class(reg));
+ unsigned register_idx = arch_register_get_index(reg);
+
+ return be_peephole_get_value(regclass_idx, register_idx);
+}
+
+typedef ir_node*(*peephole_opt_func) (ir_node *node);
+
+/**
+ * Do peephole optimisations, works backwards over blockschedules and calls the generic op handler function
+ * which should be of type peephole_opt_func. The values of the values in the registers are availble
+ * in the register_values variable during the optimisation functions.
+ */
void be_peephole_opt(be_irg_t *birg);
#endif
*/
static void emit_ia32_Const(const ir_node *node)
{
- const ia32_immediate_attr_t *attr = get_ia32_immediate_attr_const(node);
-
- /* a zero? */
- if(attr->symconst == NULL && attr->offset == 0) {
- assert(get_ia32_flags(node) & arch_irn_flags_modify_flags);
- be_emit_cstring("\txorl ");
- ia32_emit_dest_register(node, 0);
- be_emit_cstring(", ");
- ia32_emit_dest_register(node, 0);
- } else {
- be_emit_cstring("\tmovl ");
- emit_ia32_Immediate(node);
- be_emit_cstring(", ");
- ia32_emit_dest_register(node, 0);
- }
+ be_emit_cstring("\tmovl ");
+ emit_ia32_Immediate(node);
+ be_emit_cstring(", ");
+ ia32_emit_dest_register(node, 0);
be_emit_finish_line_gas(node);
}
DEBUG_ONLY(static firm_dbg_module_t *dbg = NULL;)
+static const arch_env_t *arch_env;
+static ia32_code_gen_t *cg;
+
typedef int is_op_func_t(const ir_node *n);
typedef ir_node *load_func_t(dbg_info *db, ir_graph *irg, ir_node *block, ir_node *base, ir_node *index, ir_node *mem);
/**
* Tries to create pushs from IncSP,Store combinations
*/
-static void ia32_create_Pushs(ir_node *irn, ia32_code_gen_t *cg) {
+static void ia32_create_Pushs(ir_node *irn)
+{
int i;
int offset;
ir_node *node;
/**
* Performs Peephole Optimizations.
*/
-static void ia32_peephole_optimize_node(ir_node *node, void *env) {
- ia32_code_gen_t *cg = env;
-
+static void ia32_peephole_optimize_node(ir_node *node, void *env)
+{
+ (void) env;
if (be_is_IncSP(node)) {
ia32_optimize_IncSP(node);
if (cg->opt & IA32_OPT_PUSHARGS)
- ia32_create_Pushs(node, cg);
+ ia32_create_Pushs(node);
}
}
-void ia32_peephole_optimization(ir_graph *irg, ia32_code_gen_t *cg)
+static ir_node *optimize_ia32_Const(ir_node *node)
{
- be_peephole_opt(cg->birg);
- irg_walk_graph(irg, ia32_peephole_optimize_node, NULL, cg);
+ const ia32_immediate_attr_t *attr = get_ia32_immediate_attr_const(node);
+ const arch_register_t *reg;
+ ir_graph *irg = current_ir_graph;
+ ir_node *block;
+ dbg_info *dbgi;
+ ir_node *produceval;
+ ir_node *xor;
+ ir_node *noreg;
+
+ /* try to transform a mov 0, reg to xor reg reg */
+ if(attr->offset != 0 || attr->symconst != NULL)
+ return NULL;
+ /* xor destroys the flags, so noone must be using them */
+ if(be_peephole_get_value(CLASS_ia32_flags, REG_EFLAGS) != NULL)
+ return NULL;
+
+ reg = arch_get_irn_register(arch_env, node);
+ assert(be_peephole_get_reg_value(reg) == NULL);
+
+ /* create xor(produceval, produceval) */
+ block = get_nodes_block(node);
+ dbgi = get_irn_dbg_info(node);
+ produceval = new_rd_ia32_ProduceVal(dbgi, irg, block);
+ arch_set_irn_register(arch_env, produceval, reg);
+
+ noreg = ia32_new_NoReg_gp(cg);
+ xor = new_rd_ia32_Xor(dbgi, irg, block, noreg, noreg, new_NoMem(),
+ produceval, produceval);
+ arch_set_irn_register(arch_env, xor, reg);
+
+ sched_add_before(node, produceval);
+ sched_add_before(node, xor);
+ exchange(node, xor);
+ sched_remove(node);
+
+ return xor;
}
-/******************************************************************
- * _ _ __ __ _
- * /\ | | | | | \/ | | |
- * / \ __| | __| |_ __ ___ ___ ___| \ / | ___ __| | ___
- * / /\ \ / _` |/ _` | '__/ _ \/ __/ __| |\/| |/ _ \ / _` |/ _ \
- * / ____ \ (_| | (_| | | | __/\__ \__ \ | | | (_) | (_| | __/
- * /_/ \_\__,_|\__,_|_| \___||___/___/_| |_|\___/ \__,_|\___|
- *
- ******************************************************************/
+static void register_peephole_optimisation(ir_op *op, peephole_opt_func func)
+{
+ assert(op->ops.generic == NULL);
+ op->ops.generic = (void*) func;
+}
+
+void ia32_peephole_optimization(ir_graph *irg, ia32_code_gen_t *new_cg)
+{
+ cg = new_cg;
+ arch_env = cg->arch_env;
+
+ /* register peephole optimisations */
+ clear_irp_opcodes_generic_func();
+ register_peephole_optimisation(op_ia32_Const, optimize_ia32_Const);
+
+ be_peephole_opt(cg->birg);
+ irg_walk_graph(irg, ia32_peephole_optimize_node, NULL, NULL);
+}
/**
* Removes node from schedule if it is not used anymore. If irn is a mode_T node
cnst = new_rd_ia32_Const(dbgi, irg, block, NULL, 0, val);
SET_IA32_ORIG_NODE(cnst, ia32_get_old_node_name(env_cg, node));
- if(val == 0) {
- set_ia32_flags(cnst,
- get_ia32_flags(cnst) | arch_irn_flags_modify_flags);
- }
/* see above */
if (get_irg_start_block(irg) == block) {
int use_sse2;
/** use ffreep instead of fpop */
int use_ffreep;
- /** use ftst instead of compare */
+ /** use ftst where possible */
int use_ftst;
/** use femms to pop all float registers */
int use_femms;