- Split bearch.h correctly into bearch.h and bearch_t.h
[libfirm] / ir / be / arm / arm_emitter.c
index 8fb8fef..5b93963 100644 (file)
@@ -1,3 +1,4 @@
+#define SILENCER
 /* arm emitter */
 /* $Id$ */
 
@@ -18,6 +19,8 @@
 #include "irargs_t.h"
 
 #include "../besched.h"
+#include "../beblocksched.h"
+#include "../beirg_t.h"
 
 #include "arm_emitter.h"
 #include "gen_arm_emitter.h"
 
 static const arch_env_t *arch_env = NULL;
 
+/**
+ * Switch to a new section
+ */
+void arm_switch_section(FILE *f, sections sec) {
+       static sections curr_sec = NO_SECTION;
+
+       if (curr_sec == sec)
+               return;
+
+       curr_sec = sec;
+       switch (sec) {
+
+       case NO_SECTION:
+               break;
+
+       case SECTION_TEXT:
+               fprintf(f, "\t.text\n");
+               break;
+
+       case SECTION_DATA:
+               fprintf(f, "\t.data\n");
+               break;
+
+       default:
+               assert(0);
+       }
+}
 
 /*************************************************************
  *             _       _    __   _          _
@@ -44,80 +74,49 @@ static const arch_env_t *arch_env = NULL;
  * |_|                                       |_|
  *************************************************************/
 
+/**
+ * Returns non-zero if a mode has a Immediate attribute.
+ */
 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;
+       arm_attr_t *attr = get_arm_attr(irn);
+       return ARM_GET_SHF_MOD(attr) == ARM_SHF_IMM;
 }
 
 /**
- * Return a const or symconst as string.
+ * Return a const or SymConst as string.
  */
-static const char *node_const_to_str(ir_node *n) {
-       char buffer[SNPRINTF_BUF_LEN];
-
-       if ( is_immediate_node(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;
+static const char *node_const_to_str(ir_node *n, char *buf, int buflen) {
+       if (is_immediate_node(n)) {
+               snprintf(buf, buflen, "#0x%X", arm_decode_imm_w_shift(get_arm_value(n)));
+               return buf;
        }
+       else if (is_arm_SymConst(n))
+               return get_arm_symconst_label(n);
 
+       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;
+static const char *node_offset_to_str(ir_node *n, char *buf, int buflen) {
        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;
+               ir_entity *ent = be_get_frame_entity(n);
+               offset = get_entity_offset(ent);
+       } else if (irn_op == op_be_Reload || irn_op == op_be_Spill) {
+               ir_entity *ent = be_get_frame_entity(n);
+               offset = get_entity_offset(ent);
+       } else if (irn_op == op_be_IncSP) {
+               offset = - be_get_IncSP_offset(n);
        } 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;
+       snprintf(buf, buflen, "%d", offset);
+       return buf;
 }
 
 /* We always pass the ir_node which is a pointer. */
@@ -141,12 +140,6 @@ static const arch_register_t *get_in_reg(const ir_node *irn, int 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;
 }
@@ -250,6 +243,7 @@ static int arm_get_reg_name(lc_appendable_t *app,
 static int arm_const_to_str(lc_appendable_t *app,
     const lc_arg_occ_t *occ, const lc_arg_value_t *arg)
 {
+       char buffer[SNPRINTF_BUF_LEN];
        const char *buf;
        ir_node    *X = arg->v_ptr;
 
@@ -257,30 +251,62 @@ static int arm_const_to_str(lc_appendable_t *app,
                return lc_appendable_snadd(app, "(null)", 6);
 
        if (occ->conversion == 'C') {
-               buf = node_const_to_str(X);
+               buf = node_const_to_str(X, buffer, sizeof(buffer));
        }
        else { /* 'O' */
-               buf = node_offset_to_str(X);
+               buf = node_offset_to_str(X, buffer, sizeof(buffer));
        }
 
        return lc_appendable_snadd(app, buf, strlen(buf));
 }
 
 /**
- * Determines the SSE suffix depending on the mode.
+ * Returns the tarval or offset of an arm node as a string.
+ */
+static int arm_shift_str(lc_appendable_t *app,
+    const lc_arg_occ_t *occ, const lc_arg_value_t *arg)
+{
+       char buffer[SNPRINTF_BUF_LEN];
+       ir_node            *irn = arg->v_ptr;
+       arm_shift_modifier mod;
+
+       if (!irn)
+               return lc_appendable_snadd(app, "(null)", 6);
+
+       mod = get_arm_shift_modifier(irn);
+       if (ARM_HAS_SHIFT(mod)) {
+               long v = get_tarval_long(get_arm_value(irn));
+
+               snprintf(buffer, sizeof(buffer), ", %s #%ld", arm_shf_mod_name(mod), v);
+               return lc_appendable_snadd(app, buffer, strlen(buffer));
+       }
+       return 0;
+}
+
+/**
+ * Determines the instruction 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;
+       ir_node *irn = arg->v_ptr;
+       arm_attr_t *attr;
+       ir_mode *mode;
+       int bits;
 
-       if (!X)
+       if (! irn)
                return lc_appendable_snadd(app, "(null)", 6);
 
-       if (get_mode_size_bits(get_irn_mode(X)) == 32)
+       attr = get_arm_attr(irn);
+       mode = attr->op_mode ? attr->op_mode : get_irn_mode(irn);
+       bits = get_mode_size_bits(mode);
+
+       if (bits == 32)
                return lc_appendable_chadd(app, 's');
-       else
+       else if (bits == 64)
                return lc_appendable_chadd(app, 'd');
+       else
+               return lc_appendable_chadd(app, 'e');
 }
 
 /**
@@ -293,8 +319,9 @@ const lc_arg_env_t *arm_get_arg_env(void) {
        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 };
+       static const lc_arg_handler_t arm_shf_handler   = { arm_get_arg_type, arm_shift_str };
 
-       if(env == NULL) {
+       if (env == NULL) {
                /* extend the firm printer */
                env = firm_get_arg_env();
                        //lc_arg_new_env();
@@ -304,6 +331,7 @@ const lc_arg_env_t *arm_get_arg_env(void) {
                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);
+               lc_arg_register(env, "arm:shf",  'X', &arm_shf_handler);
        }
 
        return env;
@@ -312,50 +340,47 @@ const lc_arg_env_t *arm_get_arg_env(void) {
 /**
  * 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);
+static void arm_fprintf_format(FILE *F, const char *cmd_buf, const char *cmnt_buf, const ir_node *irn) {
+       lc_efprintf(arm_get_arg_env(), F, "\t%-35s %-60s /* %+F (%G) */\n", cmd_buf, cmnt_buf, irn, irn);
 }
 
-/*
- * Add a number to a prefix. This number will not be used a second time.
+/**
+ * Returns a unique label. 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;
+static unsigned get_unique_label(void) {
+       static unsigned id = 0;
+       return ++id;
 }
 
-
 /**
- * Returns the target label for a control flow node.
+ * Emit a SymConst
  */
-static char *get_cfop_target(const ir_node *irn, char *buf) {
-       ir_node *bl = get_irn_link(irn);
+static void emit_arm_SymConst(ir_node *irn, void *env) {
+       arm_emit_env_t *emit_env = env;
+       FILE *F = emit_env->out;
+       SymConstEntry *entry = obstack_alloc(&emit_env->obst, sizeof(*entry));
+       const lc_arg_env_t *arg_env = arm_get_arg_env();
+       char cmd_buf[256];
 
-       snprintf(buf, SNPRINTF_BUF_LEN, "BLOCK_%ld", get_irn_node_nr(bl));
-       return buf;
-}
+       entry->label      = get_unique_label();
+       entry->symconst   = irn;
+       entry->next       = emit_env->symbols;
+       emit_env->symbols = entry;
 
-/************************************************************************/
-/* emit_arm                                                             */
-/************************************************************************/
+       lc_esnprintf(arg_env, cmd_buf, 256, "ldr %1D, .L%u", irn, entry->label);
+       arm_fprintf_format(F, cmd_buf, "/* indirect SymConst */", irn);
+}
 
-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);
+/**
+ * Returns the next block in a block schedule.
+ */
+static ir_node *sched_next_block(ir_node *block) {
+    return get_irn_link(block);
 }
 
+/**
+ * Emit a conditional jump.
+ */
 static void emit_arm_CondJmp(ir_node *irn, void *env) {
        arm_emit_env_t *emit_env = env;
        FILE *out = emit_env->out;
@@ -369,9 +394,9 @@ static void emit_arm_CondJmp(ir_node *irn, void *env) {
        char cmd_buf[SNPRINTF_BUF_LEN], cmnt_buf[SNPRINTF_BUF_LEN];
 
 
-       foreach_out_edge(irn, edge) {
-               ir_nodeproj = get_edge_src_irn(edge);
-               long nr = get_Proj_proj(proj);
+       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;
@@ -380,55 +405,71 @@ static void emit_arm_CondJmp(ir_node *irn, void *env) {
                } else {
                        assert(0 && "tertium non datur! (CondJmp)");
                }
-       }
+       }
 
        if (proj_num == pn_Cmp_False) {
-               fprintf(out, "\tB BLOCK_%ld\t\t\t/* false case */\n", get_irn_node_nr(false_block));
+               /* always false: should not happen */
+               fprintf(out, "\tb BLOCK_%ld\t\t\t/* false case */\n", get_irn_node_nr(false_block));
        } else if (proj_num == pn_Cmp_True) {
-               fprintf(out, "\tB BLOCK_%ld\t\t\t/* true case */\n", get_irn_node_nr(true_block));
+               /* always true: should not happen */
+               fprintf(out, "\tb BLOCK_%ld\t\t\t/* true case */\n", get_irn_node_nr(true_block));
        } else {
+               ir_node *block = get_nodes_block(irn);
+
                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(), 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(), 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 {
+                       if (true_block == sched_next_block(block)) {
+                               /* negate it */
+                               proj_num = get_negated_pnc(proj_num, opmode);
+                       }
                        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");
+                               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"); suffix = "al";
                        }
 
-                       lc_esnprintf(arm_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "CMP %1S, %2S", irn, irn);
+                       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));
+               if (true_block == sched_next_block(block)) {
+                       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, "/* false case */");
                        arm_fprintf_format(out, cmd_buf, cmnt_buf, irn);
+
+                       lc_esnprintf(arm_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "/* fallthrough BLOCK_%d */", get_irn_node_nr(false_block));
+                       arm_fprintf_format(out, "", cmnt_buf, irn);
                }
+               else {
+                       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);
+
+            if (false_block == sched_next_block(block)) {
+                lc_esnprintf(arm_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "/* fallthrough BLOCK_%d */", get_irn_node_nr(false_block));
+                arm_fprintf_format(out, "", cmnt_buf, irn);
+            }
+            else {
+                           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);
+            }
+        }
        }
 }
 
@@ -449,29 +490,29 @@ static void emit_arm_CopyB(ir_node *irn, void *env) {
        case 0:
                break;
        case 1:
-               lc_esnprintf(arg_env, cmd_buf, SNPRINTF_BUF_LEN, "LDR %%r12, [%2S, #0]!", irn);
+               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);
+               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);
+               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);
+               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);
+               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);
+               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);
+               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);
+               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;
        }
@@ -487,7 +528,7 @@ static void emit_arm_SwitchJmp(ir_node *irn, void *env) {
        ir_node **projs;
        int n_projs;
        int block_nr;
-       int default_block_num;
+       int default_block_num = -1;
 
        block_nr = get_irn_node_nr(irn);
        n_projs = get_arm_n_projs(irn);
@@ -503,32 +544,33 @@ static void emit_arm_SwitchJmp(ir_node *irn, void *env) {
 
                projs[get_Proj_proj(proj)] = proj;
        }
+       assert(default_block_num >= 0);
 
        // 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(), 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);
+       arm_fprintf_format(out, 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(), 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);
+       arm_fprintf_format(out, 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(), 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);
+       arm_fprintf_format(out, 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(), 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);
+       arm_fprintf_format(out, 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(), 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);
+       arm_fprintf_format(out, cmd_buf, cmnt_buf, irn);
 
        // LDR %r12, .TABLE_X_START
        // ADD %r12, %r12, [%1S, LSL #2]
@@ -560,25 +602,32 @@ static void emit_arm_SwitchJmp(ir_node *irn, void *env) {
 
 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);
+       FILE *F = emit_env->out;
+       ir_entity *ent = be_Call_get_entity(irn);
+    char cmd_buf[SNPRINTF_BUF_LEN], cmnt_buf[SNPRINTF_BUF_LEN];
+
+    if (ent)
+           lc_esnprintf(arm_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "bl %s", get_entity_ld_name(ent));
+    else
+        lc_esnprintf(arm_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "%1D", get_irn_n(irn, be_pos_Call_ptr));
+    lc_esnprintf(arm_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "/* %+F (be_Call) */", irn);
+    arm_fprintf_format(F, cmd_buf, cmnt_buf, irn);
 }
 
+/** Emit an IncSP node */
 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) {
+       int offs = be_get_IncSP_offset(irn);
+
+       if (offs != 0) {
                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(), 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);
+               arm_fprintf_format(F, 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, "");
+               char cmnt_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);
+               arm_fprintf_format(F, "", cmnt_buf, irn);
        }
 }
 
@@ -593,60 +642,83 @@ static void emit_be_IncSP(const ir_node *irn, arm_emit_env_t *emit_env) {
 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");
+       const lc_arg_env_t *arm_env = arm_get_arg_env();
+       char cmd_buf[SNPRINTF_BUF_LEN], cmnt_buf[SNPRINTF_BUF_LEN];
 
        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);
+               lc_esnprintf(arm_env, cmnt_buf, SNPRINTF_BUF_LEN, "/* omitted Copy: %1S -> %1D */", irn, irn);
+               lc_efprintf(arm_env, F, "\t%-35s %-60s /* %+F */\n", "", 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);
+       if (mode_is_float(mode)) {
+               if (USE_FPA(emit_env->cg->isa)) {
+                       lc_esnprintf(arm_env, cmd_buf, SNPRINTF_BUF_LEN, "mvf%M %1D, %1S", irn, irn, irn);
+                       lc_esnprintf(arm_env, cmnt_buf, SNPRINTF_BUF_LEN, "/* Copy: %1S -> %1D */", irn, irn);
+                       arm_fprintf_format(F, cmd_buf, cmnt_buf, irn);
+               }
+               else {
+                       assert(0 && "move not supported for this mode");
+               }
        } 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);
+               lc_esnprintf(arm_env, cmd_buf, SNPRINTF_BUF_LEN, "mov %1D, %1S", irn, irn);
+               lc_esnprintf(arm_env, cmnt_buf, SNPRINTF_BUF_LEN, "/* Copy: %1S -> %1D */", irn, irn);
+               arm_fprintf_format(F, cmd_buf, cmnt_buf, irn);
        } else {
                assert(0 && "move not supported for this mode");
        }
 //     emit_arm_Copy(irn, emit_env);
 }
 
+/**
+ * Emit code for a Spill.
+ */
 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);
+       const lc_arg_env_t *arm_env = arm_get_arg_env();
+       char cmd_buf[SNPRINTF_BUF_LEN], cmnt_buf[SNPRINTF_BUF_LEN];
+
+       if (mode_is_float(mode)) {
+               if (USE_FPA(emit_env->cg->isa)) {
+                       lc_esnprintf(arm_env, cmd_buf, SNPRINTF_BUF_LEN, "stf %2S, [%1S, #%O]", irn, irn, irn );
+                       lc_esnprintf(arm_env, cmnt_buf, SNPRINTF_BUF_LEN, "/* Spill(%2S) -> (%1S) */", irn, irn);
+                       arm_fprintf_format(F, cmd_buf, cmnt_buf, irn);
+               }
+               else {
+                       assert(0 && "move not supported for this mode");
+               }
+       } else if (mode_is_dataM(mode)) {
+               lc_esnprintf(arm_env, cmd_buf, SNPRINTF_BUF_LEN, "str %2S, [%1S, #%O]", irn, irn, irn );
+               lc_esnprintf(arm_env, cmnt_buf, SNPRINTF_BUF_LEN, "/* Spill(%2S) -> (%1S) */", irn, irn);
+               arm_fprintf_format(F, cmd_buf, cmnt_buf, irn);
        } else {
                assert(0 && "spill not supported for this mode");
        }
 }
 
+/**
+ * Emit code for a Reload.
+ */
 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);
+       const lc_arg_env_t *arm_env = arm_get_arg_env();
+       char cmd_buf[SNPRINTF_BUF_LEN], cmnt_buf[SNPRINTF_BUF_LEN];
+
+       if (mode_is_float(mode)) {
+               if (USE_FPA(emit_env->cg->isa)) {
+                       lc_esnprintf(arm_env, cmd_buf, SNPRINTF_BUF_LEN, "ldf %1D, [%1S, #%O]", irn, irn, irn );
+                       lc_esnprintf(arm_env, cmnt_buf, SNPRINTF_BUF_LEN, "/* Reload(%1S) -> (%1D) */", irn, irn);
+                       arm_fprintf_format(F, cmd_buf, cmnt_buf, irn);
+               }
+               else {
+                       assert(0 && "move not supported for this mode");
+               }
+       } else if (mode_is_dataM(mode)) {
+               lc_esnprintf(arm_env, cmd_buf, SNPRINTF_BUF_LEN, "ldr %1D, [%1S, #%O]", irn, irn, irn );
+               lc_esnprintf(arm_env, cmnt_buf, SNPRINTF_BUF_LEN, "/* Reload(%1S) -> (%1D) */", irn, irn);
+               arm_fprintf_format(F, cmd_buf, cmnt_buf, irn);
        } else {
                assert(0 && "reload not supported for this mode");
        }
@@ -654,22 +726,42 @@ static void emit_be_Reload(const ir_node* irn, arm_emit_env_t *emit_env) {
 
 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);
+       const lc_arg_env_t *arm_env = arm_get_arg_env();
+       char cmd_buf[SNPRINTF_BUF_LEN], cmnt_buf[SNPRINTF_BUF_LEN];
+
+       lc_esnprintf(arm_env, cmd_buf, SNPRINTF_BUF_LEN, "eor %1S, %1S, %2S", irn, irn, irn);
+       lc_esnprintf(arm_env, cmnt_buf, SNPRINTF_BUF_LEN, "/* begin Perm(%1S, %2S) */", irn, irn);
+       arm_fprintf_format(F, cmd_buf, cmnt_buf, irn);
+
+       lc_esnprintf(arm_env, cmd_buf, SNPRINTF_BUF_LEN, "eor %2S, %1S, %2S", irn, irn, irn);
+       lc_esnprintf(arm_env, cmnt_buf, SNPRINTF_BUF_LEN, " ");
+       arm_fprintf_format(F, cmd_buf, cmnt_buf, irn);
+
+       lc_esnprintf(arm_env, cmd_buf, SNPRINTF_BUF_LEN, "eor %1S, %1S, %2S", irn, irn, irn);
+       lc_esnprintf(arm_env, cmnt_buf, SNPRINTF_BUF_LEN, "/* end Perm(%1S, %2S) */", irn, irn);
+       arm_fprintf_format(F, cmd_buf, cmnt_buf, 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");
+       const lc_arg_env_t *arm_env = arm_get_arg_env();
+       char cmd_buf[SNPRINTF_BUF_LEN], cmnt_buf[SNPRINTF_BUF_LEN];
 
-       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);
+       if (mode_is_float(mode)) {
+               if (USE_FPA(emit_env->cg->isa)) {
+                       lc_esnprintf(arm_env, cmd_buf, SNPRINTF_BUF_LEN, "ldf %1D, [%1S, #%O]", irn, irn, irn );
+                       lc_esnprintf(arm_env, cmnt_buf, SNPRINTF_BUF_LEN, "/* StackParam: (%1S + %O) -> %1D */",irn , irn, irn, get_irn_n(irn, 0));
+                       arm_fprintf_format(F, cmd_buf, cmnt_buf, irn);
+               }
+               else {
+                       assert(0 && "move not supported for this mode");
+               }
+       } else {
+               lc_esnprintf(arm_env, cmd_buf, SNPRINTF_BUF_LEN, "ldr %1D, [%1S, #%O]", irn, irn, irn );
+               lc_esnprintf(arm_env, cmnt_buf, SNPRINTF_BUF_LEN, "/* StackParam: (%1S + %O) -> %1D */",irn , irn, irn, get_irn_n(irn, 0));
+               arm_fprintf_format(F, cmd_buf, cmnt_buf, irn);
+       }
 }
 
 /************************************************************************/
@@ -677,17 +769,32 @@ static void emit_be_StackParam(const ir_node *irn, arm_emit_env_t *emit_env) {
 /************************************************************************/
 
 static void emit_Jmp(ir_node *irn, void *env) {
+       char cmd_buf[SNPRINTF_BUF_LEN];
        arm_emit_env_t *emit_env = env;
-       FILE *out = emit_env->out;
+       FILE *F = emit_env->out;
        const ir_edge_t *edge = get_irn_out_edge_first(irn);
+       const lc_arg_env_t *arm_env = arm_get_arg_env();
        ir_node *target_block = get_edge_src_irn(edge);
-       fprintf(out, "\tB BLOCK_%ld\t\t\t/* unconditional Jump */\n", get_irn_node_nr(target_block));
+
+       lc_esnprintf(arm_env, cmd_buf, SNPRINTF_BUF_LEN, "b BLOCK_%d", get_irn_node_nr(target_block));
+       arm_fprintf_format(F, cmd_buf, "/* unconditional Jump */", irn);
 }
 
-static void emit_Proj(ir_node *irn, void *env) {
+static void emit_arm_fpaDbl2GP(const ir_node *n, arm_emit_env_t *env) {
+  FILE *F = env->out;
+  char cmd_buf[256];
+  const lc_arg_env_t *arg_env = arm_get_arg_env();
 
+  lc_esnprintf(arg_env, cmd_buf, 256, "stfd %1S, [sp, #-8]! ", n);
+  arm_fprintf_format(F, cmd_buf, "/* Push fp to stack */", n);
+
+  lc_esnprintf(arg_env, cmd_buf, 256, "ldmfd sp!, {%2D, %1D} ", n, n);
+  arm_fprintf_format(F, cmd_buf, "/* Pop destination */", n);
 }
 
+static void emit_silence(ir_node *irn, void *env) {
+
+}
 
 
 /***********************************************************************************
@@ -706,9 +813,10 @@ static void emit_Proj(ir_node *irn, void *env) {
  */
 static void arm_register_emitters(void) {
 
-#define ARM_EMIT(a) op_arm_##a->ops.generic = (op_func)emit_arm_##a
+#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
+#define SILENCE(a)   op_##a->ops.generic = (op_func)emit_silence
 
        /* first clear the generic function pointer for all ops */
        clear_irp_opcodes_generic_func();
@@ -717,13 +825,13 @@ static void arm_register_emitters(void) {
        arm_register_spec_emitters();
 
        /* other emitter functions */
-       ARM_EMIT(CondJmp);
-//     ARM_EMIT(SwitchJmp);
-       ARM_EMIT(CopyB);
+       ARM_EMIT(CondJmp);
+       ARM_EMIT(CopyB);
 //     ARM_EMIT(CopyB_i);
 //     ARM_EMIT(Const);
        ARM_EMIT(SymConst);
        ARM_EMIT(SwitchJmp);
+       ARM_EMIT(fpaDbl2GP);
 
        /* benode emitter */
        BE_EMIT(Call);
@@ -736,36 +844,41 @@ static void arm_register_emitters(void) {
        BE_EMIT(StackParam);
 
        /* firm emitter */
-       EMIT(Jmp);
-
+       EMIT(Jmp);
 
        /* noisy stuff */
 #ifdef SILENCER
-       EMIT(Proj);
+       SILENCE(Proj);
+       SILENCE(Phi);
+       SILENCE(be_Keep);
+       SILENCE(be_CopyKeep);
 #endif
 
 #undef ARM_EMIT
 #undef BE_EMIT
 #undef EMIT
+#undef SILENCE
 }
 
+typedef void (node_emitter)(const ir_node *, void *);
+
 /**
  * Emits code for a node.
  */
 static void arm_emit_node(const ir_node *irn, void *env) {
-       arm_emit_env_t        *emit_env = env;
-       FILE              *F        = emit_env->out;
-       ir_op             *op       = get_irn_op(irn);
-       DEBUG_ONLY(firm_dbg_module_t *mod      = emit_env->mod;)
+       arm_emit_env_t *emit_env = env;
+       FILE           *F        = emit_env->out;
+       ir_op          *op       = get_irn_op(irn);
+       DEBUG_ONLY(firm_dbg_module_t *mod = emit_env->mod;)
 
        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);
+               node_emitter *emit = (node_emitter *)op->ops.generic;
+               emit(irn, env);
        }
        else {
-               ir_fprintf(F, "\t\t\t\t\t/* %+F */\n", irn);
+               ir_fprintf(F, "\t%-35s /* %+F %G */\n", "", irn, irn);
        }
 }
 
@@ -776,9 +889,6 @@ static void arm_emit_node(const ir_node *irn, void *env) {
 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);
@@ -790,10 +900,13 @@ void arm_gen_block(ir_node *block, void *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");
+       ir_entity *ent = get_irg_entity(irg);
+       const char *irg_name = get_entity_ld_name(ent);
+       arm_switch_section(F, SECTION_TEXT);
        fprintf(F, "\t.align  2\n");
-       fprintf(F, "\t.global %s\n", irg_name);
+
+       if (get_entity_visibility(ent) == visibility_external_visible)
+               fprintf(F, "\t.global %s\n", irg_name);
        fprintf(F, "%s:\n", irg_name);
 }
 
@@ -801,6 +914,7 @@ void arm_emit_start(FILE *F, ir_graph *irg) {
  * Emits code for function end
  */
 void arm_emit_end(FILE *F, ir_graph *irg) {
+       fprintf(F, "\t.ident \"firmcc\"\n");
 }
 
 /**
@@ -819,14 +933,19 @@ void arm_gen_labels(ir_node *block, void *env) {
 
 
 /**
- * Main driver
+ * Main driver. Emits the code for one routine.
  */
 void arm_gen_routine(FILE *F, ir_graph *irg, const arm_code_gen_t *cg) {
+       SymConstEntry *entry;
        arm_emit_env_t emit_env;
+    ir_node **blk_sched;
+    int i, n;
 
        emit_env.out      = F;
        emit_env.arch_env = cg->arch_env;
        emit_env.cg       = cg;
+       emit_env.symbols  = NULL;
+       obstack_init(&emit_env.obst);
        FIRM_DBG_REGISTER(emit_env.mod, "firm.be.arm.emit");
 
        /* set the global arch_env (needed by print hooks) */
@@ -834,8 +953,33 @@ void arm_gen_routine(FILE *F, ir_graph *irg, const arm_code_gen_t *cg) {
 
        arm_register_emitters();
 
+       /* create the block schedule. For now, we don't need it earlier. */
+       blk_sched = be_create_block_schedule(cg->irg, cg->birg->exec_freq);
+
        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);
+
+       n = ARR_LEN(blk_sched);
+       for (i = 0; i < n;) {
+               ir_node *block, *next_bl;
+
+               block   = blk_sched[i];
+               ++i;
+               next_bl = i < n ? blk_sched[i] : NULL;
+
+               /* set here the link. the emitter expects to find the next block here */
+               set_irn_link(block, next_bl);
+               arm_gen_block(block, &emit_env);
+       }
+
+       /* emit SymConst values */
+       if (emit_env.symbols)
+               fprintf(F, "\t.align 2\n");
+
+       for (entry = emit_env.symbols; entry; entry = entry->next) {
+               fprintf(F, ".L%u:\n", entry->label);
+               lc_efprintf(arm_get_arg_env(), F, "\t.word\t%C\n", entry->symconst);
+       }
+
+       obstack_free(&emit_env.obst, NULL);
 }