smulhrs, umulhrs, binary)
DEF_INTERNAL_SIGNED_OPTAB_FN (SAT_ADD, ECF_CONST, first, ssadd, usadd, binary)
+DEF_INTERNAL_SIGNED_OPTAB_FN (SAT_SUB, ECF_CONST, first, sssub, ussub, binary)
DEF_INTERNAL_COND_FN (ADD, ECF_CONST, add, binary)
DEF_INTERNAL_COND_FN (SUB, ECF_CONST, sub, binary)
(match (unsigned_integer_sat_add @0 @1)
(bit_ior:c (usadd_left_part_2 @0 @1) (usadd_right_part_2 @0 @1)))
+/* Unsigned saturation sub, case 1 (branch with gt):
+ SAT_U_SUB = X > Y ? X - Y : 0 */
+(match (unsigned_integer_sat_sub @0 @1)
+ (cond (gt @0 @1) (minus @0 @1) integer_zerop)
+ (if (INTEGRAL_TYPE_P (type) && TYPE_UNSIGNED (type)
+ && types_match (type, @0, @1))))
+
+/* Unsigned saturation sub, case 2 (branch with ge):
+ SAT_U_SUB = X >= Y ? X - Y : 0. */
+(match (unsigned_integer_sat_sub @0 @1)
+ (cond (ge @0 @1) (minus @0 @1) integer_zerop)
+ (if (INTEGRAL_TYPE_P (type) && TYPE_UNSIGNED (type)
+ && types_match (type, @0, @1))))
+
/* x > y && x != XXX_MIN --> x > y
x > y && x == XXX_MIN --> false . */
(for eqne (eq ne)
OPTAB_NX(sub_optab, "sub$Q$a3")
OPTAB_VL(subv_optab, "subv$I$a3", MINUS, "sub", '3', gen_intv_fp_libfunc)
OPTAB_VX(subv_optab, "sub$F$a3")
-OPTAB_NL(sssub_optab, "sssub$Q$a3", SS_MINUS, "sssub", '3', gen_signed_fixed_libfunc)
-OPTAB_NL(ussub_optab, "ussub$Q$a3", US_MINUS, "ussub", '3', gen_unsigned_fixed_libfunc)
+OPTAB_NL(sssub_optab, "sssub$a3", SS_MINUS, "sssub", '3', gen_signed_fixed_libfunc)
+OPTAB_NL(ussub_optab, "ussub$a3", US_MINUS, "ussub", '3', gen_unsigned_fixed_libfunc)
OPTAB_NL(smul_optab, "mul$Q$a3", MULT, "mul", '3', gen_int_fp_fixed_libfunc)
OPTAB_NX(smul_optab, "mul$P$a3")
OPTAB_NX(smul_optab, "mul$F$a3")
}
extern bool gimple_unsigned_integer_sat_add (tree, tree*, tree (*)(tree));
+extern bool gimple_unsigned_integer_sat_sub (tree, tree*, tree (*)(tree));
+
+static void
+build_saturation_binary_arith_call (gimple_stmt_iterator *gsi, internal_fn fn,
+ tree lhs, tree op_0, tree op_1)
+{
+ if (direct_internal_fn_supported_p (fn, TREE_TYPE (lhs), OPTIMIZE_FOR_BOTH))
+ {
+ gcall *call = gimple_build_call_internal (fn, 2, op_0, op_1);
+ gimple_call_set_lhs (call, lhs);
+ gsi_replace (gsi, call, /* update_eh_info */ true);
+ }
+}
/*
- * Try to match saturation arith pattern(s).
- * 1. SAT_ADD (unsigned)
- * _7 = _4 + _6;
- * _8 = _4 > _7;
- * _9 = (long unsigned int) _8;
- * _10 = -_9;
- * _12 = _7 | _10;
- * =>
- * _12 = .SAT_ADD (_4, _6); */
+ * Try to match saturation unsigned add.
+ * _7 = _4 + _6;
+ * _8 = _4 > _7;
+ * _9 = (long unsigned int) _8;
+ * _10 = -_9;
+ * _12 = _7 | _10;
+ * =>
+ * _12 = .SAT_ADD (_4, _6); */
+
static void
-match_saturation_arith (gimple_stmt_iterator *gsi, gassign *stmt)
+match_unsigned_saturation_add (gimple_stmt_iterator *gsi, gassign *stmt)
{
- gcall *call = NULL;
+ tree ops[2];
+ tree lhs = gimple_assign_lhs (stmt);
+ if (gimple_unsigned_integer_sat_add (lhs, ops, NULL))
+ build_saturation_binary_arith_call (gsi, IFN_SAT_ADD, lhs, ops[0], ops[1]);
+}
+
+/*
+ * Try to match saturation unsigned sub.
+ * _1 = _4 >= _5;
+ * _3 = _4 - _5;
+ * _6 = _1 ? _3 : 0;
+ * =>
+ * _6 = .SAT_SUB (_4, _5); */
+
+static void
+match_unsigned_saturation_sub (gimple_stmt_iterator *gsi, gassign *stmt)
+{
tree ops[2];
tree lhs = gimple_assign_lhs (stmt);
- if (gimple_unsigned_integer_sat_add (lhs, ops, NULL)
- && direct_internal_fn_supported_p (IFN_SAT_ADD, TREE_TYPE (lhs),
- OPTIMIZE_FOR_BOTH))
- {
- call = gimple_build_call_internal (IFN_SAT_ADD, 2, ops[0], ops[1]);
- gimple_call_set_lhs (call, lhs);
- gsi_replace (gsi, call, true);
- }
+ if (gimple_unsigned_integer_sat_sub (lhs, ops, NULL))
+ build_saturation_binary_arith_call (gsi, IFN_SAT_SUB, lhs, ops[0], ops[1]);
}
/* Recognize for unsigned x
break;
case BIT_IOR_EXPR:
- match_saturation_arith (&gsi, as_a<gassign *> (stmt));
+ match_unsigned_saturation_add (&gsi, as_a<gassign *> (stmt));
/* fall-through */
case BIT_XOR_EXPR:
match_uaddc_usubc (&gsi, stmt, code);
match_single_bit_test (&gsi, stmt);
break;
+ case COND_EXPR:
+ match_unsigned_saturation_sub (&gsi, as_a<gassign *> (stmt));
+ break;
+
default:;
}
}