Commit 1725b8d0 authored by Matthias Braun's avatar Matthias Braun
Browse files

implement floatingpoint compares

[r27827]
parent 035c482f
......@@ -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;
......
......@@ -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";
}
......
......@@ -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);
}
/**
......
......@@ -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);
......
......@@ -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)
......
......@@ -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;
};
......
......@@ -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" ],
......
......@@ -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);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment