edges_deactivate(irg);
edges_activate(irg);
}
-
-int be_mux_is_abs(ir_node *sel, ir_node *mux_true, ir_node *mux_false)
-{
- ir_node *cmp_left;
- ir_node *cmp_right;
- ir_mode *mode;
- ir_relation relation;
-
- if (!is_Cmp(sel))
- return 0;
-
- /**
- * Note further that these optimization work even for floating point
- * with NaN's because -NaN == NaN.
- * However, if +0 and -0 is handled differently, we cannot use the Abs/-Abs
- * transformations.
- */
- mode = get_irn_mode(mux_true);
- if (mode_honor_signed_zeros(mode))
- return 0;
-
- /* must be <, <=, >=, > */
- relation = get_Cmp_relation(sel);
- if ((relation & ir_relation_less_greater) == 0)
- return 0;
-
- if (!ir_is_negated_value(mux_true, mux_false))
- return 0;
-
- /* must be x cmp 0 */
- cmp_right = get_Cmp_right(sel);
- if (!is_Const(cmp_right) || !is_Const_null(cmp_right))
- return 0;
-
- cmp_left = get_Cmp_left(sel);
- if (cmp_left == mux_false) {
- if (relation & ir_relation_less) {
- return 1;
- } else {
- assert(relation & ir_relation_greater);
- return -1;
- }
- } else if (cmp_left == mux_true) {
- if (relation & ir_relation_less) {
- return -1;
- } else {
- assert(relation & ir_relation_greater);
- return 1;
- }
- }
-
- return 0;
-}
-
-ir_node *be_get_abs_op(ir_node *sel)
-{
- ir_node *cmp_left = get_Cmp_left(sel);
- return cmp_left;
-}
*/
void be_transform_graph(ir_graph *irg, arch_pretrans_nodes *func);
-/**
- * If Mux(sel, t, f) represents an Abs return 1, if it represents -Abs return
- * -1, otherwise 0
- */
-int be_mux_is_abs(ir_node *sel, ir_node *mux_true, ir_node *mux_false);
-
-ir_node *be_get_abs_op(ir_node *sel);
-
#endif
if (get_mode_size_bits(mode) > 32)
return false;
/* we can handle Abs for all modes and compares (except 64bit) */
- if (be_mux_is_abs(sel, mux_true, mux_false) != 0)
+ if (ir_mux_is_abs(sel, mux_true, mux_false) != 0)
return true;
/* we can't handle MuxF yet */
if (mode_is_float(mode))
SET_IA32_ORIG_NODE(new_node, node);
}
}
- } else {
- ir_node *xorn;
- ir_node *sign_extension;
-
- if (get_mode_size_bits(mode) == 32) {
- new_op = be_transform_node(op);
- } else {
- new_op = create_I2I_Conv(mode, mode_Is, dbgi, block, op, node);
- }
-
- sign_extension = create_sex_32_64(dbgi, new_block, new_op, node);
-
- xorn = new_bd_ia32_Xor(dbgi, new_block, noreg_GP, noreg_GP,
- nomem, new_op, sign_extension);
- SET_IA32_ORIG_NODE(xorn, node);
-
- if (negate) {
- new_node = new_bd_ia32_Sub(dbgi, new_block, noreg_GP, noreg_GP,
- nomem, sign_extension, xorn);
- } else {
- new_node = new_bd_ia32_Sub(dbgi, new_block, noreg_GP, noreg_GP,
- nomem, xorn, sign_extension);
- }
- SET_IA32_ORIG_NODE(new_node, node);
}
return new_node;
assert(get_irn_mode(sel) == mode_b);
- is_abs = be_mux_is_abs(sel, mux_true, mux_false);
+ is_abs = ir_mux_is_abs(sel, mux_true, mux_false);
if (is_abs != 0) {
- return create_abs(dbgi, block, be_get_abs_op(sel), is_abs < 0, node);
+ if (ia32_mode_needs_gp_reg(mode)) {
+ ir_fprintf(stderr, "Optimisation warning: Integer abs %+F not transformed\n",
+ node);
+ } else {
+ ir_node *op = ir_get_abs_op(sel, mux_true, mux_false);
+ return create_abs(dbgi, block, op, is_abs < 0, node);
+ }
}
/* Note: a Mux node uses a Load two times IFF it's used in the compare AND in the result */
return res;
}
-#if 0
-static ir_node *gen_Abs(ir_node *node)
-{
- ir_mode *const mode = get_irn_mode(node);
-
- if (mode_is_float(mode)) {
- return gen_helper_unfpop(node, mode, new_bd_sparc_fabs_s,
- new_bd_sparc_fabs_d, new_bd_sparc_fabs_q);
- } else {
- ir_node *const block = be_transform_node(get_nodes_block(node));
- dbg_info *const dbgi = get_irn_dbg_info(node);
- ir_node *const op = get_Abs_op(node);
- ir_node *const new_op = be_transform_node(op);
- ir_node *const sra = new_bd_sparc_Sra_imm(dbgi, block, new_op, NULL, 31);
- ir_node *const xor = new_bd_sparc_Xor_reg(dbgi, block, new_op, sra);
- ir_node *const sub = new_bd_sparc_Sub_reg(dbgi, block, xor, sra);
- return sub;
- }
-}
-#endif
-
/**
* Transforms a Not node.
*
return false;
}
+static const ir_node *skip_upconv(const ir_node *node)
+{
+ while (is_Conv(node)) {
+ ir_mode *mode = get_irn_mode(node);
+ const ir_node *op = get_Conv_op(node);
+ ir_mode *op_mode = get_irn_mode(op);
+ if (!smaller_mode(op_mode, mode))
+ break;
+ node = op;
+ }
+ return node;
+}
+
+int ir_mux_is_abs(const ir_node *sel, const ir_node *mux_true,
+ const ir_node *mux_false)
+{
+ ir_node *cmp_left;
+ ir_node *cmp_right;
+ ir_mode *mode;
+ ir_relation relation;
+
+ if (!is_Cmp(sel))
+ return 0;
+
+ /**
+ * Note further that these optimization work even for floating point
+ * with NaN's because -NaN == NaN.
+ * However, if +0 and -0 is handled differently, we cannot use the Abs/-Abs
+ * transformations.
+ */
+ mode = get_irn_mode(mux_true);
+ if (mode_honor_signed_zeros(mode))
+ return 0;
+
+ /* must be <, <=, >=, > */
+ relation = get_Cmp_relation(sel);
+ if ((relation & ir_relation_less_greater) == 0)
+ return 0;
+
+ if (!ir_is_negated_value(mux_true, mux_false))
+ return 0;
+
+ mux_true = skip_upconv(mux_true);
+ mux_false = skip_upconv(mux_false);
+
+ /* must be x cmp 0 */
+ cmp_right = get_Cmp_right(sel);
+ if (!is_Const(cmp_right) || !is_Const_null(cmp_right))
+ return 0;
+
+ cmp_left = get_Cmp_left(sel);
+ if (cmp_left == mux_false) {
+ if (relation & ir_relation_less) {
+ return 1;
+ } else {
+ assert(relation & ir_relation_greater);
+ return -1;
+ }
+ } else if (cmp_left == mux_true) {
+ if (relation & ir_relation_less) {
+ return -1;
+ } else {
+ assert(relation & ir_relation_greater);
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+ir_node *ir_get_abs_op(const ir_node *sel, ir_node *mux_true,
+ ir_node *mux_false)
+{
+ ir_node *cmp_left = get_Cmp_left(sel);
+ return cmp_left == skip_upconv(mux_false) ? mux_false : mux_true;
+}
+
/**
* Optimize a Mux into some simpler cases.
*/
static ir_node *transform_node_Mux(ir_node *n)
{
- ir_node *oldn = n, *sel = get_Mux_sel(n);
- ir_mode *mode = get_irn_mode(n);
- ir_node *t = get_Mux_true(n);
- ir_node *f = get_Mux_false(n);
- ir_graph *irg = get_irn_irg(n);
+ ir_node *oldn = n;
+ ir_node *sel = get_Mux_sel(n);
+ ir_mode *mode = get_irn_mode(n);
+ ir_node *t = get_Mux_true(n);
+ ir_node *f = get_Mux_false(n);
+ ir_graph *irg = get_irn_irg(n);
if (is_irg_state(irg, IR_GRAPH_STATE_KEEP_MUX))
return n;
+ /* implement integer abs: abs(x) = x^(x >>s 31) - (x >>s 31) */
+ if (get_mode_arithmetic(mode) == irma_twos_complement) {
+ int abs = ir_mux_is_abs(sel, t, f);
+ if (abs != 0) {
+ dbg_info *dbgi = get_irn_dbg_info(n);
+ ir_node *block = get_nodes_block(n);
+ ir_node *op = ir_get_abs_op(sel, t, f);
+ int bits = get_mode_size_bits(mode);
+ ir_node *shiftconst = new_r_Const_long(irg, mode_Iu, bits-1);
+ ir_node *sext = new_rd_Shrs(dbgi, block, op, shiftconst, mode);
+ ir_node *xorn = new_rd_Eor(dbgi, block, op, sext, mode);
+ ir_node *res;
+ if (abs > 0) {
+ res = new_rd_Sub(dbgi, block, xorn, sext, mode);
+ } else {
+ res = new_rd_Sub(dbgi, block, sext, xorn, mode);
+ }
+ return res;
+ }
+ }
+
if (is_Mux(t)) {
ir_node* block = get_nodes_block(n);
ir_node* c0 = sel;
*/
ir_op_ops *firm_set_default_operations(unsigned code, ir_op_ops *ops);
+int ir_mux_is_abs(const ir_node *sel, const ir_node *mux_true,
+ const ir_node *mux_false);
+
+ir_node *ir_get_abs_op(const ir_node *sel, ir_node *mux_true,
+ ir_node *mux_false);
+
#endif