* gives a (conservative) estimation of possible relation when comparing
* left+right
*/
-static ir_relation determine_possible_cmp_relations(const ir_node *left,
- const ir_node *right)
+ir_relation ir_get_possible_cmp_relations(const ir_node *left,
+ const ir_node *right)
{
ir_relation possible = ir_relation_true;
ir_tarval *tv_l = value_of(left);
{
ir_node *left = get_Cmp_left(cmp);
ir_node *right = get_Cmp_right(cmp);
- ir_relation possible = determine_possible_cmp_relations(left, right);
+ ir_relation possible = ir_get_possible_cmp_relations(left, right);
ir_relation relation = get_Cmp_relation(cmp);
/* if none of the requested relations is possible, return false */
ir_tarval *tv;
if (a == b) {
- n = a; /* Or has it's own neutral element */
+ n = a; /* idempotence */
DBG_OPT_ALGSIM0(oldn, n, FS_OPT_OR);
return n;
}
- /* constants are cormalized to right, check this site first */
+ /* constants are normalized to right, check this side first */
tv = value_of(b);
if (tarval_is_null(tv)) {
n = a;
ir_tarval *tv;
if (a == b) {
- n = a; /* And has it's own neutral element */
+ n = a; /* idempotence */
DBG_OPT_ALGSIM0(oldn, n, FS_OPT_AND);
return n;
}
- /* constants are normalized to right, check this site first */
+ /* constants are normalized to right, check this side first */
tv = value_of(b);
if (tarval_is_all_one(tv)) {
n = a;
first_val = get_Phi_pred(n, i);
if ( (first_val != n) /* not self pointer */
#if 0
- /* BEWARE: when the if is changed to 1, Phi's will ignore it's Bad
- * predecessors. Then, Phi nodes in dead code might be removed, causing
- * nodes pointing to themself (Add's for instance).
- * This is really bad and causes endless recursions in several
- * code pathes, so we do NOT optimize such a code.
+ /* BEWARE: when the if is changed to 1, Phis will ignore their Bad
+ * predecessors. Then, Phi nodes in unreachable code might be removed,
+ * causing nodes pointing to themselev (Adds for instance).
+ * This is really bad and causes endless recursion on several
+ * code pathes, so we do NOT optimize such code.
* This is not that bad as it sounds, optimize_cf() removes bad control flow
* (and bad Phi predecessors), so live code is optimized later.
*/
} /* equivalent_node_Proj_Store */
/**
- * Does all optimizations on nodes that must be done on it's Proj's
+ * Does all optimizations on nodes that must be done on its Projs
* because of creating new nodes.
*/
static ir_node *equivalent_node_Proj(ir_node *proj)
return n;
}
+/**
+ * Create a 0 constant of given mode.
+ */
+static ir_node *create_zero_const(ir_graph *irg, ir_mode *mode)
+{
+ ir_tarval *tv = get_mode_null(mode);
+ ir_node *cnst = new_r_Const(irg, tv);
+
+ return cnst;
+}
+
/**
* Transform an And.
*/
ir_mode *mode;
vrp_attr *a_vrp, *b_vrp;
- /* we can combine the relations of two compares with the same operands */
if (is_Cmp(a) && is_Cmp(b)) {
- ir_node *a_left = get_Cmp_left(a);
- ir_node *a_right = get_Cmp_left(a);
- ir_node *b_left = get_Cmp_left(b);
- ir_node *b_right = get_Cmp_right(b);
+ ir_node *a_left = get_Cmp_left(a);
+ ir_node *a_right = get_Cmp_right(a);
+ ir_node *b_left = get_Cmp_left(b);
+ ir_node *b_right = get_Cmp_right(b);
+ ir_relation a_relation = get_Cmp_relation(a);
+ ir_relation b_relation = get_Cmp_relation(b);
+ /* we can combine the relations of two compares with the same
+ * operands */
if (a_left == b_left && b_left == b_right) {
dbg_info *dbgi = get_irn_dbg_info(n);
ir_node *block = get_nodes_block(n);
- ir_relation a_relation = get_Cmp_relation(a);
- ir_relation b_relation = get_Cmp_relation(b);
ir_relation new_relation = a_relation & b_relation;
return new_rd_Cmp(dbgi, block, a_left, a_right, new_relation);
}
+ /* Cmp(a==0) and Cmp(b==0) can be optimized to Cmp(a|b==0) */
+ if (is_Const(a_right) && is_Const_null(a_right)
+ && is_Const(b_right) && is_Const_null(b_right)
+ && a_relation == b_relation && a_relation == ir_relation_equal
+ && !mode_is_float(get_irn_mode(a_left))
+ && !mode_is_float(get_irn_mode(b_left))) {
+ dbg_info *dbgi = get_irn_dbg_info(n);
+ ir_node *block = get_nodes_block(n);
+ ir_mode *mode = get_irn_mode(a_left);
+ ir_node *n_b_left = get_irn_mode(b_left) != mode ?
+ new_rd_Conv(dbgi, block, b_left, mode) : b_left;
+ ir_node *or = new_rd_Or(dbgi, block, a_left, n_b_left, mode);
+ ir_graph *irg = get_irn_irg(n);
+ ir_node *zero = create_zero_const(irg, mode);
+ return new_rd_Cmp(dbgi, block, or, zero, ir_relation_equal);
+ }
}
mode = get_irn_mode(n);
return false;
}
-/**
- * Create a 0 constant of given mode.
- */
-static ir_node *create_zero_const(ir_graph *irg, ir_mode *mode)
-{
- ir_tarval *tv = get_mode_null(mode);
- ir_node *cnst = new_r_Const(irg, tv);
-
- return cnst;
-}
-
/**
* Normalizes and optimizes Cmp nodes.
*/
bool changed = false;
bool changedc = false;
ir_relation relation = get_Cmp_relation(n);
- ir_relation possible = determine_possible_cmp_relations(left, right);
+ ir_relation possible = ir_get_possible_cmp_relations(left, right);
/* mask out impossible relations */
ir_relation new_relation = relation & possible;
} /* transform_node_Proj_Bound */
/**
- * Does all optimizations on nodes that must be done on it's Proj's
+ * Does all optimizations on nodes that must be done on its Projs
* because of creating new nodes.
*/
static ir_node *transform_node_Proj(ir_node *proj)
/* Note: the obvious rot formulation (a << x) | (a >> (32-x)) gets
* transformed to (a << x) | (a >> -x) by transform_node_shift_modulo() */
- if (!is_negated_value(c1, c2)) {
+ if (!ir_is_negated_value(c1, c2)) {
return irn_or;
}
return n;
} /* transform_node_Or_Rotl */
+static bool is_cmp_unequal_zero(const ir_node *node)
+{
+ ir_relation relation = get_Cmp_relation(node);
+ ir_node *left = get_Cmp_left(node);
+ ir_node *right = get_Cmp_right(node);
+ ir_mode *mode = get_irn_mode(left);
+
+ if (!is_Const(right) || !is_Const_null(right))
+ return false;
+ if (mode_is_signed(mode)) {
+ return relation == ir_relation_less_greater;
+ } else {
+ return relation == ir_relation_greater;
+ }
+}
+
/**
* Transform an Or.
*/
ir_relation new_relation = a_relation | b_relation;
return new_rd_Cmp(dbgi, block, a_left, a_right, new_relation);
}
+ /* Cmp(a!=0) or Cmp(b!=0) => Cmp(a|b != 0) */
+ if (is_cmp_unequal_zero(a) && is_cmp_unequal_zero(b)
+ && !mode_is_float(get_irn_mode(a_left))
+ && !mode_is_float(get_irn_mode(b_left))) {
+ ir_graph *irg = get_irn_irg(n);
+ dbg_info *dbgi = get_irn_dbg_info(n);
+ ir_node *block = get_nodes_block(n);
+ ir_mode *mode = get_irn_mode(a_left);
+ ir_node *n_b_left = get_irn_mode(b_left) != mode ?
+ new_rd_Conv(dbgi, block, b_left, mode) : b_left;
+ ir_node *or = new_rd_Or(dbgi, block, a_left, n_b_left, mode);
+ ir_node *zero = create_zero_const(irg, mode);
+ return new_rd_Cmp(dbgi, block, or, zero, ir_relation_less_greater);
+ }
}
mode = get_irn_mode(n);
return n;
} /* transform_node_End */
-bool is_negated_value(ir_node *a, ir_node *b)
+int ir_is_negated_value(const ir_node *a, const ir_node *b)
{
if (is_Minus(a) && get_Minus_op(a) == b)
return true;
return n;
} /* transform_node_Sync */
+static ir_node *transform_node_Load(ir_node *n)
+{
+ /* if our memory predecessor is a load from the same address, then reuse the
+ * previous result */
+ ir_node *mem = get_Load_mem(n);
+ ir_node *mem_pred;
+
+ if (!is_Proj(mem))
+ return n;
+ /* don't touch volatile loads */
+ if (get_Load_volatility(n) == volatility_is_volatile)
+ return n;
+ mem_pred = get_Proj_pred(mem);
+ if (is_Load(mem_pred)) {
+ ir_node *pred_load = mem_pred;
+
+ /* conservatively compare the 2 loads. TODO: This could be less strict
+ * with fixup code in some situations (like smaller/bigger modes) */
+ if (get_Load_ptr(pred_load) != get_Load_ptr(n))
+ return n;
+ if (get_Load_mode(pred_load) != get_Load_mode(n))
+ return n;
+ /* all combinations of aligned/unaligned pred/n should be fine so we do
+ * not compare the unaligned attribute */
+ {
+ ir_node *block = get_nodes_block(n);
+ ir_node *jmp = new_r_Jmp(block);
+ ir_graph *irg = get_irn_irg(n);
+ ir_node *bad = new_r_Bad(irg);
+ ir_mode *mode = get_Load_mode(n);
+ ir_node *res = new_r_Proj(pred_load, mode, pn_Load_res);
+ ir_node *in[pn_Load_max] = { mem, jmp, bad, res };
+ ir_node *tuple = new_r_Tuple(block, ARRAY_SIZE(in), in);
+ return tuple;
+ }
+ } else if (is_Store(mem_pred)) {
+ ir_node *pred_store = mem_pred;
+ ir_node *value = get_Store_value(pred_store);
+
+ if (get_Store_ptr(pred_store) != get_Load_ptr(n))
+ return n;
+ if (get_irn_mode(value) != get_Load_mode(n))
+ return n;
+ /* all combinations of aligned/unaligned pred/n should be fine so we do
+ * not compare the unaligned attribute */
+ {
+ ir_node *block = get_nodes_block(n);
+ ir_node *jmp = new_r_Jmp(block);
+ ir_graph *irg = get_irn_irg(n);
+ ir_node *bad = new_r_Bad(irg);
+ ir_node *res = value;
+ ir_node *in[pn_Load_max] = { mem, jmp, bad, res };
+ ir_node *tuple = new_r_Tuple(block, ARRAY_SIZE(in), in);
+ return tuple;
+ }
+ }
+
+ return n;
+}
+
/**
* optimize a trampoline Call into a direct Call
*/
ir_graph *irg;
type_dbg_info *tdb;
dbg_info *db;
- int i, n_res, n_param;
+ size_t i, n_res, n_param;
ir_variadicity var;
if (! is_Proj(callee))
}
var = get_method_variadicity(mtp);
set_method_variadicity(ctp, var);
- if (var == variadicity_variadic) {
- set_method_first_variadic_param_index(ctp, get_method_first_variadic_param_index(mtp) + 1);
- }
/* When we resolve a trampoline, the function must be called by a this-call */
set_method_calling_convention(ctp, get_method_calling_convention(mtp) | cc_this_call);
set_method_additional_properties(ctp, get_method_additional_properties(mtp));
CASE(Sync);
CASE_PROJ(Bound);
CASE_PROJ(CopyB);
- CASE_PROJ(Load);
CASE_PROJ(Store);
CASE_PROJ_EX(Cond);
CASE_PROJ_EX(Div);
+ CASE_PROJ_EX(Load);
CASE_PROJ_EX(Mod);
default:
/* leave NULL */;
/* NEVER do CSE on volatile Loads */
return 1;
/* do not CSE Loads with different alignment. Be conservative. */
- if (get_Load_align(a) != get_Load_align(b))
+ if (get_Load_unaligned(a) != get_Load_unaligned(b))
return 1;
return get_Load_mode(a) != get_Load_mode(b);
static int node_cmp_attr_Store(const ir_node *a, const ir_node *b)
{
/* do not CSE Stores with different alignment. Be conservative. */
- if (get_Store_align(a) != get_Store_align(b))
+ if (get_Store_unaligned(a) != get_Store_unaligned(b))
return 1;
/* NEVER do CSE on volatile Stores */
/* Should we really check the constraints here? Should be better, but is strange. */
n = get_ASM_n_input_constraints(a);
if (n != get_ASM_n_input_constraints(b))
- return 0;
+ return 1;
ca = get_ASM_input_constraints(a);
cb = get_ASM_input_constraints(b);
for (i = 0; i < n; ++i) {
- if (ca[i].pos != cb[i].pos || ca[i].constraint != cb[i].constraint)
+ if (ca[i].pos != cb[i].pos || ca[i].constraint != cb[i].constraint
+ || ca[i].mode != cb[i].mode)
return 1;
}
n = get_ASM_n_output_constraints(a);
if (n != get_ASM_n_output_constraints(b))
- return 0;
+ return 1;
ca = get_ASM_output_constraints(a);
cb = get_ASM_output_constraints(b);
for (i = 0; i < n; ++i) {
- if (ca[i].pos != cb[i].pos || ca[i].constraint != cb[i].constraint)
+ if (ca[i].pos != cb[i].pos || ca[i].constraint != cb[i].constraint
+ || ca[i].mode != cb[i].mode)
return 1;
}
n = get_ASM_n_clobbers(a);
if (n != get_ASM_n_clobbers(b))
- return 0;
+ return 1;
cla = get_ASM_clobbers(a);
clb = get_ASM_clobbers(b);
if (nn != n) {
/* n is reachable again */
- edges_node_revival(nn, get_irn_irg(nn));
+ edges_node_revival(nn);
}
return nn;
#if 0
/* Propagating Unknowns here seems to be a bad idea, because
sometimes we need a node as a input and did not want that
- it kills it's user.
+ it kills its user.
However, it might be useful to move this into a later phase
(if you think that optimizing such code is useful). */
if (is_Unknown(pred) && mode_is_data(get_irn_mode(node)))
Run always for transformation induced Bads. */
n = gigo(n);
if (n != oldn) {
- edges_node_deleted(oldn, irg);
+ edges_node_deleted(oldn);
/* We found an existing, better node, so we can deallocate the old node. */
irg_kill_node(irg, oldn);
size_t node_size;
/*
- * we MUST copy the node here temporary, because it's still
+ * we MUST copy the node here temporarily, because it's still
* needed for DBG_OPT_CSTEVAL
*/
node_size = offsetof(ir_node, attr) + n->op->attr_size;
memcpy(oldn->in, n->in, ARR_LEN(n->in) * sizeof(n->in[0]));
/* note the inplace edges module */
- edges_node_deleted(n, irg);
+ edges_node_deleted(n);
/* evaluation was successful -- replace the node. */
irg_kill_node(irg, n);
n = identify_cons(n);
if (n != oldn) {
- edges_node_deleted(oldn, irg);
+ edges_node_deleted(oldn);
/* We found an existing, better node, so we can deallocate the old node. */
irg_kill_node(irg, oldn);
* @return
* The operations.
*/
-static ir_op_ops *firm_set_default_hash(ir_opcode code, ir_op_ops *ops)
+static ir_op_ops *firm_set_default_hash(unsigned code, ir_op_ops *ops)
{
#define CASE(a) \
case iro_##a: \
/*
* Sets the default operation for an ir_ops.
*/
-ir_op_ops *firm_set_default_operations(ir_opcode code, ir_op_ops *ops)
+ir_op_ops *firm_set_default_operations(unsigned code, ir_op_ops *ops)
{
ops = firm_set_default_hash(code, ops);
ops = firm_set_default_computed_value(code, ops);