summaryrefslogtreecommitdiff
path: root/gcc/match.pd
diff options
context:
space:
mode:
authoramker <amker@138bc75d-0d04-0410-961f-82ee72b054a4>2016-12-02 14:13:11 +0000
committeramker <amker@138bc75d-0d04-0410-961f-82ee72b054a4>2016-12-02 14:13:11 +0000
commite7a6ef612a3e48068b6c76ff33442c733e37766b (patch)
treecdfa44848ffd774d45ea67c233edfb0982bdf3d9 /gcc/match.pd
parentb85c95b19c7fed12b1284dd0942756c4d9aaf75d (diff)
downloadgcc-e7a6ef612a3e48068b6c76ff33442c733e37766b.tar.gz
* match.pd: Add new pattern:
(cond (cmp (convert? x) c1) (op x c2) c3) -> (op (minmax x c1) c2). gcc/testsuite * gcc.dg/fold-bopcond-1.c: New test. * gcc.dg/fold-bopcond-2.c: New test. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@243180 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/match.pd')
-rw-r--r--gcc/match.pd100
1 files changed, 100 insertions, 0 deletions
diff --git a/gcc/match.pd b/gcc/match.pd
index bc8a5e74d2d..dbb91034e95 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -2038,6 +2038,106 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
(convert (cond (eq @1 (convert @3))
(convert:from_type @3) (convert:from_type @2)))))))))
+/* (cond (cmp (convert? x) c1) (op x c2) c3) -> (op (minmax x c1) c2) if:
+
+ 1) OP is PLUS or MINUS.
+ 2) CMP is LT, LE, GT or GE.
+ 3) C3 == (C1 op C2), and computation doesn't have undefined behavior.
+
+ This pattern also handles special cases like:
+
+ A) Operand x is a unsigned to signed type conversion and c1 is
+ integer zero. In this case,
+ (signed type)x < 0 <=> x > MAX_VAL(signed type)
+ (signed type)x >= 0 <=> x <= MAX_VAL(signed type)
+ B) Const c1 may not equal to (C3 op' C2). In this case we also
+ check equality for (c1+1) and (c1-1) by adjusting comparison
+ code.
+
+ TODO: Though signed type is handled by this pattern, it cannot be
+ simplified at the moment because C standard requires additional
+ type promotion. In order to match&simplify it here, the IR needs
+ to be cleaned up by other optimizers, i.e, VRP. */
+(for op (plus minus)
+ (for cmp (lt le gt ge)
+ (simplify
+ (cond (cmp (convert? @X) INTEGER_CST@1) (op @X INTEGER_CST@2) INTEGER_CST@3)
+ (with { tree from_type = TREE_TYPE (@X), to_type = TREE_TYPE (@1); }
+ (if (types_match (from_type, to_type)
+ /* Check if it is special case A). */
+ || (TYPE_UNSIGNED (from_type)
+ && !TYPE_UNSIGNED (to_type)
+ && TYPE_PRECISION (from_type) == TYPE_PRECISION (to_type)
+ && integer_zerop (@1)
+ && (cmp == LT_EXPR || cmp == GE_EXPR)))
+ (with
+ {
+ bool overflow = false;
+ enum tree_code code, cmp_code = cmp;
+ wide_int real_c1, c1 = @1, c2 = @2, c3 = @3;
+ signop sgn = TYPE_SIGN (from_type);
+
+ /* Handle special case A), given x of unsigned type:
+ ((signed type)x < 0) <=> (x > MAX_VAL(signed type))
+ ((signed type)x >= 0) <=> (x <= MAX_VAL(signed type)) */
+ if (!types_match (from_type, to_type))
+ {
+ if (cmp_code == LT_EXPR)
+ cmp_code = GT_EXPR;
+ if (cmp_code == GE_EXPR)
+ cmp_code = LE_EXPR;
+ c1 = wi::max_value (to_type);
+ }
+ /* To simplify this pattern, we require c3 = (c1 op c2). Here we
+ compute (c3 op' c2) and check if it equals to c1 with op' being
+ the inverted operator of op. Make sure overflow doesn't happen
+ if it is undefined. */
+ if (op == PLUS_EXPR)
+ real_c1 = wi::sub (c3, c2, sgn, &overflow);
+ else
+ real_c1 = wi::add (c3, c2, sgn, &overflow);
+
+ code = cmp_code;
+ if (!overflow || !TYPE_OVERFLOW_UNDEFINED (from_type))
+ {
+ /* Check if c1 equals to real_c1. Boundary condition is handled
+ by adjusting comparison operation if necessary. */
+ if (!wi::cmp (wi::sub (real_c1, 1, sgn, &overflow), c1, sgn)
+ && !overflow)
+ {
+ /* X <= Y - 1 equals to X < Y. */
+ if (cmp_code == LE_EXPR)
+ code = LT_EXPR;
+ /* X > Y - 1 equals to X >= Y. */
+ if (cmp_code == GT_EXPR)
+ code = GE_EXPR;
+ }
+ if (!wi::cmp (wi::add (real_c1, 1, sgn, &overflow), c1, sgn)
+ && !overflow)
+ {
+ /* X < Y + 1 equals to X <= Y. */
+ if (cmp_code == LT_EXPR)
+ code = LE_EXPR;
+ /* X >= Y + 1 equals to X > Y. */
+ if (cmp_code == GE_EXPR)
+ code = GT_EXPR;
+ }
+ if (code != cmp_code || !wi::cmp (real_c1, c1, sgn))
+ {
+ if (cmp_code == LT_EXPR || cmp_code == LE_EXPR)
+ code = MIN_EXPR;
+ if (cmp_code == GT_EXPR || cmp_code == GE_EXPR)
+ code = MAX_EXPR;
+ }
+ }
+ }
+ (if (code == MAX_EXPR)
+ (op (max @X { wide_int_to_tree (from_type, real_c1); })
+ { wide_int_to_tree (from_type, c2); })
+ (if (code == MIN_EXPR)
+ (op (min @X { wide_int_to_tree (from_type, real_c1); })
+ { wide_int_to_tree (from_type, c2); })))))))))
+
(for cnd (cond vec_cond)
/* A ? B : (A ? X : C) -> A ? B : C. */
(simplify