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;
our %compare_attr;
our %copy_attr;
our %reg_classes;
+our %custom_irn_flags;
# include spec file
# 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";
}
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);
}
/**
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);
/* 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);
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);
}
}
+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)
*/
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);
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)
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)
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)) {
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;
}
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)
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
*/
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;
};
{ name => "i7", type => $ignore }, # return address - 8
{ mode => $mode_gp }
],
- fp_flags => [
+ fpflags_class => [
{ name => "fpflags", type => $ignore },
{ mode => $mode_fpflags, flags => "manual_ra" }
],
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)
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 => {
},
Call => {
- irn_flags => [ "modify_flags" ],
+ irn_flags => [ "modifies_flags", "modifies_fp_flags" ],
state => "exc_pinned",
arity => "variable",
out_arity => "variable",
},
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" ],
},
Tst => {
- irn_flags => [ "rematerializable", "modify_flags" ],
+ irn_flags => [ "rematerializable", "modifies_flags" ],
emit => '. tst %S1',
mode => $mode_flags,
reg_req => { in => [ "gp" ], out => [ "flags" ] },
SwitchJmp => {
op_flags => [ "labeled", "cfopcode", "forking" ],
+ irn_flags => [ "modifies_flags" ],
state => "pinned",
mode => "mode_T",
attr => "int n_projs, long def_proj_num",
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,
},
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" ],
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;
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);
}
/**
{
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;
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);
+ }
}
/**
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);