Added arm backend from BE praktikum
authorMichael Beck <beck@ipd.info.uni-karlsruhe.de>
Mon, 27 Mar 2006 11:54:07 +0000 (11:54 +0000)
committerMichael Beck <beck@ipd.info.uni-karlsruhe.de>
Mon, 27 Mar 2006 11:54:07 +0000 (11:54 +0000)
15 files changed:
ir/be/arm/arm_emitter.c [new file with mode: 0644]
ir/be/arm/arm_emitter.h [new file with mode: 0644]
ir/be/arm/arm_gen_decls.c [new file with mode: 0644]
ir/be/arm/arm_gen_decls.h [new file with mode: 0644]
ir/be/arm/arm_map_regs.c [new file with mode: 0644]
ir/be/arm/arm_map_regs.h [new file with mode: 0644]
ir/be/arm/arm_new_nodes.c [new file with mode: 0644]
ir/be/arm/arm_new_nodes.h [new file with mode: 0644]
ir/be/arm/arm_nodes_attr.h [new file with mode: 0644]
ir/be/arm/arm_spec.pl [new file with mode: 0644]
ir/be/arm/arm_transform.c [new file with mode: 0644]
ir/be/arm/arm_transform.h [new file with mode: 0644]
ir/be/arm/bearch_arm.c [new file with mode: 0644]
ir/be/arm/bearch_arm.h [new file with mode: 0644]
ir/be/arm/bearch_arm_t.h [new file with mode: 0644]

diff --git a/ir/be/arm/arm_emitter.c b/ir/be/arm/arm_emitter.c
new file mode 100644 (file)
index 0000000..787ed0c
--- /dev/null
@@ -0,0 +1,844 @@
+/* arm 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 "irprog_t.h"
+#include "irargs_t.h"
+
+#include "../besched.h"
+
+#include "arm_emitter.h"
+#include "gen_arm_emitter.h"
+#include "arm_nodes_attr.h"
+#include "arm_new_nodes.h"
+#include "arm_map_regs.h"
+#include "gen_arm_regalloc_if.h"
+
+#include "../benode_t.h"
+
+#define SNPRINTF_BUF_LEN 128
+
+static const arch_env_t *arch_env = NULL;
+
+
+/*************************************************************
+ *             _       _    __   _          _
+ *            (_)     | |  / _| | |        | |
+ *  _ __  _ __ _ _ __ | |_| |_  | |__   ___| |_ __   ___ _ __
+ * | '_ \| '__| | '_ \| __|  _| | '_ \ / _ \ | '_ \ / _ \ '__|
+ * | |_) | |  | | | | | |_| |   | | | |  __/ | |_) |  __/ |
+ * | .__/|_|  |_|_| |_|\__|_|   |_| |_|\___|_| .__/ \___|_|
+ * | |                                       | |
+ * |_|                                       |_|
+ *************************************************************/
+
+int is_immediate_node(ir_node *irn) {
+       if (is_arm_Add_i(irn) || is_arm_Sub_i(irn))
+               return 1;
+       if (is_arm_Shr_i(irn) || is_arm_Shr_i(irn) || is_arm_Shl_i(irn))
+               return 1;
+       if (is_arm_And_i(irn) || is_arm_Or_i(irn) || is_arm_Eor_i(irn))
+               return 1;
+       if (is_arm_Or_Shl_i(irn))
+               return 1;
+       return 0;
+}
+
+/**
+ * Return a const or symconst as string.
+ */
+static const char *node_const_to_str(ir_node *n) {
+       char buffer[SNPRINTF_BUF_LEN];
+       ir_mode *mode = get_irn_mode(n);
+
+       if ( is_immediate_node(n) ) {
+               tarval *tv = get_arm_value(n);
+               long longvalue = get_tarval_long(get_arm_value(n));
+               char *str;
+               assert(longvalue < 0x1000 && "constant doesn't fit in shifter_operand");
+               snprintf(buffer, SNPRINTF_BUF_LEN - 1, "#%ld << %ld", longvalue & 0xff, (longvalue >> 8) << 1 );
+               str = xmalloc(strlen(buffer) * sizeof(char));
+               strcpy(str, buffer);
+               return str;
+       }
+       if ( is_arm_Const(n) || is_arm_Const_Neg(n) ) {
+               tarval *tv = get_arm_value(n);
+               if ( mode_is_int(get_tarval_mode(tv)) ) {
+                       long longvalue = get_tarval_long(get_arm_value(n));
+                       char *str;
+                       assert(longvalue < 0x1000 && "constant doesn't fit in shifter_operand");
+                       snprintf(buffer, SNPRINTF_BUF_LEN - 1, "#%ld << %ld", longvalue & 0xff, (longvalue >> 8) << 1 );
+                       str = xmalloc(strlen(buffer) * sizeof(char));
+                       strcpy(str, buffer);
+                       return str;
+               } else {
+                       return "found something else in arm_const";
+               }
+       } else if ( is_arm_SymConst(n) ) {
+               return get_arm_symconst_label(n);
+       } else {
+               assert( 0 && "das ist gar keine Konstante");
+               return NULL;
+       }
+
+}
+
+/**
+ * Returns node's offset as string.
+ */
+static char *node_offset_to_str(ir_node *n) {
+       char buffer[SNPRINTF_BUF_LEN];
+       char *result;
+       int offset = 0;
+       ir_op *irn_op = get_irn_op(n);
+       if (irn_op == op_be_StackParam) {
+               entity *ent = be_get_frame_entity(n);
+               offset = get_entity_offset_bytes(ent);
+       } else if (irn_op==op_be_Reload || irn_op==op_be_Spill) {
+               entity * ent = be_get_spill_entity(n);
+               offset = get_entity_offset_bytes(ent);
+       } else if (irn_op==op_be_IncSP) {
+               int offs = be_get_IncSP_offset(n);
+               be_stack_dir_t dir  = be_get_IncSP_direction(n);
+               offset = (dir == be_stack_dir_expand) ? -offs : offs;
+       } else {
+               return "node_offset_to_str will fuer diesen Knotentyp noch implementiert werden";
+       }
+       snprintf(buffer, SNPRINTF_BUF_LEN, "%d", offset);
+       result = xmalloc(sizeof(char)*(strlen(buffer) + 1));
+       strcpy(result, buffer);
+       return result;
+}
+
+/* We always pass the ir_node which is a pointer. */
+static int arm_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(const 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);
+
+       /* ONLY TEMPORARY WORK-AROUND */
+//     if (!reg) {
+//             printf("FIXME\n");
+//             reg = &arm_general_purpose_regs[REG_MURX];
+//     }
+
+       assert(reg && "no in register found");
+       return reg;
+}
+
+/**
+ * Returns the register at out position pos.
+ */
+static const arch_register_t *get_out_reg(const ir_node *irn, int pos) {
+       ir_node                *proj;
+       const arch_register_t  *reg = NULL;
+
+       assert(get_irn_n_edges(irn) > pos && "Invalid OUT position");
+
+       /* 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_arm_irn(irn)) {
+               reg = get_arm_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_arm_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_arm_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 arm_get_reg_name(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;
+       int         nr = occ->width - 1;
+
+       if (!X)
+               return lc_appendable_snadd(app, "(null)", 6);
+
+       if (occ->conversion == 'S') {
+               buf = get_arm_reg_name(X, nr, 1);
+       }
+       else { /* 'D' */
+               buf = get_arm_reg_name(X, nr, 0);
+       }
+
+       lc_appendable_chadd(app, '%');
+       return lc_appendable_snadd(app, buf, strlen(buf));
+}
+
+/**
+ * Returns the tarval or offset of an arm node as a string.
+ */
+static int arm_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_appendable_snadd(app, "(null)", 6);
+
+       if (occ->conversion == 'C') {
+               buf = node_const_to_str(X);
+       }
+       else { /* 'O' */
+               buf = node_offset_to_str(X);
+       }
+
+       return lc_appendable_snadd(app, buf, strlen(buf));
+}
+
+/**
+ * Determines the SSE suffix depending on the mode.
+ */
+static int arm_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_appendable_snadd(app, "(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 arm printf arg environment.
+ * We use the firm environment with some additional handlers.
+ */
+const lc_arg_env_t *arm_get_arg_env(void) {
+       static lc_arg_env_t *env = NULL;
+
+       static const lc_arg_handler_t arm_reg_handler   = { arm_get_arg_type, arm_get_reg_name };
+       static const lc_arg_handler_t arm_const_handler = { arm_get_arg_type, arm_const_to_str };
+       static const lc_arg_handler_t arm_mode_handler  = { arm_get_arg_type, arm_get_mode_suffix };
+
+       if(env == NULL) {
+               /* extend the firm printer */
+               env = firm_get_arg_env();
+                       //lc_arg_new_env();
+
+               lc_arg_register(env, "arm:sreg", 'S', &arm_reg_handler);
+               lc_arg_register(env, "arm:dreg", 'D', &arm_reg_handler);
+               lc_arg_register(env, "arm:cnst", 'C', &arm_const_handler);
+               lc_arg_register(env, "arm:offs", 'O', &arm_const_handler);
+               lc_arg_register(env, "arm:mode", 'M', &arm_mode_handler);
+       }
+
+       return env;
+}
+
+/**
+ * Formated print of commands and comments.
+ */
+static void arm_fprintf_format(FILE *F, char *cmd_buf, char *cmnt_buf, ir_node *irn) {
+       lc_efprintf(arm_get_arg_env(), F, "\t%-35s %-60s /* %+F */\n", cmd_buf, cmnt_buf, irn);
+}
+
+/*
+ * 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;
+}
+
+/************************************************************************/
+/* emit_arm                                                             */
+/************************************************************************/
+
+static void emit_arm_SymConst(ir_node *irn, void *env) {
+       arm_emit_env_t *emit_env = env;
+       FILE *out = emit_env->out;
+       char buffer1[SNPRINTF_BUF_LEN];
+       char *skip_label = get_unique_label(buffer1, SNPRINTF_BUF_LEN, ".L");
+       char buffer2[SNPRINTF_BUF_LEN];
+       char *indi_label = get_unique_label(buffer2, SNPRINTF_BUF_LEN, ".L");
+       fprintf( out, "\tB %s\t\t\t\t\t/* start of indirect SymConst */\n", skip_label );
+       fprintf( out, "\t.align 2\n" );
+       fprintf( out, "%s:\n", indi_label );
+       lc_efprintf(arm_get_arg_env(), out, "\t.word\t%C\n", irn);
+       fprintf( out, "\t.align 2\n" );
+       fprintf( out, "%s:\n", skip_label );
+       lc_efprintf(arm_get_arg_env(), out, "\tLDR %1D, %s\t\t\t/* end of indirect SymConst */\n", irn, indi_label);
+}
+
+static void emit_arm_CondJmp(ir_node *irn, void *env) {
+       arm_emit_env_t *emit_env = env;
+       FILE *out = emit_env->out;
+       const ir_edge_t *edge;
+       ir_node *true_block = NULL;
+       ir_node *false_block = NULL;
+       ir_node *op1 = get_irn_n(irn, 0);
+       ir_mode *opmode = get_irn_mode(op1);
+       char *suffix;
+       int proj_num = get_arm_proj_num(irn);
+       char cmd_buf[SNPRINTF_BUF_LEN], cmnt_buf[SNPRINTF_BUF_LEN];
+
+
+       foreach_out_edge(irn, edge) {
+               ir_node* proj = get_edge_src_irn(edge);
+               long nr = get_Proj_proj(proj);
+               ir_node *block = get_irn_link(proj);
+               if ( nr == pn_Cond_true) {
+                       true_block = block;
+               } else if (nr == pn_Cond_false) {
+                       false_block = block;
+               } else {
+                       assert(0 && "tertium non datur! (CondJmp)");
+               }
+       }
+
+       if (proj_num == pn_Cmp_False) {
+               fprintf(out, "\tB BLOCK_%d\t\t\t/* false case */\n", get_irn_node_nr(false_block));
+       } else if (proj_num == pn_Cmp_True) {
+               fprintf(out, "\tB BLOCK_%d\t\t\t/* true case */\n", get_irn_node_nr(true_block));
+       } else {
+               if (mode_is_float(opmode)) {
+                       suffix = "ICHWILLIMPLEMENTIERTWERDEN";
+
+                       lc_esnprintf(arm_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "FCMP %1S, %2S", irn, irn);
+                       lc_esnprintf(arm_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "/* Compare(%1S, %2S) -> FCPSR */", irn, irn );
+                       arm_fprintf_format(out, cmd_buf, cmnt_buf, irn);
+
+                       lc_esnprintf(arm_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "FMSTAT", irn, irn);
+                       lc_esnprintf(arm_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "/* FCSPR -> CPSR */");
+                       arm_fprintf_format(out, cmd_buf, cmnt_buf, irn);
+
+                       lc_esnprintf(arm_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "B%s BLOCK_%d", suffix, get_irn_node_nr(true_block));
+                       lc_esnprintf(arm_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "/* true case */");
+                       arm_fprintf_format(out, cmd_buf, cmnt_buf, irn);
+
+                       lc_esnprintf(arm_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "B BLOCK_%d", get_irn_node_nr(false_block));
+                       lc_esnprintf(arm_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "/* false case */");
+                       arm_fprintf_format(out, cmd_buf, cmnt_buf, irn);
+               } else {
+                       switch(proj_num) {
+                               case pn_Cmp_Eq:  suffix = "EQ"; break;
+                               case pn_Cmp_Lt:  suffix = "LT"; break;
+                               case pn_Cmp_Le:  suffix = "LE"; break;
+                               case pn_Cmp_Gt:  suffix = "GT"; break;
+                               case pn_Cmp_Ge:  suffix = "GE"; break;
+                               case pn_Cmp_Lg:  suffix = "NE"; break;
+                               case pn_Cmp_Leg: suffix = "AL"; break;
+                       default: assert(0 && "komische Dinge geschehen");
+                       }
+
+                       lc_esnprintf(arm_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "CMP %1S, %2S", irn, irn);
+                       lc_esnprintf(arm_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "/* Compare(%1S, %2S) -> CPSR */", irn, irn );
+                       arm_fprintf_format(out, cmd_buf, cmnt_buf, irn);
+
+                       lc_esnprintf(arm_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "B%s BLOCK_%d", suffix, get_irn_node_nr(true_block));
+                       lc_esnprintf(arm_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "/* true case */");
+                       arm_fprintf_format(out, cmd_buf, cmnt_buf, irn);
+
+                       lc_esnprintf(arm_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "B BLOCK_%d", get_irn_node_nr(false_block));
+                       lc_esnprintf(arm_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "/* false case */");
+                       arm_fprintf_format(out, cmd_buf, cmnt_buf, irn);
+               }
+       }
+}
+
+static void emit_arm_CopyB(ir_node *irn, void *env) {
+       arm_emit_env_t *emit_env = env;
+       FILE *out = emit_env->out;
+       char cmd_buf[SNPRINTF_BUF_LEN], cmnt_buf[SNPRINTF_BUF_LEN];
+       unsigned int size = get_tarval_long(get_arm_value(irn));
+       const lc_arg_env_t *arg_env = arm_get_arg_env();
+
+       lc_esnprintf(arg_env, cmnt_buf, SNPRINTF_BUF_LEN, "/* MemCopy (%2S)->(%1S) [%d bytes], Use %3S, %4S, %5S and %%r12 */", irn, irn, size, irn, irn, irn);
+
+       assert ( size > 0 && "CopyB needs size > 0" );
+       if (size & 3)
+               size += 4;
+       size >>= 2;
+       switch(size & 3) {
+       case 0:
+               break;
+       case 1:
+               lc_esnprintf(arg_env, cmd_buf, SNPRINTF_BUF_LEN, "LDR %%r12, [%2S, #0]!", irn);
+               arm_fprintf_format(out, cmd_buf, cmnt_buf, irn);
+               lc_esnprintf(arg_env, cmd_buf, SNPRINTF_BUF_LEN, "STR  %%r12, [%1S, #0]!", irn);
+               arm_fprintf_format(out, cmd_buf, cmnt_buf, irn);
+               break;
+       case 2:
+               lc_esnprintf(arg_env, cmd_buf, SNPRINTF_BUF_LEN, "LDMIA %2S!, {%%r12, %3S}", irn, irn);
+               arm_fprintf_format(out, cmd_buf, cmnt_buf, irn);
+               lc_esnprintf(arg_env, cmd_buf, SNPRINTF_BUF_LEN, "STMIA %1S!, {%%r12, %3S}", irn, irn);
+               arm_fprintf_format(out, cmd_buf, cmnt_buf, irn);
+               break;
+       case 3:
+               lc_esnprintf(arg_env, cmd_buf, SNPRINTF_BUF_LEN, "LDMIA %2S!, {%%r12, %3S, %4S}", irn, irn, irn);
+               arm_fprintf_format(out, cmd_buf, cmnt_buf, irn);
+               lc_esnprintf(arg_env, cmd_buf, SNPRINTF_BUF_LEN, "STMIA %1S!, {%%r12, %3S, %4S}", irn, irn, irn);
+               arm_fprintf_format(out, cmd_buf, cmnt_buf, irn);
+               break;
+       }
+       size >>= 2;
+       while (size) {
+               lc_esnprintf(arg_env, cmd_buf, SNPRINTF_BUF_LEN, "LDMIA %2S!, {%%r12, %3S, %4S, %5S}", irn, irn, irn, irn);
+               arm_fprintf_format(out, cmd_buf, cmnt_buf, irn);
+               lc_esnprintf(arg_env, cmd_buf, SNPRINTF_BUF_LEN, "STMIA %1S!, {%%r12, %3S, %4S, %5S}", irn, irn, irn, irn);
+               arm_fprintf_format(out, cmd_buf, cmnt_buf, irn);
+               --size;
+       }
+}
+
+static void emit_arm_SwitchJmp(ir_node *irn, void *env) {
+       char cmd_buf[SNPRINTF_BUF_LEN], cmnt_buf[SNPRINTF_BUF_LEN];
+       const ir_edge_t    *edge;
+       ir_node            *proj;
+       arm_emit_env_t *emit_env = env;
+       FILE *out = emit_env->out;
+       int i;
+       ir_node **projs;
+       int n_projs;
+       int block_nr;
+       int default_block_num;
+
+       block_nr = get_irn_node_nr(irn);
+       n_projs = get_arm_n_projs(irn);
+
+       projs = xcalloc(n_projs , sizeof(ir_node*));
+
+       foreach_out_edge(irn, edge) {
+               proj = get_edge_src_irn(edge);
+               assert(is_Proj(proj) && "Only proj allowed at SwitchJmp");
+
+               if (get_Proj_proj(proj) == get_arm_default_proj_num(irn))
+                       default_block_num = get_irn_node_nr(get_irn_link(proj));
+
+               projs[get_Proj_proj(proj)] = proj;
+       }
+
+       // CMP %1S, n_projs - 1
+       // BHI default
+
+
+
+       lc_esnprintf(arm_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "CMP %1S, #%u", irn, n_projs - 1);
+       lc_esnprintf(arm_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "", irn);
+       lc_efprintf(arm_get_arg_env(), out, "\t%-35s %-60s /* %+F */\n", cmd_buf, cmnt_buf, irn);
+
+       lc_esnprintf(arm_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "BHI BLOCK_%d", default_block_num);
+       lc_esnprintf(arm_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "", irn);
+       lc_efprintf(arm_get_arg_env(), out, "\t%-35s %-60s /* %+F */\n", cmd_buf, cmnt_buf, irn);
+
+
+       lc_esnprintf(arm_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "LDR %%r12, TABLE_%d_START", block_nr);
+       lc_esnprintf(arm_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "", irn);
+       lc_efprintf(arm_get_arg_env(), out, "\t%-35s %-60s /* %+F */\n", cmd_buf, cmnt_buf, irn);
+
+       lc_esnprintf(arm_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "ADD %%r12, %%r12, %1S, LSL #2", irn);
+       lc_esnprintf(arm_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "", irn);
+       lc_efprintf(arm_get_arg_env(), out, "\t%-35s %-60s /* %+F */\n", cmd_buf, cmnt_buf, irn);
+
+       lc_esnprintf(arm_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "LDR %%r15, [%%r12, #0]");
+       lc_esnprintf(arm_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "", irn);
+       lc_efprintf(arm_get_arg_env(), out, "\t%-35s %-60s /* %+F */\n", cmd_buf, cmnt_buf, irn);
+
+       // LDR %r12, .TABLE_X_START
+       // ADD %r12, %r12, [%1S, LSL #2]
+       // LDR %r15, %r12
+
+       fprintf(out, "TABLE_%d_START:\n\t.word\tTABLE_%d\n", block_nr, block_nr);
+       fprintf(out, "\t.align 2\n");
+       fprintf(out, "TABLE_%d:\n", block_nr);
+
+
+       for ( i=0; i<n_projs; i++) {
+               ir_node *block;
+               proj = projs[i];
+               if ( proj ) {
+                       block = get_irn_link(proj);
+               } else {
+                       block = get_irn_link(projs[get_arm_default_proj_num(irn)]);
+               }
+               fprintf(out, "\t.word\tBLOCK_%d\n",get_irn_node_nr(block));
+       }
+       fprintf(out, "\t.align 2\n");
+
+       xfree(projs);
+}
+
+/************************************************************************/
+/* emit_be                                                              */
+/************************************************************************/
+
+static void emit_be_Call(ir_node *irn, void *env) {
+       arm_emit_env_t *emit_env = env;
+       FILE *out = emit_env->out;
+       entity *target_entity = be_Call_get_entity(irn);
+       const char *target_name = get_entity_name(target_entity);
+       fprintf(out, "\tBL %s\t\t\t\t/* Call */\n", target_name);
+}
+
+static void emit_be_IncSP(const ir_node *irn, arm_emit_env_t *emit_env) {
+       FILE *F = emit_env->out;
+       unsigned offs = be_get_IncSP_offset(irn);
+       if (offs) {
+               char cmd_buf[SNPRINTF_BUF_LEN], cmnt_buf[SNPRINTF_BUF_LEN];
+               lc_esnprintf(arm_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "ADD %1D, %1S, #%O", irn, irn, irn );
+               lc_esnprintf(arm_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "/* IncSP(%O) */", irn);
+               lc_efprintf(arm_get_arg_env(), F, "\t%-35s %-60s /* %+F */\n", cmd_buf, cmnt_buf, irn);
+       } else {
+               char cmd_buf[SNPRINTF_BUF_LEN], cmnt_buf[SNPRINTF_BUF_LEN];
+               lc_esnprintf(arm_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "");
+               lc_esnprintf(arm_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "/* omitted IncSP(%O) */", irn);
+               lc_efprintf(arm_get_arg_env(), F, "\t%-35s %-60s /* %+F */\n", cmd_buf, cmnt_buf, irn);
+       }
+}
+
+// void emit_be_AddSP(const ir_node *irn, arm_emit_env_t *emit_env) {
+//     FILE *F = emit_env->out;
+//     char cmd_buf[SNPRINTF_BUF_LEN], cmnt_buf[SNPRINTF_BUF_LEN];
+//     lc_esnprintf(arm_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "ADD %1D, %1S, %2S", irn, irn, irn );
+//     lc_esnprintf(arm_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "/* AddSP(%2S) */", irn);
+//     lc_efprintf(arm_get_arg_env(), F, "\t%-35s %-60s /* %+F */\n", cmd_buf, cmnt_buf, irn);
+// }
+
+static void emit_be_Copy(const ir_node *irn, arm_emit_env_t *emit_env) {
+       FILE *F    = emit_env->out;
+       ir_mode *mode = get_irn_mode(irn);
+       assert( (mode != mode_E) && "IEEE Extended FP not supported");
+
+       if (get_in_reg(irn, 0) == get_out_reg(irn, 0)) {
+               char cmd_buf[256], cmnt_buf[256];
+               lc_esnprintf(arm_get_arg_env(), cmd_buf, 256, "");
+               lc_esnprintf(arm_get_arg_env(), cmnt_buf, 256, "/* omitted Copy: %1S -> %1D */", irn, irn);
+               lc_efprintf(arm_get_arg_env(), F, "\t%-35s %-60s /* %+F */\n", cmd_buf, cmnt_buf, irn);
+               return;
+       }
+
+       if (mode == mode_F) {
+               char cmd_buf[256], cmnt_buf[256];
+               lc_esnprintf(arm_get_arg_env(), cmd_buf, 256, "FCPYS %1D, %1S", irn, irn);
+               lc_esnprintf(arm_get_arg_env(), cmnt_buf, 256, "/* Copy: %1S -> %1D */", irn, irn);
+               lc_efprintf(arm_get_arg_env(), F, "\t%-35s %-60s /* %+F */\n", cmd_buf, cmnt_buf, irn);
+       } else if (mode == mode_D) {
+               char cmd_buf[256], cmnt_buf[256];
+               lc_esnprintf(arm_get_arg_env(), cmd_buf, 256, "FCPYD %1D, %1S", irn, irn);
+               lc_esnprintf(arm_get_arg_env(), cmnt_buf, 256, "/* Copy: %1S -> %1D */", irn, irn);
+               lc_efprintf(arm_get_arg_env(), F, "\t%-35s %-60s /* %+F */\n", cmd_buf, cmnt_buf, irn);
+       } else if (mode_is_numP(mode)) {
+               char cmd_buf[256], cmnt_buf[256];
+               lc_esnprintf(arm_get_arg_env(), cmd_buf, 256, "MOV %1D, %1S", irn, irn);
+               lc_esnprintf(arm_get_arg_env(), cmnt_buf, 256, "/* Copy: %1S -> %1D */", irn, irn);
+               lc_efprintf(arm_get_arg_env(), F, "\t%-35s %-60s /* %+F */\n", cmd_buf, cmnt_buf, irn);
+       } else {
+               assert(0 && "move not supported for this mode");
+       }
+//     emit_arm_Copy(irn, emit_env);
+}
+
+static void emit_be_Spill(const ir_node *irn, arm_emit_env_t *emit_env) {
+       FILE *F = emit_env->out;
+       ir_mode *mode = get_irn_mode(irn);
+       assert( (mode != mode_E) && "IEEE Extended FP not supported");
+       if (mode_is_dataM(mode)) {
+               char cmd_buf[256], cmnt_buf[256];
+               lc_esnprintf(arm_get_arg_env(), cmd_buf, 256, "STR %2S, [%1S, #%O]", irn, irn, irn );
+               lc_esnprintf(arm_get_arg_env(), cmnt_buf, 256, "/* Spill(%2S) -> (%1S) */", irn, irn);
+               lc_efprintf(arm_get_arg_env(), F, "\t%-35s %-60s /* %+F */\n", cmd_buf, cmnt_buf, irn);
+       } else {
+               assert(0 && "spill not supported for this mode");
+       }
+}
+
+static void emit_be_Reload(const ir_node* irn, arm_emit_env_t *emit_env) {
+       FILE *F = emit_env->out;
+       ir_mode *mode = get_irn_mode(irn);
+       assert( (mode != mode_E) && "IEEE Extended FP not supported");
+       if (mode_is_dataM(mode)) {
+               char cmd_buf[256], cmnt_buf[256];
+               lc_esnprintf(arm_get_arg_env(), cmd_buf, 256, "LDR %1D, [%1S, #%O]", irn, irn, irn );
+               lc_esnprintf(arm_get_arg_env(), cmnt_buf, 256, "/* Reload(%1S) -> (%1D) */", irn, irn);
+               lc_efprintf(arm_get_arg_env(), F, "\t%-35s %-60s /* %+F */\n", cmd_buf, cmnt_buf, irn);
+       } else {
+               assert(0 && "reload not supported for this mode");
+       }
+}
+
+static void emit_be_Perm(const ir_node* irn, arm_emit_env_t *emit_env) {
+       FILE *F = emit_env->out;
+       ir_mode *mode = get_irn_mode(irn);
+       assert( (mode != mode_E) && "IEEE Extended FP not supported");
+       lc_efprintf(arm_get_arg_env(), F, "\tEOR %1S, %1S, %2S\t\t\t/* begin Perm(%1S, %2S) */\n", irn, irn, irn, irn, irn);
+       lc_efprintf(arm_get_arg_env(), F, "\tEOR %2S, %1S, %2S\n", irn, irn, irn);
+       lc_efprintf(arm_get_arg_env(), F, "\tEOR %1S, %1S, %2S\t\t\t/* end Perm(%1S, %2S) */\n", irn, irn, irn, irn, irn);
+}
+
+static void emit_be_StackParam(const ir_node *irn, arm_emit_env_t *emit_env) {
+       FILE *F = emit_env->out;
+       ir_mode *mode = get_irn_mode(irn);
+       char cmd_buf[256], cmnt_buf[256];
+       assert( (mode != mode_E) && "IEEE Extended FP not supported");
+
+       lc_esnprintf(arm_get_arg_env(), cmd_buf, 256, "LDR %1D, [%1S, #%O]", irn, irn, irn );
+       lc_esnprintf(arm_get_arg_env(), cmnt_buf, 256, "/* StackParam: (%1S + %O) -> %1D */",irn , irn, irn, get_irn_n(irn, 0));
+       lc_efprintf(arm_get_arg_env(), F, "\t%-35s %-60s /* %+F */\n", cmd_buf, cmnt_buf, irn);
+}
+
+/************************************************************************/
+/* emit                                                                 */
+/************************************************************************/
+
+static void emit_Jmp(ir_node *irn, void *env) {
+       arm_emit_env_t *emit_env = env;
+       FILE *out = emit_env->out;
+       const ir_edge_t *edge = get_irn_out_edge_first(irn);
+       ir_node *target_block = get_edge_src_irn(edge);
+       fprintf(out, "\tB BLOCK_%d\t\t\t/* unconditional Jump */\n", get_irn_node_nr(target_block));
+}
+
+static void emit_Proj(ir_node *irn, void *env) {
+
+}
+
+
+
+/***********************************************************************************
+ *                  _          __                                             _
+ *                 (_)        / _|                                           | |
+ *  _ __ ___   __ _ _ _ __   | |_ _ __ __ _ _ __ ___   _____      _____  _ __| | __
+ * | '_ ` _ \ / _` | | '_ \  |  _| '__/ _` | '_ ` _ \ / _ \ \ /\ / / _ \| '__| |/ /
+ * | | | | | | (_| | | | | | | | | | | (_| | | | | | |  __/\ V  V / (_) | |  |   <
+ * |_| |_| |_|\__,_|_|_| |_| |_| |_|  \__,_|_| |_| |_|\___| \_/\_/ \___/|_|  |_|\_\
+ *
+ ***********************************************************************************/
+
+/**
+ * Enters the emitter functions for handled nodes into the generic
+ * pointer of an opcode.
+ */
+static void arm_register_emitters(void) {
+
+#define ARM_EMIT(a) op_arm_##a->ops.generic = (op_func)emit_arm_##a
+#define EMIT(a)      op_##a->ops.generic = (op_func)emit_##a
+#define BE_EMIT(a)   op_be_##a->ops.generic = (op_func)emit_be_##a
+
+       /* first clear the generic function pointer for all ops */
+       clear_irp_opcodes_generic_func();
+
+       /* register all emitter functions defined in spec */
+       arm_register_spec_emitters();
+
+       /* other emitter functions */
+       ARM_EMIT(CondJmp);
+//     ARM_EMIT(SwitchJmp);
+       ARM_EMIT(CopyB);
+//     ARM_EMIT(CopyB_i);
+//     ARM_EMIT(Const);
+       ARM_EMIT(SymConst);
+       ARM_EMIT(SwitchJmp);
+
+       /* benode emitter */
+       BE_EMIT(Call);
+       BE_EMIT(IncSP);
+//     BE_EMIT(AddSP);
+       BE_EMIT(Copy);
+       BE_EMIT(Spill);
+       BE_EMIT(Reload);
+       BE_EMIT(Perm);
+       BE_EMIT(StackParam);
+
+       /* firm emitter */
+       EMIT(Jmp);
+
+
+       /* noisy stuff */
+#ifdef SILENCER
+       EMIT(Proj);
+#endif
+
+#undef ARM_EMIT
+#undef BE_EMIT
+#undef EMIT
+}
+
+/**
+ * Emits code for a node.
+ */
+static void arm_emit_node(const ir_node *irn, void *env) {
+       arm_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) {
+               void (*emit)(const ir_node *, void *) = (void (*)(const ir_node *, void *))op->ops.generic;
+               (*emit)(irn, env);
+       }
+       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 arm_gen_block(ir_node *block, void *env) {
+       ir_node *irn;
+
+       if (! is_Block(block))
+               return;
+
+       fprintf(((arm_emit_env_t *)env)->out, "BLOCK_%ld:\n", get_irn_node_nr(block));
+       sched_foreach(block, irn) {
+               arm_emit_node(irn, env);
+       }
+}
+
+
+/**
+ * Emits code for function start.
+ */
+void arm_emit_start(FILE *F, ir_graph *irg) {
+       const char *irg_name = get_entity_name(get_irg_entity(irg));
+       fprintf(F, "\t.text\n");
+       fprintf(F, "\t.align  2\n");
+       fprintf(F, "\t.global %s\n", irg_name);
+       fprintf(F, "%s:\n", irg_name);
+}
+
+/**
+ * Emits code for function end
+ */
+void arm_emit_end(FILE *F, ir_graph *irg) {
+       const char *irg_name = get_entity_name(get_irg_entity(irg));
+}
+
+/**
+ * Sets labels for control flow nodes (jump target)
+ * TODO: Jump optimization
+ */
+void arm_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 arm_gen_routine(FILE *F, ir_graph *irg, const arm_code_gen_t *cg) {
+       arm_emit_env_t emit_env;
+
+       emit_env.mod      = firm_dbg_register("firm.be.arm.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;
+
+       arm_register_emitters();
+
+       arm_emit_start(F, irg);
+       irg_block_walk_graph(irg, arm_gen_labels, NULL, &emit_env);
+       irg_walk_blkwise_graph(irg, NULL, arm_gen_block, &emit_env);
+       arm_emit_end(F, irg);
+}
diff --git a/ir/be/arm/arm_emitter.h b/ir/be/arm/arm_emitter.h
new file mode 100644 (file)
index 0000000..787a7d4
--- /dev/null
@@ -0,0 +1,28 @@
+#ifndef _arm_EMITTER_H_
+#define _arm_EMITTER_H_
+
+#include "irargs_t.h"  // this also inlucdes <libcore/lc_print.h>
+#include "irnode.h"
+#include "debug.h"
+
+#include "../bearch.h"
+
+#include "bearch_arm_t.h"
+
+typedef struct _arm_emit_env_t {
+       firm_dbg_module_t         *mod;
+       FILE                      *out;
+       const arch_env_t          *arch_env;
+       const arm_code_gen_t *cg;
+} arm_emit_env_t;
+
+const lc_arg_env_t *arm_get_arg_env(void);
+
+void equalize_dest_src(FILE *F, ir_node *n);
+
+int get_arm_reg_nr(ir_node *irn, int posi, int in_out);
+const char *get_arm_in_reg_name(ir_node *irn, int pos);
+
+void arm_gen_routine(FILE *F, ir_graph *irg, const arm_code_gen_t *cg);
+
+#endif /* _arm_EMITTER_H_ */
diff --git a/ir/be/arm/arm_gen_decls.c b/ir/be/arm/arm_gen_decls.c
new file mode 100644 (file)
index 0000000..964452e
--- /dev/null
@@ -0,0 +1,596 @@
+/**
+ * Dumps global variables and constants as arm 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 "arm_gen_decls.h"
+
+/************************************************************************/
+
+/*
+ * 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 arm_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 arm_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.value\t");
+    break;
+
+  case 4:
+    obstack_printf(obst, "\t.long\t");
+    break;
+
+  case 8:
+    obstack_printf(obst, "\t.quad\t");
+    break;
+
+  case 10:
+  case 12:
+    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.value\t");
+    break;
+
+  case 4:
+    obstack_printf(obst, "\t.long\t");
+    break;
+
+  case 8:
+    obstack_printf(obst, "\t.quad\t");
+    break;
+
+  case 10:
+  case 12:
+    /* handled in arith */
+    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.string \"");
+  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);
+      }
+      obstack_printf(obst, "\t.type\t%s,%%object\n", ld_name);
+      obstack_printf(obst, "\t.size\t%s,%d\n", ld_name, (get_type_size_bits(ty) + 7) >> 3);
+
+      align = get_type_alignment_bytes(ty);
+      arm_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.zero\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.zero\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 arm_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));
+}
+
+/************************************************************************/
+
+void arm_gen_decls(FILE *out) {
+  struct obstack rodata, data, comm;
+  int    size;
+  char   *cp;
+
+  obstack_init(&rodata);
+  obstack_init(&data);
+  obstack_init(&comm);
+
+  arm_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.section\t.rodata\n");
+    fwrite(cp, 1, size, out);
+  }
+
+  size = obstack_object_size(&comm);
+  cp   = obstack_finish(&comm);
+  if (size > 0) {
+    fprintf(out, "\t.common\n");
+    fwrite(cp, 1, size, out);
+  }
+
+  obstack_free(&rodata, NULL);
+  obstack_free(&data, NULL);
+  obstack_free(&comm, NULL);
+}
diff --git a/ir/be/arm/arm_gen_decls.h b/ir/be/arm/arm_gen_decls.h
new file mode 100644 (file)
index 0000000..2f2c10f
--- /dev/null
@@ -0,0 +1,9 @@
+#ifndef _ARM_GEN_DECLS_H_
+#define _ARM_GEN_DECLS_H_
+
+/**
+ * Generate all entities.
+ */
+void arm_gen_decls(FILE *out);
+
+#endif /* _ARM_GEN_DECLS_H_ */
diff --git a/ir/be/arm/arm_map_regs.c b/ir/be/arm/arm_map_regs.c
new file mode 100644 (file)
index 0000000..3871663
--- /dev/null
@@ -0,0 +1,91 @@
+/**
+ * Register mapping for firm nodes. Stolen from bearch_firm :)
+ * $Id$
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+
+#include "arm_map_regs.h"
+#include "arm_new_nodes.h"
+
+#include "gen_arm_regalloc_if.h"
+
+
+static const arch_register_t *gpreg_param_reg_std[] = {
+       &arm_general_purpose_regs[REG_R0],
+       &arm_general_purpose_regs[REG_R1],
+       &arm_general_purpose_regs[REG_R2],
+       &arm_general_purpose_regs[REG_R3],
+};
+
+const arch_register_t *arm_get_RegParam_reg(int n) {
+       assert(n < 4 && n >=0 && "register param > 3 angefordert");
+       return gpreg_param_reg_std[n];
+}
+
+/* Mapping to store registers in firm nodes */
+
+struct arm_irn_reg_assoc {
+       const ir_node *irn;
+       const arch_register_t *reg;
+};
+
+int arm_cmp_irn_reg_assoc(const void *a, const void *b, size_t len) {
+       const struct arm_irn_reg_assoc *x = a;
+       const struct arm_irn_reg_assoc *y = b;
+
+       return x->irn != y->irn;
+}
+
+static struct arm_irn_reg_assoc *get_irn_reg_assoc(const ir_node *irn, set *reg_set) {
+       struct arm_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 arm_set_firm_reg(ir_node *irn, const arch_register_t *reg, set *reg_set) {
+       struct arm_irn_reg_assoc *assoc = get_irn_reg_assoc(irn, reg_set);
+       assoc->reg = reg;
+}
+
+const arch_register_t *arm_get_firm_reg(const ir_node *irn, set *reg_set) {
+       struct arm_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 arm_translate_proj_pos(const ir_node *proj) {
+       ir_node *pred = get_Proj_pred(proj);
+       long nr       = get_Proj_proj(proj);
+
+       if (is_arm_Load(pred) || is_arm_fLoadd(pred) || is_arm_fLoads(pred)) {
+               if (nr == pn_Load_res)
+                       return 0;
+               assert(0 && "unsupported Proj(Load) number");
+       }
+       else if (is_arm_Store(pred) || is_arm_fStores(pred) || is_arm_fStored(pred)) {
+               return 0;
+       }
+       else if (is_arm_fDiv(pred)) {
+               if (nr == pn_Quot_res)
+                       return 0;
+               else
+                       assert(0 && "there should be no more Projs for a fDiv");
+       }
+
+//     assert(0 && "unsupported Proj(X)");
+       return nr;
+}
diff --git a/ir/be/arm/arm_map_regs.h b/ir/be/arm/arm_map_regs.h
new file mode 100644 (file)
index 0000000..45b9ba5
--- /dev/null
@@ -0,0 +1,18 @@
+#ifndef _arm_MAP_REGS_H_
+#define _arm_MAP_REGS_H_
+
+#include "irnode.h"
+#include "set.h"
+
+#include "../bearch.h"
+#include "arm_nodes_attr.h"
+
+const arch_register_t *arm_get_RegParam_reg(int n);
+
+int  arm_cmp_irn_reg_assoc(const void *a, const void *b, size_t len);
+void arm_set_firm_reg(ir_node *irn, const arch_register_t *reg, set *reg_set);
+const arch_register_t *arm_get_firm_reg(const ir_node *irn, set *reg_set);
+
+long arm_translate_proj_pos(const ir_node *proj);
+
+#endif /* _arm_MAP_REGS_H_ */
diff --git a/ir/be/arm/arm_new_nodes.c b/ir/be/arm/arm_new_nodes.c
new file mode 100644 (file)
index 0000000..69ba1c2
--- /dev/null
@@ -0,0 +1,599 @@
+/**
+ * This file implements the creation of the achitecture specific firm opcodes
+ * and the coresponding node constructors for the arm 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 "arm_nodes_attr.h"
+#include "arm_new_nodes.h"
+#include "gen_arm_regalloc_if.h"
+
+#include "../beabi.h"
+#include "bearch_arm_t.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 arm_register_req_t **reqs, int inout) {
+       char *dir = inout ? "out" : "in";
+       int   max = inout ? get_arm_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 arm 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_arm(ir_node *n, FILE *F, dump_reason_t reason) {
+       ir_mode     *mode = NULL;
+       int          bad  = 0;
+       int          i;
+       arm_attr_t *attr;
+       const arm_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_arm_attr(n);
+                       fprintf(F, "=== arm attr begin ===\n");
+
+                       /* dump IN requirements */
+                       if (get_irn_arity(n) > 0) {
+                               reqs = get_arm_in_req_all(n);
+                               dump_reg_req(F, n, reqs, 0);
+                       }
+
+                       /* dump OUT requirements */
+                       if (attr->n_res > 0) {
+                               reqs = get_arm_out_req_all(n);
+                               dump_reg_req(F, n, reqs, 1);
+                       }
+
+                       /* dump assigned registers */
+                       slots = get_arm_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_arm_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 (get_arm_value(n)) {
+                               if (is_arm_CopyB(n)) {
+                                       fprintf(F, "size = %u\n", get_tarval_long(get_arm_value(n)));
+                               } else {
+                                       if (mode_is_float(get_irn_mode(n))) {
+                                               fprintf(F, "float value = (%lf)\n", get_tarval_double(get_arm_value(n)));
+                                       } else if (mode_is_int(get_irn_mode(n))) {
+                                               long v =  get_tarval_long(get_arm_value(n));
+                                               fprintf(F, "long value = %ld (0x%08lx)\n", v, v);
+                                       } else if (mode_is_reference(get_irn_mode(n))) {
+                                               fprintf(F, "pointer\n");
+                                       } else {
+                                               assert(0 && "unbehandelter Typ im const-Knoten");
+                                       }
+                               }
+                       }
+                       if (get_arm_proj_num(n) >= 0) {
+                               fprintf(F, "proj_num = (%d)\n", get_arm_proj_num(n));
+                       }
+                       /* TODO: dump all additional attributes */
+
+                       fprintf(F, "=== arm 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 :-(
+ */
+arm_attr_t *get_arm_attr(const ir_node *node) {
+       assert(is_arm_irn(node) && "need arm node to get attributes");
+       return (arm_attr_t *)get_irn_generic_attr((ir_node *)node);
+}
+
+/**
+ * Returns the argument register requirements of a arm node.
+ */
+const arm_register_req_t **get_arm_in_req_all(const ir_node *node) {
+       arm_attr_t *attr = get_arm_attr(node);
+       return attr->in_req;
+}
+
+/**
+ * Returns the result register requirements of an arm node.
+ */
+const arm_register_req_t **get_arm_out_req_all(const ir_node *node) {
+       arm_attr_t *attr = get_arm_attr(node);
+       return attr->out_req;
+}
+
+/**
+ * Returns the argument register requirement at position pos of an arm node.
+ */
+const arm_register_req_t *get_arm_in_req(const ir_node *node, int pos) {
+       arm_attr_t *attr = get_arm_attr(node);
+       return attr->in_req[pos];
+}
+
+/**
+ * Returns the result register requirement at position pos of an arm node.
+ */
+const arm_register_req_t *get_arm_out_req(const ir_node *node, int pos) {
+       arm_attr_t *attr = get_arm_attr(node);
+       return attr->out_req[pos];
+}
+
+/**
+ * Sets the OUT register requirements at position pos.
+ */
+void set_arm_req_out(ir_node *node, const arm_register_req_t *req, int pos) {
+       arm_attr_t *attr   = get_arm_attr(node);
+       attr->out_req[pos] = req;
+}
+
+/**
+ * Sets the complete OUT requirements of node.
+ */
+void set_arm_req_out_all(ir_node *node, const arm_register_req_t **reqs) {
+       arm_attr_t *attr = get_arm_attr(node);
+       attr->out_req    = reqs;
+}
+
+/**
+ * Sets the IN register requirements at position pos.
+ */
+void set_arm_req_in(ir_node *node, const arm_register_req_t *req, int pos) {
+       arm_attr_t *attr  = get_arm_attr(node);
+       attr->in_req[pos] = req;
+}
+
+/**
+ * Returns the register flag of an arm node.
+ */
+arch_irn_flags_t get_arm_flags(const ir_node *node) {
+       arm_attr_t *attr = get_arm_attr(node);
+       return attr->flags;
+}
+
+/**
+ * Sets the register flag of an arm node.
+ */
+void set_arm_flags(const ir_node *node, arch_irn_flags_t flags) {
+       arm_attr_t *attr = get_arm_attr(node);
+       attr->flags      = flags;
+}
+
+/**
+ * Returns the result register slots of an arm node.
+ */
+const arch_register_t **get_arm_slots(const ir_node *node) {
+       arm_attr_t *attr = get_arm_attr(node);
+       return attr->slots;
+}
+
+/**
+ * Returns the name of the OUT register at position pos.
+ */
+const char *get_arm_out_reg_name(const ir_node *node, int pos) {
+       arm_attr_t *attr = get_arm_attr(node);
+
+       assert(is_arm_irn(node) && "Not an arm 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_arm_out_regnr(const ir_node *node, int pos) {
+       arm_attr_t *attr = get_arm_attr(node);
+
+       assert(is_arm_irn(node) && "Not an arm 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_arm_out_reg(const ir_node *node, int pos) {
+       arm_attr_t *attr = get_arm_attr(node);
+
+       assert(is_arm_irn(node) && "Not an arm 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_arm_n_res(ir_node *node, int n_res) {
+       arm_attr_t *attr = get_arm_attr(node);
+       attr->n_res      = n_res;
+}
+
+/**
+ * Returns the number of results.
+ */
+int get_arm_n_res(const ir_node *node) {
+       arm_attr_t *attr = get_arm_attr(node);
+       return attr->n_res;
+}
+/**
+ * Returns the tarvalue
+ */
+tarval *get_arm_value(const ir_node *node) {
+       arm_attr_t *attr = get_arm_attr(node);
+       return attr->value;
+}
+
+/**
+ * Sets the tarvalue
+ */
+void set_arm_value(ir_node *node, tarval *tv) {
+       arm_attr_t *attr = get_arm_attr(node);
+       attr->value = tv;
+}
+
+/**
+ * Returns the proj num
+ */
+int get_arm_proj_num(const ir_node *node) {
+       arm_attr_t *attr = get_arm_attr(node);
+       return attr->proj_num;
+}
+
+/**
+ * Sets the proj num
+ */
+void set_arm_proj_num(ir_node *node, int proj_num) {
+       arm_attr_t *attr = get_arm_attr(node);
+       attr->proj_num      = proj_num;
+}
+
+/**
+ * Returns the SymConst label
+ */
+const char *get_arm_symconst_label(ir_node *node) {
+       arm_attr_t *attr = get_arm_attr(node);
+       return attr->symconst_label;
+}
+
+/**
+ * Sets the SymConst label
+ */
+void set_arm_symconst_label(ir_node *node, const char *symconst_label) {
+       arm_attr_t *attr = get_arm_attr(node);
+       attr->symconst_label = symconst_label;
+}
+
+
+/**
+ * Returns the number of projs.
+ */
+int get_arm_n_projs(ir_node *node) {
+       arm_attr_t *attr = get_arm_attr(node);
+       return attr->n_projs;
+}
+
+/**
+ * Sets the number of projs.
+ */
+void set_arm_n_projs(ir_node *node, int n_projs) {
+       arm_attr_t *attr = get_arm_attr(node);
+       attr->n_projs = n_projs;
+}
+
+/**
+ * Returns the default_proj_num.
+ */
+long get_arm_default_proj_num(ir_node *node) {
+       arm_attr_t *attr = get_arm_attr(node);
+       return attr->default_proj_num;
+}
+
+/**
+ * Sets the default_proj_num.
+ */
+void set_arm_default_proj_num(ir_node *node, long default_proj_num) {
+       arm_attr_t *attr = get_arm_attr(node);
+       attr->default_proj_num = default_proj_num;
+}
+
+
+
+void init_arm_attributes(ir_node *node, int flags, const arm_register_req_t ** in_reqs,
+                                                const arm_register_req_t ** out_reqs, int n_res) {
+       arm_attr_t *attr = get_arm_attr(node);
+       attr->in_req = in_reqs;
+       attr->out_req = out_reqs;
+       attr->n_res = n_res;
+       attr->flags = flags;
+       attr->slots = xcalloc(n_res, sizeof(attr->slots[0]));
+       attr->value = NULL;
+       attr->proj_num = -42;
+       attr->symconst_label = NULL;
+       attr->n_projs = 0;
+       attr->default_proj_num = 0;
+}
+
+static int arm_comp_condJmp(arm_attr_t *attr_a, arm_attr_t *attr_b) {
+       return 1;
+}
+
+ir_node *arm_new_NoReg_gp(arm_code_gen_t *cg) {
+       return be_abi_get_callee_save_irn(cg->birg->abi, &arm_general_purpose_regs[REG_RXX]);
+}
+
+ir_node *arm_new_NoReg_fp(arm_code_gen_t *cg) {
+       return be_abi_get_callee_save_irn(cg->birg->abi, &arm_floating_point_regs[REG_FXX]);
+}
+
+
+
+
+/***************************************************************************************
+ *                  _                            _                   _
+ *                 | |                          | |                 | |
+ *  _ __   ___   __| | ___    ___ ___  _ __  ___| |_ _ __ _   _  ___| |_ ___  _ __ ___
+ * | '_ \ / _ \ / _` |/ _ \  / __/ _ \| '_ \/ __| __| '__| | | |/ __| __/ _ \| '__/ __|
+ * | | | | (_) | (_| |  __/ | (_| (_) | | | \__ \ |_| |  | |_| | (__| || (_) | |  \__ \
+ * |_| |_|\___/ \__,_|\___|  \___\___/|_| |_|___/\__|_|   \__,_|\___|\__\___/|_|  |___/
+ *
+ ***************************************************************************************/
+
+/* limit the possible registers for sp in arm_StoreStackM4Inc */
+static void limit_reg_arm_StoreStackM4Inc_sp(void *_unused, bitset_t *bs) {
+  bs = bitset_clear_all(bs);   /* disallow all register (positive constraints given) */
+  bitset_set(bs, 14);           /* allow r13 */
+  bitset_clear(bs, 13);         /* disallow ignore reg r12 */
+  bitset_clear(bs, 14);         /* disallow ignore reg r13 */
+  bitset_clear(bs, 15);         /* disallow ignore reg r15 */
+  bitset_clear(bs, 16);         /* disallow ignore reg rxx */
+  bitset_clear(bs, 17);         /* disallow ignore reg MURX */
+}
+
+static const arm_register_req_t _arm_req_sp = {
+  {
+    arch_register_req_type_limited,
+    &arm_reg_classes[CLASS_arm_general_purpose],
+    limit_reg_arm_StoreStackM4Inc_sp,
+    NULL,        /* limit environment */
+    NULL,        /* same node */
+    NULL         /* different node */
+  },
+  0,
+  0
+};
+
+/* construct Store: Store(ptr, val, mem) = ST ptr,val */
+ir_node *new_r_arm_StoreStackMInc(ir_graph *irg, ir_node *block, ir_node *mem, ir_node *sp,
+                                                                 int n_regs, ir_node **regs, ir_mode *mode) {
+  ir_node *res;
+  ir_node *in[16];
+  int flags = 0;
+  static const arm_register_req_t *_in_req_arm_StoreStackM4Inc[] =
+  {
+       &arm_default_req_none,
+    &_arm_req_sp,
+    &arm_default_req_arm_general_purpose,
+    &arm_default_req_arm_general_purpose,
+    &arm_default_req_arm_general_purpose,
+    &arm_default_req_arm_general_purpose,
+    &arm_default_req_arm_general_purpose,
+    &arm_default_req_arm_general_purpose,
+    &arm_default_req_arm_general_purpose,
+    &arm_default_req_arm_general_purpose,
+    &arm_default_req_arm_general_purpose,
+    &arm_default_req_arm_general_purpose,
+    &arm_default_req_arm_general_purpose,
+    &arm_default_req_arm_general_purpose,
+    &arm_default_req_arm_general_purpose,
+    &arm_default_req_arm_general_purpose,
+  };
+
+  assert(n_regs <= 15);
+
+  in[0] = mem;
+  in[1] = sp;
+  memcpy(&in[2], regs, n_regs * sizeof(in[0]));
+  res = new_ir_node(NULL, irg, block, op_arm_StoreStackM4Inc, mode, 2 + n_regs, in);
+  flags |= arch_irn_flags_rematerializable;   /* op can be easily recalculated */
+
+  /* init node attributes */
+  init_arm_attributes(res, flags, _in_req_arm_StoreStackM4Inc, NULL, 0);
+
+  res = optimize_node(res);
+  irn_vrfy_irg(res, irg);
+
+  return res;
+}
+
+/**
+ * Register additional opcodes here.
+ */
+static void arm_register_additional_opcodes(int cur_opcode) {
+}
+
+
+/* Include the generated constructor functions */
+#include "gen_arm_new_nodes.c.inl"
diff --git a/ir/be/arm/arm_new_nodes.h b/ir/be/arm/arm_new_nodes.h
new file mode 100644 (file)
index 0000000..1f899f6
--- /dev/null
@@ -0,0 +1,159 @@
+#ifndef _arm_NEW_NODES_H_
+#define _arm_NEW_NODES_H_
+
+/**
+ * Function prototypes for the assembler ir node constructors.
+ * $Id$
+ */
+
+#include "arm_nodes_attr.h"
+#include "bearch_arm_t.h"
+
+/***************************************************************************************************
+ *        _   _                   _       __        _                    _   _               _
+ *       | | | |                 | |     / /       | |                  | | | |             | |
+ *   __ _| |_| |_ _ __   ___  ___| |_   / /_ _  ___| |_   _ __ ___   ___| |_| |__   ___   __| |___
+ *  / _` | __| __| '__| / __|/ _ \ __| / / _` |/ _ \ __| | '_ ` _ \ / _ \ __| '_ \ / _ \ / _` / __|
+ * | (_| | |_| |_| |    \__ \  __/ |_ / / (_| |  __/ |_  | | | | | |  __/ |_| | | | (_) | (_| \__ \
+ *  \__,_|\__|\__|_|    |___/\___|\__/_/ \__, |\___|\__| |_| |_| |_|\___|\__|_| |_|\___/ \__,_|___/
+ *                                        __/ |
+ *                                       |___/
+ ***************************************************************************************************/
+
+/**
+ * Returns the attributes of an arm node.
+ */
+arm_attr_t *get_arm_attr(const ir_node *node);
+
+/**
+ * Returns the argument register requirements of an arm node.
+ */
+const arm_register_req_t **get_arm_in_req_all(const ir_node *node);
+
+/**
+ * Returns the result register requirements of an arm node.
+ */
+const arm_register_req_t **get_arm_out_req_all(const ir_node *node);
+
+/**
+ * Returns the argument register requirements of an arm node.
+ */
+const arm_register_req_t *get_arm_in_req(const ir_node *node, int pos);
+
+/**
+ * Returns the result register requirements of an arm node.
+ */
+const arm_register_req_t *get_arm_out_req(const ir_node *node, int pos);
+
+/**
+ * Sets the OUT register requirements at position pos.
+ */
+void set_arm_req_out(ir_node *node, const arm_register_req_t *req, int pos);
+
+/**
+ * Sets the complete OUT requirements of node.
+ */
+void set_arm_req_out_all(ir_node *node, const arm_register_req_t **reqs);
+
+/**
+ * Sets the IN register requirements at position pos.
+ */
+void set_arm_req_in(ir_node *node, const arm_register_req_t *req, int pos);
+
+/**
+ * Returns the register flag of an arm node.
+ */
+arch_irn_flags_t get_arm_flags(const ir_node *node);
+
+/**
+ * Sets the register flag of an arm node.
+ */
+void set_arm_flags(const ir_node *node, arch_irn_flags_t flags);
+
+/**
+ * Returns the result register slots of an arm node.
+ */
+const arch_register_t **get_arm_slots(const ir_node *node);
+
+/**
+ * Returns the name of the OUT register at position pos.
+ */
+const char *get_arm_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_arm_out_regnr(const ir_node *node, int pos);
+
+/**
+ * Returns the OUT register at position pos.
+ */
+const arch_register_t *get_arm_out_reg(const ir_node *node, int pos);
+
+/**
+ * Sets the number of results.
+ */
+void set_arm_n_res(ir_node *node, int n_res);
+
+/**
+ * Returns the number of results.
+ */
+int get_arm_n_res(const ir_node *node);
+
+void init_arm_attributes(ir_node *node, int flags, const arm_register_req_t ** in_reqs,
+                                                const arm_register_req_t ** out_reqs, int n_res);
+
+ir_node *arm_new_NoReg_gp(arm_code_gen_t *cg);
+ir_node *arm_new_NoReg_fp(arm_code_gen_t *cg);
+
+/**
+ * Returns the tarval
+ */
+tarval *get_arm_value(const ir_node *node);
+
+/**
+ * Sets the tarval
+ */
+void set_arm_value(ir_node *node, tarval *tv);
+
+/**
+ * Returns the proj num
+ */
+int get_arm_proj_num(const ir_node *node);
+
+/**
+ * Sets the proj num
+ */
+void set_arm_proj_num(ir_node *node, int proj_num);
+
+const char *get_arm_symconst_label(ir_node *node);
+void set_arm_symconst_label(ir_node *node, const char *symconst_label);
+
+ir_node *new_r_arm_StoreStackMInc(ir_graph *irg, ir_node *block, ir_node *mem, ir_node *sp,
+                                                             int n_regs, ir_node **regs, ir_mode *mode);
+
+/**
+ * Returns the number of projs.
+ */
+int get_arm_n_projs(ir_node *node);
+
+/**
+ * Sets the number of projs.
+ */
+void set_arm_n_projs(ir_node *node, int n_projs);
+
+/**
+ * Returns the default_proj_num.
+ */
+long get_arm_default_proj_num(ir_node *node);
+
+/**
+ * Sets the default_proj_num.
+ */
+void set_arm_default_proj_num(ir_node *node, long default_proj_num);
+
+
+/* Include the generated headers */
+#include "gen_arm_new_nodes.h"
+
+#endif /* _arm_NEW_NODES_H_ */
diff --git a/ir/be/arm/arm_nodes_attr.h b/ir/be/arm/arm_nodes_attr.h
new file mode 100644 (file)
index 0000000..b7e9de7
--- /dev/null
@@ -0,0 +1,31 @@
+#ifndef _ARM_NODES_ATTR_H_
+#define _ARM_NODES_ATTR_H_
+
+#include "../bearch.h"
+#include "../../common/firm_types.h"
+
+
+typedef struct _arm_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 */
+} arm_register_req_t;
+
+
+typedef struct _arm_attr_t {
+       arch_irn_flags_t flags;     /**<< indicating if spillable, rematerializeable ... etc. */
+       int              n_res;     /**<< number of results for this node */
+
+       const arm_register_req_t **in_req;  /**<< register requirements for arguments */
+       const arm_register_req_t **out_req; /**<< register requirements for results */
+
+       const arch_register_t **slots;          /**<< register slots for assigned registers */
+
+       tarval *value;
+       const char *symconst_label;
+       int proj_num;
+       int n_projs;
+       long default_proj_num;
+} arm_attr_t;
+
+#endif /* _ARM_NODES_ATTR_H_ */
diff --git a/ir/be/arm/arm_spec.pl b/ir/be/arm/arm_spec.pl
new file mode 100644 (file)
index 0000000..0fcb9ff
--- /dev/null
@@ -0,0 +1,833 @@
+# Creation: 2006/02/13
+# $Id$
+# This is a template specification for the Firm-Backend
+
+# the cpu architecture (ia32, ia64, mips, sparc, ppc, ...)
+
+$arch = "arm";
+
+# $comment_string = 'WIRHABENKEINEKOMMENTARE';
+$comment_string = '/*';
+
+# the number of additional opcodes you want to register
+$additional_opcodes = 0;
+
+# 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",
+#   "irn_flags" => "R|N|I"
+#   "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
+#
+# irn_flags: special node flags, OPTIONAL (default is 0)
+# following irn_flags are supported:
+#   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" => "r0", "type" => 1 },
+                         { "name" => "r1", "type" => 1 },
+                         { "name" => "r2", "type" => 1 },
+                         { "name" => "r3", "type" => 1 },
+                         { "name" => "r4", "type" => 2 },
+                         { "name" => "r5", "type" => 2 },
+                         { "name" => "r6", "type" => 2 },
+                         { "name" => "r7", "type" => 2 },
+                         { "name" => "r8", "type" => 2 },
+                         { "name" => "r9", "type" => 2 },
+                         { "name" => "r10", "type" => 2 },
+                         { "name" => "r11", "type" => 2 },
+                         { "name" => "r12", "type" => 6 }, # reserved for linker
+                         { "name" => "r13", "type" => 6 }, # this is our stack pointer
+                         { "name" => "r14", "type" => 3 }, # this is our return address
+                         { "name" => "r15", "type" => 6 }, # this is our program counter
+                                                { "name" => "rxx", "type" => 6 }, # dummy register for no_mem
+                                                { "name" => "MURX", "type" => 6 }, # this is our workaround-register
+                         { "mode" => "mode_P" }
+                       ],
+  "floating_point"  => [
+                         { "name" => "f0", "type" => 1 },
+                         { "name" => "f1", "type" => 1 },
+                         { "name" => "f2", "type" => 1 },
+                         { "name" => "f3", "type" => 1 },
+                         { "name" => "f4", "type" => 2 },
+                         { "name" => "f5", "type" => 2 },
+                         { "name" => "f6", "type" => 2 },
+                         { "name" => "f7", "type" => 2 },
+                                                { "name" => "fxx", "type" => 6 }, # dummy register for no_mem
+                         { "mode" => "mode_D" }
+                       ]
+); # %reg_classes
+
+#--------------------------------------------------#
+#                        _                         #
+#                       (_)                        #
+#  _ __   _____      __  _ _ __    ___  _ __  ___  #
+# | '_ \ / _ \ \ /\ / / | | '__|  / _ \| '_ \/ __| #
+# | | | |  __/\ V  V /  | | |    | (_) | |_) \__ \ #
+# |_| |_|\___| \_/\_/   |_|_|     \___/| .__/|___/ #
+#                                      | |         #
+#                                      |_|         #
+#--------------------------------------------------#
+
+%nodes = (
+
+#-----------------------------------------------------------------#
+#  _       _                                         _            #
+# (_)     | |                                       | |           #
+#  _ _ __ | |_ ___  __ _  ___ _ __   _ __   ___   __| | ___  ___  #
+# | | '_ \| __/ _ \/ _` |/ _ \ '__| | '_ \ / _ \ / _` |/ _ \/ __| #
+# | | | | | ||  __/ (_| |  __/ |    | | | | (_) | (_| |  __/\__ \ #
+# |_|_| |_|\__\___|\__, |\___|_|    |_| |_|\___/ \__,_|\___||___/ #
+#                   __/ |                                         #
+#                  |___/                                          #
+#-----------------------------------------------------------------#
+
+# commutative operations
+
+"Add" => {
+  "op_flags"  => "C",
+  "irn_flags" => "R",
+  "comment"   => "construct Add: Add(a, b) = Add(b, a) = a + b",
+  "reg_req"   => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "general_purpose" ] },
+  "emit"      => '. ADD %D1, %S1, %S2\t\t\t/* Add(%S1, %S2) -> %D1, (%A1, %A2) */'
+},
+
+"Add_i" => {
+  "irn_flags" => "R",
+  "comment"   => "construct Add: Add(a, const) = Add(const, a) = a + const",
+  "reg_req"   => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] },
+  "emit"      => '. ADD %D1, %S1, %C\t\t\t/* Add(%C, %S1) -> %D1, (%A1, const) */',
+  "cmp_attr"  =>
+'    if (attr_a->value == NULL || attr_b->value == NULL)
+           return 1;
+
+    return get_tarval_long(attr_a->value) != get_tarval_long(attr_b->value);
+'
+},
+
+"Mul" => {
+  #"op_flags"  => "C",
+  "irn_flags" => "R",
+  "comment"   => "construct Mul: Mul(a, b) = Mul(b, a) = a * b",
+  "reg_req"   => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "!in_r1" ] },
+  "emit"      =>'. MUL %D1, %S1, %S2\t\t\t/* Mul(%S1, %S2) -> %D1, (%A1, %A2) */'
+},
+
+"And" => {
+  "op_flags"  => "C",
+  "irn_flags" => "R",
+  "comment"   => "construct And: And(a, b) = And(b, a) = a AND b",
+  "reg_req"   => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "general_purpose" ] },
+  "emit"      => '. AND %D1, %S1, %S2\t\t/* And(%S1, %S2) -> %D1, (%A1, %A2) */'
+},
+
+"And_i" => {
+  "irn_flags" => "R",
+  "comment"   => "construct And: And(a, const) = And(const, a) = a AND const",
+  "reg_req"   => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] },
+  "emit"      => '. AND %D1, %S1, %C\t\t\t/* And(%C, %S1) -> %D1, (%A1, const) */',
+  "cmp_attr"  =>
+'    if (attr_a->value == NULL || attr_b->value == NULL)
+           return 1;
+
+    return get_tarval_long(attr_a->value) != get_tarval_long(attr_b->value);
+'
+},
+
+"Or" => {
+  "op_flags"  => "C",
+  "irn_flags" => "R",
+  "comment"   => "construct Or: Or(a, b) = Or(b, a) = a OR b",
+  "reg_req"   => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "general_purpose" ] },
+  "emit"      => '. ORR %D1, %S1, %S2\t\t/* Or(%S1, %S2) -> %D1, (%A1, %A2) */'
+},
+
+"Or_i" => {
+  "irn_flags" => "R",
+  "comment"   => "construct Or: Or(a, const) = Or(const, a) = a OR const",
+  "reg_req"   => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] },
+  "emit"      => '. ORR %D1, %S1, %C\t\t\t/* Or(%C, %S1) -> %D1, (%A1, const) */',
+  "cmp_attr"  =>
+'    if (attr_a->value == NULL || attr_b->value == NULL)
+           return 1;
+
+    return get_tarval_long(attr_a->value) != get_tarval_long(attr_b->value);
+'
+},
+
+"Or_Shl_i" => {
+  "irn_flags" => "R",
+  "comment"   => "construct Or with immediate shifter operand",
+  "reg_req"   => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "general_purpose" ] },
+  "emit"      => '. ORR %D1, %S1, %S2 LSL %C\t\t\t/* Or_Shl_i(%S1, %S2 << %C) -> %D1, (%A1, const) */',
+  "cmp_attr"  =>
+'    if (attr_a->value == NULL || attr_b->value == NULL)
+           return 1;
+
+    return get_tarval_long(attr_a->value) != get_tarval_long(attr_b->value);
+'
+},
+
+"Eor" => {
+  "op_flags"  => "C",
+  "irn_flags" => "R",
+  "comment"   => "construct Eor: Eor(a, b) = Eor(b, a) = a EOR b",
+  "reg_req"   => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "general_purpose" ] },
+  "emit"      => '. EOR %D1, %S1, %S2\t\t\t/* Xor(%S1, %S2) -> %D1, (%A1, %A2) */'
+},
+
+"Eor_i" => {
+  "irn_flags" => "R",
+  "comment"   => "construct Eor: Eor(a, const) = Eor(const, a) = a EOR const",
+  "reg_req"   => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] },
+  "emit"      => '. EOR %D1, %S1, %C\t\t\t/* Xor(%C, %S1) -> %D1, (%A1, const) */',
+  "cmp_attr"  =>
+'    if (attr_a->value == NULL || attr_b->value == NULL)
+           return 1;
+
+    return get_tarval_long(attr_a->value) != get_tarval_long(attr_b->value);
+'
+},
+
+# not commutative operations
+
+"Sub" => {
+  "irn_flags" => "R",
+  "comment"   => "construct Sub: Sub(a, b) = a - b",
+  "reg_req"   => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "general_purpose" ] },
+  "emit"      => '. SUB %D1, %S1, %S2\t\t\t/* Sub(%S1, %S2) -> %D1, (%A1, %A2) */'
+},
+
+"Sub_i" => {
+  "irn_flags" => "R",
+  "comment"   => "construct Sub: Sub(a, const) = a - const",
+  "reg_req"   => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] },
+  "emit"      => '. SUB %D1, %S1, %C\t\t\t/* Sub(%S1, %C) -> %D1, (%A1, const) */',
+  "cmp_attr"  =>
+'    if (attr_a->value == NULL || attr_b->value == NULL)
+           return 1;
+
+    return get_tarval_long(attr_a->value) != get_tarval_long(attr_b->value);
+'
+},
+
+"Shl" => {
+  "irn_flags" => "R",
+  "comment"   => "construct Shl: Shl(a, b) = a << b",
+  "reg_req"   => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "general_purpose" ] },
+  "emit"      => '. MOV %D1, %S1, LSL %S2\t/* Shl(%S1, %S2) -> %D1, (%A1, %A2) */'
+},
+
+"Shl_i" => {
+  "irn_flags" => "R",
+  "comment"   => "construct Shl: Shl(a, const) = a << const",
+  "reg_req"   => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] },
+  "emit"      => '. MOV %D1, %S1, LSL %C\t\t\t/* Shl(%S1, %C) -> %D1, (%A1, const) */',
+  "cmp_attr"  =>
+'    if (attr_a->value == NULL || attr_b->value == NULL)
+           return 1;
+
+    return get_tarval_long(attr_a->value) != get_tarval_long(attr_b->value);
+'
+},
+
+"Shr" => {
+  "irn_flags" => "R",
+  "comment"   => "construct Shr: Shr(a, b) = a >> b",
+  "reg_req"   => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "in_r1" ] },
+  "emit"      => '. MOV %D1, %S1, LSR %S2\t\t\t/* Shr(%S1, %S2) -> %D1, (%A1, %A2) */'
+},
+
+"Shr_i" => {
+  "irn_flags" => "R",
+  "comment"   => "construct Shr: Shr(a, const) = a >> const",
+  "reg_req"   => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] },
+  "emit"      => '. MOV %D1, %S1, LSR %C\t\t\t/* Shr(%S1, %C) -> %D1, (%A1, const) */',
+  "cmp_attr"  =>
+'    if (attr_a->value == NULL || attr_b->value == NULL)
+           return 1;
+
+    return get_tarval_long(attr_a->value) != get_tarval_long(attr_b->value);
+'
+},
+
+"Shrs" => {
+  "irn_flags" => "R",
+  "comment"   => "construct Shrs: Shrs(a, b) = a >> b",
+  "reg_req"   => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "in_r1" ] },
+  "emit"      => '. MOV %D1, %S1, ASR %S2\t\t\t\t\t/* Shrs(%S1, %S2) -> %D1, (%A1, %A2) */'
+},
+
+"Shrs_i" => {
+  "irn_flags" => "R",
+  "comment"   => "construct Shrs: Shrs(a, const) = a >> const",
+  "reg_req"   => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] },
+  "emit"      => '. MOV %D1, %S1, ASR %C\t\t\t/* Shrs(%S1, %C) -> %D1, (%A1, const) */',
+  "cmp_attr"  =>
+'    if (attr_a->value == NULL || attr_b->value == NULL)
+           return 1;
+
+    return get_tarval_long(attr_a->value) != get_tarval_long(attr_b->value);
+'
+},
+
+#"Div" => {
+#  "irn_flags" => "R",
+#  "comment"   => "construct Div: Div(a, b) = a / b",
+#  "reg_req"   => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "general_purpose" ] },
+#  "emit"      =>'. div %S1, %S2, %D1\t\t\t/* div(%S1, %S2) -> %D1, (%A1, %A2) */'
+#},
+#
+#"Div_i" => {
+#  "irn_flags" => "R",
+#  "comment"   => "construct Div: Div(a, const) = a / const",
+#  "reg_req"   => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] },
+#  "emit"      => '. div %S1, %C, %D1\t\t\t/* signed div(%C, %S1) -> %D1, (%A1, const) */'
+#},
+#
+#"Mod" => {
+#  "irn_flags" => "R",
+#  "comment"   => "construct Mod: Mod(a, b) = a % b",
+#  "reg_req"   => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "general_purpose" ] },
+#  "emit"      =>'. mod %S1, %S2, %D1\t\t\t/* mod(%S1, %S2) -> %D1, (%A1, %A2) */'
+#},
+#
+#"Mod_i" => {
+#  "irn_flags" => "R",
+#  "comment"   => "construct mod: Mod(a, const) = a % const",
+#  "reg_req"   => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] },
+#  "emit"      => '. mod %S1, %C, %D1\t\t\t/* mod(%C, %S1) -> %D1, (%A1, const) */'
+#},
+#
+#"DivMod" => {
+#  "irn_flags" => "R",
+#  "comment"   => "construct DivMod: DivMod(a, b) = a / b",
+#  "reg_req"   => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "general_purpose" ] },
+#  "emit"      =>'. div %S1, %S2, %D1\t\t\t/* div(%S1, %S2) -> %D1, (%A1, %A2) */'
+#},
+#
+#"Div_i" => {
+#  "irn_flags" => "R",
+#  "comment"   => "construct DivMod: DivMod(a, const) = a / const",
+#  "reg_req"   => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] },
+#  "emit"      => '. div %S1, %C, %D1\t\t\t/* signed div(%C, %S1) -> %D1, (%A1, const) */'
+#},
+
+#"RotR" => {
+#  "irn_flags" => "R",
+#  "comment"   => "construct RotR: RotR(a, b) = a ROTR b",
+#  "reg_req"   => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "general_purpose" ] },
+#  "emit"      => '. MOV %D1, %S1, ROR %S2\t\t\t/* RotR(%S1, %S2) -> %D1, (%A1, %A2) */'
+##  "emit"      => '. ror %S1, %S2, %D1\t\t\t/* RotR(%S1, %S2) -> %D1, (%A1, %A2) */'
+#},
+
+#"RotL" => {
+#  "irn_flags" => "R",
+#  "comment"   => "construct RotL: RotL(a, b) = a ROTL b",
+#  "reg_req"   => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "general_purpose" ] },
+#  "emit"      => '. rol %S1, %S2, %D1\t\t\t/* RotL(%S1, %S2) -> %D1, (%A1, %A2) */'
+#},
+
+#"RotL_i" => {
+#  "irn_flags" => "R",
+#  "comment"   => "construct RotL: RotL(a, const) = a ROTL const",
+#  "reg_req"   => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] },
+#  "emit"      => '. rol %S1, %C, %D1\t\t\t/* RotL(%S1, %C) -> %D1, (%A1, const) */'
+#},
+
+"Minus" => {
+  "irn_flags" => "R",
+  "comment"   => "construct Minus: Minus(a) = -a",
+  "reg_req"   => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] },
+  "emit"      => '. RSB %D1, %S1, #0\t\t\t/* Neg(%S1) -> %D1, (%A1) */'
+},
+
+#"Inc" => {
+#  "irn_flags" => "R",
+#  "comment"   => "construct Increment: Inc(a) = a++",
+#  "reg_req"   => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] },
+#  "emit"      => '. inc %S1, %D1\t\t\t/* Inc(%S1) -> %D1, (%A1) */'
+#},
+#
+#"Dec" => {
+#  "irn_flags" => "R",
+#  "comment"   => "construct Decrement: Dec(a) = a--",
+#  "reg_req"   => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] },
+#  "emit"      => '. dec %S1, %D1\t\t\t/* Dec(%S1) -> %D1, (%A1) */'
+#},
+
+"Not" => {
+  "arity"       => 1,
+#  "remat"       => 1,
+  "irn_flags"   => "R",
+  "comment"     => "construct Not: Not(a) = !a",
+  "reg_req"     => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] },
+  "emit"        => '. MVN %D1, %S1\t\t\t/* Not(%S1) -> %D1, (%A1) */'
+},
+
+"Abs" => {
+  "irn_flags" => "R",
+  "comment"   => "construct Abs: Abs(a) = |a|",
+  "reg_req"   => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] },
+  "emit"      =>
+'. MOVS %S1, %S1, #0\t\t\t/* set condition flag */\n
+. RSBMI %D1, %S1, #0\t\t\t/* Neg(%S1) -> %D1, (%A1) */'
+},
+
+# other operations
+
+"EmptyReg" => {
+  "op_flags"  => "c",
+  "irn_flags" => "R",
+  "comment"  => "just to get an emptz register for calculations",
+  "reg_req"  => { "out" => [ "general_purpose" ] },
+  "emit"      => '. /* %D1 now available for calculations */',
+  "cmp_attr"  => 'return 1;'
+},
+
+"Copy" => {
+  "comment"  => "implements a register copy",
+  "reg_req"  => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] },
+},
+
+"CopyB" => {
+  "op_flags" => "F|H",
+  "state"    => "pinned",
+  "comment"  => "implements a memcopy: CopyB(dst, src, size, mem) == memcpy(dst, src, size)",
+  "reg_req"  => { "in" => [ "!r13", "!r13", "general_purpose", "general_purpose", "general_purpose", "none" ], "out" => [ "none" ] },
+},
+
+"Const" => {
+  "irn_flags" => "R",
+  "comment"   => "represents an integer constant",
+  "reg_req"   => { "out" => [ "general_purpose" ] },
+  "emit"      => '. MOV %D1, %C  \t\t\t/* Mov Const into register */',
+  "cmp_attr"  =>
+'    if (attr_a->value == NULL || attr_b->value == NULL)
+           return 1;
+
+    return get_tarval_long(attr_a->value) != get_tarval_long(attr_b->value);
+'
+},
+
+"Const_Neg" => {
+  "irn_flags" => "R",
+  "comment"   => "represents a negated integer constant",
+  "reg_req"   => { "out" => [ "general_purpose" ] },
+  "emit"      => '. MVN %D1, %C  \t\t\t/* Mov negated Const into register */',
+  "cmp_attr"  =>
+'    if (attr_a->value == NULL || attr_b->value == NULL)
+           return 1;
+
+    return get_tarval_long(attr_a->value) != get_tarval_long(attr_b->value);
+'
+},
+
+"SymConst" => {
+  "op_flags"  => "c",
+  "irn_flags" => "R",
+  "comment"   => "represents a symbolic constant",
+  "reg_req"   => { "out" => [ "general_purpose" ] },
+#  "emit"      => '. LDR %D1, %C\t\t\t/* Mov Const into register */',
+  "cmp_attr"  =>
+'    if (attr_a->value == NULL || attr_b->value == NULL)
+           return 1;
+
+    return get_tarval_long(attr_a->value) != get_tarval_long(attr_b->value);
+'
+},
+
+"CondJmp" => {
+  "op_flags"  => "L|X|Y",
+  "comment"   => "construct conditional jump: CMP A, B && JMPxx LABEL",
+  "cmp_attr"  => "  return arm_comp_condJmp(attr_a, attr_b);\n",
+  "reg_req"   => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "none", "none"] },
+},
+
+"SwitchJmp" => {
+  "op_flags"  => "L|X|Y",
+  "comment"   => "construct switch",
+  "reg_req"   => { "in" => [ "general_purpose" ], "out" => [ "none" ] },
+  "cmp_attr"  => "  return 0;\n",
+},
+
+# Load / Store
+
+"Load" => {
+  "op_flags"  => "L|F",
+  "irn_flags" => "R",
+  "state"     => "exc_pinned",
+  "comment"   => "construct Load: Load(ptr, mem) = LD ptr -> reg",
+  "reg_req"   => { "in" => [ "general_purpose", "none" ], "out" => [ "general_purpose" ] },
+  "emit"      => '. LDR %D1, [%S1, #0]\t\t\t/* Load((%S1)) -> %D1, (%A1) */'
+#  "emit"      => '. LDR %D1, %S1, %O\t\t\t/* Load((%S1)) -> %D1, (%A1) */'
+},
+
+"Loadb" => {
+  "op_flags"  => "L|F",
+  "irn_flags" => "R",
+  "state"     => "exc_pinned",
+  "comment"   => "construct Load: Load(ptr, mem) = LD ptr -> reg",
+  "reg_req"   => { "in" => [ "general_purpose", "none" ], "out" => [ "general_purpose" ] },
+  "emit"      => '. LDRB %D1, [%S1, #0]\t\t\t/* Load((%S1)) -> %D1, (%A1) */'
+#  "emit"      => '. LDRB %D1, %S1, %O\t\t\t/* Load((%S1)) -> %D1, (%A1) */'
+},
+
+"Loadbs" => {
+  "op_flags"  => "L|F",
+  "irn_flags" => "R",
+  "state"     => "exc_pinned",
+  "comment"   => "construct Load: Load(ptr, mem) = LD ptr -> reg",
+  "reg_req"   => { "in" => [ "general_purpose", "none" ], "out" => [ "general_purpose" ] },
+  "emit"      => '. LDRSB %D1, [%S1, #0]\t\t\t/* Load((%S1)) -> %D1, (%A1) */'
+#  "emit"      => '. LDRSB %D1, %S1, %O\t\t\t/* Load((%S1)) -> %D1, (%A1) */'
+},
+
+"Loadh" => {
+  "op_flags"  => "L|F",
+  "irn_flags" => "R",
+  "state"     => "exc_pinned",
+  "comment"   => "construct Load: Load(ptr, mem) = LD ptr -> reg",
+  "reg_req"   => { "in" => [ "general_purpose", "none" ], "out" => [ "general_purpose" ] },
+  "emit"      => '. LDRH %D1, [%S1, #0]\t\t\t/* Load((%S1)) -> %D1, (%A1) */'
+#  "emit"      => '. LDRH %D1, %S1, %O\t\t\t/* Load((%S1)) -> %D1, (%A1) */'
+},
+
+"Loadhs" => {
+  "op_flags"  => "L|F",
+  "irn_flags" => "R",
+  "state"     => "exc_pinned",
+  "comment"   => "construct Load: Load(ptr, mem) = LD ptr -> reg",
+  "reg_req"   => { "in" => [ "general_purpose", "none" ], "out" => [ "general_purpose" ] },
+  "emit"      => '. LDRSH %D1, [%S1, #0]\t\t\t/* Load((%S1)) -> %D1, (%A1) */'
+#  "emit"      => '. LDRSH %D1, %S1, %O\t\t\t/* Load((%S1)) -> %D1, (%A1) */'
+},
+
+"Storeb" => {
+  "op_flags"  => "L|F",
+  "irn_flags" => "R",
+  "state"     => "exc_pinned",
+  "comment"   => "construct Store: Store(ptr, val, mem) = ST ptr,val",
+  "reg_req"   => { "in" => [ "general_purpose", "general_purpose", "none" ] },
+  "emit"      => '. STRB %S2, [%S1, #0]\t\t\t/* Store(%S2) -> (%S1), (%A1, %A2) */'
+#  "emit"      => '. movl %S2, %O(%S1)\t\t\t/* Store(%S2) -> (%S1), (%A1, %A2) */'
+},
+
+"Storebs" => {
+  "op_flags"  => "L|F",
+  "irn_flags" => "R",
+  "state"     => "exc_pinned",
+  "comment"   => "construct Store: Store(ptr, val, mem) = ST ptr,val",
+  "reg_req"   => { "in" => [ "general_purpose", "general_purpose", "none" ] },
+  "emit"      => '. STRSB %S2, [%S1, #0]\t\t\t/* Store(%S2) -> (%S1), (%A1, %A2) */'
+#  "emit"      => '. movl %S2, %O(%S1)\t\t\t/* Store(%S2) -> (%S1), (%A1, %A2) */'
+},
+
+"Storeh" => {
+  "op_flags"  => "L|F",
+  "irn_flags" => "R",
+  "state"     => "exc_pinned",
+  "comment"   => "construct Store: Store(ptr, val, mem) = ST ptr,val",
+  "reg_req"   => { "in" => [ "general_purpose", "general_purpose", "none" ] },
+  "emit"      => '. STRH %S2, [%S1, #0]\t\t\t/* Store(%S2) -> (%S1), (%A1, %A2) */'
+#  "emit"      => '. movl %S2, %O(%S1)\t\t\t/* Store(%S2) -> (%S1), (%A1, %A2) */'
+},
+
+"Storehs" => {
+  "op_flags"  => "L|F",
+  "irn_flags" => "R",
+  "state"     => "exc_pinned",
+  "comment"   => "construct Store: Store(ptr, val, mem) = ST ptr,val",
+  "reg_req"   => { "in" => [ "general_purpose", "general_purpose", "none" ] },
+  "emit"      => '. STRSH%S2, [%S1, #0]\t\t\t/* Store(%S2) -> (%S1), (%A1, %A2) */'
+#  "emit"      => '. movl %S2, %O(%S1)\t\t\t/* Store(%S2) -> (%S1), (%A1, %A2) */'
+},
+
+"Store" => {
+  "op_flags"  => "L|F",
+  "irn_flags" => "R",
+  "state"     => "exc_pinned",
+  "comment"   => "construct Store: Store(ptr, val, mem) = ST ptr,val",
+  "reg_req"   => { "in" => [ "general_purpose", "general_purpose", "none" ] },
+  "emit"      => '. STR %S2, [%S1, #0]\t\t\t/* Store(%S2) -> (%S1), (%A1, %A2) */'
+#  "emit"      => '. movl %S2, %O(%S1)\t\t\t/* Store(%S2) -> (%S1), (%A1, %A2) */'
+},
+
+"StoreStackM4Inc" => {
+  "op_flags"  => "L|F",
+  "irn_flags" => "R",
+  "state"     => "exc_pinned",
+  "comment"   => "construct Store: Store(ptr, val, mem) = ST ptr,val",
+  "reg_req"   => { "in" => [ "r13", "general_purpose", "general_purpose", "general_purpose", "general_purpose", "none" ], "out" => [ "general_purpose", "none" ] },
+  "emit"      => '. STMFD %S1!, {%S2, %S3, %S4, %S5}\t\t\t/* Store multiple on Stack*/'
+},
+
+"LoadStackM3" => {
+  "op_flags"  => "L|F",
+  "irn_flags" => "R",
+  "state"     => "exc_pinned",
+  "comment"   => "construct Load: Load(ptr, mem) = LD ptr -> reg",
+  "reg_req"   => { "in" => [ "r13", "none" ], "out" => [ "general_purpose", "general_purpose", "general_purpose", "none" ] },
+  "emit"      => '. LDMFD %S1, {%D1, %D2, %D3}\t\t\t/* Load multiple from Stack */'
+},
+
+
+
+
+
+
+
+
+#--------------------------------------------------------#
+#    __ _             _                     _            #
+#   / _| |           | |                   | |           #
+#  | |_| | ___   __ _| |_   _ __   ___   __| | ___  ___  #
+#  |  _| |/ _ \ / _` | __| | '_ \ / _ \ / _` |/ _ \/ __| #
+#  | | | | (_) | (_| | |_  | | | | (_) | (_| |  __/\__ \ #
+#  |_| |_|\___/ \__,_|\__| |_| |_|\___/ \__,_|\___||___/ #
+#--------------------------------------------------------#
+
+# commutative operations
+
+"fAddd" => {
+  "op_flags"  => "C",
+  "irn_flags" => "R",
+  "comment"   => "construct DP FP Add: Add(a, b) = Add(b, a) = a + b",
+  "reg_req"   => { "in" => [ "floating_point", "floating_point" ], "out" => [ "floating_point" ] },
+  "emit"      => '. FADDD %D1, %S1, %S2\t\t\t/* FP Add(%S1, %S2) -> %D1 */'
+},
+
+"fAdds" => {
+  "op_flags"  => "C",
+  "irn_flags" => "R",
+  "comment"   => "construct SP FP Add: Add(a, b) = Add(b, a) = a + b",
+  "reg_req"   => { "in" => [ "floating_point", "floating_point" ], "out" => [ "floating_point" ] },
+  "emit"      => '. FADDS %D1, %S1, %S2\t\t\t/* FP Add(%S1, %S2) -> %D1 */'
+},
+
+"fMuls" => {
+  "op_flags"  => "C",
+  "comment"   => "construct FP Mul: Mul(a, b) = Mul(b, a) = a * b",
+  "reg_req"   => { "in" => [ "floating_point", "floating_point" ], "out" => [ "floating_point" ] },
+  "emit"      =>'. FMULS %D1, %S1, %S2\t\t\t/* FP Mul(%S1, %S2) -> %D1 */'
+},
+
+"fMuld" => {
+  "op_flags"  => "C",
+  "comment"   => "construct FP Mul: Mul(a, b) = Mul(b, a) = a * b",
+  "reg_req"   => { "in" => [ "floating_point", "floating_point" ], "out" => [ "floating_point" ] },
+  "emit"      =>'. FMULD %D1, %S1, %S2\t\t\t/* FP Mul(%S1, %S2) -> %D1 */'
+},
+
+"fDivs" => {
+  "comment"   => "construct FP Div: Div(a, b) = a / b",
+  "reg_req"   => { "in" => [ "floating_point", "floating_point" ], "out" => [ "floating_point" ] },
+  "emit"      =>'. FDIVS %D1, %S1, %S2\t\t\t/* FP Div(%S1, %S2) -> %D1 */'
+},
+
+"fDivd" => {
+  "comment"   => "construct FP Div: Div(a, b) = a / b",
+  "reg_req"   => { "in" => [ "floating_point", "floating_point" ], "out" => [ "floating_point" ] },
+  "emit"      =>'. FDIVD %D1, %S1, %S2\t\t\t/* FP Div(%S1, %S2) -> %D1 */'
+},
+
+"fDiv" => {
+  "comment"   => "construct FP Div: Div(a, b) = a / b",
+  "reg_req"   => { "in" => [ "floating_point", "floating_point" ], "out" => [ "floating_point" ] },
+  "emit"      =>'. FDIV %D1, %S1, %S2\t\t\t/* FP Div(%S1, %S2) -> %D1 */'
+},
+
+"fMax" => {
+  "op_flags"  => "C",
+  "irn_flags" => "R",
+  "comment"   => "construct FP Max: Max(a, b) = Max(b, a) = a > b ? a : b",
+  "reg_req"   => { "in" => [ "floating_point", "floating_point" ], "out" => [ "floating_point" ] },
+  "emit"      =>'. fmax %S1, %S2, %D1\t\t\t/* FP Max(%S1, %S2) -> %D1 */'
+},
+
+"fMin" => {
+  "op_flags"  => "C",
+  "irn_flags" => "R",
+  "comment"   => "construct FP Min: Min(a, b) = Min(b, a) = a < b ? a : b",
+  "reg_req"   => { "in" => [ "floating_point", "floating_point" ], "out" => [ "floating_point" ] },
+  "emit"      =>'. fmin %S1, %S2, %D1\t\t\t/* FP Min(%S1, %S2) -> %D1 */'
+},
+
+# not commutative operations
+
+"fSubs" => {
+  "irn_flags" => "R",
+  "comment"   => "construct FP Sub: Sub(a, b) = a - b",
+  "reg_req"   => { "in" => [ "floating_point", "floating_point" ], "out" => [ "floating_point" ] },
+  "emit"      => '. FSUBS %D1, %S1, %S2\t\t\t/* FP Sub(%S1, %S2) -> %D1 */'
+},
+
+"fSubd" => {
+  "irn_flags" => "R",
+  "comment"   => "construct FP Sub: Sub(a, b) = a - b",
+  "reg_req"   => { "in" => [ "floating_point", "floating_point" ], "out" => [ "floating_point" ] },
+  "emit"      => '. FSUBD %D1, %S1, %S2\t\t\t/* FP Sub(%S1, %S2) -> %D1 */'
+},
+
+"fMinus" => {
+  "irn_flags" => "R",
+  "comment"   => "construct FP Minus: Minus(a) = -a",
+  "reg_req"   => { "in" => [ "floating_point" ], "out" => [ "floating_point" ] },
+  "emit"      => '. fneg %S1, %D1\t\t\t/* FP Minus(%S1) -> %D1 */'
+},
+
+"fAbss" => {
+  "irn_flags" => "R",
+  "comment"   => "construct FP Absolute value: fAbss(a) = |a|",
+  "reg_req"   => { "in" => [ "floating_point" ], "out" => [ "floating_point" ] },
+  "emit"      => '. FABSS %D1, %S1\t\t\t/* FP Abss(%S1) -> %D1 */'
+},
+
+"fAbsd" => {
+  "irn_flags" => "R",
+  "comment"   => "construct FP Absolute value: fAbsd(a) = |a|",
+  "reg_req"   => { "in" => [ "floating_point" ], "out" => [ "floating_point" ] },
+  "emit"      => '. FABSD %D1, %S1\t\t\t/* FP Absd(%S1) -> %D1 */'
+},
+
+# other operations
+
+"fConst" => {
+  "op_flags"  => "c",
+  "irn_flags" => "R",
+  "comment"   => "represents a FP constant",
+  "reg_req"   => { "out" => [ "floating_point" ] },
+  "emit"      => '. FMOV %D1, %C\t\t\t/* Mov fConst into register */',
+  "cmp_attr"  =>
+'    if (attr_a->value == NULL || attr_b->value == NULL)
+           return 1;
+
+       return get_tarval_double(attr_a->value) != get_tarval_double(attr_b->value);'
+},
+
+"fConvD2S" => {
+  "irn_flags" => "R",
+  "comment"   => "convert double to single",
+  "reg_req"   => { "in" => [ "floating_point" ], "out" => [ "floating_point" ] },
+  "emit"      => '. FCVTSD %D1, %S1\t\t\t/* Convert double to single */',
+},
+
+"fConvS2D" => {
+  "irn_flags" => "R",
+  "comment"   => "convert single to double",
+  "reg_req"   => { "in" => [ "floating_point" ], "out" => [ "floating_point" ] },
+  "emit"      => '. FCVTDS %D1, %S1\t\t\t/* Convert single to double */',
+},
+
+
+# Load / Store
+
+"fLoads" => {
+  "op_flags"  => "L|F",
+  "irn_flags" => "R",
+  "state"     => "exc_pinned",
+  "comment"   => "construct FP Load: Load(ptr, mem) = LD ptr",
+  "reg_req"   => { "in" => [ "general_purpose", "none" ], "out" => [ "floating_point" ] },
+  "emit"      => '. FLDS %D1, %S1\t\t\t/* Load((%S1)) -> %D1 */'
+#  "emit"      => '. fmov %O(%S1), %D1\t\t\t/* Load((%S1)) -> %D1 */'
+},
+
+"fLoadd" => {
+  "op_flags"  => "L|F",
+  "irn_flags" => "R",
+  "state"     => "exc_pinned",
+  "comment"   => "construct FP Load: Load(ptr, mem) = LD ptr",
+  "reg_req"   => { "in" => [ "general_purpose", "none" ], "out" => [ "floating_point" ] },
+  "emit"      => '. FLDD %D1, %S1\t\t\t/* Load((%S1)) -> %D1 */'
+#  "emit"      => '. fmov %O(%S1), %D1\t\t\t/* Load((%S1)) -> %D1 */'
+},
+
+"fStores" => {
+  "op_flags"  => "L|F",
+  "irn_flags" => "R",
+  "state"     => "exc_pinned",
+  "comment"   => "construct Store: Store(ptr, val, mem) = ST ptr,val",
+  "reg_req"   => { "in" => [ "general_purpose", "floating_point", "none" ] },
+  "emit"      => '. FSTS %S2, %S1\t\t\t/* Store(%S2) -> (%S1), (%A1, %A2) */'
+},
+
+"fStored" => {
+  "op_flags"  => "L|F",
+  "irn_flags" => "R",
+  "state"     => "exc_pinned",
+  "comment"   => "construct Store: Store(ptr, val, mem) = ST ptr,val",
+  "reg_req"   => { "in" => [ "general_purpose", "floating_point", "none" ] },
+  "emit"      => '. FSTD %S2, %S1\t\t\t/* Store(%S2) -> (%S1), (%A1, %A2) */'
+},
+
+); # end of %nodes
diff --git a/ir/be/arm/arm_transform.c b/ir/be/arm/arm_transform.c
new file mode 100644 (file)
index 0000000..2775d61
--- /dev/null
@@ -0,0 +1,1064 @@
+/* The codegenrator (transform FIRM into arm FIRM */
+/* $Id$ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#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 "bearch_arm_t.h"
+
+#include "arm_nodes_attr.h"
+#include "../arch/archop.h"     /* we need this for Min and Max nodes */
+#include "arm_transform.h"
+#include "arm_new_nodes.h"
+#include "arm_map_regs.h"
+
+#include "gen_arm_regalloc_if.h"
+
+#include <limits.h>
+
+extern ir_op *get_op_Mulh(void);
+
+
+
+/****************************************************************************************************
+ *                  _        _                        __                           _   _
+ *                 | |      | |                      / _|                         | | (_)
+ *  _ __   ___   __| | ___  | |_ _ __ __ _ _ __  ___| |_ ___  _ __ _ __ ___   __ _| |_ _  ___  _ __
+ * | '_ \ / _ \ / _` |/ _ \ | __| '__/ _` | '_ \/ __|  _/ _ \| '__| '_ ` _ \ / _` | __| |/ _ \| '_ \
+ * | | | | (_) | (_| |  __/ | |_| | | (_| | | | \__ \ || (_) | |  | | | | | | (_| | |_| | (_) | | | |
+ * |_| |_|\___/ \__,_|\___|  \__|_|  \__,_|_| |_|___/_| \___/|_|  |_| |_| |_|\__,_|\__|_|\___/|_| |_|
+ *
+ ****************************************************************************************************/
+
+
+
+
+
+typedef struct vals_ {
+     int ops;
+     unsigned char values[4];
+     unsigned char shifts[4];
+} vals;
+
+static vals construct_vals() {
+     vals result = {0, {0, 0, 0, 0}, {0, 0, 0, 0}};
+     return result;
+}
+
+static vals gen_vals_from_word(unsigned int value)
+{
+     vals result = construct_vals();
+     int cur_offset = 0;
+     while (value != 0) {
+          if ((value & 3) == 0) {
+               cur_offset += 2;
+               value >>= 2;
+          } else {
+               result.values[result.ops] = value & 0xff;
+               result.shifts[result.ops] = cur_offset;
+               ++result.ops;
+               value >>= 8;
+               cur_offset += 8;
+          }
+     }
+     return result;
+}
+
+static ir_node *create_const_node(arm_transform_env_t *env, int value) {
+               ir_node *result = new_rd_arm_Const(env->dbg, env->irg, env->block, env->mode);
+               get_arm_attr(result)->value = new_tarval_from_long(value, env->mode);
+               return result;
+}
+
+#define NEW_BINOP_NODE(opname, env, op1, op2) new_rd_arm_##opname(env->dbg, env->irg, env->block, op1, op2, env->mode)
+
+unsigned int create_shifter_operand(unsigned int shift, unsigned int immediate) {
+       return immediate | ((shift>>1)<<8);
+}
+
+static ir_node *create_const_graph_value(arm_transform_env_t *env, unsigned int value) {
+       ir_node *result;
+       int negate = 0;
+
+       if (value < 0x100 || ~value < 0x100 ) {
+               if ( ~value < 0x100 ) {
+                       negate = 1;
+                       value = ~value;
+               }
+               result = create_const_node(env, value);
+       } else {
+               vals v;
+               vals v1 = gen_vals_from_word(value);
+               vals v2 = gen_vals_from_word(~value);
+               int cnt = 0;
+               if (v2.ops == 1) {
+                       result = new_rd_arm_Const_Neg(env->dbg, env->irg, env->block, env->mode);
+                       set_arm_value(result, new_tarval_from_long(create_shifter_operand(v2.shifts[0], v2.values[0]), mode_Iu));
+               } else {
+                       if ( v2.ops < v1.ops ) {
+                               negate = 1;
+                               v = v2;
+                       } else {
+                               v = v1;
+                       }
+                       if (v.shifts[cnt] == 0) {
+                               result = create_const_node(env, v.values[cnt]);
+                       } else {
+                               result = create_const_node(env, create_shifter_operand(v.shifts[cnt], v.values[cnt]));
+                       }
+                       ++cnt;
+                       while(cnt < v.ops) {
+                               ir_node *const_node = create_const_node(env, v.values[cnt]);
+                               ir_node *orr_i_node = new_rd_arm_Or_i(env->dbg, env->irg, env->block, result, env->mode);
+                               set_arm_value(orr_i_node, new_tarval_from_long(create_shifter_operand(v.shifts[cnt], v.values[cnt]), mode_Iu));
+                               result = orr_i_node;
+                               ++cnt;
+                       }
+               }
+       }
+       if ( negate ) {
+               result = new_rd_arm_Not(env->dbg, env->irg, env->block, result, env->mode);
+       }
+       return result;
+}
+
+// static ir_node *create_const_graph_value(arm_transform_env_t *env, unsigned int value) {
+//     ir_node *irn = env->irn;
+//     ir_node *result;
+//     int negate = 0;
+//
+//     if ( ~value < 0x100 ) {
+//             negate = 1;
+//             value = ~value;
+//     }
+//
+//     if (value < 0x100) {
+//             return create_const_node(env, value);
+//     } else {
+//             vals v = gen_vals_from_word(value);
+//             int cnt = 0;
+//             ir_node *mov_val = create_const_node(env, v.values[cnt]);
+//             if (v.shifts[cnt] != 0) {
+//                     ir_node *shift_node = new_rd_arm_Shl_i(env->dbg, env->irg, env->block, mov_val, env->mode);
+//                     set_arm_value(shift_node, new_tarval_from_long(v.shifts[cnt], mode_Iu));
+//                     result = shift_node;
+//             } else {
+//                     result = mov_val;
+//             }
+//             ++cnt;
+//             while(cnt < v.ops) {
+//                     ir_node *const_node = create_const_node(env, v.values[cnt]);
+//                     ir_node *orr_i_node = new_rd_arm_Or_i(env->dbg, env->irg, env->block, result, env->mode);
+//                     unsigned shift = v.shifts[cnt];
+//                     unsigned immediate = v.values[cnt];
+//                     unsigned immediate_with_shift = immediate | ((shift>>1)<<8);
+//                     set_arm_value(orr_i_node, new_tarval_from_long(immediate_with_shift, mode_Iu));
+//                     result = orr_i_node;
+//                     ++cnt;
+//             }
+//             return result;
+//     }
+// }
+
+static ir_node *create_const_graph(arm_transform_env_t *env) {
+       int value = get_tarval_long(get_Const_tarval(env->irn));
+       return create_const_graph_value(env, value);
+}
+
+
+
+static ir_node *gen_Const(arm_transform_env_t *env) {
+       ir_node *result;
+       assert(env->mode != mode_E && "IEEE Extended FP not supported");
+       if (env->mode == mode_F) {
+               result = new_rd_arm_fConst(env->dbg, env->irg, env->block, env->mode);
+               get_arm_attr(result)->value = get_Const_tarval(env->irn);
+       } else if (env->mode == mode_D) {
+               result = new_rd_arm_fConst(env->dbg, env->irg, env->block, env->mode);
+               get_arm_attr(result)->value = get_Const_tarval(env->irn);
+       } else if (env->mode == mode_P) {
+               return env->irn;
+       } else {
+               result = create_const_graph(env);
+       }
+       return result;
+}
+
+static ir_node *gen_mask(arm_transform_env_t *env, ir_node *op, int result_bits) {
+       unsigned mask_bits = (1 << result_bits) - 1;
+       ir_node *mask_node = create_const_graph_value(env, mask_bits);
+       return new_rd_arm_And(env->dbg, env->irg, env->block, op, mask_node, get_irn_mode(env->irn));
+}
+
+static ir_node *gen_sign_extension(arm_transform_env_t *env, ir_node *op, int result_bits) {
+       int shift_width = 32 - result_bits;
+       ir_node *shift_const_node = create_const_graph_value(env, shift_width);
+       ir_node *lshift_node = new_rd_arm_Shl(env->dbg, env->irg, env->block, op, shift_const_node, get_irn_mode(op));
+       ir_node *rshift_node = new_rd_arm_Shrs(env->dbg, env->irg, env->block, lshift_node, shift_const_node, get_irn_mode(env->irn));
+       return rshift_node;
+}
+
+static ir_node *gen_Conv(arm_transform_env_t *env, ir_node *op) {
+       ir_mode *in_mode = get_irn_mode(op);
+       ir_mode *out_mode = env->mode;
+
+       assert( in_mode != mode_E && "");
+       assert( in_mode != mode_Ls && "");
+       assert( in_mode != mode_Lu && "");
+       assert( out_mode != mode_E && "");
+       assert( out_mode != mode_Ls && "");
+       assert( out_mode != mode_Lu && "");
+
+       if (in_mode == out_mode)
+               return op;
+
+       if ((mode_is_int(in_mode) || mode_is_reference(in_mode))
+               && (mode_is_reference(out_mode) || mode_is_int(out_mode))) {
+               int in_bits = get_mode_size_bits(in_mode);
+               int out_bits = get_mode_size_bits(out_mode);
+               int in_sign = get_mode_sign(in_mode);
+               int out_sign = get_mode_sign(out_mode);
+
+               // 32 -> 32
+                       // NOPpen
+               if (in_bits == out_bits && in_bits == 32)
+                       return op;
+
+               // 16 -> 16
+                       // unsigned -> unsigned
+                               // NOP
+                       // unsigned -> signed
+                               // sign extension (31:16)=(15)
+                       // signed -> unsigned
+                               // maskieren (31:16)=0
+                       // signed -> signed
+                               // NOP
+               if (in_bits == out_bits && out_bits < 32) {
+                       if (in_sign && !out_sign) {
+                               return gen_mask(env, op, out_bits);
+                       } else {
+                               return gen_sign_extension(env, op, out_bits);
+                       }
+               }
+
+               // 16 -> 32
+                       // unsigned -> unsigned
+                               // NOP
+                       // unsigned -> signed
+                               // NOP
+                       // signed -> unsigned
+                               // sign extension (31:16)=(15)
+                       // signed -> signed
+                               // sign extension (31:16)=(15)
+               if (in_bits < out_bits) {
+                       if (in_sign) {
+                               return gen_sign_extension(env, op, out_bits);
+                       } else {
+                               return op;
+                       }
+               }
+
+               // 32 -> 16
+                       // unsigned -> unsigned
+                               // maskieren (31:16)=0
+                       // unsigned -> signed
+                               // maskieren (31:16)=0
+                       // signed -> unsigned
+                               // maskieren (31:16)=0
+                       // signed -> signed
+                               // sign extension (erledigt auch maskieren) (31:16)=(15)
+               if (in_bits > out_bits) {
+                       if (in_sign && out_sign) {
+                               return gen_sign_extension(env, op, out_bits);
+                       } else {
+                               return gen_mask(env, op, out_bits);
+                       }
+               }
+               assert(0 && "recheck integer conversion logic!");
+               return env->irn;
+       } else if (in_mode == mode_D && out_mode == mode_F) {
+               return new_rd_arm_fConvD2S(env->dbg, env->irg, env->block, op, env->mode);
+       } else if (in_mode == mode_F && out_mode == mode_D) {
+               return new_rd_arm_fConvS2D(env->dbg, env->irg, env->block, op, env->mode);
+       } else if (mode_is_int(in_mode) && mode_is_float(out_mode)) {
+               return env->irn; /* TODO: implement int->float conversion*/
+       } else if (mode_is_float(in_mode) && mode_is_int(out_mode)) {
+               return env->irn; /* TODO: implement float->int conversion*/
+       } else {
+               assert(0 && "not implemented conversion");
+               return env->irn;
+       }
+}
+
+
+/**
+ * Creates an arm Add.
+ *
+ * @param env   The transformation environment
+ * @param op1   first operator
+ * @param op2   second operator
+ * @return the created arm Add node
+ */
+static ir_node *gen_Add(arm_transform_env_t *env, ir_node *op1, ir_node *op2) {
+       ir_node *result = NULL;
+       assert(!mode_is_float(env->mode) || (get_irn_mode(op1)->sort == get_irn_mode(op2)->sort));
+       assert(env->mode != mode_E && "IEEE Extended FP not supported");
+
+       if (env->mode == mode_F) {
+               result = new_rd_arm_fAdds(env->dbg, env->irg, env->block, op1, op2, env->mode);
+       } else if (env->mode == mode_D) {
+               result = new_rd_arm_fAddd(env->dbg, env->irg, env->block, op1, op2, env->mode);
+       } else if (mode_is_numP(env->mode)) {
+               if (is_arm_Const(op1)) {
+                       result = new_rd_arm_Add_i(env->dbg, env->irg, env->block, op2, env->mode);
+                       set_arm_value(result, get_arm_value(op1));
+               } else if (is_arm_Const(op2)) {
+                       result = new_rd_arm_Add_i(env->dbg, env->irg, env->block, op1, env->mode);
+                       set_arm_value(result, get_arm_value(op2));
+               } else {
+                       result = new_rd_arm_Add(env->dbg, env->irg, env->block, op1, op2, env->mode);
+               }
+       } else {
+               assert(0 && "unknown mode for add");
+       }
+       return result;
+}
+
+
+
+/**
+ * Creates an arm Mul.
+ *
+ * @param dbg       firm node dbg
+ * @param block     the block the new node should belong to
+ * @param op1       first operator
+ * @param op2       second operator
+ * @param mode      node mode
+ * @return the created arm Mul node
+ */
+static ir_node *gen_Mul(arm_transform_env_t *env, ir_node *op1, ir_node *op2) {
+       assert(!mode_is_float(env->mode) || (get_irn_mode(op1)->sort == get_irn_mode(op2)->sort));
+       assert(env->mode != mode_E && "IEEE Extended FP not supported");
+
+       if (env->mode == mode_F) {
+               return new_rd_arm_fMuls(env->dbg, env->irg, env->block, op1, op2, env->mode);
+       }
+       if (env->mode == mode_D) {
+               return new_rd_arm_fMuld(env->dbg, env->irg, env->block, op1, op2, env->mode);
+       }
+       return new_rd_arm_Mul(env->dbg, env->irg, env->block, op1, op2, env->mode);
+}
+
+
+/**
+ * Creates an arm floating Div.
+ *
+ * @param dbg       firm node dbg
+ * @param block     the block the new node should belong to
+ * @param op1       first operator
+ * @param op2       second operator
+ * @param mode      node mode
+ * @return the created arm fDiv node
+ */
+static ir_node *gen_Quot(arm_transform_env_t *env, ir_node *op1, ir_node *op2) {
+       // assert(mode_is_float(env->mode) && "only floating point supported");
+       assert(get_irn_mode(op1)->sort == get_irn_mode(op2)->sort);
+       assert(mode_is_float(get_irn_mode(op1)));
+       assert(get_irn_mode(op1) != mode_E && "IEEE Extended FP not supported");
+
+       if (get_irn_mode(op1) == mode_F) {
+               return new_rd_arm_fDivs(env->dbg, env->irg, env->block, op1, op2, env->mode);
+       }
+       return new_rd_arm_fDivd(env->dbg, env->irg, env->block, op1, op2, env->mode);
+}
+
+
+/**
+ * Creates an arm And.
+ *
+ * @param dbg       firm node dbg
+ * @param block     the block the new node should belong to
+ * @param op1       first operator
+ * @param op2       second operator
+ * @param mode      node mode
+ * @return the created arm And node
+ */
+static ir_node *gen_And(arm_transform_env_t *env, ir_node *op1, ir_node *op2) {
+       ir_node *result;
+       if (is_arm_Const(op1)) {
+               result = new_rd_arm_And_i(env->dbg, env->irg, env->block, op2, env->mode);
+               set_arm_value(result, get_arm_value(op1));
+       } else if (is_arm_Const(op2)) {
+               result = new_rd_arm_And_i(env->dbg, env->irg, env->block, op1, env->mode);
+               set_arm_value(result, get_arm_value(op2));
+       } else {
+               result = new_rd_arm_And(env->dbg, env->irg, env->block, op1, op2, env->mode);
+       }
+       return result;
+}
+
+
+
+/**
+ * Creates an arm Or.
+ *
+ * @param dbg       firm node dbg
+ * @param block     the block the new node should belong to
+ * @param op1       first operator
+ * @param op2       second operator
+ * @param mode      node mode
+ * @return the created arm Or node
+ */
+static ir_node *gen_Or(arm_transform_env_t *env, ir_node *op1, ir_node *op2) {
+       ir_node *result;
+       if (is_arm_Const(op1)) {
+               result = new_rd_arm_Or_i(env->dbg, env->irg, env->block, op2, env->mode);
+               set_arm_value(result, get_arm_value(op1));
+       } else if (is_arm_Const(op2)) {
+               result = new_rd_arm_Or_i(env->dbg, env->irg, env->block, op1, env->mode);
+               set_arm_value(result, get_arm_value(op2));
+       } else {
+               result = new_rd_arm_Or(env->dbg, env->irg, env->block, op1, op2, env->mode);
+       }
+       return result;
+}
+
+
+
+/**
+ * Creates an arm Eor.
+ *
+ * @param dbg       firm node dbg
+ * @param block     the block the new node should belong to
+ * @param op1       first operator
+ * @param op2       second operator
+ * @param mode      node mode
+ * @return the created arm Eor node
+ */
+static ir_node *gen_Eor(arm_transform_env_t *env, ir_node *op1, ir_node *op2) {
+       ir_node *result;
+       if (is_arm_Const(op1)) {
+               result = new_rd_arm_Eor_i(env->dbg, env->irg, env->block, op2, env->mode);
+               set_arm_value(result, get_arm_value(op1));
+       } else if (is_arm_Const(op2)) {
+               result = new_rd_arm_Eor_i(env->dbg, env->irg, env->block, op1, env->mode);
+               set_arm_value(result, get_arm_value(op2));
+       } else {
+               result = new_rd_arm_Eor(env->dbg, env->irg, env->block, op1, op2, env->mode);
+       }
+       return result;
+}
+
+
+
+/**
+ * Creates an arm Sub.
+ *
+ * @param dbg       firm node dbg
+ * @param block     the block the new node should belong to
+ * @param op1       first operator
+ * @param op2       second operator
+ * @param mode      node mode
+ * @return the created arm Sub node
+ */
+static ir_node *gen_Sub(arm_transform_env_t *env, ir_node *op1, ir_node *op2) {
+       ir_node *result = NULL;
+       assert(!mode_is_float(env->mode) || (get_irn_mode(op1)->sort == get_irn_mode(op2)->sort));
+       assert(env->mode != mode_E && "IEEE Extended FP not supported");
+
+       if (env->mode == mode_F) {
+               result = new_rd_arm_fSubs(env->dbg, env->irg, env->block, op1, op2, env->mode);
+       } else if (env->mode == mode_D) {
+               result = new_rd_arm_fSubd(env->dbg, env->irg, env->block, op1, op2, env->mode);
+       } else if (mode_is_numP(env->mode)) {
+               if (is_arm_Const(op2)) {
+                       result = new_rd_arm_Sub_i(env->dbg, env->irg, env->block, op1, env->mode);
+                       set_arm_value(result, get_arm_value(op2));
+               } else {
+                       result = new_rd_arm_Sub(env->dbg, env->irg, env->block, op1, op2, env->mode);
+               }
+       } else {
+               assert(0 && "unknown mode for sub");
+       }
+       return result;
+}
+
+/**
+ * Creates an arm Shl.
+ *
+ * @param dbg       firm node dbg
+ * @param block     the block the new node should belong to
+ * @param op1       first operator
+ * @param op2       second operator
+ * @param mode      node mode
+ * @return the created arm Shl node
+ */
+static ir_node *gen_Shl(arm_transform_env_t *env, ir_node *op1, ir_node *op2) {
+       ir_node *result;
+       if (is_arm_Const(op2)) {
+               result = new_rd_arm_Shl_i(env->dbg, env->irg, env->block, op1, env->mode);
+               set_arm_value(result, get_arm_value(op2));
+       } else {
+               result = new_rd_arm_Shl(env->dbg, env->irg, env->block, op1, op2, env->mode);
+       }
+       return result;
+}
+
+
+
+/**
+ * Creates an arm Shr.
+ *
+ * @param dbg       firm node dbg
+ * @param block     the block the new node should belong to
+ * @param op1       first operator
+ * @param op2       second operator
+ * @param mode      node mode
+ * @return the created arm Shr node
+ */
+static ir_node *gen_Shr(arm_transform_env_t *env, ir_node *op1, ir_node *op2) {
+       ir_node *result;
+       if (is_arm_Const(op2)) {
+               result = new_rd_arm_Shr_i(env->dbg, env->irg, env->block, op1, env->mode);
+               set_arm_value(result, get_arm_value(op2));
+       } else {
+               result = new_rd_arm_Shr(env->dbg, env->irg, env->block, op1, op2, env->mode);
+       }
+       return result;
+}
+
+/**
+ * Creates an arm Shrs.
+ *
+ * @param dbg       firm node dbg
+ * @param block     the block the new node should belong to
+ * @param op1       first operator
+ * @param op2       second operator
+ * @param mode      node mode
+ * @return the created arm Shrs node
+ */
+static ir_node *gen_Shrs(arm_transform_env_t *env, ir_node *op1, ir_node *op2) {
+       ir_node *result;
+       if (is_arm_Const(op2)) {
+               result = new_rd_arm_Shrs_i(env->dbg, env->irg, env->block, op1, env->mode);
+               set_arm_value(result, get_arm_value(op2));
+       } else {
+               result = new_rd_arm_Shrs(env->dbg, env->irg, env->block, op1, op2, env->mode);
+       }
+       return result;
+}
+
+/**
+ * Transforms a Not node.
+ *
+ * @param mod     the debug module
+ * @param block   the block the new node should belong to
+ * @param node    the ir Not node
+ * @param op      operator
+ * @param mode    node mode
+ * @return the created arm Not node
+ */
+static ir_node *gen_Not(arm_transform_env_t *env, ir_node *op) {
+       return new_rd_arm_Not(env->dbg, env->irg, env->block, op, env->mode);
+}
+
+
+static ir_node *gen_Abs(arm_transform_env_t *env, ir_node *op) {
+       assert(env->mode != mode_E && "IEEE Extended FP not supported");
+
+       if (env->mode == mode_F) {
+               return new_rd_arm_fAbss(env->dbg, env->irg, env->block, op, env->mode);
+       }
+       if (env->mode == mode_D) {
+               return new_rd_arm_fAbsd(env->dbg, env->irg, env->block, op, env->mode);
+       }
+
+       return new_rd_arm_Abs(env->dbg, env->irg, env->block, op, env->mode);
+}
+
+
+/**
+ * Transforms a Minus node.
+ *
+ * @param mod     the debug module
+ * @param block   the block the new node should belong to
+ * @param node    the ir Minus node
+ * @param op      operator
+ * @param mode    node mode
+ * @return the created arm Minus node
+ */
+static ir_node *gen_Minus(arm_transform_env_t *env, ir_node *op) {
+       if (mode_is_float(env->mode)) {
+               return new_rd_arm_fMinus(env->dbg, env->irg, env->block, op, env->mode);
+       }
+       return new_rd_arm_Minus(env->dbg, env->irg, env->block, op, env->mode);
+}
+
+
+/**
+ * Transforms a Load.
+ *
+ * @param mod     the debug module
+ * @param block   the block the new node should belong to
+ * @param node    the ir Load node
+ * @param mode    node mode
+ * @return the created arm Load node
+ */
+static ir_node *gen_Load(arm_transform_env_t *env) {
+       ir_node *node = env->irn;
+       ir_mode *mode = get_Load_mode(node);
+
+//     const ir_edge_t *edge;
+//
+//     foreach_out_edge(node, edge) {
+//             ir_node* proj = get_edge_src_irn(edge);
+//             long nr = get_Proj_proj(proj);
+//             if ( nr == pn_Load_res )
+//                     mode = proj->mode;
+//     }
+//     besser: get_Load_mode() verwenden!
+
+       assert(mode!=NULL && "irgendwie hat das load kein proj fuers result");
+       if (mode==mode_F) {
+               return new_rd_arm_fLoads(env->dbg, env->irg, env->block, get_Load_ptr(node), get_Load_mem(node), env->mode);
+       }
+       if (mode==mode_D) {
+               return new_rd_arm_fLoadd(env->dbg, env->irg, env->block, get_Load_ptr(node), get_Load_mem(node), env->mode);
+       }
+       if (mode == mode_Bu) {
+               return new_rd_arm_Loadb(env->dbg, env->irg, env->block, get_Load_ptr(node), get_Load_mem(node), env->mode);
+       }
+       if (mode == mode_Bs) {
+               return new_rd_arm_Loadbs(env->dbg, env->irg, env->block, get_Load_ptr(node), get_Load_mem(node), env->mode);
+       }
+       if (mode == mode_Hu) {
+               return new_rd_arm_Loadh(env->dbg, env->irg, env->block, get_Load_ptr(node), get_Load_mem(node), env->mode);
+       }
+       if (mode == mode_Hs) {
+               return new_rd_arm_Loadhs(env->dbg, env->irg, env->block, get_Load_ptr(node), get_Load_mem(node), env->mode);
+       }
+       if (mode_is_reference(mode)) {
+               return new_rd_arm_Load(env->dbg, env->irg, env->block, get_Load_ptr(node), get_Load_mem(node), env->mode);
+       }
+       return new_rd_arm_Load(env->dbg, env->irg, env->block, get_Load_ptr(node), get_Load_mem(node), env->mode);
+}
+
+
+
+/**
+ * Transforms a Store.
+ *
+ * @param mod     the debug module
+ * @param block   the block the new node should belong to
+ * @param node    the ir Store node
+ * @param mode    node mode
+ * @return the created arm Store node
+ */
+static ir_node *gen_Store(arm_transform_env_t *env) {
+       ir_node *node = env->irn;
+       ir_mode *mode = get_irn_mode(get_Store_value(node));
+       assert(env->mode != mode_E && "IEEE Extended FP not supported");
+
+       if (mode == mode_F) {
+               return new_rd_arm_fStores(env->dbg, env->irg, env->block, get_Store_ptr(node), get_Store_value(node), get_Store_mem(node), env->mode);
+       }
+       if (mode == mode_D) {
+               return new_rd_arm_fStored(env->dbg, env->irg, env->block, get_Store_ptr(node), get_Store_value(node), get_Store_mem(node), env->mode);
+       }
+       if (mode == mode_Bu) {
+               return new_rd_arm_Storeb(env->dbg, env->irg, env->block, get_Store_ptr(node), get_Store_value(node), get_Store_mem(node), env->mode);
+       }
+       if (mode == mode_Bs) {
+               return new_rd_arm_Storebs(env->dbg, env->irg, env->block, get_Store_ptr(node), get_Store_value(node), get_Store_mem(node), env->mode);
+       }
+       if (mode == mode_Hu) {
+               return new_rd_arm_Storeh(env->dbg, env->irg, env->block, get_Store_ptr(node), get_Store_value(node), get_Store_mem(node), env->mode);
+       }
+       if (mode == mode_Hs) {
+               return new_rd_arm_Storehs(env->dbg, env->irg, env->block, get_Store_ptr(node), get_Store_value(node), get_Store_mem(node), env->mode);
+       }
+       return new_rd_arm_Store(env->dbg, env->irg, env->block, get_Store_ptr(node), get_Store_value(node), get_Store_mem(node), env->mode);
+}
+
+
+static ir_node *gen_Cond(arm_transform_env_t *env) {
+       ir_node *result = NULL;
+       ir_node *selector = get_Cond_selector(env->irn);
+       ir_node *irn = env->irn;
+       if ( get_irn_mode(selector) == mode_b ) {
+               //CondJmp
+               ir_node *proj_node = get_Cond_selector(irn);
+               ir_mode *proj_mode = get_irn_mode(proj_node);
+               ir_node *cmp_node = get_Proj_pred(proj_node);
+               ir_node *op1 = get_Cmp_left(cmp_node);
+               ir_node *op2 = get_Cmp_right(cmp_node);
+               result = new_rd_arm_CondJmp(env->dbg, env->irg, env->block, op1, op2, mode_T);
+               set_arm_proj_num(result, get_Proj_proj(proj_node));
+       } else {
+               //SwitchJmp
+               ir_node *op = get_irn_n(env->irn, 0);
+               ir_node *const_graph;
+               ir_node *sub;
+               ir_node *const_node;
+
+               ir_node *proj;
+               const ir_edge_t *edge;
+               int min = INT_MAX;
+               int max = INT_MIN;
+               int translation;
+               int norm_max;
+               int norm_min;
+               int pn;
+               arm_transform_env_t const_env;
+               int n_projs;
+               ir_node **projs;
+
+               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);
+
+                       min = pn<min ? pn : min;
+                       max = pn>max ? pn : max;
+               }
+               translation = min;
+               norm_max = max - translation;
+               norm_min = min - translation;
+
+               n_projs = norm_max + 1;
+               projs = xcalloc(n_projs , sizeof(ir_node*));
+
+
+               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) - translation;
+                       set_Proj_proj(proj, pn);
+               }
+
+
+               const_node = new_rd_Const(env->dbg, env->irg, env->block, mode_Iu, new_tarval_from_long(translation, mode_Iu));
+               const_env = *env;
+               const_env.mode = mode_Is;
+               const_env.irn = const_node;
+               const_graph = gen_Const(&const_env);
+               sub = new_rd_arm_Sub(env->dbg, env->irg, env->block, op, const_graph, get_irn_mode(op));
+               result = new_rd_arm_SwitchJmp(env->dbg, env->irg, env->block, sub, mode_T);
+               set_arm_n_projs(result, n_projs);
+               set_arm_default_proj_num(result, get_Cond_defaultProj(irn)-translation);
+       }
+       return result;
+}
+
+/**
+ * Returns the name of a SymConst.
+ * @param symc  the SymConst
+ * @return name of the SymConst
+ */
+const char *get_sc_name(ir_node *symc) {
+       if (get_irn_opcode(symc) != iro_SymConst)
+               return "NONE";
+
+       switch (get_SymConst_kind(symc)) {
+               case symconst_addr_name:
+                       return get_id_str(get_SymConst_name(symc));
+
+               case symconst_addr_ent:
+                       return get_entity_ld_name(get_SymConst_entity(symc));
+
+               default:
+                       assert(0 && "Unsupported SymConst");
+       }
+
+       return NULL;
+}
+
+static ir_node *gen_SymConst(arm_transform_env_t *env) {
+       ir_node *result;
+       const char *str = get_sc_name(env->irn);
+       result = new_rd_arm_SymConst(env->dbg, env->irg, env->block, env->mode);
+       set_arm_symconst_label(result, str);
+       return result;
+}
+
+
+
+
+
+/**
+ * Transforms a CopyB node.
+ *
+ * @param env   The transformation environment
+ * @return The transformed node.
+ */
+static ir_node *gen_CopyB(arm_transform_env_t *env) {
+       ir_node  *res   = NULL;
+       dbg_info *dbg   = env->dbg;
+       ir_graph *irg   = env->irg;
+       ir_mode  *mode  = env->mode;
+       ir_node  *block = env->block;
+       ir_node  *node  = env->irn;
+       ir_node  *src   = get_CopyB_src(node);
+       ir_node  *dst   = get_CopyB_dst(node);
+       ir_node  *mem   = get_CopyB_mem(node);
+       int       size  = get_type_size_bytes(get_CopyB_type(node));
+       ir_node *src_copy;
+       ir_node *dst_copy;
+
+       arm_transform_env_t const_env;
+       const_env.block    = block;
+       const_env.dbg      = dbg;
+       const_env.irg      = irg;
+       const_env.irn      = node;
+       const_env.mod      = env->mod;
+       const_env.mode     = mode_Iu;
+
+       src_copy = be_new_Copy(&arm_reg_classes[CLASS_arm_general_purpose], irg, block, src);
+       dst_copy = be_new_Copy(&arm_reg_classes[CLASS_arm_general_purpose], irg, block, dst);
+
+       res = new_rd_arm_CopyB( dbg, irg, block, dst_copy, src_copy, new_rd_arm_EmptyReg(dbg, irg, block, mode_Iu), new_rd_arm_EmptyReg(dbg, irg, block, mode_Iu), new_rd_arm_EmptyReg(dbg, irg, block, mode_Iu), mem, mode);
+       set_arm_value(res, new_tarval_from_long(size, mode_Iu));
+
+       return res;
+}
+
+
+
+
+
+// /************************************************************************/
+// /* be transforms                                                        */
+// /************************************************************************/
+//
+// static ir_node *gen_be_Copy(arm_transform_env_t *env, ir_node *op) {
+//     return new_rd_arm_Copy(env->dbg, env->irg, env->block, op, env->mode);
+// }
+
+/*********************************************************
+ *                  _             _      _
+ *                 (_)           | |    (_)
+ *  _ __ ___   __ _ _ _ __     __| |_ __ ___   _____ _ __
+ * | '_ ` _ \ / _` | | '_ \   / _` | '__| \ \ / / _ \ '__|
+ * | | | | | | (_| | | | | | | (_| | |  | |\ V /  __/ |
+ * |_| |_| |_|\__,_|_|_| |_|  \__,_|_|  |_| \_/ \___|_|
+ *
+ *********************************************************/
+
+/************************************************************************/
+/* move constants out of startblock                                       */
+/************************************************************************/
+void arm_move_consts(ir_node *node, void *env) {
+       arm_code_gen_t *cgenv = (arm_code_gen_t *)env;
+       int i;
+       if (is_Block(node))
+               return;
+       if (is_Phi(node)) {
+               for (i=0; i<get_irn_arity(node); i++) {
+                       ir_node *pred = get_irn_n(node,i);
+                       opcode pred_code = get_irn_opcode(pred);
+                       if (pred_code == iro_Const) {
+                               ir_node *const_graph;
+                               arm_transform_env_t tenv;
+                               tenv.block    = get_nodes_block(get_irn_n(get_nodes_block(node),i));
+                               tenv.dbg      = get_irn_dbg_info(pred);
+                               tenv.irg      = current_ir_graph;
+                               tenv.irn      = pred;
+                               tenv.mod      = cgenv->mod;
+                               tenv.mode     = get_irn_mode(pred);
+                               const_graph = create_const_graph(&tenv);
+                               set_irn_n(node, i, const_graph);
+                       } else if (pred_code == iro_SymConst) {
+                               const char *str = get_sc_name(pred);
+                               ir_node *symconst_node;
+                               symconst_node = new_rd_arm_SymConst(get_irn_dbg_info(pred),
+                                       current_ir_graph, get_nodes_block(get_irn_n(get_nodes_block(node),i)), get_irn_mode(pred));
+                               set_arm_symconst_label(symconst_node, str);
+                               set_irn_n(node, i, symconst_node);
+                       }
+               }
+               return;
+       }
+       for (i=0; i<get_irn_arity(node); i++) {
+               ir_node *pred = get_irn_n(node,i);
+               opcode pred_code = get_irn_opcode(pred);
+               if (pred_code == iro_Const) {
+                       ir_node *const_graph;
+                       arm_transform_env_t tenv;
+                       tenv.block    = get_nodes_block(node);
+                       tenv.dbg      = get_irn_dbg_info(pred);
+                       tenv.irg      = current_ir_graph;
+                       tenv.irn      = pred;
+                       tenv.mod      = cgenv->mod;
+                       tenv.mode     = get_irn_mode(pred);
+                       const_graph = create_const_graph(&tenv);
+                       set_irn_n(node, i, const_graph);
+               } else if (pred_code == iro_SymConst) {
+                       const char *str = get_sc_name(pred);
+                       ir_node *symconst_node;
+                       symconst_node = new_rd_arm_SymConst(get_irn_dbg_info(pred),
+                               current_ir_graph, get_nodes_block(node), get_irn_mode(pred));
+                       set_arm_symconst_label(symconst_node, str);
+                       set_irn_n(node, i, symconst_node);
+               }
+       }
+}
+
+
+/************************************************************************/
+/* move symbolic constants out of startblock                            */
+/************************************************************************/
+void arm_move_symconsts(ir_node *node, void *env) {
+       arm_code_gen_t *cgenv = (arm_code_gen_t *)env;
+       int i;
+       if (is_Block(node))
+               return;
+       for (i=0; i<get_irn_arity(node); i++) {
+               ir_node *pred = get_irn_n(node,i);
+               opcode pred_code = get_irn_opcode(pred);
+               if (pred_code == iro_SymConst) {
+                       const char *str = get_sc_name(pred);
+                       ir_node *symconst_node;
+                       symconst_node = new_rd_arm_SymConst(get_irn_dbg_info(pred),
+                               current_ir_graph, get_nodes_block(node), get_irn_mode(pred));
+                       set_arm_symconst_label(symconst_node, str);
+                       set_irn_n(node, i, symconst_node);
+               }
+       }
+}
+
+
+/**
+ * Transforms the given firm node (and maybe some other related nodes)
+ * into one or more assembler nodes.
+ *
+ * @param node    the firm node
+ * @param env     the debug module
+ */
+void arm_transform_node(ir_node *node, void *env) {
+       arm_code_gen_t *cgenv = (arm_code_gen_t *)env;
+       opcode  code               = get_irn_opcode(node);
+       ir_node *asm_node          = NULL;
+       arm_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);
+
+#define UNOP(a)        case iro_##a: asm_node = gen_##a(&tenv, get_##a##_op(node)); break
+#define BINOP(a)       case iro_##a: asm_node = gen_##a(&tenv, get_##a##_left(node), get_##a##_right(node)); break
+#define GEN(a)         case iro_##a: asm_node = gen_##a(&tenv); 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);  // done
+               BINOP(Mul);  // done
+               BINOP(Quot); // done
+               BINOP(And);  // done
+               BINOP(Or);   // done
+               BINOP(Eor);  // done
+
+               BINOP(Sub);  // done
+               BINOP(Shl);  // done
+               BINOP(Shr);  // done
+               BINOP(Shrs); // done
+
+               UNOP(Minus); // done
+               UNOP(Not);   // done
+               UNOP(Abs);   // done
+
+               GEN(CopyB); // done
+               GEN(Const); // TODO: floating point consts
+               UNOP(Conv); // TODO: floating point conversions
+
+               GEN(Load);   // done
+               GEN(Store);  // done
+
+               GEN(SymConst);
+               GEN(Cond);        // integer done
+
+               /* TODO: implement these nodes */
+
+               IGN(Div);    // intrinsic lowering
+               IGN(Mod);    // intrinsic lowering
+               IGN(DivMod); // TODO: implement DivMod
+
+               IGN(Mux);
+               IGN(Unknown);
+               IGN(Cmp);     // done, implemented in cond
+
+               /* You probably don't need to handle the following nodes */
+
+               IGN(Call);
+               IGN(Proj);
+               IGN(Alloc);
+
+               IGN(Block);
+               IGN(Start);
+               IGN(End);
+               IGN(NoMem);
+               IGN(Phi);
+               IGN(IJmp);
+               IGN(Jmp);     // emitter done
+               IGN(Break);
+               IGN(Sync);
+
+               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 (get_irn_op(node) == get_op_Max() ||
+                               get_irn_op(node) == get_op_Min() ||
+                               get_irn_op(node) == get_op_Mulh())
+                       {
+                               /* TODO: implement */
+                               /* ignore for now  */
+                       }
+                       break;
+bad:
+               fprintf(stderr, "Not implemented: %s\n", get_irn_opname(node));
+               assert(0);
+       }
+
+       if (asm_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"));
+       }
+}
diff --git a/ir/be/arm/arm_transform.h b/ir/be/arm/arm_transform.h
new file mode 100644 (file)
index 0000000..b61ac20
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef _ARM_TRANSFORM_H_
+#define _ARM_TRANSFORM_H_
+
+void arm_move_consts(ir_node *node, void *env);
+void arm_move_symconsts(ir_node *node, void *env);
+void arm_transform_node(ir_node *node, void *env);
+
+#endif /* _ARM_TRANSFORM_H_ */
diff --git a/ir/be/arm/bearch_arm.c b/ir/be/arm/bearch_arm.c
new file mode 100644 (file)
index 0000000..189190c
--- /dev/null
@@ -0,0 +1,976 @@
+/* The main arm 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 "lower_intrinsics.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_arm_t.h"
+
+#include "arm_new_nodes.h"           /* arm nodes interface */
+#include "gen_arm_regalloc_if.h"     /* the generated interface (register type and class defenitions) */
+#include "arm_gen_decls.h"           /* interface declaration emitter */
+#include "arm_transform.h"
+#include "arm_emitter.h"
+#include "arm_map_regs.h"
+
+#define DEBUG_MODULE "firm.be.arm.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 arm 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 *arm_get_irn_reg_req(const void *self, arch_register_req_t *req, const ir_node *irn, int pos) {
+       const arm_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 = arm_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_arm_irn(irn)) {
+               if (pos >= 0) {
+                       irn_req = get_arm_in_req(irn, pos);
+               }
+               else {
+                       irn_req = get_arm_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, &(arm_default_req_arm_floating_point.req), sizeof(*req));
+                       }
+                       else if (mode_is_int(mode) || mode_is_reference(mode)) {
+                               memcpy(req, &(arm_default_req_arm_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 arm_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 = arm_translate_proj_pos(irn);
+               irn = my_skip_proj(irn);
+       }
+
+       if (is_arm_irn(irn)) {
+               const arch_register_t **slots;
+
+               slots      = get_arm_slots(irn);
+               slots[pos] = reg;
+       }
+       else {
+               /* here we set the registers for the Phi nodes */
+               arm_set_firm_reg(irn, reg, cur_reg_set);
+       }
+}
+
+static const arch_register_t *arm_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 = arm_translate_proj_pos(irn);
+               irn = my_skip_proj(irn);
+       }
+
+       if (is_arm_irn(irn)) {
+               const arch_register_t **slots;
+               slots = get_arm_slots(irn);
+               reg   = slots[pos];
+       }
+       else {
+               reg = arm_get_firm_reg(irn, cur_reg_set);
+       }
+
+       return reg;
+}
+
+static arch_irn_class_t arm_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_arm_irn(irn)) {
+               return arch_irn_class_normal;
+       }
+
+       return 0;
+}
+
+static arch_irn_flags_t arm_get_flags(const void *self, const ir_node *irn) {
+       irn = my_skip_proj(irn);
+
+       if (is_arm_irn(irn)) {
+               return get_arm_flags(irn);
+       }
+       else if (is_Unknown(irn)) {
+               return arch_irn_flags_ignore;
+       }
+
+       return 0;
+}
+
+static entity *arm_get_frame_entity(const void *self, const ir_node *irn) {
+       /* TODO: return the entity assigned to the frame */
+       return NULL;
+}
+
+/**
+ * This function is called by the generic backend to correct offsets for
+ * nodes accessing the stack.
+ */
+static void arm_set_stack_bias(const void *self, ir_node *irn, int bias) {
+       /* TODO: correct offset if irn accesses the stack */
+}
+
+/* fill register allocator interface */
+
+static const arch_irn_ops_if_t arm_irn_ops_if = {
+       arm_get_irn_reg_req,
+       arm_set_irn_reg,
+       arm_get_irn_reg,
+       arm_classify,
+       arm_get_flags,
+       arm_get_frame_entity,
+       arm_set_stack_bias
+};
+
+arm_irn_ops_t arm_irn_ops = {
+       &arm_irn_ops_if,
+       NULL
+};
+
+
+
+/**************************************************
+ *                _                         _  __
+ *               | |                       (_)/ _|
+ *   ___ ___   __| | ___  __ _  ___ _ __    _| |_
+ *  / __/ _ \ / _` |/ _ \/ _` |/ _ \ '_ \  | |  _|
+ * | (_| (_) | (_| |  __/ (_| |  __/ | | | | | |
+ *  \___\___/ \__,_|\___|\__, |\___|_| |_| |_|_|
+ *                        __/ |
+ *                       |___/
+ **************************************************/
+
+/**
+ * Transforms the standard firm graph into
+ * a ARM firm graph
+ */
+static void arm_prepare_graph(void *self) {
+       arm_code_gen_t *cg = self;
+
+       irg_walk_blkwise_graph(cg->irg, arm_move_consts, arm_transform_node, cg);
+}
+
+
+
+/**
+ * Called immediately before emit phase.
+ */
+static void arm_finish_irg(ir_graph *irg, arm_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 arm_before_sched(void *self) {
+       /* Some stuff you need to do after scheduling but before register allocation */
+}
+
+static void arm_before_ra(void *self) {
+       /* Some stuff you need to do immediately after register allocation */
+}
+
+
+/**
+ * Emits the code, closes the output file and frees
+ * the code generator interface.
+ */
+static void arm_emit_and_done(void *self) {
+       arm_code_gen_t *cg = self;
+       ir_graph           *irg = cg->irg;
+       FILE               *out = cg->out;
+
+       if (cg->emit_decls) {
+               arm_gen_decls(cg->out);
+               cg->emit_decls = 0;
+       }
+
+       arm_finish_irg(irg, cg);
+       dump_ir_block_graph_sched(irg, "-arm-finished");
+       arm_gen_routine(out, irg, cg);
+
+       cur_reg_set = NULL;
+
+       /* de-allocate code generator */
+       del_set(cg->reg_set);
+       free(self);
+}
+
+enum convert_which { low, high };
+
+/**
+ * Move an floating point value to a integer register.
+ * Place the move operation into block bl.
+ */
+static ir_node *convert_to_int(ir_node *bl, ir_node *arg, enum convert_which which) {
+       return NULL;
+}
+
+/**
+ * Convert the arguments of a call to support the
+ * ARM calling convention of general purpose AND floating
+ * point arguments
+ */
+static void handle_calls(ir_node *call, void *env)
+{
+       arm_code_gen_t *cg = env;
+       int i, j, n, size, idx, flag, n_param, n_res;
+       ir_type *mtp, *new_mtd, *new_tp[5];
+       ir_node *new_in[5], **in;
+       ir_node *bl;
+
+       if (! is_Call(call))
+               return;
+
+       /* check, if we need conversions */
+       n = get_Call_n_params(call);
+       mtp = get_Call_type(call);
+       assert(get_method_n_params(mtp) == n);
+
+       /* it's always enough to handle the first 4 parameters */
+       if (n > 4)
+               n = 4;
+       flag = size = idx = 0;
+       bl = get_nodes_block(call);
+       for (i = 0; i < n; ++i) {
+               ir_type *param_tp = get_method_param_type(mtp, i);
+
+               if (is_compound_type(param_tp)) {
+                       /* an aggregate parameter: bad case */
+                       assert(0);
+               }
+               else {
+                       /* a primitive parameter */
+                       ir_mode *mode = get_type_mode(param_tp);
+
+                       if (mode_is_float(mode)) {
+                               if (get_mode_size_bits(mode) > 32) {
+                                       size += 2 * 4;
+                                       new_tp[idx] = cg->int_tp;
+                                       new_in[idx] = convert_to_int(bl, get_Call_param(call, i), low);
+                                       ++idx;
+                                       new_tp[idx] = cg->int_tp;
+                                       new_in[idx] = convert_to_int(bl, get_Call_param(call, i), high);
+                                       ++idx;
+                               }
+                               else {
+                                       size += 4;
+                                       new_tp[idx] = cg->int_tp;
+                                       new_in[idx] = convert_to_int(bl, get_Call_param(call, i), low);
+                                       ++idx;
+                               }
+                               flag = 1;
+                       }
+                       else {
+                               size += 4;
+                               new_tp[idx] = param_tp;
+                               new_in[idx] = get_Call_param(call, i);
+                               ++idx;
+                       }
+               }
+
+               if (size >= 16)
+                       break;
+       }
+
+       /* if flag is NOT set, no need to translate the method type */
+       if (! flag)
+               return;
+
+       /* construct a new method type */
+       n       = i;
+       n_param = get_method_n_params(mtp) - n + idx;
+       n_res   = get_method_n_ress(mtp);
+       new_mtd = new_d_type_method(get_type_ident(mtp), n_param, n_res, get_type_dbg_info(mtp));
+
+       for (i = 0; i < idx; ++i)
+               set_method_param_type(new_mtd, i, new_tp[i]);
+       for (i = n, j = idx; i < get_method_n_params(mtp); ++i)
+               set_method_param_type(new_mtd, j++, get_method_param_type(mtp, i));
+       for (i = 0; i < n_res; ++i)
+               set_method_res_type(new_mtd, i, get_method_res_type(mtp, i));
+
+       set_method_calling_convention(new_mtd, get_method_calling_convention(mtp));
+       set_method_first_variadic_param_index(new_mtd, get_method_first_variadic_param_index(mtp));
+
+       if (is_lowered_type(mtp)) {
+               mtp = get_associated_type(mtp);
+       }
+       set_lowered_type(mtp, new_mtd);
+
+       set_Call_type(call, new_mtd);
+
+       /* calculate new in array of the Call */
+       NEW_ARR_A(ir_node *, in, n_param + 2);
+       for (i = 0; i < idx; ++i)
+               in[2 + i] = new_in[i];
+       for (i = n, j = idx; i < get_method_n_params(mtp); ++i)
+               in[2 + j++] = get_Call_param(call, i);
+
+       in[0] = get_Call_mem(call);
+       in[1] = get_Call_ptr(call);
+
+       /* finally, change the call inputs */
+       set_irn_in(call, n_param + 2, in);
+}
+
+/**
+ * Handle graph transformations before the abi converter does it's work
+ */
+static void arm_before_abi(void *self) {
+       arm_code_gen_t *cg = self;
+
+       irg_walk_graph(cg->irg, NULL, handle_calls, cg);
+}
+
+static void *arm_cg_init(FILE *F, const be_irg_t *birg);
+
+static const arch_code_generator_if_t arm_code_gen_if = {
+       arm_cg_init,
+       arm_before_abi,         /* before abi introduce */
+       arm_prepare_graph,
+       arm_before_sched,   /* before scheduling hook */
+       arm_before_ra,      /* before register allocation hook */
+       NULL, /* after register allocation */
+       arm_emit_and_done,
+};
+
+/**
+ * Initializes the code generator.
+ */
+static void *arm_cg_init(FILE *F, const be_irg_t *birg) {
+       static ir_type *int_tp = NULL;
+       arm_isa_t      *isa = (arm_isa_t *)birg->main_env->arch_env->isa;
+       arm_code_gen_t *cg;
+
+    if (! int_tp) {
+               /* create an integer type with machine size */
+               int_tp = new_type_primitive(new_id_from_chars("int", 3), mode_Is);
+       }
+
+       cg = xmalloc(sizeof(*cg));
+       cg->impl     = &arm_code_gen_if;
+       cg->irg      = birg->irg;
+       cg->reg_set  = new_set(arm_cmp_irn_reg_assoc, 1024);
+       cg->mod      = firm_dbg_register("firm.be.arm.cg");
+       cg->out      = F;
+       cg->arch_env = birg->main_env->arch_env;
+       cg->birg     = birg;
+       cg->int_tp   = int_tp;
+
+       isa->num_codegens++;
+
+       if (isa->num_codegens > 1)
+               cg->emit_decls = 0;
+       else
+               cg->emit_decls = 1;
+
+       cur_reg_set = cg->reg_set;
+
+       arm_irn_ops.cg = cg;
+
+       return (arch_code_generator_t *)cg;
+}
+
+
+/**
+ * Maps all intrinsic calls that the backend support
+ * and map all instructions the backend did not support
+ * to runtime calls.
+ */
+void arm_global_init(void) {
+  ir_type *tp, *int_tp, *uint_tp;
+  i_record records[8];
+  int n_records = 0;
+
+#define ID(x) new_id_from_chars(x, sizeof(x)-1)
+
+  int_tp  = new_type_primitive(ID("int"), mode_Is);
+  uint_tp = new_type_primitive(ID("uint"), mode_Iu);
+
+  {
+    runtime_rt rt_Div;
+    i_instr_record *map_Div = &records[n_records++].i_instr;
+
+    tp = new_type_method(ID("rt_iDiv"), 2, 1);
+    set_method_param_type(tp, 0, int_tp);
+    set_method_param_type(tp, 1, int_tp);
+    set_method_res_type(tp, 0, int_tp);
+
+    rt_Div.ent             = new_entity(get_glob_type(), ID("__divsi3"), tp);
+    rt_Div.mode            = mode_T;
+    rt_Div.mem_proj_nr     = pn_Div_M;
+    rt_Div.exc_proj_nr     = pn_Div_X_except;
+    rt_Div.exc_mem_proj_nr = pn_Div_M;
+    rt_Div.res_proj_nr     = pn_Div_res;
+
+    set_entity_visibility(rt_Div.ent, visibility_external_allocated);
+
+    map_Div->kind     = INTRINSIC_INSTR;
+    map_Div->op       = op_Div;
+    map_Div->i_mapper = i_mapper_RuntimeCall;
+    map_Div->ctx      = &rt_Div;
+  }
+  {
+    runtime_rt rt_Div;
+    i_instr_record *map_Div = &records[n_records++].i_instr;
+
+    tp = new_type_method(ID("rt_uDiv"), 2, 1);
+    set_method_param_type(tp, 0, uint_tp);
+    set_method_param_type(tp, 1, uint_tp);
+    set_method_res_type(tp, 0, uint_tp);
+
+    rt_Div.ent             = new_entity(get_glob_type(), ID("__udivsi3"), tp);
+    rt_Div.mode            = mode_T;
+    rt_Div.mem_proj_nr     = pn_Div_M;
+    rt_Div.exc_proj_nr     = pn_Div_X_except;
+    rt_Div.exc_mem_proj_nr = pn_Div_M;
+    rt_Div.res_proj_nr     = pn_Div_res;
+
+    set_entity_visibility(rt_Div.ent, visibility_external_allocated);
+
+    map_Div->kind     = INTRINSIC_INSTR;
+    map_Div->op       = op_Div;
+    map_Div->i_mapper = i_mapper_RuntimeCall;
+    map_Div->ctx      = &rt_Div;
+  }
+  {
+    runtime_rt rt_Mod;
+    i_instr_record *map_Mod = &records[n_records++].i_instr;
+
+    tp = new_type_method(ID("rt_iMod"), 2, 1);
+    set_method_param_type(tp, 0, int_tp);
+    set_method_param_type(tp, 1, int_tp);
+    set_method_res_type(tp, 0, int_tp);
+
+    rt_Mod.ent             = new_entity(get_glob_type(), ID("__modsi3"), tp);
+    rt_Mod.mode            = mode_T;
+    rt_Mod.mem_proj_nr     = pn_Mod_M;
+    rt_Mod.exc_proj_nr     = pn_Mod_X_except;
+    rt_Mod.exc_mem_proj_nr = pn_Mod_M;
+    rt_Mod.res_proj_nr     = pn_Mod_res;
+
+    set_entity_visibility(rt_Mod.ent, visibility_external_allocated);
+
+    map_Mod->kind     = INTRINSIC_INSTR;
+    map_Mod->op       = op_Mod;
+    map_Mod->i_mapper = i_mapper_RuntimeCall;
+    map_Mod->ctx      = &rt_Mod;
+  }
+  {
+    runtime_rt rt_Mod;
+    i_instr_record *map_Mod = &records[n_records++].i_instr;
+
+    tp = new_type_method(ID("rt_uMod"), 2, 1);
+    set_method_param_type(tp, 0, uint_tp);
+    set_method_param_type(tp, 1, uint_tp);
+    set_method_res_type(tp, 0, uint_tp);
+
+    rt_Mod.ent             = new_entity(get_glob_type(), ID("__umodsi3"), tp);
+    rt_Mod.mode            = mode_T;
+    rt_Mod.mem_proj_nr     = pn_Mod_M;
+    rt_Mod.exc_proj_nr     = pn_Mod_X_except;
+    rt_Mod.exc_mem_proj_nr = pn_Mod_M;
+    rt_Mod.res_proj_nr     = pn_Mod_res;
+
+    set_entity_visibility(rt_Mod.ent, visibility_external_allocated);
+
+    map_Mod->kind     = INTRINSIC_INSTR;
+    map_Mod->op       = op_Mod;
+    map_Mod->i_mapper = i_mapper_RuntimeCall;
+    map_Mod->ctx      = &rt_Mod;
+  }
+
+  if (n_records > 0)
+    lower_intrinsics(records, n_records);
+}
+
+/*****************************************************************
+ *  ____             _                  _   _____  _____
+ * |  _ \           | |                | | |_   _|/ ____|  /\
+ * | |_) | __ _  ___| | _____ _ __   __| |   | | | (___   /  \
+ * |  _ < / _` |/ __| |/ / _ \ '_ \ / _` |   | |  \___ \ / /\ \
+ * | |_) | (_| | (__|   <  __/ | | | (_| |  _| |_ ____) / ____ \
+ * |____/ \__,_|\___|_|\_\___|_| |_|\__,_| |_____|_____/_/    \_\
+ *
+ *****************************************************************/
+
+static arm_isa_t arm_isa_template = {
+       &arm_isa_if,                        /* isa interface */
+       &arm_general_purpose_regs[REG_R13], /* stack pointer */
+       &arm_general_purpose_regs[REG_R11], /* base pointer */
+       -1,                                 /* stack direction */
+       0                                   /* number of codegenerator objects */
+};
+
+/**
+ * Initializes the backend ISA and opens the output file.
+ */
+static void *arm_init(void) {
+       static int inited = 0;
+       arm_isa_t *isa;
+
+       if(inited)
+               return NULL;
+
+       isa = xcalloc(1, sizeof(*isa));
+       memcpy(isa, &arm_isa_template, sizeof(*isa));
+
+       arm_register_init(isa);
+       arm_create_opcodes();
+
+       inited = 1;
+
+       return isa;
+}
+
+
+
+/**
+ * Closes the output file and frees the ISA structure.
+ */
+static void arm_done(void *self) {
+       free(self);
+}
+
+
+
+static int arm_get_n_reg_class(const void *self) {
+       return N_CLASSES;
+}
+
+static const arch_register_class_t *arm_get_reg_class(const void *self, int i) {
+       assert(i >= 0 && i < N_CLASSES && "Invalid arm register class requested.");
+       return &arm_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 *arm_get_reg_class_for_mode(const void *self, const ir_mode *mode) {
+       if (mode_is_float(mode))
+               return &arm_reg_classes[CLASS_arm_floating_point];
+       else
+               return &arm_reg_classes[CLASS_arm_general_purpose];
+}
+
+
+
+/**
+ * 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 base pointer.
+ * @return The Firm type modelling the ABI between type.
+ */
+static ir_type *arm_get_between_type(void *self) {
+       static ir_type *between_type = NULL;
+       static entity *old_bp_ent    = NULL;
+
+       if(!between_type) {
+               entity *ret_addr_ent;
+               ir_type *ret_addr_type = new_type_primitive(new_id_from_str("return_addr"), mode_P);
+               ir_type *old_bp_type   = new_type_primitive(new_id_from_str("bp"), mode_P);
+
+               between_type           = new_type_class(new_id_from_str("arm_between_type"));
+               old_bp_ent             = new_entity(between_type, new_id_from_str("old_bp"), old_bp_type);
+               ret_addr_ent           = new_entity(between_type, new_id_from_str("old_bp"), ret_addr_type);
+
+               set_entity_offset_bytes(old_bp_ent, 0);
+               set_entity_offset_bytes(ret_addr_ent, get_type_size_bytes(old_bp_type));
+               set_type_size_bytes(between_type, get_type_size_bytes(old_bp_type) + get_type_size_bytes(ret_addr_type));
+       }
+
+       return between_type;
+}
+
+
+
+
+
+
+
+
+typedef struct {
+       be_abi_call_flags_bits_t flags;
+       const arch_env_t *arch_env;
+       const arch_isa_t *isa;
+       ir_graph *irg;
+} arm_abi_env_t;
+
+static void *arm_abi_init(const be_abi_call_t *call, const arch_env_t *arch_env, ir_graph *irg)
+{
+       arm_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      = arch_env->isa;
+       return env;
+}
+
+static void arm_abi_dont_save_regs(void *self, pset *s)
+{
+       arm_abi_env_t *env = self;
+       if(env->flags.try_omit_fp)
+               pset_insert_ptr(s, env->isa->bp);
+}
+
+
+
+/**
+ * Build the ARM prolog
+ */
+static const arch_register_t *arm_abi_prologue(void *self, ir_node **mem, pmap *reg_map) {
+       ir_node *keep, *store;
+       arm_abi_env_t *env = self;
+       ir_graph *irg = env->irg;
+       ir_node *block = get_irg_start_block(irg);
+//     ir_node *regs[16];
+//     int n_regs = 0;
+       arch_register_class_t *gp = &arm_reg_classes[CLASS_arm_general_purpose];
+       static const arm_register_req_t *fp_req[] = {
+               &arm_default_req_arm_general_purpose_r11
+       };
+
+       ir_node *fp = be_abi_reg_map_get(reg_map, env->isa->bp);
+       ir_node *ip = be_abi_reg_map_get(reg_map, &arm_general_purpose_regs[REG_R12]);
+       ir_node *sp = be_abi_reg_map_get(reg_map, env->isa->sp);
+       ir_node *lr = be_abi_reg_map_get(reg_map, &arm_general_purpose_regs[REG_R14]);
+       ir_node *pc = be_abi_reg_map_get(reg_map, &arm_general_purpose_regs[REG_R15]);
+//     ir_node *r0 = be_abi_reg_map_get(reg_map, &arm_general_purpose_regs[REG_R0]);
+//     ir_node *r1 = be_abi_reg_map_get(reg_map, &arm_general_purpose_regs[REG_R1]);
+//     ir_node *r2 = be_abi_reg_map_get(reg_map, &arm_general_purpose_regs[REG_R2]);
+//     ir_node *r3 = be_abi_reg_map_get(reg_map, &arm_general_purpose_regs[REG_R3]);
+
+       if(env->flags.try_omit_fp)
+               return env->isa->sp;
+
+       ip = be_new_Copy(gp, irg, block, sp );
+               arch_set_irn_register(env->arch_env, ip, &arm_general_purpose_regs[REG_R12]);
+               be_set_constr_single_reg(ip, BE_OUT_POS(0), &arm_general_purpose_regs[REG_R12] );
+
+//     if (r0) regs[n_regs++] = r0;
+//     if (r1) regs[n_regs++] = r1;
+//     if (r2) regs[n_regs++] = r2;
+//     if (r3) regs[n_regs++] = r3;
+//     sp = new_r_arm_StoreStackMInc(irg, block, *mem, sp, n_regs, regs, get_irn_mode(sp));
+//             set_arm_req_out(sp, &arm_default_req_arm_general_purpose_r13, 0);
+//             arch_set_irn_register(env->arch_env, sp, env->isa->sp);
+       store = new_rd_arm_StoreStackM4Inc(NULL, irg, block, sp, fp, ip, lr, pc, *mem, mode_T);
+               set_arm_req_out(store, &arm_default_req_arm_general_purpose_r13, 0);
+//             arch_set_irn_register(env->arch_env, store, env->isa->sp);
+
+       sp = new_r_Proj(irg, block, store, env->isa->sp->reg_class->mode, 0);
+               arch_set_irn_register(env->arch_env, sp, env->isa->sp);
+       *mem = new_r_Proj(irg, block, store, mode_M, 1);
+
+       keep = be_new_CopyKeep_single(gp, irg, block, ip, sp, get_irn_mode(ip));
+               be_node_set_reg_class(keep, 1, gp);
+               arch_set_irn_register(env->arch_env, keep, &arm_general_purpose_regs[REG_R12]);
+               be_set_constr_single_reg(keep, BE_OUT_POS(0), &arm_general_purpose_regs[REG_R12] );
+
+       fp = new_rd_arm_Sub_i(NULL, irg, block, keep, get_irn_mode(fp) );
+               set_arm_value(fp, new_tarval_from_long(4, mode_Iu));
+               set_arm_req_out_all(fp, fp_req);
+               //set_arm_req_out(fp, &arm_default_req_arm_general_purpose_r11, 0);
+               arch_set_irn_register(env->arch_env, fp, env->isa->bp);
+
+//     be_abi_reg_map_set(reg_map, &arm_general_purpose_regs[REG_R0], r0);
+//     be_abi_reg_map_set(reg_map, &arm_general_purpose_regs[REG_R1], r1);
+//     be_abi_reg_map_set(reg_map, &arm_general_purpose_regs[REG_R2], r2);
+//     be_abi_reg_map_set(reg_map, &arm_general_purpose_regs[REG_R3], r3);
+       be_abi_reg_map_set(reg_map, env->isa->bp, fp);
+       be_abi_reg_map_set(reg_map, &arm_general_purpose_regs[REG_R12], keep);
+       be_abi_reg_map_set(reg_map, env->isa->sp, sp);
+       be_abi_reg_map_set(reg_map, &arm_general_purpose_regs[REG_R14], lr);
+       be_abi_reg_map_set(reg_map, &arm_general_purpose_regs[REG_R15], pc);
+
+       return env->isa->bp;
+}
+
+static void arm_abi_epilogue(void *self, ir_node *bl, ir_node **mem, pmap *reg_map) {
+       arm_abi_env_t *env = self;
+       ir_node *curr_sp = be_abi_reg_map_get(reg_map, env->isa->sp);
+       ir_node *curr_bp = be_abi_reg_map_get(reg_map, env->isa->bp);
+       ir_node *curr_pc = be_abi_reg_map_get(reg_map, &arm_general_purpose_regs[REG_R15]);
+       ir_node *curr_lr = be_abi_reg_map_get(reg_map, &arm_general_purpose_regs[REG_R14]);
+       static const arm_register_req_t *sub12_req[] = {
+               &arm_default_req_arm_general_purpose_r13
+       };
+
+//     TODO: Activate Omit fp in epilogue
+       if(env->flags.try_omit_fp) {
+               curr_sp = be_new_IncSP(env->isa->sp, env->irg, bl, curr_sp, *mem, BE_STACK_FRAME_SIZE, be_stack_dir_shrink);
+
+               curr_lr = be_new_CopyKeep_single(&arm_reg_classes[CLASS_arm_general_purpose], env->irg, bl, curr_lr, curr_sp, get_irn_mode(curr_lr));
+               be_node_set_reg_class(curr_lr, 1, &arm_reg_classes[CLASS_arm_general_purpose]);
+               arch_set_irn_register(env->arch_env, curr_lr, &arm_general_purpose_regs[REG_R14]);
+               be_set_constr_single_reg(curr_lr, BE_OUT_POS(0), &arm_general_purpose_regs[REG_R14] );
+
+               curr_pc = be_new_Copy(&arm_reg_classes[CLASS_arm_general_purpose], env->irg, bl, curr_lr );
+               arch_set_irn_register(env->arch_env, curr_pc, &arm_general_purpose_regs[REG_R15]);
+               be_set_constr_single_reg(curr_pc, BE_OUT_POS(0), &arm_general_purpose_regs[REG_R15] );
+       } else {
+               ir_node *sub12_node;
+               ir_node *load_node;
+               sub12_node = new_rd_arm_Sub_i(NULL, env->irg, bl, curr_bp, mode_Iu );
+               set_arm_value(sub12_node, new_tarval_from_long(12,mode_Iu));
+               set_arm_req_out_all(sub12_node, sub12_req);
+               arch_set_irn_register(env->arch_env, sub12_node, env->isa->sp);
+               load_node = new_rd_arm_LoadStackM3( NULL, env->irg, bl, sub12_node, *mem, mode_T );
+               set_arm_req_out(load_node, &arm_default_req_arm_general_purpose_r11, 0);
+               set_arm_req_out(load_node, &arm_default_req_arm_general_purpose_r13, 1);
+               set_arm_req_out(load_node, &arm_default_req_arm_general_purpose_r15, 2);
+               curr_bp = new_r_Proj(env->irg, bl, load_node, env->isa->bp->reg_class->mode, 0);
+               curr_sp = new_r_Proj(env->irg, bl, load_node, env->isa->sp->reg_class->mode, 1);
+               curr_pc = new_r_Proj(env->irg, bl, load_node, mode_Iu, 2);
+               *mem    = new_r_Proj(env->irg, bl, load_node, mode_M, 3);
+               arch_set_irn_register(env->arch_env, curr_bp, env->isa->bp);
+               arch_set_irn_register(env->arch_env, curr_sp, env->isa->sp);
+               arch_set_irn_register(env->arch_env, curr_pc, &arm_general_purpose_regs[REG_R15]);
+       }
+       be_abi_reg_map_set(reg_map, env->isa->sp, curr_sp);
+       be_abi_reg_map_set(reg_map, env->isa->bp, curr_bp);
+       be_abi_reg_map_set(reg_map, &arm_general_purpose_regs[REG_R14], curr_lr);
+       be_abi_reg_map_set(reg_map, &arm_general_purpose_regs[REG_R15], curr_pc);
+}
+
+static const be_abi_callbacks_t arm_abi_callbacks = {
+       arm_abi_init,
+       free,
+       arm_get_between_type,
+       arm_abi_dont_save_regs,
+       arm_abi_prologue,
+       arm_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
+ */
+void arm_get_call_abi(const void *self, ir_type *method_type, be_abi_call_t *abi) {
+       ir_type  *tp;
+       ir_mode  *mode;
+       int       i;
+       int       n = get_method_n_params(method_type);
+//     const arch_register_t *reg;
+       be_abi_call_flags_t flags = {
+               0, /* store from left to right */
+               0, /* store arguments sequential */
+               1, /* try to omit the frame pointer */
+               1, /* the function can use any register as frame pointer */
+               1  /* a call can take the callee's address as an immediate */
+       };
+
+       /* set stack parameter passing style */
+       be_abi_call_set_flags(abi, flags, &arm_abi_callbacks);
+
+       for (i = 0; i < n; i++) {
+               /* reg = get reg for param i;          */
+               /* be_abi_call_param_reg(abi, i, reg); */
+               if (i < 4)
+
+                       be_abi_call_param_reg(abi, i, arm_get_RegParam_reg(i));
+               else
+                       be_abi_call_param_stack(abi, i, 4, 0, 0);
+       }
+
+       /* default: return value is in R0 resp. F0 */
+       assert(get_method_n_ress(method_type) < 2);
+       if (get_method_n_ress(method_type) > 0) {
+               tp   = get_method_res_type(method_type, 0);
+               mode = get_type_mode(tp);
+
+               be_abi_call_res_reg(abi, 0,
+                       mode_is_float(mode) ? &arm_floating_point_regs[REG_F0] : &arm_general_purpose_regs[REG_R0]);
+       }
+}
+
+static const void *arm_get_irn_ops(const arch_irn_handler_t *self, const ir_node *irn) {
+       return &arm_irn_ops;
+}
+
+const arch_irn_handler_t arm_irn_handler = {
+       arm_get_irn_ops
+};
+
+const arch_irn_handler_t *arm_get_irn_handler(const void *self) {
+       return &arm_irn_handler;
+}
+
+int arm_to_appear_in_schedule(void *block_env, const ir_node *irn) {
+       return is_arm_irn(irn);
+}
+
+/**
+ * Initializes the code generator interface.
+ */
+static const arch_code_generator_if_t *arm_get_code_generator_if(void *self) {
+       return &arm_code_gen_if;
+}
+
+list_sched_selector_t arm_sched_selector;
+
+/**
+ * Returns the reg_pressure scheduler with to_appear_in_schedule() over\loaded
+ */
+static const list_sched_selector_t *arm_get_list_sched_selector(const void *self) {
+       memcpy(&arm_sched_selector, reg_pressure_selector, sizeof(list_sched_selector_t));
+       arm_sched_selector.to_appear_in_schedule = arm_to_appear_in_schedule;
+       return &arm_sched_selector;
+}
+
+#ifdef WITH_LIBCORE
+static void arm_register_options(lc_opt_entry_t *ent)
+{
+}
+#endif /* WITH_LIBCORE */
+
+const arch_isa_if_t arm_isa_if = {
+#ifdef WITH_LIBCORE
+       arm_register_options,
+#endif
+       arm_init,
+       arm_done,
+       arm_get_n_reg_class,
+       arm_get_reg_class,
+       arm_get_reg_class_for_mode,
+       arm_get_call_abi,
+       arm_get_irn_handler,
+       arm_get_code_generator_if,
+       arm_get_list_sched_selector,
+};
diff --git a/ir/be/arm/bearch_arm.h b/ir/be/arm/bearch_arm.h
new file mode 100644 (file)
index 0000000..077733b
--- /dev/null
@@ -0,0 +1,10 @@
+#ifndef _BEARCH_ARM_H_
+#define _BEARCH_ARM_H_
+
+#include "../bearch.h"
+
+extern const arch_isa_if_t arm_isa_if;
+void arm_global_init(void);
+
+
+#endif /* _BEARCH_ARM_H_ */
diff --git a/ir/be/arm/bearch_arm_t.h b/ir/be/arm/bearch_arm_t.h
new file mode 100644 (file)
index 0000000..e24d2bb
--- /dev/null
@@ -0,0 +1,52 @@
+#ifndef _BEARCH_ARM_T_H_
+#define _BEARCH_ARM_T_H_
+
+#include "debug.h"
+#include "bearch_arm.h"
+#include "arm_nodes_attr.h"
+#include "../be.h"
+#include "set.h"
+#include <stdio.h>
+
+typedef struct _arm_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_type                        *int_tp;         /**< the int type, needed for Call conversion */
+} arm_code_gen_t;
+
+
+typedef struct _arm_isa_t {
+       const arch_isa_if_t   *impl;
+       const arch_register_t *sp;            /**< The stack pointer register. */
+       const arch_register_t *bp;            /**< The base pointer register. */
+       const int              stack_dir;     /**< -1 for decreasing, 1 for increasing. */
+       int                    num_codegens;
+} arm_isa_t;
+
+
+typedef struct _arm_irn_ops_t {
+       const arch_irn_ops_if_t *impl;
+       arm_code_gen_t     *cg;
+} arm_irn_ops_t;
+
+
+/* this is a struct to minimize the number of parameters
+   for transformation walker */
+typedef struct _arm_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 */
+//     arm_code_gen_t    *cg;       /**< The code generator */
+} arm_transform_env_t;
+
+
+#endif /* _BEARCH_ARM_T_H_ */