- implemented ia32 inport, outport for ir_bk_(in|out)port
[libfirm] / ir / be / mips / mips_transform.c
index 138dd47..2a23ff6 100644 (file)
@@ -1,9 +1,29 @@
-/* The codegenrator (transform FIRM into mips FIRM */
-/* $Id$ */
+/*
+ * 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.
+ */
 
-#ifdef HAVE_CONFIG_H
+/**
+ * @file
+ * @brief   The codegenrator (transform FIRM into mips FIRM
+ * @author  Matthias Braun, Mehdi
+ * @version $Id$
+ */
 #include "config.h"
-#endif
 
 #include <limits.h>
 
 #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 "mips_transform.h"
 #include "mips_new_nodes.h"
 #include "mips_map_regs.h"
  *
  ****************************************************************************************************/
 
-#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, env->mode);\
-       }
+typedef ir_node *construct_binop_func(dbg_info *db, ir_node *block,
+               ir_node *left, ir_node *right);
 
-MIPS_GENBINFUNC(add)
-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, env->mode);              \
-       }
+static inline int mode_needs_gp_reg(ir_mode *mode) {
+       return mode_is_int(mode) || mode_is_reference(mode);
+}
+
+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;
 
-MIPS_GENUNFUNC(not)
+       assert(val >=  -32768 && val <= 32767);
+       res      = new_bd_mips_Immediate(NULL, block, MIPS_IMM_CONST, NULL, val);
+       slots    = get_mips_slots(res);
+       slots[0] = &mips_gp_regs[REG_GP_NOREG];
 
-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);
+       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_bd_mips_zero(NULL, 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, mode);
-               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, mode);
-       attr = get_mips_attr(lui);
-       attr->tv = new_tarval_from_long(val, mode);
-
-       if(lower == 0)
-               return lui;
+       if(val < -32768 || val > 32767)
+               return NULL;
 
-       lli = new_rd_mips_lli(dbg, irg, block, lui, mode);
-       attr = get_mips_attr(lli);
-       attr->tv = new_tarval_from_long(val, mode);
-
-       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_mode* mode = get_irn_mode(pred);
-       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)
+{
+       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, mode);
-               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, mode);
-               attr = get_mips_attr(result);
-               attr->symconst_id = get_SymConst_name(pred);
-               return result;
-       }
+       res = func(dbgi, 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_bd_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_bd_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_bd_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_bd_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_bd_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_bd_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_bd_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_bd_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)
+{
+       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_bd_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_bd_mips_sltu(dbgi, 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)
+{
+       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_bd_mips_subu(dbgi, block, zero, new_op);
+
+       return res;
+}
 
-       n = get_Proj_proj(proj);
+static ir_node *gen_Abs(ir_node *node)
+{
+       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_bd_mips_sra( dbgi, block, new_op, sra_const);
+       add       = new_bd_mips_addu(dbgi, block, new_op, sra);
+       xor       = new_bd_mips_xor( dbgi, 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)
+{
+       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, env->mode);
-       } else if(n == pn_DivMod_res_mod) {
-               return new_rd_mips_mfhi(env->dbg, env->irg, env->block, new_proj, env->mode);
+       if(tarval_is_long(tv)) {
+               val = get_tarval_long(tv);
+       } else {
+               panic("Can't get value of tarval %+F", 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_bd_mips_lui(dbgi, 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_bd_mips_or(dbgi, 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;
+       dbg_info *dbgi  = get_irn_dbg_info(node);
+       ir_node  *block = be_transform_node(get_nodes_block(node));
+       ir_entity *entity;
+       const arch_register_t **slots;
+       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_bd_mips_lui(dbgi, block, MIPS_IMM_SYMCONST_HI, entity, 0);
+       or_const = new_bd_mips_Immediate(dbgi, block, MIPS_IMM_SYMCONST_LO, entity, 0);
+       or       = new_bd_mips_or(dbgi, block, lui, or_const);
 
-       switch(n) {
-       case pn_Cmp_False:
-               if(true_false)
-                       return NULL;
+       slots    = get_mips_slots(or_const);
+       slots[0] = &mips_gp_regs[REG_GP_NOREG];
+
+       return or;
+}
 
-               return make_jmp_or_fallthrough(env);
+typedef ir_node* (*gen_load_func)(dbg_info *dbg, 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)
+{
+       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_bd_mips_lw;
+               break;
+       case 16:
+               func = sign ? new_bd_mips_lh : new_bd_mips_lhu;
+               break;
+       case 8:
+               func = sign ? new_bd_mips_lb : new_bd_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, 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, get_irn_mode(op1));
-               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_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)
+{
+       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_bd_mips_sw;
+               break;
+       case 16:
+               func = new_bd_mips_sh;
+               break;
+       case 8:
+               func = new_bd_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, get_irn_mode(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, 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, get_irn_mode(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, get_irn_mode(op1));
-               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_bd_mips_mflo(dbgi, 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_bd_mips_mfhi(dbgi, 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_bd_mips_mflo(dbgi, block, proj);
+               case pn_DivMod_res_mod:
+                       proj = new_rd_Proj(dbgi, irg, block, new_div, mode_M,
+                                          pn_mips_div_lohi);
+                       return new_bd_mips_mfhi(dbgi, 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", 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);
+}
+
+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);
 
-               return make_jmp_or_fallthrough(env);
+       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_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);
@@ -444,7 +617,7 @@ static ir_node *gen_node_for_Cond(mips_transform_env_t *env)
        if(minval != 0) {
                minval_const = new_rd_Const(dbg, irg, block, selector_mode, new_tarval_from_long(minval, selector_mode));
                minval_const = gen_node_for_Const(env, dbg, irg, block, minval_const);
-               sub = new_rd_mips_sub(dbg, irg, block, selector, minval_const, selector_mode);
+               sub = new_bd_mips_sub(dbg, block, selector, minval_const);
        } else {
                sub = selector;
        }
@@ -457,10 +630,10 @@ static ir_node *gen_node_for_Cond(mips_transform_env_t *env)
 
        max_const = new_rd_Const(dbg, irg, block, unsigned_mode, new_tarval_from_long(maxval - minval + 1, unsigned_mode));
        max_const = gen_node_for_Const(env, dbg, irg, block, max_const);
-       sltu = new_rd_mips_slt(dbg, irg, block, sub, max_const, unsigned_mode);
+       sltu = new_bd_mips_slt(dbg, block, sub, max_const);
 
        zero = gen_zero_node(env, dbg, irg, block);
-       beq = new_rd_mips_beq(dbg, irg, block, sltu, zero, mode_T);
+       beq = new_bd_mips_beq(dbg, block, sltu, zero, mode_T);
 
        // attach defaultproj to beq now
        set_irn_n(defaultproj, 0, beq);
@@ -468,18 +641,18 @@ static ir_node *gen_node_for_Cond(mips_transform_env_t *env)
 
        two_const = new_rd_Const(dbg, irg, block, unsigned_mode, new_tarval_from_long(2, unsigned_mode));
        two_const = gen_node_for_Const(env, dbg, irg, block, two_const);
-       sl = new_rd_mips_sl(dbg, irg, block, sub, two_const, unsigned_mode);
+       sl = new_bd_mips_sl(dbg, block, sub, two_const);
 
-       la = new_rd_mips_la(dbg, irg, block, mode_Iu);
-       add = new_rd_mips_add(dbg, irg, block, sl, la, mode_Iu);
-       load = new_rd_mips_load_r(dbg, irg, block, new_rd_NoMem(irg), add, mode_T);
+       la   = new_bd_mips_la(    dbg, block);
+       add  = new_bd_mips_addu(  dbg, block, sl, la);
+       load = new_bd_mips_load_r(dbg, block, new_NoMem(), add, mode_T);
        attr = get_mips_attr(load);
        attr->modes.load_store_mode = mode_Iu;
        attr->tv = new_tarval_from_long(0, mode_Iu);
 
        proj = new_rd_Proj(dbg, irg, block, load, mode_Iu, pn_Load_res);
 
-       switchjmp = new_rd_mips_SwitchJump(dbg, irg, block, proj, mode_T);
+       switchjmp = new_bd_mips_SwitchJump(dbg, block, proj, mode_T);
        attr = get_mips_attr(switchjmp);
        attr->switch_default_pn = defaultprojn;
 
@@ -492,154 +665,160 @@ 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;
-       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)
+{
+       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_bd_mips_beq(dbgi, block, new_left, new_right);
+               break;
 
-       return value_proj;
-}
+       case pn_Cmp_Lt:
+               zero = mips_create_zero();
+               slt  = new_bd_mips_slt(dbgi, block, new_left, new_right);
+               res  = new_bd_mips_bne(dbgi, 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_bd_mips_slt(dbgi, block, new_right, new_left);
+               res  = new_bd_mips_beq(dbgi, block, slt, zero);
+               break;
 
-       pred = get_Conv_op(node);
-       result = new_rd_mips_andi(env->dbg, env->irg, env->block, pred, node->mode);
-       attr = get_mips_attr(result);
-       attr->tv = new_tarval_from_long(immediate, mode_Iu);
+       case pn_Cmp_Gt:
+               zero = mips_create_zero();
+               slt  = new_bd_mips_slt(dbgi, block, new_right, new_left);
+               res  = new_bd_mips_bne(dbgi, block, slt, zero);
+               break;
 
-       return result;
-}
+       case pn_Cmp_Ge:
+               zero = mips_create_zero();
+               slt  = new_bd_mips_slt(dbgi, block, new_right, new_left);
+               res  = new_bd_mips_bne(dbgi, 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_bd_mips_bne(dbgi, 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, node->mode);
+static ir_node *gen_Conv(ir_node *node)
+{
+       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_bd_mips_seb(dbgi, block, new_op);
+               } else if(src_size == 16) {
+                       res = new_bd_mips_seh(dbgi, block, new_op);
+               } else {
+                       panic("invalid conv %+F", 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", node);
                }
+               res = new_bd_mips_and(dbgi, 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;
-
-       div = new_rd_mips_div(env->dbg, env->irg, env->block, op1, op2, mode_T);
-
-       // 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");
-               }
+       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)) {
+               res = new_bd_mips_div(dbgi, block, new_left, new_right);
+       } else {
+               res = new_bd_mips_divu(dbgi, block, new_left, new_right);
        }
 
-       return div;
-}
+       set_irn_pinned(res, get_irn_pinned(node));
 
-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);
+       return res;
 }
 
-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_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_Mod(mips_transform_env_t *env) {
-       ir_node *node = env->irn;
+static ir_node *gen_Div(ir_node *node)
+{
+       return create_div(node, get_Div_left(node), get_Div_right(node),
+                         get_Div_resmode(node));
+}
 
-       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;
        ir_node *mflo;
        ir_node *op1, *op2;
+       ir_mode *mode = get_irn_mode(node);
 
        op1 = get_Mul_left(node);
        op2 = get_Mul_right(node);
@@ -648,55 +827,48 @@ static ir_node *gen_node_for_Mul(mips_transform_env_t *env) {
        assert(get_mode_size_bits(get_irn_mode(op1)) == get_mode_size_bits(env->mode));
        assert(get_mode_size_bits(get_irn_mode(op2)) == get_mode_size_bits(env->mode));
 
-       mul = new_rd_mips_mult(env->dbg, env->irg, env->block, get_Mul_left(node), get_Mul_right(node), env->mode);
-       mflo = new_rd_mips_mflo(env->dbg, env->irg, env->block, mul, env->mode);
+       if(mode_is_signed(mode)) {
+               mul = new_bd_mips_mult(env->dbg, env->block, get_Mul_left(node), get_Mul_right(node));
+       } else {
+               mul = new_bd_mips_multu(env->dbg, env->block, get_Mul_left(node), get_Mul_right(node));
+       }
+       mflo = new_bd_mips_mflo(env->dbg, env->block, mul);
 
        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_Jmp(mips_transform_env_t *env) {
-       return make_jmp_or_fallthrough(env);
-}
-
-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), node->mode);
-       attr = get_mips_attr(sra);
-       attr->tv = new_tarval_from_long(31, mode_Iu);
-       add = new_rd_mips_add(env->dbg, env->irg, env->block, get_Abs_op(node), sra, node->mode);
-       xor = new_rd_mips_xor(env->dbg, env->irg, env->block, sra, add, node->mode);
+static
+ir_node *gen_node_for_IJmp(mips_transform_env_t *env) {
+       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);
 
-       return xor;
+       return new_bd_mips_jr(dbg, block, target);
 }
 
-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;
 
-       subu = new_rd_mips_subuzero(env->dbg, env->irg, env->block, get_Rot_right(node), env->mode);
-       srlv = new_rd_mips_srlv(env->dbg, env->irg, env->block, get_Rot_left(node), subu, env->mode);
-       sllv = new_rd_mips_sllv(env->dbg, env->irg, env->block, get_Rot_left(node), get_Rot_right(node), env->mode);
-       or = new_rd_mips_or(env->dbg, env->irg, env->block, sllv, srlv, env->mode);
+       subu = new_bd_mips_subuzero(env->dbg, env->block, get_Rot_right(node));
+       srlv = new_bd_mips_srlv(env->dbg, env->block, get_Rot_left(node), subu);
+       sllv = new_bd_mips_sllv(env->dbg, env->block, get_Rot_left(node), get_Rot_right(node));
+       or   = new_bd_mips_or(env->dbg, env->block, sllv, srlv);
 
        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 :-)
  */
@@ -771,7 +943,7 @@ ir_node *gen_code_for_CopyB(ir_node *block, ir_node *node) {
                for (i = 0; i < 4; ++i) {
                        ir_node *load;
 
-                       load = new_rd_mips_load_r(dbg, irg, new_bl, mem_phi, src, mode_T);
+                       load = new_bd_mips_load_r(dbg, new_bl, mem_phi, src, mode_T);
                        attr = get_mips_attr(load);
                        attr->modes.load_store_mode = mode_Iu;
                        attr->tv = new_tarval_from_long(i * 4, mode_Iu);
@@ -783,7 +955,7 @@ ir_node *gen_code_for_CopyB(ir_node *block, ir_node *node) {
                for (i = 0; i < 4; ++i) {
                        ir_node *store;
 
-                       store = new_rd_mips_store_r(dbg, irg, new_bl, mem_phi, dst, ld[i], mode_T);
+                       store = new_bd_mips_store_r(dbg, new_bl, mem_phi, dst, ld[i], mode_T);
                        attr = get_mips_attr(store);
                        attr->modes.load_store_mode = mode_Iu;
                        attr->tv = new_tarval_from_long(i * 4, mode_Iu);
@@ -812,14 +984,14 @@ ir_node *gen_code_for_CopyB(ir_node *block, ir_node *node) {
                        i -= 1;
                }
 
-               load = new_rd_mips_load_r(dbg, irg, block, mem, src, mode_T);
+               load = new_bd_mips_load_r(dbg, block, mem, src, mode_T);
                attr = get_mips_attr(load);
                attr->modes.load_store_mode = mode;
                attr->tv = new_tarval_from_long(offset, mode_Iu);
 
                projv = new_rd_Proj(dbg, irg, block, load, mode, pn_Load_res);
 
-               store = new_rd_mips_store_r(dbg, irg, block, mem, dst, projv, mode_T);
+               store = new_bd_mips_store_r(dbg, block, mem, dst, projv, mode_T);
                attr = get_mips_attr(store);
                attr->modes.load_store_mode = mode;
                attr->tv = new_tarval_from_long(offset, mode_Iu);
@@ -842,101 +1014,70 @@ static void mips_fix_CopyB_Proj(mips_transform_env_t* env) {
        long n = get_Proj_proj(node);
 
        if(n == pn_CopyB_M_except) {
-               assert(0);
+               panic("Unsupported Proj from CopyB");
        } else if(n == pn_CopyB_M_regular) {
                set_Proj_proj(node, pn_Store_M);
        } else if(n == pn_CopyB_M_except) {
                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 *nomem = new_rd_NoMem(env->irg);
-       ir_node *ptr   = get_irn_n(node, 0);
-       ir_node *val   = get_irn_n(node, 1);
-       entity  *ent   = be_get_frame_entity(node);
-       mips_attr_t *attr;
+       ir_node   *node = env->irn;
+       ir_node   *sched_point = NULL;
+       ir_node   *store;
+       ir_node   *nomem = new_NoMem();
+       ir_node   *ptr   = get_irn_n(node, 0);
+       ir_node   *val   = get_irn_n(node, 1);
+       ir_entity *ent   = be_get_frame_entity(node);
 
        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_bd_mips_sw(env->dbg, 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) {
-       ir_node *node = env->irn;
-       ir_node *sched_point = NULL;
-       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);
-       entity  *ent   = be_get_frame_entity(node);
+       ir_node   *node = env->irn;
+       ir_node   *sched_point = NULL;
+       ir_node   *load, *proj;
+       ir_node   *ptr   = get_irn_n(node, 0);
+       ir_node   *mem   = get_irn_n(node, 1);
+       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_bd_mips_lw(env->dbg, 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);
        }
 
        /* copy the register from the old node to the new Load */
-       reg = arch_get_irn_register(env->cg->arch_env, node);
-       arch_set_irn_register(env->cg->arch_env, proj, reg);
+       reg = arch_get_irn_register(node);
+       arch_set_irn_register(proj, reg);
 
        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;
@@ -946,14 +1087,15 @@ static ir_node *gen_node_for_AddSP(mips_transform_env_t *env)
        op1 = get_irn_n(node, 0);
        op2 = get_irn_n(node, 1);
 
-       add = new_rd_mips_add(env->dbg, env->irg, env->block, op1, op2, mode_Iu);
+       add = new_bd_mips_addu(env->dbg, env->block, op1, op2);
 
        /* copy the register requirements from the old node to the new node */
-       reg = arch_get_irn_register(env->cg->arch_env, node);
-       arch_set_irn_register(env->cg->arch_env, add, reg);
+       reg = arch_get_irn_register(node);
+       arch_set_irn_register(add, reg);
 
        return add;
 }
+#endif
 
 /*********************************************************
  *                  _             _      _
@@ -965,198 +1107,47 @@ static ir_node *gen_node_for_AddSP(mips_transform_env_t *env)
  *
  *********************************************************/
 
+typedef ir_node *(*mips_transform_func) (ir_node *node);
 
-/**
- * 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;
-       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, add);
-               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 void register_transformer(ir_op *op, mips_transform_func func)
+{
+       assert(op->ops.generic == NULL);
+       op->ops.generic = (op_func) func;
 }
 
-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();
+
+       register_transformer(op_Add, gen_Add);
+       register_transformer(op_Sub, gen_Sub);
+       register_transformer(op_And, gen_And);
+       register_transformer(op_Or,  gen_Or);
+       register_transformer(op_Eor, gen_Eor);
+       register_transformer(op_Shl, gen_Shl);
+       register_transformer(op_Shr, gen_Shr);
+       register_transformer(op_Shrs, gen_Shrs);
+       register_transformer(op_Not, gen_Not);
+       register_transformer(op_Minus, gen_Minus);
+       register_transformer(op_Div, gen_Div);
+       register_transformer(op_Mod, gen_Mod);
+       register_transformer(op_DivMod, gen_DivMod);
+       register_transformer(op_Abs, gen_Abs);
+       register_transformer(op_Load, gen_Load);
+       register_transformer(op_Store, gen_Store);
+       register_transformer(op_Cond, gen_Cond);
+       register_transformer(op_Conv, gen_Conv);
+       register_transformer(op_Const, gen_Const);
+       register_transformer(op_SymConst, gen_SymConst);
+       register_transformer(op_Unknown, gen_Unknown);
+       register_transformer(op_Proj, gen_Proj);
+       register_transformer(op_Phi, gen_Phi);
+}
 
-               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)
+{
+       register_transformers();
+       be_transform_graph(cg->birg, NULL);
 }
 
 /**
@@ -1173,11 +1164,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)) {