added mips backend from the backend praktikum
authorMichael Beck <beck@ipd.info.uni-karlsruhe.de>
Mon, 27 Mar 2006 16:08:13 +0000 (16:08 +0000)
committerMichael Beck <beck@ipd.info.uni-karlsruhe.de>
Mon, 27 Mar 2006 16:08:13 +0000 (16:08 +0000)
18 files changed:
ir/be/mips/bearch_mips.c [new file with mode: 0644]
ir/be/mips/bearch_mips.h [new file with mode: 0644]
ir/be/mips/bearch_mips_t.h [new file with mode: 0644]
ir/be/mips/mips_emitter.c [new file with mode: 0644]
ir/be/mips/mips_emitter.h [new file with mode: 0644]
ir/be/mips/mips_gen_decls.c [new file with mode: 0644]
ir/be/mips/mips_gen_decls.h [new file with mode: 0644]
ir/be/mips/mips_map_regs.c [new file with mode: 0644]
ir/be/mips/mips_map_regs.h [new file with mode: 0644]
ir/be/mips/mips_new_nodes.c [new file with mode: 0644]
ir/be/mips/mips_new_nodes.h [new file with mode: 0644]
ir/be/mips/mips_nodes_attr.h [new file with mode: 0644]
ir/be/mips/mips_scheduler.c [new file with mode: 0644]
ir/be/mips/mips_scheduler.h [new file with mode: 0644]
ir/be/mips/mips_spec.pl [new file with mode: 0644]
ir/be/mips/mips_transform.c [new file with mode: 0644]
ir/be/mips/mips_transform.h [new file with mode: 0644]
ir/be/mips/mips_util.h [new file with mode: 0644]

diff --git a/ir/be/mips/bearch_mips.c b/ir/be/mips/bearch_mips.c
new file mode 100644 (file)
index 0000000..8c3e007
--- /dev/null
@@ -0,0 +1,928 @@
+/* The main mips backend driver file. */
+/* $Id$ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "pseudo_irg.h"
+#include "irgwalk.h"
+#include "irprog.h"
+#include "irprintf.h"
+#include "ircons.h"
+#include "irgmod.h"
+#include "irgopt.h"
+#include "irgwalk.h"
+#include "iredges.h "
+#include "irdump.h"
+#include "irextbb.h"
+
+#include "bitset.h"
+#include "debug.h"
+
+#include "../bearch.h"                /* the general register allocator interface */
+#include "../benode_t.h"
+#include "../belower.h"
+#include "../besched_t.h"
+#include "../be.h"
+#include "../beabi.h"
+
+#include "bearch_mips_t.h"
+
+#include "mips_new_nodes.h"           /* mips nodes interface */
+#include "gen_mips_regalloc_if.h"     /* the generated interface (register type and class defenitions) */
+#include "mips_gen_decls.h"           /* interface declaration emitter */
+#include "mips_transform.h"
+#include "mips_emitter.h"
+#include "mips_map_regs.h"
+#include "mips_util.h"
+#include "mips_scheduler.h"
+
+#define DEBUG_MODULE "firm.be.mips.isa"
+
+/* TODO: ugly, but we need it to get access to the registers assigned to Phi nodes */
+static set *cur_reg_set = NULL;
+
+/**************************************************
+ *                         _ _              _  __
+ *                        | | |            (_)/ _|
+ *  _ __ ___  __ _    __ _| | | ___   ___   _| |_
+ * | '__/ _ \/ _` |  / _` | | |/ _ \ / __| | |  _|
+ * | | |  __/ (_| | | (_| | | | (_) | (__  | | |
+ * |_|  \___|\__, |  \__,_|_|_|\___/ \___| |_|_|
+ *            __/ |
+ *           |___/
+ **************************************************/
+
+static ir_node *my_skip_proj(const ir_node *n) {
+       while (is_Proj(n))
+               n = get_Proj_pred(n);
+       return (ir_node *)n;
+}
+
+/**
+ * Return register requirements for a mips node.
+ * If the node returns a tuple (mode_T) then the proj's
+ * will be asked for this information.
+ */
+static const arch_register_req_t *mips_get_irn_reg_req(const void *self, arch_register_req_t *req, const ir_node *irn, int pos) {
+       const mips_register_req_t *irn_req;
+       long               node_pos = pos == -1 ? 0 : pos;
+       ir_mode           *mode     = get_irn_mode(irn);
+       firm_dbg_module_t *mod      = firm_dbg_register(DEBUG_MODULE);
+
+       if (is_Block(irn) || mode == mode_X || mode == mode_M) {
+               DBG((mod, LEVEL_1, "ignoring mode_T, mode_M node %+F\n", irn));
+               return NULL;
+       }
+
+       if (mode == mode_T && pos < 0) {
+               DBG((mod, LEVEL_1, "ignoring request for OUT requirements at %+F\n", irn));
+               return NULL;
+       }
+
+       DBG((mod, LEVEL_1, "get requirements at pos %d for %+F ... ", pos, irn));
+
+       if (is_Proj(irn)) {
+               /* in case of a proj, we need to get the correct OUT slot */
+               /* of the node corresponding to the proj number */
+               if (pos == -1) {
+                       node_pos = mips_translate_proj_pos(irn);
+               }
+               else {
+                       node_pos = pos;
+               }
+
+               irn = my_skip_proj(irn);
+
+               DB((mod, LEVEL_1, "skipping Proj, going to %+F at pos %d ... ", irn, node_pos));
+       }
+
+       /* get requirements for our own nodes */
+       if (is_mips_irn(irn)) {
+               if (pos >= 0) {
+                       irn_req = get_mips_in_req(irn, pos);
+               }
+               else {
+                       irn_req = get_mips_out_req(irn, node_pos);
+               }
+
+               DB((mod, LEVEL_1, "returning reqs for %+F at pos %d\n", irn, pos));
+
+               memcpy(req, &(irn_req->req), sizeof(*req));
+
+               if (arch_register_req_is(&(irn_req->req), should_be_same)) {
+                       assert(irn_req->same_pos >= 0 && "should be same constraint for in -> out NYI");
+                       req->other_same = get_irn_n(irn, irn_req->same_pos);
+               }
+
+               if (arch_register_req_is(&(irn_req->req), should_be_different)) {
+                       assert(irn_req->different_pos >= 0 && "should be different constraint for in -> out NYI");
+                       req->other_different = get_irn_n(irn, irn_req->different_pos);
+               }
+       }
+       /* get requirements for FIRM nodes */
+       else {
+               /* treat Phi like Const with default requirements */
+               if (is_Phi(irn)) {
+                       DB((mod, LEVEL_1, "returning standard reqs for %+F\n", irn));
+
+                       if (mode_is_float(mode)) {
+                               //memcpy(req, &(mips_default_req_mips_floating_point.req), sizeof(*req));
+                               assert(0 && "floating point not supported (yet)");
+                       }
+                       else if (mode_is_int(mode) || mode_is_reference(mode)) {
+                               memcpy(req, &(mips_default_req_mips_general_purpose.req), sizeof(*req));
+                       }
+                       else if (mode == mode_T || mode == mode_M) {
+                               DBG((mod, LEVEL_1, "ignoring Phi node %+F\n", irn));
+                               return NULL;
+                       }
+                       else {
+                               assert(0 && "unsupported Phi-Mode");
+                       }
+               }
+               else {
+                       DB((mod, LEVEL_1, "returning NULL for %+F (node not supported)\n", irn));
+                       req = NULL;
+               }
+       }
+
+       return req;
+}
+
+static void mips_set_irn_reg(const void *self, ir_node *irn, const arch_register_t *reg) {
+       int pos = 0;
+
+       if (is_Proj(irn)) {
+
+               if (get_irn_mode(irn) == mode_X) {
+                       return;
+               }
+
+               pos = mips_translate_proj_pos(irn);
+               irn = my_skip_proj(irn);
+       }
+
+       if (is_mips_irn(irn)) {
+               const arch_register_t **slots;
+
+               slots      = get_mips_slots(irn);
+               slots[pos] = reg;
+       }
+       else {
+               /* here we set the registers for the Phi nodes */
+               mips_set_firm_reg(irn, reg, cur_reg_set);
+       }
+}
+
+static const arch_register_t *mips_get_irn_reg(const void *self, const ir_node *irn) {
+       int pos = 0;
+       const arch_register_t *reg = NULL;
+
+       if (is_Proj(irn)) {
+
+               if (get_irn_mode(irn) == mode_X) {
+                       return NULL;
+               }
+
+               pos = mips_translate_proj_pos(irn);
+               irn = my_skip_proj(irn);
+       }
+
+       if (is_mips_irn(irn)) {
+               const arch_register_t **slots;
+               slots = get_mips_slots(irn);
+               reg   = slots[pos];
+       }
+       else {
+               reg = mips_get_firm_reg(irn, cur_reg_set);
+       }
+
+       return reg;
+}
+
+static arch_irn_class_t mips_classify(const void *self, const ir_node *irn) {
+       irn = my_skip_proj(irn);
+
+       if (is_cfop(irn)) {
+               return arch_irn_class_branch;
+       } else if (is_mips_irn(irn)) {
+               return arch_irn_class_normal;
+       }
+
+       return 0;
+}
+
+static arch_irn_flags_t mips_get_flags(const void *self, const ir_node *irn) {
+       irn = my_skip_proj(irn);
+
+       if (is_mips_irn(irn)) {
+               return get_mips_flags(irn);
+       }
+       else if (is_Unknown(irn)) {
+               return arch_irn_flags_ignore;
+       }
+
+       return 0;
+}
+
+static entity *mips_get_frame_entity(const void *self, const ir_node *irn) {
+       if(is_mips_load_r(irn) || is_mips_store_r(irn)) {
+               mips_attr_t *attr = get_mips_attr(irn);
+
+               return attr->stack_entity;
+       }
+
+       return NULL;
+}
+
+/**
+ * This function is called by the generic backend to correct offsets for
+ * nodes accessing the stack.
+ */
+static void mips_set_frame_offset(const void *self, ir_node *irn, int offset) {
+       mips_attr_t *attr = get_mips_attr(irn);
+       assert(is_mips_load_r(irn) || is_mips_store_r(irn));
+
+       attr->stack_entity_offset = offset;
+}
+
+/* fill register allocator interface */
+
+static const arch_irn_ops_if_t mips_irn_ops_if = {
+       mips_get_irn_reg_req,
+       mips_set_irn_reg,
+       mips_get_irn_reg,
+       mips_classify,
+       mips_get_flags,
+       mips_get_frame_entity,
+       mips_set_frame_offset
+};
+
+mips_irn_ops_t mips_irn_ops = {
+       &mips_irn_ops_if,
+       NULL
+};
+
+
+
+/**************************************************
+ *                _                         _  __
+ *               | |                       (_)/ _|
+ *   ___ ___   __| | ___  __ _  ___ _ __    _| |_
+ *  / __/ _ \ / _` |/ _ \/ _` |/ _ \ '_ \  | |  _|
+ * | (_| (_) | (_| |  __/ (_| |  __/ | | | | | |
+ *  \___\___/ \__,_|\___|\__, |\___|_| |_| |_|_|
+ *                        __/ |
+ *                       |___/
+ **************************************************/
+
+
+typedef struct {
+       ir_node *start;
+       ir_node *end;
+       unsigned cnt;
+} anchor;
+
+/**
+ * Ext-Block walker: create a block schedule
+ */
+static void create_block_list(ir_extblk *blk, void *env) {
+       anchor *list = env;
+       int i, n;
+
+       for (i = 0, n = get_extbb_n_blocks(blk); i < n; ++i) {
+               ir_node *block = get_extbb_block(blk, i);
+
+               set_irn_link(block, NULL);
+               if (list->start)
+                       set_irn_link(list->end, block);
+               else
+                       list->start = block;
+
+               list->end = block;
+               list->cnt += 1;
+       }
+}
+
+/* return the scheduled block at position pos */
+ir_node *mips_get_sched_block(const mips_code_gen_t *cg, int pos) {
+       if (0 <= pos && pos < ARR_LEN(cg->bl_list))
+               return cg->bl_list[pos];
+       return NULL;
+}
+
+/* return the number of scheduled blocks */
+int mips_get_sched_n_blocks(const mips_code_gen_t *cg) {
+       return ARR_LEN(cg->bl_list);
+}
+
+/* set a block schedule number */
+void mips_set_block_sched_nr(ir_node *block, int nr) {
+       set_irn_link(block, INT_TO_PTR(nr));
+}
+
+/* get a block schedule number */
+int mips_get_block_sched_nr(ir_node *block) {
+       return PTR_TO_INT(get_irn_link(block));
+}
+
+/**
+ * Creates a block schedule for the given graph.
+ */
+static void mips_create_block_sched(mips_code_gen_t *cg) {
+       anchor list;
+       ir_node **bl_list, *block;
+       unsigned i;
+
+       if (cg->bl_list) {
+               DEL_ARR_F(cg->bl_list);
+               free_survive_dce(cg->bl_list_sdce);
+       }
+
+       /* calculate the block schedule here */
+       compute_extbb(cg->irg);
+
+       list.start = NULL;
+       list.end   = NULL;
+       list.cnt   = 0;
+       irg_extblock_walk_graph(cg->irg, NULL, create_block_list, &list);
+
+
+       bl_list = NEW_ARR_F(ir_node *, list.cnt);
+       cg->bl_list_sdce = new_survive_dce();
+       for (i = 0, block = list.start; block; block = get_irn_link(block)) {
+               bl_list[i] = block;
+               survive_dce_register_irn(cg->bl_list_sdce, &bl_list[i]);
+               i++;
+       }
+
+       cg->bl_list = bl_list;
+}
+
+typedef struct _wenv_t {
+       ir_node *list;
+} wenv_t;
+
+/**
+ * Walker: link all CopyB nodes
+ */
+static void collect_copyb_nodes(ir_node *node, void *env) {
+       wenv_t *wenv = env;
+
+       if (get_irn_op(node) == op_CopyB) {
+               set_irn_link(node, wenv->list);
+               wenv->list = node;
+       }
+}
+
+static void replace_copyb_nodes(mips_code_gen_t *cg) {
+       wenv_t env;
+       ir_node *copy, *next;
+       ir_node *old_bl, *new_bl, *jmp, *new_jmp, *mem;
+       const ir_edge_t *edge;
+
+       /* build code for all copyB */
+       env.list = NULL;
+       irg_walk_graph(cg->irg, NULL, collect_copyb_nodes, &env);
+
+       for (copy = env.list; copy; copy = next) {
+               next = get_irn_link(copy);
+
+               old_bl = get_nodes_block(copy);
+               part_block(copy);
+               jmp     = get_Block_cfgpred(old_bl, 0);
+               new_jmp = new_r_Jmp(cg->irg, get_nodes_block(copy));
+
+               new_bl = new_r_Block(cg->irg, 1, &new_jmp);
+               set_nodes_block(jmp, new_bl);
+
+               mem = gen_code_for_CopyB(new_bl, copy);
+
+               /* fix copyB's out edges */
+               foreach_out_edge(copy, edge) {
+                       ir_node *succ = get_edge_src_irn(edge);
+
+                       assert(is_Proj(succ));
+                       switch (get_Proj_proj(succ)) {
+                       case pn_CopyB_M_regular:
+                       case pn_CopyB_M_except:
+                               exchange(succ, mem);
+                               break;
+                       default:
+                               exchange(succ, get_irg_bad(cg->irg));
+                       }
+               }
+       }
+}
+
+/**
+ * Transforms the standard firm graph into
+ * a mips firm graph
+ */
+static void mips_prepare_graph(void *self) {
+       mips_code_gen_t *cg = self;
+       int bl_nr, n;
+
+       // replace all copyb nodes in the block with a loop
+       // and mips store/load nodes
+       replace_copyb_nodes(cg);
+
+       // Calculate block schedule
+       mips_create_block_sched(cg);
+
+       /* enter the block number into every blocks link field */
+       for (bl_nr = 0, n = mips_get_sched_n_blocks(cg); bl_nr < n; ++bl_nr) {
+               ir_node *bl = mips_get_sched_block(cg, bl_nr);
+               mips_set_block_sched_nr(bl, bl_nr);
+       }
+
+       // walk the graph and transform firm nodes into mips nodes where possible
+       irg_walk_blkwise_graph(cg->irg, mips_pre_transform_node, mips_transform_node, cg);
+
+       dump_ir_block_graph_sched(cg->irg, "-transformed");
+}
+
+/**
+ * Called immediately before emit phase.
+ */
+static void mips_finish_irg(ir_graph *irg, mips_code_gen_t *cg) {
+       /* TODO: - fix offsets for nodes accessing stack
+                        - ...
+       */
+}
+
+
+/**
+ * These are some hooks which must be filled but are probably not needed.
+ */
+static void mips_before_sched(void *self) {
+       /* Some stuff you need to do after scheduling but before register allocation */
+}
+
+static void mips_before_ra(void *self) {
+       /* Some stuff you need to do immediately after register allocation */
+}
+
+static void mips_after_ra(void* self) {
+       mips_code_gen_t *cg = self;
+       irg_walk_blkwise_graph(cg->irg, NULL, mips_after_ra_walker, self);
+}
+
+/**
+ * Emits the code, closes the output file and frees
+ * the code generator interface.
+ */
+static void mips_emit_and_done(void *self) {
+       mips_code_gen_t *cg = self;
+       ir_graph           *irg = cg->irg;
+       FILE               *out = cg->out;
+
+       mips_register_emitters();
+
+       if (cg->emit_decls) {
+               mips_gen_decls(cg->out);
+               cg->emit_decls = 0;
+       }
+
+       mips_finish_irg(irg, cg);
+       dump_ir_block_graph_sched(irg, "-mips-finished");
+       mips_gen_routine(out, irg, cg);
+
+       cur_reg_set = NULL;
+
+       /* de-allocate code generator */
+       del_set(cg->reg_set);
+       if (cg->bl_list) {
+               DEL_ARR_F(cg->bl_list);
+               free_survive_dce(cg->bl_list_sdce);
+       }
+       free(cg);
+}
+
+static void *mips_cg_init(FILE *F, const be_irg_t *birg);
+
+static const arch_code_generator_if_t mips_code_gen_if = {
+       mips_cg_init,
+       NULL,                            /* before abi introduce */
+       mips_prepare_graph,
+       mips_before_sched,   /* before scheduling hook */
+       mips_before_ra,      /* before register allocation hook */
+       mips_after_ra,
+       mips_emit_and_done
+};
+
+/**
+ * Initializes the code generator.
+ */
+static void *mips_cg_init(FILE *F, const be_irg_t *birg) {
+       mips_isa_t      *isa = (mips_isa_t *)birg->main_env->arch_env->isa;
+       mips_code_gen_t *cg  = xmalloc(sizeof(*cg));
+
+       cg->impl     = &mips_code_gen_if;
+       cg->irg      = birg->irg;
+       cg->reg_set  = new_set(mips_cmp_irn_reg_assoc, 1024);
+       cg->mod      = firm_dbg_register("firm.be.mips.cg");
+       cg->out      = F;
+       cg->arch_env = birg->main_env->arch_env;
+       cg->birg     = birg;
+       cg->bl_list  = NULL;
+
+       isa->num_codegens++;
+
+       if (isa->num_codegens > 1)
+               cg->emit_decls = 0;
+       else
+               cg->emit_decls = 1;
+
+       cur_reg_set = cg->reg_set;
+
+       mips_irn_ops.cg = cg;
+
+       return (arch_code_generator_t *)cg;
+}
+
+
+/*****************************************************************
+ *  ____             _                  _   _____  _____
+ * |  _ \           | |                | | |_   _|/ ____|  /\
+ * | |_) | __ _  ___| | _____ _ __   __| |   | | | (___   /  \
+ * |  _ < / _` |/ __| |/ / _ \ '_ \ / _` |   | |  \___ \ / /\ \
+ * | |_) | (_| | (__|   <  __/ | | | (_| |  _| |_ ____) / ____ \
+ * |____/ \__,_|\___|_|\_\___|_| |_|\__,_| |_____|_____/_/    \_\
+ *
+ *****************************************************************/
+
+static mips_isa_t mips_isa_template = {
+       &mips_isa_if,
+       &mips_general_purpose_regs[REG_SP],
+       &mips_general_purpose_regs[REG_FP],
+       -1,             // stack direction
+       0               // num codegens?!? TODO what is this?
+};
+
+/**
+ * Initializes the backend ISA and opens the output file.
+ */
+static void *mips_init(void) {
+       static int inited = 0;
+       mips_isa_t *isa;
+
+       if(inited)
+               return NULL;
+
+       isa = xcalloc(1, sizeof(*isa));
+       memcpy(isa, &mips_isa_template, sizeof(*isa));
+
+       mips_register_init(isa);
+       mips_create_opcodes();
+       mips_init_opcode_transforms();
+
+       inited = 1;
+
+       return isa;
+}
+
+/**
+ * Closes the output file and frees the ISA structure.
+ */
+static void mips_done(void *self) {
+       free(self);
+}
+
+static int mips_get_n_reg_class(const void *self) {
+       return N_CLASSES;
+}
+
+static const arch_register_class_t *mips_get_reg_class(const void *self, int i) {
+       assert(i >= 0 && i < N_CLASSES && "Invalid mips register class requested.");
+       return &mips_reg_classes[i];
+}
+
+
+
+/**
+ * Get the register class which shall be used to store a value of a given mode.
+ * @param self The this pointer.
+ * @param mode The mode in question.
+ * @return A register class which can hold values of the given mode.
+ */
+const arch_register_class_t *mips_get_reg_class_for_mode(const void *self, const ir_mode *mode) {
+       ASSERT_NO_FLOAT(mode);
+       return &mips_reg_classes[CLASS_mips_general_purpose];
+}
+
+typedef struct {
+       be_abi_call_flags_bits_t flags;
+       const mips_isa_t *isa;
+       const arch_env_t *arch_env;
+       ir_graph *irg;
+       // do special handling to support debuggers
+       int debug;
+} mips_abi_env_t;
+
+static void *mips_abi_init(const be_abi_call_t *call, const arch_env_t *arch_env, ir_graph *irg)
+{
+       mips_abi_env_t *env    = xmalloc(sizeof(env[0]));
+       be_abi_call_flags_t fl = be_abi_call_get_flags(call);
+       env->flags = fl.bits;
+       env->irg   = irg;
+       env->arch_env = arch_env;
+       env->isa   = (const mips_isa_t*) arch_env->isa;
+       env->debug = 1;
+       return env;
+}
+
+static void mips_abi_dont_save_regs(void *self, pset *s)
+{
+       mips_abi_env_t *env = self;
+       if(env->flags.try_omit_fp)
+               pset_insert_ptr(s, env->isa->fp);
+}
+
+static const arch_register_t *mips_abi_prologue(void *self, ir_node** mem, pmap *reg_map)
+{
+       mips_abi_env_t *env = self;
+       ir_graph *irg = env->irg;
+       dbg_info *dbg = NULL; // TODO where can I get this from?
+       ir_node *block = get_irg_start_block(env->irg);
+       mips_attr_t *attr;
+       ir_node *sp = be_abi_reg_map_get(reg_map, &mips_general_purpose_regs[REG_SP]);
+       ir_node *fp = be_abi_reg_map_get(reg_map, &mips_general_purpose_regs[REG_FP]);
+       int initialstackframesize;
+
+       if(env->debug) {
+               /*
+                * The calling conventions wants a stack frame of at least 24bytes size with
+                *   a0-a3 saved in offset 0-12
+                *   fp saved in offset 16
+                *   ra saved in offset 20
+                */
+               ir_node *mm[6];
+               ir_node *sync, *reg, *store;
+               initialstackframesize = 24;
+
+               // - setup first part of stackframe
+               sp = new_rd_mips_addi(dbg, irg, block, sp, mode_Is);
+               attr = get_mips_attr(sp);
+               attr->tv = new_tarval_from_long(-initialstackframesize, mode_Is);
+               mips_set_irn_reg(NULL, sp, &mips_general_purpose_regs[REG_SP]);
+               //arch_set_irn_register(mips_get_arg_env(), sp, &mips_general_purpose_regs[REG_SP]);
+
+               /* TODO: where to get an edge with a0-a3
+               int i;
+               for(i = 0; i < 4; ++i) {
+                       ir_node *reg = be_abi_reg_map_get(reg_map, &mips_general_purpose_regs[REG_A0 + i]);
+                       ir_node *store = new_rd_mips_store_r(dbg, irg, block, *mem, sp, reg, mode_T);
+                       attr = get_mips_attr(store);
+                       attr->load_store_mode = mode_Iu;
+                       attr->tv = new_tarval_from_long(i * 4, mode_Is);
+
+                       mm[i] = new_r_Proj(irg, block, store, mode_M, pn_Store_M);
+               }
+               */
+
+               reg = be_abi_reg_map_get(reg_map, &mips_general_purpose_regs[REG_FP]);
+               store = new_rd_mips_store_r(dbg, irg, block, *mem, sp, reg, mode_T);
+               attr = get_mips_attr(store);
+               attr->modes.load_store_mode = mode_Iu;
+               attr->tv = new_tarval_from_long(16, mode_Is);
+
+               mm[4] = new_r_Proj(irg, block, store, mode_M, pn_Store_M);
+
+               reg = be_abi_reg_map_get(reg_map, &mips_general_purpose_regs[REG_RA]);
+               store = new_rd_mips_store_r(dbg, irg, block, *mem, sp, reg, mode_T);
+               attr = get_mips_attr(store);
+               attr->modes.load_store_mode = mode_Iu;
+               attr->tv = new_tarval_from_long(20, mode_Is);
+
+               mm[5] = new_r_Proj(irg, block, store, mode_M, pn_Store_M);
+
+               // TODO ideally we would route these mem edges directly towards the epilogue
+               sync = new_r_Sync(irg, block, 2, mm+4);
+               *mem = sync;
+       } else {
+               ir_node *reg, *store;
+               initialstackframesize = 4;
+
+               // save old framepointer
+               sp = new_rd_mips_addi(dbg, irg, block, sp, mode_Is);
+               attr = get_mips_attr(sp);
+               attr->tv = new_tarval_from_long(-initialstackframesize, mode_Is);
+               mips_set_irn_reg(NULL, sp, &mips_general_purpose_regs[REG_SP]);
+               //arch_set_irn_register(mips_get_arg_env(), sp, &mips_general_purpose_regs[REG_SP]);
+
+               reg = be_abi_reg_map_get(reg_map, &mips_general_purpose_regs[REG_FP]);
+               store = new_rd_mips_store_r(dbg, irg, block, *mem, sp, reg, mode_T);
+               attr = get_mips_attr(store);
+               attr->modes.load_store_mode = mode_Iu;
+               attr->tv = new_tarval_from_long(0, mode_Is);
+
+               *mem = new_r_Proj(irg, block, store, mode_M, pn_Store_M);
+       }
+
+       // setup framepointer
+       fp = new_rd_mips_addi(dbg, irg, block, sp, mode_Is);
+       attr = get_mips_attr(fp);
+       attr->tv = new_tarval_from_long(initialstackframesize, mode_Is);
+       mips_set_irn_reg(NULL, fp, &mips_general_purpose_regs[REG_FP]);
+       //arch_set_irn_register(mips_get_arg_env(), fp, &mips_general_purpose_regs[REG_FP]);
+
+       be_abi_reg_map_set(reg_map, &mips_general_purpose_regs[REG_FP], fp);
+       be_abi_reg_map_set(reg_map, &mips_general_purpose_regs[REG_SP], sp);
+
+       return &mips_general_purpose_regs[REG_SP];
+}
+
+static void mips_abi_epilogue(void *self, ir_node *block, ir_node **mem, pmap *reg_map)
+{
+       mips_abi_env_t *env = self;
+       ir_graph *irg = env->irg;
+       dbg_info *dbg = NULL; // TODO where can I get this from?
+       mips_attr_t *attr;
+       ir_node *sp = be_abi_reg_map_get(reg_map, &mips_general_purpose_regs[REG_SP]);
+       ir_node *fp = be_abi_reg_map_get(reg_map, &mips_general_purpose_regs[REG_FP]);
+       ir_node *load;
+       int initial_frame_size = env->debug ? 24 : 4;
+       int fp_save_offset = env->debug ? 16 : 0;
+
+       // restore sp
+       //sp = be_new_IncSP(&mips_general_purpose_regs[REG_SP], irg, block, sp, *mem, BE_STACK_FRAME_SIZE, be_stack_dir_against);
+
+       // copy fp to sp
+       sp = new_rd_mips_move(dbg, irg, block, fp, mode_Iu);
+       mips_set_irn_reg(NULL, sp, &mips_general_purpose_regs[REG_SP]);
+       //arch_set_irn_register(mips_get_arg_env(), fp, &mips_general_purpose_regs[REG_SP]);
+
+       // 1. restore fp
+       load = new_rd_mips_load_r(dbg, irg, block, *mem, sp, mode_T);
+       attr = get_mips_attr(load);
+       attr->modes.load_store_mode = mode_Iu;
+       // sp is at the fp address already, so we have to do fp_save_offset - initial_frame_size
+       attr->tv = new_tarval_from_long(fp_save_offset - initial_frame_size, mode_Is);
+
+       fp = new_r_Proj(irg, block, load, mode_Iu, pn_Load_res);
+       mips_set_irn_reg(NULL, fp, &mips_general_purpose_regs[REG_FP]);
+       //arch_set_irn_register(mips_get_arg_env(), fp, &mips_general_purpose_regs[REG_FP]);
+
+       be_abi_reg_map_set(reg_map, &mips_general_purpose_regs[REG_FP], fp);
+       be_abi_reg_map_set(reg_map, &mips_general_purpose_regs[REG_SP], sp);
+}
+
+/**
+ * Produces the type which sits between the stack args and the locals on the stack.
+ * it will contain the return address and space to store the old frame pointer.
+ * @return The Firm type modelling the ABI between type.
+ */
+static ir_type *mips_abi_get_between_type(void *self) {
+       mips_abi_env_t *env = self;
+
+       static ir_type *debug_between_type = NULL;
+       static ir_type *opt_between_type = NULL;
+       static entity *old_fp_ent    = NULL;
+
+       if(env->debug && debug_between_type == NULL) {
+               entity *a0_ent, *a1_ent, *a2_ent, *a3_ent;
+               entity *ret_addr_ent;
+               ir_type *ret_addr_type = new_type_primitive(new_id_from_str("return_addr"), mode_P);
+               ir_type *old_fp_type   = new_type_primitive(new_id_from_str("fp"), mode_P);
+               ir_type *old_param_type = new_type_primitive(new_id_from_str("param"), mode_Iu);
+
+               debug_between_type     = new_type_class(new_id_from_str("mips_between_type"));
+               a0_ent                             = new_entity(debug_between_type, new_id_from_str("a0_ent"), old_param_type);
+               a1_ent                             = new_entity(debug_between_type, new_id_from_str("a1_ent"), old_param_type);
+               a2_ent                             = new_entity(debug_between_type, new_id_from_str("a2_ent"), old_param_type);
+               a3_ent                             = new_entity(debug_between_type, new_id_from_str("a3_ent"), old_param_type);
+               old_fp_ent             = new_entity(debug_between_type, new_id_from_str("old_fp"), old_fp_type);
+               ret_addr_ent           = new_entity(debug_between_type, new_id_from_str("ret_addr"), ret_addr_type);
+
+               set_entity_offset_bytes(a0_ent, 0);
+               set_entity_offset_bytes(a1_ent, 4);
+               set_entity_offset_bytes(a2_ent, 8);
+               set_entity_offset_bytes(a3_ent, 12);
+               set_entity_offset_bytes(old_fp_ent, 16);
+               set_entity_offset_bytes(ret_addr_ent, 20);
+
+               set_type_size_bytes(debug_between_type, 24);
+       } else if(!env->debug && opt_between_type == NULL) {
+               ir_type *old_fp_type   = new_type_primitive(new_id_from_str("fp"), mode_P);
+               entity *old_fp_ent;
+
+               opt_between_type       = new_type_class(new_id_from_str("mips_between_type"));
+               old_fp_ent             = new_entity(opt_between_type, new_id_from_str("old_fp"), old_fp_type);
+               set_entity_offset_bytes(old_fp_ent, 0);
+               set_type_size_bytes(opt_between_type, 4);
+       }
+
+       return env->debug ? debug_between_type : opt_between_type;
+}
+
+static const be_abi_callbacks_t mips_abi_callbacks = {
+       mips_abi_init,
+       free,
+       mips_abi_get_between_type,
+       mips_abi_dont_save_regs,
+       mips_abi_prologue,
+       mips_abi_epilogue,
+};
+
+/**
+ * Get the ABI restrictions for procedure calls.
+ * @param self        The this pointer.
+ * @param method_type The type of the method (procedure) in question.
+ * @param abi         The abi object to be modified
+ */
+static void mips_get_call_abi(const void *self, ir_type *method_type, be_abi_call_t *abi) {
+       ir_type  *tp;
+       ir_mode  *mode;
+       int       n = get_method_n_params(method_type);
+       int result_count;
+       int       i;
+       ir_mode **modes;
+       const arch_register_t *reg;
+       be_abi_call_flags_t call_flags;
+
+       memset(&call_flags, 0, sizeof(call_flags));
+       call_flags.bits.left_to_right         = 0;
+       call_flags.bits.store_args_sequential = 0;
+       call_flags.bits.try_omit_fp           = 1;
+       call_flags.bits.fp_free               = 0;
+       call_flags.bits.call_has_imm          = 1;
+
+       /* set stack parameter passing style */
+       be_abi_call_set_flags(abi, call_flags, &mips_abi_callbacks);
+
+       /* collect the mode for each type */
+       modes = alloca(n * sizeof(modes[0]));
+       for (i = 0; i < n; i++) {
+               tp       = get_method_param_type(method_type, i);
+               modes[i] = get_type_mode(tp);
+       }
+
+       // assigns parameters to registers or stack
+       for (i = 0; i < n; i++) {
+               // first 4 params in $a0-$a3, the others on the stack
+               if(i < 4) {
+                       reg = &mips_general_purpose_regs[REG_A0 + i];
+                       be_abi_call_param_reg(abi, i, reg);
+               } else {
+                       /* default: all parameters on stack */
+                       be_abi_call_param_stack(abi, i, 4, 0, 0);
+               }
+       }
+
+       /* set return register */
+       /* default: return value is in R0 (and maybe R1) */
+       result_count = get_method_n_ress(method_type);
+       assert(result_count <= 2 && "More than 2 result values not supported");
+       for(i = 0; i < result_count; ++i) {
+               const arch_register_t* reg;
+               tp   = get_method_res_type(method_type, i);
+               mode = get_type_mode(tp);
+               ASSERT_NO_FLOAT(mode);
+
+               reg = &mips_general_purpose_regs[REG_V0 + i];
+               be_abi_call_res_reg(abi, i, reg);
+       }
+}
+
+static const void *mips_get_irn_ops(const arch_irn_handler_t *self, const ir_node *irn) {
+       return &mips_irn_ops;
+}
+
+const arch_irn_handler_t mips_irn_handler = {
+       mips_get_irn_ops
+};
+
+const arch_irn_handler_t *mips_get_irn_handler(const void *self) {
+       return &mips_irn_handler;
+}
+
+/**
+ * Initializes the code generator interface.
+ */
+static const arch_code_generator_if_t *mips_get_code_generator_if(void *self) {
+       return &mips_code_gen_if;
+}
+
+#ifdef WITH_LIBCORE
+static void mips_register_options(lc_opt_entry_t *ent)
+{
+}
+#endif /* WITH_LIBCORE */
+
+const arch_isa_if_t mips_isa_if = {
+#ifdef WITH_LIBCORE
+       mips_register_options,
+#endif
+       mips_init,
+       mips_done,
+       mips_get_n_reg_class,
+       mips_get_reg_class,
+       mips_get_reg_class_for_mode,
+       mips_get_call_abi,
+       mips_get_irn_handler,
+       mips_get_code_generator_if,
+       mips_get_list_sched_selector,
+};
diff --git a/ir/be/mips/bearch_mips.h b/ir/be/mips/bearch_mips.h
new file mode 100644 (file)
index 0000000..bc0fdc1
--- /dev/null
@@ -0,0 +1,22 @@
+#ifndef _BEARCH_MIPS_H_
+#define _BEARCH_MIPS_H_
+
+#include "../bearch.h"
+
+typedef struct _mips_code_gen_t mips_code_gen_t;
+
+extern const arch_isa_if_t mips_isa_if;
+
+/** return the scheduled block at position pos */
+ir_node *mips_get_sched_block(const mips_code_gen_t *cg, int pos);
+
+/** return the number of scheduled blocks */
+int mips_get_sched_n_blocks(const mips_code_gen_t *cg);
+
+/** set a block schedule number */
+void mips_set_block_sched_nr(ir_node *block, int nr);
+
+/** get a block schedule number */
+int mips_get_block_sched_nr(ir_node *block);
+
+#endif /* _BEARCH_MIPS_H_ */
diff --git a/ir/be/mips/bearch_mips_t.h b/ir/be/mips/bearch_mips_t.h
new file mode 100644 (file)
index 0000000..1e4e303
--- /dev/null
@@ -0,0 +1,54 @@
+#ifndef _BEARCH_mips_T_H_
+#define _BEARCH_mips_T_H_
+
+#include "debug.h"
+#include "irgopt.h"
+#include "bearch_mips.h"
+#include "mips_nodes_attr.h"
+#include "../be.h"
+#include "set.h"
+
+struct _mips_code_gen_t {
+       const arch_code_generator_if_t *impl;           /**< implementation */
+       ir_graph                       *irg;            /**< current irg */
+       FILE                           *out;            /**< output file */
+       const arch_env_t               *arch_env;       /**< the arch env */
+       set                            *reg_set;        /**< set to memorize registers for FIRM nodes (e.g. phi) */
+       firm_dbg_module_t              *mod;            /**< debugging module */
+       int                             emit_decls;     /**< flag indicating if decls were already emitted */
+       const be_irg_t                 *birg;           /**< The be-irg (contains additional information about the irg) */
+       ir_node                        **bl_list;               /**< The block schedule list. */
+       survive_dce_t                              *bl_list_sdce;       /**< survive dce environment for the block schedule list */
+};
+
+
+typedef struct _mips_isa_t {
+       const arch_isa_if_t   *impl;
+       const arch_register_t *sp;            /**< The stack pointer register. */
+       const arch_register_t *fp;            /**< The base pointer register. */
+       const int              stack_dir;     /**< -1 for decreasing, 1 for increasing. */
+       int                  num_codegens;
+} mips_isa_t;
+
+
+typedef struct _mips_irn_ops_t {
+       const arch_irn_ops_if_t *impl;
+       mips_code_gen_t     *cg;
+} mips_irn_ops_t;
+
+
+/* this is a struct to minimize the number of parameters
+   for transformation walker */
+typedef struct _mips_transform_env_t {
+       firm_dbg_module_t *mod;      /**< The firm debugger */
+       dbg_info          *dbg;      /**< The node debug info */
+       ir_graph          *irg;      /**< The irg, the node should be created in */
+       ir_node           *block;    /**< The block, the node should belong to */
+       ir_node           *irn;      /**< The irn, to be transformed */
+       ir_mode           *mode;     /**< The mode of the irn */
+       mips_code_gen_t   *cg;       /**< The code generator */
+} mips_transform_env_t;
+
+ir_node *mips_new_NoReg(mips_code_gen_t *cg);
+
+#endif /* _BEARCH_mips_T_H_ */
diff --git a/ir/be/mips/mips_emitter.c b/ir/be/mips/mips_emitter.c
new file mode 100644 (file)
index 0000000..bcd7a20
--- /dev/null
@@ -0,0 +1,773 @@
+/* mips emitter */
+/* $Id$ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <limits.h>
+
+#include "xmalloc.h"
+#include "tv.h"
+#include "iredges.h"
+#include "debug.h"
+#include "irgwalk.h"
+#include "irprintf.h"
+#include "irop_t.h"
+#include "irargs_t.h"
+#include "irprog_t.h"
+#include "irouts.h"
+
+#include "../besched.h"
+#include "../benode_t.h"
+#include "../beutil.h"
+
+#include "mips_emitter.h"
+#include "gen_mips_emitter.h"
+#include "mips_nodes_attr.h"
+#include "mips_new_nodes.h"
+#include "mips_map_regs.h"
+
+#define SNPRINTF_BUF_LEN 128
+
+static const arch_env_t *arch_env = NULL;
+
+
+/*************************************************************
+ *             _       _    __   _          _
+ *            (_)     | |  / _| | |        | |
+ *  _ __  _ __ _ _ __ | |_| |_  | |__   ___| |_ __   ___ _ __
+ * | '_ \| '__| | '_ \| __|  _| | '_ \ / _ \ | '_ \ / _ \ '__|
+ * | |_) | |  | | | | | |_| |   | | | |  __/ | |_) |  __/ |
+ * | .__/|_|  |_|_| |_|\__|_|   |_| |_|\___|_| .__/ \___|_|
+ * | |                                       | |
+ * |_|                                       |_|
+ *************************************************************/
+
+static const char *get_symconst_str(ir_node *node)
+{
+       ident *id;
+
+       switch(get_SymConst_kind(node)) {
+       case symconst_addr_name:
+               id = get_SymConst_name(node);
+               return get_id_str(id);
+       case symconst_addr_ent:
+               id = get_entity_ident(get_SymConst_entity(node));
+               return get_id_str(id);
+       default:
+               assert(0);
+       }
+
+       return NULL;
+}
+
+/**
+ * Return a const or symconst as string.
+ */
+static const char *node_const_to_str(ir_node *n)
+{
+       static char buf[64];
+       const mips_attr_t *attr = get_mips_attr(n);
+       long val;
+
+       if(is_mips_load_r(n) || is_mips_store_r(n)) {
+               mips_attr_t *attr = get_mips_attr(n);
+               ir_node *symconst;
+
+               if(attr->tv != NULL) {
+                       val = get_tarval_long(attr->tv);
+                       snprintf(buf, sizeof(buf), "%ld", val);
+
+                       return buf;
+               }
+               if(attr->stack_entity != NULL) {
+                       snprintf(buf, sizeof(buf), "%d", attr->stack_entity_offset);
+                       return buf;
+               }
+
+               symconst = get_irn_n(n, 1);
+               assert(get_irn_opcode(symconst) == iro_SymConst);
+
+               return get_symconst_str(symconst);
+       } else if(is_mips_la(n)) {
+               snprintf(buf, sizeof(buf), "%s", get_id_str(attr->symconst_id));
+               return buf;
+       } else if(is_mips_lli(n)) {
+               assert(attr->tv != NULL);
+               if(get_mode_sign(get_tarval_mode(attr->tv))) {
+                       long val = get_tarval_long(attr->tv);
+                       snprintf(buf, sizeof(buf), "0x%04X", val & 0xffff);
+               } else {
+                       unsigned long val = get_tarval_long(attr->tv);
+                       snprintf(buf, sizeof(buf), "0x%04X", val & 0xffff);
+               }
+
+               return buf;
+       } else if(is_mips_lui(n)) {
+               assert(attr->tv != NULL);
+               if(get_mode_sign(get_tarval_mode(attr->tv))) {
+                       long val = get_tarval_long(attr->tv);
+                       val = (val & 0xffff0000) >> 16;
+                       snprintf(buf, sizeof(buf), "0x%04X", val & 0xffff);
+               } else {
+                       unsigned long val = get_tarval_long(attr->tv);
+                       val = (val & 0xffff0000) >> 16;
+                       snprintf(buf, sizeof(buf), "0x%04X", val & 0xffff);
+               }
+
+               return buf;
+       }
+
+       assert(attr->tv != NULL);
+       val = get_tarval_long(attr->tv);
+       snprintf(buf, sizeof(buf), "%ld", val);
+
+       return buf;
+}
+
+/**
+ * Returns node's offset as string.
+ */
+static const char *node_offset_to_str(ir_node *n)
+{
+       return "";
+}
+
+/* We always pass the ir_node which is a pointer. */
+static int mips_get_arg_type(const lc_arg_occ_t *occ) {
+       return lc_arg_type_ptr;
+}
+
+
+/**
+ * Returns the register at in position pos.
+ */
+static const arch_register_t *get_in_reg(ir_node *irn, int pos)
+{
+       ir_node                *op;
+       const arch_register_t  *reg = NULL;
+
+       assert(get_irn_arity(irn) > pos && "Invalid IN position");
+
+       /* The out register of the operator at position pos is the
+          in register we need. */
+       op = get_irn_n(irn, pos);
+
+       reg = arch_get_irn_register(arch_env, op);
+
+       assert(reg && "no in register found");
+       return reg;
+}
+
+/**
+ * Returns the register at out position pos.
+ */
+static const arch_register_t *get_out_reg(ir_node *irn, int pos)
+{
+       ir_node                *proj;
+       const arch_register_t  *reg = NULL;
+
+       /* 1st case: irn is not of mode_T, so it has only                 */
+       /*           one OUT register -> good                             */
+       /* 2nd case: irn is of mode_T -> collect all Projs and ask the    */
+       /*           Proj with the corresponding projnum for the register */
+
+       if (get_irn_mode(irn) != mode_T) {
+               reg = arch_get_irn_register(arch_env, irn);
+       }
+       else if (is_mips_irn(irn)) {
+               reg = get_mips_out_reg(irn, pos);
+       }
+       else {
+               const ir_edge_t *edge;
+
+               foreach_out_edge(irn, edge) {
+                       proj = get_edge_src_irn(edge);
+                       assert(is_Proj(proj) && "non-Proj from mode_T node");
+                       if (get_Proj_proj(proj) == pos) {
+                               reg = arch_get_irn_register(arch_env, proj);
+                               break;
+                       }
+               }
+       }
+
+       assert(reg && "no out register found");
+       return reg;
+}
+
+/**
+ * Returns the number of the in register at position pos.
+ */
+int get_mips_reg_nr(ir_node *irn, int pos, int in_out)
+{
+       const arch_register_t *reg;
+
+       if (in_out == 1) {
+               reg = get_in_reg(irn, pos);
+       }
+       else {
+               reg = get_out_reg(irn, pos);
+       }
+
+       return arch_register_get_index(reg);
+}
+
+/**
+ * Returns the name of the in register at position pos.
+ */
+const char *get_mips_reg_name(ir_node *irn, int pos, int in_out)
+{
+       const arch_register_t *reg;
+
+       if (in_out == 1) {
+               reg = get_in_reg(irn, pos);
+       }
+       else {
+               reg = get_out_reg(irn, pos);
+       }
+
+       return arch_register_get_name(reg);
+}
+
+/**
+ * Get the register name for a node.
+ */
+static int mips_get_reg_name(lc_appendable_t *app,
+    const lc_arg_occ_t *occ, const lc_arg_value_t *arg)
+{
+       const char *buf;
+       int res;
+       ir_node    *X  = arg->v_ptr;
+       int         nr = occ->width - 1;
+
+       if (!X)
+               return lc_arg_append(app, occ, "(null)", 6);
+
+       if (occ->conversion == 'S') {
+               buf = get_mips_reg_name(X, nr, 1);
+       }
+       else { /* 'D' */
+               buf = get_mips_reg_name(X, nr, 0);
+       }
+
+       res = lc_appendable_chadd(app, '$');
+       res += lc_appendable_snadd(app, buf, strlen(buf));
+       return res;
+}
+
+/**
+ * Returns the tarval or offset of an mips node as a string.
+ */
+static int mips_const_to_str(lc_appendable_t *app,
+    const lc_arg_occ_t *occ, const lc_arg_value_t *arg)
+{
+       const char *buf;
+       ir_node    *X = arg->v_ptr;
+
+       if (!X)
+               return lc_arg_append(app, occ, "(null)", 6);
+
+       if (occ->conversion == 'C') {
+               buf = node_const_to_str(X);
+       }
+       else { /* 'O' */
+               buf = node_offset_to_str(X);
+       }
+
+       return lc_arg_append(app, occ, buf, strlen(buf));
+}
+
+/**
+ * Determines the SSE suffix depending on the mode.
+ */
+static int mips_get_mode_suffix(lc_appendable_t *app,
+    const lc_arg_occ_t *occ, const lc_arg_value_t *arg)
+{
+       ir_node *X = arg->v_ptr;
+
+       if (!X)
+               return lc_arg_append(app, occ, "(null)", 6);
+
+       if (get_mode_size_bits(get_irn_mode(X)) == 32)
+               return lc_appendable_chadd(app, 's');
+       else
+               return lc_appendable_chadd(app, 'd');
+}
+
+/**
+ * Return the mips printf arg environment.
+ * We use the firm environment with some additional handlers.
+ */
+const lc_arg_env_t *mips_get_arg_env(void)
+{
+       static lc_arg_env_t *env = NULL;
+
+       static const lc_arg_handler_t mips_reg_handler   = { mips_get_arg_type, mips_get_reg_name };
+       static const lc_arg_handler_t mips_const_handler = { mips_get_arg_type, mips_const_to_str };
+       static const lc_arg_handler_t mips_mode_handler  = { mips_get_arg_type, mips_get_mode_suffix };
+
+       if(env == NULL) {
+               /* extend the firm printer */
+               env = firm_get_arg_env();
+                       //lc_arg_new_env();
+
+               lc_arg_register(env, "mips:sreg", 'S', &mips_reg_handler);
+               lc_arg_register(env, "mips:dreg", 'D', &mips_reg_handler);
+               lc_arg_register(env, "mips:cnst", 'C', &mips_const_handler);
+               lc_arg_register(env, "mips:offs", 'O', &mips_const_handler);
+               lc_arg_register(env, "mips:mode", 'M', &mips_mode_handler);
+       }
+
+       return env;
+}
+
+/*
+ * Add a number to a prefix. This number will not be used a second time.
+ */
+static char *get_unique_label(char *buf, size_t buflen, const char *prefix)
+{
+       static unsigned long id = 0;
+       snprintf(buf, buflen, "%s%lu", prefix, ++id);
+       return buf;
+}
+
+
+/**
+ * Returns the target label for a control flow node.
+ */
+static char *get_cfop_target(const ir_node *irn, char *buf)
+{
+       ir_node *bl = get_irn_link(irn);
+
+       snprintf(buf, SNPRINTF_BUF_LEN, "BLOCK_%ld", get_irn_node_nr(bl));
+       return buf;
+}
+
+/************************************************************************/
+/* ABI Handling
+/************************************************************************/
+
+static void mips_emit_IncSP(const ir_node *node, mips_emit_env_t *env)
+{
+       FILE *F = env->out;
+       int offset = be_get_IncSP_offset(node);
+       if(offset == 0)
+               return;
+
+       if(be_get_IncSP_direction(node) != be_stack_dir_expand)
+               offset = -offset;
+
+       fprintf(F, "\taddi $sp, $sp, %d\n", -offset);
+}
+
+static void mips_emit_Copy(const ir_node *node, mips_emit_env_t *env)
+{
+       FILE *F = env->out;
+
+       lc_efprintf(mips_get_arg_env(), F, "\tor %1D, $zero, %1S\t\t\t# copy\n", node, node);
+}
+
+static void mips_emit_Return(const ir_node* node, mips_emit_env_t *env)
+{
+       FILE *F = env->out;
+       fprintf(F, "\tj $ra\t\t\t\t# return\n");
+}
+
+static void mips_emit_nops(FILE* F, int n)
+{
+       int i;
+
+       for(i = 0; i < n; ++i) {
+               fprintf(F, "\tnop\n");
+       }
+}
+
+static void mips_emit_Perm(const ir_node *node, mips_emit_env_t *env)
+{
+       FILE* F = env->out;
+
+       assert(/*get_irn_n_outs(node) == 2 &&*/ get_irn_arity(node) == 2);
+
+       lc_efprintf(mips_get_arg_env(), F, "\txor %1S, %1S, %2S\t\t\t# perm\n", node, node, node);
+       mips_emit_nops(F, 3);
+       lc_efprintf(mips_get_arg_env(), F, "\txor %2S, %2S, %1S\n", node, node, node);
+       mips_emit_nops(F, 3);
+       lc_efprintf(mips_get_arg_env(), F, "\txor %1S, %1S, %2S\n", node, node, node);
+       mips_emit_nops(F, 3);
+}
+
+static void mips_emit_Spill(const ir_node* node, mips_emit_env_t *env)
+{
+       FILE* F = env->out;
+
+       ir_node* context = be_get_Spill_context(node);
+       entity* ent = be_get_spill_entity(node);
+       lc_efprintf(mips_get_arg_env(), F, "\tsw %1S, %d($fp)\n", node, get_entity_offset_bytes(ent));
+}
+
+static void mips_emit_Reload(const ir_node* node, mips_emit_env_t *env)
+{
+       FILE* F = env->out;
+
+       entity* ent = be_get_spill_entity(node);
+       lc_efprintf(mips_get_arg_env(), F, "\tlw %1D, %d($fp)\n", node, get_entity_offset_bytes(ent));
+}
+
+/************************************************************************/
+/* Calls
+/************************************************************************/
+
+static void mips_emit_Call(ir_node *node, mips_emit_env_t *env)
+{
+       FILE *F = env->out;
+       const arch_register_t *callee_reg;
+
+       // call to imediate value (label)
+       entity *callee = be_Call_get_entity(node);
+       if(callee != NULL) {
+               fprintf(F, "\tjal %s\n", get_entity_name(callee));
+               return;
+       }
+
+       // call to function pointer
+       callee_reg = get_in_reg(node, be_pos_Call_ptr);
+       assert(callee_reg != NULL);
+
+       fprintf(F, "\tjal %s\n", arch_register_get_name(callee_reg));
+}
+
+/************************************************************************
+ *      _
+ *     | |_   _ _ __ ___  _ __  ___
+ *  _  | | | | | '_ ` _ \| '_ \/ __|
+ * | |_| | |_| | | | | | | |_) \__ \
+ *  \___/ \__,_|_| |_| |_| .__/|___/
+ *                       |_|
+ ************************************************************************/
+
+const char* mips_get_block_label(const ir_node* block)
+{
+       static char buf[64];
+       snprintf(buf, sizeof(buf), "BLOCK_%ld", get_irn_node_nr(block));
+
+       return buf;
+}
+
+static void mips_emit_Jump(ir_node *node, mips_emit_env_t *env)
+{
+       FILE *F = env->out;
+       const ir_node *block = get_irn_link(node);
+
+       assert(is_Block(block));
+
+       fprintf(F, "\tb %s\n", mips_get_block_label(block));
+}
+
+ir_node *mips_get_jump_block(const ir_node* node, int projn)
+{
+       const ir_edge_t *oute;
+       for(oute = get_irn_out_edge_first(node); oute != NULL;
+           oute = get_irn_out_edge_next(node, oute)) {
+               ir_node *proj = get_edge_src_irn(oute);
+               long n;
+               assert(is_Proj(proj));
+
+               n = get_Proj_proj(proj);
+               if(n == projn)
+                       return get_irn_link(proj);
+       }
+
+       return NULL;
+}
+
+/************************************************************************
+ *  ____          _ _       _         _                                                                        *
+ * / ___|_      _(_) |_ ___| |__     | |_   _ _ __ ___  _ __                   *
+ * \___ \ \ /\ / / | __/ __| '_ \ _  | | | | | '_ ` _ \| '_ \                  *
+ *  ___) \ V  V /| | || (__| | | | |_| | |_| | | | | | | |_) |                 *
+ * |____/ \_/\_/ |_|\__\___|_| |_|\___/ \__,_|_| |_| |_| .__/                  *
+ *                                                     |_|                             *
+ *                                                                      *
+ ************************************************************************/
+
+/* jump table entry (target and corresponding number) */
+typedef struct _branch_t {
+       ir_node *target;
+       int      value;
+} branch_t;
+
+/* jump table for switch generation */
+typedef struct _jmp_tbl_t {
+       ir_node  *defBlock;        /**< default target */
+       int       min_value;       /**< smallest switch case */
+       int       max_value;       /**< largest switch case */
+       int       num_branches;    /**< number of jumps */
+       char     *label;           /**< label of the jump table */
+       branch_t *branches;        /**< jump array */
+} jmp_tbl_t;
+
+/**
+ * Compare two variables of type branch_t. Used to sort all switch cases
+ */
+static int mips_cmp_branch_t(const void *a, const void *b) {
+       branch_t *b1 = (branch_t *)a;
+       branch_t *b2 = (branch_t *)b;
+
+       if (b1->value <= b2->value)
+               return -1;
+       else
+               return 1;
+}
+
+const char* mips_get_jumptbl_label(const ir_node* switchjmp)
+{
+       static char buf[64];
+       snprintf(buf, sizeof(buf), "__JUMPTBL%ld", get_irn_node_nr(switchjmp));
+
+       return buf;
+}
+
+/**
+ * Emits code for a SwitchJmp (creates a jump table if
+ * possible otherwise a cmp-jmp cascade). Stolen from ia32
+ */
+void emit_mips_jump_table(const ir_node *irn, FILE* F) {
+       int                 lastval, i, pn, do_jmp_tbl = 1;
+       jmp_tbl_t           tbl;
+       ir_node            *proj;
+       const ir_edge_t    *edge;
+       const lc_arg_env_t *env = mips_get_arg_env();
+       mips_attr_t *attr;
+       int i2;
+
+       attr = get_mips_attr(irn);
+
+       /* fill the table structure */
+       tbl.label        = xmalloc(SNPRINTF_BUF_LEN);
+       tbl.label        = get_unique_label(tbl.label, SNPRINTF_BUF_LEN, "JMPTBL_");
+       tbl.defBlock     = NULL;
+       tbl.num_branches = get_irn_n_edges(irn);
+       tbl.branches     = xcalloc(tbl.num_branches, sizeof(tbl.branches[0]));
+       tbl.min_value    = INT_MAX;
+       tbl.max_value    = INT_MIN;
+
+       i = 0;
+       /* go over all proj's and collect them */
+       foreach_out_edge(irn, edge) {
+               proj = get_edge_src_irn(edge);
+               assert(is_Proj(proj) && "Only proj allowed at SwitchJmp");
+
+               pn = get_Proj_proj(proj);
+
+               /* create branch entry */
+               tbl.branches[i].target = get_irn_link(proj);
+               tbl.branches[i].value  = pn;
+
+               tbl.min_value = pn < tbl.min_value ? pn : tbl.min_value;
+               tbl.max_value = pn > tbl.max_value ? pn : tbl.max_value;
+
+               i++;
+       }
+
+       /* sort the branches by their number */
+       qsort(tbl.branches, tbl.num_branches, sizeof(tbl.branches[0]), mips_cmp_branch_t);
+
+       fprintf(F, "%s:\n", mips_get_jumptbl_label(irn));
+       lastval = tbl.min_value;
+       for(i = 0; i < tbl.num_branches; ++i) {
+               const branch_t *branch = &tbl.branches[i];
+               int value = branch->value;
+
+               for(i2 = lastval + 1; i2 < value; ++i2) {
+                       fprintf(F, "\t.word %s\n", get_id_str(attr->symconst_id));
+               }
+
+               fprintf(F, "\t.word %s\n", mips_get_block_label(branch->target));
+               lastval = branch->value;
+       }
+
+       if (tbl.label)
+               free(tbl.label);
+       if (tbl.branches)
+               free(tbl.branches);
+}
+
+static void dump_jump_tables(ir_node* node, void *env)
+{
+       FILE* F = (FILE*) env;
+
+       // emit jump tables
+       if(is_mips_SwitchJump(node)) {
+               fprintf(F, ".data\n");
+               emit_mips_jump_table(node, F);
+               fprintf(F, ".text\n");
+       }
+}
+
+/***********************************************************************************
+ *                  _          __                                             _
+ *                 (_)        / _|                                           | |
+ *  _ __ ___   __ _ _ _ __   | |_ _ __ __ _ _ __ ___   _____      _____  _ __| | __
+ * | '_ ` _ \ / _` | | '_ \  |  _| '__/ _` | '_ ` _ \ / _ \ \ /\ / / _ \| '__| |/ /
+ * | | | | | | (_| | | | | | | | | | | (_| | | | | | |  __/\ V  V / (_) | |  |   <
+ * |_| |_| |_|\__,_|_|_| |_| |_| |_|  \__,_|_| |_| |_|\___| \_/\_/ \___/|_|  |_|\_\
+ *
+ ***********************************************************************************/
+
+static void mips_emit_nothing(ir_mode *mode, mips_emit_env_t *env)
+{
+}
+
+static void mips_emit_this_shouldnt_happen(ir_mode *mode, mips_emit_env_t *env)
+{
+       assert(0);
+}
+
+/**
+ * Register emitter functions for mips backend
+ */
+void mips_register_emitters(void)
+{
+       /* first clear the generic function pointer for all ops */
+       clear_irp_opcodes_generic_func();
+
+       /* register all emitter functions defined in spec */
+       mips_register_spec_emitters();
+
+       /* benode emitter */
+       op_be_IncSP->ops.generic = (op_func) mips_emit_IncSP;
+       op_be_SetSP->ops.generic = (op_func) mips_emit_this_shouldnt_happen;
+       op_be_AddSP->ops.generic = (op_func) mips_emit_this_shouldnt_happen;
+       op_be_Call->ops.generic = (op_func) mips_emit_Call;
+       op_be_Keep->ops.generic = (op_func) mips_emit_nothing;
+       op_be_Copy->ops.generic = (op_func) mips_emit_Copy;
+       op_be_Return->ops.generic = (op_func) mips_emit_Return;
+       op_be_RegParams->ops.generic = (op_func) mips_emit_nothing;
+       op_be_Spill->ops.generic = (op_func) mips_emit_Spill;
+       op_be_Reload->ops.generic = (op_func) mips_emit_Reload;
+
+       op_Start->ops.generic = (op_func) mips_emit_nothing;
+       op_Proj->ops.generic = (op_func) mips_emit_nothing;
+       op_SymConst->ops.generic = (op_func) mips_emit_nothing;
+       op_Jmp->ops.generic = (op_func) mips_emit_Jump;
+       op_Cmp->ops.generic = (op_func) mips_emit_this_shouldnt_happen;
+       op_Cond->ops.generic = (op_func) mips_emit_this_shouldnt_happen;
+}
+
+typedef void (*emit_func) (const ir_node *, mips_emit_env_t *);
+
+/**
+ * Emits assembly for a single node
+ */
+static void mips_emit_node(ir_node *irn, mips_emit_env_t* env)
+{
+       mips_emit_env_t        *emit_env = env;
+       firm_dbg_module_t *mod      = emit_env->mod;
+       FILE              *F        = emit_env->out;
+       ir_op             *op       = get_irn_op(irn);
+
+       DBG((mod, LEVEL_1, "emitting code for %+F\n", irn));
+
+       if (op->ops.generic) {
+               emit_func emit = (emit_func) op->ops.generic;
+               (*emit) (irn, env);
+
+#if 0
+               if(emit != (emit_func) mips_emit_nothing)
+                       mips_emit_nops(F, 5);
+#endif
+       } else {
+               ir_fprintf(F, "\t\t\t\t\t# %+F\n", irn);
+       }
+}
+
+/**
+ * Walks over the nodes in a block connected by scheduling edges
+ * and emits code for each node.
+ */
+void mips_gen_block(ir_node *block, void *env)
+{
+       FILE *F = ((mips_emit_env_t *)env)->out;
+       ir_node *irn;
+
+       if (! is_Block(block))
+               return;
+
+       fprintf(F, "%s:\n", mips_get_block_label(block));
+       sched_foreach(block, irn) {
+               mips_emit_node(irn, env);
+       }
+       fprintf(F, "\n");
+}
+
+/**
+ * Emits code for function start.
+ */
+void mips_emit_start(FILE *F, ir_graph *irg)
+{
+       const char *irg_name = get_entity_name(get_irg_entity(irg));
+
+       // dump jump tables
+       irg_walk_graph(irg, NULL, dump_jump_tables, F);
+
+       fprintf(F, "\n\n");
+       fprintf(F, "# Function Start of %s\n", irg_name);
+       fprintf(F, "%s:\n", irg_name);
+}
+
+/**
+ * Emits code for function end
+ */
+void mips_emit_end(FILE *F, ir_graph *irg)
+{
+       const char *irg_name = get_entity_name(get_irg_entity(irg));
+
+       fprintf(F, "# End of function %s we should never get here...\n", irg_name);
+       fprintf(F, "\tjal exit\n");
+}
+
+/**
+ * Sets labels for control flow nodes (jump target)
+ * TODO: Jump optimization
+ */
+void mips_gen_labels(ir_node *block, void *env)
+{
+       ir_node *pred;
+       int n = get_Block_n_cfgpreds(block);
+
+       for (n--; n >= 0; n--) {
+               pred = get_Block_cfgpred(block, n);
+               set_irn_link(pred, block);
+       }
+}
+
+/**
+ * Main driver
+ */
+void mips_gen_routine(FILE *F, ir_graph *irg, const mips_code_gen_t *cg)
+{
+       mips_emit_env_t emit_env;
+       int i, n;
+
+       emit_env.mod      = firm_dbg_register("firm.be.mips.emit");
+       emit_env.out      = F;
+       emit_env.arch_env = cg->arch_env;
+       emit_env.cg       = cg;
+
+       /* set the global arch_env (needed by print hooks) */
+       arch_env = cg->arch_env;
+
+       irg_block_walk_graph(irg, mips_gen_labels, NULL, &emit_env);
+       mips_emit_start(F, irg);
+//     irg_walk_blkwise_graph(irg, NULL, mips_gen_block, &emit_env);
+
+       dump_ir_block_graph_sched(irg, "-kaputtelist");
+
+       for (i = 0, n = mips_get_sched_n_blocks(cg); i < n; ++i) {
+               ir_node *block = mips_get_sched_block(cg, i);
+               mips_gen_block(block, &emit_env);
+       }
+
+       mips_emit_end(F, irg);
+}
diff --git a/ir/be/mips/mips_emitter.h b/ir/be/mips/mips_emitter.h
new file mode 100644 (file)
index 0000000..86c4133
--- /dev/null
@@ -0,0 +1,35 @@
+#ifndef _mips_EMITTER_H_
+#define _mips_EMITTER_H_
+
+#include "irargs_t.h"  // this also inlucdes <libcore/lc_print.h>
+#include "irnode.h"
+#include "debug.h"
+
+#include "../bearch.h"
+
+#include "bearch_mips_t.h"
+
+typedef struct _mips_emit_env_t {
+       firm_dbg_module_t         *mod;
+       FILE                      *out;
+       const arch_env_t          *arch_env;
+       const mips_code_gen_t *cg;
+} mips_emit_env_t;
+
+const lc_arg_env_t *mips_get_arg_env(void);
+
+void equalize_dest_src(FILE *F, ir_node *n);
+
+int get_mips_reg_nr(ir_node *irn, int posi, int in_out);
+const char *get_mips_in_reg_name(ir_node *irn, int pos);
+
+void mips_gen_routine(FILE *F, ir_graph *irg, const mips_code_gen_t *cg);
+void mips_register_emitters(void);
+ir_node *mips_get_jump_block(const ir_node* node, int projn);
+
+/** returns the label used for a block */
+const char* mips_get_block_label(const ir_node* block);
+/** returns the label for the jumptable */
+const char* mips_get_jumptbl_label(const ir_node* switchjmp);
+
+#endif /* _mips_EMITTER_H_ */
diff --git a/ir/be/mips/mips_gen_decls.c b/ir/be/mips/mips_gen_decls.c
new file mode 100644 (file)
index 0000000..ed1a854
--- /dev/null
@@ -0,0 +1,609 @@
+/**
+ * Dumps global variables and constants as mips assembler.
+ * @date 14.02.2006
+ * @version $Id$
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <assert.h>
+
+#include "xmalloc.h"
+#include <obstack.h>
+
+#ifdef obstack_chunk_alloc
+# undef obstack_chunk_alloc
+# define obstack_chunk_alloc xmalloc
+#else
+# define obstack_chunk_alloc xmalloc
+# define obstack_chunk_free free
+#endif
+
+#include "tv.h"
+#include "irnode.h"
+#include "entity.h"
+#include "irprog.h"
+
+#include "mips_gen_decls.h"
+
+extern int obstack_printf(struct obstack *obst, char *fmt, ...);
+
+/************************************************************************/
+
+/*
+ * returns the highest bit value
+ */
+static unsigned highest_bit(unsigned v)
+{
+  int res = -1;
+
+  if (v >= (1U << 16U)) {
+    res += 16;
+    v >>= 16;
+  }
+  if (v >= (1U << 8U)) {
+    res += 8;
+    v >>= 8;
+  }
+  if (v >= (1U << 4U)) {
+    res += 4;
+    v >>= 4;
+  }
+  if (v >= (1U << 2U)) {
+    res += 2;
+    v >>= 2;
+  }
+  if (v >= (1U << 1U)) {
+    res += 1;
+    v >>= 1;
+  }
+  if (v >= 1)
+    res += 1;
+
+  return res;
+}
+
+/*
+ * output the alignment
+ */
+static void mips_dump_align(struct obstack *obst, int align)
+{
+  int h = highest_bit(align);
+
+  if ((1 << h) < align)
+    ++h;
+  align = (1 << h);
+
+  if (align > 1)
+    obstack_printf(obst, "\t.align %d\n", align);
+}
+
+static void dump_arith_tarval(struct obstack *obst, tarval *tv, int bytes)
+{
+  switch (bytes) {
+
+  case 1:
+    obstack_printf(obst, "0x%02x", get_tarval_sub_bits(tv, 0));
+    break;
+
+  case 2:
+    obstack_printf(obst, "0x%02x%02x", get_tarval_sub_bits(tv, 1), get_tarval_sub_bits(tv, 0));
+    break;
+
+  case 4:
+    obstack_printf(obst, "0x%02x%02x%02x%02x",
+       get_tarval_sub_bits(tv, 3), get_tarval_sub_bits(tv, 2), get_tarval_sub_bits(tv, 1), get_tarval_sub_bits(tv, 0));
+    break;
+
+  case 8:
+    obstack_printf(obst, "0x%02x%02x%02x%02x%02x%02x%02x%02x",
+       get_tarval_sub_bits(tv, 7), get_tarval_sub_bits(tv, 6), get_tarval_sub_bits(tv, 5), get_tarval_sub_bits(tv, 4),
+       get_tarval_sub_bits(tv, 3), get_tarval_sub_bits(tv, 2), get_tarval_sub_bits(tv, 1), get_tarval_sub_bits(tv, 0));
+    break;
+
+  case 10:
+  case 12:
+    break;
+
+  default:
+    fprintf(stderr, "Try to dump an tarval with %d bytes\n", bytes);
+    assert(0);
+  }
+}
+
+/*
+ * dump an arithmetic tarval
+ */
+static void mips_dump_arith_tarval(struct obstack *obst, tarval *tv, int bytes)
+{
+  switch (bytes) {
+
+  case 1:
+    obstack_printf(obst, "\t.byte\t");
+    break;
+
+  case 2:
+    obstack_printf(obst, "\t.half\t");
+    break;
+
+  case 4:
+    obstack_printf(obst, "\t.word\t");
+    break;
+
+  default:
+    fprintf(stderr, "Try to dump an tarval with %d bytes\n", bytes);
+    assert(0);
+  }
+  dump_arith_tarval(obst, tv, bytes);
+}
+
+
+/*
+ * dump an atomic value
+ */
+static void do_dump_atomic_init(struct obstack *obst, ir_node *init)
+{
+  ir_mode *mode = get_irn_mode(init);
+  int bytes     = get_mode_size_bytes(mode);
+  tarval *tv;
+
+  switch (get_irn_opcode(init)) {
+
+  case iro_Cast:
+    do_dump_atomic_init(obst, get_Cast_op(init));
+    return;
+
+  case iro_Conv:
+    do_dump_atomic_init(obst, get_Conv_op(init));
+    return;
+
+  case iro_Const:
+    tv = get_Const_tarval(init);
+
+    /* beware of old stuff */
+    assert(! mode_is_reference(mode));
+
+    /* it's a arithmetic value */
+    dump_arith_tarval(obst, tv, bytes);
+    return;
+
+  case iro_SymConst:
+    switch (get_SymConst_kind(init)) {
+    case symconst_addr_name:
+      obstack_printf(obst, "%s", get_id_str(get_SymConst_name(init)));
+      break;
+
+    case symconst_addr_ent:
+      obstack_printf(obst, "%s", get_entity_ld_name(get_SymConst_entity(init)));
+      break;
+
+    case symconst_size:
+      obstack_printf(obst, "%d", get_type_size_bytes(get_SymConst_type(init)));
+      break;
+
+    default:
+      assert(0 && "dump_atomic_init(): don't know how to init from this SymConst");
+    }
+    return;
+
+  case iro_Add:
+    do_dump_atomic_init(obst, get_Add_left(init));
+    obstack_printf(obst, " + ");
+    do_dump_atomic_init(obst, get_Add_right(init));
+    return;
+
+  case iro_Sub:
+    do_dump_atomic_init(obst, get_Sub_left(init));
+    obstack_printf(obst, " - ");
+    do_dump_atomic_init(obst, get_Sub_right(init));
+    return;
+
+  case iro_Mul:
+    do_dump_atomic_init(obst, get_Mul_left(init));
+    obstack_printf(obst, " * ");
+    do_dump_atomic_init(obst, get_Mul_right(init));
+    return;
+
+  default:
+    assert(0 && "dump_atomic_init(): unknown IR-node");
+  }
+}
+
+/*
+ * dump an atomic value
+ */
+static void dump_atomic_init(struct obstack *obst, ir_node *init)
+{
+  ir_mode *mode = get_irn_mode(init);
+  int bytes     = get_mode_size_bytes(mode);
+
+  switch (bytes) {
+
+  case 1:
+    obstack_printf(obst, "\t.byte\t");
+    break;
+
+  case 2:
+    obstack_printf(obst, "\t.half\t");
+    break;
+
+  case 4:
+    obstack_printf(obst, "\t.word\t");
+    break;
+
+  default:
+    fprintf(stderr, "Try to dump an tarval with %d bytes\n", bytes);
+    assert(0);
+  }
+
+  do_dump_atomic_init(obst, init);
+  obstack_printf(obst, "\n");
+}
+
+/************************************************************************/
+/* Routines to dump global variables                                    */
+/************************************************************************/
+
+/**
+ * Determine if an entity is a string constant
+ * @param ent The entity
+ * @return 1 if it is a string constant, 0 otherwise
+ */
+static int ent_is_string_const(entity *ent)
+{
+  int res = 0;
+  ir_type *ty;
+
+  ty = get_entity_type(ent);
+
+  /* if it's an array */
+  if (is_Array_type(ty)) {
+    ir_type *elm_ty = get_array_element_type(ty);
+
+    /* and the array's element type is primitive */
+    if (is_Primitive_type(elm_ty)) {
+      ir_mode *mode = get_type_mode(elm_ty);
+
+      /*
+       * and the mode of the element type is an int of
+       * the same size as the byte mode
+       */
+      if (mode_is_int(mode)
+        && get_mode_size_bits(mode) == get_mode_size_bits(mode_Bs))
+      {
+       int i, c, n;
+
+       n = get_compound_ent_n_values(ent);
+       for (i = 0; i < n; ++i) {
+         ir_node *irn = get_compound_ent_value(ent, i);
+         if(get_irn_opcode(irn) != iro_Const)
+           return 0;
+
+         c = (int) get_tarval_long(get_Const_tarval(irn));
+
+         if((i < n - 1 && !(isgraph(c) || isspace(c)))
+            || (i == n - 1 && c != '\0'))
+           return 0;
+       }
+
+       res = 1;
+      }
+    }
+  }
+
+  return res;
+}
+
+/**
+ * Dump a atring constant.
+ * No checks are made!!
+ * @param obst The obst to dump on.
+ * @param ent The entity to dump.
+ */
+static void dump_string_cst(struct obstack *obst, entity *ent)
+{
+  int i, n;
+
+  obstack_printf(obst, "\t.asciiz \"");
+  n = get_compound_ent_n_values(ent);
+
+  for (i = 0; i < n-1; ++i) {
+    ir_node *irn;
+    int c;
+
+    irn = get_compound_ent_value(ent, i);
+    c = (int) get_tarval_long(get_Const_tarval(irn));
+
+    switch (c) {
+    case '"' : obstack_printf(obst, "\\\""); break;
+    case '\n': obstack_printf(obst, "\\n"); break;
+    case '\r': obstack_printf(obst, "\\r"); break;
+    case '\t': obstack_printf(obst, "\\t"); break;
+    default  :
+      if (isprint(c))
+       obstack_printf(obst, "%c", c);
+      else
+       obstack_printf(obst, "%O", c);
+      break;
+    }
+  }
+  obstack_printf(obst, "\"\n");
+}
+
+struct arr_info {
+  int n_elems;
+  int visit_cnt;
+  int size;
+};
+
+/*
+ * Dumps the initialization of global variables that are not
+ * "uninitialized".
+ */
+static void dump_global(struct obstack *rdata_obstack, struct obstack *data_obstack, struct obstack *comm_obstack, entity *ent)
+{
+  ir_type *ty         = get_entity_type(ent);
+  const char *ld_name = get_entity_ld_name(ent);
+  int align, h;
+  struct obstack *obst = data_obstack;
+
+  /*
+   * FIXME: did NOT work for partly constant values
+   */
+  if (! is_Method_type(ty)) {
+    ent_variability variability = get_entity_variability(ent);
+    visibility visibility = get_entity_visibility(ent);
+
+    if (variability == variability_constant) {
+      /* a constant entity, put it on the rdata */
+      obst = rdata_obstack;
+    }
+
+    /* check, wether it is initialized, if yes create data */
+    if (variability != variability_uninitialized) {
+      if (visibility == visibility_external_visible) {
+        obstack_printf(obst, ".globl\t%s\n", ld_name);
+      }
+
+      align = get_type_alignment_bytes(ty);
+      mips_dump_align(obst, align);
+
+      obstack_printf(obst, "%s:\n", ld_name);
+
+      if (is_atomic_type(ty)) {
+       if (get_entity_visibility(ent) != visibility_external_allocated)
+          dump_atomic_init(obst, get_atomic_ent_value(ent));
+      }
+      else {
+       int i, size = 0;
+
+       if (ent_is_string_const(ent)) {
+         dump_string_cst(obst, ent);
+       }
+       else if (is_Array_type(ty)) {
+          int filler;
+
+          /* potential spare values should be already included! */
+                 for (i = 0; i < get_compound_ent_n_values(ent); ++i) {
+            entity *step = get_compound_ent_value_member(ent, i);
+            ir_type *stype = get_entity_type(step);
+
+            if (get_type_mode(stype)) {
+              int align = (get_type_alignment_bits(stype) + 7) >> 3;
+              int n     = size % align;
+
+              if (n > 0) {
+                obstack_printf(obst, "\t.space\t%d\n", align - n);
+                size += align - n;
+              }
+            }
+            dump_atomic_init(obst, get_compound_ent_value(ent, i));
+            size += get_type_size_bytes(stype);
+         }
+          filler = get_type_size_bytes(ty) - size;
+
+          if (filler > 0)
+            obstack_printf(obst, "\t.space\t%d\n", filler);
+        }
+        else if (is_compound_type(ty)) {
+          ir_node **vals;
+          int type_size, j;
+
+          /* Compound entities are NOT sorted.
+           * The sorting strategy used doesn't work for `value' compound fields nor
+           * for partially_constant entities.
+           */
+
+          /*
+           * in the worst case, every entity allocates one byte, so the type
+           * size should be equal or bigger the number of fields
+           */
+          type_size = get_type_size_bytes(ty);
+          vals      = xcalloc(type_size, sizeof(*vals));
+
+          /* collect the values and store them at the offsets */
+          for(i = 0; i < get_compound_ent_n_values(ent); ++i) {
+            int                 graph_length, aipos, offset;
+            struct arr_info     *ai;
+            int                 all_n = 1;
+            compound_graph_path *path = get_compound_ent_value_path(ent, i);
+
+            /* get the access path to the costant value */
+            graph_length = get_compound_graph_path_length(path);
+            ai = xcalloc(graph_length, sizeof(struct arr_info));
+
+            /* We wanna know how many arrays are on the path to the entity. We also have to know how
+             * many elements each array holds to calculate the offset for the entity. */
+            for (j = 0; j < graph_length; j++) {
+              entity  *step      = get_compound_graph_path_node(path, j);
+              ir_type *step_type = get_entity_type(step);
+              int     ty_size    = (get_type_size_bits(step_type) + 7) >> 3;
+              int     k, n       = 0;
+
+              if (is_Array_type(step_type))
+                for (k = 0; k < get_array_n_dimensions(step_type); k++)
+                  n += get_tarval_long(get_Const_tarval(get_array_upper_bound(step_type, k)));
+              if (n) all_n *= n;
+              ai[j].n_elems = n ? all_n + 1 : 0;
+              ai[j].visit_cnt = 0;
+              ai[j].size = ty_size;
+            }
+
+            aipos = graph_length - 1;
+            if (aipos) aipos--;
+
+            for (offset = j = 0; j < graph_length; j++) {
+              entity *step       = get_compound_graph_path_node(path, j);
+              ir_type *step_type = get_entity_type(step);
+              int ent_ofs        = get_entity_offset_bytes(step);
+              int stepsize       = 0;
+
+              /* add all positive offsets (= offsets in structs) */
+              if (ent_ofs >= 0) offset += ent_ofs;
+
+              if (j == graph_length - 1) {
+                stepsize = (get_type_size_bits(step_type) + 7) >> 3;
+
+                /* Search the next free position in vals depending on the information from above (ai). */
+                while (vals[offset]) {
+                  if (ai[aipos].visit_cnt < ai[aipos].n_elems) {
+                    offset += stepsize;
+                    ai[aipos].visit_cnt++;
+                  }
+                  else
+                    while (aipos >= 0 && ai[aipos].visit_cnt == ai[aipos].n_elems) {
+                      stepsize = ai[aipos--].size;
+                      offset  += stepsize;
+                  }
+                }
+
+                assert(aipos >= 0 && "couldn't store entity");
+                vals[offset] = get_compound_ent_value(ent, i);
+              }
+            }
+
+            free(ai);
+          }
+
+          /* now write them sorted */
+          for(i = 0; i < type_size; ) {
+            if (vals[i]) {
+              dump_atomic_init(obst, vals[i]);
+              i += (get_mode_size_bytes(get_irn_mode(vals[i])));
+            }
+            else {
+              /* a gap */
+              obstack_printf(obst, "\t.byte\t0\n");
+              ++i;
+            }
+          }
+          free(vals);
+        }
+        else {
+          assert(0 && "unsupported type");
+        }
+      }
+      obstack_printf(obst, "\n");
+    }
+    else if (visibility != visibility_external_allocated) {
+      if (visibility == visibility_local) {
+        obstack_printf(comm_obstack, "\t.local\t%s\n", ld_name);
+      }
+
+      /* calculate the alignment */
+      align = get_type_alignment_bytes(ty);
+      h = highest_bit(align);
+
+      if ((1 << h) < align)
+       ++h;
+      align = (1 << h);
+
+      if (align < 1)
+       align = 1;
+
+      obstack_printf(comm_obstack, "\t.comm\t%s,%d,%d\n", ld_name, (get_type_size_bits(ty) + 7) >> 3, align);
+    }
+  }
+}
+
+/*
+ * Dumps declarations of global variables and the initialization code.
+ */
+void mips_dump_globals(struct obstack *rdata_obstack, struct obstack *data_obstack, struct obstack *comm_obstack)
+{
+  ir_type *gt = get_glob_type();
+  int i, n = get_class_n_members(gt);
+
+  for (i = 0; i < n; i++)
+    dump_global(rdata_obstack, data_obstack, comm_obstack, get_class_member(gt, i));
+}
+
+
+static void mips_emit_stdlib_call(FILE *F, const char* name, int num) {
+       fprintf(F, "%s:\n", name);
+       fprintf(F, "\tori $v0, $zero, %d\n", num);
+       fprintf(F, "\tsyscall\n");
+       fprintf(F, "\tj $ra\n");
+       fprintf(F, "\n");
+}
+
+/**
+ * Emits a default library for spim... Hack for now...
+ */
+static void mips_emit_standard_lib(FILE* F) {
+       static int output = 0;
+       if(output)
+               return;
+       output = 1;
+
+       mips_emit_stdlib_call(F, "print_int", 1);
+       mips_emit_stdlib_call(F, "print_string", 4);
+       mips_emit_stdlib_call(F, "read_int", 5);
+       mips_emit_stdlib_call(F, "read_string", 8);
+       mips_emit_stdlib_call(F, "sbrk", 9);
+       mips_emit_stdlib_call(F, "exit", 10);
+}
+
+/************************************************************************/
+
+void mips_gen_decls(FILE *out) {
+  struct obstack rodata, data, comm;
+  int    size;
+  char   *cp;
+
+  obstack_init(&rodata);
+  obstack_init(&data);
+  obstack_init(&comm);
+
+  mips_dump_globals(&rodata, &data, &comm);
+
+  size = obstack_object_size(&data);
+  cp   = obstack_finish(&data);
+  if (size > 0) {
+    fprintf(out, "\t.data\n");
+    fwrite(cp, 1, size, out);
+  }
+
+  size = obstack_object_size(&rodata);
+  cp   = obstack_finish(&rodata);
+  if (size > 0) {
+    fprintf(out, "\t.data\n");
+    fwrite(cp, 1, size, out);
+  }
+
+  size = obstack_object_size(&comm);
+  cp   = obstack_finish(&comm);
+  if (size > 0) {
+    fprintf(out, "\t.data\n");
+    fwrite(cp, 1, size, out);
+  }
+
+  obstack_free(&rodata, NULL);
+  obstack_free(&data, NULL);
+  obstack_free(&comm, NULL);
+
+  fprintf(out, "\t.text\n");
+
+  mips_emit_standard_lib(out);
+}
diff --git a/ir/be/mips/mips_gen_decls.h b/ir/be/mips/mips_gen_decls.h
new file mode 100644 (file)
index 0000000..6335677
--- /dev/null
@@ -0,0 +1,9 @@
+#ifndef _MIPS_GEN_DECLS_H_
+#define _MIPS_GEN_DECLS_H_
+
+/**
+ * Generate all entities.
+ */
+void mips_gen_decls(FILE *out);
+
+#endif /* _MIPS_GEN_DECLS_H_ */
diff --git a/ir/be/mips/mips_map_regs.c b/ir/be/mips/mips_map_regs.c
new file mode 100644 (file)
index 0000000..5598385
--- /dev/null
@@ -0,0 +1,58 @@
+/**
+ * Register mapping for firm nodes. Stolen from bearch_firm :)
+ * $Id$
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+
+#include "mips_map_regs.h"
+#include "mips_new_nodes.h"
+
+/* Mapping to store registers in firm nodes */
+
+struct mips_irn_reg_assoc {
+       const ir_node *irn;
+       const arch_register_t *reg;
+};
+
+int mips_cmp_irn_reg_assoc(const void *a, const void *b, size_t len) {
+       const struct mips_irn_reg_assoc *x = a;
+       const struct mips_irn_reg_assoc *y = b;
+
+       return x->irn != y->irn;
+}
+
+static struct mips_irn_reg_assoc *get_irn_reg_assoc(const ir_node *irn, set *reg_set) {
+       struct mips_irn_reg_assoc templ;
+       unsigned int hash;
+
+       templ.irn = irn;
+       templ.reg = NULL;
+       hash = HASH_PTR(irn);
+
+       return set_insert(reg_set, &templ, sizeof(templ), hash);
+}
+
+void mips_set_firm_reg(ir_node *irn, const arch_register_t *reg, set *reg_set) {
+       struct mips_irn_reg_assoc *assoc = get_irn_reg_assoc(irn, reg_set);
+       assoc->reg = reg;
+}
+
+const arch_register_t *mips_get_firm_reg(const ir_node *irn, set *reg_set) {
+       struct mips_irn_reg_assoc *assoc = get_irn_reg_assoc(irn, reg_set);
+       return assoc->reg;
+}
+
+/**
+ * Translates the projnum into a "real" argument position for register
+ * requirements dependend on the predecessor.
+ */
+long mips_translate_proj_pos(const ir_node *proj) {
+       ir_node *pred = get_Proj_pred(proj);
+       long nr       = get_Proj_proj(proj);
+
+       return nr;
+}
diff --git a/ir/be/mips/mips_map_regs.h b/ir/be/mips/mips_map_regs.h
new file mode 100644 (file)
index 0000000..40edbac
--- /dev/null
@@ -0,0 +1,16 @@
+#ifndef _mips_MAP_REGS_H_
+#define _mips_MAP_REGS_H_
+
+#include "irnode.h"
+#include "set.h"
+
+#include "../bearch.h"
+#include "mips_nodes_attr.h"
+
+int  mips_cmp_irn_reg_assoc(const void *a, const void *b, size_t len);
+void mips_set_firm_reg(ir_node *irn, const arch_register_t *reg, set *reg_set);
+const arch_register_t *mips_get_firm_reg(const ir_node *irn, set *reg_set);
+
+long mips_translate_proj_pos(const ir_node *proj);
+
+#endif /* _mips_MAP_REGS_H_ */
diff --git a/ir/be/mips/mips_new_nodes.c b/ir/be/mips/mips_new_nodes.c
new file mode 100644 (file)
index 0000000..1fb0066
--- /dev/null
@@ -0,0 +1,500 @@
+/**
+ * This file implements the creation of the achitecture specific firm opcodes
+ * and the coresponding node constructors for the mips assembler irg.
+ * $Id$
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef _WIN32
+#include <malloc.h>
+#else
+#include <alloca.h>
+#endif
+
+#include <stdlib.h>
+
+#include "irprog_t.h"
+#include "irgraph_t.h"
+#include "irnode_t.h"
+#include "irmode_t.h"
+#include "ircons_t.h"
+#include "iropt_t.h"
+#include "irop.h"
+#include "firm_common_t.h"
+#include "irvrfy_t.h"
+#include "irprintf.h"
+
+#include "../bearch.h"
+
+#include "mips_nodes_attr.h"
+#include "mips_new_nodes.h"
+#include "gen_mips_regalloc_if.h"
+
+
+
+/***********************************************************************************
+ *      _                                   _       _             __
+ *     | |                                 (_)     | |           / _|
+ *   __| |_   _ _ __ ___  _ __   ___ _ __   _ _ __ | |_ ___ _ __| |_ __ _  ___ ___
+ *  / _` | | | | '_ ` _ \| '_ \ / _ \ '__| | | '_ \| __/ _ \ '__|  _/ _` |/ __/ _ \
+ * | (_| | |_| | | | | | | |_) |  __/ |    | | | | | ||  __/ |  | || (_| | (_|  __/
+ *  \__,_|\__,_|_| |_| |_| .__/ \___|_|    |_|_| |_|\__\___|_|  |_| \__,_|\___\___|
+ *                       | |
+ *                       |_|
+ ***********************************************************************************/
+
+/**
+ * Returns a string containing the names of all registers within the limited bitset
+ */
+static char *get_limited_regs(const arch_register_req_t *req, char *buf, int max) {
+       bitset_t *bs   = bitset_alloca(req->cls->n_regs);
+       char     *p    = buf;
+       int       size = 0;
+       int       i, cnt;
+
+       req->limited(NULL, bs);
+
+       for (i = 0; i < req->cls->n_regs; i++) {
+               if (bitset_is_set(bs, i)) {
+                       cnt = snprintf(p, max - size, " %s", req->cls->regs[i].name);
+                       if (cnt < 0) {
+                               fprintf(stderr, "dumper problem, exiting\n");
+                               exit(1);
+                       }
+
+                       p    += cnt;
+                       size += cnt;
+
+                       if (size >= max)
+                               break;
+               }
+       }
+
+       return buf;
+}
+
+/**
+ * Dumps the register requirements for either in or out.
+ */
+static void dump_reg_req(FILE *F, ir_node *n, const mips_register_req_t **reqs, int inout) {
+       char *dir = inout ? "out" : "in";
+       int   max = inout ? get_mips_n_res(n) : get_irn_arity(n);
+       char *buf = alloca(1024);
+       int   i;
+
+       memset(buf, 0, 1024);
+
+       if (reqs) {
+               for (i = 0; i < max; i++) {
+                       fprintf(F, "%sreq #%d =", dir, i);
+
+                       if (reqs[i]->req.type == arch_register_req_type_none) {
+                               fprintf(F, " n/a");
+                       }
+
+                       if (reqs[i]->req.type & arch_register_req_type_normal) {
+                               fprintf(F, " %s", reqs[i]->req.cls->name);
+                       }
+
+                       if (reqs[i]->req.type & arch_register_req_type_limited) {
+                               fprintf(F, " %s", get_limited_regs(&reqs[i]->req, buf, 1024));
+                       }
+
+                       if (reqs[i]->req.type & arch_register_req_type_should_be_same) {
+                               ir_fprintf(F, " same as %+F", get_irn_n(n, reqs[i]->same_pos));
+                       }
+
+                       if (reqs[i]->req.type & arch_register_req_type_should_be_different) {
+                               ir_fprintf(F, " different from %+F", get_irn_n(n, reqs[i]->different_pos));
+                       }
+
+                       fprintf(F, "\n");
+               }
+
+               fprintf(F, "\n");
+       }
+       else {
+               fprintf(F, "%sreq = N/A\n", dir);
+       }
+}
+
+
+/**
+ * Dumper interface for dumping mips nodes in vcg.
+ * @param n        the node to dump
+ * @param F        the output file
+ * @param reason   indicates which kind of information should be dumped
+ * @return 0 on success or != 0 on failure
+ */
+static int dump_node_mips(ir_node *n, FILE *F, dump_reason_t reason) {
+       ir_mode     *mode = NULL;
+       int          bad  = 0;
+       int          i;
+       mips_attr_t *attr;
+       char buf[64];
+       const mips_register_req_t **reqs;
+       const arch_register_t     **slots;
+
+       switch (reason) {
+               case dump_node_opcode_txt:
+                       fprintf(F, "%s", get_irn_opname(n));
+                       break;
+
+               case dump_node_mode_txt:
+                       mode = get_irn_mode(n);
+
+                       if (mode) {
+                               fprintf(F, "[%s]", get_mode_name(mode));
+                       }
+                       else {
+                               fprintf(F, "[?NOMODE?]");
+                       }
+                       break;
+
+               case dump_node_nodeattr_txt:
+
+                       /* TODO: dump some attributes which should show up */
+                       /* in node name in dump (e.g. consts or the like)  */
+
+                       break;
+
+               case dump_node_info_txt:
+                       attr = get_mips_attr(n);
+                       fprintf(F, "=== mips attr begin ===\n");
+
+                       /* dump IN requirements */
+                       if (get_irn_arity(n) > 0) {
+                               reqs = get_mips_in_req_all(n);
+                               dump_reg_req(F, n, reqs, 0);
+                       }
+
+                       /* dump OUT requirements */
+                       if (attr->n_res > 0) {
+                               reqs = get_mips_out_req_all(n);
+                               dump_reg_req(F, n, reqs, 1);
+                       }
+
+                       /* dump assigned registers */
+                       slots = get_mips_slots(n);
+                       if (slots && attr->n_res > 0) {
+                               for (i = 0; i < attr->n_res; i++) {
+                                       if (slots[i]) {
+                                               fprintf(F, "reg #%d = %s\n", i, slots[i]->name);
+                                       }
+                                       else {
+                                               fprintf(F, "reg #%d = n/a\n", i);
+                                       }
+                               }
+                       }
+                       fprintf(F, "\n");
+
+                       /* dump n_res */
+                       fprintf(F, "n_res = %d\n", get_mips_n_res(n));
+
+                       /* dump flags */
+                       fprintf(F, "flags =");
+                       if (attr->flags == arch_irn_flags_none) {
+                               fprintf(F, " none");
+                       }
+                       else {
+                               if (attr->flags & arch_irn_flags_dont_spill) {
+                                       fprintf(F, " unspillable");
+                               }
+                               if (attr->flags & arch_irn_flags_rematerializable) {
+                                       fprintf(F, " remat");
+                               }
+                               if (attr->flags & arch_irn_flags_ignore) {
+                                       fprintf(F, " ignore");
+                               }
+                       }
+                       fprintf(F, " (%d)\n", attr->flags);
+
+                       if(attr->modes.load_store_mode != NULL) {
+                               fprintf(F, " load_store_mode %s\n", get_mode_name(attr->modes.load_store_mode));
+                       }
+                       if(attr->stack_entity != NULL) {
+                               fprintf(F, " stack entity %s\n", get_entity_name(attr->stack_entity));
+                       }
+                       if(attr->tv != NULL) {
+                               tarval_snprintf(buf, sizeof(buf), attr->tv);
+                               fprintf(F, " tarval %s\n", buf);
+                       }
+                       if(attr->symconst_id != NULL) {
+                               fprintf(F, " symconst '%s'\n", get_id_str(attr->symconst_id));
+                       }
+
+                       fprintf(F, "=== mips attr end ===\n");
+                       /* end of: case dump_node_info_txt */
+                       break;
+       }
+
+
+       return bad;
+}
+
+
+
+/***************************************************************************************************
+ *        _   _                   _       __        _                    _   _               _
+ *       | | | |                 | |     / /       | |                  | | | |             | |
+ *   __ _| |_| |_ _ __   ___  ___| |_   / /_ _  ___| |_   _ __ ___   ___| |_| |__   ___   __| |___
+ *  / _` | __| __| '__| / __|/ _ \ __| / / _` |/ _ \ __| | '_ ` _ \ / _ \ __| '_ \ / _ \ / _` / __|
+ * | (_| | |_| |_| |    \__ \  __/ |_ / / (_| |  __/ |_  | | | | | |  __/ |_| | | | (_) | (_| \__ \
+ *  \__,_|\__|\__|_|    |___/\___|\__/_/ \__, |\___|\__| |_| |_| |_|\___|\__|_| |_|\___/ \__,_|___/
+ *                                        __/ |
+ *                                       |___/
+ ***************************************************************************************************/
+
+/**
+ * Wraps get_irn_generic_attr() as it takes no const ir_node, so we need to do a cast.
+ * Firm was made by people hating const :-(
+ */
+mips_attr_t *get_mips_attr(const ir_node *node) {
+       assert(is_mips_irn(node) && "need mips node to get attributes");
+       return (mips_attr_t *)get_irn_generic_attr((ir_node *)node);
+}
+
+/**
+ * Returns the argument register requirements of a mips node.
+ */
+const mips_register_req_t **get_mips_in_req_all(const ir_node *node) {
+       mips_attr_t *attr = get_mips_attr(node);
+       return attr->in_req;
+}
+
+/**
+ * Returns the result register requirements of an mips node.
+ */
+const mips_register_req_t **get_mips_out_req_all(const ir_node *node) {
+       mips_attr_t *attr = get_mips_attr(node);
+       return attr->out_req;
+}
+
+/**
+ * Returns the argument register requirement at position pos of an mips node.
+ */
+const mips_register_req_t *get_mips_in_req(const ir_node *node, int pos) {
+       mips_attr_t *attr = get_mips_attr(node);
+       return attr->in_req[pos];
+}
+
+/**
+ * Returns the result register requirement at position pos of an mips node.
+ */
+const mips_register_req_t *get_mips_out_req(const ir_node *node, int pos) {
+       mips_attr_t *attr = get_mips_attr(node);
+       return attr->out_req[pos];
+}
+
+/**
+ * Sets the OUT register requirements at position pos.
+ */
+void set_mips_req_out(ir_node *node, const mips_register_req_t *req, int pos) {
+       mips_attr_t *attr   = get_mips_attr(node);
+       attr->out_req[pos] = req;
+}
+
+/**
+ * Sets the IN register requirements at position pos.
+ */
+void set_mips_req_in(ir_node *node, const mips_register_req_t *req, int pos) {
+       mips_attr_t *attr  = get_mips_attr(node);
+       attr->in_req[pos] = req;
+}
+
+/**
+ * Returns the register flag of an mips node.
+ */
+arch_irn_flags_t get_mips_flags(const ir_node *node) {
+       mips_attr_t *attr = get_mips_attr(node);
+       return attr->flags;
+}
+
+/**
+ * Sets the register flag of an mips node.
+ */
+void set_mips_flags(const ir_node *node, arch_irn_flags_t flags) {
+       mips_attr_t *attr = get_mips_attr(node);
+       attr->flags      = flags;
+}
+
+/**
+ * Returns the result register slots of an mips node.
+ */
+const arch_register_t **get_mips_slots(const ir_node *node) {
+       mips_attr_t *attr = get_mips_attr(node);
+       return attr->slots;
+}
+
+/**
+ * Returns the name of the OUT register at position pos.
+ */
+const char *get_mips_out_reg_name(const ir_node *node, int pos) {
+       mips_attr_t *attr = get_mips_attr(node);
+
+       assert(is_mips_irn(node) && "Not an mips node.");
+       assert(pos < attr->n_res && "Invalid OUT position.");
+       assert(attr->slots[pos]  && "No register assigned");
+
+       return arch_register_get_name(attr->slots[pos]);
+}
+
+/**
+ * Returns the index of the OUT register at position pos within its register class.
+ */
+int get_mips_out_regnr(const ir_node *node, int pos) {
+       mips_attr_t *attr = get_mips_attr(node);
+
+       assert(is_mips_irn(node) && "Not an mips node.");
+       assert(pos < attr->n_res && "Invalid OUT position.");
+       assert(attr->slots[pos]  && "No register assigned");
+
+       return arch_register_get_index(attr->slots[pos]);
+}
+
+/**
+ * Returns the OUT register at position pos.
+ */
+const arch_register_t *get_mips_out_reg(const ir_node *node, int pos) {
+       mips_attr_t *attr = get_mips_attr(node);
+
+       assert(is_mips_irn(node) && "Not an mips node.");
+       assert(pos < attr->n_res && "Invalid OUT position.");
+       assert(attr->slots[pos]  && "No register assigned");
+
+       return attr->slots[pos];
+}
+
+/**
+ * Sets the number of results.
+ */
+void set_mips_n_res(ir_node *node, int n_res) {
+       mips_attr_t *attr = get_mips_attr(node);
+       attr->n_res      = n_res;
+}
+
+/**
+ * Returns the number of results.
+ */
+int get_mips_n_res(const ir_node *node) {
+       mips_attr_t *attr = get_mips_attr(node);
+       return attr->n_res;
+}
+
+/**
+ * Initializes the nodes attributes.
+ */
+void init_mips_attributes(ir_node *node, arch_irn_flags_t flags, const mips_register_req_t **in_reqs,
+                                                  const mips_register_req_t **out_reqs, int n_res)
+{
+       mips_attr_t *attr = get_mips_attr(node);
+
+       attr->flags = flags;
+       attr->out_req = out_reqs;
+
+       attr->n_res = n_res;
+       if(n_res) {
+               attr->slots = xcalloc(n_res, sizeof(attr->slots[0]));
+       } else {
+               attr->slots = NULL;
+       }
+       attr->in_req = in_reqs;
+}
+
+/************************************************************************
+ *  ___ _____     _     _ _
+ * |_ _|  ___|__ | | __| (_)_ __   __ _
+ *  | || |_ / _ \| |/ _` | | '_ \ / _` |
+ *  | ||  _| (_) | | (_| | | | | | (_| |
+ * |___|_|  \___/|_|\__,_|_|_| |_|\__, |
+ *                                |___/
+ ************************************************************************/
+
+// test if a tarval can be expressed in a 16bit immediate value
+static int is_tarval_16(ir_node* node)
+{
+       mips_attr_t *attr = get_mips_attr(node);
+       tarval* tv = attr->tv;
+       long val = get_tarval_long(tv);
+       if(get_mode_sign(get_irn_mode(node))) {
+               if(val < -32768 || val > 32767)
+                       return 0;
+       } else {
+               unsigned long uval = (unsigned long) val;
+               if(uval > 65536)
+                       return 0;
+       }
+
+       return 1;
+}
+
+#define MIPS_MAKE_IFOLDING_TRANSFORM(srcnode, inode, commutative)      \
+ir_node *mips_transform_##srcnode(ir_node* node)                               \
+{                                                                                                                              \
+       ir_node* op1 = get_irn_n(node, 0);                                                      \
+       ir_node* op2 = get_irn_n(node, 1);                                                      \
+       ir_node* result;                                                                                        \
+       if(op1 == NULL || op2 == NULL)                                                          \
+               return node;                                                                                    \
+                                                                                                                               \
+       if((is_mips_lli(op2) || is_mips_lui(op2)) && is_tarval_16(op2)) {       \
+               mips_attr_t *attr, *op_attr = get_mips_attr(op2);               \
+               long val = get_tarval_long(op_attr->tv);                                \
+               result = new_rd_mips_##inode(get_irn_dbg_info(node), get_irn_irg(node), get_nodes_block(node),  \
+                       op1, get_irn_mode(node));                                                       \
+               attr = get_mips_attr(result);                                                   \
+               attr->tv = new_tarval_from_long(val, get_mode_sign(get_irn_mode(node)) ? mode_Hs : mode_Hu);    \
+               return result;                                                                                  \
+       }                                                                                                                       \
+                                                                                                                               \
+       if(commutative && (is_mips_lli(op1) || is_mips_lui(op1)) && is_tarval_16(op1)) {        \
+               mips_attr_t *attr, *op_attr = get_mips_attr(op1);       \
+               long val = get_tarval_long(op_attr->tv);                                \
+               result = new_rd_mips_##inode(get_irn_dbg_info(node), get_irn_irg(node), get_nodes_block(node),  \
+                       op2, get_irn_mode(node));                                                       \
+               attr = get_mips_attr(result);                                                   \
+               attr->tv = new_tarval_from_long(val, get_mode_sign(get_irn_mode(node)) ? mode_Hs : mode_Hu);    \
+               return result;                                                                                  \
+       }                                                                                                                       \
+                                                                                                                               \
+       return node;                                                                                            \
+}
+
+MIPS_MAKE_IFOLDING_TRANSFORM(add, addi, 1);
+MIPS_MAKE_IFOLDING_TRANSFORM(and, andi, 1);
+MIPS_MAKE_IFOLDING_TRANSFORM(or, ori, 1);
+MIPS_MAKE_IFOLDING_TRANSFORM(sra, srai, 0);
+MIPS_MAKE_IFOLDING_TRANSFORM(xor, xori, 1);
+MIPS_MAKE_IFOLDING_TRANSFORM(sl, sli, 0);
+MIPS_MAKE_IFOLDING_TRANSFORM(sr, sri, 0);
+MIPS_MAKE_IFOLDING_TRANSFORM(slt, slti, 0);
+
+void mips_init_opcode_transforms() {
+       op_mips_add->ops.transform_node = mips_transform_add;
+       op_mips_and->ops.transform_node = mips_transform_and;
+       op_mips_or->ops.transform_node = mips_transform_or;
+       op_mips_sra->ops.transform_node = mips_transform_sra;
+       op_mips_xor->ops.transform_node = mips_transform_xor;
+       op_mips_sl->ops.transform_node = mips_transform_sl;
+       op_mips_sr->ops.transform_node = mips_transform_sr;
+       op_mips_slt->ops.transform_node = mips_transform_slt;
+}
+
+/***************************************************************************************
+ *                  _                            _                   _
+ *                 | |                          | |                 | |
+ *  _ __   ___   __| | ___    ___ ___  _ __  ___| |_ _ __ _   _  ___| |_ ___  _ __ ___
+ * | '_ \ / _ \ / _` |/ _ \  / __/ _ \| '_ \/ __| __| '__| | | |/ __| __/ _ \| '__/ __|
+ * | | | | (_) | (_| |  __/ | (_| (_) | | | \__ \ |_| |  | |_| | (__| || (_) | |  \__ \
+ * |_| |_|\___/ \__,_|\___|  \___\___/|_| |_|___/\__|_|   \__,_|\___|\__\___/|_|  |___/
+ *
+ ***************************************************************************************/
+
+static void mips_register_additional_opcodes(int n) {
+       /* we don't need any additional opcodes */
+}
+
+/* Include the generated constructor functions */
+#include "gen_mips_new_nodes.c.inl"
diff --git a/ir/be/mips/mips_new_nodes.h b/ir/be/mips/mips_new_nodes.h
new file mode 100644 (file)
index 0000000..d0219e8
--- /dev/null
@@ -0,0 +1,113 @@
+#ifndef _mips_NEW_NODES_H_
+#define _mips_NEW_NODES_H_
+
+/**
+ * Function prototypes for the assembler ir node constructors.
+ * $Id$
+ */
+
+#include "mips_nodes_attr.h"
+
+/***************************************************************************************************
+ *        _   _                   _       __        _                    _   _               _
+ *       | | | |                 | |     / /       | |                  | | | |             | |
+ *   __ _| |_| |_ _ __   ___  ___| |_   / /_ _  ___| |_   _ __ ___   ___| |_| |__   ___   __| |___
+ *  / _` | __| __| '__| / __|/ _ \ __| / / _` |/ _ \ __| | '_ ` _ \ / _ \ __| '_ \ / _ \ / _` / __|
+ * | (_| | |_| |_| |    \__ \  __/ |_ / / (_| |  __/ |_  | | | | | |  __/ |_| | | | (_) | (_| \__ \
+ *  \__,_|\__|\__|_|    |___/\___|\__/_/ \__, |\___|\__| |_| |_| |_|\___|\__|_| |_|\___/ \__,_|___/
+ *                                        __/ |
+ *                                       |___/
+ ***************************************************************************************************/
+
+/**
+ * Returns the attributes of an mips node.
+ */
+mips_attr_t *get_mips_attr(const ir_node *node);
+
+/**
+ * Returns the argument register requirements of an mips node.
+ */
+const mips_register_req_t **get_mips_in_req_all(const ir_node *node);
+
+/**
+ * Returns the result register requirements of an mips node.
+ */
+const mips_register_req_t **get_mips_out_req_all(const ir_node *node);
+
+/**
+ * Returns the argument register requirements of an mips node.
+ */
+const mips_register_req_t *get_mips_in_req(const ir_node *node, int pos);
+
+/**
+ * Returns the result register requirements of an mips node.
+ */
+const mips_register_req_t *get_mips_out_req(const ir_node *node, int pos);
+
+/**
+ * Sets the OUT register requirements at position pos.
+ */
+void set_mips_req_out(ir_node *node, const mips_register_req_t *req, int pos);
+
+/**
+ * Sets the IN register requirements at position pos.
+ */
+void set_mips_req_in(ir_node *node, const mips_register_req_t *req, int pos);
+
+/**
+ * Returns the register flag of an mips node.
+ */
+arch_irn_flags_t get_mips_flags(const ir_node *node);
+
+/**
+ * Sets the register flag of an mips node.
+ */
+void set_mips_flags(const ir_node *node, arch_irn_flags_t flags);
+
+/**
+ * Returns the result register slots of an mips node.
+ */
+const arch_register_t **get_mips_slots(const ir_node *node);
+
+/**
+ * Returns the name of the OUT register at position pos.
+ */
+const char *get_mips_out_reg_name(const ir_node *node, int pos);
+
+/**
+ * Returns the index of the OUT register at position pos within its register class.
+ */
+int get_mips_out_regnr(const ir_node *node, int pos);
+
+/**
+ * Returns the OUT register at position pos.
+ */
+const arch_register_t *get_mips_out_reg(const ir_node *node, int pos);
+
+/**
+ * Sets the number of results.
+ */
+void set_mips_n_res(ir_node *node, int n_res);
+
+/**
+ * Returns the number of results.
+ */
+int get_mips_n_res(const ir_node *node);
+
+
+/**
+ * Initializes the nodes attributes.
+ */
+void init_mips_attributes(ir_node *node, arch_irn_flags_t flags, const mips_register_req_t **in_reqs,
+        const mips_register_req_t **out_reqs, int n_res);
+
+/**
+ * Initilize transform ops for the mips opcodes
+ */
+void mips_init_opcode_transforms();
+
+
+/* Include the generated headers */
+#include "gen_mips_new_nodes.h"
+
+#endif /* _mips_NEW_NODES_H_ */
diff --git a/ir/be/mips/mips_nodes_attr.h b/ir/be/mips/mips_nodes_attr.h
new file mode 100644 (file)
index 0000000..fc44e3d
--- /dev/null
@@ -0,0 +1,35 @@
+#ifndef _MIPS_NODES_ATTR_H_
+#define _MIPS_NODES_ATTR_H_
+
+#include "../bearch.h"
+#include "irmode_t.h"
+
+typedef struct _mips_register_req_t {
+       const arch_register_req_t req;
+       int same_pos;        /**<< in case of "should be same" we need to remember the pos to get the irn */
+       int different_pos;   /**<< in case of "should be different" we need to remember the pos to get the irn */
+} mips_register_req_t;
+
+
+typedef struct _mips_attr_t {
+       arch_irn_flags_t flags;     /**<< indicating if spillable, rematerializeable ... etc. */
+       int              n_res;     /**<< number of results for this node */
+
+       tarval *tv;                                     /**<< contains the immediate value (if the node has any) */
+       ident *symconst_id;                     /**<< contains the ident (for la operations) */
+
+       union {
+               ir_mode *load_store_mode;       /**<< contains the mode of a load/store */
+               ir_mode *original_mode;         /**<< contains the original mode of the node */
+       } modes;
+       entity *stack_entity;           /**<< contains the entity on the stack for a load/store mode */
+       int stack_entity_offset;        /**<< contains the real stack offset for the entity */
+       int switch_default_pn;          /**< proj number of default case in switch */
+
+       const mips_register_req_t **in_req;  /**<< register requirements for arguments */
+       const mips_register_req_t **out_req; /**<< register requirements for results */
+
+       const arch_register_t **slots;       /**<< register slots for assigned registers */
+} mips_attr_t;
+
+#endif /* _mips_NODES_ATTR_H_ */
diff --git a/ir/be/mips/mips_scheduler.c b/ir/be/mips/mips_scheduler.c
new file mode 100644 (file)
index 0000000..b2fdda3
--- /dev/null
@@ -0,0 +1,188 @@
+/* Mips implementation of list scheduler selector */
+/* $Id$ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
+#include "mips_scheduler.h"
+
+#include "../besched_t.h"
+#include "../be.h"
+#include "../beabi.h"
+#include "iredges.h"
+#include "ircons.h"
+#include "gen_mips_regalloc_if.h"
+
+#include "mips_new_nodes.h"
+
+list_sched_selector_t mips_sched_selector;
+
+typedef struct {
+       const arch_env_t* arch_env;
+       pset *div_set;
+       /**
+        * This array holds an entry for each register that specifies how much cycles
+        * have to pass before we can access that register again
+        * (because mips will write the register value back in the WB phase of the pipeline)
+        */
+       int busy_registers[N_mips_general_purpose_REGS];
+       /// current block
+       ir_node* block;
+       ir_node* last_nop;
+} mips_sched_env_t;
+
+static void *mips_scheduler_init_graph(const list_sched_selector_t *vtab, const arch_env_t *arch_env, ir_graph *irg)
+{
+       mips_sched_env_t *sched_env = xmalloc(sizeof(sched_env[0]));
+       memset(sched_env, 0, sizeof(sched_env[0]));
+
+       sched_env->arch_env = arch_env;
+       sched_env->div_set = new_pset(pset_default_ptr_cmp, 4);
+
+       return sched_env;
+}
+
+static void mips_scheduler_finish_graph(void* graph_env)
+{
+       mips_sched_env_t *sched_env = (mips_sched_env_t*) graph_env;
+       del_pset(sched_env->div_set);
+}
+
+static void *mips_scheduler_init_block(void *graph_env, ir_node *block)
+{
+       mips_sched_env_t *sched_env = (mips_sched_env_t*) graph_env;
+       assert(pset_count(sched_env->div_set) == 0);
+       srand(12234);
+       // TODO later we might have blocks that don't end in a jump
+       memset(&sched_env->busy_registers, 0, sizeof(sched_env->busy_registers));
+       sched_env->block = block;
+       sched_env->last_nop = NULL;
+       return sched_env;
+}
+
+static void mips_scheduler_finish_block(void* graph_env)
+{
+       mips_sched_env_t *sched_env = (mips_sched_env_t*) graph_env;
+       // attach last nop to end node (so that firm doesn't discard it)
+       if(sched_env->last_nop != NULL) {
+               ir_node* end = get_irg_end(get_irn_irg(sched_env->block));
+       }
+       sched_env->block = NULL;
+}
+
+static int mips_scheduler_to_appear_in_schedule(void *block_env, const ir_node *irn)
+{
+       return is_mips_irn(irn) && !is_mips_zero(irn) && !is_mips_reinterpret_conv(irn) && !is_mips_fallthrough(irn);
+}
+
+static void mips_collect_mflohis(pset* set, ir_node* node) {
+       // construct a list of nodes that need to be scheduled before
+       // we are allowed to schedule another div or mul instruction
+       const ir_edge_t *edge, *edge2;
+
+       if(is_mips_div(node)) {
+               foreach_out_edge(node, edge) {
+                       const ir_node* node2 = get_edge_src_irn(edge);
+
+                       assert(is_Proj(node2));
+                       foreach_out_edge(node2, edge2) {
+                               const ir_node* node3 = get_edge_src_irn(edge2);
+                               if(is_mips_mfhi(node3) || is_mips_mflo(node3))
+                                       pset_insert_ptr(set, node3);
+                       }
+               }
+       } else if(is_mips_mult(node)) {
+               foreach_out_edge(node, edge) {
+                       const ir_node* node2 = get_edge_src_irn(edge);
+
+                       if(is_mips_mfhi(node2) || is_mips_mflo(node2))
+                               pset_insert_ptr(set, node2);
+               }
+       }
+}
+
+static int mips_scheduler_node_allowed(mips_sched_env_t *sched_env, ir_node* node)
+{
+       if(pset_count(sched_env->div_set) != 0 && (is_mips_div(node) || is_mips_mult(node))) {
+               return 0;
+       }
+
+       return 1;
+}
+
+static ir_node *mips_scheduler_select(void *block_env, pset *ready_set)
+{
+       mips_sched_env_t *sched_env = (mips_sched_env_t*) block_env;
+       const arch_env_t *arch_env = (const arch_env_t*) sched_env->arch_env;
+       ir_node *node = NULL;
+       ir_node *block = sched_env->block;
+       ir_node *condjmp = NULL;
+       ir_graph *irg = get_irn_irg(block);
+       int have_non_branch_nodes = 0;
+
+       // test all nodes in the ready set and take the first non-branch that
+       // is allowed
+       for(node = pset_first(ready_set); node != NULL; node = pset_next(ready_set)) {
+               if(arch_irn_classify(arch_env, node) == arch_irn_class_branch) {
+                       if(is_irn_forking(node))
+                               condjmp = node;
+                       continue;
+               }
+
+               have_non_branch_nodes = 1;
+
+               if(mips_scheduler_node_allowed(sched_env, node))
+               {
+                       pset_break(ready_set);
+
+                       // TODO update busy_registers
+
+                       if(is_mips_div(node) || is_mips_mult(node)) {
+                               mips_collect_mflohis(sched_env->div_set, node);
+                       } else if(is_mips_mflo(node) || is_mips_mfhi(node)) {
+                               pset_remove_ptr(sched_env->div_set, node);
+                       }
+
+                       return node;
+               }
+       }
+
+       // if we arrive here no non-branch node was found that we can emit
+
+       // return a branch if there are just branches left
+       if(!have_non_branch_nodes) {
+               // schedule conditional branches before non-conditional ones
+               if(condjmp != NULL) {
+                       return condjmp;
+               }
+               node = pset_first(ready_set);
+               assert(arch_irn_classify(arch_env, node) == arch_irn_class_branch);
+               pset_break(ready_set);
+               return node;
+       }
+
+       // emit a nop
+       node = new_rd_mips_nop(NULL, irg, block, mode_M);
+       keep_alive(node);
+       return node;
+}
+
+/**
+ * Returns the reg_pressure scheduler with to_appear_in_schedule() overloaded
+ */
+const list_sched_selector_t *mips_get_list_sched_selector(const void *self)
+{
+       memset(&mips_sched_selector, 0, sizeof(mips_sched_selector));
+       mips_sched_selector.init_graph = mips_scheduler_init_graph;
+       mips_sched_selector.init_block = mips_scheduler_init_block;
+       mips_sched_selector.select = mips_scheduler_select;
+       mips_sched_selector.to_appear_in_schedule = mips_scheduler_to_appear_in_schedule;
+       mips_sched_selector.finish_block = mips_scheduler_finish_block;
+       mips_sched_selector.finish_graph = mips_scheduler_finish_graph;
+       return &mips_sched_selector;
+}
diff --git a/ir/be/mips/mips_scheduler.h b/ir/be/mips/mips_scheduler.h
new file mode 100644 (file)
index 0000000..e16a83b
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef _MIPS_SCHEDULER_H_
+#define _MIPS_SCHEDULER_H_
+
+#include "../besched_t.h"
+
+const list_sched_selector_t *mips_get_list_sched_selector(const void *self);
+
+#endif
diff --git a/ir/be/mips/mips_spec.pl b/ir/be/mips/mips_spec.pl
new file mode 100644 (file)
index 0000000..736f018
--- /dev/null
@@ -0,0 +1,606 @@
+# Creation: 2006/02/13
+# $Id$
+# This is a template specification for the Firm-Backend
+
+# the cpu architecture (ia32, ia64, mips, sparc, ppc, ...)
+
+$arch = "mips";
+
+$comment_string = "#";
+
+# The node description is done as a perl hash initializer with the
+# following structure:
+#
+# %nodes = (
+#
+# <op-name> => {
+#   op_flags  => "N|L|C|X|I|F|Y|H|c|K",
+#   "arity"     => "0|1|2|3 ... |variable|dynamic|any",
+#   "state"     => "floats|pinned|mem_pinned|exc_pinned",
+#   "args"      => [
+#                    { "type" => "type 1", "name" => "name 1" },
+#                    { "type" => "type 2", "name" => "name 2" },
+#                    ...
+#                  ],
+#   "comment"   => "any comment for constructor",
+#   reg_req   => { in => [ "reg_class|register" ], out => [ "reg_class|register|in_rX" ] },
+#   "cmp_attr"  => "c source code for comparing node attributes",
+#   emit      => "emit code with templates",
+#   "rd_constructor" => "c source code which constructs an ir_node"
+# },
+#
+# ... # (all nodes you need to describe)
+#
+# ); # close the %nodes initializer
+
+# op_flags: flags for the operation, OPTIONAL (default is "N")
+# the op_flags correspond to the firm irop_flags:
+#   N   irop_flag_none
+#   L   irop_flag_labeled
+#   C   irop_flag_commutative
+#   X   irop_flag_cfopcode
+#   I   irop_flag_ip_cfopcode
+#   F   irop_flag_fragile
+#   Y   irop_flag_forking
+#   H   irop_flag_highlevel
+#   c   irop_flag_constlike
+#   K   irop_flag_keep
+#
+#   R   rematerializeable
+#   N   not spillable
+#   I   ignore for register allocation
+#
+# state: state of the operation, OPTIONAL (default is "floats")
+#
+# arity: arity of the operation, MUST NOT BE OMITTED
+#
+# args:  the OPTIONAL arguments of the node constructor (debug, irg and block
+#        are always the first 3 arguments and are always autmatically
+#        created)
+#        If this key is missing the following arguments will be created:
+#        for i = 1 .. arity: ir_node *op_i
+#        ir_mode *mode
+#
+# comment: OPTIONAL comment for the node constructor
+#
+# rd_constructor: for every operation there will be a
+#      new_rd_<arch>_<op-name> function with the arguments from above
+#      which creates the ir_node corresponding to the defined operation
+#      you can either put the complete source code of this function here
+#
+#      This key is OPTIONAL. If omitted, the following constructor will
+#      be created:
+#      if (!op_<arch>_<op-name>) assert(0);
+#      for i = 1 to arity
+#         set in[i] = op_i
+#      done
+#      res = new_ir_node(db, irg, block, op_<arch>_<op-name>, mode, arity, in)
+#      return res
+#
+# NOTE: rd_constructor and args are only optional if and only if arity is 0,1,2 or 3
+
+# register types:
+#   0 - no special type
+#   1 - caller save (register must be saved by the caller of a function)
+#   2 - callee save (register must be saved by the called function)
+#   4 - ignore (do not assign this register)
+# NOTE: Last entry of each class is the largest Firm-Mode a register can hold\
+%reg_classes = (
+  "general_purpose" => [
+                         { name => "zero", type => 4+2 },  # always zero
+                         { name => "at", type => 4 }, # reserved for assembler
+                         { name => "v0", type => 1 }, # first return value
+                         { name => "v1", type => 1 }, # second return value
+                         { name => "a0", type => 1 }, # first argument
+                         { name => "a1", type => 1 }, # second argument
+                         { name => "a2", type => 1 }, # third argument
+                         { name => "a3", type => 1 }, # fourth argument
+                         { name => "t0", type => 1 },
+                         { name => "t1", type => 1 },
+                         { name => "t2", type => 1 },
+                         { name => "t3", type => 1 },
+                         { name => "t4", type => 1 },
+                         { name => "t5", type => 1 },
+                         { name => "t6", type => 1 },
+                         { name => "t7", type => 1 },
+                         { name => "s0", type => 2 },
+                         { name => "s1", type => 2 },
+                         { name => "s2", type => 2 },
+                         { name => "s3", type => 2 },
+                         { name => "s4", type => 2 },
+                         { name => "s5", type => 2 },
+                         { name => "s6", type => 2 },
+                         { name => "s7", type => 2 },
+                         { name => "t8", type => 1 },
+                         { name => "t9", type => 1 },
+                         { name => "k0", type => 4 }, # reserved for OS
+                         { name => "k1", type => 4 }, # reserved for OS
+                         { name => "gp", type => 4 }, # general purpose
+                         { name => "sp", type => 4+2 }, # stack pointer
+                         { name => "fp", type => 4+2 }, # frame pointer
+                         { name => "ra", type => 2+1 }, # return address. This is also caller save, because
+                                                                                                                       # the jla instruction that is used for calls modifies
+                                                                                                                       # the ra register. It is callee save too, because at the last
+                                                                                                                       # command of a function (the ja $ra) it needs to have it's
+                                                                                                                       # old value.
+                         { mode => "mode_P" }
+                       ],
+); # %reg_classes
+
+#--------------------------------------------------#
+#                        _                         #
+#                       (_)                        #
+#  _ __   _____      __  _ _ __    ___  _ __  ___  #
+# | '_ \ / _ \ \ /\ / / | | '__|  / _ \| '_ \/ __| #
+# | | | |  __/\ V  V /  | | |    | (_) | |_) \__ \ #
+# |_| |_|\___| \_/\_/   |_|_|     \___/| .__/|___/ #
+#                                      | |         #
+#                                      |_|         #
+#--------------------------------------------------#
+
+%nodes = (
+
+#-----------------------------------------------------------------#
+#  _       _                                         _            #
+# (_)     | |                                       | |           #
+#  _ _ __ | |_ ___  __ _  ___ _ __   _ __   ___   __| | ___  ___  #
+# | | '_ \| __/ _ \/ _` |/ _ \ '__| | '_ \ / _ \ / _` |/ _ \/ __| #
+# | | | | | ||  __/ (_| |  __/ |    | | | | (_) | (_| |  __/\__ \ #
+# |_|_| |_|\__\___|\__, |\___|_|    |_| |_|\___/ \__,_|\___||___/ #
+#                   __/ |                                         #
+#                  |___/                                          #
+#-----------------------------------------------------------------#
+
+# commutative operations
+
+add => {
+  op_flags  => "C",
+  reg_req   => { in => [ "general_purpose", "general_purpose" ], out => [ "general_purpose" ] },
+  emit      => '
+       if (mode_is_signed(get_irn_mode(n)))
+2.             add %D1, %S1, %S2
+       else
+2.             addu %D1, %S1, %S2
+'
+},
+
+addi => {
+  reg_req   => { in => [ "general_purpose" ], out => [ "general_purpose" ] },
+  emit      => '
+       if (mode_is_signed(get_irn_mode(n)))
+2.             addi %D1, %S1, %C
+       else
+2.             addiu %D1, %S1, %C
+',
+  cmp_attr => 'return attr_a->tv != attr_b->tv;',
+},
+
+and => {
+  op_flags  => "C",
+  reg_req   => { in => [ "general_purpose", "general_purpose" ], out => [ "general_purpose" ] },
+  emit      => '. and %D1, %S1, %S2',
+},
+
+andi => {
+  reg_req   => { in => [ "general_purpose" ], out => [ "general_purpose" ] },
+  emit      => '. andi %D1, %S1, %C',
+  cmp_attr => 'return attr_a->tv != attr_b->tv;',
+},
+
+div => {
+  reg_req   => { in => [ "general_purpose", "general_purpose" ], out => [ "none", "none", "none", "none" ] },
+  emit      => '
+       mips_attr_t *attr = get_mips_attr(n);
+       if(attr->modes.original_mode->sign) {
+2.             div %S1, %S2
+       } else {
+2.             divu %S1, %S2
+       }
+',
+},
+
+mult => {
+  op_flags  => "C",
+  reg_req   => { in => [ "general_purpose", "general_purpose" ], out => [ "none" ] },
+  emit      => '
+       if (mode_is_signed(get_irn_mode(n)))
+2.             mult %S1, %S2
+       else
+2.             multu %S1, %S2
+'
+},
+
+nor => {
+  op_flags  => "C",
+  reg_req   => { in => [ "general_purpose", "general_purpose" ], out => [ "general_purpose" ] },
+  emit      => '. nor %D1, %S1, %S2'
+},
+
+not => {
+  reg_req   => { in => [ "general_purpose" ], out => [ "general_purpose" ] },
+  emit      => '
+  assert(get_mode_size_bits(get_irn_mode(n)) == 32);
+. nor %D1, %S1, $zero
+'
+},
+
+or => {
+  op_flags  => "C",
+  reg_req   => { in => [ "general_purpose", "general_purpose" ], out => [ "general_purpose" ] },
+  emit      => '. or %D1, %S1, %S2'
+},
+
+ori => {
+  reg_req   => { in => [ "general_purpose" ], out => [ "general_purpose" ] },
+  emit      => '. ori %D1, %S1, %C',
+  cmp_attr => 'return attr_a->tv != attr_b->tv;',
+},
+
+sl => {
+  reg_req   => { in => [ "general_purpose", "general_purpose" ], out => [ "general_purpose" ] },
+  emit      => '
+       if (mode_is_signed(get_irn_mode(n)))
+2.             sal %D1, %S1, %S2
+       else
+2.             sll %D1, %S1, %S2',
+},
+
+sli => {
+  reg_req   => { in => [ "general_purpose" ], out => [ "general_purpose" ] },
+  emit      => '
+       if (mode_is_signed(get_irn_mode(n)))
+2.             sal %D1, %S1, %C
+       else
+2.             sll %D1, %S1, %C',
+},
+
+sra => {
+  reg_req   => { in => [ "general_purpose", "general_purpose" ], out => [ "general_purpose" ] },
+  emit      => '. sra %D1, %S1, %S2',
+},
+
+srai => {
+  reg_req   => { in => [ "general_purpose" ], out => [ "general_purpose" ] },
+  emit      => '. sra %D1, %S1, %C',
+  cmp_attr => 'return attr_a->tv != attr_b->tv;',
+},
+
+sr => {
+  reg_req   => { in => [ "general_purpose", "general_purpose" ], out => [ "general_purpose" ] },
+  emit      => '
+       if (mode_is_signed(get_irn_mode(n)))
+2.             sra %D1, %S1, %S2
+       else
+2.             srl %D1, %S1, %S2
+',
+},
+
+sri => {
+  reg_req   => { in => [ "general_purpose" ], out => [ "general_purpose" ] },
+  emit      => '
+       if (mode_is_signed(get_irn_mode(n)))
+2.             sra %D1, %S1, %C
+       else
+2.             srl %D1, %S1, %C
+',
+},
+
+srlv => {
+  reg_req   => { in => [ "general_purpose", "general_purpose" ], out => [ "general_purpose" ] },
+  emit      => '. srlv %D1, %S1, %S2',
+},
+
+sllv => {
+  reg_req   => { in => [ "general_purpose", "general_purpose" ], out => [ "general_purpose" ] },
+  emit      => '. sllv %D1, %S1, %S2',
+},
+
+sub => {
+  reg_req   => { in => [ "general_purpose", "general_purpose" ], out => [ "general_purpose" ] },
+  emit      => '. sub %D1, %S1, %S2'
+},
+
+subu => {
+  reg_req   => { in => [ "general_purpose", "general_purpose" ], out => [ "general_purpose" ] },
+  emit      => '. subu %D1, %S1, %S2',
+},
+
+subuzero => {
+  reg_req      => { in => [ "general_purpose" ], out => [ "general_purpose" ] },
+  emit => '. subu %D1, $zero, %S1',
+},
+
+xor => {
+  reg_req   => { in => [ "general_purpose", "general_purpose" ], out => [ "general_purpose" ] },
+  emit      => '. xor %D1, %S1, %S2'
+},
+
+xori => {
+  reg_req   => { in => [ "general_purpose" ], out => [ "general_purpose" ] },
+  emit      => '. xori %D1, %S1, %C',
+  cmp_attr => 'return attr_a->tv != attr_b->tv;',
+},
+
+#   ____                _              _
+#  / ___|___  _ __  ___| |_ __ _ _ __ | |_ ___
+# | |   / _ \| '_ \/ __| __/ _` | '_ \| __/ __|
+# | |__| (_) | | | \__ \ || (_| | | | | |_\__ \
+#  \____\___/|_| |_|___/\__\__,_|_| |_|\__|___/
+#
+
+# load upper imediate
+lui => {
+  op_flags     => "c",
+  reg_req   => { out => [ "general_purpose" ] },
+  emit      => '. lui %D1, %C',
+  cmp_attr => 'return attr_a->tv != attr_b->tv;',
+},
+
+# load lower immediate
+lli => {
+  op_flags     => "c",
+  reg_req   => { in => [ "general_purpose" ], out => [ "general_purpose" ] },
+  emit      => '. ori %D1, %S1, %C',
+  cmp_attr => 'return attr_a->tv != attr_b->tv;',
+},
+
+la => {
+  op_flags     => "c",
+  reg_req   => { out => [ "general_purpose" ] },
+  emit      => '. la %D1, %C',
+  cmp_attr => 'return attr_a->symconst_id != attr_b->symconst_id;',
+},
+
+mflo => {
+  reg_req => { in => [ "none" ], out => [ "general_purpose" ] },
+  emit   => '. mflo %D1'
+},
+
+mfhi => {
+  reg_req => { in => [ "none" ], out => [ "general_purpose" ] },
+  emit   => '. mfhi %D1'
+},
+
+zero => {
+  reg_req => { out => [ "zero" ] },
+  emit => '',
+},
+
+#
+#  ____                       _        __  _
+# | __ ) _ __ __ _ _ __   ___| |__    / / | |_   _ _ __ ___  _ __
+# |  _ \| '__/ _` | '_ \ / __| '_ \  / /  | | | | | '_ ` _ \| '_ \
+# | |_) | | | (_| | | | | (__| | | |/ / |_| | |_| | | | | | | |_) |
+# |____/|_|  \__,_|_| |_|\___|_| |_/_/ \___/ \__,_|_| |_| |_| .__/
+#                                                           |_|
+#
+
+slt => {
+       reg_req => { in => [ "general_purpose", "general_purpose" ], out => [ "general_purpose" ] },
+       emit => '
+       if (mode_is_signed(get_irn_mode(n)))
+2.             slt %D1, %S1, %S2
+       else
+2.             sltu %D1, %S1, %S2
+',
+},
+
+slti => {
+       reg_req => { in => [ "general_purpose" ], out => [ "general_purpose" ] },
+       emit => '
+       if (mode_is_signed(get_irn_mode(n)))
+2.             slti %D1, %S1, %C
+       else
+2.             sltiu %D1, %S1, %C
+',
+  cmp_attr => 'return attr_a->tv != attr_b->tv;',
+},
+
+beq => {
+       op_flags  => "X|Y",
+       # TxT -> TxX
+       reg_req => { in => [ "general_purpose", "general_purpose" ], out => [ "in_r0", "none" ] },
+       emit => '
+       ir_node *jumpblock = mips_get_jump_block(n, 1);
+       assert(jumpblock != NULL);
+
+       lc_efprintf(arg_env, F, "\tbeq %1S, %2S, BLOCK_%d\n", n, n, get_irn_node_nr(jumpblock));
+'
+},
+
+bne => {
+       op_flags  => "X|Y",
+       # TxT -> TxX
+       reg_req => { in => [ "general_purpose", "general_purpose" ], out => [ "in_r0", "none" ] },
+       emit => '
+       ir_node *jumpblock = mips_get_jump_block(n, 1);
+       assert(jumpblock != NULL);
+
+       lc_efprintf(arg_env, F, "\tbne %1S, %2S, BLOCK_%d\n", n, n, get_irn_node_nr(jumpblock));
+'
+},
+
+bgtz => {
+       op_flags  => "X|Y",
+       # TxT -> TxX
+       reg_req => { in => [ "general_purpose" ], out => [ "in_r0", "none" ] },
+       emit => '
+       ir_node *jumpblock = mips_get_jump_block(n, 1);
+       assert(jumpblock != NULL);
+
+       lc_efprintf(arg_env, F, "\tbgtz %1S, BLOCK_%d\n", n, get_irn_node_nr(jumpblock));
+'
+},
+
+blez => {
+       op_flags  => "X|Y",
+       # TxT -> TxX
+       reg_req => { in => [ "general_purpose" ], out => [ "in_r0", "none" ] },
+       emit => '
+       ir_node *jumpblock = mips_get_jump_block(n, 1);
+       assert(jumpblock != NULL);
+
+       lc_efprintf(arg_env, F, "\tblez %1S, BLOCK_%d\n", n, get_irn_node_nr(jumpblock));
+'
+},
+
+j => {
+  op_flags => "X",
+  reg_req => { in => [ "general_purpose" ] },
+  emit => '. j %S1',
+},
+
+b => {
+  op_flags => "X",
+  # -> X
+  reg_req => { in => [ ], out => [ "none" ] },
+  emit => '
+       ir_node *jumpblock = get_irn_link(n);
+       assert(jumpblock != NULL);
+
+       lc_efprintf(arg_env, F, "\tb BLOCK_%d\t\t\t# mips_b\n", get_irn_node_nr(jumpblock));
+'
+},
+
+fallthrough => {
+  op_flags => "X",
+  # -> X
+  reg_req => { in => [ ], out => [ "none" ] },
+  emit => '. # fallthrough'
+},
+
+SwitchJump => {
+  op_flags => "X",
+  # -> X,X,...
+  reg_req => { in => [ "general_purpose" ], out => [ "none" ] },
+  emit => '. j %S1'
+},
+
+#  _                    _
+# | |    ___   __ _  __| |
+# | |   / _ \ / _` |/ _` |
+# | |__| (_) | (_| | (_| |
+# |_____\___/ \__,_|\__,_|
+#
+
+load_r => {
+  reg_req      => { in => [ "none", "general_purpose" ], out => [ "none", "none", "general_purpose" ] },
+  emit         => '
+       mips_attr_t* attr = get_mips_attr(n);
+       ir_mode *mode;
+
+       mode = attr->modes.load_store_mode;
+
+       switch (get_mode_size_bits(mode)) {
+       case 8:
+               if (mode_is_signed(mode))
+3.                     lb %D3, %C(%S2)
+               else
+3.                     lbu %D3, %C(%S2)
+               break;
+       case 16:
+               if (mode_is_signed(mode))
+3.                     lh %D3, %C(%S2)
+               else
+3.                     lhu %D3, %C(%S2)
+               break;
+       case 32:
+2.             lw %D3, %C(%S2)
+               break;
+       default:
+               assert(! "Only 8, 16 and 32 bit loads supported");
+               break;
+       }
+',
+  cmp_attr => 'return attr_a->tv != attr_b->tv || attr_a->stack_entity != attr_b->stack_entity;',
+},
+
+
+#  _                    _    ______  _
+# | |    ___   __ _  __| |  / / ___|| |_ ___  _ __ ___
+# | |   / _ \ / _` |/ _` | / /\___ \| __/ _ \| '__/ _ \
+# | |__| (_) | (_| | (_| |/ /  ___) | || (_) | | |  __/
+# |_____\___/ \__,_|\__,_/_/  |____/ \__\___/|_|  \___|
+#
+
+store_r => {
+  reg_req      => { in => [ "none", "general_purpose", "general_purpose" ], out => [ "none", "none" ] },
+  emit         => '
+       mips_attr_t* attr = get_mips_attr(n);
+       ir_mode* mode;
+
+       mode = attr->modes.load_store_mode;
+
+       switch (get_mode_size_bits(mode)) {
+       case 8:
+               if (mode_is_signed(mode))
+2.             sb %S3, %C(%S2)
+               break;
+       case 16:
+               if (mode_is_signed(mode))
+2.             sh %S3, %C(%S2)
+               break;
+       case 32:
+2.             sw %S3, %C(%S2)
+               break;
+       default:
+               assert(! "Only 8, 16 and 32 bit stores supported");
+               break;
+       }
+',
+  cmp_attr => 'return attr_a->tv != attr_b->tv;',
+},
+
+store_i => {
+  reg_req      => { in => [ "none", "none", "general_purpose" ], out => [ "none", "none" ] },
+  emit         => '
+       mips_attr_t* attr = get_mips_attr(n);
+       ir_mode *mode;
+
+       mode = attr->modes.load_store_mode;
+
+       switch (get_mode_size_bits(mode)) {
+       case 8:
+2.             sb %S3, %C
+               break;
+       case 16:
+2.             sh %S3, %C
+               break;
+       case 32:
+2.             sw %S3, %C
+               break;
+       default:
+               assert(! "Only 8, 16 and 32 bit stores supported");
+               break;
+       }
+',
+  cmp_attr => '
+       return attr_a->stack_entity != attr_b->stack_entity;
+',
+},
+
+move => {
+  reg_req   => { in => [ "general_purpose" ], out => [ "general_purpose" ] },
+  emit      => '. or %D1, $zero, %S1'
+},
+
+#
+# Conversion
+#
+
+reinterpret_conv => {
+  reg_req   => { in => [ "general_purpose" ], out => [ "in_r1" ] },
+  emit      => '. # reinterpret %S1 -> %D1',
+},
+
+#
+# Miscelaneous
+#
+
+nop => {
+  op_flags  => "K",
+  reg_req      => { in => [], out => [ "none" ] },
+  emit         => '. nop  # nop',
+},
+
+); # end of %nodes
diff --git a/ir/be/mips/mips_transform.c b/ir/be/mips/mips_transform.c
new file mode 100644 (file)
index 0000000..d5dc9c6
--- /dev/null
@@ -0,0 +1,1189 @@
+/* The codegenrator (transform FIRM into mips FIRM */
+/* $Id$ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <limits.h>
+
+#include "irnode_t.h"
+#include "irgraph_t.h"
+#include "irmode_t.h"
+#include "irgmod.h"
+#include "iredges.h"
+#include "irvrfy.h"
+#include "ircons.h"
+#include "dbginfo.h"
+#include "iropt_t.h"
+#include "debug.h"
+
+#include "../benode_t.h"
+#include "../beabi.h"
+#include "../besched.h"
+#include "../besched_t.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"
+#include "mips_util.h"
+#include "mips_emitter.h"
+
+#include "gen_mips_regalloc_if.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);\
+       }
+
+MIPS_GENBINFUNC(add);
+MIPS_GENBINFUNC(sub);
+MIPS_GENBINFUNC(div);
+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);              \
+       }
+
+MIPS_GENUNFUNC(not);
+
+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);
+}
+
+static ir_node* gen_zero_node(mips_transform_env_t *env, dbg_info *ebg, ir_graph *irg, ir_node *block)
+{
+       ir_node *zero = be_abi_get_callee_save_irn(env->cg->birg->abi, &mips_general_purpose_regs[REG_ZERO]);
+       // TODO make zero nodes work
+       //ir_node *unknown = new_rd_mips_zero(dbg, irg, block, mode);
+
+       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)
+{
+       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;
+
+       val = get_tarval_long(tv);
+       if(val == 0)
+               return gen_zero_node(env, dbg, irg, block);
+
+       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);
+
+               return lli;
+       }
+
+       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;
+
+       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;
+}
+
+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_mode* mode = get_irn_mode(pred);
+       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);
+       }
+
+       return gen_node_for_Const(env, dbg, irg, block, pred);
+}
+
+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);
+       } else {
+               block = get_nodes_block(node);
+       }
+
+       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;
+       }
+
+       // TODO
+       assert(0);
+       return NULL;
+}
+
+/**
+ * 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));
+
+       mode = get_Load_mode(node);
+       assert(mode->vector_elem == 1);
+       assert(mode->sort == irms_int_number || mode->sort == irms_reference);
+
+       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));
+
+       attr = get_mips_attr(result);
+       attr->tv = new_tarval_from_long(0, mode_Iu);
+       attr->modes.load_store_mode = mode;
+
+       return result;
+}
+
+/**
+ * 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;
+
+       ASSERT_NO_FLOAT(env->mode);
+
+       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);
+
+       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);
+       }
+       attr = get_mips_attr(result);
+       attr->tv = new_tarval_from_long(0, mode_Iu);
+       attr->modes.load_store_mode = mode;
+
+       return result;
+}
+
+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;
+
+       n = get_Proj_proj(proj);
+
+       // 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;
+
+       // 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);
+
+       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);
+       }
+
+       return proj;
+}
+
+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));
+
+       edge = get_irn_out_edge_first(node);
+       next_block = get_edge_src_irn(edge);
+
+       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);
+       }
+
+       return new_rd_mips_b(env->dbg, env->irg, env->block, mode_X);
+}
+
+static ir_node *gen_node_for_Cond_Proj(mips_transform_env_t *env, ir_node* node, int true_false)
+{
+       // 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 *result = NULL;
+       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;
+
+       n = get_Proj_proj(proj);
+       assert(n < 8 && "Only ordered comps supported");
+
+       assert(get_irn_opcode(original_cmp) == iro_Cmp);
+       op1 = get_Cmp_left(original_cmp);
+       op2 = get_Cmp_right(original_cmp);
+
+       switch(n) {
+       case pn_Cmp_False:
+               if(true_false)
+                       return NULL;
+
+               return make_jmp_or_fallthrough(env);
+
+       case pn_Cmp_Eq:
+               if(!true_false)
+                       return make_jmp_or_fallthrough(env);
+
+               condjmp = new_rd_mips_beq(dbg, irg, block, op1, op2, mode_T);
+               return new_rd_Proj(dbg, irg, block, condjmp, mode_X, 1);
+
+       case pn_Cmp_Lt:
+               if(!true_false)
+                       return make_jmp_or_fallthrough(env);
+
+               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);
+
+       case pn_Cmp_Le:
+               if(!true_false)
+                       return make_jmp_or_fallthrough(env);
+
+               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);
+
+       case pn_Cmp_Gt:
+               if(!true_false)
+                       return make_jmp_or_fallthrough(env);
+
+               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);
+
+       case pn_Cmp_Ge:
+               if(!true_false)
+                       return make_jmp_or_fallthrough(env);
+
+               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);
+
+       case pn_Cmp_Lg:
+               if(!true_false)
+                       return make_jmp_or_fallthrough(env);
+
+               condjmp = new_rd_mips_bne(dbg, irg, block, op1, op2, mode_T);
+               return new_rd_Proj(dbg, irg, block, condjmp, mode_X, 1);
+
+       case pn_Cmp_Leg:
+               if(!true_false)
+                       return NULL;
+
+               return make_jmp_or_fallthrough(env);
+
+       default:
+               assert(0);
+       }
+
+       return NULL;
+}
+
+static ir_node *gen_node_for_Proj(mips_transform_env_t *env)
+{
+       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);
+               }
+       }
+
+       return proj;
+}
+
+static ir_node *gen_node_for_Cond(mips_transform_env_t *env)
+{
+       ir_node *selector = get_Cond_selector(env->irn);
+       ir_mode *selector_mode = get_irn_mode(selector);
+       ir_node *node = env->irn;
+       dbg_info *dbg = env->dbg;
+       ir_graph *irg = env->irg;
+       ir_node *block = env->block;
+       ir_node *sub, *sltu, *minval_const, *max_const, *switchjmp;
+       ir_node *defaultproj, *defaultproj_succ;
+       ir_node *beq, *sl;
+       long pn, minval, maxval, defaultprojn;
+       const ir_edge_t *edge;
+       ir_node *zero, *two_const, *add, *la, *load, *proj;
+       ir_mode *unsigned_mode;
+       mips_attr_t *attr;
+
+       // mode_b conds are handled by gen_node_for_Proj
+       if(get_mode_sort(selector_mode) != irms_int_number)
+               return env->irn;
+
+       assert(get_mode_size_bits(selector_mode) == 32);
+
+       defaultprojn = get_Cond_defaultProj(node);
+
+       // go over all projs to find min-&maxval of the switch
+       minval = INT_MAX;
+       maxval = INT_MIN;
+       foreach_out_edge(node, edge) {
+               ir_node* proj = get_edge_src_irn(edge);
+               assert(is_Proj(proj) && "Only proj allowed at SwitchJmp");
+
+               pn = get_Proj_proj(proj);
+               if(pn == defaultprojn) {
+                       defaultproj = proj;
+                       continue;
+               }
+
+               if(pn < minval)
+                       minval = pn;
+               if(pn > maxval)
+                       maxval = pn;
+       }
+       assert(defaultproj != NULL);
+
+       // subtract minval from the switch value
+
+       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);
+       } else {
+               sub = selector;
+       }
+
+       // compare if we're above maxval-minval or below zero.
+       // we can do this with 1 compare because we use unsigned mode
+       unsigned_mode = new_ir_mode(get_mode_name(selector_mode),
+                       get_mode_sort(selector_mode), get_mode_size_bits(selector_mode),
+                       0, get_mode_arithmetic(selector_mode), get_mode_modulo_shift(selector_mode));
+
+       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);
+
+       zero = gen_zero_node(env, dbg, irg, block);
+       beq = new_rd_mips_beq(dbg, irg, block, sltu, zero, mode_T);
+
+       // attach defaultproj to beq now
+       set_irn_n(defaultproj, 0, beq);
+       set_Proj_proj(defaultproj, 1);
+
+       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);
+
+       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);
+       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);
+       attr = get_mips_attr(switchjmp);
+       attr->switch_default_pn = defaultprojn;
+
+       edge = get_irn_out_edge_first(defaultproj);
+       defaultproj_succ = get_edge_src_irn(edge);
+       attr->symconst_id = new_id_from_str(mips_get_block_label(defaultproj_succ));
+
+       attr = get_mips_attr(la);
+       attr->symconst_id = new_id_from_str(mips_get_jumptbl_label(switchjmp));
+
+       return switchjmp;
+}
+
+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_general_purpose_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;
+
+       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);
+
+       return value_proj;
+}
+
+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;
+
+       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);
+
+       return result;
+}
+
+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;
+
+       pred = get_Conv_op(node);
+       srcmode = get_irn_mode(pred);
+       destmode = get_irn_mode(node);
+
+       dst_size = get_mode_size_bits(destmode);
+       src_size = get_mode_size_bits(srcmode);
+
+       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);
+       }
+       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);
+               }
+       } else {
+               if(src_size == 8) {
+                       return create_conv_and(env, 0xff);
+               } else if(src_size == 16) {
+                       return create_conv_and(env, 0xffff);
+               }
+       }
+
+       assert(0);
+       return NULL;
+}
+
+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)
+{
+       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");
+               }
+       }
+
+       return div;
+}
+
+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_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_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_node_for_Mul(mips_transform_env_t *env) {
+       ir_node *node = env->irn;
+       ir_node *mul;
+       ir_node *mflo;
+       ir_node *op1, *op2;
+
+       op1 = get_Mul_left(node);
+       op2 = get_Mul_right(node);
+
+       assert(get_mode_size_bits(env->mode) == 32);
+       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);
+
+       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);
+
+       return xor;
+}
+
+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);
+
+       return or;
+}
+
+static ir_node *gen_node_for_Unknown(mips_transform_env_t *env)
+{
+       return gen_zero_node(env, env->dbg, env->irg, env->block);
+}
+
+/*
+ * lower a copyB into standard Firm assembler :-)
+ */
+ir_node *gen_code_for_CopyB(ir_node *block, ir_node *node) {
+       ir_node *cnt, *sub;
+       ir_node *dst = get_CopyB_dst(node);
+       ir_node *src = get_CopyB_src(node);
+       ir_type *type = get_CopyB_type(node);
+       ir_node *mem = get_CopyB_mem(node);
+       ir_node *mm[4];
+       ir_node *result = NULL;
+       int size = get_type_size_bytes(type);
+       dbg_info *dbg = get_irn_dbg_info(node);
+       ir_graph *irg = get_irn_irg(block);
+       mips_attr_t *attr;
+       int i, n;
+
+       if (size > 16) {
+               ir_node     *phi, *projT, *projF, *cmp, *proj, *cond, *jmp, *in[2];
+               ir_node     *new_bl, *src_phi, *dst_phi, *mem_phi, *add;
+               ir_mode     *p_mode = get_irn_mode(src);
+               ir_node     *ld[4];
+
+               /* build the control loop */
+               in[0] = in[1] = new_r_Unknown(irg, mode_X);
+
+               new_bl = new_r_Block(irg, 2, in);
+
+               in[0] = cnt = new_Const_long(mode_Is, (size >> 4));
+        in[1] = new_r_Unknown(irg, mode_Is);
+               phi   = new_r_Phi(irg, new_bl, 2, in, mode_Is);
+
+               sub = new_rd_Sub(dbg, irg, new_bl, phi, new_Const_long(mode_Is, -1), mode_Is);
+               set_Phi_pred(phi, 1, sub);
+
+               cmp = new_rd_Cmp(dbg, irg, new_bl, sub, new_Const_long(mode_Is, 0));
+               proj = new_r_Proj(irg, new_bl, cmp, mode_b, pn_Cmp_Lg);
+               cond = new_rd_Cond(dbg, irg, new_bl, proj);
+
+               projT = new_r_Proj(irg, new_bl, cond, mode_X, pn_Cond_true);
+               projF = new_r_Proj(irg, new_bl, cond, mode_X, pn_Cond_false);
+
+               jmp = get_Block_cfgpred(block, 0);
+               set_Block_cfgpred(block, 0, projF);
+
+               set_Block_cfgpred(new_bl, 0, jmp);
+               set_Block_cfgpred(new_bl, 1, projT);
+
+               size &= 0xF;
+
+               /* build the copy */
+               in[0]   = src;
+        in[1]   = new_r_Unknown(irg, p_mode);
+               src_phi = new_r_Phi(irg, new_bl, 2, in, p_mode);
+
+               in[0]   = dst;
+               dst_phi = new_r_Phi(irg, new_bl, 2, in, p_mode);
+
+               add = new_rd_Add(dbg, irg, new_bl, src_phi, new_Const_long(mode_Is, 16), p_mode);
+               set_Phi_pred(src_phi, 1, add);
+               add = new_rd_Add(dbg, irg, new_bl, dst_phi, new_Const_long(mode_Is, 16), p_mode);
+               set_Phi_pred(dst_phi, 1, add);
+
+               in[0]   = mem;
+        in[1]   = new_r_Unknown(irg, mode_M);
+               mem_phi = new_r_Phi(irg, new_bl, 2, in, mode_M);
+
+               src = src_phi;
+               dst = dst_phi;
+
+               /* create 4 parallel loads */
+               for (i = 0; i < 4; ++i) {
+                       ir_node *load;
+
+                       load = new_rd_mips_load_r(dbg, irg, 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);
+
+                       ld[i] = new_rd_Proj(dbg, irg, new_bl, load, mode_Iu, pn_Load_res);
+               }
+
+               /* create 4 parallel stores */
+               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);
+                       attr = get_mips_attr(store);
+                       attr->modes.load_store_mode = mode_Iu;
+                       attr->tv = new_tarval_from_long(i * 4, mode_Iu);
+
+                       mm[i] = new_rd_Proj(dbg, irg, new_bl, store, mode_M, pn_Store_M);
+               }
+               mem = new_r_Sync(irg, new_bl, 4, mm);
+               result = mem;
+               set_Phi_pred(mem_phi, 1, mem);
+       }
+
+       // output store/loads manually
+       n = 0;
+       for(i = size; i > 0; ) {
+               ir_mode *mode;
+               ir_node *load, *store, *projv;
+               int offset = size - i;
+               if(i >= 4) {
+                       mode = mode_Iu;
+                       i -= 4;
+               } else if(i >= 2) {
+                       mode = mode_Hu;
+                       i -= 2;
+               } else {
+                       mode = mode_Bu;
+                       i -= 1;
+               }
+
+               load = new_rd_mips_load_r(dbg, irg, 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);
+               attr = get_mips_attr(store);
+               attr->modes.load_store_mode = mode;
+               attr->tv = new_tarval_from_long(offset, mode_Iu);
+
+               mm[n] = new_rd_Proj(dbg, irg, block, store, mode_M, pn_Store_M);
+               n++;
+       }
+
+       if(n > 0) {
+               result = new_r_Sync(irg, block, n, mm);
+       } else if(n == 1) {
+               result = mm[0];
+       }
+
+       return result;
+}
+
+static void mips_fix_CopyB_Proj(mips_transform_env_t* env) {
+       ir_node *node = env->irn;
+       long n = get_Proj_proj(node);
+
+       if(n == pn_CopyB_M_except) {
+               assert(0);
+       } 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);
+       }
+}
+
+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;
+
+       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);
+
+       if (sched_point) {
+               sched_add_after(sched_point, store);
+               sched_add_after(store, proj);
+
+               sched_remove(node);
+       }
+
+       exchange(node, proj);
+}
+
+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 *nomem = new_rd_NoMem(env->irg);
+       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);
+       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;
+
+       proj = new_rd_Proj(env->dbg, env->irg, env->block, load, mode, pn_Load_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);
+
+       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)
+{
+       ir_node *node = env->irn;
+       ir_node *op1, *op2;
+       ir_node *add;
+       const arch_register_t *reg;
+
+       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);
+
+       /* 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);
+
+       return add;
+}
+
+/*********************************************************
+ *                  _             _      _
+ *                 (_)           | |    (_)
+ *  _ __ ___   __ _ _ _ __     __| |_ __ ___   _____ _ __
+ * | '_ ` _ \ / _` | | '_ \   / _` | '__| \ \ / / _ \ '__|
+ * | | | | | | (_| | | | | | | (_| | |  | |\ V /  __/ |
+ * |_| |_| |_|\__,_|_|_| |_|  \__,_|_|  |_| \_/ \___|_|
+ *
+ *********************************************************/
+
+
+/**
+ * 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;
+       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"));
+       }
+}
+
+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;
+       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);
+
+               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);
+               }
+       }
+}
+
+/**
+ * Calls the transform functions for Spill and Reload.
+ */
+void mips_after_ra_walker(ir_node *node, void *env) {
+       mips_code_gen_t *cg = env;
+       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;
+       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)) {
+               mips_transform_Spill(&tenv);
+       }
+}
diff --git a/ir/be/mips/mips_transform.h b/ir/be/mips/mips_transform.h
new file mode 100644 (file)
index 0000000..2fef391
--- /dev/null
@@ -0,0 +1,18 @@
+#ifndef _MIPS_TRANSFORM_H_
+#define _MIPS_TRANSFORM_H_
+
+/**
+ * Create Firm assembler for a copyB node.
+ *
+ * @param blk   the block where to place the code
+ * @param node  the copyB node to lower
+ *
+ * @return the memory from the lowered CopyB
+ */
+ir_node *gen_code_for_CopyB(ir_node *blk, ir_node *node);
+
+void mips_pre_transform_node(ir_node *node, void *env);
+void mips_transform_node(ir_node *node, void *env);
+void mips_after_ra_walker(ir_node *node, void *env);
+
+#endif /* _MIPS_TRANSFORM_H_ */
diff --git a/ir/be/mips/mips_util.h b/ir/be/mips/mips_util.h
new file mode 100644 (file)
index 0000000..6c076af
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef _MIPS_UTIL_H_
+#define _MIPS_UTIL_H_
+
+#define ASSERT_NO_FLOAT(mode) { assert(  (!mode_is_float(mode)) && "floating point not supported (yet)"); }
+
+#endif