Commit 86c66a17 authored by Matthias Braun's avatar Matthias Braun
Browse files

- allow_ifconv interface was totally braindamaged. Use a simple and intuitive

  interface now.
- Fix several bugs in the ia32 version of it
- Unfortunately this leads to the obscure Doz construct being always created
  (instead of only when cmovs are allowed) and firm generates broken code
  for that (testcase coming in 5 minutes)

[r26985]
parent 51d50900
......@@ -227,16 +227,18 @@ void do_gvn_pre(ir_graph *irg);
ir_graph_pass_t *do_gvn_pre_pass(const char *name);
/**
* This function is called to evaluate, if a mux can build
* of the current architecture.
* This function is called to evaluate, if a
* mux(@p sel, @p mux_false, @p mux_true) should be built for the current
* architecture.
* If it returns non-zero, a mux is created, else the code
* is not modified.
* @param sel A selector of a Cond.
* @param phi_list List of Phi nodes about to be converted (linked via get_Phi_next() field)
* @param phi_list phi node to be converted
* @param i First data predecessor involved in if conversion
* @param j Second data predecessor involved in if conversion
*/
typedef int (*arch_allow_ifconv_func)(ir_node *sel, ir_node* phi_list, int i, int j);
typedef int (*arch_allow_ifconv_func)(ir_node *sel, ir_node *mux_false,
ir_node *mux_true);
/**
* The parameters structure.
......
......@@ -1061,41 +1061,14 @@ static ir_graph **arm_get_irg_list(const void *self, ir_graph ***irg_list) {
* Allows or disallows the creation of Psi nodes for the given Phi nodes.
* @return 1 if allowed, 0 otherwise
*/
static int arm_is_psi_allowed(ir_node *sel, ir_node *phi_list, int i, int j) {
ir_node *cmp, *cmp_a, *phi;
ir_mode *mode;
static int arm_is_mux_allowed(ir_node *sel, ir_node *mux_false,
ir_node *mux_true)
{
(void) sel;
(void) mux_false;
(void) mux_true;
/* currently Psi support is not implemented */
return 0;
/* we don't want long long Psi */
#define IS_BAD_PSI_MODE(mode) (!mode_is_float(mode) && get_mode_size_bits(mode) > 32)
if (get_irn_mode(sel) != mode_b)
return 0;
cmp = get_Proj_pred(sel);
cmp_a = get_Cmp_left(cmp);
mode = get_irn_mode(cmp_a);
if (IS_BAD_PSI_MODE(mode))
return 0;
/* check the Phi nodes */
for (phi = phi_list; phi; phi = get_irn_link(phi)) {
ir_node *pred_i = get_irn_n(phi, i);
ir_node *pred_j = get_irn_n(phi, j);
ir_mode *mode_i = get_irn_mode(pred_i);
ir_mode *mode_j = get_irn_mode(pred_j);
if (IS_BAD_PSI_MODE(mode_i) || IS_BAD_PSI_MODE(mode_j))
return 0;
}
#undef IS_BAD_PSI_MODE
return 1;
}
static asm_constraint_flags_t arm_parse_asm_constraint(const char **c)
......@@ -1117,7 +1090,7 @@ static int arm_is_valid_clobber(const char *clobber)
static const backend_params *arm_get_libfirm_params(void) {
static const ir_settings_if_conv_t ifconv = {
4, /* maxdepth, doesn't matter for Psi-conversion */
arm_is_psi_allowed /* allows or disallows Psi creation for given selector */
arm_is_mux_allowed /* allows or disallows Mux creation for given selector */
};
static ir_settings_arch_dep_t ad = {
1, /* allow subs */
......
......@@ -50,6 +50,7 @@
#include "irtools.h"
#include "iroptimize.h"
#include "instrument.h"
#include "iropt_t.h"
#include "../beabi.h"
#include "../beirg.h"
......@@ -2130,264 +2131,238 @@ static void ia32_mark_remat(ir_node *node)
}
/**
* Check for Abs or -Abs.
* Check if Mux(sel, t, f) would represent an Abs (or -Abs).
*/
static int psi_is_Abs_or_Nabs(ir_node *cmp, ir_node *sel, ir_node *t, ir_node *f)
static bool mux_is_abs(ir_node *sel, ir_node *mux_true, ir_node *mux_false)
{
ir_node *l, *r;
ir_node *cmp_left;
ir_node *cmp_right;
ir_node *cmp;
pn_Cmp pnc;
if (cmp == NULL)
return 0;
if (!is_Proj(sel))
return false;
cmp = get_Proj_pred(sel);
if (!is_Cmp(cmp))
return false;
/* must be <, <=, >=, > */
pnc = get_Proj_proj(sel);
if (pnc != pn_Cmp_Ge && pnc != pn_Cmp_Gt &&
pnc != pn_Cmp_Le && pnc != pn_Cmp_Lt)
return 0;
switch (pnc) {
case pn_Cmp_Ge:
case pn_Cmp_Gt:
case pn_Cmp_Le:
case pn_Cmp_Lt:
case pn_Cmp_Uge:
case pn_Cmp_Ug:
case pn_Cmp_Ul:
case pn_Cmp_Ule:
break;
default:
return false;
}
l = get_Cmp_left(cmp);
r = get_Cmp_right(cmp);
if (!is_negated_value(mux_true, mux_false))
return false;
/* must be x cmp 0 */
if ((l != t && l != f) || !is_Const(r) || !is_Const_null(r))
cmp_right = get_Cmp_right(cmp);
if (!is_Const(cmp_right) || !is_Const_null(cmp_right))
return 0;
if ((!is_Minus(t) || get_Minus_op(t) != f) &&
(!is_Minus(f) || get_Minus_op(f) != t))
return 0;
return 1;
cmp_left = get_Cmp_left(cmp);
if (cmp_left != mux_true && cmp_left != mux_false)
return false;
return true;
}
/**
* Check for Abs only
* Check if Mux(sel, mux_true, mux_false) would represent a Max or Min operation
*/
static int psi_is_Abs(ir_node *cmp, ir_node *sel, ir_node *t, ir_node *f)
static bool mux_is_float_min_max(ir_node *sel, ir_node *mux_true, ir_node *mux_false)
{
ir_node *l, *r;
ir_node *cmp_l;
ir_node *cmp_r;
ir_node *cmp;
pn_Cmp pnc;
if (cmp == NULL)
return 0;
/* must be <, <=, >=, > */
if (!is_Proj(sel))
return false;
cmp = get_Proj_pred(sel);
if (!is_Cmp(cmp))
return false;
cmp_l = get_Cmp_left(cmp);
cmp_r = get_Cmp_right(cmp);
if (!mode_is_float(get_irn_mode(cmp_l)))
return false;
/* check for min/max. They're defined as (C-Semantik):
* min(a, b) = a < b ? a : b
* or min(a, b) = a <= b ? a : b
* max(a, b) = a > b ? a : b
* or max(a, b) = a >= b ? a : b
* (Note we only handle float min/max here)
*/
pnc = get_Proj_proj(sel);
if (pnc != pn_Cmp_Ge && pnc != pn_Cmp_Gt &&
pnc != pn_Cmp_Le && pnc != pn_Cmp_Lt)
return 0;
switch (pnc) {
case pn_Cmp_Ge:
case pn_Cmp_Gt:
/* this is a max */
if (cmp_l == mux_true && cmp_r == mux_false)
return true;
break;
case pn_Cmp_Le:
case pn_Cmp_Lt:
/* this is a min */
if (cmp_l == mux_true && cmp_r == mux_false)
return true;
break;
case pn_Cmp_Uge:
case pn_Cmp_Ug:
/* this is a min */
if (cmp_l == mux_false && cmp_r == mux_true)
return true;
break;
case pn_Cmp_Ule:
case pn_Cmp_Ul:
/* this is a max */
if (cmp_l == mux_false && cmp_r == mux_true)
return true;
break;
l = get_Cmp_left(cmp);
r = get_Cmp_right(cmp);
default:
break;
}
/* must be x cmp 0 */
if ((l != t && l != f) || !is_Const(r) || !is_Const_null(r))
return 0;
return false;
}
if ((!is_Minus(t) || get_Minus_op(t) != f) &&
(!is_Minus(f) || get_Minus_op(f) != t))
return 0;
static bool mux_is_set(ir_node *sel, ir_node *mux_true, ir_node *mux_false)
{
(void) sel;
ir_mode *mode = get_irn_mode(mux_true);
if (pnc & pn_Cmp_Gt) {
/* x >= 0 ? -x : x is NABS */
if (is_Minus(t))
return 0;
} else {
/* x < 0 ? x : -x is NABS */
if (is_Minus(f))
return 0;
if (!mode_is_int(mode) && !mode_is_reference(mode))
return false;
if (is_Const(mux_true) && is_Const_one(mux_true)
&& is_Const(mux_false) && is_Const_null(mux_false)) {
return true;
}
return 1;
if (is_Const(mux_false) && is_Const_null(mux_false)
&& is_Const(mux_true) && is_Const_one(mux_true)) {
return true;
}
return false;
}
static bool mux_is_float_const_const(ir_node *sel, ir_node *mux_true, ir_node *mux_false)
{
(void) sel;
/**
* Allows or disallows the creation of Mux nodes for the given Phi nodes.
*
* @param sel A selector of a Cond.
* @param phi_list List of Phi nodes about to be converted (linked via get_Phi_next() field)
* @param i First data predecessor involved in if conversion
* @param j Second data predecessor involved in if conversion
*
* @return 1 if allowed, 0 otherwise
*/
static int ia32_is_mux_allowed(ir_node *sel, ir_node *phi_list, int i, int j)
if (!mode_is_float(get_irn_mode(mux_true)))
return false;
return is_Const(mux_true) && is_Const(mux_false);
}
static bool mux_is_doz(ir_node *sel, ir_node *mux_true, ir_node *mux_false)
{
ir_node *phi;
ir_node *cmp;
pn_Cmp pn;
ir_node *cl, *cr;
/* we can't handle Muxs with 64bit compares yet */
if (is_Proj(sel)) {
cmp = get_Proj_pred(sel);
if (is_Cmp(cmp)) {
ir_node *left = get_Cmp_left(cmp);
ir_mode *cmp_mode = get_irn_mode(left);
if (!mode_is_float(cmp_mode) && get_mode_size_bits(cmp_mode) > 32) {
/* 64bit Abs IS supported */
for (phi = phi_list; phi; phi = get_Phi_next(phi)) {
ir_node *t = get_Phi_pred(phi, i);
ir_node *f = get_Phi_pred(phi, j);
if (! psi_is_Abs(cmp, sel, t, f))
return 0;
}
return 1;
}
} else {
/* we do not support nodes without Cmp yet */
return 0;
}
} else {
/* we do not support nodes without Cmp yet */
return 0;
ir_node *cmp_left;
ir_node *cmp_right;
ir_mode *mode;
long pn;
if (!is_Proj(sel))
return false;
cmp = get_Proj_pred(sel);
if (!is_Cmp(cmp))
return false;
cmp_left = get_Cmp_left(cmp);
cmp_right = get_Cmp_right(cmp);
mode = get_irn_mode(mux_true);
pn = get_Proj_proj(sel);
if ((pn & pn_Cmp_Gt) && !mode_is_signed(mode) &&
is_Const(mux_false) && is_Const_null(mux_false) && is_Sub(mux_true) &&
get_Sub_left(mux_true) == cmp_left &&
get_Sub_right(mux_true) == cmp_right) {
/* Mux(a >=u b, a - b, 0) unsigned Doz */
return true;
}
if ((pn & pn_Cmp_Lt) && !mode_is_signed(mode) &&
is_Const(mux_true) && is_Const_null(mux_true) && is_Sub(mux_false) &&
get_Sub_left(mux_false) == cmp_left &&
get_Sub_right(mux_false) == cmp_right) {
/* Mux(a <=u b, 0, a - b) unsigned Doz */
return true;
}
pn = get_Proj_proj(sel);
cl = get_Cmp_left(cmp);
cr = get_Cmp_right(cmp);
if (ia32_cg_config.use_cmov) {
if (ia32_cg_config.use_sse2) {
/* check the Phi nodes: no 64bit and no floating point cmov */
for (phi = phi_list; phi; phi = get_Phi_next(phi)) {
ir_mode *mode = get_irn_mode(phi);
if (mode_is_float(mode)) {
/* check for Min, Max */
ir_node *t = get_Phi_pred(phi, i);
ir_node *f = get_Phi_pred(phi, j);
/* SSE2 supports Min & Max */
if (pn == pn_Cmp_Lt || pn == pn_Cmp_Le || pn == pn_Cmp_Ge || pn == pn_Cmp_Gt) {
if (cl == t && cr == f) {
/* Mux(a <=/>= b, a, b) => MIN, MAX */
continue;
} else if (cl == f && cr == t) {
/* Mux(a <=/>= b, b, a) => MAX, MIN */
continue;
}
}
return 0;
} else if (get_mode_size_bits(mode) > 32) {
/* no 64bit cmov */
return 0;
}
}
} else {
/* check the Phi nodes: no 64bit and no floating point cmov */
for (phi = phi_list; phi; phi = get_Phi_next(phi)) {
ir_mode *mode = get_irn_mode(phi);
if (mode_is_float(mode)) {
ir_node *t = get_Phi_pred(phi, i);
ir_node *f = get_Phi_pred(phi, j);
/* always support Mux(!float, C1, C2) */
if (is_Const(t) && is_Const(f) && !mode_is_float(get_irn_mode(cl))) {
switch (be_transformer) {
case TRANSFORMER_DEFAULT:
/* always support Mux(!float, C1, C2) */
continue;
#ifdef FIRM_GRGEN_BE
case TRANSFORMER_PBQP:
case TRANSFORMER_RAND:
/* no support for Mux(*, C1, C2) */
return 0;
#endif
default:
panic("invalid transformer");
}
}
/* only abs or nabs supported */
if (! psi_is_Abs_or_Nabs(cmp, sel, t, f))
return 0;
} else if (get_mode_size_bits(mode) > 32)
return 0;
}
}
return false;
}
return 1;
} else { /* No Cmov, only some special cases */
/* Now some supported cases here */
for (phi = phi_list; phi; phi = get_Phi_next(phi)) {
ir_mode *mode = get_irn_mode(phi);
ir_node *t, *f;
t = get_Phi_pred(phi, i);
f = get_Phi_pred(phi, j);
if (mode_is_float(mode)) {
/* always support Mux(!float, C1, C2) */
if (is_Const(t) && is_Const(f) &&
!mode_is_float(get_irn_mode(cl))) {
switch (be_transformer) {
case TRANSFORMER_DEFAULT:
/* always support Mux(!float, C1, C2) */
continue;
static int ia32_is_mux_allowed(ir_node *sel, ir_node *mux_false,
ir_node *mux_true)
{
ir_mode *mode;
/* we can handle Abs for all modes and compares */
if (mux_is_abs(sel, mux_true, mux_false))
return true;
/* we can handle Set for all modes and compares */
if (mux_is_set(sel, mux_true, mux_false))
return true;
/* SSE has own min/max operations */
if (ia32_cg_config.use_sse2
&& mux_is_float_min_max(sel, mux_true, mux_false))
return true;
/* we can handle Mux(?, Const[f], Const[f]) */
if (mux_is_float_const_const(sel, mux_true, mux_false)) {
#ifdef FIRM_GRGEN_BE
case TRANSFORMER_PBQP:
case TRANSFORMER_RAND:
/* no support for Mux(*, C1, C2) */
return 0;
/* well, some code selectors can't handle it */
if (be_transformer != TRANSFORMER_PBQP
|| be_transformer != TRANSFORMER_RAND)
return true;
#else
return true;
#endif
default:
panic("invalid transformer");
}
}
/* only abs or nabs supported */
if (! psi_is_Abs_or_Nabs(cmp, sel, t, f))
return 0;
} else if (get_mode_size_bits(mode) > 32) {
/* no 64bit yet */
return 0;
}
}
if (is_Const(t) && is_Const(f)) {
if ((is_Const_null(t) && is_Const_one(f)) || (is_Const_one(t) && is_Const_null(f))) {
/* always support Mux(x, C1, C2) */
continue;
}
} else if (pn == pn_Cmp_Lt || pn == pn_Cmp_Le || pn == pn_Cmp_Ge || pn == pn_Cmp_Gt) {
#if 0
if (cl == t && cr == f) {
/* Mux(a <=/>= b, a, b) => Min, Max */
continue;
}
if (cl == f && cr == t) {
/* Mux(a <=/>= b, b, a) => Max, Min */
continue;
}
#endif
if ((pn & pn_Cmp_Gt) && !mode_is_signed(mode) &&
is_Const(f) && is_Const_null(f) && is_Sub(t) &&
get_Sub_left(t) == cl && get_Sub_right(t) == cr) {
/* Mux(a >=u b, a - b, 0) unsigned Doz */
continue;
}
if ((pn & pn_Cmp_Lt) && !mode_is_signed(mode) &&
is_Const(t) && is_Const_null(t) && is_Sub(f) &&
get_Sub_left(f) == cl && get_Sub_right(f) == cr) {
/* Mux(a <=u b, 0, a - b) unsigned Doz */
continue;
}
if (is_Const(cr) && is_Const_null(cr)) {
if (cl == t && is_Minus(f) && get_Minus_op(f) == cl) {
/* Mux(a <=/>= 0 ? a : -a) Nabs/Abs */
continue;
} else if (cl == f && is_Minus(t) && get_Minus_op(t) == cl) {
/* Mux(a <=/>= 0 ? -a : a) Abs/Nabs */
continue;
}
}
}
return 0;
/* no support for 64bit inputs to cmov */
mode = get_irn_mode(mux_true);
if (get_mode_size_bits(mode) > 32)
return false;
if (mux_is_doz(sel, mux_true, mux_false))
return true;
/* Check Cmp before the node */
if (is_Proj(sel)) {
ir_node *cmp = get_Proj_pred(sel);
if (is_Cmp(cmp)) {
ir_mode *cmp_mode = get_irn_mode(get_Cmp_left(cmp));
/* we can't handle 64bit compares */
if (get_mode_size_bits(cmp_mode) > 32)
return false;
/* we can't handle float compares */
if (mode_is_float(cmp_mode))
return false;
}
/* all checks passed */
return 1;
}
return 0;
/* did we disable cmov generation? */
if (!ia32_cg_config.use_cmov)
return false;
/* we can use a cmov */
return true;
}
static asm_constraint_flags_t ia32_parse_asm_constraint(const char **c)
......
......@@ -661,7 +661,8 @@ Sbb => {
},
Sbb0 => {
irn_flags => "R",
# Spiller currently fails when rematerializing flag consumers
# irn_flags => "R",
reg_req => { in => [ "flags" ], out => [ "gp", "flags" ] },
outs => [ "res", "flags" ],
emit => ". sbb%M %D0, %D0",
......@@ -1119,9 +1120,9 @@ SetccMem => {
CMovcc => {
#irn_flags => "R",
state => "exc_pinned",
# (note: leave the false,true order intact to make it compatible with other
# ia32_binary ops)
state => "exc_pinned",
reg_req => { in => [ "gp", "gp", "none", "gp", "gp", "eflags" ],
out => [ "in_r4 in_r5", "flags", "none" ] },
ins => [ "base", "index", "mem", "val_false", "val_true", "eflags" ],
......
......@@ -3155,6 +3155,7 @@ static ir_node *gen_Mux(ir_node *node)
}
}
}
if (is_Const(mux_true) && is_Const(mux_false)) {
ia32_address_mode_t am;
ir_node *load;
......
......@@ -4282,10 +4282,13 @@ static ir_node *transform_node_Proj_Cmp(ir_node *proj) {
/*
* UpConv(x) REL 0 ==> x REL 0
* Don't do this for float values as it's unclear whether it is a
* win. (on the other side it makes detection/creation of fabs hard)
*/
if (get_mode_size_bits(mode) > get_mode_size_bits(op_mode) &&
((proj_nr == pn_Cmp_Eq || proj_nr == pn_Cmp_Lg) ||
mode_is_signed(mode) || !mode_is_signed(op_mode))) {
mode_is_signed(mode) || !mode_is_signed(op_mode)) &&
!mode_is_float(mode)) {
tv = get_mode_null(op_mode);
left = op;
mode = op_mode;
......@@ -5442,12 +5445,12 @@ static ir_node *transform_node_End(ir_node *n) {
return n;
} /* transform_node_End */
/** returns 1 if a == -b */
static int is_negated_value(ir_node *a, ir_node *b) {
bool is_negated_value(ir_node *a, ir_node *b)
{
if (is_Minus(a) && get_Minus_op(a) == b)
return 1;
return true;
if (is_Minus(b) && get_Minus_op(b) == a)
return 1;
return true;
if (is_Sub(a) && is_Sub(b)) {