BugFix: copy mode when creating inverse operation
[libfirm] / ir / be / ia32 / ia32_emitter.c
index d81f6d9..29cd8b0 100644 (file)
@@ -512,8 +512,6 @@ const char *ia32_emit_x87_binop(const ir_node *n, ia32_emit_env_t *env) {
                        assert(0 && "unsupported op type");
        }
 
-#undef PRODUCES_RESULT
-
        return buf;
 }
 
@@ -536,7 +534,12 @@ const char *ia32_emit_unop(const ir_node *n, ia32_emit_env_t *env) {
                                lc_esnprintf(ia32_get_arg_env(), buf, SNPRINTF_BUF_LEN, "%C", n);
                        }
                        else {
-                               lc_esnprintf(ia32_get_arg_env(), buf, SNPRINTF_BUF_LEN, "%1D", n);
+                               if (is_ia32_MulS(n) || is_ia32_Mulh(n)) {
+                                       /* MulS and Mulh implicitly multiply by EAX */
+                                       lc_esnprintf(ia32_get_arg_env(), buf, SNPRINTF_BUF_LEN, "%4S", n);
+                               }
+                               else
+                                       lc_esnprintf(ia32_get_arg_env(), buf, SNPRINTF_BUF_LEN, "%1D", n);
                        }
                        break;
                case ia32_AddrModeD:
@@ -827,14 +830,14 @@ static void finish_CondJmp(FILE *F, const ir_node *irn, ir_mode *mode) {
        /* the first Proj must always be created */
        if (get_Proj_proj(proj1) == pn_Cond_true) {
                snprintf(cmd_buf, SNPRINTF_BUF_LEN, "j%s %s",
-                                       get_cmp_suffix(get_ia32_pncode(irn), !mode_is_signed(get_irn_mode(get_irn_n(irn, 0)))),
+                                       get_cmp_suffix(get_ia32_pncode(irn), ! mode_is_signed(get_irn_mode(get_irn_n(irn, 0)))),
                                        get_cfop_target(proj1, buf));
                snprintf(cmnt_buf, SNPRINTF_BUF_LEN, "/* cmp(a, b) == TRUE */");
        }
        else  {
                snprintf(cmd_buf, SNPRINTF_BUF_LEN, "j%s %s",
                                        get_cmp_suffix(get_negated_pnc(get_ia32_pncode(irn), mode),
-                                       !mode_is_signed(get_irn_mode(get_irn_n(irn, 0)))),
+                                       ! mode_is_signed(get_irn_mode(get_irn_n(irn, 0)))),
                                        get_cfop_target(proj1, buf));
                snprintf(cmnt_buf, SNPRINTF_BUF_LEN, "/* cmp(a, b) == FALSE */");
        }
@@ -927,6 +930,21 @@ static void emit_ia32_CJmpAM(const ir_node *irn, ia32_emit_env_t *env) {
        finish_CondJmp(F, irn, get_ia32_res_mode(irn));
 }
 
+/**
+ * Emits code for conditional SSE floating point jump with two variables.
+ */
+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];
+
+       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);
+       IA32_DO_EMIT(irn);
+       finish_CondJmp(F, irn, get_ia32_res_mode(irn));
+
+}
+
 /**
  * Emits code for conditional x87 floating point jump with two variables.
  */
@@ -962,7 +980,7 @@ static void emit_ia32_x87CondJmp(ir_node *irn, ia32_emit_env_t *env) {
        if (reverse)
                set_ia32_pncode(irn, (long)get_negated_pnc(get_ia32_pncode(irn), mode_Is));
 
-       snprintf(cmd_buf, SNPRINTF_BUF_LEN, "%s %s", instr, reg);
+       snprintf(cmd_buf, SNPRINTF_BUF_LEN, "%s %%%s", instr, reg);
        lc_esnprintf(ia32_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "/* %+F */", irn);
        IA32_DO_EMIT(irn);
        lc_esnprintf(ia32_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "fnstsw %%ax", irn);
@@ -979,14 +997,15 @@ static void CMov_emitter(ir_node *irn, ia32_emit_env_t *env) {
        FILE               *F       = env->out;
        const lc_arg_env_t *arg_env = ia32_get_arg_env();
        const char *cmp_suffix = get_cmp_suffix(get_ia32_pncode(irn), ! mode_is_signed(get_irn_mode(get_irn_n(irn, 0))));
+       int is_PsiCondCMov     = is_ia32_PsiCondCMov(irn);
 
        char cmd_buf[SNPRINTF_BUF_LEN];
        char cmnt_buf[SNPRINTF_BUF_LEN];
        const arch_register_t *in1, *in2, *out;
 
        out = arch_get_irn_register(env->arch_env, irn);
-       in1 = arch_get_irn_register(env->arch_env, get_irn_n(irn, 2));
-       in2 = arch_get_irn_register(env->arch_env, get_irn_n(irn, 3));
+       in1 = arch_get_irn_register(env->arch_env, get_irn_n(irn, 2 - is_PsiCondCMov));
+       in2 = arch_get_irn_register(env->arch_env, get_irn_n(irn, 3 - is_PsiCondCMov));
 
        /* we have to emit the cmp first, because the destination register */
        /* could be one of the compare registers                           */
@@ -996,7 +1015,7 @@ static void CMov_emitter(ir_node *irn, ia32_emit_env_t *env) {
        else if (is_ia32_xCmpCMov(irn)) {
                lc_esnprintf(arg_env, cmd_buf, SNPRINTF_BUF_LEN, "ucomis%M %1S, %2S", get_irn_n(irn, 0), irn, irn);
        }
-       else if (is_ia32_PsiCondCMov(irn)) {
+       else if (is_PsiCondCMov) {
                /* omit compare because flags are already set by And/Or */
                snprintf(cmd_buf, SNPRINTF_BUF_LEN, " ");
        }
@@ -1745,6 +1764,7 @@ static void ia32_register_emitters(void) {
        IA32_EMIT(xCmp);
        IA32_EMIT(xCmpSet);
        IA32_EMIT(xCmpCMov);
+       IA32_EMIT(xCondJmp);
        IA32_EMIT2(fcomJmp, x87CondJmp);
        IA32_EMIT2(fcompJmp, x87CondJmp);
        IA32_EMIT2(fcomppJmp, x87CondJmp);