aboutsummaryrefslogtreecommitdiff
path: root/gcc/match.pd
diff options
context:
space:
mode:
authorJeff Law <law@redhat.com>2015-02-13 13:17:55 -0700
committerJeff Law <law@gcc.gnu.org>2015-02-13 13:17:55 -0700
commitbe1448389ab3038cccba3ed99e157bd6842ef88f (patch)
tree79bec4c1dc64b01a597c72371d5e618363458405 /gcc/match.pd
parentd05022766b7e692567e24198d44b91253c4a2625 (diff)
downloadgcc-be1448389ab3038cccba3ed99e157bd6842ef88f.zip
gcc-be1448389ab3038cccba3ed99e157bd6842ef88f.tar.gz
gcc-be1448389ab3038cccba3ed99e157bd6842ef88f.tar.bz2
re PR rtl-optimization/47477 (Sub-optimal mov at end of method)
PR rtl-optimization/47477 * match.pd (convert (plus/minus (convert @0) (convert @1): New simplifier to narrow arithmetic. PR rtl-optimization/47477 * gcc.dg/tree-ssa/pr47477.c: New test. From-SVN: r220695
Diffstat (limited to 'gcc/match.pd')
-rw-r--r--gcc/match.pd41
1 files changed, 41 insertions, 0 deletions
diff --git a/gcc/match.pd b/gcc/match.pd
index 81c4ee6..d438179 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -1018,3 +1018,44 @@ along with GCC; see the file COPYING3. If not see
(logs (pows @0 @1))
(mult @1 (logs @0)))))
+/* Narrowing of arithmetic and logical operations.
+
+ These are conceptually similar to the transformations performed for
+ the C/C++ front-ends by shorten_binary_op and shorten_compare. Long
+ term we want to move all that code out of the front-ends into here. */
+
+/* If we have a narrowing conversion of an arithmetic operation where
+ both operands are widening conversions from the same type as the outer
+ narrowing conversion. Then convert the innermost operands to a suitable
+ unsigned type (to avoid introducing undefined behaviour), perform the
+ operation and convert the result to the desired type. */
+(for op (plus minus)
+ (simplify
+ (convert (op (convert@2 @0) (convert@3 @1)))
+ (if (INTEGRAL_TYPE_P (type)
+ /* We check for type compatibility between @0 and @1 below,
+ so there's no need to check that @1/@3 are integral types. */
+ && INTEGRAL_TYPE_P (TREE_TYPE (@0))
+ && INTEGRAL_TYPE_P (TREE_TYPE (@2))
+ /* The precision of the type of each operand must match the
+ precision of the mode of each operand, similarly for the
+ result. */
+ && (TYPE_PRECISION (TREE_TYPE (@0))
+ == GET_MODE_PRECISION (TYPE_MODE (TREE_TYPE (@0))))
+ && (TYPE_PRECISION (TREE_TYPE (@1))
+ == GET_MODE_PRECISION (TYPE_MODE (TREE_TYPE (@1))))
+ && TYPE_PRECISION (type) == GET_MODE_PRECISION (TYPE_MODE (type))
+ /* The inner conversion must be a widening conversion. */
+ && TYPE_PRECISION (TREE_TYPE (@2)) > TYPE_PRECISION (TREE_TYPE (@0))
+ && ((GENERIC
+ && (TYPE_MAIN_VARIANT (TREE_TYPE (@0))
+ == TYPE_MAIN_VARIANT (TREE_TYPE (@1)))
+ && (TYPE_MAIN_VARIANT (TREE_TYPE (@0))
+ == TYPE_MAIN_VARIANT (type)))
+ || (GIMPLE
+ && types_compatible_p (TREE_TYPE (@0), TREE_TYPE (@1))
+ && types_compatible_p (TREE_TYPE (@0), type))))
+ (if (TYPE_OVERFLOW_WRAPS (TREE_TYPE (@0)))
+ (convert (op @0 @1)))
+ (with { tree utype = unsigned_type_for (TREE_TYPE (@0)); }
+ (convert (op (convert:utype @0) (convert:utype @1)))))))