)
#endif
-/* X != C1 ? -X : C2 simplifies to -X when -C1 == C2. */
+/* X != C1 ? -X : C2 simplifies to -X when -C1 == C2. Additionally,
+ when C1 is the minimum signed value (e.g. INT_MIN), -X would be
+ undefined for signed types, so emit (signed)(-(unsigned)X) instead. */
(simplify
(cond (ne @0 INTEGER_CST@1) (negate@3 @0) INTEGER_CST@2)
(if (!TYPE_SATURATING (type)
- && (TYPE_OVERFLOW_WRAPS (type)
- || !wi::only_sign_bit_p (wi::to_wide (@1)))
&& wi::eq_p (wi::neg (wi::to_wide (@1)), wi::to_wide (@2)))
- @3))
+ (if (TYPE_OVERFLOW_WRAPS (type)
+ || !wi::only_sign_bit_p (wi::to_wide (@1)))
+ @3
+ (with { tree utype = unsigned_type_for (TREE_TYPE (@0)); }
+ (convert (negate (convert:utype @0)))))))
/* X != C1 ? ~X : C2 simplifies to ~X when ~C1 == C2. */
(simplify
return x != INT_MIN ? -x : INT_MIN;
}
-/* { dg-final { scan-tree-dump "goto" "optimized" } } */
+/* The branch should now be eliminated since we emit
+ (signed)(-(unsigned)x) which is well-defined. */
+/* { dg-final { scan-tree-dump-not "goto" "optimized" } } */
--- /dev/null
+/* PR tree-optimization/125050 */
+/* { dg-do compile } */
+/* { dg-options "-O1 -fdump-tree-phiopt2" } */
+
+int f(int a)
+{
+ if (a == -__INT_MAX__ - 1)
+ return -__INT_MAX__ - 1;
+ return -a;
+}
+
+/* This should be converted to (int)(-(unsigned)a). */
+/* { dg-final { scan-tree-dump-not "if " "phiopt2" } } */
--- /dev/null
+/* { dg-do compile } */
+/* { dg-options "-O1 -fdump-tree-phiopt2-raw" } */
+
+/* a == INT_MIN ? INT_MIN : -a -> (int)(-(unsigned)a) */
+int f1(int a)
+{
+ if (a == -__INT_MAX__ - 1)
+ return -__INT_MAX__ - 1;
+ return -a;
+}
+
+/* a != INT_MIN ? -a : INT_MIN -> (int)(-(unsigned)a) */
+int f2(int a)
+{
+ if (a != -__INT_MAX__ - 1)
+ return -a;
+ return -__INT_MAX__ - 1;
+}
+
+/* { dg-final { scan-tree-dump-times "negate_expr" 2 "phiopt2" } } */
+/* { dg-final { scan-tree-dump-not "gimple_cond <" "phiopt2" } } */
--- /dev/null
+/* { dg-do compile } */
+/* { dg-options "-O1 -fdump-tree-phiopt2-raw" } */
+
+/* Try the same pattern with different integer types. */
+
+long f_long(long a)
+{
+ if (a == -__LONG_MAX__ - 1)
+ return -__LONG_MAX__ - 1;
+ return -a;
+}
+
+long long f_ll(long long a)
+{
+ if (a == -__LONG_LONG_MAX__ - 1)
+ return -__LONG_LONG_MAX__ - 1;
+ return -a;
+}
+
+/* { dg-final { scan-tree-dump-times "negate_expr" 2 "phiopt2" } } */
+/* { dg-final { scan-tree-dump-not "gimple_cond <" "phiopt2" } } */