psi transform and emit logical rewritten from scratch
authorMatthias Braun <matze@braunis.de>
Fri, 15 Jun 2007 09:03:32 +0000 (09:03 +0000)
committerMatthias Braun <matze@braunis.de>
Fri, 15 Jun 2007 09:03:32 +0000 (09:03 +0000)
[r14513]

ir/be/ia32/bearch_ia32.c
ir/be/ia32/ia32_emitter.c
ir/be/ia32/ia32_finish.c
ir/be/ia32/ia32_new_nodes.c
ir/be/ia32/ia32_new_nodes.h
ir/be/ia32/ia32_nodes_attr.h
ir/be/ia32/ia32_optimize.c
ir/be/ia32/ia32_spec.pl
ir/be/ia32/ia32_transform.c
ir/be/ia32/ia32_transform.h

index 684d5cf..7802d98 100644 (file)
@@ -867,17 +867,10 @@ ia32_irn_ops_t ia32_irn_ops = {
 static void ia32_prepare_graph(void *self) {
        ia32_code_gen_t *cg = self;
 
-       /* transform psi condition trees */
-       ia32_pre_transform_phase(cg);
-
-       /* transform all remaining nodes */
+       /* transform nodes into assembler instructions */
        ia32_transform_graph(cg);
-       //add_fpu_edges(cg->birg);
 
-       // Matze: disabled for now. Because after transformation start block has no
-       // self-loop anymore so it might be merged with its successor block. This
-       // will bring several nodes to the startblock which sometimes get scheduled
-       // before the initial IncSP/Barrier
+       /* do local optimisations (mainly CSE) */
        local_optimize_graph(cg->irg);
 
        if (cg->dump)
index ab56822..5137215 100644 (file)
@@ -930,25 +930,58 @@ void emit_ia32_x87CondJmp(ia32_emit_env_t *env, const ir_node *node) {
        finish_CondJmp(env, node, mode_E, pnc);
 }
 
+static
+void emit_register_or_immediate(ia32_emit_env_t *env, const ir_node *node,
+                                int pos)
+{
+       ir_node *op = get_irn_n(node, pos);
+       if(is_ia32_Immediate(op)) {
+               emit_ia32_Immediate(env, op);
+       } else {
+               ia32_emit_source_register(env, node, pos);
+       }
+}
+
+static
+int is_ia32_Immediate_0(const ir_node *node)
+{
+       const ia32_immediate_attr_t *attr = get_ia32_immediate_attr_const(node);
+       tarval                      *tv   = attr->offset;
+
+       if(tv == NULL || attr->symconst != NULL)
+               return 0;
+
+       return classify_tarval(tv) == CNST_NULL;
+}
+
 static
 void CMov_emitter(ia32_emit_env_t *env, const ir_node *node) {
        long pnc = get_ia32_pncode(node);
-       int is_PsiCondCMov = is_ia32_PsiCondCMov(node);
-       int idx_left  = 2 - is_PsiCondCMov;
-       int idx_right = 3 - is_PsiCondCMov;
        const arch_register_t *in1, *in2, *out;
 
        out = arch_get_irn_register(env->arch_env, node);
-       in1 = arch_get_irn_register(env->arch_env, get_irn_n(node, idx_left));
-       in2 = arch_get_irn_register(env->arch_env, get_irn_n(node, idx_right));
+       in1 = arch_get_irn_register(env->arch_env, get_irn_n(node, 2));
+       in2 = arch_get_irn_register(env->arch_env, get_irn_n(node, 3));
 
        /* we have to emit the cmp first, because the destination register */
        /* could be one of the compare registers                           */
        if (is_ia32_CmpCMov(node)) {
-               be_emit_cstring(env, "\tcmp ");
-               ia32_emit_source_register(env, node, 1);
-               be_emit_cstring(env, ", ");
-               ia32_emit_source_register(env, node, 0);
+               long pncr = pnc & ~ia32_pn_Cmp_Unsigned;
+               ir_node *cmp_right = get_irn_n(node, 1);
+
+               if( (pncr == pn_Cmp_Eq || pncr == pn_Cmp_Lg)
+                               && is_ia32_Immediate(cmp_right)
+                               && is_ia32_Immediate_0(cmp_right)) {
+                       be_emit_cstring(env, "\ttest ");
+                       ia32_emit_source_register(env, node, 0);
+                       be_emit_cstring(env, ", ");
+                       ia32_emit_source_register(env, node, 0);
+               } else {
+                       be_emit_cstring(env, "\tcmp ");
+                       emit_register_or_immediate(env, node, 1);
+                       be_emit_cstring(env, ", ");
+                       ia32_emit_source_register(env, node, 0);
+               }
        } else if (is_ia32_xCmpCMov(node)) {
                be_emit_cstring(env, "\tucomis");
                ia32_emit_mode_suffix_mode(env, get_irn_mode(node));
@@ -956,12 +989,6 @@ void CMov_emitter(ia32_emit_env_t *env, const ir_node *node) {
                ia32_emit_source_register(env, node, 1);
                be_emit_cstring(env, ", ");
                ia32_emit_source_register(env, node, 0);
-       } else if (is_PsiCondCMov) {
-               /* omit compare because flags are already set by And/Or */
-               be_emit_cstring(env, "\ttest ");
-               ia32_emit_source_register(env, node, 0);
-               be_emit_cstring(env, ", ");
-               ia32_emit_source_register(env, node, 0);
        } else {
                assert(0 && "unsupported CMov");
        }
@@ -972,42 +999,26 @@ void CMov_emitter(ia32_emit_env_t *env, const ir_node *node) {
        } else if (REGS_ARE_EQUAL(out, in1)) {
                ir_node *n = (ir_node*) node;
                /* true in == out -> need complement compare and exchange true and default in */
-               ir_node *t = get_irn_n(n, idx_left);
-               set_irn_n(n, idx_left, get_irn_n(n, idx_right));
-               set_irn_n(n, idx_right, t);
+               ir_node *t = get_irn_n(n, 2);
+               set_irn_n(n, 2, get_irn_n(n, 3));
+               set_irn_n(n, 3, t);
 
                pnc = get_negated_pnc(pnc, get_irn_mode(node));
        } else {
                /* out is different from in: need copy default -> out */
-               if (is_PsiCondCMov) {
-                       be_emit_cstring(env, "\tmovl ");
-                       ia32_emit_dest_register(env, node, 2);
-                       be_emit_cstring(env, ", ");
-                       ia32_emit_dest_register(env, node, 0);
-               } else {
-                       be_emit_cstring(env, "\tmovl ");
-                       ia32_emit_source_register(env, node, 3);
-                       be_emit_cstring(env, ", ");
-                       ia32_emit_dest_register(env, node, 0);
-               }
-               be_emit_finish_line_gas(env, node);
-       }
-
-       if (is_PsiCondCMov) {
-               be_emit_cstring(env, "\tcmov");
-               ia32_emit_cmp_suffix(env, pnc);
-               be_emit_cstring(env, "l ");
-               ia32_emit_source_register(env, node, 1);
-               be_emit_cstring(env, ", ");
-               ia32_emit_dest_register(env, node, 0);
-       } else {
-               be_emit_cstring(env, "\tcmov");
-               ia32_emit_cmp_suffix(env, pnc);
-               be_emit_cstring(env, "l ");
-               ia32_emit_source_register(env, node, 2);
+               be_emit_cstring(env, "\tmovl ");
+               ia32_emit_source_register(env, node, 3);
                be_emit_cstring(env, ", ");
                ia32_emit_dest_register(env, node, 0);
+               be_emit_finish_line_gas(env, node);
        }
+
+       be_emit_cstring(env, "\tcmov");
+       ia32_emit_cmp_suffix(env, pnc);
+       be_emit_cstring(env, "l ");
+       ia32_emit_source_register(env, node, 2);
+       be_emit_cstring(env, ", ");
+       ia32_emit_dest_register(env, node, 0);
        be_emit_finish_line_gas(env, node);
 }
 
@@ -1016,11 +1027,6 @@ void emit_ia32_CmpCMov(ia32_emit_env_t *env, const ir_node *node) {
        CMov_emitter(env, node);
 }
 
-static
-void emit_ia32_PsiCondCMov(ia32_emit_env_t *env, const ir_node *node) {
-       CMov_emitter(env, node);
-}
-
 static
 void emit_ia32_xCmpCMov(ia32_emit_env_t *env, const ir_node *node) {
        CMov_emitter(env, node);
@@ -1028,7 +1034,7 @@ void emit_ia32_xCmpCMov(ia32_emit_env_t *env, const ir_node *node) {
 
 static
 void Set_emitter(ia32_emit_env_t *env, const ir_node *node, ir_mode *mode) {
-       int pnc = get_ia32_pncode(node);
+       long pnc = get_ia32_pncode(node);
        const char *reg8bit;
        const arch_register_t *out;
 
@@ -1036,16 +1042,25 @@ void Set_emitter(ia32_emit_env_t *env, const ir_node *node, ir_mode *mode) {
        reg8bit = ia32_get_mapped_reg_name(env->isa->regs_8bit, out);
 
        if (is_ia32_CmpSet(node)) {
-               be_emit_cstring(env, "\tcmp ");
-               ia32_emit_binop(env, node);
+               long     pncr      = pnc & ~ia32_pn_Cmp_Unsigned;
+               ir_node *cmp_right = get_irn_n(node, n_ia32_CmpSet_cmp_right);
+
+               if( (pncr == pn_Cmp_Eq || pncr == pn_Cmp_Lg)
+                               && is_ia32_Immediate(cmp_right)
+                               && is_ia32_Immediate_0(cmp_right)) {
+                       be_emit_cstring(env, "\ttest ");
+                       ia32_emit_source_register(env, node, n_ia32_CmpSet_cmp_left);
+                       be_emit_cstring(env, ", ");
+                       ia32_emit_source_register(env, node, n_ia32_CmpSet_cmp_left);
+               } else {
+                       be_emit_cstring(env, "\tcmp ");
+                       ia32_emit_binop(env, node);
+               }
        } else if (is_ia32_xCmpSet(node)) {
                be_emit_cstring(env, "\tucomis");
                ia32_emit_mode_suffix_mode(env, get_irn_mode(get_irn_n(node, 2)));
                be_emit_char(env, ' ');
                ia32_emit_binop(env, node);
-       } else if (is_ia32_PsiCondSet(node)) {
-               be_emit_cstring(env, "\tcmp $0, ");
-               ia32_emit_source_register(env, node, 0);
        } else {
                assert(0 && "unsupported Set");
        }
@@ -1068,11 +1083,6 @@ void emit_ia32_CmpSet(ia32_emit_env_t *env, const ir_node *node) {
        Set_emitter(env, node, get_irn_mode(get_irn_n(node, 2)));
 }
 
-static
-void emit_ia32_PsiCondSet(ia32_emit_env_t *env, const ir_node *node) {
-       Set_emitter(env, node, get_irn_mode(get_irn_n(node, 0)));
-}
-
 static
 void emit_ia32_xCmpSet(ia32_emit_env_t *env, const ir_node *node) {
        Set_emitter(env, node, get_irn_mode(get_irn_n(node, 2)));
@@ -1336,22 +1346,22 @@ void emit_Jmp(ia32_emit_env_t *env, const ir_node *node) {
 static
 void emit_ia32_Immediate(ia32_emit_env_t *env, const ir_node *node)
 {
-       const ia32_attr_t *attr = get_ia32_attr_const(node);
+       const ia32_immediate_attr_t *attr = get_ia32_immediate_attr_const(node);
 
-       assert(attr->am_sc != NULL || attr->cnst_val.tv != NULL);
-       if(attr->am_sc != NULL) {
-               ident *id = get_entity_ld_ident(attr->am_sc);
+       assert(attr->symconst != NULL || attr->offset != NULL);
+       if(attr->symconst != NULL) {
+               ident *id = get_entity_ld_ident(attr->symconst);
 
-               if(attr->data.am_sc_sign)
+               if(attr->attr.data.am_sc_sign)
                        be_emit_char(env, '-');
                be_emit_ident(env, id);
        }
-       if(attr->cnst_val.tv != NULL) {
-               if(attr->am_sc != NULL)
+       if(attr->offset != NULL) {
+               if(attr->symconst != NULL)
                        be_emit_char(env, '+');
                else
                        be_emit_char(env, '$');
-               be_emit_tarval(env, attr->cnst_val.tv);
+               be_emit_tarval(env, attr->offset);
        }
 }
 
@@ -1956,9 +1966,7 @@ void ia32_register_emitters(void) {
        IA32_EMIT(CJmp);
        IA32_EMIT(CJmpAM);
        IA32_EMIT(CmpCMov);
-       IA32_EMIT(PsiCondCMov);
        IA32_EMIT(CmpSet);
-       IA32_EMIT(PsiCondSet);
        IA32_EMIT(SwitchJmp);
        IA32_EMIT(CopyB);
        IA32_EMIT(CopyB_i);
index eb6b887..b7db6cd 100644 (file)
@@ -272,7 +272,6 @@ static INLINE int need_constraint_copy(ir_node *irn) {
                ! is_ia32_Conv_I2I(irn)     &&
                ! is_ia32_Conv_I2I8Bit(irn) &&
                ! is_ia32_CmpCMov(irn)      &&
-               ! is_ia32_PsiCondCMov(irn)  &&
                ! is_ia32_CmpSet(irn);
 }
 
index 41899f6..0cbed07 100644 (file)
@@ -430,6 +430,15 @@ const ia32_asm_attr_t *get_ia32_asm_attr_const(const ir_node *node) {
        return asm_attr;
 }
 
+const ia32_immediate_attr_t *get_ia32_immediate_attr_const(const ir_node *node)
+{
+       const ia32_attr_t     *attr     = get_ia32_attr_const(node);
+       const ia32_immediate_attr_t *immediate_attr
+               = CONST_CAST_IA32_ATTR(ia32_immediate_attr_t, attr);
+
+       return immediate_attr;
+}
+
 /**
  * Gets the type of an ia32 node.
  */
@@ -1195,6 +1204,20 @@ init_ia32_asm_attributes(ir_node *res)
 #endif
 }
 
+void
+init_ia32_immediate_attributes(ir_node *res, ir_entity *symconst,
+                               int symconst_sign, tarval *offset)
+{
+       ia32_immediate_attr_t *attr = get_irn_generic_attr(res);
+
+#ifndef DEBUG
+       attr->attr.attr_type   |= IA32_ATTR_ia32_immediate_attr_t;
+#endif
+       attr->symconst             = symconst;
+       attr->attr.data.am_sc_sign = symconst_sign;
+       attr->offset               = offset;
+}
+
 ir_node *get_ia32_result_proj(const ir_node *node)
 {
        const ir_edge_t *edge;
@@ -1291,6 +1314,20 @@ int ia32_compare_asm_attr(ir_node *a, ir_node *b)
        return 0;
 }
 
+static
+int ia32_compare_immediate_attr(ir_node *a, ir_node *b)
+{
+       const ia32_immediate_attr_t *attr_a = get_ia32_immediate_attr_const(a);
+       const ia32_immediate_attr_t *attr_b = get_ia32_immediate_attr_const(b);
+
+       if(attr_a->symconst != attr_b->symconst ||
+          attr_a->attr.data.am_sc_sign != attr_b->attr.data.am_sc_sign ||
+          attr_a->offset != attr_b->offset)
+               return 1;
+
+       return 0;
+}
+
 /* copies the ia32 attributes */
 static void ia32_copy_attr(const ir_node *old_node, ir_node *new_node)
 {
index 74093d3..5d408d0 100644 (file)
@@ -57,6 +57,8 @@ const ia32_attr_t *get_ia32_attr_const(const ir_node *node);
 ia32_x87_attr_t *get_ia32_x87_attr(ir_node *node);
 const ia32_x87_attr_t *get_ia32_x87_attr_const(const ir_node *node);
 
+const ia32_immediate_attr_t *get_ia32_immediate_attr_const(const ir_node *node);
+
 /**
  * Gets the type of an ia32 node.
  */
@@ -492,6 +494,8 @@ void init_ia32_attributes(ir_node *node, arch_irn_flags_t flags,
 
 void init_ia32_x87_attributes(ir_node *node);
 void init_ia32_asm_attributes(ir_node *node);
+void init_ia32_immediate_attributes(ir_node *node, ir_entity *symconst,
+                                    int symconst_sign, tarval *offset);
 
 /**
  * Registers the ia32_copy_attr function for all ia32 opcodes.
index 37ad310..996a3cb 100644 (file)
@@ -31,6 +31,7 @@
 #include "firm_types.h"
 #include "../bearch_t.h"
 #include "../bemachine.h"
+#include "irnode_t.h"
 
 typedef enum { flavour_Div = 1, flavour_Mod, flavour_DivMod } ia32_op_flavour_t;
 typedef enum { pn_EAX, pn_EDX } pn_ia32_Register;
@@ -87,15 +88,17 @@ enum {
 
 #ifndef NDEBUG
 typedef enum {
-       IA32_ATTR_INVALID         = 0,
-       IA32_ATTR_ia32_attr_t     = 1 << 0,
-       IA32_ATTR_ia32_x87_attr_t = 1 << 1,
-       IA32_ATTR_ia32_asm_attr_t = 1 << 2,
+       IA32_ATTR_INVALID               = 0,
+       IA32_ATTR_ia32_attr_t           = 1 << 0,
+       IA32_ATTR_ia32_x87_attr_t       = 1 << 1,
+       IA32_ATTR_ia32_asm_attr_t       = 1 << 2,
+       IA32_ATTR_ia32_immediate_attr_t = 1 << 3,
 } ia32_attr_type_t;
 #endif
 
 typedef struct ia32_attr_t ia32_attr_t;
 struct ia32_attr_t {
+       except_attr  exc;               /**< the exception attribute. MUST be the first one. */
        struct {
                unsigned tp:3;              /**< ia32 node type. */
                unsigned imm_tp:2;          /**< ia32 immop type. */
@@ -152,6 +155,13 @@ struct ia32_attr_t {
        const arch_register_t **slots;     /**< register slots for assigned registers */
 };
 
+typedef struct ia32_immediate_attr_t ia32_immediate_attr_t;
+struct ia32_immediate_attr_t {
+       ia32_attr_t  attr;
+       ir_entity   *symconst;
+       tarval      *offset;
+};
+
 typedef struct ia32_x87_attr_t ia32_x87_attr_t;
 struct ia32_x87_attr_t {
        ia32_attr_t            attr;
@@ -167,9 +177,10 @@ struct ia32_asm_attr_t {
 /* the following union is necessary to indicate to the compiler that we might want to cast
  * the structs (we use them to simulate OO-inheritance) */
 union allow_casts_attr_t_ {
-       ia32_attr_t      attr;
-       ia32_x87_attr_t  x87_attr;
-       ia32_asm_attr_t  asm_attr;
+       ia32_attr_t            attr;
+       ia32_x87_attr_t        x87_attr;
+       ia32_asm_attr_t        asm_attr;
+       ia32_immediate_attr_t  immediate_attr;
 };
 
 #ifndef NDEBUG
index aba8b0e..6270789 100644 (file)
@@ -71,15 +71,6 @@ static INLINE int be_is_NoReg(ia32_code_gen_t *cg, const ir_node *irn) {
        return irn == cg->noreg_gp || irn == cg->noreg_xmm || irn == cg->noreg_vfp;
 }
 
-void ia32_pre_transform_phase(ia32_code_gen_t *cg) {
-       /*
-               We need to transform the consts twice:
-               - the psi condition tree transformer needs existing constants to be ia32 constants
-               - the psi condition tree transformer inserts new firm constants which need to be transformed
-       */
-       irg_walk_graph(cg->irg, NULL, ia32_transform_psi_cond_tree, cg);
-}
-
 /********************************************************************************************************
  *  _____                _           _         ____        _   _           _          _   _
  * |  __ \              | |         | |       / __ \      | | (_)         (_)        | | (_)
index 4522585..b2a0294 100644 (file)
@@ -303,13 +303,17 @@ $default_attr_type = "ia32_attr_t";
        ia32_asm_attr_t =>
                "\tinit_ia32_attributes(res, flags, in_reqs, out_reqs, exec_units, n_res, latency);\n".
                "\tinit_ia32_x87_attributes(res);".
-               "\tinit_ia32_asm_attributes(res);"
+               "\tinit_ia32_asm_attributes(res);",
+       ia32_immediate_attr_t =>
+               "\tinit_ia32_attributes(res, flags, in_reqs, out_reqs, exec_units, n_res, latency);\n".
+               "\tinit_ia32_immediate_attributes(res, symconst, symconst_sign, offset);"
 );
 
 %compare_attr = (
-       ia32_attr_t     => "ia32_compare_nodes_attr",
-       ia32_x87_attr_t => "ia32_compare_x87_attr",
-       ia32_asm_attr_t => "ia32_compare_asm_attr",
+       ia32_attr_t           => "ia32_compare_nodes_attr",
+       ia32_x87_attr_t       => "ia32_compare_x87_attr",
+       ia32_asm_attr_t       => "ia32_compare_asm_attr",
+       ia32_immediate_attr_t => "ia32_compare_immediate_attr",
 );
 
 %operands = (
@@ -329,6 +333,8 @@ Immediate => {
        op_flags  => "c",
        irn_flags => "I",
        reg_req   => { out => [ "gp_NOREG" ] },
+       attr      => "ir_entity *symconst, int symconst_sign, tarval *offset",
+       attr_type => "ia32_immediate_attr_t",
        mode      => $mode_gp,
 },
 
@@ -752,6 +758,7 @@ Dec => {
 Not => {
        irn_flags => "R",
        reg_req   => { in => [ "gp", "gp", "gp", "none" ], out => [ "in_r3" ] },
+       ins       => [ "base", "index", "val", "mem" ],
        emit      => '. not%M %unop2',
        units     => [ "GP" ],
        mode      => $mode_gp,
@@ -1321,14 +1328,9 @@ Conv_FP2FP => {
 CmpCMov => {
        irn_flags => "R",
        reg_req   => { in => [ "gp", "gp", "gp", "gp" ], out => [ "in_r4" ] },
-       latency   => 2,
-       units     => [ "GP" ],
-       mode      => $mode_gp,
-},
-
-PsiCondCMov => {
-       irn_flags => "R",
-       reg_req   => { in => [ "gp", "gp", "gp" ], out => [ "in_r3" ] },
+       ins       => [ "cmp_left", "cmp_right", "val_true", "val_false" ],
+       attr      => "pn_Cmp pn_code",
+       init_attr => "attr->pn_code = pn_code;",
        latency   => 2,
        units     => [ "GP" ],
        mode      => $mode_gp,
@@ -1354,14 +1356,9 @@ vfCmpCMov => {
 CmpSet => {
        irn_flags => "R",
        reg_req   => { in => [ "gp", "gp", "gp", "gp", "none" ], out => [ "eax ebx ecx edx" ] },
-       latency   => 2,
-       units     => [ "GP" ],
-       mode      => $mode_gp,
-},
-
-PsiCondSet => {
-       irn_flags => "R",
-       reg_req   => { in => [ "gp" ], out => [ "eax ebx ecx edx" ] },
+       ins       => [ "base", "index", "cmp_left", "cmp_right", "mem" ],
+       attr      => "pn_Cmp pn_code",
+       init_attr => "attr->pn_code = pn_code;",
        latency   => 2,
        units     => [ "GP" ],
        mode      => $mode_gp,
index 59338f5..aa9dde9 100644 (file)
@@ -238,6 +238,20 @@ static ir_entity *get_entity_for_tv(ia32_code_gen_t *cg, ir_node *cnst)
        return res;
 }
 
+static int is_Const_0(ir_node *node) {
+       if(!is_Const(node))
+               return 0;
+
+       return classify_Const(node) == CNST_NULL;
+}
+
+static int is_Const_1(ir_node *node) {
+       if(!is_Const(node))
+               return 0;
+
+       return classify_Const(node) == CNST_ONE;
+}
+
 /**
  * Transforms a Const.
  */
@@ -352,6 +366,7 @@ static ir_node *gen_SymConst(ir_node *node) {
        return cnst;
 }
 
+#if 0
 /**
  * SSE convert of an integer node into a floating point node.
  */
@@ -392,6 +407,7 @@ static ir_node *gen_sse_conv_f2d(ia32_code_gen_t *cg, dbg_info *dbgi,
 
        return conv;
 }
+#endif
 
 /* Generates an entity for a known FP const (used for FP Neg + Abs) */
 ir_entity *ia32_gen_fp_known_const(ia32_known_const_t kct) {
@@ -1004,9 +1020,8 @@ static ir_node *gen_Max(ir_node *node) {
                if (! mode_is_signed(op_mode)) {
                        pnc |= ia32_pn_Cmp_Unsigned;
                }
-               new_op = new_rd_ia32_CmpCMov(dbgi, irg, block, new_op1, new_op2, new_op1, new_op2);
-               set_ia32_pncode(new_op, pnc);
-               set_ia32_am_support(new_op, ia32_am_None);
+               new_op = new_rd_ia32_CmpCMov(dbgi, irg, block, new_op1, new_op2,
+                                            new_op1, new_op2, pnc);
        }
        SET_IA32_ORIG_NODE(new_op, ia32_get_old_node_name(env_cg, node));
 
@@ -1044,9 +1059,8 @@ static ir_node *gen_Min(ir_node *node) {
                if (! mode_is_signed(op_mode)) {
                        pnc |= ia32_pn_Cmp_Unsigned;
                }
-               new_op = new_rd_ia32_CmpCMov(dbgi, irg, block, new_op1, new_op2, new_op1, new_op2);
-               set_ia32_pncode(new_op, pnc);
-               set_ia32_am_support(new_op, ia32_am_None);
+               new_op = new_rd_ia32_CmpCMov(dbgi, irg, block, new_op1, new_op2,
+                                            new_op1, new_op2, pnc);
        }
        SET_IA32_ORIG_NODE(new_op, ia32_get_old_node_name(env_cg, node));
 
@@ -1657,6 +1671,7 @@ static ir_node *gen_Load(ir_node *node) {
                }
        }
 
+       set_irn_pinned(new_op, get_irn_pinned(node));
        set_ia32_am_support(new_op, ia32_am_Source);
        set_ia32_op_type(new_op, ia32_AddrModeS);
        set_ia32_am_flavour(new_op, am_flav);
@@ -1744,6 +1759,7 @@ static ir_node *gen_Store(ir_node *node) {
                }
        }
 
+       set_irn_pinned(new_op, get_irn_pinned(node));
        set_ia32_am_support(new_op, ia32_am_Dest);
        set_ia32_op_type(new_op, ia32_AddrModeD);
        set_ia32_am_flavour(new_op, am_flav);
@@ -1997,36 +2013,83 @@ typedef ir_node *cmov_func_t(dbg_info *db, ir_graph *irg, ir_node *block,
 static ir_node *gen_Psi(ir_node *node) {
        ir_node  *block           = be_transform_node(get_nodes_block(node));
        ir_node  *psi_true        = get_Psi_val(node, 0);
-       ir_node  *new_psi_true    = be_transform_node(psi_true);
        ir_node  *psi_default     = get_Psi_default(node);
-       ir_node  *new_psi_default = be_transform_node(psi_default);
        ia32_code_gen_t *cg       = env_cg;
        ir_graph *irg             = current_ir_graph;
        dbg_info *dbgi            = get_irn_dbg_info(node);
-       ir_mode  *mode            = get_irn_mode(node);
-       ir_node  *cmp_proj        = get_Mux_sel(node);
-       ir_node  *noreg           = ia32_new_NoReg_gp(cg);
-       ir_node  *nomem           = new_rd_NoMem(irg);
-       ir_node  *cmp, *cmp_a, *cmp_b, *and1, *and2, *new_op = NULL;
+       ir_node  *cond            = get_Psi_cond(node, 0);
+       ir_node  *noreg           = ia32_new_NoReg_gp(env_cg);
+       ir_node  *nomem           = new_NoMem();
+       ir_node  *new_op;
+       ir_node  *cmp, *cmp_a, *cmp_b;
        ir_node  *new_cmp_a, *new_cmp_b;
        ir_mode  *cmp_mode;
-       int      pnc;
-
-       assert(get_irn_mode(cmp_proj) == mode_b && "Condition for Psi must have mode_b");
+       int       pnc;
+
+       assert(get_Psi_n_conds(node) == 1);
+       assert(get_irn_mode(cond) == mode_b);
+
+       if(is_And(cond) || is_Or(cond)) {
+               ir_node *new_cond = be_transform_node(cond);
+               tarval  *tv_zero  = new_tarval_from_long(0, mode_Iu);
+               ir_node *zero     = new_rd_ia32_Immediate(NULL, irg, block, NULL, 0,
+                                                         tv_zero);
+               arch_set_irn_register(env_cg->arch_env, zero,
+                                     &ia32_gp_regs[REG_GP_NOREG]);
+
+               /* we have to compare the result against zero */
+               new_cmp_a = new_cond;
+               new_cmp_b = zero;
+               pnc       = pn_Cmp_Lg;
+       } else {
+               cmp       = get_Proj_pred(cond);
+               cmp_a     = get_Cmp_left(cmp);
+               cmp_b     = get_Cmp_right(cmp);
+               cmp_mode  = get_irn_mode(cmp_a);
+               pnc       = get_Proj_proj(cond);
+
+               new_cmp_b = try_create_Immediate(cmp_b, 0);
+               if(new_cmp_b == NULL) {
+                       new_cmp_b = try_create_Immediate(cmp_a, 0);
+                       if(new_cmp_b != NULL) {
+                               pnc       = get_inversed_pnc(pnc);
+                               new_cmp_a = be_transform_node(cmp_b);
+                       }
+               } else {
+                       new_cmp_a = be_transform_node(cmp_a);
+               }
+               if(new_cmp_b == NULL) {
+                       new_cmp_a = be_transform_node(cmp_a);
+                       new_cmp_b = be_transform_node(cmp_b);
+               }
 
-       cmp       = get_Proj_pred(cmp_proj);
-       cmp_a     = get_Cmp_left(cmp);
-       cmp_b     = get_Cmp_right(cmp);
-       cmp_mode  = get_irn_mode(cmp_a);
-       new_cmp_a = be_transform_node(cmp_a);
-       new_cmp_b = be_transform_node(cmp_b);
+               if (!mode_is_signed(cmp_mode)) {
+                       pnc |= ia32_pn_Cmp_Unsigned;
+               }
+       }
 
-       pnc   = get_Proj_proj(cmp_proj);
-       if (mode_is_float(cmp_mode) || !mode_is_signed(cmp_mode)) {
-               pnc |= ia32_pn_Cmp_Unsigned;
+       if(is_Const_1(psi_true) && is_Const_0(psi_default)) {
+               new_op = new_rd_ia32_CmpSet(dbgi, irg, block, noreg, noreg,
+                                           new_cmp_a, new_cmp_b, nomem, pnc);
+       } else if(is_Const_0(psi_true) && is_Const_1(psi_default)) {
+               pnc = get_inversed_pnc(pnc);
+               new_op = new_rd_ia32_CmpSet(dbgi, irg, block, noreg, noreg,
+                                           new_cmp_a, new_cmp_b, nomem, pnc);
+       } else {
+               ir_node *new_psi_true    = be_transform_node(psi_true);
+               ir_node *new_psi_default = be_transform_node(psi_default);
+               new_op = new_rd_ia32_CmpCMov(dbgi, irg, block, new_cmp_a, new_cmp_b,
+                                        new_psi_true, new_psi_default, pnc);
        }
+       SET_IA32_ORIG_NODE(new_op, ia32_get_old_node_name(cg, node));
+       return new_op;
 
+#if 0
        if (mode_is_float(mode)) {
+               if(mode_is_float(cmp_mode)) {
+                       pnc |= ia32_pn_Cmp_Unsigned;
+               }
+
                /* floating point psi */
                FP_USED(cg);
 
@@ -2144,6 +2207,7 @@ static ir_node *gen_Psi(ir_node *node) {
                        }
                }
        }
+#endif
 
        return new_op;
 }
@@ -2195,6 +2259,7 @@ static ir_node *gen_x87_fp_to_gp(ir_node *node) {
        fist = new_rd_ia32_vfist(dbgi, irg, block,
                        get_irg_frame(irg), noreg, new_op, trunc_mode, new_NoMem());
 
+       set_irn_pinned(load, op_pin_state_floats);
        set_ia32_use_frame(fist);
        set_ia32_am_support(fist, ia32_am_Dest);
        set_ia32_op_type(fist, ia32_AddrModeD);
@@ -2205,6 +2270,7 @@ static ir_node *gen_x87_fp_to_gp(ir_node *node) {
        /* do a Load */
        load = new_rd_ia32_Load(dbgi, irg, block, get_irg_frame(irg), noreg, fist);
 
+       set_irn_pinned(load, op_pin_state_floats);
        set_ia32_use_frame(load);
        set_ia32_am_support(load, ia32_am_Source);
        set_ia32_op_type(load, ia32_AddrModeS);
@@ -2425,7 +2491,6 @@ ir_node *try_create_Immediate(ir_node *node, char immediate_constraint_type)
        ir_graph    *irg;
        dbg_info    *dbgi;
        ir_node     *block;
-       ia32_attr_t *attr;
 
        mode = get_irn_mode(node);
        if(!mode_is_int(mode) && !mode_is_character(mode) &&
@@ -2502,25 +2567,20 @@ ir_node *try_create_Immediate(ir_node *node, char immediate_constraint_type)
        if(cnst == NULL && symconst == NULL)
                return NULL;
 
+       if(offset_sign && offset != NULL) {
+               offset = tarval_neg(offset);
+       }
+
        irg   = current_ir_graph;
        dbgi  = get_irn_dbg_info(node);
        block = get_irg_start_block(irg);
-       res   = new_rd_ia32_Immediate(dbgi, irg, block);
+       res   = new_rd_ia32_Immediate(dbgi, irg, block, symconst_ent, symconst_sign,
+                                     offset);
        arch_set_irn_register(env_cg->arch_env, res, &ia32_gp_regs[REG_GP_NOREG]);
 
        /* make sure we don't schedule stuff before the barrier */
        add_irn_dep(res, get_irg_frame(irg));
 
-       /* misuse some fields for now... */
-       attr                  = get_ia32_attr(res);
-       attr->am_sc           = symconst_ent;
-       attr->data.am_sc_sign = symconst_sign;
-       if(offset_sign && offset != NULL) {
-               offset = tarval_neg(offset);
-       }
-       attr->cnst_val.tv = offset;
-       attr->data.imm_tp = ia32_ImmConst;
-
        return res;
 }
 
@@ -2922,6 +2982,7 @@ static ir_node *gen_be_StackParam(ir_node *node) {
                pn_res = pn_ia32_Load_res;
        }
 
+       set_irn_pinned(new_op, op_pin_state_floats);
        set_ia32_frame_ent(new_op, ent);
        set_ia32_use_frame(new_op);
 
@@ -2991,6 +3052,7 @@ static ir_node *gen_be_FrameLoad(ir_node *node) {
                new_op = new_rd_ia32_Load(dbgi, irg, block, new_ptr, noreg, new_mem);
        }
 
+       set_irn_pinned(new_op, op_pin_state_floats);
        set_ia32_frame_ent(new_op, ent);
        set_ia32_use_frame(new_op);
 
@@ -4078,6 +4140,73 @@ static ir_node *gen_Proj_be_Call(ir_node *node) {
        return new_rd_Proj(dbgi, irg, block, new_call, mode, proj);
 }
 
+static ir_node *gen_Proj_Cmp(ir_node *node)
+{
+       /* normally Cmps are processed when looking at Cond nodes, but this case
+        * can happen in complicated Psi conditions */
+
+       ir_graph *irg           = current_ir_graph;
+       dbg_info *dbgi          = get_irn_dbg_info(node);
+       ir_node  *block         = be_transform_node(get_nodes_block(node));
+       ir_node  *cmp           = get_Proj_pred(node);
+       long      pnc           = get_Proj_proj(node);
+       ir_node  *cmp_left      = get_Cmp_left(cmp);
+       ir_node  *cmp_right     = get_Cmp_right(cmp);
+       ir_node  *new_cmp_left;
+       ir_node  *new_cmp_right;
+       ir_node  *noreg         = ia32_new_NoReg_gp(env_cg);
+       ir_node  *nomem         = new_rd_NoMem(irg);
+       ir_mode  *cmp_mode      = get_irn_mode(cmp_left);
+       ir_node  *new_op;
+
+       assert(!mode_is_float(cmp_mode));
+
+       /* (a != b) -> (a ^ b) */
+       if(pnc == pn_Cmp_Lg) {
+               if(is_Const_0(cmp_left)) {
+                       new_op = be_transform_node(cmp_right);
+               } else if(is_Const_0(cmp_right)) {
+                       new_op = be_transform_node(cmp_left);
+               } else {
+                       new_op = gen_binop(cmp, cmp_left, cmp_right, new_rd_ia32_Xor, 1);
+               }
+
+               return new_op;
+       }
+       /* TODO:
+        * (a == b) -> !(a ^ b)
+        * (a < 0)  -> (a & 0x80000000)
+        * (a <= 0) -> !(a & 0x7fffffff)
+        * (a > 0)  -> (a & 0x7fffffff)
+        * (a >= 0) -> !(a & 0x80000000)
+        */
+
+       if(!mode_is_signed(cmp_mode)) {
+               pnc |= ia32_pn_Cmp_Unsigned;
+       }
+
+       new_cmp_right = try_create_Immediate(cmp_right, 0);
+       if(new_cmp_right == NULL) {
+               new_cmp_right = try_create_Immediate(cmp_left, 0);
+               if(new_cmp_left != NULL) {
+                       pnc = get_inversed_pnc(pnc);
+                       new_cmp_left = be_transform_node(cmp_right);
+               }
+       } else {
+               new_cmp_left = be_transform_node(cmp_left);
+       }
+       if(new_cmp_right == NULL) {
+               new_cmp_left = be_transform_node(cmp_left);
+               new_cmp_right = be_transform_node(cmp_right);
+       }
+
+       new_op = new_rd_ia32_CmpSet(dbgi, irg, block, noreg, noreg, new_cmp_left,
+                                   new_cmp_right, nomem, pnc);
+       SET_IA32_ORIG_NODE(new_op, ia32_get_old_node_name(env_cg, cmp));
+
+       return new_op;
+}
+
 static ir_node *gen_Proj(ir_node *node) {
        ir_graph *irg  = current_ir_graph;
        dbg_info *dbgi = get_irn_dbg_info(node);
@@ -4107,6 +4236,8 @@ static ir_node *gen_Proj(ir_node *node) {
                return gen_Proj_be_AddSP(node);
        } else if (be_is_Call(pred)) {
                return gen_Proj_be_Call(node);
+       } else if (is_Cmp(pred)) {
+               return gen_Proj_Cmp(node);
        } else if (get_irn_op(pred) == op_Start) {
                if (proj == pn_Start_X_initial_exec) {
                        ir_node *block = get_nodes_block(pred);
@@ -4280,149 +4411,6 @@ void ia32_transform_graph(ia32_code_gen_t *cg) {
        be_transform_graph(cg->birg, ia32_pretransform_node, cg);
 }
 
-/**
- * Transforms a psi condition.
- */
-static void transform_psi_cond(ir_node *cond, ir_mode *mode, ia32_code_gen_t *cg) {
-       int i;
-
-       /* if the mode is target mode, we have already seen this part of the tree */
-       if (get_irn_mode(cond) == mode)
-               return;
-
-       assert(get_irn_mode(cond) == mode_b && "logical operator for condition must be mode_b");
-
-       set_irn_mode(cond, mode);
-
-       for (i = get_irn_arity(cond) - 1; i >= 0; i--) {
-               ir_node *in = get_irn_n(cond, i);
-
-               /* if in is a compare: transform into Set/xCmp */
-               if (is_Proj(in)) {
-                       ir_node  *new_op = NULL;
-                       ir_node  *cmp    = get_Proj_pred(in);
-                       ir_node  *cmp_a  = get_Cmp_left(cmp);
-                       ir_node  *cmp_b  = get_Cmp_right(cmp);
-                       dbg_info *dbgi   = get_irn_dbg_info(cmp);
-                       ir_graph *irg    = get_irn_irg(cmp);
-                       ir_node  *block  = get_nodes_block(cmp);
-                       ir_node  *noreg  = ia32_new_NoReg_gp(cg);
-                       ir_node  *nomem  = new_rd_NoMem(irg);
-                       int      pnc     = get_Proj_proj(in);
-
-                       /* this is a compare */
-                       if (mode_is_float(mode)) {
-                               /* Psi is float, we need a floating point compare */
-
-                               if (USE_SSE2(cg)) {
-                                       ir_mode *m = get_irn_mode(cmp_a);
-                                       /* SSE FPU */
-                                       if (! mode_is_float(m)) {
-                                               cmp_a = gen_sse_conv_int2float(cg, dbgi, irg, block, cmp_a, cmp_a, mode);
-                                               cmp_b = gen_sse_conv_int2float(cg, dbgi, irg, block, cmp_b, cmp_b, mode);
-                                       } else if (m == mode_F) {
-                                               /* we convert cmp values always to double, to get correct bitmask with cmpsd */
-                                               cmp_a = gen_sse_conv_f2d(cg, dbgi, irg, block, cmp_a, cmp_a);
-                                               cmp_b = gen_sse_conv_f2d(cg, dbgi, irg, block, cmp_b, cmp_b);
-                                       }
-
-                                       new_op = new_rd_ia32_xCmp(dbgi, irg, block, noreg, noreg, cmp_a, cmp_b, nomem);
-                                       set_ia32_pncode(new_op, pnc);
-                                       SET_IA32_ORIG_NODE(new_op, ia32_get_old_node_name(cg, cmp));
-                               } else {
-                                       /* x87 FPU */
-                                       assert(0);
-                               }
-                       } else {
-                               /* integer Psi */
-                               construct_binop_func *set_func  = NULL;
-
-                               if (mode_is_float(get_irn_mode(cmp_a))) {
-                                       /* 1st case: compare operands are floats */
-                                       FP_USED(cg);
-
-                                       if (USE_SSE2(cg)) {
-                                               /* SSE FPU */
-                                               set_func  = new_rd_ia32_xCmpSet;
-                                       } else {
-                                               /* x87 FPU */
-                                               set_func  = new_rd_ia32_vfCmpSet;
-                                       }
-
-                                       pnc &= 7; /* fp compare -> int compare */
-                               } else {
-                                       /* 2nd case: compare operand are integer too */
-                                       set_func  = new_rd_ia32_CmpSet;
-                               }
-
-                               new_op = set_func(dbgi, irg, block, noreg, noreg, cmp_a, cmp_b, nomem);
-                               if (! mode_is_signed(mode))
-                                       pnc |= ia32_pn_Cmp_Unsigned;
-
-                               set_ia32_pncode(new_op, pnc);
-                               set_ia32_am_support(new_op, ia32_am_Source);
-                       }
-
-                       /* the the new compare as in */
-                       set_irn_n(cond, i, new_op);
-               } else {
-                       /* another complex condition */
-                       transform_psi_cond(in, mode, cg);
-               }
-       }
-}
-
-/**
- * The Psi selector can be a tree of compares combined with "And"s and "Or"s.
- * We create a Set node, respectively a xCmp in case the Psi is a float, for
- * each compare, which causes the compare result to be stored in a register. The
- * "And"s and "Or"s are transformed later, we just have to set their mode right.
- */
-void ia32_transform_psi_cond_tree(ir_node *node, void *env) {
-       ia32_code_gen_t *cg = env;
-       ir_node         *psi_sel, *new_cmp, *block;
-       ir_graph        *irg;
-       ir_mode         *mode;
-
-       /* check for Psi */
-       if (get_irn_opcode(node) != iro_Psi)
-               return;
-
-       psi_sel = get_Psi_cond(node, 0);
-
-       /* if psi_cond is a cmp: do nothing, this case is covered by gen_Psi */
-       if (is_Proj(psi_sel)) {
-               assert(is_Cmp(get_Proj_pred(psi_sel)));
-               return;
-       }
-
-       //mode = get_irn_mode(node);
-       // TODO probably wrong...
-       mode = mode_Iu;
-
-       transform_psi_cond(psi_sel, mode, cg);
-
-       irg   = get_irn_irg(node);
-       block = get_nodes_block(node);
-
-       /* we need to compare the evaluated condition tree with 0 */
-       mode = get_irn_mode(node);
-       if (mode_is_float(mode)) {
-               /* BEWARE: new_r_Const_long works for floating point as well */
-               ir_node *zero = new_r_Const_long(irg, block, mode, 0);
-
-               psi_sel = gen_sse_conv_int2float(cg, NULL, irg, block, psi_sel, NULL, mode);
-               new_cmp = new_r_Cmp(irg, block, psi_sel, zero);
-               new_cmp = new_r_Proj(irg, block, new_cmp, mode_b, pn_Cmp_Ne);
-       } else {
-               ir_node *zero = new_r_Const_long(irg, block, mode_Iu, 0);
-               new_cmp = new_r_Cmp(irg, block, psi_sel, zero);
-               new_cmp = new_r_Proj(irg, block, new_cmp, mode_b, pn_Cmp_Gt | pn_Cmp_Lt);
-       }
-
-       set_Psi_cond(node, 0, new_cmp);
-}
-
 void ia32_init_transform(void)
 {
        FIRM_DBG_REGISTER(dbg, "firm.be.ia32.transform");
index afb839a..ecf1ba3 100644 (file)
  */
 void ia32_transform_graph(ia32_code_gen_t *cg);
 
-/**
- * The Psi selector can be a tree of compares combined with "And"s and "Or"s.
- * We create a Set node, respectively a xCmp in case the Psi is a float, for each
- * compare, which causes the compare result to be stores in a register.  The
- * "And"s and "Or"s are transformed later, we only adjust their mode.
- */
-void ia32_transform_psi_cond_tree(ir_node *node, void *env);
-
 #ifndef NDEBUG
 /**
  * Prints the old node name on cg obst and returns a pointer to it.