backend: created a (not so nice) macro to iterate over all values defined by an instr...
[libfirm] / ir / be / ia32 / ia32_emitter.c
index 3d8d34c..d0f2bc6 100644 (file)
  * @brief       This file implements the ia32 node emitter.
  * @author      Christian Wuerdig, Matthias Braun
  * @version     $Id$
+ *
+ * Summary table for x86 floatingpoint compares:
+ *   pnc_Eq  => !P && E
+ *   pnc_Lt  => !P && B
+ *   pnc_Le  => !P && BE
+ *   pnc_Gt  => A
+ *   pnc_Ge  => AE
+ *   pnc_Lg  => P || NE
+ *   pnc_Leg => NP  (ordered)
+ *   pnc_Uo  => P
+ *   pnc_Ue  => E
+ *   pnc_Ul  => B
+ *   pnc_Ule => BE
+ *   pnc_Ug  => P || A
+ *   pnc_Uge => P || AE
+ *   pnc_Ne  => NE
  */
 #include "config.h"
 
@@ -54,6 +70,7 @@
 #include "../be_dbgout.h"
 
 #include "ia32_emitter.h"
+#include "ia32_common_transform.h"
 #include "gen_ia32_emitter.h"
 #include "gen_ia32_regalloc_if.h"
 #include "ia32_nodes_attr.h"
@@ -64,8 +81,6 @@
 
 DEBUG_ONLY(static firm_dbg_module_t *dbg = NULL;)
 
-#define BLOCK_PREFIX ".L"
-
 #define SNPRINTF_BUF_LEN 128
 
 static const ia32_isa_t *isa;
@@ -143,20 +158,6 @@ static const arch_register_t *get_in_reg(const ir_node *irn, int pos)
        if (reg == &ia32_gp_regs[REG_GP_NOREG])
                panic("trying to emit noreg for %+F input %d", irn, pos);
 
-       /* in case of unknown register: just return a valid register */
-       if (reg == &ia32_gp_regs[REG_GP_UKNWN]) {
-               const arch_register_req_t *req = arch_get_register_req(irn, pos);
-
-               if (arch_register_req_is(req, limited)) {
-                       /* in case of limited requirements: get the first allowed register */
-                       unsigned idx = rbitset_next(req->limited, 0, 1);
-                       reg = arch_register_for_index(req->cls, idx);
-               } else {
-                       /* otherwise get first register in class */
-                       reg = arch_register_for_index(req->cls, 0);
-               }
-       }
-
        return reg;
 }
 
@@ -201,20 +202,10 @@ static const arch_register_t *get_out_reg(const ir_node *irn, int pos)
 static char *get_unique_label(char *buf, size_t buflen, const char *prefix)
 {
        static unsigned long id = 0;
-       snprintf(buf, buflen, "%s%lu", prefix, ++id);
+       snprintf(buf, buflen, "%s%s%lu", be_gas_get_private_prefix(), prefix, ++id);
        return buf;
 }
 
-/*************************************************************
- *             _       _    __   _          _
- *            (_)     | |  / _| | |        | |
- *  _ __  _ __ _ _ __ | |_| |_  | |__   ___| |_ __   ___ _ __
- * | '_ \| '__| | '_ \| __|  _| | '_ \ / _ \ | '_ \ / _ \ '__|
- * | |_) | |  | | | | | |_| |   | | | |  __/ | |_) |  __/ |
- * | .__/|_|  |_|_| |_|\__|_|   |_| |_|\___|_| .__/ \___|_|
- * | |                                       | |
- * |_|                                       |_|
- *************************************************************/
 
 /**
  * Emit the name of the 8bit low register
@@ -282,11 +273,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_visibility(entity) == ir_visibility_external) {
                        be_emit_cstring("@INDNTPOFF");
                } else {
                        be_emit_cstring("@NTPOFF");
@@ -421,13 +411,16 @@ void ia32_emit_x87_mode_suffix(const ir_node *node)
 
        if (mode_is_float(mode)) {
                switch (get_mode_size_bits(mode)) {
-                       case 32: be_emit_char('s'); return;
-                       case 64: be_emit_char('l'); return;
-                       case 80:
-                       case 96: be_emit_char('t'); return;
+                       case  32: be_emit_char('s'); return;
+                       case  64: be_emit_char('l'); return;
+                       /* long doubles have different sizes due to alignment on different
+                        * platforms. */
+                       case  80:
+                       case  96:
+                       case 128: be_emit_char('t'); return;
                }
        } else {
-               assert(mode_is_int(mode));
+               assert(mode_is_int(mode) || mode_is_reference(mode));
                switch (get_mode_size_bits(mode)) {
                        case 16: be_emit_char('s');     return;
                        case 32: be_emit_char('l');     return;
@@ -442,7 +435,7 @@ void ia32_emit_x87_mode_suffix(const ir_node *node)
 static char get_xmm_mode_suffix(ir_mode *mode)
 {
        assert(mode_is_float(mode));
-       switch(get_mode_size_bits(mode)) {
+       switch (get_mode_size_bits(mode)) {
        case 32: return 's';
        case 64: return 'd';
        default: panic("Invalid XMM mode");
@@ -494,27 +487,13 @@ static ir_node *get_cfop_target_block(const ir_node *irn)
        return get_irn_link(irn);
 }
 
-/**
- * Emits a block label for the given block.
- */
-static void ia32_emit_block_name(const ir_node *block)
-{
-       if (has_Block_entity(block)) {
-               ir_entity *entity = get_Block_entity(block);
-               be_gas_emit_entity(entity);
-       } else {
-               be_emit_cstring(BLOCK_PREFIX);
-               be_emit_irprintf("%ld", get_irn_node_nr(block));
-       }
-}
-
 /**
  * Emits the target label for a control flow node.
  */
 static void ia32_emit_cfop_target(const ir_node *node)
 {
        ir_node *block = get_cfop_target_block(node);
-       ia32_emit_block_name(block);
+       be_gas_emit_block_name(block);
 }
 
 /*
@@ -556,6 +535,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 +548,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 +629,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 +662,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;
+               for (;;) {
+                       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 +683,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 +704,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 +753,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;
                        }
 
@@ -853,7 +840,7 @@ void ia32_emit_binop(const ir_node *node)
  */
 void ia32_emit_x87_binop(const ir_node *node)
 {
-       switch(get_ia32_op_type(node)) {
+       switch (get_ia32_op_type(node)) {
                case ia32_Normal:
                        {
                                const ia32_x87_attr_t *x87_attr = get_ia32_x87_attr_const(node);
@@ -949,8 +936,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;
@@ -996,16 +982,10 @@ static pn_Cmp ia32_get_negated_pnc(pn_Cmp pnc)
        return get_negated_pnc(pnc, mode);
 }
 
-void ia32_emit_cmp_suffix_node(const ir_node *node,
-                               int flags_pos)
+void ia32_emit_cmp_suffix_node(const ir_node *node, int flags_pos)
 {
-       const ia32_attr_t *attr = get_ia32_attr_const(node);
-
        pn_Cmp pnc = get_ia32_condcode(node);
-
        pnc = determine_final_pnc(node, flags_pos, pnc);
-       if (attr->data.ins_permuted)
-               pnc = ia32_get_negated_pnc(pnc);
 
        ia32_emit_cmp_suffix(pnc);
 }
@@ -1057,7 +1037,6 @@ static void emit_ia32_Jcc(const ir_node *node)
        int            need_parity_label = 0;
        const ir_node *proj_true;
        const ir_node *proj_false;
-       const ir_node *block;
        pn_Cmp         pnc = get_ia32_condcode(node);
 
        pnc = determine_final_pnc(node, 0, pnc);
@@ -1069,8 +1048,6 @@ static void emit_ia32_Jcc(const ir_node *node)
        proj_false = get_proj(node, pn_ia32_Jcc_false);
        assert(proj_false && "Jcc without false Proj");
 
-       block      = get_nodes_block(node);
-
        if (can_be_fallthrough(proj_true)) {
                /* exchange both proj's so the second one can be omitted */
                const ir_node *t = proj_true;
@@ -1083,37 +1060,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 +1109,67 @@ 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
+        * Permuting inputs of a cmov means the condition is negated!
+        */
+       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 +1179,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,24 +1189,24 @@ 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);
 }
 
-/*********************************************************
- *                 _ _       _
- *                (_) |     (_)
- *   ___ _ __ ___  _| |_     _ _   _ _ __ ___  _ __  ___
- *  / _ \ '_ ` _ \| | __|   | | | | | '_ ` _ \| '_ \/ __|
- * |  __/ | | | | | | |_    | | |_| | | | | | | |_) \__ \
- *  \___|_| |_| |_|_|\__|   | |\__,_|_| |_| |_| .__/|___/
- *                         _/ |               | |
- *                        |__/                |_|
- *********************************************************/
 
 /* jump table entry (target and corresponding number) */
 typedef struct _branch_t {
@@ -1222,12 +1247,12 @@ static void generate_jump_table(jmp_tbl_t *tbl, const ir_node *node)
        const ir_edge_t    *edge;
 
        /* fill the table structure */
-       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);
-       tbl->min_value    = INT_MAX;
-       tbl->max_value    = INT_MIN;
+       tbl->min_value    = LONG_MAX;
+       tbl->max_value    = LONG_MIN;
 
        default_pn = get_ia32_condcode(node);
        i = 0;
@@ -1350,7 +1375,7 @@ static const char* emit_asm_operand(const ir_node *node, const char *s)
        c = *(++s);
 
        /* parse modifiers */
-       switch(c) {
+       switch (c) {
        case 0:
                ir_fprintf(stderr, "Warning: asm text (%+F) ends with %%\n", node);
                be_emit_char('%');
@@ -1429,7 +1454,7 @@ static const char* emit_asm_operand(const ir_node *node, const char *s)
        /* emit it */
        if (modifier != 0) {
                be_emit_char('%');
-               switch(modifier) {
+               switch (modifier) {
                case 'b':
                        reg_name = ia32_get_mapped_reg_name(isa->regs_8bit, reg);
                        break;
@@ -1470,7 +1495,7 @@ static void emit_ia32_Asm(const ir_node *node)
        if (s[0] != '\t')
                be_emit_char('\t');
 
-       while(*s != 0) {
+       while (*s != 0) {
                if (*s == '%') {
                        s = emit_asm_operand(node, s);
                } else {
@@ -1481,16 +1506,6 @@ static void emit_ia32_Asm(const ir_node *node)
        ia32_emitf(NULL, "\n#NO_APP\n");
 }
 
-/**********************************
- *   _____                  ____
- *  / ____|                |  _ \
- * | |     ___  _ __  _   _| |_) |
- * | |    / _ \| '_ \| | | |  _ <
- * | |___| (_) | |_) | |_| | |_) |
- *  \_____\___/| .__/ \__, |____/
- *             | |     __/ |
- *             |_|    |___/
- **********************************/
 
 /**
  * Emit movsb/w instructions to make mov count divideable by 4
@@ -1530,17 +1545,6 @@ static void emit_ia32_CopyB_i(const ir_node *node)
 }
 
 
-
-/***************************
- *   _____
- *  / ____|
- * | |     ___  _ ____   __
- * | |    / _ \| '_ \ \ / /
- * | |___| (_) | | | \ V /
- *  \_____\___/|_| |_|\_/
- *
- ***************************/
-
 /**
  * Emit code for conversions (I, FP), (FP, I) and (FP, FP).
  */
@@ -1595,16 +1599,6 @@ static void emit_ia32_Call(const ir_node *node)
 }
 
 
-/*******************************************
- *  _                          _
- * | |                        | |
- * | |__   ___ _ __   ___   __| | ___  ___
- * | '_ \ / _ \ '_ \ / _ \ / _` |/ _ \/ __|
- * | |_) |  __/ | | | (_) | (_| |  __/\__ \
- * |_.__/ \___|_| |_|\___/ \__,_|\___||___/
- *
- *******************************************/
-
 /**
  * Emits code to increase stack pointer.
  */
@@ -1622,16 +1616,6 @@ static void emit_be_IncSP(const ir_node *node)
        }
 }
 
-static inline bool is_unknown_reg(const arch_register_t *reg)
-{
-       if(reg == &ia32_gp_regs[REG_GP_UKNWN]
-                       || reg == &ia32_xmm_regs[REG_XMM_UKNWN]
-                       || reg == &ia32_vfp_regs[REG_VFP_UKNWN])
-               return true;
-
-       return false;
-}
-
 /**
  * Emits code for Copy/CopyKeep.
  */
@@ -1643,8 +1627,6 @@ static void Copy_emitter(const ir_node *node, const ir_node *op)
        if (in == out) {
                return;
        }
-       if (is_unknown_reg(in))
-               return;
        /* copies of vf nodes aren't real... */
        if (arch_register_get_class(in) == &ia32_reg_classes[CLASS_ia32_vfp])
                return;
@@ -1816,10 +1798,14 @@ static void emit_ia32_ClimbFrame(const ir_node *node)
 
        ia32_emitf(node, "\tmovl %S0, %D0\n");
        ia32_emitf(node, "\tmovl $%u, %S1\n", attr->count);
-       ia32_emitf(NULL, BLOCK_PREFIX "%ld:\n", get_irn_node_nr(node));
+       be_gas_emit_block_name(node);
+       be_emit_cstring(":\n");
+       be_emit_write_line();
        ia32_emitf(node, "\tmovl (%D0), %D0\n");
        ia32_emitf(node, "\tdec %S1\n");
-       ia32_emitf(node, "\tjnz " BLOCK_PREFIX "%ld\n", get_irn_node_nr(node));
+       be_emit_cstring("\tjnz ");
+       be_gas_emit_block_name(node);
+       be_emit_finish_line_gas(node);
 }
 
 static void emit_be_Return(const ir_node *node)
@@ -1839,16 +1825,6 @@ static void emit_Nothing(const ir_node *node)
 }
 
 
-/***********************************************************************************
- *                  _          __                                             _
- *                 (_)        / _|                                           | |
- *  _ __ ___   __ _ _ _ __   | |_ _ __ __ _ _ __ ___   _____      _____  _ __| | __
- * | '_ ` _ \ / _` | | '_ \  |  _| '__/ _` | '_ ` _ \ / _ \ \ /\ / / _ \| '__| |/ /
- * | | | | | | (_| | | | | | | | | | | (_| | | | | | |  __/\ V  V / (_) | |  |   <
- * |_| |_| |_|\__,_|_|_| |_| |_| |_|  \__,_|_| |_| |_|\___| \_/\_/ \___/|_|  |_|\_\
- *
- ***********************************************************************************/
-
 /**
  * Enters the emitter functions for handled nodes into the generic
  * pointer of an opcode.
@@ -1871,7 +1847,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);
@@ -1883,6 +1859,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);
@@ -1995,7 +1972,7 @@ static void ia32_emit_align_label(void)
 static int should_align_block(const ir_node *block)
 {
        static const double DELTA = .0001;
-       ir_exec_freq *exec_freq   = cg->birg->exec_freq;
+       ir_exec_freq *exec_freq   = be_get_irg_exec_freq(cg->irg);
        ir_node      *prev        = get_prev_block_sched(block);
        double        block_freq;
        double        prev_freq = 0;  /**< execfreq of the fallthrough block */
@@ -2012,7 +1989,7 @@ static int should_align_block(const ir_node *block)
                return 0;
 
        n_cfgpreds = get_Block_n_cfgpreds(block);
-       for(i = 0; i < n_cfgpreds; ++i) {
+       for (i = 0; i < n_cfgpreds; ++i) {
                const ir_node *pred      = get_Block_cfgpred_block(block, i);
                double         pred_freq = get_block_execfreq(exec_freq, pred);
 
@@ -2042,7 +2019,7 @@ static void ia32_emit_block_header(ir_node *block)
        ir_graph     *irg = current_ir_graph;
        int           need_label = block_needs_label(block);
        int           i, arity;
-       ir_exec_freq *exec_freq = cg->birg->exec_freq;
+       ir_exec_freq *exec_freq = be_get_irg_exec_freq(cg->irg);
 
        if (block == get_irg_end_block(irg))
                return;
@@ -2074,14 +2051,14 @@ static void ia32_emit_block_header(ir_node *block)
        }
 
        if (need_label) {
-               ia32_emit_block_name(block);
+               be_gas_emit_block_name(block);
                be_emit_char(':');
 
                be_emit_pad_comment();
                be_emit_cstring("   /* ");
        } else {
                be_emit_cstring("\t/* ");
-               ia32_emit_block_name(block);
+               be_gas_emit_block_name(block);
                be_emit_cstring(": ");
        }
 
@@ -2178,13 +2155,15 @@ void ia32_gen_routine(ia32_code_gen_t *ia32_cg, ir_graph *irg)
 
        cg       = ia32_cg;
        isa      = cg->isa;
-       do_pic   = cg->birg->main_env->options->pic;
+       do_pic   = be_get_irg_options(cg->irg)->pic;
+
+       be_gas_elf_type_char = '@';
 
        ia32_register_emitters();
 
-       get_unique_label(pic_base_label, sizeof(pic_base_label), ".PIC_BASE");
+       get_unique_label(pic_base_label, sizeof(pic_base_label), "PIC_BASE");
 
-       be_dbg_method_begin(entity, be_abi_get_stack_layout(cg->birg->abi));
+       be_dbg_method_begin(entity);
        be_gas_emit_function_prolog(entity, ia32_cg_config.function_alignment);
 
        /* we use links to point to target blocks */
@@ -2224,7 +2203,7 @@ void ia32_gen_routine(ia32_code_gen_t *ia32_cg, ir_graph *irg)
                        ia32_emit_exc_label(exc_list[i].exc_instr);
                        be_emit_char('\n');
                        be_emit_cstring("\t.long ");
-                       ia32_emit_block_name(exc_list[i].block);
+                       be_gas_emit_block_name(exc_list[i].block);
                        be_emit_char('\n');
                }
        }
@@ -2239,8 +2218,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];
 
@@ -2270,6 +2249,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;
@@ -2348,11 +2328,10 @@ static void bemit_entity(ir_entity *entity, bool entity_sign, int offset,
        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_visibility(entity) == visibility_external_allocated) {
+               if (get_entity_visibility(entity) == ir_visibility_external) {
                        be_emit_cstring("@INDNTPOFF");
                } else {
                        be_emit_cstring("@NTPOFF");
@@ -2374,7 +2353,7 @@ static void bemit_entity(ir_entity *entity, bool entity_sign, int offset,
 static void bemit_jmp_destination(const ir_node *dest_block)
 {
        be_emit_cstring("\t.long ");
-       ia32_emit_block_name(dest_block);
+       be_gas_emit_block_name(dest_block);
        be_emit_cstring(" - . - 4\n");
        be_emit_write_line();
 }
@@ -2382,6 +2361,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)
@@ -2392,6 +2376,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)
 {
@@ -2402,6 +2396,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.
  *
@@ -2633,7 +2637,7 @@ static void bemit_copy(const ir_node *copy)
        const arch_register_t *in  = get_in_reg(copy, 0);
        const arch_register_t *out = get_out_reg(copy, 0);
 
-       if (in == out || is_unknown_reg(in))
+       if (in == out)
                return;
        /* copies of vf nodes aren't real... */
        if (arch_register_get_class(in) == &ia32_reg_classes[CLASS_ia32_vfp])
@@ -2715,10 +2719,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; \
@@ -2802,10 +2807,11 @@ 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) { \
@@ -2860,7 +2866,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;
@@ -2869,10 +2946,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) {
@@ -2893,7 +2970,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 {
@@ -2988,8 +3065,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);
@@ -3017,8 +3094,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);
@@ -3070,21 +3147,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);
@@ -4030,7 +4092,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);
@@ -4086,7 +4148,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);