More missing config.h
[libfirm] / ir / be / ia32 / ia32_emitter.c
index 0f76d6b..0afa23d 100644 (file)
@@ -272,18 +272,22 @@ static int ia32_get_reg_name(lc_appendable_t *app,
 static int ia32_get_x87_name(lc_appendable_t *app,
     const lc_arg_occ_t *occ, const lc_arg_value_t *arg)
 {
-       const char *buf;
+       const char  *buf;
        ir_node     *irn = arg->v_ptr;
        int         nr = occ->width - 1;
        ia32_attr_t *attr;
+       int         res = 0;
 
        if (! irn)
                return lc_appendable_snadd(app, "(null)", 6);
 
        attr = get_ia32_attr(irn);
-       buf = attr->x87[nr]->name;
-       lc_appendable_chadd(app, '%');
-       return lc_appendable_snadd(app, buf, strlen(buf));
+       buf  = attr->x87[nr]->name;
+
+       res += lc_appendable_chadd(app, '%');
+       res += lc_appendable_snadd(app, buf, strlen(buf));
+
+       return res;
 }
 
 /**
@@ -525,13 +529,12 @@ const char *ia32_emit_x87_binop(const ir_node *n, ia32_emit_env_t *env) {
                                const arch_register_t *in2 = attr->x87[1];
                                const arch_register_t *out = attr->x87[2];
                                const arch_register_t *in;
-                               const char            *in_name;
 
-                               in      = out ? (REGS_ARE_EQUAL(out, in2) ? in1 : in2) : in2;
-                               out     = out ? out : in1;
-                               in_name = arch_register_get_name(in);
+                               in  = out ? (REGS_ARE_EQUAL(out, in2) ? in1 : in2) : in2;
+                               out = out ? out : in1;
 
-                               snprintf(buf, SNPRINTF_BUF_LEN, "%%%s, %%%s", arch_register_get_name(out), in_name);
+                               snprintf(buf, SNPRINTF_BUF_LEN, "%%%s, %%%s",
+                                       arch_register_get_name(out), arch_register_get_name(in));
                        }
                        break;
                case ia32_AddrModeS:
@@ -871,15 +874,23 @@ static void finish_CondJmp(FILE *F, const ir_node *irn, ir_mode *mode) {
        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;
 
-               flipped = 1;
-               pnc = get_negated_pnc(pnc, mode);
+               proj_true  = proj_false;
+               proj_false = t;
+               flipped    = 1;
+               pnc        = get_negated_pnc(pnc, mode);
        }
 
        /* the first Proj must always be created */
        is_unsigned = mode_is_float(mode) || ! mode_is_signed(mode);
+
+       /* in case of unordered compare, check for parity */
+       if (pnc & pn_Cmp_Uo) {
+               snprintf(cmd_buf, SNPRINTF_BUF_LEN, "jp %s", get_cfop_target(proj_true, buf));
+               snprintf(cmnt_buf, SNPRINTF_BUF_LEN, "/* jump to false if result is unordered */");
+               IA32_DO_EMIT(irn);
+       }
+
        snprintf(cmd_buf, SNPRINTF_BUF_LEN, "j%s %s",
                 get_cmp_suffix(pnc, is_unsigned),
                 get_cfop_target(proj_true, buf));
@@ -981,12 +992,13 @@ static void emit_ia32_xCondJmp(ir_node *irn, ia32_emit_env_t *env) {
        FILE *F = env->out;
        char cmd_buf[SNPRINTF_BUF_LEN];
        char cmnt_buf[SNPRINTF_BUF_LEN];
+       const lc_arg_env_t *arg_env = ia32_get_arg_env();
 
-       lc_esnprintf(ia32_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "ucomis%M %s", irn, ia32_emit_binop(irn, env));
-       lc_esnprintf(ia32_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "/* %+F */", irn);
+       lc_esnprintf(arg_env, cmd_buf, SNPRINTF_BUF_LEN, "ucomis%M %s", irn, ia32_emit_binop(irn, env));
+       lc_esnprintf(arg_env, cmnt_buf, SNPRINTF_BUF_LEN, "/* %+F */", irn);
        IA32_DO_EMIT(irn);
-       finish_CondJmp(F, irn, mode_F);
 
+       finish_CondJmp(F, irn, mode_F);
 }
 
 /**
@@ -1139,8 +1151,7 @@ static void Set_emitter(ir_node *irn, ir_mode *mode, ia32_emit_env_t *env) {
                lc_esnprintf(arg_env, cmd_buf, SNPRINTF_BUF_LEN, "ucomis%M %s", get_irn_n(irn, 2), ia32_emit_binop(irn, env));
        }
        else if (is_ia32_PsiCondSet(irn)) {
-               /* omit compare because flags are already set by And/Or */
-               snprintf(cmd_buf, SNPRINTF_BUF_LEN, " ");
+               lc_esnprintf(arg_env, cmd_buf, SNPRINTF_BUF_LEN, "cmp %1S, 0", irn);
        }
        else {
                assert(0 && "unsupported Set");
@@ -1775,9 +1786,10 @@ static void emit_be_Perm(const ir_node *irn, ia32_emit_env_t *emit_env) {
        assert(cls1 == cls2 && "Register class mismatch at Perm");
 
        if (cls1 == &ia32_reg_classes[CLASS_ia32_gp]) {
+#if 0
                if(emit_env->isa->opt_arch == arch_athlon) {
                        // xchg commands are Vector path on athlons and therefore stall the DirectPath pipeline
-                       // it is nearly always beneficial to use the 3 xor trick instead of an xchg
+                       // it is often beneficial to use the 3 xor trick instead of an xchg
                        cmnt_buf[0] = 0;
                        lc_esnprintf(ia32_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "xor %1S, %2S", irn, irn);
                        IA32_DO_EMIT(irn);
@@ -1785,8 +1797,11 @@ static void emit_be_Perm(const ir_node *irn, ia32_emit_env_t *emit_env) {
                        IA32_DO_EMIT(irn);
                        lc_esnprintf(ia32_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "xor %1S, %2S", irn, irn);
                } else {
+#endif
                        lc_esnprintf(ia32_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "xchg %1S, %2S", irn, irn);
+#if 0
                }
+#endif
        }
        else if (cls1 == &ia32_reg_classes[CLASS_ia32_xmm]) {
                lc_esnprintf(ia32_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN,
@@ -1819,7 +1834,7 @@ static void emit_ia32_Const(const ir_node *n, ia32_emit_env_t *env) {
                lc_esnprintf(arg_env, cmd_buf, 256, "mov %1D, OFFSET FLAT:%C ", n, n);
                lc_esnprintf(arg_env, cmnt_buf, 256, "/* Move address of SymConst into register */");
        } else {
-               assert(mode == get_tarval_mode(tv));
+               assert(mode == get_tarval_mode(tv) || (mode_is_reference(get_tarval_mode(tv)) && mode == mode_Iu));
                /* beware: in some rare cases mode is mode_b which has no tarval_null() */
                if (tv == get_tarval_b_false() || tv == get_tarval_null(mode)) {
                        const char *instr = "xor";
@@ -2021,6 +2036,9 @@ static void ia32_emit_dbg(const ir_node *irn, ia32_emit_env_t *env) {
        unsigned lineno;
        const char *fname = be_retrieve_dbg_info(db, &lineno);
 
+       if (! env->cg->birg->main_env->options->stabs_debug_support)
+               return;
+
        if (fname) {
                if (last_name != fname) {
                        last_line = -1;
@@ -2150,37 +2168,55 @@ static int is_first_loop_block(ir_node *block, ir_node *prev_block, ia32_emit_en
  * and emits code for each node.
  */
 static void ia32_gen_block(ir_node *block, ir_node *last_block, ia32_emit_env_t *env) {
-       ir_graph *irg = get_irn_irg(block);
-       ir_node *start_block = get_irg_start_block(irg);
+       ir_graph      *irg         = get_irn_irg(block);
+       ir_node       *start_block = get_irg_start_block(irg);
+       int           need_label   = 1;
+       FILE          *F           = env->out;
        const ir_node *irn;
-       int need_label = 1;
-       FILE *F = env->out;
+       int           i;
 
        assert(is_Block(block));
 
-       if(block == start_block)
+       if (block == start_block)
                need_label = 0;
 
        if (need_label && get_irn_arity(block) == 1) {
                ir_node *pred_block = get_Block_cfgpred_block(block, 0);
 
-               if(pred_block == last_block && get_irn_n_edges_kind(pred_block, EDGE_KIND_BLOCK) <= 2)
+               if (pred_block == last_block && get_irn_n_edges_kind(pred_block, EDGE_KIND_BLOCK) <= 2)
                        need_label = 0;
        }
 
-       // special case because the start block contains no jump instruction
-       if(last_block == start_block) {
+       /* special case: if one of our cfg preds is a switch-jmp we need a label, */
+       /*               otherwise there might be jump table entries jumping to   */
+       /*               non-existent (omitted) labels                            */
+       for (i = get_Block_n_cfgpreds(block) - 1; i >= 0; --i) {
+               ir_node *pred = get_Block_cfgpred(block, i);
+
+               if (is_Proj(pred)) {
+                       assert(get_irn_mode(pred) == mode_X);
+                       if (is_ia32_SwitchJmp(get_Proj_pred(pred))) {
+                               need_label = 1;
+                               break;
+                       }
+               }
+       }
+
+       /* special case because the start block contains no jump instruction */
+       if (last_block == start_block) {
                const ir_edge_t *edge;
                ir_node *startsucc = NULL;
 
                foreach_block_succ(start_block, edge) {
                        startsucc = get_edge_src_irn(edge);
-                       if(startsucc != start_block)
+                       if (startsucc != start_block)
                                break;
                }
                assert(startsucc != NULL);
 
-               if(startsucc != block) {
+               /* if the last block was the start block and we are not inside the */
+               /* start successor, emit a jump to the start successor             */
+               if (startsucc != block) {
                        char buf[SNPRINTF_BUF_LEN];
                        ir_snprintf(buf, sizeof(buf), BLOCK_PREFIX("%d"),
                                    get_irn_node_nr(startsucc));
@@ -2194,21 +2230,22 @@ static void ia32_gen_block(ir_node *block, ir_node *last_block, ia32_emit_env_t
                int align = 1;
                ir_exec_freq *execfreqs = env->cg->birg->execfreqs;
 
-               // align the loop headers
-               if(!is_first_loop_block(block, last_block, env)) {
-
-                       // align blocks where the previous block has no fallthrough
+               /* align the loop headers */
+               if (! is_first_loop_block(block, last_block, env)) {
+                       /* align blocks where the previous block has no fallthrough */
                        arity = get_irn_arity(block);
-                       for(i = 0; i < arity; ++i) {
+
+                       for (i = 0; i < arity; ++i) {
                                ir_node *predblock = get_Block_cfgpred_block(block, i);
-                               if(predblock == last_block) {
+
+                               if (predblock == last_block) {
                                        align = 0;
                                        break;
                                }
                        }
                }
 
-               if(align)
+               if (align)
                        ia32_emit_align_label(env->out, env->isa->opt_arch);
 
                ir_snprintf(cmd_buf, sizeof(cmd_buf), BLOCK_PREFIX("%d:"),
@@ -2219,11 +2256,12 @@ static void ia32_gen_block(ir_node *block, ir_node *last_block, ia32_emit_env_t
                fprintf(F, "/* preds:");
 
                arity = get_irn_arity(block);
-               for(i = 0; i < arity; ++i) {
+               for (i = 0; i < arity; ++i) {
                        ir_node *predblock = get_Block_cfgpred_block(block, i);
                        fprintf(F, " %ld", get_irn_node_nr(predblock));
                }
-               if(execfreqs != NULL) {
+
+               if (execfreqs != NULL) {
                        fprintf(F, " freq: %f", get_block_execfreq(execfreqs, block));
                }