From: Matthias Braun Date: Tue, 27 Jul 2010 17:57:58 +0000 (+0000) Subject: implement floatingpoint compares X-Git-Url: http://nsz.repo.hu/git/?a=commitdiff_plain;h=1725b8d0b77469e08c106f25c84060fd7efc1c88;p=libfirm implement floatingpoint compares [r27827] --- diff --git a/ir/be/be_types.h b/ir/be/be_types.h index 32a7cff25..c6fa565ba 100644 --- a/ir/be/be_types.h +++ b/ir/be/be_types.h @@ -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; diff --git a/ir/be/scripts/generate_new_opcodes.pl b/ir/be/scripts/generate_new_opcodes.pl index 4e35413fe..8a932f680 100755 --- a/ir/be/scripts/generate_new_opcodes.pl +++ b/ir/be/scripts/generate_new_opcodes.pl @@ -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"; } diff --git a/ir/be/sparc/bearch_sparc.c b/ir/be/sparc/bearch_sparc.c index e7c954e88..5e2e1a93c 100644 --- a/ir/be/sparc/bearch_sparc.c +++ b/ir/be/sparc/bearch_sparc.c @@ -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); } /** diff --git a/ir/be/sparc/sparc_emitter.c b/ir/be/sparc/sparc_emitter.c index 2863ba04a..4b751aef3 100644 --- a/ir/be/sparc/sparc_emitter.c +++ b/ir/be/sparc/sparc_emitter.c @@ -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); diff --git a/ir/be/sparc/sparc_new_nodes.c b/ir/be/sparc/sparc_new_nodes.c index 354bf7596..eb5d9e4bf 100644 --- a/ir/be/sparc/sparc_new_nodes.c +++ b/ir/be/sparc/sparc_new_nodes.c @@ -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) diff --git a/ir/be/sparc/sparc_nodes_attr.h b/ir/be/sparc/sparc_nodes_attr.h index b7f4aa45d..8cb690f06 100644 --- a/ir/be/sparc/sparc_nodes_attr.h +++ b/ir/be/sparc/sparc_nodes_attr.h @@ -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; }; diff --git a/ir/be/sparc/sparc_spec.pl b/ir/be/sparc/sparc_spec.pl index 6733e6dba..af685815a 100644 --- a/ir/be/sparc/sparc_spec.pl +++ b/ir/be/sparc/sparc_spec.pl @@ -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" ], diff --git a/ir/be/sparc/sparc_transform.c b/ir/be/sparc/sparc_transform.c index c289ac771..ad7a7296d 100644 --- a/ir/be/sparc/sparc_transform.c +++ b/ir/be/sparc/sparc_transform.c @@ -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);