Remove one unnecessary malloc() when emitting switches.
[libfirm] / ir / be / ia32 / ia32_emitter.c
index 0150574..1d8fd90 100644 (file)
@@ -1191,12 +1191,12 @@ typedef struct _branch_t {
 
 /* jump table for switch generation */
 typedef struct _jmp_tbl_t {
-       ir_node  *defProj;         /**< default target */
-       long      min_value;       /**< smallest switch case */
-       long      max_value;       /**< largest switch case */
-       long      num_branches;    /**< number of jumps */
-       char     *label;           /**< label of the jump table */
-       branch_t *branches;        /**< jump array */
+       ir_node  *defProj;                 /**< default target */
+       long      min_value;               /**< smallest switch case */
+       long      max_value;               /**< largest switch case */
+       long      num_branches;            /**< number of jumps */
+       char      label[SNPRINTF_BUF_LEN]; /**< label of the jump table */
+       branch_t *branches;                /**< jump array */
 } jmp_tbl_t;
 
 /**
@@ -1229,8 +1229,7 @@ static void emit_ia32_SwitchJmp(const ir_node *node)
        const ir_edge_t    *edge;
 
        /* fill the table structure */
-       tbl.label        = XMALLOCN(char, SNPRINTF_BUF_LEN);
-       tbl.label        = get_unique_label(tbl.label, SNPRINTF_BUF_LEN, ".TBL_");
+       get_unique_label(tbl.label, SNPRINTF_BUF_LEN, ".TBL_");
        tbl.defProj      = NULL;
        tbl.num_branches = get_irn_n_edges(node) - 1;
        tbl.branches     = XMALLOCNZ(branch_t, tbl.num_branches);
@@ -1296,10 +1295,7 @@ static void emit_ia32_SwitchJmp(const ir_node *node)
                ia32_emitf(tbl.branches[0].target, "\tjmp %L\n");
        }
 
-       if (tbl.label)
-               free(tbl.label);
-       if (tbl.branches)
-               free(tbl.branches);
+       free(tbl.branches);
 }
 
 /**
@@ -2701,7 +2697,6 @@ BINOP(sbb,  0x1B, 0x1D, 0x81, 3)
 BINOP(and,  0x23, 0x25, 0x81, 4)
 BINOP(sub,  0x2B, 0x2D, 0x81, 5)
 BINOP(xor,  0x33, 0x35, 0x81, 6)
-BINOP(cmp,  0x3B, 0x3D, 0x81, 7)
 BINOP(test, 0x85, 0xA9, 0xF7, 0)
 
 #define BINOPMEM(op, ext) \
@@ -2893,6 +2888,75 @@ static void bemit_cmov(const ir_node *node)
        }
 }
 
+static void bemit_cmp(const ir_node *node)
+{
+       unsigned  ls_size = get_mode_size_bits(get_ia32_ls_mode(node));
+       ir_node  *right;
+
+       if (ls_size == 16)
+               bemit8(0x66);
+
+       right = get_irn_n(node, n_ia32_binary_right);
+       if (is_ia32_Immediate(right)) {
+               /* Use in-reg, because some instructions (cmp, test) have no out-reg. */
+               const ir_node               *op   = get_irn_n(node, n_ia32_binary_right);
+               const ia32_immediate_attr_t *attr = get_ia32_immediate_attr_const(op);
+               unsigned                     size;
+
+               if (attr->symconst != NULL) {
+                       size = 4;
+               } else {
+                       /* check for sign extension */
+                       size = get_signed_imm_size(attr->offset);
+               }
+
+               switch (size) {
+                       case 1:
+                               bemit8(0x81 | SIGNEXT_IMM);
+                               /* cmp has this special mode */
+                               if (get_ia32_op_type(node) == ia32_AddrModeS) {
+                                       bemit_mod_am(7, node);
+                               } else {
+                                       const arch_register_t *reg = get_in_reg(node, n_ia32_binary_left);
+                                       bemit_modru(reg, 7);
+                               }
+                               bemit8((unsigned char)attr->offset);
+                               return;
+                       case 2:
+                       case 4:
+                               /* check for eax variant: this variant is shorter for 32bit immediates only */
+                               if (get_ia32_op_type(node) == ia32_AddrModeS) {
+                                       bemit8(0x81);
+                                       bemit_mod_am(7, node);
+                               } else {
+                                       const arch_register_t *reg = get_in_reg(node, n_ia32_binary_left);
+                                       if (reg->index == REG_EAX) {
+                                               bemit8(0x3D);
+                                       } else {
+                                               bemit8(0x81);
+                                               bemit_modru(reg, 7);
+                                       }
+                               }
+                               if (ls_size == 16) {
+                                       bemit16(attr->offset);
+                               } else {
+                                       bemit_entity(attr->symconst, attr->sc_sign, attr->offset, false);
+                               }
+                               return;
+               }
+               panic("invalid imm size?!?");
+       } else {
+               const arch_register_t *out = get_in_reg(node, n_ia32_binary_left);
+               bemit8(0x3B);
+               if (get_ia32_op_type(node) == ia32_Normal) {
+                       const arch_register_t *op2 = get_in_reg(node, n_ia32_binary_right);
+                       bemit_modrr(op2, out);
+               } else {
+                       bemit_mod_am(reg_gp_map[out->index], node);
+               }
+       }
+}
+
 static void bemit_cmp8bit(const ir_node *node)
 {
        ir_node *right = get_irn_n(node, n_ia32_binary_right);
@@ -3046,19 +3110,20 @@ static void bemit_ ## op(const ir_node *node) { \
 //EMIT_SINGLEOP(aaa,  0x37)
 //EMIT_SINGLEOP(aas,  0x3F)
 //EMIT_SINGLEOP(nop,  0x90)
-EMIT_SINGLEOP(cwtl, 0x98)
-EMIT_SINGLEOP(cltd, 0x99)
+EMIT_SINGLEOP(cwtl,  0x98)
+EMIT_SINGLEOP(cltd,  0x99)
 //EMIT_SINGLEOP(fwait, 0x9B)
-EMIT_SINGLEOP(sahf, 0x9E)
+EMIT_SINGLEOP(sahf,  0x9E)
 //EMIT_SINGLEOP(popf, 0x9D)
-EMIT_SINGLEOP(int3, 0xCC)
+EMIT_SINGLEOP(leave, 0xC9)
+EMIT_SINGLEOP(int3,  0xCC)
 //EMIT_SINGLEOP(iret, 0xCF)
 //EMIT_SINGLEOP(xlat, 0xD7)
 //EMIT_SINGLEOP(lock, 0xF0)
-EMIT_SINGLEOP(rep,  0xF3)
+EMIT_SINGLEOP(rep,   0xF3)
 //EMIT_SINGLEOP(halt, 0xF4)
-EMIT_SINGLEOP(cmc,  0xF5)
-EMIT_SINGLEOP(stc,  0xF9)
+EMIT_SINGLEOP(cmc,   0xF5)
+EMIT_SINGLEOP(stc,   0xF9)
 //EMIT_SINGLEOP(cli,  0xFA)
 //EMIT_SINGLEOP(sti,  0xFB)
 //EMIT_SINGLEOP(std,  0xFD)
@@ -3444,6 +3509,14 @@ static void bemit_fbinopp(const ir_node *node, unsigned const code)
        bemit8(code + out->index);
 }
 
+static void bemit_fabs(const ir_node *node)
+{
+       (void)node;
+
+       bemit8(0xD9);
+       bemit8(0xE1);
+}
+
 static void bemit_fadd(const ir_node *node)
 {
        bemit_fbinop(node, 0, 0);
@@ -3702,10 +3775,22 @@ static void bemit_ftstfnstsw(const ir_node *node)
        bemit_fnstsw();
 }
 
-static void bemit_fucomfnstsw(const ir_node *node)
+static void bemit_fucomi(const ir_node *node)
 {
-       (void)node;
+       const ia32_x87_attr_t *attr = get_ia32_x87_attr_const(node);
+       bemit8(0xDB); // fucomi
+       bemit8(0xE8 + attr->x87[1]->index);
+}
+
+static void bemit_fucomip(const ir_node *node)
+{
+       const ia32_x87_attr_t *attr = get_ia32_x87_attr_const(node);
+       bemit8(0xDF); // fucomip
+       bemit8(0xE8 + attr->x87[1]->index);
+}
 
+static void bemit_fucomfnstsw(const ir_node *node)
+{
        const ia32_x87_attr_t *attr = get_ia32_x87_attr_const(node);
        bemit8(0xDD); // fucom
        bemit8(0xE0 + attr->x87[1]->index);
@@ -3714,8 +3799,6 @@ static void bemit_fucomfnstsw(const ir_node *node)
 
 static void bemit_fucompfnstsw(const ir_node *node)
 {
-       (void)node;
-
        const ia32_x87_attr_t *attr = get_ia32_x87_attr_const(node);
        bemit8(0xDD); // fucomp
        bemit8(0xE8 + attr->x87[1]->index);
@@ -3788,7 +3871,9 @@ static void ia32_register_binary_emitters(void)
        register_emitter(op_ia32_FnstCW,        bemit_fnstcw);
        register_emitter(op_ia32_FtstFnstsw,    bemit_ftstfnstsw);
        register_emitter(op_ia32_FucomFnstsw,   bemit_fucomfnstsw);
+       register_emitter(op_ia32_Fucomi,        bemit_fucomi);
        register_emitter(op_ia32_FucompFnstsw,  bemit_fucompfnstsw);
+       register_emitter(op_ia32_Fucompi,       bemit_fucomip);
        register_emitter(op_ia32_FucomppFnstsw, bemit_fucomppfnstsw);
        register_emitter(op_ia32_IDiv,          bemit_idiv);
        register_emitter(op_ia32_IJmp,          bemit_ijmp);
@@ -3800,6 +3885,7 @@ static void ia32_register_binary_emitters(void)
        register_emitter(op_ia32_Jmp,           bemit_jump);
        register_emitter(op_ia32_LdTls,         bemit_ldtls);
        register_emitter(op_ia32_Lea,           bemit_lea);
+       register_emitter(op_ia32_Leave,         bemit_leave);
        register_emitter(op_ia32_Load,          bemit_load);
        register_emitter(op_ia32_Mul,           bemit_mul);
        register_emitter(op_ia32_Neg,           bemit_neg);
@@ -3842,6 +3928,7 @@ static void ia32_register_binary_emitters(void)
        register_emitter(op_ia32_Xor0,          bemit_xor0);
        register_emitter(op_ia32_XorMem,        bemit_xormem);
        register_emitter(op_ia32_XorMem8Bit,    bemit_xormem8bit);
+       register_emitter(op_ia32_fabs,          bemit_fabs);
        register_emitter(op_ia32_fadd,          bemit_fadd);
        register_emitter(op_ia32_faddp,         bemit_faddp);
        register_emitter(op_ia32_fchs,          bemit_fchs);