fixed some bugs
[libfirm] / ir / be / ia32 / ia32_emitter.c
index 5eb95a2..d795abd 100644 (file)
@@ -43,6 +43,9 @@ static const arch_env_t *arch_env = NULL;
 char *ia32_emit_binop(const ir_node *n) {
        static char *buf = NULL;
 
+       /* verify that this function is never called on non-AM supporting operations */
+       assert(get_ia32_am_support(n) != ia32_am_None && "emit binop expects addressmode support");
+
        if (! buf) {
                buf = xcalloc(1, SNPRINTF_BUF_LEN);
        }
@@ -53,26 +56,21 @@ char *ia32_emit_binop(const ir_node *n) {
        switch(get_ia32_op_type(n)) {
                case ia32_Normal:
                        if (get_ia32_cnst(n)) {
-                               lc_esnprintf(ia32_get_arg_env(), buf, SNPRINTF_BUF_LEN, "%1D, %s", n, get_ia32_cnst(n));
+                               lc_esnprintf(ia32_get_arg_env(), buf, SNPRINTF_BUF_LEN, "%3S, %s", n, get_ia32_cnst(n));
                        }
                        else {
-                               lc_esnprintf(ia32_get_arg_env(), buf, SNPRINTF_BUF_LEN, "%1D, %4S", n, n);
+                               lc_esnprintf(ia32_get_arg_env(), buf, SNPRINTF_BUF_LEN, "%3S, %4S", n, n);
                        }
                        break;
                case ia32_AddrModeS:
-                       lc_esnprintf(ia32_get_arg_env(), buf, SNPRINTF_BUF_LEN, "%1D, %s", n, ia32_emit_am(n));
+                       lc_esnprintf(ia32_get_arg_env(), buf, SNPRINTF_BUF_LEN, "%4S, %s", n, ia32_emit_am(n));
                        break;
                case ia32_AddrModeD:
                        if (get_ia32_cnst(n)) {
                                lc_esnprintf(ia32_get_arg_env(), buf, SNPRINTF_BUF_LEN, "%s, %s", ia32_emit_am(n), get_ia32_cnst(n));
                        }
                        else {
-                               if (is_ia32_St(n)) {
-                                       lc_esnprintf(ia32_get_arg_env(), buf, SNPRINTF_BUF_LEN, "%s, %3S", ia32_emit_am(n), n);
-                               }
-                               else {
-                                       lc_esnprintf(ia32_get_arg_env(), buf, SNPRINTF_BUF_LEN, "%s, %4S", ia32_emit_am(n), n);
-                               }
+                               lc_esnprintf(ia32_get_arg_env(), buf, SNPRINTF_BUF_LEN, "%s, %3S", ia32_emit_am(n), n);
                        }
                        break;
                default:
@@ -118,6 +116,10 @@ char *ia32_emit_am(const ir_node *n) {
        char             *s;
        int               size;
        static struct obstack *obst  = NULL;
+       ir_mode *mode = get_ia32_ls_mode(n);
+
+       if (! is_ia32_Lea(n))
+               assert(mode && "AM node must have ls_mode attribute set.");
 
        if (! obst) {
                obst = xcalloc(1, sizeof(*obst));
@@ -129,6 +131,22 @@ char *ia32_emit_am(const ir_node *n) {
        /* obstack_free with NULL results in an uninitialized obstack */
        obstack_init(obst);
 
+       if (mode) {
+               switch (get_mode_size_bits(mode)) {
+                       case 8:
+                               obstack_printf(obst, "BYTE PTR ");
+                               break;
+                       case 16:
+                               obstack_printf(obst, "WORD PTR ");
+                               break;
+                       case 32:
+                               obstack_printf(obst, "DWORD PTR ");
+                               break;
+                       default:
+                               assert(0 && "unsupported mode size");
+               }
+       }
+
        obstack_printf(obst, "[");
 
        if (am_flav & ia32_B) {
@@ -206,8 +224,6 @@ 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    */
@@ -236,22 +252,6 @@ static const arch_register_t *get_out_reg(const ir_node *irn, int pos) {
        return reg;
 }
 
-/**
- * Returns the number of the in register at position pos.
- */
-int get_ia32_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);
-}
-
 enum io_direction {
   IN_REG,
   OUT_REG
@@ -267,6 +267,11 @@ static const char *get_ia32_reg_name(ir_node *irn, int pos, enum io_direction in
                reg = get_in_reg(irn, pos);
        }
        else {
+               /* destination address mode nodes don't have outputs */
+               if (is_ia32_irn(irn) && get_ia32_op_type(irn) == ia32_AddrModeD) {
+                       return "MEM";
+               }
+
                reg = get_out_reg(irn, pos);
        }
 
@@ -310,7 +315,7 @@ static int ia32_const_to_str(lc_appendable_t *app,
                buf = get_ia32_am_offs(X);
        }
 
-       return lc_arg_append(app, occ, buf, strlen(buf));
+       return buf ? lc_arg_append(app, occ, buf, strlen(buf)) : 0;
 }
 
 /**
@@ -483,8 +488,8 @@ static void finish_CondJmp(FILE *F, const ir_node *irn) {
 static void emit_ia32_CondJmp(const ir_node *irn, emit_env_t *env) {
        FILE *F = env->out;
 
-       lc_efprintf(ia32_get_arg_env(), F, "\tcmp %2S, %1S\t\t\t/* CondJmp(%+F, %+F) */\n", irn, irn,
-                                                                                                                                       get_irn_n(irn, 0), get_irn_n(irn, 1));
+       lc_efprintf(ia32_get_arg_env(), F, "\tcmp %s\t\t\t/* CondJmp(%+F, %+F) */\n",
+               ia32_emit_binop(irn), get_irn_n(irn, 0), get_irn_n(irn, 1));
        finish_CondJmp(F, irn);
 }
 
@@ -494,7 +499,8 @@ static void emit_ia32_CondJmp(const ir_node *irn, emit_env_t *env) {
 void emit_ia32_CondJmp_i(const ir_node *irn, emit_env_t *env) {
        FILE *F = env->out;
 
-       lc_efprintf(ia32_get_arg_env(), F, "\tcmp %C, %1S\t\t\t/* CondJmp_i(%+F) */\n", irn, irn, get_irn_n(irn, 0));
+       lc_efprintf(ia32_get_arg_env(), F, "\tcmp %s\t\t\t/* CondJmp_i(%+F) */\n",
+               ia32_emit_binop(irn), get_irn_n(irn, 0));
        finish_CondJmp(F, irn);
 }
 
@@ -619,7 +625,7 @@ void emit_ia32_SwitchJmp(const ir_node *irn, emit_env_t *emit_env) {
                if (tbl.num_branches > 1) {
                        /* create table */
 
-                       lc_efprintf(env, F, "\tjmp *%s(,%1S,4)\t\t/* get jump table entry as target */\n", tbl.label, irn);
+                       lc_efprintf(env, F, "\tjmp [%1S*4+%s]\t\t/* get jump table entry as target */\n", irn, tbl.label);
 
                        fprintf(F, "\t.section\t.rodata\t\t/* start jump table */\n");
                        fprintf(F, "\t.align 4\n");
@@ -764,8 +770,18 @@ void emit_ia32_CopyB_i(const ir_node *irn, emit_env_t *emit_env) {
 
 void emit_be_Call(const ir_node *irn, emit_env_t *emit_env) {
        FILE *F = emit_env->out;
+       entity *ent = be_Call_get_entity(irn);
+
+       fprintf(F, "\tcall ");
 
-       lc_efprintf(ia32_get_arg_env(), F, "\tcall %3S\t\t\t/* %+F(%+F) (be_Call) */\n", irn, irn, get_irn_n(irn, 2));
+       if (ent) {
+               fprintf(F, "%s", get_entity_name(ent));
+       }
+       else {
+               lc_efprintf(ia32_get_arg_env(), F, "%1D", get_irn_n(irn, be_pos_Call_ptr));
+       }
+
+       ir_fprintf(F, "\t\t\t/* %+F (be_Call) */\n", irn);
 }
 
 void emit_be_IncSP(const ir_node *irn, emit_env_t *emit_env) {
@@ -782,12 +798,23 @@ void emit_be_IncSP(const ir_node *irn, emit_env_t *emit_env) {
        }
 }
 
-void emit_be_AddSP(const ir_node *irn, emit_env_t *emit_env) {
+void emit_be_SetSP(const ir_node *irn, emit_env_t *emit_env) {
        FILE *F = emit_env->out;
-       lc_efprintf(ia32_get_arg_env(), F, "\tadd %1D, %1S\t\t\t/* %+F (AddSP) */\n", irn, irn, irn);
+
+       lc_efprintf(ia32_get_arg_env(), F, "\tmov %1D,%3S\t\t\t/* restore SP */\n", irn, irn);
 }
 
+void emit_be_Copy(const ir_node *irn, emit_env_t *emit_env) {
+       FILE *F = emit_env->out;
 
+       lc_efprintf(ia32_get_arg_env(), F, "\tmov %1D,%1S\t\t\t/* %+F */\n", irn, irn, irn);
+}
+
+void emit_be_Perm(const ir_node *irn, emit_env_t *emit_env) {
+       FILE *F = emit_env->out;
+
+       lc_efprintf(ia32_get_arg_env(), F, "\txchg %1S, %2S\t\t\t/* %+F(%1A, %2A) */\n", irn, irn, irn);
+}
 
 /***********************************************************************************
  *                  _          __                                             _
@@ -824,7 +851,9 @@ static void ia32_register_emitters(void) {
        /* benode emitter */
        BE_EMIT(Call);
        BE_EMIT(IncSP);
-       BE_EMIT(AddSP);
+       BE_EMIT(SetSP);
+       BE_EMIT(Copy);
+       BE_EMIT(Perm);
 
        /* firm emitter */
        EMIT(Jmp);