- implemented apply phase
[libfirm] / ir / be / arm / arm_emitter.c
index 0848575..85fa69e 100644 (file)
@@ -25,9 +25,7 @@
  */
 #define SILENCER
 
-#ifdef HAVE_CONFIG_H
 #include "config.h"
-#endif
 
 #include <limits.h>
 
 #include "../beblocksched.h"
 #include "../beirg_t.h"
 #include "../begnuas.h"
+#include "../be_dbgout.h"
 
 #include "arm_emitter.h"
+#include "arm_optimize.h"
 #include "gen_arm_emitter.h"
 #include "arm_nodes_attr.h"
 #include "arm_new_nodes.h"
@@ -65,9 +65,7 @@
 
 DEBUG_ONLY(static firm_dbg_module_t *dbg = NULL;)
 
-static const arch_env_t     *arch_env = NULL;
 static const arm_code_gen_t *cg;
-static const arm_isa_t      *isa;
 static set                  *sym_or_tv;
 
 /**
@@ -83,16 +81,13 @@ static const arch_register_t *get_in_reg(const ir_node *irn, int pos) {
           in register we need. */
        op = get_irn_n(irn, pos);
 
-       reg = arch_get_irn_register(arch_env, op);
+       reg = arch_get_irn_register(op);
 
        assert(reg && "no in register found");
 
        /* in case of a joker register: just return a valid register */
        if (arch_register_type_is(reg, joker)) {
-               const arch_register_req_t *req;
-
-               /* ask for the requirements */
-               req = arch_get_register_req(arch_env, irn, pos);
+               const arch_register_req_t *req = arch_get_register_req(irn, pos);
 
                if (arch_register_req_is(req, limited)) {
                        /* in case of limited requirements: get the first allowed register */
@@ -121,7 +116,7 @@ static const arch_register_t *get_out_reg(const ir_node *node, int pos)
     /*           Proj with the corresponding projnum for the register */
 
     if (get_irn_mode(node) != mode_T) {
-        reg = arch_get_irn_register(arch_env, node);
+        reg = arch_get_irn_register(node);
     } else if (is_arm_irn(node)) {
         reg = get_arm_out_reg(node, pos);
     } else {
@@ -131,7 +126,7 @@ static const arch_register_t *get_out_reg(const ir_node *node, int pos)
             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);
+                reg = arch_get_irn_register(proj);
                 break;
             }
         }
@@ -173,13 +168,11 @@ void arm_emit_dest_register(const ir_node *node, int pos) {
  */
 void arm_emit_offset(const ir_node *node) {
        int offset = 0;
-       ir_op *irn_op = get_irn_op(node);
+       ir_opcode opc = get_irn_opcode(node);
 
-       if (irn_op == op_be_Reload || irn_op == op_be_Spill) {
+       if (opc == beo_Reload || opc == beo_Spill) {
                ir_entity *ent = be_get_frame_entity(node);
                offset = get_entity_offset(ent);
-       } else if (irn_op == op_be_IncSP) {
-               offset = - be_get_IncSP_offset(node);
        } else {
                assert(!"unimplemented arm_emit_offset for this node type");
                panic("unimplemented arm_emit_offset for this node type");
@@ -192,12 +185,13 @@ void arm_emit_offset(const ir_node *node) {
  */
 static void arm_emit_fpa_postfix(const ir_mode *mode) {
        int bits = get_mode_size_bits(mode);
+       char c = 'e';
+
        if (bits == 32)
-               be_emit_char('s');
+               c = 's';
        else if (bits == 64)
-               be_emit_char('d');
-       else
-               be_emit_char('e');
+               c = 'd';
+       be_emit_char(c);
 }
 
 /**
@@ -222,9 +216,9 @@ void arm_emit_immediate(const ir_node *node) {
        const arm_attr_t *attr = get_arm_attr_const(node);
 
        if (ARM_GET_SHF_MOD(attr) == ARM_SHF_IMM) {
-               be_emit_irprintf("#0x%X", arm_decode_imm_w_shift(get_arm_value(node)));
+               be_emit_irprintf("#0x%X", arm_decode_imm_w_shift(get_arm_imm_value(node)));
        } else if (ARM_GET_FPA_IMM(attr)) {
-               be_emit_irprintf("#0x%F", get_arm_value(node));
+               be_emit_irprintf("#%s", arm_get_fpa_imm_name(get_arm_imm_value(node)));
        } else if (is_arm_SymConst(node))
                be_emit_ident(get_arm_symconst_id(node));
        else {
@@ -240,9 +234,9 @@ void arm_emit_shift(const ir_node *node) {
 
        mod = get_arm_shift_modifier(node);
        if (ARM_HAS_SHIFT(mod)) {
-               long v = get_tarval_long(get_arm_value(node));
+               int v = get_arm_imm_value(node);
 
-               be_emit_irprintf(", %s #%l", arm_shf_mod_name(mod), v);
+               be_emit_irprintf(", %s #%d", arm_shf_mod_name(mod), v);
        }
 }
 
@@ -297,7 +291,7 @@ static void emit_arm_fpaConst(const ir_node *irn) {
        unsigned label;
        ir_mode *mode;
 
-       key.u.tv     = get_arm_value(irn);
+       key.u.tv     = get_fpaConst_value(irn);
        key.is_ident = 0;
        key.label    = 0;
        entry = (sym_or_tv_t *)set_insert(sym_or_tv, &key, sizeof(key), HASH_PTR(key.u.generic));
@@ -337,7 +331,7 @@ static ir_node *get_cfop_target_block(const ir_node *irn) {
  */
 static void arm_emit_block_name(const ir_node *block) {
        if (has_Block_label(block)) {
-               be_emit_string(be_gas_label_prefix());
+               be_emit_string(be_gas_block_label_prefix());
                be_emit_irprintf("%lu", get_Block_label(block));
        } else {
                be_emit_cstring(BLOCK_PREFIX);
@@ -452,6 +446,80 @@ static void emit_arm_CmpBra(const ir_node *irn) {
        }
 }
 
+
+/**
+ * Emit a Tst with conditional branch.
+ */
+static void emit_arm_TstBra(const ir_node *irn)
+{
+       const ir_edge_t *edge;
+       const ir_node *proj_true  = NULL;
+       const ir_node *proj_false = NULL;
+       const ir_node *block;
+       const ir_node *next_block;
+       const char *suffix;
+       int proj_num = get_arm_CondJmp_proj_num(irn);
+
+       foreach_out_edge(irn, edge) {
+               ir_node *proj = get_edge_src_irn(edge);
+               long nr = get_Proj_proj(proj);
+               if (nr == pn_Cond_true) {
+                       proj_true = proj;
+               } else {
+                       proj_false = proj;
+               }
+       }
+
+       /* for now, the code works for scheduled and non-schedules blocks */
+       block = get_nodes_block(irn);
+
+       /* we have a block schedule */
+       next_block = sched_next_block(block);
+
+       assert(proj_num != pn_Cmp_False);
+       assert(proj_num != pn_Cmp_True);
+
+       if (get_cfop_target_block(proj_true) == next_block) {
+               /* exchange both proj's so the second one can be omitted */
+               const ir_node *t = proj_true;
+
+               proj_true  = proj_false;
+               proj_false = t;
+               proj_num   = get_negated_pnc(proj_num, mode_Iu);
+       }
+       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(!"Cmp unsupported"); suffix = "al";
+       }
+       be_emit_cstring("\ttst ");
+       arm_emit_source_register(irn, 0);
+       be_emit_cstring(", ");
+       arm_emit_source_register(irn, 1);
+       be_emit_finish_line_gas(irn);
+
+       /* emit the true proj */
+       be_emit_irprintf("\tb%s ", suffix);
+       arm_emit_cfop_target(proj_true);
+       be_emit_finish_line_gas(proj_true);
+
+       if (get_cfop_target_block(proj_false) == next_block) {
+               be_emit_cstring("\t/* fallthrough to ");
+               arm_emit_cfop_target(proj_false);
+               be_emit_cstring(" */");
+               be_emit_finish_line_gas(proj_false);
+       } else {
+               be_emit_cstring("b ");
+               arm_emit_cfop_target(proj_false);
+               be_emit_finish_line_gas(proj_false);
+       }
+}
+
 /**
  * Emit a Compare with conditional branch.
  */
@@ -478,7 +546,7 @@ static int reg_cmp(const void *a, const void *b) {
  * Create the CopyB instruction sequence.
  */
 static void emit_arm_CopyB(const ir_node *irn) {
-       unsigned int size = get_tarval_long(get_arm_value(irn));
+       unsigned size = (unsigned)get_arm_imm_value(irn);
 
        const char *tgt = arch_register_get_name(get_in_reg(irn, 0));
        const char *src = arch_register_get_name(get_in_reg(irn, 1));
@@ -505,7 +573,7 @@ static void emit_arm_CopyB(const ir_node *irn) {
        be_emit_string(src);
        be_emit_cstring(")->(");
        arm_emit_source_register(irn, 0);
-       be_emit_irprintf(" [%d bytes], Uses ", size);
+       be_emit_irprintf(" [%u bytes], Uses ", size);
        be_emit_string(t0);
        be_emit_cstring(", ");
        be_emit_string(t1);
@@ -628,7 +696,7 @@ static void emit_arm_SwitchJmp(const ir_node *irn) {
        block_nr = get_irn_node_nr(irn);
        n_projs = get_arm_SwitchJmp_n_projs(irn);
 
-       projs = xcalloc(n_projs , sizeof(ir_node*));
+       projs = XMALLOCNZ(ir_node*, n_projs);
 
        foreach_out_edge(irn, edge) {
                proj = get_edge_src_irn(edge);
@@ -712,19 +780,22 @@ static void emit_be_Call(const ir_node *irn) {
 
 /** Emit an IncSP node */
 static void emit_be_IncSP(const ir_node *irn) {
-       int offs = be_get_IncSP_offset(irn);
+       int offs = -be_get_IncSP_offset(irn);
 
        if (offs != 0) {
-               be_emit_cstring("\tadd ");
+               if (offs < 0) {
+                       be_emit_cstring("\tsub ");
+                       offs = -offs;
+               } else {
+                       be_emit_cstring("\tadd ");
+               }
                arm_emit_dest_register(irn, 0);
                be_emit_cstring(", ");
                arm_emit_source_register(irn, 0);
-               be_emit_cstring(", #");
-               arm_emit_offset(irn);
+               be_emit_irprintf(", #0x%X", offs);
        } else {
-               be_emit_cstring("\t/* omitted IncSP(");
-               arm_emit_offset(irn);
-               be_emit_cstring(") */");
+               /* omitted IncSP(0) */
+               return;
        }
        be_emit_finish_line_gas(irn);
 }
@@ -733,16 +804,12 @@ static void emit_be_Copy(const ir_node *irn) {
        ir_mode *mode = get_irn_mode(irn);
 
        if (get_in_reg(irn, 0) == get_out_reg(irn, 0)) {
-               be_emit_cstring("\t/* omitted Copy: ");
-               arm_emit_source_register(irn, 0);
-               be_emit_cstring(" -> ");
-               arm_emit_dest_register(irn, 0);
-               be_emit_finish_line_gas(irn);
+               /* omitted Copy */
                return;
        }
 
        if (mode_is_float(mode)) {
-               if (USE_FPA(isa)) {
+               if (USE_FPA(cg->isa)) {
                        be_emit_cstring("\tmvf");
                        arm_emit_mode(irn);
                        be_emit_char(' ');
@@ -895,7 +962,7 @@ static void emit_arm_fpaDbl2GP(const ir_node *irn) {
 
 static void emit_arm_LdTls(const ir_node *irn) {
        (void) irn;
-       panic("TLS not supported for this target\n");
+       panic("TLS not supported for this target");
        /* Er... our gcc does not support it... Install a newer toolchain. */
 }
 
@@ -922,7 +989,7 @@ typedef void (emit_func)(const ir_node *irn);
 /**
  * Set a node emitter. Make it a bit more type safe.
  */
-static INLINE void set_emitter(ir_op *op, emit_func arm_emit_node) {
+static inline void set_emitter(ir_op *op, emit_func arm_emit_node) {
        op->ops.generic = (op_func)arm_emit_node;
 }
 
@@ -945,6 +1012,7 @@ static void arm_register_emitters(void) {
 
        /* other emitter functions */
        ARM_EMIT(CmpBra);
+       ARM_EMIT(TstBra);
        ARM_EMIT(fpaCmfBra);
        ARM_EMIT(fpaCmfeBra);
        ARM_EMIT(CopyB);
@@ -985,40 +1053,6 @@ static void arm_register_emitters(void) {
 #undef SILENCE
 }
 
-static const char *last_name = NULL;
-static unsigned last_line = -1;
-static unsigned num = -1;
-
-/**
- * Emit the debug support for node node.
- */
-static void arm_emit_dbg(const ir_node *irn) {
-       dbg_info *db = get_irn_dbg_info(irn);
-       unsigned lineno;
-       const char *fname = ir_retrieve_dbg_info(db, &lineno);
-
-       if (! cg->birg->main_env->options->stabs_debug_support)
-               return;
-
-       if (fname) {
-               if (last_name != fname) {
-                       last_line = -1;
-                       be_dbg_include_begin(cg->birg->main_env->db_handle, fname);
-                       last_name = fname;
-               }
-               if (last_line != lineno) {
-                       char name[64];
-
-                       snprintf(name, sizeof(name), ".LM%u", ++num);
-                       last_line = lineno;
-                       be_dbg_line(cg->birg->main_env->db_handle, lineno, name);
-                       be_emit_string(name);
-                       be_emit_cstring(":\n");
-                       be_emit_write_line();
-               }
-       }
-}
-
 /**
  * Emits code for a node.
  */
@@ -1027,7 +1061,7 @@ static void arm_emit_node(const ir_node *irn) {
 
        if (op->ops.generic) {
                emit_func *emit = (emit_func *)op->ops.generic;
-               arm_emit_dbg(irn);
+               be_dbg_set_dbg_info(get_irn_dbg_info(irn));
                (*emit)(irn);
        } else {
                be_emit_cstring("\t/* TODO */");
@@ -1097,7 +1131,7 @@ static void arm_gen_block(ir_node *block, ir_node *prev_block) {
        ir_node *irn;
 
        arm_emit_block_header(block, prev_block);
-       arm_emit_dbg(block);
+       be_dbg_set_dbg_info(get_irn_dbg_info(block));
        sched_foreach(block, irn) {
                arm_emit_node(irn);
        }
@@ -1159,18 +1193,18 @@ static int cmp_sym_or_tv(const void *elt, const void *key, size_t size) {
  * Main driver. Emits the code for one routine.
  */
 void arm_gen_routine(const arm_code_gen_t *arm_cg, ir_graph *irg) {
-       ir_node **blk_sched;
-       int i, n;
-       ir_node *last_block = NULL;
+       ir_node   **blk_sched;
+       int       i, n;
+       ir_node   *last_block = NULL;
+       ir_entity *entity     = get_irg_entity(irg);
 
        cg        = arm_cg;
-       isa       = (const arm_isa_t *)cg->arch_env->isa;
-       arch_env  = cg->arch_env;
        sym_or_tv = new_set(cmp_sym_or_tv, 8);
 
-
        arm_register_emitters();
 
+       be_dbg_method_begin(entity, be_abi_get_stack_layout(cg->birg->abi));
+
        /* create the block schedule. For now, we don't need it earlier. */
        blk_sched = be_create_block_schedule(cg->irg, cg->birg->exec_freq);
 
@@ -1191,6 +1225,8 @@ void arm_gen_routine(const arm_code_gen_t *arm_cg, ir_graph *irg) {
                last_block = block;
        }
 
+       be_dbg_method_end();
+
        /* emit SymConst values */
        if (set_count(sym_or_tv) > 0) {
                sym_or_tv_t *entry;