From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 112940 invoked by alias); 24 Nov 2015 20:54:03 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Received: (qmail 112929 invoked by uid 89); 24 Nov 2015 20:54:02 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-0.7 required=5.0 tests=AWL,BAYES_50,RP_MATCHES_RCVD,SPF_HELO_PASS autolearn=ham version=3.3.2 X-HELO: mx1.redhat.com Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES256-GCM-SHA384 encrypted) ESMTPS; Tue, 24 Nov 2015 20:53:59 +0000 Received: from int-mx11.intmail.prod.int.phx2.redhat.com (int-mx11.intmail.prod.int.phx2.redhat.com [10.5.11.24]) by mx1.redhat.com (Postfix) with ESMTPS id D563F5D; Tue, 24 Nov 2015 20:53:57 +0000 (UTC) Received: from tucnak.zalov.cz (ovpn-116-34.ams2.redhat.com [10.36.116.34]) by int-mx11.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id tAOKrteU003452 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=NO); Tue, 24 Nov 2015 15:53:56 -0500 Received: from tucnak.zalov.cz (localhost [127.0.0.1]) by tucnak.zalov.cz (8.15.2/8.15.2) with ESMTP id tAOKrswd019439; Tue, 24 Nov 2015 21:53:54 +0100 Received: (from jakub@localhost) by tucnak.zalov.cz (8.15.2/8.15.2/Submit) id tAOKrqPw019438; Tue, 24 Nov 2015 21:53:52 +0100 Date: Tue, 24 Nov 2015 20:55:00 -0000 From: Jakub Jelinek To: Richard Biener Cc: gcc-patches@gcc.gnu.org, Richard Henderson Subject: [PATCH] Convert manual unsigned +/- overflow checking into {ADD,SUB}_OVERFLOW (PR target/67089) Message-ID: <20151124205352.GS5675@tucnak.redhat.com> Reply-To: Jakub Jelinek MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline User-Agent: Mutt/1.5.23 (2014-03-12) X-IsSubscribed: yes X-SW-Source: 2015-11/txt/msg02963.txt.bz2 Hi! This is the GIMPLE side of Richard's i?86 uadd/usub overflow testing improvements. If unsigned addition or subtraction result is used both normally and in a GIMPLE_COND/COND_EXPR/tcc_comparison that tests if unsigned overflow happened, the patch replaces it shortly before expansion with {ADD,SUB}_OVERFLOW, so that RTL expansion can generate better code on it. Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk? 2015-11-24 Jakub Jelinek PR target/67089 * tree-ssa-math-opts.c (uaddsub_overflow_check_p, match_uaddsub_overflow): New functions. (pass_optimize_widening_mul::execute): Call match_uaddsub_overflow. * gcc.dg/pr67089-1.c: New test. * gcc.dg/pr67089-2.c: New test. * gcc.dg/pr67089-3.c: New test. * gcc.dg/pr67089-4.c: New test. * gcc.dg/pr67089-5.c: New test. * gcc.dg/pr67089-6.c: New test. * gcc.dg/pr67089-7.c: New test. --- gcc/tree-ssa-math-opts.c.jj 2015-11-18 11:19:23.000000000 +0100 +++ gcc/tree-ssa-math-opts.c 2015-11-24 17:00:10.825900958 +0100 @@ -3491,6 +3491,189 @@ convert_mult_to_fma (gimple *mul_stmt, t return true; } + +/* Helper function of match_uaddsub_overflow. Return 1 + if USE_STMT is unsigned overflow check ovf != 0 for + STMT, -1 if USE_STMT is unsigned overflow check ovf == 0 + and 0 otherwise. */ + +static int +uaddsub_overflow_check_p (gimple *stmt, gimple *use_stmt) +{ + enum tree_code ccode = ERROR_MARK; + tree crhs1 = NULL_TREE, crhs2 = NULL_TREE; + if (gimple_code (use_stmt) == GIMPLE_COND) + { + ccode = gimple_cond_code (use_stmt); + crhs1 = gimple_cond_lhs (use_stmt); + crhs2 = gimple_cond_rhs (use_stmt); + } + else if (is_gimple_assign (use_stmt)) + { + if (gimple_assign_rhs_class (use_stmt) == GIMPLE_BINARY_RHS) + { + ccode = gimple_assign_rhs_code (use_stmt); + crhs1 = gimple_assign_rhs1 (use_stmt); + crhs2 = gimple_assign_rhs2 (use_stmt); + } + else if (gimple_assign_rhs_code (use_stmt) == COND_EXPR) + { + tree cond = gimple_assign_rhs1 (use_stmt); + if (COMPARISON_CLASS_P (cond)) + { + ccode = TREE_CODE (cond); + crhs1 = TREE_OPERAND (cond, 0); + crhs2 = TREE_OPERAND (cond, 1); + } + else + return 0; + } + else + return 0; + } + else + return 0; + + if (TREE_CODE_CLASS (ccode) != tcc_comparison) + return 0; + + enum tree_code code = gimple_assign_rhs_code (stmt); + tree lhs = gimple_assign_lhs (stmt); + tree rhs1 = gimple_assign_rhs1 (stmt); + tree rhs2 = gimple_assign_rhs2 (stmt); + + switch (ccode) + { + case GT_EXPR: + case LE_EXPR: + /* r = a - b; r > a or r <= a + r = a + b; a > r or a <= r or b > r or b <= r. */ + if ((code == MINUS_EXPR && crhs1 == lhs && crhs2 == rhs1) + || (code == PLUS_EXPR && (crhs1 == rhs1 || crhs1 == rhs2) + && crhs2 == lhs)) + return ccode == GT_EXPR ? 1 : -1; + break; + case LT_EXPR: + case GE_EXPR: + /* r = a - b; a < r or a >= r + r = a + b; r < a or r >= a or r < b or r >= b. */ + if ((code == MINUS_EXPR && crhs1 == rhs1 && crhs2 == lhs) + || (code == PLUS_EXPR && crhs1 == lhs + && (crhs2 == rhs1 || crhs2 == rhs2))) + return ccode == LT_EXPR ? 1 : -1; + break; + default: + break; + } + return 0; +} + +/* Recognize for unsigned x + x = y - z; + if (x > y) + where there are other uses of x and replace it with + _7 = SUB_OVERFLOW (y, z); + x = REALPART_EXPR <_7>; + _8 = IMAGPART_EXPR <_7>; + if (_8) + and similarly for addition. */ + +static bool +match_uaddsub_overflow (gimple_stmt_iterator *gsi, gimple *stmt, + enum tree_code code) +{ + tree lhs = gimple_assign_lhs (stmt); + tree type = TREE_TYPE (lhs); + use_operand_p use_p; + imm_use_iterator iter; + bool use_seen = false; + bool ovf_use_seen = false; + gimple *use_stmt; + + gcc_checking_assert (code == PLUS_EXPR || code == MINUS_EXPR); + if (!INTEGRAL_TYPE_P (type) + || !TYPE_UNSIGNED (type) + || has_zero_uses (lhs) + || has_single_use (lhs) + || optab_handler (code == PLUS_EXPR ? uaddv4_optab : usubv4_optab, + TYPE_MODE (type)) == CODE_FOR_nothing) + return false; + + FOR_EACH_IMM_USE_FAST (use_p, iter, lhs) + { + use_stmt = USE_STMT (use_p); + if (is_gimple_debug (use_stmt)) + continue; + + if (uaddsub_overflow_check_p (stmt, use_stmt)) + ovf_use_seen = true; + else + use_seen = true; + if (ovf_use_seen && use_seen) + break; + } + + if (!ovf_use_seen || !use_seen) + return false; + + tree ctype = build_complex_type (type); + tree rhs1 = gimple_assign_rhs1 (stmt); + tree rhs2 = gimple_assign_rhs2 (stmt); + gcall *g = gimple_build_call_internal (code == PLUS_EXPR + ? IFN_ADD_OVERFLOW : IFN_SUB_OVERFLOW, + 2, rhs1, rhs2); + tree ctmp = make_ssa_name (ctype); + gimple_call_set_lhs (g, ctmp); + gsi_insert_before (gsi, g, GSI_SAME_STMT); + gassign *g2 = gimple_build_assign (lhs, REALPART_EXPR, + build1 (REALPART_EXPR, type, ctmp)); + gsi_replace (gsi, g2, true); + tree ovf = make_ssa_name (type); + g2 = gimple_build_assign (ovf, IMAGPART_EXPR, + build1 (IMAGPART_EXPR, type, ctmp)); + gsi_insert_after (gsi, g2, GSI_NEW_STMT); + + FOR_EACH_IMM_USE_STMT (use_stmt, iter, lhs) + { + if (is_gimple_debug (use_stmt)) + continue; + + int ovf_use = uaddsub_overflow_check_p (stmt, use_stmt); + if (ovf_use == 0) + continue; + if (gimple_code (use_stmt) == GIMPLE_COND) + { + gcond *cond_stmt = as_a (use_stmt); + gimple_cond_set_lhs (cond_stmt, ovf); + gimple_cond_set_rhs (cond_stmt, build_int_cst (type, 0)); + gimple_cond_set_code (cond_stmt, ovf_use == 1 ? NE_EXPR : EQ_EXPR); + } + else + { + gcc_checking_assert (is_gimple_assign (use_stmt)); + if (gimple_assign_rhs_class (use_stmt) == GIMPLE_BINARY_RHS) + { + gimple_assign_set_rhs1 (use_stmt, ovf); + gimple_assign_set_rhs2 (use_stmt, build_int_cst (type, 0)); + gimple_assign_set_rhs_code (use_stmt, + ovf_use == 1 ? NE_EXPR : EQ_EXPR); + } + else + { + gcc_checking_assert (gimple_assign_rhs_code (use_stmt) + == COND_EXPR); + tree cond = build2 (ovf_use == 1 ? NE_EXPR : EQ_EXPR, + boolean_type_node, ovf, + build_int_cst (type, 0)); + gimple_assign_set_rhs1 (use_stmt, cond); + } + } + update_stmt (use_stmt); + } + return true; +} + + /* Find integer multiplications where the operands are extended from smaller types, and replace the MULT_EXPR with a WIDEN_MULT_EXPR where appropriate. */ @@ -3563,7 +3746,8 @@ pass_optimize_widening_mul::execute (fun case PLUS_EXPR: case MINUS_EXPR: - convert_plusminus_to_widen (&gsi, stmt, code); + if (!convert_plusminus_to_widen (&gsi, stmt, code)) + match_uaddsub_overflow (&gsi, stmt, code); break; default:; --- gcc/testsuite/gcc.dg/pr67089-1.c.jj 2015-11-24 18:16:30.817446026 +0100 +++ gcc/testsuite/gcc.dg/pr67089-1.c 2015-11-24 19:03:41.302284096 +0100 @@ -0,0 +1,112 @@ +/* PR target/67089 */ +/* { dg-do run } */ +/* { dg-options "-O2" } */ + +extern void abort (void); + +int cnt, d; + +__attribute__((noinline, noclone)) +void foo (int x) +{ + asm volatile ("" : "+m" (d) : "g" (x) : "memory"); + cnt++; +} + +#define T(n, type, op, cond) \ +__attribute__((noinline, noclone)) \ +type \ +f##n (type x, type y) \ +{ \ + type r = op; \ + cond; \ + return r; \ +} + +T (1, unsigned int, x - y, if (r > x) foo (0)) +T (2, unsigned long, x - y, if (r <= x) foo (0)) +T (3, unsigned short, x - y, if (x < r) foo (r)) +T (4, unsigned long long, x - y, if (x >= r) foo (0)) +T (5, unsigned int, x - y, if (r >= x) foo (0)) +T (6, unsigned long, x - y, if (r < x) foo (0)) +T (7, unsigned short, x - y, if (x <= r) foo (r)) +T (8, unsigned long long, x - y, if (d || x > r) foo (0)) +T (9, unsigned int, x - y, if (d || r > x) foo (0)) +T (10, unsigned long, x - y, if (d || r <= x) foo (0)) +T (11, unsigned char, x - y, if (d || x < r) foo (0)) +T (12, unsigned long long, x - y, if (d || x >= r) foo (0)) +T (13, unsigned int, x - y, if (d || r >= x) foo (0)) +T (14, unsigned long, x - y, if (d || r < x) foo (0)) +T (15, unsigned short, x - y, if (d || x <= r) foo (0)) +T (16, unsigned long long, x - y, if (d || x > r) foo (0)) + +int +main () +{ + if (f1 (5, 3) != 2U || cnt != 0) abort (); + if (f1 (5, 7) != -2U || cnt != 1) abort (); + if (f1 (5, 5) != 0U || cnt != 1) abort (); + if (f1 (5, 0) != 5U || cnt != 1) abort (); + if (f2 (7, 1) != 6UL || cnt != 2) abort (); + if (f2 (7, 8) != -1UL || cnt != 2) abort (); + if (f2 (9, 9) != 0UL || cnt != 3) abort (); + if (f2 (9, 0) != 9UL || cnt != 4) abort (); + if (f3 (15, 14) != 1 || cnt != 4) abort (); + if (f3 (15, 25) != (unsigned short) -10 || cnt != 5) abort (); + if (f3 (15, 15) != 0 || cnt != 5) abort (); + if (f3 (15, 0) != 15 || cnt != 5) abort (); + if (f4 (9132, 9127) != 5ULL || cnt != 6) abort (); + if (f4 (9132, 9137) != -5ULL || cnt != 6) abort (); + if (f4 (9132, 9132) != 0 || cnt != 7) abort (); + if (f4 (9132, 0) != 9132ULL || cnt != 8) abort (); + if (f5 (5, 3) != 2U || cnt != 8) abort (); + if (f5 (5, 7) != -2U || cnt != 9) abort (); + if (f5 (5, 5) != 0U || cnt != 9) abort (); + if (f5 (5, 0) != 5U || cnt != 10) abort (); + if (f6 (7, 1) != 6UL || cnt != 11) abort (); + if (f6 (7, 8) != -1UL || cnt != 11) abort (); + if (f6 (9, 9) != 0UL || cnt != 12) abort (); + if (f6 (9, 0) != 9UL || cnt != 12) abort (); + if (f7 (15, 14) != 1 || cnt != 12) abort (); + if (f7 (15, 25) != (unsigned short) -10 || cnt != 13) abort (); + if (f7 (15, 15) != 0 || cnt != 13) abort (); + if (f7 (15, 0) != 15 || cnt != 14) abort (); + if (f8 (9132, 9127) != 5ULL || cnt != 15) abort (); + if (f8 (9132, 9137) != -5ULL || cnt != 15) abort (); + if (f8 (9132, 9132) != 0 || cnt != 16) abort (); + if (f8 (9132, 0) != 9132ULL || cnt != 16) abort (); + cnt = 0; + if (f9 (5, 3) != 2U || cnt != 0) abort (); + if (f9 (5, 7) != -2U || cnt != 1) abort (); + if (f9 (5, 5) != 0U || cnt != 1) abort (); + if (f9 (5, 0) != 5U || cnt != 1) abort (); + if (f10 (7, 1) != 6UL || cnt != 2) abort (); + if (f10 (7, 8) != -1UL || cnt != 2) abort (); + if (f10 (9, 9) != 0UL || cnt != 3) abort (); + if (f10 (9, 0) != 9UL || cnt != 4) abort (); + if (f11 (15, 14) != 1 || cnt != 4) abort (); + if (f11 (15, 25) != (unsigned char) -10 || cnt != 5) abort (); + if (f11 (15, 15) != 0 || cnt != 5) abort (); + if (f11 (15, 0) != 15 || cnt != 5) abort (); + if (f12 (9132, 9127) != 5ULL || cnt != 6) abort (); + if (f12 (9132, 9137) != -5ULL || cnt != 6) abort (); + if (f12 (9132, 9132) != 0 || cnt != 7) abort (); + if (f12 (9132, 0) != 9132ULL || cnt != 8) abort (); + if (f13 (5, 3) != 2U || cnt != 8) abort (); + if (f13 (5, 7) != -2U || cnt != 9) abort (); + if (f13 (5, 5) != 0U || cnt != 9) abort (); + if (f13 (5, 0) != 5U || cnt != 10) abort (); + if (f14 (7, 1) != 6UL || cnt != 11) abort (); + if (f14 (7, 8) != -1UL || cnt != 11) abort (); + if (f14 (9, 9) != 0UL || cnt != 12) abort (); + if (f14 (9, 0) != 9UL || cnt != 12) abort (); + if (f15 (15, 14) != 1 || cnt != 12) abort (); + if (f15 (15, 25) != (unsigned short) -10 || cnt != 13) abort (); + if (f15 (15, 15) != 0 || cnt != 13) abort (); + if (f15 (15, 0) != 15 || cnt != 14) abort (); + if (f16 (9132, 9127) != 5ULL || cnt != 15) abort (); + if (f16 (9132, 9137) != -5ULL || cnt != 15) abort (); + if (f16 (9132, 9132) != 0 || cnt != 16) abort (); + if (f16 (9132, 0) != 9132ULL || cnt != 16) abort (); + return 0; +} --- gcc/testsuite/gcc.dg/pr67089-2.c.jj 2015-11-24 18:18:51.804434548 +0100 +++ gcc/testsuite/gcc.dg/pr67089-2.c 2015-11-24 19:03:44.769234628 +0100 @@ -0,0 +1,112 @@ +/* PR target/67089 */ +/* { dg-do run } */ +/* { dg-options "-O2" } */ + +extern void abort (void); + +int cnt, d; + +__attribute__((noinline, noclone)) +void foo (int x) +{ + asm volatile ("" : "+m" (d) : "g" (x) : "memory"); + cnt++; +} + +#define T(n, type, op, cond) \ +__attribute__((noinline, noclone)) \ +type \ +f##n (type x, type y) \ +{ \ + type r = op; \ + cond; \ + return r; \ +} + +T (1, unsigned int, x - y, if (r > y) foo (0)) +T (2, unsigned long, x - y, if (r <= y) foo (0)) +T (3, unsigned short, x - y, if (y < r) foo (r)) +T (4, unsigned long long, x - y, if (y >= r) foo (0)) +T (5, unsigned int, x - y, if (r >= y) foo (0)) +T (6, unsigned long, x - y, if (r < y) foo (0)) +T (7, unsigned short, x - y, if (y <= r) foo (r)) +T (8, unsigned long long, x - y, if (d || y > r) foo (0)) +T (9, unsigned int, x - y, if (d || r > y) foo (0)) +T (10, unsigned long, x - y, if (d || r <= y) foo (0)) +T (11, unsigned char, x - y, if (d || y < r) foo (0)) +T (12, unsigned long long, x - y, if (d || y >= r) foo (0)) +T (13, unsigned int, x - y, if (d || r >= y) foo (0)) +T (14, unsigned long, x - y, if (d || r < y) foo (0)) +T (15, unsigned short, x - y, if (d || y <= r) foo (0)) +T (16, unsigned long long, x - y, if (d || y > r) foo (0)) + +int +main () +{ + if (f1 (5, 3) != 2U || cnt != 0) abort (); + if (f1 (5, 7) != -2U || cnt != 1) abort (); + if (f1 (5, 5) != 0U || cnt != 1) abort (); + if (f1 (5, 0) != 5U || cnt != 2) abort (); + if (f2 (7, 1) != 6UL || cnt != 2) abort (); + if (f2 (7, 8) != -1UL || cnt != 2) abort (); + if (f2 (9, 9) != 0UL || cnt != 3) abort (); + if (f2 (9, 0) != 9UL || cnt != 3) abort (); + if (f3 (15, 14) != 1 || cnt != 3) abort (); + if (f3 (15, 25) != (unsigned short) -10 || cnt != 4) abort (); + if (f3 (15, 15) != 0 || cnt != 4) abort (); + if (f3 (15, 0) != 15 || cnt != 5) abort (); + if (f4 (9132, 9127) != 5ULL || cnt != 6) abort (); + if (f4 (9132, 9137) != -5ULL || cnt != 6) abort (); + if (f4 (9132, 9132) != 0 || cnt != 7) abort (); + if (f4 (9132, 0) != 9132ULL || cnt != 7) abort (); + if (f5 (5, 3) != 2U || cnt != 7) abort (); + if (f5 (5, 7) != -2U || cnt != 8) abort (); + if (f5 (5, 5) != 0U || cnt != 8) abort (); + if (f5 (5, 0) != 5U || cnt != 9) abort (); + if (f6 (7, 1) != 6UL || cnt != 9) abort (); + if (f6 (7, 8) != -1UL || cnt != 9) abort (); + if (f6 (9, 9) != 0UL || cnt != 10) abort (); + if (f6 (9, 0) != 9UL || cnt != 10) abort (); + if (f7 (15, 14) != 1 || cnt != 10) abort (); + if (f7 (15, 25) != (unsigned short) -10 || cnt != 11) abort (); + if (f7 (15, 15) != 0 || cnt != 11) abort (); + if (f7 (15, 0) != 15 || cnt != 12) abort (); + if (f8 (9132, 9127) != 5ULL || cnt != 13) abort (); + if (f8 (9132, 9137) != -5ULL || cnt != 13) abort (); + if (f8 (9132, 9132) != 0 || cnt != 14) abort (); + if (f8 (9132, 0) != 9132ULL || cnt != 14) abort (); + cnt = 0; + if (f9 (5, 3) != 2U || cnt != 0) abort (); + if (f9 (5, 7) != -2U || cnt != 1) abort (); + if (f9 (5, 5) != 0U || cnt != 1) abort (); + if (f9 (5, 0) != 5U || cnt != 2) abort (); + if (f10 (7, 1) != 6UL || cnt != 2) abort (); + if (f10 (7, 8) != -1UL || cnt != 2) abort (); + if (f10 (9, 9) != 0UL || cnt != 3) abort (); + if (f10 (9, 0) != 9UL || cnt != 3) abort (); + if (f11 (15, 14) != 1 || cnt != 3) abort (); + if (f11 (15, 25) != (unsigned char) -10 || cnt != 4) abort (); + if (f11 (15, 15) != 0 || cnt != 4) abort (); + if (f11 (15, 0) != 15 || cnt != 5) abort (); + if (f12 (9132, 9127) != 5ULL || cnt != 6) abort (); + if (f12 (9132, 9137) != -5ULL || cnt != 6) abort (); + if (f12 (9132, 9132) != 0 || cnt != 7) abort (); + if (f12 (9132, 0) != 9132ULL || cnt != 7) abort (); + if (f13 (5, 3) != 2U || cnt != 7) abort (); + if (f13 (5, 7) != -2U || cnt != 8) abort (); + if (f13 (5, 5) != 0U || cnt != 8) abort (); + if (f13 (5, 0) != 5U || cnt != 9) abort (); + if (f14 (7, 1) != 6UL || cnt != 9) abort (); + if (f14 (7, 8) != -1UL || cnt != 9) abort (); + if (f14 (9, 9) != 0UL || cnt != 10) abort (); + if (f14 (9, 0) != 9UL || cnt != 10) abort (); + if (f15 (15, 14) != 1 || cnt != 10) abort (); + if (f15 (15, 25) != (unsigned short) -10 || cnt != 11) abort (); + if (f15 (15, 15) != 0 || cnt != 11) abort (); + if (f15 (15, 0) != 15 || cnt != 12) abort (); + if (f16 (9132, 9127) != 5ULL || cnt != 13) abort (); + if (f16 (9132, 9137) != -5ULL || cnt != 13) abort (); + if (f16 (9132, 9132) != 0 || cnt != 14) abort (); + if (f16 (9132, 0) != 9132ULL || cnt != 14) abort (); + return 0; +} --- gcc/testsuite/gcc.dg/pr67089-3.c.jj 2015-11-24 18:28:05.788530792 +0100 +++ gcc/testsuite/gcc.dg/pr67089-3.c 2015-11-24 19:03:48.375183177 +0100 @@ -0,0 +1,112 @@ +/* PR target/67089 */ +/* { dg-do run } */ +/* { dg-options "-O2" } */ + +extern void abort (void); + +int cnt, d; + +__attribute__((noinline, noclone)) +void foo (int x) +{ + asm volatile ("" : "+m" (d) : "g" (x) : "memory"); + cnt++; +} + +#define T(n, type, op, cond) \ +__attribute__((noinline, noclone)) \ +type \ +f##n (type x, type y) \ +{ \ + type r = op; \ + cond; \ + return r; \ +} + +T (1, unsigned int, x + y, if (r > x) foo (0)) +T (2, unsigned long, x + y, if (r <= x) foo (0)) +T (3, unsigned short, x + y, if (x < r) foo (r)) +T (4, unsigned long long, x + y, if (x >= r) foo (0)) +T (5, unsigned int, x + y, if (r >= x) foo (0)) +T (6, unsigned long, x + y, if (r < x) foo (0)) +T (7, unsigned short, x + y, if (x <= r) foo (r)) +T (8, unsigned long long, x + y, if (d || x > r) foo (0)) +T (9, unsigned int, x + y, if (d || r > x) foo (0)) +T (10, unsigned long, x + y, if (d || r <= x) foo (0)) +T (11, unsigned char, x + y, if (d || x < r) foo (0)) +T (12, unsigned long long, x + y, if (d || x >= r) foo (0)) +T (13, unsigned int, x + y, if (d || r >= x) foo (0)) +T (14, unsigned long, x + y, if (d || r < x) foo (0)) +T (15, unsigned short, x + y, if (d || x <= r) foo (0)) +T (16, unsigned long long, x + y, if (d || x > r) foo (0)) + +int +main () +{ + if (f1 (-7U, 0) != -7U || cnt != 0) abort (); + if (f1 (-7U, 6) != -1U || cnt != 1) abort (); + if (f1 (-7U, 7) != 0U || cnt != 1) abort (); + if (f1 (-7U, 8) != 1U || cnt != 1) abort (); + if (f2 (-9UL, 0) != -9UL || cnt != 2) abort (); + if (f2 (-9UL, 8) != -1UL || cnt != 2) abort (); + if (f2 (-9UL, 9) != 0UL || cnt != 3) abort (); + if (f2 (-9UL, 10) != 1UL || cnt != 4) abort (); + if (f3 (-15, 0) != (unsigned short) -15 || cnt != 4) abort (); + if (f3 (-15, 14) != (unsigned short) -1 || cnt != 5) abort (); + if (f3 (-15, 15) != 0 || cnt != 5) abort (); + if (f3 (-15, 16) != 1 || cnt != 5) abort (); + if (f4 (-9132ULL, 0) != -9132ULL || cnt != 6) abort (); + if (f4 (-9132ULL, 9131) != -1ULL || cnt != 6) abort (); + if (f4 (-9132ULL, 9132) != 0 || cnt != 7) abort (); + if (f4 (-9132ULL, 9133) != 1ULL || cnt != 8) abort (); + if (f5 (-7U, 0) != -7U || cnt != 9) abort (); + if (f5 (-7U, 6) != -1U || cnt != 10) abort (); + if (f5 (-7U, 7) != 0U || cnt != 10) abort (); + if (f5 (-7U, 8) != 1U || cnt != 10) abort (); + if (f6 (-9UL, 0) != -9UL || cnt != 10) abort (); + if (f6 (-9UL, 8) != -1UL || cnt != 10) abort (); + if (f6 (-9UL, 9) != 0UL || cnt != 11) abort (); + if (f6 (-9UL, 10) != 1UL || cnt != 12) abort (); + if (f7 (-15, 0) != (unsigned short) -15 || cnt != 13) abort (); + if (f7 (-15, 14) != (unsigned short) -1 || cnt != 14) abort (); + if (f7 (-15, 15) != 0 || cnt != 14) abort (); + if (f7 (-15, 16) != 1 || cnt != 14) abort (); + if (f8 (-9132ULL, 0) != -9132ULL || cnt != 14) abort (); + if (f8 (-9132ULL, 9131) != -1ULL || cnt != 14) abort (); + if (f8 (-9132ULL, 9132) != 0 || cnt != 15) abort (); + if (f8 (-9132ULL, 9133) != 1ULL || cnt != 16) abort (); + cnt = 0; + if (f9 (-7U, 0) != -7U || cnt != 0) abort (); + if (f9 (-7U, 6) != -1U || cnt != 1) abort (); + if (f9 (-7U, 7) != 0U || cnt != 1) abort (); + if (f9 (-7U, 8) != 1U || cnt != 1) abort (); + if (f10 (-9UL, 0) != -9UL || cnt != 2) abort (); + if (f10 (-9UL, 8) != -1UL || cnt != 2) abort (); + if (f10 (-9UL, 9) != 0UL || cnt != 3) abort (); + if (f10 (-9UL, 10) != 1UL || cnt != 4) abort (); + if (f11 (-15, 0) != (unsigned char) -15 || cnt != 4) abort (); + if (f11 (-15, 14) != (unsigned char) -1 || cnt != 5) abort (); + if (f11 (-15, 15) != 0 || cnt != 5) abort (); + if (f11 (-15, 16) != 1 || cnt != 5) abort (); + if (f12 (-9132ULL, 0) != -9132ULL || cnt != 6) abort (); + if (f12 (-9132ULL, 9131) != -1ULL || cnt != 6) abort (); + if (f12 (-9132ULL, 9132) != 0 || cnt != 7) abort (); + if (f12 (-9132ULL, 9133) != 1ULL || cnt != 8) abort (); + if (f13 (-7U, 0) != -7U || cnt != 9) abort (); + if (f13 (-7U, 6) != -1U || cnt != 10) abort (); + if (f13 (-7U, 7) != 0U || cnt != 10) abort (); + if (f13 (-7U, 8) != 1U || cnt != 10) abort (); + if (f14 (-9UL, 0) != -9UL || cnt != 10) abort (); + if (f14 (-9UL, 8) != -1UL || cnt != 10) abort (); + if (f14 (-9UL, 9) != 0UL || cnt != 11) abort (); + if (f14 (-9UL, 10) != 1UL || cnt != 12) abort (); + if (f15 (-15, 0) != (unsigned short) -15 || cnt != 13) abort (); + if (f15 (-15, 14) != (unsigned short) -1 || cnt != 14) abort (); + if (f15 (-15, 15) != 0 || cnt != 14) abort (); + if (f15 (-15, 16) != 1 || cnt != 14) abort (); + if (f16 (-9132ULL, 0) != -9132ULL || cnt != 14) abort (); + if (f16 (-9132ULL, 9131) != -1ULL || cnt != 14) abort (); + if (f16 (-9132ULL, 9132) != 0 || cnt != 15) abort (); + if (f16 (-9132ULL, 9133) != 1ULL || cnt != 16) abort (); + return 0; +} --- gcc/testsuite/gcc.dg/pr67089-4.c.jj 2015-11-24 18:42:04.482600934 +0100 +++ gcc/testsuite/gcc.dg/pr67089-4.c 2015-11-24 19:15:19.155412082 +0100 @@ -0,0 +1,112 @@ +/* PR target/67089 */ +/* { dg-do run } */ +/* { dg-options "-O2" } */ + +extern void abort (void); + +int cnt, d; + +__attribute__((noinline, noclone)) +void foo (int x) +{ + asm volatile ("" : "+m" (d) : "g" (x) : "memory"); + cnt++; +} + +#define T(n, type, op, cond) \ +__attribute__((noinline, noclone)) \ +type \ +f##n (type x, type y) \ +{ \ + type r = op; \ + cond; \ + return r; \ +} + +T (1, unsigned int, x + y, if (r > y) foo (0)) +T (2, unsigned long, x + y, if (r <= y) foo (0)) +T (3, unsigned short, x + y, if (y < r) foo (r)) +T (4, unsigned long long, x + y, if (y >= r) foo (0)) +T (5, unsigned int, x + y, if (r >= y) foo (0)) +T (6, unsigned long, x + y, if (r < y) foo (0)) +T (7, unsigned short, x + y, if (y <= r) foo (r)) +T (8, unsigned long long, x + y, if (d || y > r) foo (0)) +T (9, unsigned int, x + y, if (d || r > y) foo (0)) +T (10, unsigned long, x + y, if (d || r <= y) foo (0)) +T (11, unsigned char, x + y, if (d || y < r) foo (0)) +T (12, unsigned long long, x + y, if (d || y >= r) foo (0)) +T (13, unsigned int, x + y, if (d || r >= y) foo (0)) +T (14, unsigned long, x + y, if (d || r < y) foo (0)) +T (15, unsigned short, x + y, if (d || y <= r) foo (0)) +T (16, unsigned long long, x + y, if (d || y > r) foo (0)) + +int +main () +{ + if (f1 (-7U, 0) != -7U || cnt != 1) abort (); + if (f1 (-7U, 6) != -1U || cnt != 2) abort (); + if (f1 (-7U, 7) != 0U || cnt != 2) abort (); + if (f1 (-7U, 8) != 1U || cnt != 2) abort (); + if (f2 (-9UL, 0) != -9UL || cnt != 2) abort (); + if (f2 (-9UL, 8) != -1UL || cnt != 2) abort (); + if (f2 (-9UL, 9) != 0UL || cnt != 3) abort (); + if (f2 (-9UL, 10) != 1UL || cnt != 4) abort (); + if (f3 (-15, 0) != (unsigned short) -15 || cnt != 5) abort (); + if (f3 (-15, 14) != (unsigned short) -1 || cnt != 6) abort (); + if (f3 (-15, 15) != 0 || cnt != 6) abort (); + if (f3 (-15, 16) != 1 || cnt != 6) abort (); + if (f4 (-9132ULL, 0) != -9132ULL || cnt != 6) abort (); + if (f4 (-9132ULL, 9131) != -1ULL || cnt != 6) abort (); + if (f4 (-9132ULL, 9132) != 0 || cnt != 7) abort (); + if (f4 (-9132ULL, 9133) != 1ULL || cnt != 8) abort (); + if (f5 (-7U, 0) != -7U || cnt != 9) abort (); + if (f5 (-7U, 6) != -1U || cnt != 10) abort (); + if (f5 (-7U, 7) != 0U || cnt != 10) abort (); + if (f5 (-7U, 8) != 1U || cnt != 10) abort (); + if (f6 (-9UL, 0) != -9UL || cnt != 10) abort (); + if (f6 (-9UL, 8) != -1UL || cnt != 10) abort (); + if (f6 (-9UL, 9) != 0UL || cnt != 11) abort (); + if (f6 (-9UL, 10) != 1UL || cnt != 12) abort (); + if (f7 (-15, 0) != (unsigned short) -15 || cnt != 13) abort (); + if (f7 (-15, 14) != (unsigned short) -1 || cnt != 14) abort (); + if (f7 (-15, 15) != 0 || cnt != 14) abort (); + if (f7 (-15, 16) != 1 || cnt != 14) abort (); + if (f8 (-9132ULL, 0) != -9132ULL || cnt != 14) abort (); + if (f8 (-9132ULL, 9131) != -1ULL || cnt != 14) abort (); + if (f8 (-9132ULL, 9132) != 0 || cnt != 15) abort (); + if (f8 (-9132ULL, 9133) != 1ULL || cnt != 16) abort (); + cnt = 0; + if (f9 (-7U, 0) != -7U || cnt != 1) abort (); + if (f9 (-7U, 6) != -1U || cnt != 2) abort (); + if (f9 (-7U, 7) != 0U || cnt != 2) abort (); + if (f9 (-7U, 8) != 1U || cnt != 2) abort (); + if (f10 (-9UL, 0) != -9UL || cnt != 2) abort (); + if (f10 (-9UL, 8) != -1UL || cnt != 2) abort (); + if (f10 (-9UL, 9) != 0UL || cnt != 3) abort (); + if (f10 (-9UL, 10) != 1UL || cnt != 4) abort (); + if (f11 (-15, 0) != (unsigned char) -15 || cnt != 5) abort (); + if (f11 (-15, 14) != (unsigned char) -1 || cnt != 6) abort (); + if (f11 (-15, 15) != 0 || cnt != 6) abort (); + if (f11 (-15, 16) != 1 || cnt != 6) abort (); + if (f12 (-9132ULL, 0) != -9132ULL || cnt != 6) abort (); + if (f12 (-9132ULL, 9131) != -1ULL || cnt != 6) abort (); + if (f12 (-9132ULL, 9132) != 0 || cnt != 7) abort (); + if (f12 (-9132ULL, 9133) != 1ULL || cnt != 8) abort (); + if (f13 (-7U, 0) != -7U || cnt != 9) abort (); + if (f13 (-7U, 6) != -1U || cnt != 10) abort (); + if (f13 (-7U, 7) != 0U || cnt != 10) abort (); + if (f13 (-7U, 8) != 1U || cnt != 10) abort (); + if (f14 (-9UL, 0) != -9UL || cnt != 10) abort (); + if (f14 (-9UL, 8) != -1UL || cnt != 10) abort (); + if (f14 (-9UL, 9) != 0UL || cnt != 11) abort (); + if (f14 (-9UL, 10) != 1UL || cnt != 12) abort (); + if (f15 (-15, 0) != (unsigned short) -15 || cnt != 13) abort (); + if (f15 (-15, 14) != (unsigned short) -1 || cnt != 14) abort (); + if (f15 (-15, 15) != 0 || cnt != 14) abort (); + if (f15 (-15, 16) != 1 || cnt != 14) abort (); + if (f16 (-9132ULL, 0) != -9132ULL || cnt != 14) abort (); + if (f16 (-9132ULL, 9131) != -1ULL || cnt != 14) abort (); + if (f16 (-9132ULL, 9132) != 0 || cnt != 15) abort (); + if (f16 (-9132ULL, 9133) != 1ULL || cnt != 16) abort (); + return 0; +} --- gcc/testsuite/gcc.dg/pr67089-5.c.jj 2015-11-24 19:03:19.571594157 +0100 +++ gcc/testsuite/gcc.dg/pr67089-5.c 2015-11-24 19:31:29.707645365 +0100 @@ -0,0 +1,82 @@ +/* PR target/67089 */ +/* { dg-do run } */ +/* { dg-options "-O2 -ftree-loop-if-convert" } */ + +extern void abort (void); + +int cnt; +unsigned int a[16], b[16], c[16]; + +__attribute__((noinline, noclone)) +void foo (int x) +{ + asm volatile ("" : : "g" (x) : "memory"); + cnt++; +} + +__attribute__((noinline, noclone)) void +f0 (unsigned int x) +{ + for (int i = 0; i < 16; i++) + { + unsigned int r = x - a[i]; + b[i] = r; + c[i] = r > x ? 7 : x; + } +} + +#define T(n, type, op, cond) \ +__attribute__((noinline, noclone)) \ +type \ +f##n (type x) \ +{ \ + type r = op; \ + cond; \ + return r; \ +} + +T (1, unsigned int, x - 2U, if (r > x) foo (0)) +T (2, unsigned long, x - 2U, if (r <= x) foo (0)) +T (3, unsigned short, 2U - x, if (r > 2U) foo (0)) +T (4, unsigned char, 2U - x, if (r <= 2U) foo (0)) +T (5, unsigned int, x + -2U, if (r > x) foo (0)) +T (6, unsigned long, x + -2UL, if (r <= x) foo (0)) +T (7, unsigned short, (unsigned short) -2 + x, if (r > (unsigned short) -2) foo (0)) +T (8, unsigned char, (unsigned char) -2 + x, if (r <= (unsigned char) -2) foo (0)) + +int +main () +{ + int i; + for (i = 0; i < 16; i++) + a[i] = i - 7; + f0 (5); + for (i = 0; i < 16; i++) + if (b[i] != 12U - i || c[i] != 7 - 2 * (i >= 7 && i < 13)) + abort (); + if (f1 (3) != 1 || cnt != 0) abort (); + if (f1 (2) != 0 || cnt != 0) abort (); + if (f1 (1) != -1U || cnt != 1) abort (); + if (f2 (3) != 1 || cnt != 2) abort (); + if (f2 (2) != 0 || cnt != 3) abort (); + if (f2 (1) != -1UL || cnt != 3) abort (); + if (f3 (3) != (unsigned short) -1 || cnt != 4) abort (); + if (f3 (2) != 0 || cnt != 4) abort (); + if (f3 (1) != 1 || cnt != 4) abort (); + if (f4 (3) != (unsigned char) -1 || cnt != 4) abort (); + if (f4 (2) != 0 || cnt != 5) abort (); + if (f4 (1) != 1 || cnt != 6) abort (); + if (f5 (3) != 1 || cnt != 6) abort (); + if (f5 (2) != 0 || cnt != 6) abort (); + if (f5 (1) != -1U || cnt != 7) abort (); + if (f6 (3) != 1 || cnt != 8) abort (); + if (f6 (2) != 0 || cnt != 9) abort (); + if (f6 (1) != -1UL || cnt != 9) abort (); + if (f7 (3) != 1 || cnt != 9) abort (); + if (f7 (2) != 0 || cnt != 9) abort (); + if (f7 (1) != (unsigned short) -1 || cnt != 10) abort (); + if (f8 (3) != 1 || cnt != 11) abort (); + if (f8 (2) != 0 || cnt != 12) abort (); + if (f8 (1) != (unsigned char) -1 || cnt != 12) abort (); + return 0; +} --- gcc/testsuite/gcc.dg/pr67089-6.c.jj 2015-11-24 19:16:02.898794422 +0100 +++ gcc/testsuite/gcc.dg/pr67089-6.c 2015-11-24 19:32:09.928077054 +0100 @@ -0,0 +1,62 @@ +/* PR target/67089 */ +/* { dg-do compile } */ +/* { dg-options "-O2 -ftree-loop-if-convert -fdump-tree-widening_mul" } */ + +extern void abort (void); + +int cnt; +unsigned int a[16], b[16], c[16], d; +void foo (int x); + +__attribute__((noinline, noclone)) void +f0 (unsigned int x) +{ + for (int i = 0; i < 16; i++) + { + unsigned int r = x - a[i]; + b[i] = r; + c[i] = r > x ? 7 : x; + } +} + +#define T(n, type, op, cond) \ +__attribute__((noinline, noclone)) \ +type \ +f##n (type x, type y) \ +{ \ + type r = op; \ + cond; \ + return r; \ +} + +T (1, unsigned int, x - y, if (r > x) foo (0)) +T (2, unsigned long, x - y, if (r <= x) foo (0)) +T (3, unsigned short, x - y, if (x < r) foo (r)) +T (4, unsigned long long, x - y, if (x >= r) foo (0)) +T (5, unsigned int, x - y, if (d || r > x) foo (0)) +T (6, unsigned long, x - y, if (d || r <= x) foo (0)) +T (7, unsigned char, x - y, if (d || x < r) foo (0)) +T (8, unsigned long long, x - y, if (d || x >= r) foo (0)) +T (9, unsigned int, x + y, if (r >= x) foo (0)) +T (10, unsigned long, x + y, if (r < x) foo (0)) +T (11, unsigned short, x + y, if (x <= r) foo (r)) +T (12, unsigned long long, x + y, if (d || x > r) foo (0)) +T (13, unsigned int, x + y, if (d || r >= x) foo (0)) +T (14, unsigned long, x + y, if (d || r < x) foo (0)) +T (15, unsigned short, x + y, if (d || x <= r) foo (0)) +T (16, unsigned long long, x + y, if (d || x > r) foo (0)) +T (17, unsigned int, x + y, if (r >= y) foo (0)) +T (18, unsigned long, x + y, if (r < y) foo (0)) +T (19, unsigned short, x + y, if (y <= r) foo (r)) +T (20, unsigned long long, x + y, if (d || y > r) foo (0)) +T (21, unsigned int, x + y, if (d || r >= y) foo (0)) +T (22, unsigned long, x + y, if (d || r < y) foo (0)) +T (23, unsigned short, x + y, if (d || y <= r) foo (0)) +T (24, unsigned long long, x + y, if (d || y > r) foo (0)) +T (25, unsigned short, 2U - x, if (r > 2U) foo (0)) +T (26, unsigned char, 2U - x, if (r <= 2U) foo (0)) + +/* { dg-final { scan-tree-dump-times "ADD_OVERFLOW" 16 "widening_mul" { target { { i?86-*-* x86_64-*-* } && { ! ia32 } } } } } */ +/* { dg-final { scan-tree-dump-times "SUB_OVERFLOW" 11 "widening_mul" { target { { i?86-*-* x86_64-*-* } && { ! ia32 } } } } } */ +/* { dg-final { scan-tree-dump-times "ADD_OVERFLOW" 12 "widening_mul" { target { { i?86-*-* x86_64-*-* } && ia32 } } } } */ +/* { dg-final { scan-tree-dump-times "SUB_OVERFLOW" 9 "widening_mul" { target { { i?86-*-* x86_64-*-* } && ia32 } } } } */ --- gcc/testsuite/gcc.dg/pr67089-7.c.jj 2015-11-24 19:32:30.332788737 +0100 +++ gcc/testsuite/gcc.dg/pr67089-7.c 2015-11-24 19:37:12.304804499 +0100 @@ -0,0 +1,62 @@ +/* PR target/67089 */ +/* { dg-do compile } */ +/* { dg-options "-O2 -ftree-loop-if-convert -fdump-tree-widening_mul" } */ + +extern void abort (void); + +int cnt, d; +void foo (int x); + +#define T(n, type, op, cond) \ +__attribute__((noinline, noclone)) \ +type \ +f##n (type x, type y) \ +{ \ + type r = op; \ + cond; \ + return r; \ +} + +T (1, unsigned int, x - y, if (r >= x) foo (0)) +T (2, unsigned long, x - y, if (r < x) foo (0)) +T (3, unsigned short, x - y, if (x <= r) foo (r)) +T (4, unsigned long long, x - y, if (d || x > r) foo (0)) +T (5, unsigned int, x - y, if (d || r >= x) foo (0)) +T (6, unsigned long, x - y, if (d || r < x) foo (0)) +T (7, unsigned short, x - y, if (d || x <= r) foo (0)) +T (8, unsigned long long, x - y, if (d || x > r) foo (0)) +T (9, unsigned int, x - y, if (r > y) foo (0)) +T (10, unsigned long, x - y, if (r <= y) foo (0)) +T (11, unsigned short, x - y, if (y < r) foo (r)) +T (12, unsigned long long, x - y, if (y >= r) foo (0)) +T (13, unsigned int, x - y, if (r >= y) foo (0)) +T (14, unsigned long, x - y, if (r < y) foo (0)) +T (15, unsigned short, x - y, if (y <= r) foo (r)) +T (16, unsigned long long, x - y, if (d || y > r) foo (0)) +T (17, unsigned int, x - y, if (d || r > y) foo (0)) +T (18, unsigned long, x - y, if (d || r <= y) foo (0)) +T (19, unsigned char, x - y, if (d || y < r) foo (0)) +T (20, unsigned long long, x - y, if (d || y >= r) foo (0)) +T (21, unsigned int, x - y, if (d || r >= y) foo (0)) +T (22, unsigned long, x - y, if (d || r < y) foo (0)) +T (23, unsigned short, x - y, if (d || y <= r) foo (0)) +T (24, unsigned long long, x - y, if (d || y > r) foo (0)) +T (25, unsigned int, x + y, if (r > x) foo (0)) +T (26, unsigned long, x + y, if (r <= x) foo (0)) +T (27, unsigned short, x + y, if (x < r) foo (r)) +T (28, unsigned long long, x + y, if (x >= r) foo (0)) +T (29, unsigned int, x + y, if (d || r > x) foo (0)) +T (30, unsigned long, x + y, if (d || r <= x) foo (0)) +T (31, unsigned char, x + y, if (d || x < r) foo (0)) +T (32, unsigned long long, x + y, if (d || x >= r) foo (0)) +T (33, unsigned int, x + y, if (r > y) foo (0)) +T (34, unsigned long, x + y, if (r <= y) foo (0)) +T (35, unsigned short, x + y, if (y < r) foo (r)) +T (36, unsigned long long, x + y, if (y >= r) foo (0)) +T (37, unsigned int, x + y, if (d || r > y) foo (0)) +T (38, unsigned long, x + y, if (d || r <= y) foo (0)) +T (39, unsigned char, x + y, if (d || y < r) foo (0)) +T (40, unsigned long long, x + y, if (d || y >= r) foo (0)) + +/* { dg-final { scan-tree-dump-not "ADD_OVERFLOW" "widening_mul" } } */ +/* { dg-final { scan-tree-dump-not "SUB_OVERFLOW" "widening_mul" } } */ Jakub