implement floatingpoint compares
authorMatthias Braun <matze@braunis.de>
Tue, 27 Jul 2010 17:57:58 +0000 (17:57 +0000)
committerMatthias Braun <matze@braunis.de>
Tue, 27 Jul 2010 17:57:58 +0000 (17:57 +0000)
[r27827]

ir/be/be_types.h
ir/be/scripts/generate_new_opcodes.pl
ir/be/sparc/bearch_sparc.c
ir/be/sparc/sparc_emitter.c
ir/be/sparc/sparc_new_nodes.c
ir/be/sparc/sparc_nodes_attr.h
ir/be/sparc/sparc_spec.pl
ir/be/sparc/sparc_transform.c

index 32a7cff..c6fa565 100644 (file)
@@ -45,8 +45,13 @@ typedef enum arch_irn_flags_t {
        arch_irn_flags_none             = 0,       /**< Node flags. */
        arch_irn_flags_dont_spill       = 1U << 0, /**< This must not be spilled. */
        arch_irn_flags_rematerializable = 1U << 1, /**< This can be replicated instead of spilled/reloaded. */
-       arch_irn_flags_modify_flags     = 1U << 2, /**< I modify flags. */
+       arch_irn_flags_modify_flags     = 1U << 2, /**< I modify flags, used by the
+                                                       default check_modifies
+                                                       implementation in beflags */
        arch_irn_flags_simple_jump      = 1U << 3, /**< a simple jump instruction */
+
+       arch_irn_flags_backend          = 1U << 4, /**< begin of custom backend
+                                                       flags */
 } arch_irn_flags_t;
 
 typedef struct _be_lv_t                  be_lv_t;
index 4e35413..8a932f6 100755 (executable)
@@ -48,6 +48,7 @@ our $custom_init_attr_func;
 our %compare_attr;
 our %copy_attr;
 our %reg_classes;
+our %custom_irn_flags;
 
 # include spec file
 
@@ -409,15 +410,22 @@ EOF
        # set flags
        if (exists($n->{"irn_flags"})) {
                $temp .= "\t/* flags */\n";
-               my %known_irn_flags = map { $_ => 1 } (
-                       "none", "dont_spill", "rematerializable",
-                       "modify_flags", "simple_jump"
+               my %known_irn_flags = (
+                       "none"             => "arch_irn_flags_none",
+                       "dont_spill"       => "arch_irn_flags_dont_spill",
+                       "rematerializable" => "arch_irn_flags_rematerializable",
+                       "modify_flags"     => "arch_irn_flags_modify_flags",
+                       "simple_jump"      => "arch_irn_flags_simple_jump",
                );
+               if (defined(%custom_irn_flags)) {
+                       %known_irn_flags = (%known_irn_flags, %custom_irn_flags);
+               }
                foreach my $flag (@{$n->{"irn_flags"}}) {
                        if (not defined($known_irn_flags{$flag})) {
                                print STDERR "WARNING: irn_flag '$flag' in opcode $op is unknown\n";
+                       } else {
+                               $temp .= "\tflags |= " . $known_irn_flags{$flag} . ";\n";
                        }
-                       $temp .= "\tflags |= arch_irn_flags_$flag;\n";
                }
                $temp .= "\n";
        }
index e7c954e..5e2e1a9 100644 (file)
@@ -151,12 +151,24 @@ static void sparc_prepare_graph(void *self)
                dump_ir_graph(cg->irg, "transformed");
 }
 
+static bool sparc_modifies_flags(const ir_node *node)
+{
+       return arch_irn_get_flags(node) & sparc_arch_irn_flag_modifies_flags;
+}
+
+static bool sparc_modifies_fp_flags(const ir_node *node)
+{
+       return arch_irn_get_flags(node) & sparc_arch_irn_flag_modifies_fp_flags;
+}
+
 static void sparc_before_ra(void *self)
 {
        sparc_code_gen_t *cg = self;
        /* fixup flags register */
        be_sched_fix_flags(cg->irg, &sparc_reg_classes[CLASS_sparc_flags_class],
-                          NULL, NULL);
+                          NULL, sparc_modifies_flags);
+       be_sched_fix_flags(cg->irg, &sparc_reg_classes[CLASS_sparc_fpflags_class],
+                          NULL, sparc_modifies_fp_flags);
 }
 
 /**
index 2863ba0..4b751ae 100644 (file)
@@ -576,21 +576,75 @@ static void emit_sparc_FrameAddr(const ir_node *irn)
        be_emit_finish_line_gas(irn);
 }
 
+static const char *get_icc_unsigned(pn_Cmp pnc)
+{
+       switch (pnc) {
+       case pn_Cmp_False: return "bn";
+       case pn_Cmp_Eq:    return "be";
+       case pn_Cmp_Lt:    return "blu";
+       case pn_Cmp_Le:    return "bleu";
+       case pn_Cmp_Gt:    return "bgu";
+       case pn_Cmp_Ge:    return "bgeu";
+       case pn_Cmp_Lg:    return "bne";
+       case pn_Cmp_Leg:   return "ba";
+       default: panic("Cmp has unsupported pnc");
+       }
+}
+
+static const char *get_icc_signed(pn_Cmp pnc)
+{
+       switch (pnc) {
+       case pn_Cmp_False: return "bn";
+       case pn_Cmp_Eq:    return "be";
+       case pn_Cmp_Lt:    return "bl";
+       case pn_Cmp_Le:    return "ble";
+       case pn_Cmp_Gt:    return "bg";
+       case pn_Cmp_Ge:    return "bge";
+       case pn_Cmp_Lg:    return "bne";
+       case pn_Cmp_Leg:   return "ba";
+       default: panic("Cmp has unsupported pnc");
+       }
+}
+
+static const char *get_fcc(pn_Cmp pnc)
+{
+       switch (pnc) {
+       case pn_Cmp_False: return "fbn";
+       case pn_Cmp_Eq:    return "fbe";
+       case pn_Cmp_Lt:    return "fbl";
+       case pn_Cmp_Le:    return "fble";
+       case pn_Cmp_Gt:    return "fbg";
+       case pn_Cmp_Ge:    return "fbge";
+       case pn_Cmp_Lg:    return "fblg";
+       case pn_Cmp_Leg:   return "fbo";
+       case pn_Cmp_Uo:    return "fbu";
+       case pn_Cmp_Ue:    return "fbue";
+       case pn_Cmp_Ul:    return "fbul";
+       case pn_Cmp_Ule:   return "fbule";
+       case pn_Cmp_Ug:    return "fbug";
+       case pn_Cmp_Uge:   return "fbuge";
+       case pn_Cmp_Ne:    return "fbne";
+       case pn_Cmp_True:  return "fba";
+       case pn_Cmp_max:
+               break;
+       }
+       panic("invalid pnc");
+}
+
+typedef const char* (*get_cc_func)(pn_Cmp pnc);
 
 /**
  * Emits code for Branch
  */
-static void emit_sparc_BXX(const ir_node *node)
+static void emit_sparc_branch(const ir_node *node, get_cc_func get_cc)
 {
        const sparc_jmp_cond_attr_t *attr = get_sparc_jmp_cond_attr_const(node);
-       int              proj_num    = attr->proj_num;
-       bool             is_unsigned = attr->is_unsigned;
+       pn_Cmp           pnc         = attr->pnc;
        const ir_node   *proj_true   = NULL;
        const ir_node   *proj_false  = NULL;
        const ir_edge_t *edge;
        const ir_node   *block;
        const ir_node   *next_block;
-       const char      *suffix;
 
        foreach_out_edge(node, edge) {
                ir_node *proj = get_edge_src_irn(edge);
@@ -608,43 +662,22 @@ static void emit_sparc_BXX(const ir_node *node)
        /* we have a block schedule */
        next_block = get_irn_link(block);
 
-       assert(proj_num != pn_Cmp_False);
-       assert(proj_num != pn_Cmp_True);
-
        if (get_irn_link(proj_true) == next_block) {
                /* exchange both proj's so the second one can be omitted */
                const ir_node *t = proj_true;
 
                proj_true  = proj_false;
                proj_false = t;
-               proj_num   = get_negated_pnc(proj_num, mode_Iu);
-       }
-
-       if (is_unsigned) {
-               switch (proj_num) {
-                       case pn_Cmp_Eq:  suffix = "e"; break;
-                       case pn_Cmp_Lt:  suffix = "lu"; break;
-                       case pn_Cmp_Le:  suffix = "leu"; break;
-                       case pn_Cmp_Gt:  suffix = "gu"; break;
-                       case pn_Cmp_Ge:  suffix = "geu"; break;
-                       case pn_Cmp_Lg:  suffix = "ne"; break;
-                       default: panic("Cmp has unsupported pnc");
-               }
-       } else {
-               switch (proj_num) {
-                       case pn_Cmp_Eq:  suffix = "e"; break;
-                       case pn_Cmp_Lt:  suffix = "l"; break;
-                       case pn_Cmp_Le:  suffix = "le"; break;
-                       case pn_Cmp_Gt:  suffix = "g"; break;
-                       case pn_Cmp_Ge:  suffix = "ge"; break;
-                       case pn_Cmp_Lg:  suffix = "ne"; break;
-                       default: panic("Cmp has unsupported pnc");
+               if (is_sparc_fbfcc(node)) {
+                       pnc = get_negated_pnc(pnc, mode_F);
+               } else {
+                       pnc = get_negated_pnc(pnc, mode_Iu);
                }
        }
 
        /* emit the true proj */
-       be_emit_cstring("\tb");
-       be_emit_string(suffix);
+       be_emit_cstring("\t");
+       be_emit_string(get_cc(pnc));
        be_emit_char(' ');
        sparc_emit_cfop_target(proj_true);
        be_emit_finish_line_gas(proj_true);
@@ -654,7 +687,7 @@ static void emit_sparc_BXX(const ir_node *node)
        be_emit_cstring("/* TODO: use delay slot */\n");
 
        if (get_irn_link(proj_false) == next_block) {
-               be_emit_cstring("\t/* false-fallthrough to ");
+               be_emit_cstring("\t/* fallthrough to ");
                sparc_emit_cfop_target(proj_false);
                be_emit_cstring(" */");
                be_emit_finish_line_gas(proj_false);
@@ -667,6 +700,18 @@ static void emit_sparc_BXX(const ir_node *node)
        }
 }
 
+static void emit_sparc_Bicc(const ir_node *node)
+{
+       const sparc_jmp_cond_attr_t *attr = get_sparc_jmp_cond_attr_const(node);
+       bool             is_unsigned = attr->is_unsigned;
+       emit_sparc_branch(node, is_unsigned ? get_icc_unsigned : get_icc_signed);
+}
+
+static void emit_sparc_fbfcc(const ir_node *node)
+{
+       emit_sparc_branch(node, get_fcc);
+}
+
 /**
  * emit Jmp (which actually is a branch always (ba) instruction)
  */
@@ -760,8 +805,9 @@ static void sparc_register_emitters(void)
        set_emitter(op_be_Perm,         emit_be_Perm);
        set_emitter(op_be_Return,       emit_be_Return);
        set_emitter(op_sparc_Ba,        emit_sparc_Ba);
-       set_emitter(op_sparc_BXX,       emit_sparc_BXX);
+       set_emitter(op_sparc_Bicc,      emit_sparc_Bicc);
        set_emitter(op_sparc_Call,      emit_sparc_Call);
+       set_emitter(op_sparc_fbfcc,     emit_sparc_fbfcc);
        set_emitter(op_sparc_FrameAddr, emit_sparc_FrameAddr);
        set_emitter(op_sparc_HiImm,     emit_sparc_HiImm);
        set_emitter(op_sparc_LoImm,     emit_sparc_LoImm);
index 354bf75..eb5d9e4 100644 (file)
@@ -58,7 +58,7 @@ static bool has_load_store_attr(const ir_node *node)
 
 static bool has_jmp_cond_attr(const ir_node *node)
 {
-       return is_sparc_BXX(node);
+       return is_sparc_Bicc(node) || is_sparc_fbfcc(node);
 }
 
 static bool has_jmp_switch_attr(const ir_node *node)
@@ -76,7 +76,7 @@ static bool has_fp_attr(const ir_node *node)
        return is_sparc_fadd(node) || is_sparc_fsub(node)
            || is_sparc_fmul(node) || is_sparc_fdiv(node)
            || is_sparc_fftoi(node) || is_sparc_fitof(node)
-           || is_sparc_fneg(node);
+           || is_sparc_fneg(node) || is_sparc_fcmp(node);
 }
 
 static bool has_fp_conv_attr(const ir_node *node)
@@ -123,8 +123,7 @@ static void sparc_dump_node(FILE *F, ir_node *n, dump_reason_t reason)
                if (has_jmp_cond_attr(n)) {
                        const sparc_jmp_cond_attr_t *attr
                                = get_sparc_jmp_cond_attr_const(n);
-                       fprintf(F, "pnc: %d (%s)\n", attr->proj_num,
-                               get_pnc_string(attr->proj_num));
+                       fprintf(F, "pnc: %d (%s)\n", attr->pnc, get_pnc_string(attr->pnc));
                        fprintf(F, "unsigned: %s\n", attr->is_unsigned ? "true" : "false");
                }
                if (has_jmp_switch_attr(n)) {
@@ -155,11 +154,10 @@ static void sparc_set_attr_imm(ir_node *res, int immediate_value)
        attr->immediate_value = immediate_value;
 }
 
-static void init_sparc_jmp_cond_attr(ir_node *node, int proj_num,
-                                     bool is_unsigned)
+static void init_sparc_jmp_cond_attr(ir_node *node, int pnc, bool is_unsigned)
 {
        sparc_jmp_cond_attr_t *attr = get_sparc_jmp_cond_attr(node);
-       attr->proj_num    = proj_num;
+       attr->pnc         = pnc;
        attr->is_unsigned = is_unsigned;
 }
 
@@ -448,8 +446,8 @@ static int cmp_attr_sparc_jmp_cond(ir_node *a, ir_node *b)
        if (cmp_attr_sparc(a, b))
                return 1;
 
-       return attr_a->proj_num != attr_b->proj_num
-               || attr_a->is_unsigned != attr_b->is_unsigned;
+       return attr_a->pnc != attr_b->pnc
+           || attr_a->is_unsigned != attr_b->is_unsigned;
 }
 
 static int cmp_attr_sparc_jmp_switch(ir_node *a, ir_node *b)
index b7f4aa4..8cb690f 100644 (file)
@@ -42,6 +42,11 @@ struct sparc_attr_t
        ir_entity                  *immediate_value_entity; /* hack for now */
 };
 
+enum sparc_arch_irn_flags_t {
+       sparc_arch_irn_flag_modifies_flags    = arch_irn_flags_backend << 0,
+       sparc_arch_irn_flag_modifies_fp_flags = arch_irn_flags_backend << 1,
+};
+
 /**
  * attribute for FP immediate instruction
  */
@@ -96,7 +101,7 @@ struct sparc_symconst_attr_t {
 typedef struct sparc_jmp_cond_attr_t sparc_jmp_cond_attr_t;
 struct sparc_jmp_cond_attr_t {
        sparc_attr_t base;    /**< generic attribute */
-       int          proj_num;
+       pn_Cmp       pnc;
        bool         is_unsigned : 1;
 };
 
index 6733e6d..af68581 100644 (file)
@@ -59,7 +59,7 @@ $state       = 32; # register represents a state
                { name => "i7", type => $ignore }, # return address - 8
                { mode => $mode_gp }
        ],
-       fp_flags => [
+       fpflags_class => [
                { name => "fpflags", type => $ignore },
                { mode => $mode_fpflags, flags => "manual_ra" }
        ],
@@ -166,6 +166,11 @@ $default_copy_attr = "sparc_copy_attr";
        sparc_fp_conv_attr_t    => "cmp_attr_sparc_fp_conv",
 );
 
+%custom_irn_flags = (
+       modifies_flags    => "sparc_arch_irn_flag_modifies_flags",
+       modifies_fp_flags => "sparc_arch_irn_flag_modifies_fp_flags",
+);
+
 # addressing modes: imm, reg, reg +/- imm, reg + reg
 # max. imm = 13 bits signed (-4096 ... 4096)
 
@@ -322,14 +327,24 @@ FrameAddr => {
        mode      => $mode_gp,
 },
 
-BXX => {
+Bicc => {
        op_flags  => [ "labeled", "cfopcode", "forking" ],
        state     => "pinned",
        mode      => "mode_T",
+       attr_type => "sparc_jmp_cond_attr_t",
+       attr      => "pn_Cmp pnc, bool is_unsigned",
+       init_attr => "\tinit_sparc_jmp_cond_attr(res, pnc, is_unsigned);",
        reg_req   => { in => [ "flags" ], out => [ "none", "none" ] },
-       attr      => "int proj_num, bool is_unsigned",
+},
+
+fbfcc => {
+       op_flags  => [ "labeled", "cfopcode", "forking" ],
+       state     => "pinned",
+       mode      => "mode_T",
        attr_type => "sparc_jmp_cond_attr_t",
-       init_attr => "\tinit_sparc_jmp_cond_attr(res, proj_num, is_unsigned);",
+       attr      => "pn_Cmp pnc",
+       init_attr => "\tinit_sparc_jmp_cond_attr(res, pnc, false);",
+       reg_req   => { in => [ "fpflags" ], out => [ "none", "none" ] },
 },
 
 Ba => {
@@ -341,7 +356,7 @@ Ba => {
 },
 
 Call => {
-       irn_flags => [ "modify_flags" ],
+       irn_flags => [ "modifies_flags", "modifies_fp_flags" ],
        state     => "exc_pinned",
        arity     => "variable",
        out_arity => "variable",
@@ -360,7 +375,7 @@ Call => {
 },
 
 Cmp => {
-       irn_flags    => [ "rematerializable", "modify_flags" ],
+       irn_flags    => [ "rematerializable", "modifies_flags" ],
        emit         => '. cmp %S1, %R2I',
        reg_req      => { in => [ "gp", "gp" ], out => [ "flags" ] },
        ins          => [ "left", "right" ],
@@ -369,7 +384,7 @@ Cmp => {
 },
 
 Tst => {
-       irn_flags    => [ "rematerializable", "modify_flags" ],
+       irn_flags    => [ "rematerializable", "modifies_flags" ],
        emit         => '. tst %S1',
        mode         => $mode_flags,
        reg_req      => { in => [ "gp" ], out => [ "flags" ] },
@@ -378,6 +393,7 @@ Tst => {
 
 SwitchJmp => {
        op_flags  => [ "labeled", "cfopcode", "forking" ],
+       irn_flags => [ "modifies_flags" ],
        state     => "pinned",
        mode      => "mode_T",
        attr      => "int n_projs, long def_proj_num",
@@ -438,7 +454,7 @@ Xor => {
 Mul => {
        reg_req   => { in => [ "gp", "gp" ], out => [ "gp", "y" ] },
        constructors => \%binop_operand_constructors,
-       emit      => '. mul %S1, %R2I, %D1',
+       emit      => '. smul %S1, %R2I, %D1',
        mode      => $mode_gp,
 },
 
@@ -490,6 +506,15 @@ Nop => {
        emit     => '. nop',
 },
 
+fcmp => {
+       irn_flags => [ "rematerializable", "modifies_fp_flags" ],
+       reg_req   => { in => [ "fp", "fp" ], out => [ "fpflags" ] },
+       emit      => '. fcmp%FPM %S1, %S2',
+       attr_type => "sparc_fp_attr_t",
+       attr      => "ir_mode *fp_mode",
+       mode      => $mode_fpflags,
+},
+
 fadd => {
        op_flags  => [ "commutative" ],
        irn_flags => [ "rematerializable" ],
index c289ac7..ad7a729 100644 (file)
@@ -713,7 +713,7 @@ static ir_node *gen_SwitchJmp(ir_node *node)
        return new_bd_sparc_SwitchJmp(dbgi, block, sub, n_projs, get_Cond_default_proj(node) - translation);
 }
 
-static bool is_cmp_unsigned(ir_node *b_value)
+static ir_mode *get_cmp_mode(ir_node *b_value)
 {
        ir_node *pred;
        ir_node *op;
@@ -724,7 +724,7 @@ static bool is_cmp_unsigned(ir_node *b_value)
        if (!is_Cmp(pred))
                panic("can't determine cond signednes (no cmp)");
        op = get_Cmp_left(pred);
-       return !mode_is_signed(get_irn_mode(op));
+       return get_irn_mode(op);
 }
 
 /**
@@ -734,6 +734,7 @@ static ir_node *gen_Cond(ir_node *node)
 {
        ir_node  *selector = get_Cond_selector(node);
        ir_mode  *mode     = get_irn_mode(selector);
+       ir_mode  *cmp_mode;
        ir_node  *block;
        ir_node  *flag_node;
        bool      is_unsigned;
@@ -749,12 +750,19 @@ static ir_node *gen_Cond(ir_node *node)
        assert(is_Proj(selector));
        assert(is_Cmp(get_Proj_pred(selector)));
 
+       cmp_mode = get_cmp_mode(selector);
+
        block       = be_transform_node(get_nodes_block(node));
        dbgi        = get_irn_dbg_info(node);
        flag_node   = be_transform_node(get_Proj_pred(selector));
        pnc         = get_Proj_proj(selector);
-       is_unsigned = is_cmp_unsigned(selector);
-       return new_bd_sparc_BXX(dbgi, block, flag_node, pnc, is_unsigned);
+       is_unsigned = !mode_is_signed(cmp_mode);
+       if (mode_is_float(cmp_mode)) {
+               assert(!is_unsigned);
+               return new_bd_sparc_fbfcc(dbgi, block, flag_node, pnc);
+       } else {
+               return new_bd_sparc_Bicc(dbgi, block, flag_node, pnc, is_unsigned);
+       }
 }
 
 /**
@@ -769,27 +777,11 @@ static ir_node *gen_Cmp(ir_node *node)
        dbg_info *dbgi     = get_irn_dbg_info(node);
        ir_node  *new_op1  = be_transform_node(op1);
        ir_node  *new_op2  = be_transform_node(op2);
-
-       if (mode_is_float(cmp_mode)) {
-               panic("FloatCmp not implemented");
-       }
-
        assert(get_irn_mode(op2) == cmp_mode);
 
-#if 0
-       /* compare with 0 can be done with Tst */
-       if (is_Const(op2) && tarval_is_null(get_Const_tarval(op2))) {
-               new_op1 = be_transform_node(op1);
-               return new_bd_sparc_Tst(dbgi, block, new_op1, false,
-                                         is_unsigned);
-       }
-
-       if (is_Const(op1) && tarval_is_null(get_Const_tarval(op1))) {
-               new_op2 = be_transform_node(op2);
-               return new_bd_sparc_Tst(dbgi, block, new_op2, true,
-                                         is_unsigned);
+       if (mode_is_float(cmp_mode)) {
+               return new_bd_sparc_fcmp(dbgi, block, new_op1, new_op2, cmp_mode);
        }
-#endif
 
        /* integer compare */
        new_op1 = gen_extension(dbgi, block, new_op1, cmp_mode);