forgot to adjust mips backend for asm stuff
[libfirm] / ir / be / mips / mips_transform.c
index 10c38c3..190d26a 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 1995-2007 University of Karlsruhe.  All right reserved.
+ * Copyright (C) 1995-2008 University of Karlsruhe.  All right reserved.
  *
  * This file is part of libFirm.
  *
  * PURPOSE.
  */
 
-/* The codegenrator (transform FIRM into mips FIRM */
-/* $Id$ */
-
+/**
+ * @file
+ * @brief   The codegenrator (transform FIRM into mips FIRM
+ * @author  Matthias Braun, Mehdi
+ * @version $Id$
+ */
 #ifdef HAVE_CONFIG_H
 #include "config.h"
 #endif
 #include "iredges.h"
 #include "irvrfy.h"
 #include "ircons.h"
-#include "dbginfo.h"
+#include "irprintf.h"
+#include "irop.h"
 #include "iropt_t.h"
 #include "debug.h"
+#include "error.h"
 
 #include "../benode_t.h"
 #include "../beabi.h"
 #include "../besched.h"
 #include "../besched_t.h"
 #include "../beirg_t.h"
+#include "../betranshlp.h"
 #include "bearch_mips_t.h"
 
 #include "mips_nodes_attr.h"
-#include "../arch/archop.h"     /* we need this for Min and Max nodes */
+#include "archop.h"
 #include "mips_transform.h"
 #include "mips_new_nodes.h"
 #include "mips_map_regs.h"
@@ -54,6 +60,9 @@
 
 #include "gen_mips_regalloc_if.h"
 
+/** hold the current code generator during transformation */
+static mips_code_gen_t *env_cg = NULL;
+
 /****************************************************************************************************
  *                  _        _                        __                           _   _
  *                 | |      | |                      / _|                         | | (_)
  *
  ****************************************************************************************************/
 
-#define MIPS_GENBINFUNC(mips_nodetype)                                                                                                                 \
-       static ir_node* mips_gen_##mips_nodetype(mips_transform_env_t *env, ir_node *op1, ir_node *op2) {\
-               ASSERT_NO_FLOAT(env->mode);                                                                                                                             \
-               /*assert(get_irn_mode(op1) == get_irn_mode(op2));*/                                                                             \
-               /*assert(get_irn_mode(op1) == env->mode);*/                                                                                             \
-               assert(get_mode_size_bits(env->mode) == 32);                                                                                    \
-               return new_rd_mips_##mips_nodetype(env->dbg, env->irg, env->block, op1, op2);           \
-       }
-
-MIPS_GENBINFUNC(addu)
-MIPS_GENBINFUNC(sub)
-MIPS_GENBINFUNC(and)
-MIPS_GENBINFUNC(or)
-MIPS_GENBINFUNC(xor)
-MIPS_GENBINFUNC(sl)
-MIPS_GENBINFUNC(sr)
-MIPS_GENBINFUNC(sra)
-
-#define MIPS_GENUNFUNC(mips_nodetype)                                                                                                                  \
-       static ir_node *mips_gen_##mips_nodetype(mips_transform_env_t *env, ir_node *op) {                      \
-               ASSERT_NO_FLOAT(env->mode);                                                                                                                             \
-               assert(get_irn_mode(op) == env->mode);                                                                                                  \
-               assert(get_mode_size_bits(env->mode) == 32);                                                                                    \
-               return new_rd_mips_##mips_nodetype(env->dbg, env->irg, env->block, op);                     \
-       }
+typedef ir_node *construct_binop_func(dbg_info *db, ir_graph *irg,
+       ir_node *block, ir_node *left, ir_node *right);
 
-MIPS_GENUNFUNC(not)
+static INLINE int mode_needs_gp_reg(ir_mode *mode) {
+       return mode_is_int(mode) || mode_is_reference(mode);
+}
 
-static ir_node* mips_get_reg_node(mips_transform_env_t *env, const arch_register_t *reg) {
-       return be_abi_get_callee_save_irn(env->cg->birg->abi, reg);
+ir_node *mips_create_Immediate(long val)
+{
+       ir_graph *irg   = current_ir_graph;
+       ir_node  *block = get_irg_start_block(irg);
+       const arch_register_t **slots;
+       ir_node  *res;
+
+       assert(val >=  -32768 && val <= 32767);
+       res      = new_rd_mips_Immediate(NULL, irg, block, MIPS_IMM_CONST, NULL,
+                                        val);
+       slots    = get_mips_slots(res);
+       slots[0] = &mips_gp_regs[REG_GP_NOREG];
+
+       return res;
 }
 
-static ir_node* gen_zero_node(mips_transform_env_t *env, dbg_info *ebg, ir_graph *irg, ir_node *block)
+ir_node* mips_create_zero(void)
 {
-       ir_node *zero = be_abi_get_callee_save_irn(env->cg->birg->abi, &mips_gp_regs[REG_ZERO]);
-       // TODO make zero nodes work
-       //ir_node *unknown = new_rd_mips_zero(dbg, irg, block, mode);
+       ir_graph *irg   = current_ir_graph;
+       ir_node  *block = get_irg_start_block(irg);
+       ir_node  *zero  = new_rd_mips_zero(NULL, irg, block);
+       const arch_register_t **slots = get_mips_slots(zero);
+
+       slots[0] = &mips_gp_regs[REG_ZERO];
 
        return zero;
 }
 
-static ir_node* gen_node_for_Const(mips_transform_env_t *env, dbg_info *dbg, ir_graph *irg, ir_node *block, ir_node *constant)
+static ir_node *try_create_Immediate(ir_node *node)
 {
-       tarval* tv = get_Const_tarval(constant);
-       ir_node *lui;
-       ir_node *lli;
-       mips_attr_t *attr;
-       ir_mode* mode = get_irn_mode(constant);
-       unsigned long val, lower, upper;
+       tarval   *tv;
+       long      val;
+       ir_mode  *mode;
 
-       val = get_tarval_long(tv);
-       if(val == 0)
-               return gen_zero_node(env, dbg, irg, block);
+       if(!is_Const(node))
+               return NULL;
 
-       lower = val & 0xffff;
-       upper = (val >> 16) & 0xffff;
-       if(upper == 0) {
-               ir_node *zero = gen_zero_node(env, dbg, irg, block);
-               ir_node *lli = new_rd_mips_lli(dbg, irg, block, zero);
-               attr = get_mips_attr(lli);
-               attr->tv = new_tarval_from_long(val, mode);
+       mode = get_irn_mode(node);
+       if(!mode_needs_gp_reg(mode))
+               return NULL;
 
-               return lli;
+       tv = get_Const_tarval(node);
+       if(tarval_is_long(tv)) {
+               val = get_tarval_long(tv);
+       } else {
+               ir_fprintf(stderr, "Optimisation Warning: tarval %+F is not a long?\n",
+                          node);
+               return NULL;
        }
 
-       lui = new_rd_mips_lui(dbg, irg, block);
-       attr = get_mips_attr(lui);
-       attr->tv = new_tarval_from_long(val, mode);
-
-       if(lower == 0)
-               return lui;
-
-       lli = new_rd_mips_lli(dbg, irg, block, lui);
-       attr = get_mips_attr(lli);
-       attr->tv = new_tarval_from_long(val, mode);
+       if(val < -32768 || val > 32767)
+               return NULL;
 
-       return lli;
+       return mips_create_Immediate(val);
 }
 
-static ir_node* exchange_node_for_Const(mips_transform_env_t *env, ir_node* pred, int n) {
-       ir_node *node = env->irn;
-       dbg_info *dbg = get_irn_dbg_info(pred);
-       ir_graph *irg = get_irn_irg(node);
-       ir_node *block;
-
-       if(get_irn_opcode(node) == iro_Phi) {
-               ir_node *phipred = get_nodes_block(node);
-               block = get_Block_cfgpred_block(phipred, n);
-       } else {
-               block = get_nodes_block(node);
+static void create_binop_operands(ir_node **new_left, ir_node **new_right,
+                                  ir_node *left, ir_node *right,
+                                  int is_commutative)
+{
+       *new_right = try_create_Immediate(right);
+       if(*new_right != NULL) {
+               *new_left = be_transform_node(left);
+               return;
+       }
+       if(is_commutative) {
+               *new_right = try_create_Immediate(left);
+               if(*new_right != NULL) {
+                       *new_left = be_transform_node(right);
+                       return;
+               }
        }
 
-       return gen_node_for_Const(env, dbg, irg, block, pred);
+       *new_left  = be_transform_node(left);
+       *new_right = be_transform_node(right);
 }
 
-static ir_node* gen_node_for_SymConst(mips_transform_env_t *env, ir_node* pred, int n) {
-       ir_node *result;
-       symconst_kind kind;
-       mips_attr_t *attr;
-       ir_node *node = env->irn;
-       dbg_info *dbg = get_irn_dbg_info(pred);
-       ir_graph *irg = get_irn_irg(node);
-       ir_node *block;
-
-       if (is_Phi(node)) {
-               ir_node *phipred = get_nodes_block(node);
-               block = get_Block_cfgpred_block(phipred, n);
+static ir_node *gen_binop(ir_node *node, ir_node *left, ir_node *right,
+                          construct_binop_func func, int supports_immediate)
+{
+       ir_graph *irg   = current_ir_graph;
+       dbg_info *dbgi  = get_irn_dbg_info(node);
+       ir_node  *block = be_transform_node(get_nodes_block(node));
+       ir_node  *res;
+       ir_node  *new_left, *new_right;
+
+       assert(mode_needs_gp_reg(get_irn_mode(node)));
+
+       if(supports_immediate) {
+               int is_commutative = is_op_commutative(get_irn_op(node));
+               create_binop_operands(&new_left, &new_right, left, right,
+                                     is_commutative);
        } else {
-               block = get_nodes_block(node);
+               new_left  = be_transform_node(left);
+               new_right = be_transform_node(right);
        }
 
-       kind = get_SymConst_kind(pred);
-       if(kind == symconst_addr_ent) {
-               result = new_rd_mips_la(dbg, irg, block);
-               attr = get_mips_attr(result);
-               attr->symconst_id = get_entity_ld_ident(get_SymConst_entity(pred));
-               return result;
-       } else if(kind == symconst_addr_name) {
-               result = new_rd_mips_la(dbg, irg, block);
-               attr = get_mips_attr(result);
-               attr->symconst_id = get_SymConst_name(pred);
-               return result;
-       }
+       res = func(dbgi, irg, block, new_left, new_right);
 
-       // TODO
-       assert(0);
-       return NULL;
+       return res;
 }
 
-/**
- * Generates a mips node for a firm Load node
- */
-static ir_node *gen_node_for_Load(mips_transform_env_t *env) {
-       ir_node *node = env->irn;
-       ir_node *result = NULL;
-       ir_mode *mode;
-       ir_node *load_ptr;
-       mips_attr_t *attr;
-
-       ASSERT_NO_FLOAT(get_irn_mode(node));
+static ir_node *gen_Add(ir_node *node)
+{
+       /* TODO: match add(symconst, const) */
+       return gen_binop(node, get_Add_left(node), get_Add_right(node),
+                        new_rd_mips_addu, 1);
+}
 
-       mode = get_Load_mode(node);
-       assert(mode->vector_elem == 1);
-       assert(mode->sort == irms_int_number || mode->sort == irms_reference);
+static ir_node *gen_Sub(ir_node *node)
+{
+       return gen_binop(node, get_Sub_left(node), get_Sub_right(node),
+                        new_rd_mips_addu, 0);
+}
 
-       load_ptr = get_Load_ptr(node);
-       assert(get_mode_sort(mode) == irms_reference || get_mode_sort(mode) == irms_int_number);
-       result = new_rd_mips_load_r(env->dbg, env->irg, env->block,
-                       get_Load_mem(node), load_ptr, get_irn_mode(node));
+static ir_node *gen_And(ir_node *node)
+{
+       return gen_binop(node, get_Add_left(node), get_Add_right(node),
+                        new_rd_mips_and, 1);
+}
 
-       attr = get_mips_attr(result);
-       attr->tv = new_tarval_from_long(0, mode_Iu);
-       attr->modes.load_store_mode = mode;
+static ir_node *gen_Or(ir_node *node)
+{
+       return gen_binop(node, get_Add_left(node), get_Add_right(node),
+                        new_rd_mips_or, 1);
+}
 
-       return result;
+static ir_node *gen_Eor(ir_node *node)
+{
+       return gen_binop(node, get_Add_left(node), get_Add_right(node),
+                        new_rd_mips_xor, 1);
 }
 
-/**
- * Generates a mips node for a firm Store node
- */
-static ir_node *gen_node_for_Store(mips_transform_env_t *env) {
-       ir_node *node = env->irn;
-       ir_node *result = NULL;
-       ir_mode *mode;
-       mips_attr_t *attr;
-       ir_node *store_ptr;
+static ir_node *gen_Shl(ir_node *node)
+{
+       return gen_binop(node, get_Add_left(node), get_Add_right(node),
+                        new_rd_mips_sll, 1);
+}
 
-       ASSERT_NO_FLOAT(env->mode);
+static ir_node *gen_Shr(ir_node *node)
+{
+       return gen_binop(node, get_Add_left(node), get_Add_right(node),
+                        new_rd_mips_srl, 1);
+}
 
-       store_ptr = get_Store_ptr(node);
-       mode = get_irn_mode(store_ptr);
-       assert(mode->vector_elem == 1);
-       assert(mode->sort == irms_int_number || mode->sort == irms_reference);
+static ir_node *gen_Shrs(ir_node *node)
+{
+       return gen_binop(node, get_Add_left(node), get_Add_right(node),
+                        new_rd_mips_sra, 1);
+}
 
-       if(get_irn_opcode(store_ptr) == iro_SymConst) {
-               result = new_rd_mips_store_i(env->dbg, env->irg, env->block, get_Store_mem(node),
-                       get_Store_ptr(node), get_Store_value(node), env->mode);
-       } else {
-               result = new_rd_mips_store_r(env->dbg, env->irg, env->block, get_Store_mem(node),
-                       get_Store_ptr(node), get_Store_value(node), env->mode);
+static ir_node *gen_Not(ir_node *node)
+{
+       ir_graph *irg   = current_ir_graph;
+       dbg_info *dbgi  = get_irn_dbg_info(node);
+       ir_node  *block = be_transform_node(get_nodes_block(node));
+       ir_node  *op    = get_Not_op(node);
+       ir_node  *new_op;
+       ir_node  *res;
+       ir_node  *one;
+
+       /* we can transform not->or to nor */
+       if(is_Or(op)) {
+               return gen_binop(op, get_Or_left(op), get_Or_right(op),
+                                new_rd_mips_nor, 1);
        }
-       attr = get_mips_attr(result);
-       attr->tv = new_tarval_from_long(0, mode_Iu);
-       attr->modes.load_store_mode = mode;
 
-       return result;
+       /* construct (op < 1) */
+       one    = mips_create_Immediate(1);
+       new_op = be_transform_node(op);
+       res    = new_rd_mips_sltu(dbgi, irg, block, new_op, one);
+
+       return res;
 }
 
-static ir_node *gen_node_for_div_Proj(mips_transform_env_t *env) {
-       ir_node *proj = env->irn;
-       ir_node *new_proj;
-       ir_node *pred = get_irn_n(proj, 0);
-       mips_attr_t *attr;
-       long n;
+static ir_node *gen_Minus(ir_node *node)
+{
+       ir_graph *irg    = current_ir_graph;
+       dbg_info *dbgi   = get_irn_dbg_info(node);
+       ir_node  *block  = be_transform_node(get_nodes_block(node));
+       ir_node  *op     = get_Minus_op(node);
+       ir_node  *new_op = be_transform_node(op);
+       ir_node  *res;
+       ir_node  *zero;
+
+       /* construct (0 - op) */
+       zero = mips_create_zero();
+       res  = new_rd_mips_subu(dbgi, irg, block, zero, new_op);
+
+       return res;
+}
 
-       n = get_Proj_proj(proj);
+static ir_node *gen_Abs(ir_node *node)
+{
+       ir_graph *irg    = current_ir_graph;
+       dbg_info *dbgi   = get_irn_dbg_info(node);
+       ir_node  *block  = be_transform_node(get_nodes_block(node));
+       ir_node  *op     = get_Abs_op(node);
+       ir_node  *new_op = be_transform_node(op);
+       ir_node  *sra_const, *sra, *add, *xor;
+
+       /* TODO: support other bit sizes... */
+       assert(get_mode_size_bits(get_irn_mode(node)) == 32);
+       sra_const = mips_create_Immediate(31);
+       sra       = new_rd_mips_sra(dbgi, irg, block, new_op, sra_const);
+       add       = new_rd_mips_addu(dbgi, irg, block, new_op, sra);
+       xor       = new_rd_mips_xor(dbgi, irg, block, sra, add);
 
-       // set the div mode to the DivMod node
-       attr = get_mips_attr(pred);
-       assert(attr->modes.original_mode == NULL || attr->modes.original_mode == env->mode);
-       attr->modes.original_mode = env->mode;
+       return xor;
+}
 
-       // we have to construct a new proj here, to avoid circular refs that
-       // happen when we reuse the old one
-       new_proj = new_ir_node(env->dbg, env->irg, env->block, op_Proj, mode_ANY, 1, &pred);
-       set_Proj_proj(new_proj, n);
+static ir_node* gen_Const(ir_node *node)
+{
+       ir_graph *irg   = current_ir_graph;
+       dbg_info *dbgi  = get_irn_dbg_info(node);
+       ir_node  *block = be_transform_node(get_nodes_block(node));
+       tarval   *tv    = get_Const_tarval(node);
+       ir_node  *upper_node;
+       ir_node  *lower_node;
+       ir_node  *or_const;
+       unsigned long val, lower, upper;
 
-       if(n == pn_DivMod_res_div) {
-               return new_rd_mips_mflo(env->dbg, env->irg, env->block, new_proj);
-       } else if(n == pn_DivMod_res_mod) {
-               return new_rd_mips_mfhi(env->dbg, env->irg, env->block, new_proj);
+       if(tarval_is_long(tv)) {
+               val = get_tarval_long(tv);
+       } else {
+               panic("Can't get value of tarval %+F\n", node);
        }
 
-       return proj;
-}
+       val = get_tarval_long(tv);
 
-static ir_node *make_jmp_or_fallthrough(mips_transform_env_t *env)
-{
-       const ir_edge_t *edge;
-       ir_node *node = env->irn;
-       ir_node *next_block;
-       int our_block_sched_nr = mips_get_block_sched_nr(get_nodes_block(node));
+       lower = val & 0xffff;
+       upper = (val >> 16) & 0xffff;
+       if(upper == 0) {
+               upper_node = mips_create_zero();
+       } else {
+               upper_node = new_rd_mips_lui(dbgi, irg, block, MIPS_IMM_CONST, NULL,
+                                            upper);
+       }
 
-       edge = get_irn_out_edge_first(node);
-       next_block = get_edge_src_irn(edge);
+       if(lower == 0)
+               return upper_node;
 
-       if(mips_get_sched_block(env->cg, our_block_sched_nr + 1) == next_block) {
-               return new_rd_mips_fallthrough(env->dbg, env->irg, env->block, mode_X);
-       }
+       or_const   = mips_create_Immediate(lower);
+       lower_node = new_rd_mips_or(dbgi, irg, block, upper_node, or_const);
 
-       return new_rd_mips_b(env->dbg, env->irg, env->block, mode_X);
+       return lower_node;
 }
 
-static ir_node *gen_node_for_Cond_Proj(mips_transform_env_t *env, ir_node* node, int true_false)
+static ir_node* gen_SymConst(ir_node *node)
 {
-       // we can't use get_Cond_selector here because the selector is already
-       // replaced by a mips_ compare node
-       ir_node *proj = get_Cond_selector(node);
-       ir_node *original_cmp = get_irn_n(proj, 0);
-       ir_node *cmp;
-       ir_node *condjmp;
-       ir_node *op1, *op2;
-       dbg_info *dbg = env->dbg;
-       ir_graph *irg = env->irg;
-       ir_node *block = env->block;
-       long n;
+       ir_graph *irg   = current_ir_graph;
+       dbg_info *dbgi  = get_irn_dbg_info(node);
+       ir_node  *block = be_transform_node(get_nodes_block(node));
+       ir_entity *entity;
+       ir_node *lui, *or_const, *or;
+
+       if(get_SymConst_kind(node) != symconst_addr_ent) {
+               panic("Only address entity symconsts supported in mips backend");
+       }
 
-       n = get_Proj_proj(proj);
-       assert(n < 8 && "Only ordered comps supported");
+       entity = get_SymConst_entity(node);
 
-       assert(get_irn_opcode(original_cmp) == iro_Cmp);
-       op1 = get_Cmp_left(original_cmp);
-       op2 = get_Cmp_right(original_cmp);
+       lui            = new_rd_mips_lui(dbgi, irg, block, MIPS_IMM_SYMCONST_HI,
+                                        entity, 0);
+       or_const       = new_rd_mips_Immediate(dbgi, irg, block,
+                                              MIPS_IMM_SYMCONST_LO, entity, 0);
+       or             = new_rd_mips_or(dbgi, irg, block, lui, or_const);
 
-       switch(n) {
-       case pn_Cmp_False:
-               if(true_false)
-                       return NULL;
+       return or;
+}
 
-               return make_jmp_or_fallthrough(env);
+typedef ir_node* (*gen_load_func) (dbg_info *dbg, ir_graph *irg,
+                                   ir_node *block, ir_node *ptr, ir_node *mem,
+                                   ir_entity *entity, long offset);
 
-       case pn_Cmp_Eq:
-               if(!true_false)
-                       return make_jmp_or_fallthrough(env);
+/**
+ * Generates a mips node for a firm Load node
+ */
+static ir_node *gen_Load(ir_node *node)
+{
+       ir_graph *irg     = current_ir_graph;
+       dbg_info *dbgi    = get_irn_dbg_info(node);
+       ir_node  *block   = be_transform_node(get_nodes_block(node));
+       ir_node  *mem     = get_Load_mem(node);
+       ir_node  *new_mem = be_transform_node(mem);
+       ir_node  *ptr     = get_Load_ptr(node);
+       ir_node  *new_ptr = be_transform_node(ptr);
+       ir_mode  *mode    = get_Load_mode(node);
+       int       sign    = get_mode_sign(mode);
+       ir_node  *res;
+       gen_load_func func;
+
+       ASSERT_NO_FLOAT(mode);
+       assert(mode_needs_gp_reg(mode));
+
+       /* TODO: make use of offset in ptrs */
+
+       switch(get_mode_size_bits(mode)) {
+       case 32:
+               func = new_rd_mips_lw;
+               break;
+       case 16:
+               func = sign ? new_rd_mips_lh : new_rd_mips_lhu;
+               break;
+       case 8:
+               func = sign ? new_rd_mips_lb : new_rd_mips_lbu;
+               break;
+       default:
+               panic("mips backend only support 32, 16, 8 bit loads");
+       }
 
-               condjmp = new_rd_mips_beq(dbg, irg, block, op1, op2, mode_T);
-               return new_rd_Proj(dbg, irg, block, condjmp, mode_X, 1);
+       res = func(dbgi, irg, block, new_ptr, new_mem, NULL, 0);
+       set_irn_pinned(res, get_irn_pinned(node));
 
-       case pn_Cmp_Lt:
-               if(!true_false)
-                       return make_jmp_or_fallthrough(env);
+       return res;
+}
 
-               cmp = new_rd_mips_slt(dbg, irg, block, op1, op2);
-               condjmp = new_rd_mips_bgtz(dbg, irg, block, cmp, mode_T);
-               return new_rd_Proj(dbg, irg, block, condjmp, mode_X, 1);
+typedef ir_node* (*gen_store_func) (dbg_info *dbg, ir_graph *irg,
+                                    ir_node *block, ir_node *ptr, ir_node *val,
+                                    ir_node *mem, ir_entity *ent, long offset);
 
-       case pn_Cmp_Le:
-               if(!true_false)
-                       return make_jmp_or_fallthrough(env);
+/**
+ * Generates a mips node for a firm Store node
+ */
+static ir_node *gen_Store(ir_node *node)
+{
+       ir_graph    *irg     = current_ir_graph;
+       dbg_info    *dbgi    = get_irn_dbg_info(node);
+       ir_node     *block   = be_transform_node(get_nodes_block(node));
+       ir_node     *mem     = get_Store_mem(node);
+       ir_node     *new_mem = be_transform_node(mem);
+       ir_node     *ptr     = get_Store_ptr(node);
+       ir_node     *new_ptr = be_transform_node(ptr);
+       ir_node     *val     = get_Store_value(node);
+       ir_node     *new_val = be_transform_node(val);
+       ir_mode     *mode    = get_irn_mode(val);
+       gen_store_func func;
+       ir_node     *res;
+
+       assert(mode_needs_gp_reg(mode));
+
+       switch(get_mode_size_bits(mode)) {
+       case 32:
+               func = new_rd_mips_sw;
+               break;
+       case 16:
+               func = new_rd_mips_sh;
+               break;
+       case 8:
+               func = new_rd_mips_sb;
+               break;
+       default:
+               panic("store only supported for 32, 16, 8 bit values in mips backend");
+       }
 
-               cmp = new_rd_mips_slt(dbg, irg, block, op2, op1);
-               condjmp = new_rd_mips_blez(dbg, irg, block, cmp, mode_T);
-               return new_rd_Proj(dbg, irg, block, condjmp, mode_X, 1);
+       res = func(dbgi, irg, block, new_ptr, new_val, new_mem, NULL, 0);
+       set_irn_pinned(res, get_irn_pinned(node));
 
-       case pn_Cmp_Gt:
-               if(!true_false)
-                       return make_jmp_or_fallthrough(env);
+       return res;
+}
 
-               cmp = new_rd_mips_slt(dbg, irg, block, op2, op1);
-               condjmp = new_rd_mips_bgtz(dbg, irg, block, cmp, mode_T);
-               return new_rd_Proj(dbg, irg, block, condjmp, mode_X, 1);
+static ir_node *gen_Proj_DivMod(ir_node *node)
+{
+       ir_graph *irg     = current_ir_graph;
+       dbg_info *dbgi    = get_irn_dbg_info(node);
+       ir_node  *block   = be_transform_node(get_nodes_block(node));
+       ir_node  *divmod  = get_Proj_pred(node);
+       ir_node  *new_div = be_transform_node(divmod);
+       long      pn      = get_Proj_proj(node);
+       ir_node  *proj;
 
-       case pn_Cmp_Ge:
-               if(!true_false)
-                       return make_jmp_or_fallthrough(env);
+       assert(is_mips_div(new_div) || is_mips_divu(new_div));
 
-               cmp = new_rd_mips_slt(dbg, irg, block, op1, op2);
-               condjmp = new_rd_mips_blez(dbg, irg, block, cmp, mode_T);
-               return new_rd_Proj(dbg, irg, block, condjmp, mode_X, 1);
+       switch(get_irn_opcode(divmod)) {
+       case iro_Div:
+               switch(pn) {
+               case pn_Div_M:
+                       return new_rd_Proj(dbgi, irg, block, new_div, mode_M,
+                                          pn_mips_div_M);
+               case pn_Div_res:
+                       proj = new_rd_Proj(dbgi, irg, block, new_div, mode_M,
+                                          pn_mips_div_lohi);
+                       return new_rd_mips_mflo(dbgi, irg, block, proj);
+               default:
+                       break;
+               }
+       case iro_Mod:
+               switch(pn) {
+               case pn_Mod_M:
+                       return new_rd_Proj(dbgi, irg, block, new_div, mode_M,
+                                          pn_mips_div_M);
+               case pn_Mod_res:
+                       proj = new_rd_Proj(dbgi, irg, block, new_div, mode_M,
+                                          pn_mips_div_lohi);
+                       return new_rd_mips_mfhi(dbgi, irg, block, proj);
+               default:
+                       break;
+               }
 
-       case pn_Cmp_Lg:
-               if(!true_false)
-                       return make_jmp_or_fallthrough(env);
+       case iro_DivMod:
+               switch(pn) {
+               case pn_Div_M:
+                       return new_rd_Proj(dbgi, irg, block, new_div, mode_M,
+                                          pn_mips_div_M);
+               case pn_DivMod_res_div:
+                       proj = new_rd_Proj(dbgi, irg, block, new_div, mode_M,
+                                          pn_mips_div_lohi);
+                       return new_rd_mips_mflo(dbgi, irg, block, proj);
+               case pn_DivMod_res_mod:
+                       proj = new_rd_Proj(dbgi, irg, block, new_div, mode_M,
+                                          pn_mips_div_lohi);
+                       return new_rd_mips_mfhi(dbgi, irg, block, proj);
+               default:
+                       break;
+               }
+       default:
+               break;
+       }
 
-               condjmp = new_rd_mips_bne(dbg, irg, block, op1, op2, mode_T);
-               return new_rd_Proj(dbg, irg, block, condjmp, mode_X, 1);
+       panic("invalid proj attached to %+F\n", divmod);
+}
 
-       case pn_Cmp_Leg:
-               if(!true_false)
-                       return NULL;
+static ir_node *gen_Proj_Start(ir_node *node)
+{
+       ir_graph *irg   = current_ir_graph;
+       dbg_info *dbgi  = get_irn_dbg_info(node);
+       ir_node  *block = be_transform_node(get_nodes_block(node));
+       long      pn    = get_Proj_proj(node);
+
+       if(pn == pn_Start_X_initial_exec) {
+               /* we exchange the projx with a jump */
+               ir_node *jump = new_rd_Jmp(dbgi, irg, block);
+               return jump;
+       }
+       if(node == get_irg_anchor(irg, anchor_tls)) {
+               /* TODO... */
+               return be_duplicate_node(node);
+       }
+       return be_duplicate_node(node);
+}
 
-               return make_jmp_or_fallthrough(env);
+static ir_node *gen_Proj(ir_node *node)
+{
+       ir_graph *irg  = current_ir_graph;
+       dbg_info *dbgi = get_irn_dbg_info(node);
+       ir_node  *pred = get_Proj_pred(node);
+
+       switch(get_irn_opcode(pred)) {
+       case iro_Load:
+               break;
+       case iro_Store:
+               break;
+       case iro_Div:
+       case iro_Mod:
+       case iro_DivMod:
+               return gen_Proj_DivMod(node);
+
+       case iro_Start:
+               return gen_Proj_Start(node);
 
        default:
-               assert(0);
+               assert(get_irn_mode(node) != mode_T);
+               if(mode_needs_gp_reg(get_irn_mode(node))) {
+                       ir_node *new_pred = be_transform_node(pred);
+                       ir_node *block    = be_transform_node(get_nodes_block(node));
+                       long     pn       = get_Proj_proj(node);
+
+                       return new_rd_Proj(dbgi, irg, block, new_pred, mode_Iu, pn);
+               }
+               break;
        }
 
-       return NULL;
+       return be_duplicate_node(node);
 }
 
-static ir_node *gen_node_for_Proj(mips_transform_env_t *env)
+static ir_node *gen_Phi(ir_node *node)
 {
-       ir_node *proj = env->irn;
-       long n;
-       ir_node *predecessor = get_Proj_pred(proj);
-
-       // all DivMods, Div, Mod should be replaced by now
-       assert(get_irn_opcode(predecessor) != iro_DivMod);
-       assert(get_irn_opcode(predecessor) != iro_Div);
-       assert(get_irn_opcode(predecessor) != iro_Mod);
-
-       if(is_mips_div(predecessor))
-               return gen_node_for_div_Proj(env);
-
-       if(get_irn_opcode(predecessor) == iro_Cond) {
-               ir_node *selector = get_Cond_selector(predecessor);
-               ir_mode *mode = get_irn_mode(selector);
-               n = get_Proj_proj(proj);
-
-               if(get_mode_sort(mode) == irms_internal_boolean) {
-                       assert(n == pn_Cond_true || n == pn_Cond_false);
-                       return gen_node_for_Cond_Proj(env, predecessor, n == pn_Cond_true);
-               }
+       ir_graph *irg   = current_ir_graph;
+       dbg_info *dbgi  = get_irn_dbg_info(node);
+       ir_node  *block = be_transform_node(get_nodes_block(node));
+       ir_mode  *mode  = get_irn_mode(node);
+       ir_node  *phi;
+
+       if(mode_needs_gp_reg(mode)) {
+               assert(get_mode_size_bits(mode) <= 32);
+               mode = mode_Iu;
        }
 
-       return proj;
+       /* phi nodes allow loops, so we use the old arguments for now
+        * and fix this later */
+       phi = new_ir_node(dbgi, irg, block, op_Phi, mode, get_irn_arity(node),
+                         get_irn_in(node) + 1);
+       copy_node_attr(node, phi);
+       be_duplicate_deps(node, phi);
+
+       be_set_transformed_node(node, phi);
+       be_enqueue_preds(node);
+
+       return phi;
 }
 
-static ir_node *gen_node_for_Cond(mips_transform_env_t *env)
+#if 0
+static
+ir_node *gen_node_for_SwitchCond(mips_transform_env_t *env)
 {
        ir_node *selector = get_Cond_selector(env->irn);
        ir_mode *selector_mode = get_irn_mode(selector);
@@ -511,154 +682,157 @@ static ir_node *gen_node_for_Cond(mips_transform_env_t *env)
 
        return switchjmp;
 }
+#endif
 
-static ir_node *create_conv_store_load(mips_transform_env_t *env, ir_mode* srcmode, ir_mode* dstmode) {
-       ir_node *nomem, *store, *mem_proj, *value_proj, *load;
-       ir_entity *mem_entity;
-       ir_node *node = env->irn;
-       ir_node *pred = get_Conv_op(node);
-       ir_node *sp;
-       // TODO HACK make this global...
-       ident* id;
-       ir_type *i32type;
-       ir_type *ptr_i32type;
-       mips_attr_t* attr;
-
-       id = new_id_from_str("__conv0");
-       i32type = new_type_primitive(new_id_from_str("ptr32"), mode_Iu);
-       ptr_i32type = new_d_type_pointer(id, i32type, mode_P, env->dbg);
-       mem_entity = new_d_entity(get_irg_frame_type(env->irg), id, ptr_i32type, env->dbg);
-
-       sp = mips_get_reg_node(env, &mips_gp_regs[REG_SP]);
-       nomem = new_ir_node(env->dbg, env->irg, env->block, op_NoMem, mode_M, 0, NULL);
-
-       store = new_rd_mips_store_r(env->dbg, env->irg, env->block, nomem, sp, pred, mode_T);
-       attr = get_mips_attr(store);
-       attr->tv = new_tarval_from_long(0, mode_Iu);
-       attr->modes.load_store_mode = srcmode;
-       attr->stack_entity = mem_entity;
-
-       mem_proj = new_ir_node(env->dbg, env->irg, env->block, op_Proj, mode_M, 1, &store);
-       set_Proj_proj(mem_proj, pn_Store_M);
-
-       load = new_rd_mips_load_r(env->dbg, env->irg, env->block, mem_proj, sp, mode_T);
-       attr = get_mips_attr(load);
-       attr->tv = new_tarval_from_long(0, mode_Iu);
-       attr->modes.load_store_mode = dstmode;
-       attr->stack_entity = mem_entity;
+static ir_node *gen_Cond(ir_node *node)
+{
+       ir_graph *irg       = current_ir_graph;
+       dbg_info *dbgi      = get_irn_dbg_info(node);
+       ir_node  *block     = get_nodes_block(node);
+       ir_node  *sel_proj  = get_Cond_selector(node);
+       ir_node  *cmp       = get_Proj_pred(sel_proj);
+       ir_node  *left      = get_Cmp_left(cmp);
+       ir_node  *new_left  = be_transform_node(left);
+       ir_node  *right     = get_Cmp_right(cmp);
+       ir_node  *new_right = be_transform_node(right);
+       long      pnc       = get_Proj_proj(sel_proj);
+       ir_node  *res;
+       ir_node  *slt;
+       ir_node  *zero;
+
+       /* TODO: use blez & co. when possible */
+
+       switch(pnc) {
+       case pn_Cmp_False:
+       case pn_Cmp_True:
+       case pn_Cmp_Leg:
+               panic("mips backend can't handle unoptimized constant Cond");
 
-       value_proj = new_ir_node(env->dbg, env->irg, env->block, op_Proj, env->mode, 1, &load);
-       set_Proj_proj(value_proj, pn_Load_res);
+       case pn_Cmp_Eq:
+               res = new_rd_mips_beq(dbgi, irg, block, new_left, new_right);
+               break;
 
-       return value_proj;
-}
+       case pn_Cmp_Lt:
+               zero = mips_create_zero();
+               slt  = new_rd_mips_slt(dbgi, irg, block, new_left, new_right);
+               res  = new_rd_mips_bne(dbgi, irg, block, slt, zero);
+               break;
 
-static ir_node *create_conv_and(mips_transform_env_t *env, long immediate) {
-       ir_node *node = env->irn;
-       ir_node *pred;
-       ir_node *result;
-       mips_attr_t *attr;
+       case pn_Cmp_Le:
+               zero = mips_create_zero();
+               slt  = new_rd_mips_slt(dbgi, irg, block, new_right, new_left);
+               res  = new_rd_mips_beq(dbgi, irg, block, slt, zero);
+               break;
 
-       pred = get_Conv_op(node);
-       result = new_rd_mips_andi(env->dbg, env->irg, env->block, pred);
-       attr = get_mips_attr(result);
-       attr->tv = new_tarval_from_long(immediate, mode_Iu);
+       case pn_Cmp_Gt:
+               zero = mips_create_zero();
+               slt  = new_rd_mips_slt(dbgi, irg, block, new_right, new_left);
+               res  = new_rd_mips_bne(dbgi, irg, block, slt, zero);
+               break;
 
-       return result;
-}
+       case pn_Cmp_Ge:
+               zero = mips_create_zero();
+               slt  = new_rd_mips_slt(dbgi, irg, block, new_right, new_left);
+               res  = new_rd_mips_bne(dbgi, irg, block, slt, zero);
+               break;
 
-static ir_node *gen_node_for_Conv(mips_transform_env_t *env) {
-       ir_node *node = env->irn;
-       ir_node *pred;
-       ir_mode *srcmode;
-       ir_mode *destmode;
-       int dst_size, src_size;
+       case pn_Cmp_Lg:
+               res = new_rd_mips_bne(dbgi, irg, block, new_left, new_right);
+               break;
 
-       pred = get_Conv_op(node);
-       srcmode = get_irn_mode(pred);
-       destmode = get_irn_mode(node);
+       default:
+               panic("mips backend doesn't handle unordered compares yet");
+       }
 
-       dst_size = get_mode_size_bits(destmode);
-       src_size = get_mode_size_bits(srcmode);
+       return res;
+}
 
-       if(srcmode->size >= destmode->size) {
-               assert(srcmode->size > destmode->size || srcmode->sign != destmode->sign);
-               return new_rd_mips_reinterpret_conv(env->dbg, env->irg, env->block, pred);
+static ir_node *gen_Conv(ir_node *node)
+{
+       ir_graph *irg      = current_ir_graph;
+       dbg_info *dbgi     = get_irn_dbg_info(node);
+       ir_node  *block    = be_transform_node(get_nodes_block(node));
+       ir_node  *op       = get_Conv_op(node);
+       ir_node  *new_op   = be_transform_node(op);
+       ir_mode  *src_mode = get_irn_mode(op);
+       ir_mode  *dst_mode = get_irn_mode(node);
+       int       src_size = get_mode_size_bits(src_mode);
+       int       dst_size = get_mode_size_bits(dst_mode);
+       ir_node  *res;
+
+       assert(mode_needs_gp_reg(src_mode));
+       assert(mode_needs_gp_reg(dst_mode));
+
+       /* we only need to do something on upconvs */
+       if(src_size >= dst_size) {
+               /* unnecessary conv */
+               return new_op;
        }
-       if(srcmode->sign) {
-               if(srcmode->size == 8) {
-                       return create_conv_store_load(env, mode_Bs, mode_Bs);
-               } else if(srcmode->size == 16) {
-                       return create_conv_store_load(env, mode_Hs, mode_Hs);
+
+       if(mode_is_signed(src_mode)) {
+               if(src_size == 8) {
+                       res = new_rd_mips_seb(dbgi, irg, block, new_op);
+               } else if(src_size == 16) {
+                       res = new_rd_mips_seh(dbgi, irg, block, new_op);
+               } else {
+                       panic("invalid conv %+F\n", node);
                }
        } else {
+               ir_node *and_const;
+
                if(src_size == 8) {
-                       return create_conv_and(env, 0xff);
+                       and_const = mips_create_Immediate(0xff);
                } else if(src_size == 16) {
-                       return create_conv_and(env, 0xffff);
+                       and_const = mips_create_Immediate(0xffff);
+               } else {
+                       panic("invalid conv %+F\n", node);
                }
+               res = new_rd_mips_and(dbgi, irg, block, new_op, and_const);
        }
 
-       assert(0);
-       return NULL;
+       return res;
 }
 
-static ir_node *gen_node_mips_div(mips_transform_env_t *env, ir_node* op1, ir_node* op2, long p_div, long p_mod,
-                                                                 long p_m, long p_x)
+static ir_node *create_div(ir_node *node, ir_node *left, ir_node *right,
+                           ir_mode *mode)
 {
-       ir_node *node = env->irn;
-       ir_node *div;
-       const ir_edge_t *edge;
-       ir_mode *mode = get_irn_mode(node);
+       ir_graph *irg       = current_ir_graph;
+       dbg_info *dbgi      = get_irn_dbg_info(node);
+       ir_node  *block     = be_transform_node(get_nodes_block(node));
+       ir_node  *new_left  = be_transform_node(left);
+       ir_node  *new_right = be_transform_node(right);
+       ir_node  *res;
 
        if(mode_is_signed(mode)) {
-               div = new_rd_mips_div(env->dbg, env->irg, env->block, op1, op2);
+               res = new_rd_mips_div(dbgi, irg, block, new_left, new_right);
        } else {
-               div = new_rd_mips_divu(env->dbg, env->irg, env->block, op1, op2);
+               res = new_rd_mips_divu(dbgi, irg, block, new_left, new_right);
        }
 
-       // Adjust div projs
-       foreach_out_edge(node, edge) {
-               ir_node *proj = get_edge_src_irn(edge);
-               long n = get_Proj_proj(proj);
-               assert(is_Proj(proj) && "non-Proj from Mod node");
-               if (n == p_div) {
-                       set_Proj_proj(proj, pn_DivMod_res_div);
-               } else if (n == p_mod) {
-                       set_Proj_proj(proj, pn_DivMod_res_mod);
-               } else if(n == p_m) {
-                       set_Proj_proj(proj, pn_DivMod_M);
-               } else if(n == p_x) {
-                       set_Proj_proj(proj, pn_DivMod_X_except);
-               } else {
-                       assert(!"invalid proj");
-               }
-       }
+       set_irn_pinned(res, get_irn_pinned(node));
 
-       return div;
+       return res;
 }
 
-static ir_node *gen_node_for_DivMod(mips_transform_env_t *env) {
-       ir_node *node = env->irn;
-
-       return gen_node_mips_div(env, get_DivMod_left(node), get_DivMod_right(node), pn_DivMod_res_div,
-                                                        pn_DivMod_res_mod, pn_DivMod_M, pn_DivMod_X_except);
+static ir_node *gen_DivMod(ir_node *node)
+{
+       return create_div(node, get_DivMod_left(node), get_DivMod_right(node),
+                         get_DivMod_resmode(node));
 }
 
-static ir_node *gen_node_for_Div(mips_transform_env_t *env) {
-       ir_node *node = env->irn;
-
-       return gen_node_mips_div(env, get_Div_left(node), get_Div_right(node), pn_Div_res, -1,
-                                                        pn_Div_M, pn_Div_X_except);
+static ir_node *gen_Div(ir_node *node)
+{
+       return create_div(node, get_Div_left(node), get_Div_right(node),
+                         get_Div_resmode(node));
 }
 
-static ir_node *gen_node_for_Mod(mips_transform_env_t *env) {
-       ir_node *node = env->irn;
-
-       return gen_node_mips_div(env, get_Mod_left(node), get_Mod_right(node), -1, pn_Mod_res,
-                                                        pn_Mod_M, pn_Mod_X_except);
+static ir_node *gen_Mod(ir_node *node)
+{
+       return create_div(node, get_Mod_left(node), get_Mod_right(node),
+                         get_Mod_resmode(node));
 }
 
+#if 0
 static ir_node *gen_node_for_Mul(mips_transform_env_t *env) {
        ir_node *node = env->irn;
        ir_node *mul;
@@ -683,33 +857,19 @@ static ir_node *gen_node_for_Mul(mips_transform_env_t *env) {
        return mflo;
 }
 
-static ir_node *gen_node_for_IJmp(mips_transform_env_t *env) {
-       ir_node *node = env->irn;
-
-       return new_rd_mips_j(env->dbg, env->irg, env->block, get_IJmp_target(node), node->mode);
-}
+static
+ir_node *gen_node_for_IJmp(mips_transform_env_t *env) {
+       ir_graph *irg    = env->irg;
+       ir_node  *node   = env->irn;
+       dbg_info *dbg    = get_irn_dbg_info(node);
+       ir_node  *block  = get_nodes_block(node);
+       ir_node  *target = get_IJmp_target(node);
 
-static ir_node *gen_node_for_Jmp(mips_transform_env_t *env) {
-       return make_jmp_or_fallthrough(env);
+       return new_rd_mips_jr(dbg, irg, block, target);
 }
 
-static ir_node *gen_node_for_Abs(mips_transform_env_t *env) {
-       ir_node *node = env->irn;
-       ir_node *sra, *add, *xor;
-       mips_attr_t *attr;
-
-       // TODO for other bit sizes...
-       assert(get_mode_size_bits(env->mode) == 32);
-       sra = new_rd_mips_srai(env->dbg, env->irg, env->block, get_Abs_op(node));
-       attr = get_mips_attr(sra);
-       attr->tv = new_tarval_from_long(31, mode_Iu);
-       add = new_rd_mips_addu(env->dbg, env->irg, env->block, get_Abs_op(node), sra);
-       xor = new_rd_mips_xor(env->dbg, env->irg, env->block, sra, add);
-
-       return xor;
-}
-
-static ir_node *gen_node_for_Rot(mips_transform_env_t *env) {
+static
+ir_node *gen_node_for_Rot(mips_transform_env_t *env) {
        ir_node *node = env->irn;
        ir_node *subu, *srlv, *sllv, *or;
 
@@ -720,12 +880,16 @@ static ir_node *gen_node_for_Rot(mips_transform_env_t *env) {
 
        return or;
 }
+#endif
 
-static ir_node *gen_node_for_Unknown(mips_transform_env_t *env)
+static ir_node *gen_Unknown(ir_node *node)
 {
-       return gen_zero_node(env, env->dbg, env->irg, env->block);
+       (void) node;
+       assert(mode_needs_gp_reg(get_irn_mode(node)));
+       return mips_create_zero();
 }
 
+#if 0
 /*
  * lower a copyB into standard Firm assembler :-)
  */
@@ -878,36 +1042,30 @@ static void mips_fix_CopyB_Proj(mips_transform_env_t* env) {
                set_Proj_proj(node, pn_Store_X_except);
        }
 }
+#endif
 
 static void mips_transform_Spill(mips_transform_env_t* env) {
        ir_node   *node = env->irn;
        ir_node   *sched_point = NULL;
-       ir_node   *store, *proj;
+       ir_node   *store;
        ir_node   *nomem = new_rd_NoMem(env->irg);
        ir_node   *ptr   = get_irn_n(node, 0);
        ir_node   *val   = get_irn_n(node, 1);
        ir_entity *ent   = be_get_frame_entity(node);
-       mips_attr_t *attr;
 
        if(sched_is_scheduled(node)) {
                sched_point = sched_prev(node);
        }
 
-       store = new_rd_mips_store_r(env->dbg, env->irg, env->block, nomem, ptr, val, mode_T);
-       attr = get_mips_attr(store);
-       attr->stack_entity = ent;
-       attr->modes.load_store_mode = get_irn_mode(val);
-
-       proj = new_rd_Proj(env->dbg, env->irg, env->block, store, mode_M, pn_Store_M);
+       store = new_rd_mips_sw(env->dbg, env->irg, env->block, ptr, val, nomem,
+                              ent, 0);
 
        if (sched_point) {
                sched_add_after(sched_point, store);
-               sched_add_after(store, proj);
-
                sched_remove(node);
        }
 
-       exchange(node, proj);
+       exchange(node, store);
 }
 
 static void mips_transform_Reload(mips_transform_env_t* env) {
@@ -916,25 +1074,19 @@ static void mips_transform_Reload(mips_transform_env_t* env) {
        ir_node   *load, *proj;
        ir_node   *ptr   = get_irn_n(node, 0);
        ir_node   *mem   = get_irn_n(node, 1);
-       ir_mode   *mode  = get_irn_mode(node);
        ir_entity *ent   = be_get_frame_entity(node);
        const arch_register_t* reg;
-       mips_attr_t *attr;
 
        if(sched_is_scheduled(node)) {
                sched_point = sched_prev(node);
        }
 
-       load = new_rd_mips_load_r(env->dbg, env->irg, env->block, mem, ptr, mode_T);
-       attr = get_mips_attr(load);
-       attr->stack_entity = ent;
-       attr->modes.load_store_mode = mode;
+       load = new_rd_mips_lw(env->dbg, env->irg, env->block, ptr, mem, ent, 0);
 
-       proj = new_rd_Proj(env->dbg, env->irg, env->block, load, mode, pn_Load_res);
+       proj = new_rd_Proj(env->dbg, env->irg, env->block, load, mode_Iu, pn_mips_lw_res);
 
        if (sched_point) {
                sched_add_after(sched_point, load);
-               sched_add_after(load, proj);
 
                sched_remove(node);
        }
@@ -946,26 +1098,8 @@ static void mips_transform_Reload(mips_transform_env_t* env) {
        exchange(node, proj);
 }
 
-static ir_node *gen_node_for_StackParam(mips_transform_env_t *env)
-{
-       ir_node *node = env->irn;
-       ir_node *sp = get_irn_n(node, 0);
-       ir_node *load;
-       ir_node *nomem = new_rd_NoMem(env->irg);
-       ir_node *proj;
-       mips_attr_t *attr;
-
-       load = new_rd_mips_load_r(env->dbg, env->irg, env->block, nomem, sp, mode_T);
-       attr = get_mips_attr(load);
-       attr->stack_entity = be_get_frame_entity(node);
-       attr->modes.load_store_mode = env->mode;
-
-       proj = new_rd_Proj(env->dbg, env->irg, env->block, load, env->mode, pn_Load_res);
-
-       return proj;
-}
-
-static ir_node *gen_node_for_AddSP(mips_transform_env_t *env)
+#if 0
+static ir_node *gen_AddSP(ir_node *node)
 {
        ir_node *node = env->irn;
        ir_node *op1, *op2;
@@ -983,6 +1117,7 @@ static ir_node *gen_node_for_AddSP(mips_transform_env_t *env)
 
        return add;
 }
+#endif
 
 /*********************************************************
  *                  _             _      _
@@ -994,198 +1129,59 @@ static ir_node *gen_node_for_AddSP(mips_transform_env_t *env)
  *
  *********************************************************/
 
-
-/**
- * Transforms the given firm node (and maybe some other related nodes)
- * into one or more assembler nodes.
- *
- * @param node    the firm node
- * @param env     the debug module
- */
-void mips_transform_node(ir_node *node, void *env) {
-       mips_code_gen_t *cgenv = (mips_code_gen_t *)env;
-       ir_opcode code         = get_irn_opcode(node);
-       ir_node *asm_node      = node;
-       mips_transform_env_t tenv;
-
-       if (is_Block(node))
-               return;
-
-       tenv.block    = get_nodes_block(node);
-       tenv.dbg      = get_irn_dbg_info(node);
-       tenv.irg      = current_ir_graph;
-       tenv.irn      = node;
-       DEBUG_ONLY(tenv.mod      = cgenv->mod;)
-       tenv.mode     = get_irn_mode(node);
-       tenv.cg           = cgenv;
-
-#define UNOP(firm_opcode, mips_nodetype)        case iro_##firm_opcode: asm_node = mips_gen_##mips_nodetype(&tenv, get_##firm_opcode##_op(node)); break
-#define BINOP(firm_opcode, mips_nodetype)       case iro_##firm_opcode: asm_node = mips_gen_##mips_nodetype(&tenv, get_##firm_opcode##_left(node), get_##firm_opcode##_right(node)); break
-#define IGN(a)         case iro_##a: break
-#define BAD(a)         case iro_##a: goto bad
-
-       DBG((tenv.mod, LEVEL_1, "check %+F ... ", node));
-
-       switch (code) {
-               BINOP(Add, addu);
-               BINOP(Sub, sub);
-               BINOP(And, and);
-               BINOP(Or, or);
-               BINOP(Eor, xor);
-               UNOP(Not, not);
-               BINOP(Shl, sl);
-               BINOP(Shr, sr);
-               BINOP(Shrs, sra);
-
-       case iro_Abs:
-               asm_node = gen_node_for_Abs(&tenv);
-               break;
-
-       case iro_Rot:
-               asm_node = gen_node_for_Rot(&tenv);
-               break;
-
-       case iro_Div:
-               asm_node = gen_node_for_Div(&tenv);
-               break;
-
-       case iro_Mod:
-               asm_node = gen_node_for_Mod(&tenv);
-               break;
-
-       case iro_Load:
-               asm_node = gen_node_for_Load(&tenv);
-               break;
-
-       case iro_Store:
-               asm_node = gen_node_for_Store(&tenv);
-               break;
-
-       case iro_Proj:
-               asm_node = gen_node_for_Proj(&tenv);
-               break;
-
-       case iro_Conv:
-               asm_node = gen_node_for_Conv(&tenv);
-               break;
-
-       case iro_DivMod:
-               asm_node = gen_node_for_DivMod(&tenv);
-               break;
-
-       case iro_Mul:
-               asm_node = gen_node_for_Mul(&tenv);
-               break;
-
-       case iro_Jmp:
-               asm_node = gen_node_for_Jmp(&tenv);
-               break;
-
-       case iro_IJmp:
-               asm_node = gen_node_for_IJmp(&tenv);
-               break;
-
-       case iro_Unknown:
-               asm_node = gen_node_for_Unknown(&tenv);
-               break;
-
-       case iro_Cond:
-               asm_node = gen_node_for_Cond(&tenv);
-               break;
-
-               /* TODO: implement these nodes */
-               BAD(Mux);
-
-               /* You probably don't need to handle the following nodes */
-
-               // call is handled in the emit phase
-               IGN(Call);
-               // Cmp is handled together with Cond
-               IGN(Cmp);
-               IGN(Alloc);
-
-               IGN(Block);
-               IGN(Start);
-               IGN(End);
-               IGN(NoMem);
-               IGN(Phi);
-               IGN(Break);
-               IGN(Sync);
-
-               IGN(Const);
-               IGN(SymConst);
-
-               BAD(Raise);
-               BAD(Sel);
-               BAD(InstOf);
-               BAD(Cast);
-               BAD(Free);
-               BAD(Tuple);
-               BAD(Id);
-               BAD(Bad);
-               BAD(Confirm);
-               BAD(Filter);
-               BAD(CallBegin);
-               BAD(EndReg);
-               BAD(EndExcept);
-
-               default:
-                       if(be_is_StackParam(node)) {
-                               asm_node = gen_node_for_StackParam(&tenv);
-                       } else if(be_is_AddSP(node)) {
-                               asm_node = gen_node_for_AddSP(&tenv);
-                       }
-                       break;
-
-bad:
-               fprintf(stderr, "Not implemented: %s\n", get_irn_opname(node));
-               assert(0);
-       }
-
-       if (asm_node != node) {
-               exchange(node, asm_node);
-               DB((tenv.mod, LEVEL_1, "created node %+F[%p]\n", asm_node, asm_node));
-       } else {
-               DB((tenv.mod, LEVEL_1, "ignored\n"));
-       }
+static ir_node *gen_Bad(ir_node *node)
+{
+       panic("Unexpected node %+F found in mips transform phase.\n", node);
+       return NULL;
 }
 
-void mips_pre_transform_node(ir_node *node, void *env) {
-       mips_code_gen_t *cgenv = (mips_code_gen_t *)env;
-       int i;
-
-       mips_transform_env_t tenv;
-
-       if (is_Block(node))
-               return;
-
-       tenv.block    = get_nodes_block(node);
-       tenv.dbg      = get_irn_dbg_info(node);
-       tenv.irg      = current_ir_graph;
-       tenv.irn      = node;
-       DEBUG_ONLY(tenv.mod      = cgenv->mod;)
-       tenv.mode     = get_irn_mode(node);
-       tenv.cg           = cgenv;
-
-       if(is_Proj(node)) {
-               ir_node* pred = get_Proj_pred(node);
-
-               if(get_irn_opcode(pred) == iro_CopyB) {
-                       mips_fix_CopyB_Proj(&tenv);
-               }
-       }
-
-       for(i = 0; i < get_irn_arity(node); ++i) {
-               ir_node* pred = get_irn_n(node, i);
+static void register_transformers(void)
+{
+       clear_irp_opcodes_generic_func();
+
+       op_Add->ops.generic      = (op_func) gen_Add;
+       op_Sub->ops.generic      = (op_func) gen_Sub;
+       op_And->ops.generic      = (op_func) gen_And;
+       op_Or->ops.generic       = (op_func) gen_Or;
+       op_Eor->ops.generic      = (op_func) gen_Eor;
+       op_Shl->ops.generic      = (op_func) gen_Shl;
+       op_Shr->ops.generic      = (op_func) gen_Shr;
+       op_Shrs->ops.generic     = (op_func) gen_Shrs;
+       op_Not->ops.generic      = (op_func) gen_Not;
+       op_Minus->ops.generic    = (op_func) gen_Minus;
+       op_Div->ops.generic      = (op_func) gen_Div;
+       op_Mod->ops.generic      = (op_func) gen_Mod;
+       op_DivMod->ops.generic   = (op_func) gen_DivMod;
+       op_Abs->ops.generic      = (op_func) gen_Abs;
+       op_Load->ops.generic     = (op_func) gen_Load;
+       op_Store->ops.generic    = (op_func) gen_Store;
+       op_Cond->ops.generic     = (op_func) gen_Cond;
+       op_Conv->ops.generic     = (op_func) gen_Conv;
+       op_Const->ops.generic    = (op_func) gen_Const;
+       op_SymConst->ops.generic = (op_func) gen_SymConst;
+       op_Unknown->ops.generic  = (op_func) gen_Unknown;
+       op_Proj->ops.generic     = (op_func) gen_Proj;
+       op_Phi->ops.generic      = (op_func) gen_Phi;
+
+       op_Raise->ops.generic     = (op_func) gen_Bad;
+       op_Sel->ops.generic       = (op_func) gen_Bad;
+       op_InstOf->ops.generic    = (op_func) gen_Bad;
+       op_Cast->ops.generic      = (op_func) gen_Bad;
+       op_Free->ops.generic      = (op_func) gen_Bad;
+       op_Tuple->ops.generic     = (op_func) gen_Bad;
+       op_Id->ops.generic        = (op_func) gen_Bad;
+       op_Confirm->ops.generic   = (op_func) gen_Bad;
+       op_Filter->ops.generic    = (op_func) gen_Bad;
+       op_CallBegin->ops.generic = (op_func) gen_Bad;
+       op_EndReg->ops.generic    = (op_func) gen_Bad;
+       op_EndExcept->ops.generic = (op_func) gen_Bad;
+}
 
-               if (is_Const(pred)) {
-                       ir_node* constnode = exchange_node_for_Const(&tenv, pred, i);
-                       set_irn_n(node, i, constnode);
-               } else if (get_irn_op(pred) == op_SymConst) {
-                       ir_node* constnode = gen_node_for_SymConst(&tenv, pred, i);
-                       set_irn_n(node, i, constnode);
-               }
-       }
+void mips_transform_graph(mips_code_gen_t *cg)
+{
+       env_cg = cg;
+       register_transformers();
+       be_transform_graph(cg->birg, NULL, cg);
 }
 
 /**
@@ -1202,11 +1198,9 @@ void mips_after_ra_walker(ir_node *node, void *env) {
        tenv.dbg   = get_irn_dbg_info(node);
        tenv.irg   = current_ir_graph;
        tenv.irn   = node;
-       DEBUG_ONLY(tenv.mod   = cg->mod;)
        tenv.mode  = get_irn_mode(node);
        tenv.cg    = cg;
 
-       /* be_is_StackParam(node) || */
        if (be_is_Reload(node)) {
                mips_transform_Reload(&tenv);
        } else if (be_is_Spill(node)) {