backend_marked was a buggy/wrong concept, removed it
[libfirm] / ir / be / ia32 / ia32_emitter.c
index c502d1b..4716f55 100644 (file)
@@ -282,11 +282,10 @@ void ia32_emit_source_register(const ir_node *node, int pos)
 
 static void ia32_emit_entity(ir_entity *entity, int no_pic_adjust)
 {
-       set_entity_backend_marked(entity, 1);
        be_gas_emit_entity(entity);
 
        if (get_entity_owner(entity) == get_tls_type()) {
-               if (get_entity_visibility(entity) == visibility_external_allocated) {
+               if (get_entity_linkage(entity) & IR_LINKAGE_EXTERN) {
                        be_emit_cstring("@INDNTPOFF");
                } else {
                        be_emit_cstring("@NTPOFF");
@@ -556,6 +555,7 @@ static void ia32_emit_cmp_suffix(int pnc)
                be_emit_char('p');
                return;
        }
+
        if (pnc & ia32_pn_Cmp_float || pnc & ia32_pn_Cmp_unsigned) {
                str = cmp2condition_u[pnc & 7];
        } else {
@@ -568,7 +568,9 @@ static void ia32_emit_cmp_suffix(int pnc)
 typedef enum ia32_emit_mod_t {
        EMIT_RESPECT_LS   = 1U << 0,
        EMIT_ALTERNATE_AM = 1U << 1,
-       EMIT_LONG         = 1U << 2
+       EMIT_LONG         = 1U << 2,
+       EMIT_HIGH_REG     = 1U << 3,
+       EMIT_LOW_REG      = 1U << 4
 } ia32_emit_mod_t;
 
 /**
@@ -647,9 +649,11 @@ void ia32_emit_am(const ir_node *node)
  * %d   signed int              signed int
  *
  * x starts at 0
- * # modifier for %ASx, %D and %S uses ls mode of node to alter register width
+ * # modifier for %ASx, %D, %R, and %S uses ls mode of node to alter register width
  * * modifier does not prefix immediates with $, but AM with *
  * l modifier for %lu and %ld
+ * > modifier to output high 8bit register (ah, bh)
+ * < modifier to output low 8bit register (al, bl)
  */
 static void ia32_emitf(const ir_node *node, const char *fmt, ...)
 {
@@ -678,20 +682,19 @@ static void ia32_emitf(const ir_node *node, const char *fmt, ...)
                        break;
 
                ++fmt;
-               if (*fmt == '*') {
-                       mod |= EMIT_ALTERNATE_AM;
-                       ++fmt;
-               }
-
-               if (*fmt == '#') {
-                       mod |= EMIT_RESPECT_LS;
-                       ++fmt;
-               }
-
-               if (*fmt == 'l') {
-                       mod |= EMIT_LONG;
+               while (1) {
+                       switch(*fmt) {
+                       case '*': mod |= EMIT_ALTERNATE_AM; break;
+                       case '#': mod |= EMIT_RESPECT_LS;   break;
+                       case 'l': mod |= EMIT_LONG;         break;
+                       case '>': mod |= EMIT_HIGH_REG;     break;
+                       case '<': mod |= EMIT_LOW_REG;      break;
+                       default:
+                               goto end_of_mods;
+                       }
                        ++fmt;
                }
+end_of_mods:
 
                switch (*fmt++) {
                        case '%':
@@ -700,20 +703,20 @@ static void ia32_emitf(const ir_node *node, const char *fmt, ...)
 
                        case 'A': {
                                switch (*fmt++) {
+emit_AM:
                                        case 'M':
                                                if (mod & EMIT_ALTERNATE_AM)
                                                        be_emit_char('*');
-
                                                ia32_emit_am(node);
                                                break;
 
                                        case 'R': {
                                                const arch_register_t *reg = va_arg(ap, const arch_register_t*);
-                                               if (mod & EMIT_ALTERNATE_AM)
-                                                       be_emit_char('*');
                                                if (get_ia32_op_type(node) == ia32_AddrModeS) {
-                                                       ia32_emit_am(node);
+                                                       goto emit_AM;
                                                } else {
+                                                       if (mod & EMIT_ALTERNATE_AM)
+                                                               be_emit_char('*');
                                                        emit_register(reg, NULL);
                                                }
                                                break;
@@ -721,10 +724,8 @@ static void ia32_emitf(const ir_node *node, const char *fmt, ...)
 
                                        case 'S':
                                                if (get_ia32_op_type(node) == ia32_AddrModeS) {
-                                                       if (mod & EMIT_ALTERNATE_AM)
-                                                               be_emit_char('*');
-                                                       ia32_emit_am(node);
                                                        ++fmt;
+                                                       goto emit_AM;
                                                } else {
                                                        assert(get_ia32_op_type(node) == ia32_Normal);
                                                        goto emit_S;
@@ -772,7 +773,13 @@ static void ia32_emitf(const ir_node *node, const char *fmt, ...)
 
                        case 'R': {
                                const arch_register_t *reg = va_arg(ap, const arch_register_t*);
-                               emit_register(reg, NULL);
+                               if (mod & EMIT_HIGH_REG) {
+                                       emit_8bit_register_high(reg);
+                               } else if (mod & EMIT_LOW_REG) {
+                                       emit_8bit_register(reg);
+                               } else {
+                                       emit_register(reg, mod & EMIT_RESPECT_LS ? get_ia32_ls_mode(node) : NULL);
+                               }
                                break;
                        }
 
@@ -949,8 +956,7 @@ static ir_node *find_original_value(ir_node *node)
        }
 }
 
-static int determine_final_pnc(const ir_node *node, int flags_pos,
-                               int pnc)
+static int determine_final_pnc(const ir_node *node, int flags_pos, int pnc)
 {
        ir_node           *flags = get_irn_n(node, flags_pos);
        const ia32_attr_t *flags_attr;
@@ -1083,37 +1089,37 @@ static void emit_ia32_Jcc(const ir_node *node)
        if (pnc & ia32_pn_Cmp_float) {
                /* Some floating point comparisons require a test of the parity flag,
                 * which indicates that the result is unordered */
-               switch (pnc & 15) {
-                       case pn_Cmp_Uo: {
-                               ia32_emitf(proj_true, "\tjp %L\n");
-                               break;
-                       }
+               switch (pnc & 0x0f) {
+               case pn_Cmp_Uo: {
+                       ia32_emitf(proj_true, "\tjp %L\n");
+                       break;
+               }
 
-                       case pn_Cmp_Leg:
-                               ia32_emitf(proj_true, "\tjnp %L\n");
-                               break;
+               case pn_Cmp_Leg:
+                       ia32_emitf(proj_true, "\tjnp %L\n");
+                       break;
 
-                       case pn_Cmp_Eq:
-                       case pn_Cmp_Lt:
-                       case pn_Cmp_Le:
-                               /* we need a local label if the false proj is a fallthrough
-                                * as the falseblock might have no label emitted then */
-                               if (can_be_fallthrough(proj_false)) {
-                                       need_parity_label = 1;
-                                       ia32_emitf(proj_false, "\tjp 1f\n");
-                               } else {
-                                       ia32_emitf(proj_false, "\tjp %L\n");
-                               }
-                               goto emit_jcc;
+               case pn_Cmp_Eq:
+               case pn_Cmp_Lt:
+               case pn_Cmp_Le:
+                       /* we need a local label if the false proj is a fallthrough
+                        * as the falseblock might have no label emitted then */
+                       if (can_be_fallthrough(proj_false)) {
+                               need_parity_label = 1;
+                               ia32_emitf(proj_false, "\tjp 1f\n");
+                       } else {
+                               ia32_emitf(proj_false, "\tjp %L\n");
+                       }
+                       goto emit_jcc;
 
-                       case pn_Cmp_Ug:
-                       case pn_Cmp_Uge:
-                       case pn_Cmp_Ne:
-                               ia32_emitf(proj_true, "\tjp %L\n");
-                               goto emit_jcc;
+               case pn_Cmp_Ug:
+               case pn_Cmp_Uge:
+               case pn_Cmp_Ne:
+                       ia32_emitf(proj_true, "\tjp %L\n");
+                       goto emit_jcc;
 
-                       default:
-                               goto emit_jcc;
+               default:
+                       goto emit_jcc;
                }
        } else {
 emit_jcc:
@@ -1132,19 +1138,65 @@ emit_jcc:
        }
 }
 
-static void emit_ia32_CMov(const ir_node *node)
+/**
+ * Emits an ia32 Setcc. This is mostly easy but some floating point compares
+ * are tricky.
+ */
+static void emit_ia32_Setcc(const ir_node *node)
+{
+       const arch_register_t *dreg = get_out_reg(node, pn_ia32_Setcc_res);
+
+       pn_Cmp pnc = get_ia32_condcode(node);
+       pnc        = determine_final_pnc(node, n_ia32_Setcc_eflags, pnc);
+       if (pnc & ia32_pn_Cmp_float) {
+               switch (pnc & 0x0f) {
+               case pn_Cmp_Uo:
+                       ia32_emitf(node, "\tsetp %#R\n", dreg);
+                       return;
+
+               case pn_Cmp_Leg:
+                       ia32_emitf(node, "\tsetnp %#R\n", dreg);
+                       return;
+
+               case pn_Cmp_Eq:
+               case pn_Cmp_Lt:
+               case pn_Cmp_Le:
+                       ia32_emitf(node, "\tset%P %<R\n", pnc, dreg);
+                       ia32_emitf(node, "\tsetnp %>R\n", dreg);
+                       ia32_emitf(node, "\tandb %>R, %<R\n", dreg, dreg);
+                       return;
+
+               case pn_Cmp_Ug:
+               case pn_Cmp_Uge:
+               case pn_Cmp_Ne:
+                       ia32_emitf(node, "\tset%P %<R\n", pnc, dreg);
+                       ia32_emitf(node, "\tsetp %>R\n", dreg);
+                       ia32_emitf(node, "\torb %>R, %<R\n", dreg, dreg);
+                       return;
+
+               default:
+                       break;
+               }
+       }
+       ia32_emitf(node, "\tset%P %#R\n", pnc, dreg);
+}
+
+static void emit_ia32_CMovcc(const ir_node *node)
 {
        const ia32_attr_t     *attr         = get_ia32_attr_const(node);
-       int                    ins_permuted = attr->data.ins_permuted;
        const arch_register_t *out          = arch_irn_get_register(node, pn_ia32_res);
        pn_Cmp                 pnc          = get_ia32_condcode(node);
        const arch_register_t *in_true;
        const arch_register_t *in_false;
 
-       pnc = determine_final_pnc(node, n_ia32_CMov_eflags, pnc);
+       pnc = determine_final_pnc(node, n_ia32_CMovcc_eflags, pnc);
+       /* although you can't set ins_permuted in the constructor it might still
+          be set by memory operand folding */
+       if (attr->data.ins_permuted)
+               pnc = ia32_get_negated_pnc(pnc);
 
-       in_true  = arch_get_irn_register(get_irn_n(node, n_ia32_CMov_val_true));
-       in_false = arch_get_irn_register(get_irn_n(node, n_ia32_CMov_val_false));
+       in_true  = arch_get_irn_register(get_irn_n(node, n_ia32_CMovcc_val_true));
+       in_false = arch_get_irn_register(get_irn_n(node, n_ia32_CMovcc_val_false));
 
        /* should be same constraint fullfilled? */
        if (out == in_false) {
@@ -1154,7 +1206,7 @@ static void emit_ia32_CMov(const ir_node *node)
 
                assert(get_ia32_op_type(node) == ia32_Normal);
 
-               ins_permuted = !ins_permuted;
+               pnc = ia32_get_negated_pnc(pnc);
 
                tmp      = in_true;
                in_true  = in_false;
@@ -1164,10 +1216,20 @@ static void emit_ia32_CMov(const ir_node *node)
                ia32_emitf(node, "\tmovl %R, %R\n", in_false, out);
        }
 
-       if (ins_permuted)
-               pnc = ia32_get_negated_pnc(pnc);
-
        /* TODO: handling of Nans isn't correct yet */
+       if (pnc & ia32_pn_Cmp_float) {
+               switch (pnc & 0x0f) {
+               case pn_Cmp_Uo:
+               case pn_Cmp_Leg:
+               case pn_Cmp_Eq:
+               case pn_Cmp_Lt:
+               case pn_Cmp_Le:
+               case pn_Cmp_Ug:
+               case pn_Cmp_Uge:
+               case pn_Cmp_Ne:
+                       panic("CMov with floatingpoint compare/parity not supported yet");
+               }
+       }
 
        ia32_emitf(node, "\tcmov%P %#AR, %#R\n", pnc, in_true, out);
 }
@@ -1191,12 +1253,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;
 
 /**
@@ -1213,29 +1275,21 @@ static int ia32_cmp_branch_t(const void *a, const void *b)
                return 1;
 }
 
-/**
- * Emits code for a SwitchJmp (creates a jump table if
- * possible otherwise a cmp-jmp cascade). Port from
- * cggg ia32 backend
- */
-static void emit_ia32_SwitchJmp(const ir_node *node)
+static void generate_jump_table(jmp_tbl_t *tbl, const ir_node *node)
 {
-       unsigned long       interval;
-       int                 last_value, i;
+       int                 i;
        long                pnc;
        long                default_pn;
-       jmp_tbl_t           tbl;
        ir_node            *proj;
        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_");
-       tbl.defProj      = NULL;
-       tbl.num_branches = get_irn_n_edges(node) - 1;
-       tbl.branches     = XMALLOCNZ(branch_t, tbl.num_branches);
-       tbl.min_value    = INT_MAX;
-       tbl.max_value    = INT_MIN;
+       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);
+       tbl->min_value    = LONG_MAX;
+       tbl->max_value    = LONG_MIN;
 
        default_pn = get_ia32_condcode(node);
        i = 0;
@@ -1248,23 +1302,38 @@ static void emit_ia32_SwitchJmp(const ir_node *node)
 
                /* check for default proj */
                if (pnc == default_pn) {
-                       assert(tbl.defProj == NULL && "found two default Projs at SwitchJmp");
-                       tbl.defProj = proj;
+                       assert(tbl->defProj == NULL && "found two default Projs at SwitchJmp");
+                       tbl->defProj = proj;
                } else {
-                       tbl.min_value = pnc < tbl.min_value ? pnc : tbl.min_value;
-                       tbl.max_value = pnc > tbl.max_value ? pnc : tbl.max_value;
+                       tbl->min_value = pnc < tbl->min_value ? pnc : tbl->min_value;
+                       tbl->max_value = pnc > tbl->max_value ? pnc : tbl->max_value;
 
                        /* create branch entry */
-                       tbl.branches[i].target = proj;
-                       tbl.branches[i].value  = pnc;
+                       tbl->branches[i].target = proj;
+                       tbl->branches[i].value  = pnc;
                        ++i;
                }
 
        }
-       assert(i == tbl.num_branches);
+       assert(i == tbl->num_branches);
 
        /* sort the branches by their number */
-       qsort(tbl.branches, tbl.num_branches, sizeof(tbl.branches[0]), ia32_cmp_branch_t);
+       qsort(tbl->branches, tbl->num_branches, sizeof(tbl->branches[0]), ia32_cmp_branch_t);
+}
+
+/**
+ * Emits code for a SwitchJmp (creates a jump table if
+ * possible otherwise a cmp-jmp cascade). Port from
+ * cggg ia32 backend
+ */
+static void emit_ia32_SwitchJmp(const ir_node *node)
+{
+       unsigned long       interval;
+       int                 last_value, i;
+       jmp_tbl_t           tbl;
+
+       /* fill the table structure */
+       generate_jump_table(&tbl, node);
 
        /* two-complement's magic make this work without overflow */
        interval = tbl.max_value - tbl.min_value;
@@ -1296,10 +1365,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);
 }
 
 /**
@@ -1867,7 +1933,7 @@ static void ia32_register_emitters(void)
        /* other ia32 emitter functions */
        IA32_EMIT2(Conv_I2I8Bit, Conv_I2I);
        IA32_EMIT(Asm);
-       IA32_EMIT(CMov);
+       IA32_EMIT(CMovcc);
        IA32_EMIT(Call);
        IA32_EMIT(Const);
        IA32_EMIT(Conv_FP2FP);
@@ -1879,6 +1945,7 @@ static void ia32_register_emitters(void)
        IA32_EMIT(GetEIP);
        IA32_EMIT(IMul);
        IA32_EMIT(Jcc);
+       IA32_EMIT(Setcc);
        IA32_EMIT(LdTls);
        IA32_EMIT(Minus64Bit);
        IA32_EMIT(SwitchJmp);
@@ -2176,6 +2243,8 @@ void ia32_gen_routine(ia32_code_gen_t *ia32_cg, ir_graph *irg)
        isa      = cg->isa;
        do_pic   = cg->birg->main_env->options->pic;
 
+       be_gas_elf_type_char = '@';
+
        ia32_register_emitters();
 
        get_unique_label(pic_base_label, sizeof(pic_base_label), ".PIC_BASE");
@@ -2235,8 +2304,8 @@ static const lc_opt_table_entry_t ia32_emitter_options[] = {
 /* ==== Experimental binary emitter ==== */
 
 static unsigned char reg_gp_map[N_ia32_gp_REGS];
-static unsigned char reg_mmx_map[N_ia32_mmx_REGS];
-static unsigned char reg_sse_map[N_ia32_xmm_REGS];
+//static unsigned char reg_mmx_map[N_ia32_mmx_REGS];
+//static unsigned char reg_sse_map[N_ia32_xmm_REGS];
 static unsigned char pnc_map_signed[8];
 static unsigned char pnc_map_unsigned[8];
 
@@ -2266,6 +2335,7 @@ static void build_reg_map(void)
        pnc_map_unsigned[pn_Cmp_Lg]    = 0x05;
 }
 
+/** Returns the encoding for a pnc field. */
 static unsigned char pnc2cc(int pnc)
 {
        unsigned char cc;
@@ -2339,20 +2409,24 @@ static void bemit_entity(ir_entity *entity, bool entity_sign, int offset,
                return;
        }
 
-       if (is_relative) {
-               offset -= 4;
-       }
-
        /* the final version should remember the position in the bytestream
           and patch it with the correct address at linktime... */
        be_emit_cstring("\t.long ");
        if (entity_sign)
                be_emit_char('-');
-       set_entity_backend_marked(entity, 1);
        be_gas_emit_entity(entity);
 
+       if (get_entity_owner(entity) == get_tls_type()) {
+               if (get_entity_linkage(entity) & IR_LINKAGE_EXTERN) {
+                       be_emit_cstring("@INDNTPOFF");
+               } else {
+                       be_emit_cstring("@NTPOFF");
+               }
+       }
+
        if (is_relative) {
                be_emit_cstring("-.");
+               offset -= 4;
        }
 
        if (offset != 0) {
@@ -2373,6 +2447,11 @@ static void bemit_jmp_destination(const ir_node *dest_block)
 /* end emit routines, all emitters following here should only use the functions
    above. */
 
+typedef enum reg_modifier {
+       REG_LOW  = 0,
+       REG_HIGH = 1
+} reg_modifier_t;
+
 /** Create a ModR/M byte for src1,src2 registers */
 static void bemit_modrr(const arch_register_t *src1,
                         const arch_register_t *src2)
@@ -2383,6 +2462,16 @@ static void bemit_modrr(const arch_register_t *src1,
        bemit8(modrm);
 }
 
+/** Create a ModR/M8 byte for src1,src2 registers */
+static void bemit_modrr8(reg_modifier_t high_part1, const arch_register_t *src1,
+                                                reg_modifier_t high_part2, const arch_register_t *src2)
+{
+       unsigned char modrm = MOD_REG;
+       modrm |= ENC_RM(reg_gp_map[src1->index] +  (high_part1 == REG_HIGH ? 4 : 0));
+       modrm |= ENC_REG(reg_gp_map[src2->index] + (high_part2 == REG_HIGH ? 4 : 0));
+       bemit8(modrm);
+}
+
 /** Create a ModR/M byte for one register and extension */
 static void bemit_modru(const arch_register_t *reg, unsigned ext)
 {
@@ -2393,6 +2482,16 @@ static void bemit_modru(const arch_register_t *reg, unsigned ext)
        bemit8(modrm);
 }
 
+/** Create a ModR/M8 byte for one register */
+static void bemit_modrm8(reg_modifier_t high_part, const arch_register_t *reg)
+{
+       unsigned char modrm = MOD_REG;
+       assert(reg_gp_map[reg->index] < 4);
+       modrm |= ENC_RM(reg_gp_map[reg->index] + (high_part == REG_HIGH ? 4 : 0));
+       modrm |= MOD_REG;
+       bemit8(modrm);
+}
+
 /**
  * Calculate the size of an signed immediate in bytes.
  *
@@ -2706,10 +2805,11 @@ BINOP(test, 0x85, 0xA9, 0xF7, 0)
 #define BINOPMEM(op, ext) \
 static void bemit_##op(const ir_node *node) \
 { \
+       ir_node *val; \
        unsigned size = get_mode_size_bits(get_ia32_ls_mode(node)); \
        if (size == 16) \
                bemit8(0x66); \
-       ir_node *val = get_irn_n(node, n_ia32_unary_op); \
+       val = get_irn_n(node, n_ia32_unary_op); \
        if (is_ia32_Immediate(val)) { \
                const ia32_immediate_attr_t *attr   = get_ia32_immediate_attr_const(val); \
                int                          offset = attr->offset; \
@@ -2793,22 +2893,23 @@ static void bemit_##op(const ir_node *node) \
  \
 static void bemit_##op##mem(const ir_node *node) \
 { \
+       ir_node *count; \
        unsigned size = get_mode_size_bits(get_ia32_ls_mode(node)); \
        if (size == 16) \
                bemit8(0x66); \
-       ir_node *count = get_irn_n(node, 1); \
+       count = get_irn_n(node, 1); \
        if (is_ia32_Immediate(count)) { \
                int offset = get_ia32_immediate_attr_const(count)->offset; \
                if (offset == 1) { \
-                       bemit8(size == 1 ? 0xD0 : 0xD1); \
+                       bemit8(size == 8 ? 0xD0 : 0xD1); \
                        bemit_mod_am(ext, node); \
                } else { \
-                       bemit8(size == 1 ? 0xC0 : 0xC1); \
+                       bemit8(size == 8 ? 0xC0 : 0xC1); \
                        bemit_mod_am(ext, node); \
                        bemit8(offset); \
                } \
        } else { \
-               bemit8(size == 1 ? 0xD2 : 0xD3); \
+               bemit8(size == 8 ? 0xD2 : 0xD3); \
                bemit_mod_am(ext, node); \
        } \
 }
@@ -2851,7 +2952,78 @@ static void bemit_shrd(const ir_node *node)
        }
 }
 
-static void bemit_cmov(const ir_node *node)
+/**
+ * binary emitter for setcc.
+ */
+static void bemit_setcc(const ir_node *node)
+{
+       const arch_register_t *dreg = get_out_reg(node, pn_ia32_Setcc_res);
+
+       pn_Cmp pnc = get_ia32_condcode(node);
+       pnc        = determine_final_pnc(node, n_ia32_Setcc_eflags, pnc);
+       if (pnc & ia32_pn_Cmp_float) {
+               switch (pnc & 0x0f) {
+               case pn_Cmp_Uo:
+                        /* setp <dreg */
+                       bemit8(0x0F);
+                       bemit8(0x9A);
+                       bemit_modrm8(REG_LOW, dreg);
+                       return;
+
+               case pn_Cmp_Leg:
+                        /* setnp <dreg*/
+                       bemit8(0x0F);
+                       bemit8(0x9B);
+                       bemit_modrm8(REG_LOW, dreg);
+                       return;
+
+               case pn_Cmp_Eq:
+               case pn_Cmp_Lt:
+               case pn_Cmp_Le:
+                        /* set%PNC <dreg */
+                       bemit8(0x0F);
+                       bemit8(0x90 | pnc2cc(pnc));
+                       bemit_modrm8(REG_LOW, dreg);
+
+                       /* setnp >dreg */
+                       bemit8(0x0F);
+                       bemit8(0x9B);
+                       bemit_modrm8(REG_HIGH, dreg);
+
+                       /* andb %>dreg, %<dreg */
+                       bemit8(0x20);
+                       bemit_modrr8(REG_LOW, dreg, REG_HIGH, dreg);
+                       return;
+
+               case pn_Cmp_Ug:
+               case pn_Cmp_Uge:
+               case pn_Cmp_Ne:
+                       /* set%PNC <dreg */
+                       bemit8(0x0F);
+                       bemit8(0x90 | pnc2cc(pnc));
+                       bemit_modrm8(REG_LOW, dreg);
+
+                       /* setp >dreg */
+                       bemit8(0x0F);
+                       bemit8(0x9A);
+                       bemit_modrm8(REG_HIGH, dreg);
+
+                       /* orb %>dreg, %<dreg */
+                       bemit8(0x08);
+                       bemit_modrr8(REG_LOW, dreg, REG_HIGH, dreg);
+                       return;
+
+               default:
+                       break;
+               }
+       }
+       /* set%PNC <dreg */
+       bemit8(0x0F);
+       bemit8(0x90 | pnc2cc(pnc));
+       bemit_modrm8(REG_LOW, dreg);
+}
+
+static void bemit_cmovcc(const ir_node *node)
 {
        const ia32_attr_t     *attr         = get_ia32_attr_const(node);
        int                    ins_permuted = attr->data.ins_permuted;
@@ -2860,10 +3032,10 @@ static void bemit_cmov(const ir_node *node)
        const arch_register_t *in_true;
        const arch_register_t *in_false;
 
-       pnc = determine_final_pnc(node, n_ia32_CMov_eflags, pnc);
+       pnc = determine_final_pnc(node, n_ia32_CMovcc_eflags, pnc);
 
-       in_true  = arch_get_irn_register(get_irn_n(node, n_ia32_CMov_val_true));
-       in_false = arch_get_irn_register(get_irn_n(node, n_ia32_CMov_val_false));
+       in_true  = arch_get_irn_register(get_irn_n(node, n_ia32_CMovcc_val_true));
+       in_false = arch_get_irn_register(get_irn_n(node, n_ia32_CMovcc_val_false));
 
        /* should be same constraint fullfilled? */
        if (out == in_false) {
@@ -2884,7 +3056,7 @@ static void bemit_cmov(const ir_node *node)
        /* TODO: handling of Nans isn't correct yet */
 
        bemit8(0x0F);
-       bemit8(0x40 + pnc2cc(pnc));
+       bemit8(0x40 | pnc2cc(pnc));
        if (get_ia32_op_type(node) == ia32_Normal) {
                bemit_modrr(in_true, out);
        } else {
@@ -2979,8 +3151,8 @@ static void bemit_cmp8bit(const ir_node *node)
                }
                bemit8(get_ia32_immediate_attr_const(right)->offset);
        } else {
-               bemit8(0x3A);
                const arch_register_t *out = get_in_reg(node, n_ia32_Cmp_left);
+               bemit8(0x3A);
                if (get_ia32_op_type(node) == ia32_Normal) {
                        const arch_register_t *in = get_in_reg(node, n_ia32_Cmp_right);
                        bemit_modrr(out, in);
@@ -3008,8 +3180,8 @@ static void bemit_test8bit(const ir_node *node)
                }
                bemit8(get_ia32_immediate_attr_const(right)->offset);
        } else {
-               bemit8(0x84);
                const arch_register_t *out = get_in_reg(node, n_ia32_Test8Bit_left);
+               bemit8(0x84);
                if (get_ia32_op_type(node) == ia32_Normal) {
                        const arch_register_t *in = get_in_reg(node, n_ia32_Test8Bit_right);
                        bemit_modrr(out, in);
@@ -3061,21 +3233,6 @@ UNOPMEM(negmem, 0xF6, 3)
 UNOPMEM(incmem, 0xFE, 0)
 UNOPMEM(decmem, 0xFE, 1)
 
-static void bemit_set(const ir_node *node)
-{
-       pn_Cmp pnc;
-
-       bemit8(0x0F);
-
-       pnc = get_ia32_condcode(node);
-       pnc = determine_final_pnc(node, n_ia32_Set_eflags, pnc);
-       if (get_ia32_attr_const(node)->data.ins_permuted)
-               pnc = ia32_get_negated_pnc(pnc);
-
-       bemit8(0x90 + pnc2cc(pnc));
-       bemit_modru(get_out_reg(node, pn_ia32_Set_res), 2);
-}
-
 static void bemit_ldtls(const ir_node *node)
 {
        const arch_register_t *out = get_out_reg(node, 0);
@@ -3085,7 +3242,7 @@ static void bemit_ldtls(const ir_node *node)
                bemit8(0xA1); // movl 0, %eax
        } else {
                bemit8(0x8B); // movl 0, %reg
-               bemit8(MOD_IND | ENC_REG(out->index) | ENC_RM(0x05));
+               bemit8(MOD_IND | ENC_REG(reg_gp_map[out->index]) | ENC_RM(0x05));
        }
        bemit32(0);
 }
@@ -3100,6 +3257,109 @@ static void bemit_lea(const ir_node *node)
        bemit_mod_am(reg_gp_map[out->index], node);
 }
 
+/* helper function for bemit_minus64bit */
+static void bemit_helper_mov(const arch_register_t *src, const arch_register_t *dst)
+{
+       bemit8(0x8B); // movl %src, %dst
+       bemit_modrr(src, dst);
+}
+
+/* helper function for bemit_minus64bit */
+static void bemit_helper_neg(const arch_register_t *reg)
+{
+       bemit8(0xF7); // negl %reg
+       bemit_modru(reg, 3);
+}
+
+/* helper function for bemit_minus64bit */
+static void bemit_helper_sbb0(const arch_register_t *reg)
+{
+       bemit8(0x83); // sbbl $0, %reg
+       bemit_modru(reg, 3);
+       bemit8(0);
+}
+
+/* helper function for bemit_minus64bit */
+static void bemit_helper_sbb(const arch_register_t *src, const arch_register_t *dst)
+{
+       bemit8(0x1B); // sbbl %src, %dst
+       bemit_modrr(src, dst);
+}
+
+/* helper function for bemit_minus64bit */
+static void bemit_helper_xchg(const arch_register_t *src, const arch_register_t *dst)
+{
+       if (src->index == REG_EAX) {
+               bemit8(0x90 + reg_gp_map[dst->index]); // xchgl %eax, %dst
+       } else if (dst->index == REG_EAX) {
+               bemit8(0x90 + reg_gp_map[src->index]); // xchgl %src, %eax
+       } else {
+               bemit8(0x87); // xchgl %src, %dst
+               bemit_modrr(src, dst);
+       }
+}
+
+/* helper function for bemit_minus64bit */
+static void bemit_helper_zero(const arch_register_t *reg)
+{
+       bemit8(0x33); // xorl %reg, %reg
+       bemit_modrr(reg, reg);
+}
+
+static void bemit_minus64bit(const ir_node *node)
+{
+       const arch_register_t *in_lo  = get_in_reg(node, 0);
+       const arch_register_t *in_hi  = get_in_reg(node, 1);
+       const arch_register_t *out_lo = get_out_reg(node, 0);
+       const arch_register_t *out_hi = get_out_reg(node, 1);
+
+       if (out_lo == in_lo) {
+               if (out_hi != in_hi) {
+                       /* a -> a, b -> d */
+                       goto zero_neg;
+               } else {
+                       /* a -> a, b -> b */
+                       goto normal_neg;
+               }
+       } else if (out_lo == in_hi) {
+               if (out_hi == in_lo) {
+                       /* a -> b, b -> a */
+                       bemit_helper_xchg(in_lo, in_hi);
+                       goto normal_neg;
+               } else {
+                       /* a -> b, b -> d */
+                       bemit_helper_mov(in_hi, out_hi);
+                       bemit_helper_mov(in_lo, out_lo);
+                       goto normal_neg;
+               }
+       } else {
+               if (out_hi == in_lo) {
+                       /* a -> c, b -> a */
+                       bemit_helper_mov(in_lo, out_lo);
+                       goto zero_neg;
+               } else if (out_hi == in_hi) {
+                       /* a -> c, b -> b */
+                       bemit_helper_mov(in_lo, out_lo);
+                       goto normal_neg;
+               } else {
+                       /* a -> c, b -> d */
+                       bemit_helper_mov(in_lo, out_lo);
+                       goto zero_neg;
+               }
+       }
+
+normal_neg:
+       bemit_helper_neg( out_hi);
+       bemit_helper_neg( out_lo);
+       bemit_helper_sbb0(out_hi);
+       return;
+
+zero_neg:
+       bemit_helper_zero(out_hi);
+       bemit_helper_neg( out_lo);
+       bemit_helper_sbb( in_hi, out_hi);
+}
+
 /**
  * Emit a single opcode.
  */
@@ -3402,6 +3662,67 @@ emit_jcc:
        }
 }
 
+static void bemit_switchjmp(const ir_node *node)
+{
+       unsigned long          interval;
+       int                    last_value;
+       int                    i;
+       jmp_tbl_t              tbl;
+       const arch_register_t *in;
+
+       /* fill the table structure */
+       generate_jump_table(&tbl, node);
+
+       /* two-complement's magic make this work without overflow */
+       interval = tbl.max_value - tbl.min_value;
+
+       in = get_in_reg(node, 0);
+       /* emit the table */
+       if (get_signed_imm_size(interval) == 1) {
+               bemit8(0x83); // cmpl $imm8, %in
+               bemit_modru(in, 7);
+               bemit8(interval);
+       } else {
+               bemit8(0x81); // cmpl $imm32, %in
+               bemit_modru(in, 7);
+               bemit32(interval);
+       }
+       bemit8(0x0F); // ja tbl.defProj
+       bemit8(0x87);
+       ia32_emitf(tbl.defProj, ".long %L - . - 4\n");
+
+       if (tbl.num_branches > 1) {
+               /* create table */
+               bemit8(0xFF); // jmp *tbl.label(,%in,4)
+               bemit8(MOD_IND | ENC_REG(4) | ENC_RM(0x04));
+               bemit8(ENC_SIB(2, reg_gp_map[in->index], 0x05));
+               be_emit_irprintf("\t.long %s\n", tbl.label);
+
+               be_gas_emit_switch_section(GAS_SECTION_RODATA);
+               be_emit_cstring(".align 4\n");
+               be_emit_irprintf("%s:\n", tbl.label);
+
+               last_value = tbl.branches[0].value;
+               for (i = 0; i != tbl.num_branches; ++i) {
+                       while (last_value != tbl.branches[i].value) {
+                               ia32_emitf(tbl.defProj, ".long %L\n");
+                               ++last_value;
+                       }
+                       ia32_emitf(tbl.branches[i].target, ".long %L\n");
+                       ++last_value;
+               }
+               be_gas_emit_switch_section(GAS_SECTION_TEXT);
+       } else {
+               /* one jump is enough */
+               panic("switch only has one case");
+               //ia32_emitf(tbl.branches[0].target, "\tjmp %L\n");
+       }
+
+       be_emit_write_line();
+
+       free(tbl.branches);
+}
+
 /**
  * Emits a return.
  */
@@ -3857,7 +4178,7 @@ static void ia32_register_binary_emitters(void)
        register_emitter(op_ia32_AndMem,        bemit_andmem);
        register_emitter(op_ia32_AndMem8Bit,    bemit_andmem8bit);
        register_emitter(op_ia32_Breakpoint,    bemit_int3);
-       register_emitter(op_ia32_CMov,          bemit_cmov);
+       register_emitter(op_ia32_CMovcc,        bemit_cmovcc);
        register_emitter(op_ia32_Call,          bemit_call);
        register_emitter(op_ia32_Cltd,          bemit_cltd);
        register_emitter(op_ia32_Cmc,           bemit_cmc);
@@ -3891,6 +4212,7 @@ static void ia32_register_binary_emitters(void)
        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_Minus64Bit,    bemit_minus64bit);
        register_emitter(op_ia32_Mul,           bemit_mul);
        register_emitter(op_ia32_Neg,           bemit_neg);
        register_emitter(op_ia32_NegMem,        bemit_negmem);
@@ -3912,7 +4234,7 @@ static void ia32_register_binary_emitters(void)
        register_emitter(op_ia32_Sar,           bemit_sar);
        register_emitter(op_ia32_SarMem,        bemit_sarmem);
        register_emitter(op_ia32_Sbb,           bemit_sbb);
-       register_emitter(op_ia32_Set,           bemit_set);
+       register_emitter(op_ia32_Setcc,         bemit_setcc);
        register_emitter(op_ia32_Shl,           bemit_shl);
        register_emitter(op_ia32_ShlD,          bemit_shld);
        register_emitter(op_ia32_ShlMem,        bemit_shlmem);
@@ -3926,6 +4248,7 @@ static void ia32_register_binary_emitters(void)
        register_emitter(op_ia32_SubMem,        bemit_submem);
        register_emitter(op_ia32_SubMem8Bit,    bemit_submem8bit);
        register_emitter(op_ia32_SubSP,         bemit_subsp);
+       register_emitter(op_ia32_SwitchJmp,     bemit_switchjmp);
        register_emitter(op_ia32_Test,          bemit_test);
        register_emitter(op_ia32_Test8Bit,      bemit_test8bit);
        register_emitter(op_ia32_Xor,           bemit_xor);