From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 51199 invoked by alias); 6 Apr 2017 13:59:53 -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 50778 invoked by uid 89); 6 Apr 2017 13:59:52 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-6.1 required=5.0 tests=BAYES_00,GIT_PATCH_2,KAM_ASCII_DIVIDERS,RP_MATCHES_RCVD,SPF_PASS autolearn=ham version=3.3.2 spammy= X-HELO: mx2.suse.de Received: from mx2.suse.de (HELO mx2.suse.de) (195.135.220.15) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Thu, 06 Apr 2017 13:59:49 +0000 Received: from relay1.suse.de (charybdis-ext.suse.de [195.135.220.254]) by mx2.suse.de (Postfix) with ESMTP id B9BDAAC55 for ; Thu, 6 Apr 2017 13:59:48 +0000 (UTC) Date: Thu, 06 Apr 2017 13:59:00 -0000 From: Richard Biener To: gcc-patches@gcc.gnu.org Subject: [PATCH] Fix PR80341 Message-ID: User-Agent: Alpine 2.20 (LSU 67 2015-01-07) MIME-Version: 1.0 Content-Type: text/plain; charset=US-ASCII X-SW-Source: 2017-04/txt/msg00292.txt.bz2 This fixes an old bug I introduced. We may not pass in the final truncation type to get_unwidened for divisions but need to preserve the original values. That means the INTEGER_CST handling needs extension for the !for_type case as well. And some refactoring. (as much as I hate working on this premature folding code...) Bootstrap and regtest running on x86_64-unknown-linux-gnu. Richard. 2017-04-06 Richard Biener PR middle-end/80341 * tree.c (get_unwidened): Also handle ! for_type case for INTEGER_CSTs. * convert.c (do_narrow): Split out from ... (convert_to_integer_1): ... here. Do not pass final truncation type to get_unwidened for TRUNC_DIV_EXPR. * gcc.dg/torture/pr80341.c: New testcase. Index: gcc/tree.c =================================================================== *** gcc/tree.c (revision 246728) --- gcc/tree.c (working copy) *************** get_unwidened (tree op, tree for_type) *** 9033,9045 **** } } ! /* If we finally reach a constant see if it fits in for_type and in that case convert it. */ ! if (for_type ! && TREE_CODE (win) == INTEGER_CST ! && TREE_TYPE (win) != for_type ! && int_fits_type_p (win, for_type)) ! win = fold_convert (for_type, win); return win; } --- 9033,9053 ---- } } ! /* If we finally reach a constant see if it fits in sth smaller and in that case convert it. */ ! if (TREE_CODE (win) == INTEGER_CST) ! { ! tree wtype = TREE_TYPE (win); ! unsigned prec = wi::min_precision (win, TYPE_SIGN (wtype)); ! if (for_type) ! prec = MAX (prec, final_prec); ! if (prec < TYPE_PRECISION (wtype)) ! { ! tree t = lang_hooks.types.type_for_size (prec, TYPE_UNSIGNED (wtype)); ! if (t && TYPE_PRECISION (t) < TYPE_PRECISION (wtype)) ! win = fold_convert (t, win); ! } ! } return win; } Index: gcc/convert.c =================================================================== *** gcc/convert.c (revision 246728) --- gcc/convert.c (working copy) *************** convert_to_real_maybe_fold (tree type, t *** 413,418 **** --- 413,495 ---- return convert_to_real_1 (type, expr, dofold || CONSTANT_CLASS_P (expr)); } + /* Try to narrow EX_FORM ARG0 ARG1 in narrowed arg types producing a + result in TYPE. */ + + static tree + do_narrow (location_t loc, + enum tree_code ex_form, tree type, tree arg0, tree arg1, + tree expr, unsigned inprec, unsigned outprec, bool dofold) + { + /* Do the arithmetic in type TYPEX, + then convert result to TYPE. */ + tree typex = type; + + /* Can't do arithmetic in enumeral types + so use an integer type that will hold the values. */ + if (TREE_CODE (typex) == ENUMERAL_TYPE) + typex = lang_hooks.types.type_for_size (TYPE_PRECISION (typex), + TYPE_UNSIGNED (typex)); + + /* But now perhaps TYPEX is as wide as INPREC. + In that case, do nothing special here. + (Otherwise would recurse infinitely in convert. */ + if (TYPE_PRECISION (typex) != inprec) + { + /* Don't do unsigned arithmetic where signed was wanted, + or vice versa. + Exception: if both of the original operands were + unsigned then we can safely do the work as unsigned. + Exception: shift operations take their type solely + from the first argument. + Exception: the LSHIFT_EXPR case above requires that + we perform this operation unsigned lest we produce + signed-overflow undefinedness. + And we may need to do it as unsigned + if we truncate to the original size. */ + if (TYPE_UNSIGNED (TREE_TYPE (expr)) + || (TYPE_UNSIGNED (TREE_TYPE (arg0)) + && (TYPE_UNSIGNED (TREE_TYPE (arg1)) + || ex_form == LSHIFT_EXPR + || ex_form == RSHIFT_EXPR + || ex_form == LROTATE_EXPR + || ex_form == RROTATE_EXPR)) + || ex_form == LSHIFT_EXPR + /* If we have !flag_wrapv, and either ARG0 or + ARG1 is of a signed type, we have to do + PLUS_EXPR, MINUS_EXPR or MULT_EXPR in an unsigned + type in case the operation in outprec precision + could overflow. Otherwise, we would introduce + signed-overflow undefinedness. */ + || ((!TYPE_OVERFLOW_WRAPS (TREE_TYPE (arg0)) + || !TYPE_OVERFLOW_WRAPS (TREE_TYPE (arg1))) + && ((TYPE_PRECISION (TREE_TYPE (arg0)) * 2u + > outprec) + || (TYPE_PRECISION (TREE_TYPE (arg1)) * 2u + > outprec)) + && (ex_form == PLUS_EXPR + || ex_form == MINUS_EXPR + || ex_form == MULT_EXPR))) + { + if (!TYPE_UNSIGNED (typex)) + typex = unsigned_type_for (typex); + } + else + { + if (TYPE_UNSIGNED (typex)) + typex = signed_type_for (typex); + } + /* We should do away with all this once we have a proper + type promotion/demotion pass, see PR45397. */ + expr = maybe_fold_build2_loc (dofold, loc, ex_form, typex, + convert (typex, arg0), + convert (typex, arg1)); + return convert (type, expr); + } + + return NULL_TREE; + } + /* Convert EXPR to some integer (or enum) type TYPE. EXPR must be pointer, integer, discrete (enum, char, or bool), float, *************** convert_to_integer_1 (tree type, tree ex *** 719,726 **** case TRUNC_DIV_EXPR: { ! tree arg0 = get_unwidened (TREE_OPERAND (expr, 0), type); ! tree arg1 = get_unwidened (TREE_OPERAND (expr, 1), type); /* Don't distribute unless the output precision is at least as big as the actual inputs and it has the same signedness. */ --- 796,803 ---- case TRUNC_DIV_EXPR: { ! tree arg0 = get_unwidened (TREE_OPERAND (expr, 0), NULL_TREE); ! tree arg1 = get_unwidened (TREE_OPERAND (expr, 1), NULL_TREE); /* Don't distribute unless the output precision is at least as big as the actual inputs and it has the same signedness. */ *************** convert_to_integer_1 (tree type, tree ex *** 738,744 **** && (TYPE_UNSIGNED (TREE_TYPE (arg0)) || (TREE_CODE (arg1) == INTEGER_CST && !integer_all_onesp (arg1)))) ! goto trunc1; break; } --- 815,826 ---- && (TYPE_UNSIGNED (TREE_TYPE (arg0)) || (TREE_CODE (arg1) == INTEGER_CST && !integer_all_onesp (arg1)))) ! { ! tree tem = do_narrow (loc, ex_form, type, arg0, arg1, ! expr, inprec, outprec, dofold); ! if (tem) ! return tem; ! } break; } *************** convert_to_integer_1 (tree type, tree ex *** 786,857 **** || inprec > TYPE_PRECISION (TREE_TYPE (arg0)) || inprec > TYPE_PRECISION (TREE_TYPE (arg1))) { ! /* Do the arithmetic in type TYPEX, ! then convert result to TYPE. */ ! tree typex = type; ! ! /* Can't do arithmetic in enumeral types ! so use an integer type that will hold the values. */ ! if (TREE_CODE (typex) == ENUMERAL_TYPE) ! typex ! = lang_hooks.types.type_for_size (TYPE_PRECISION (typex), ! TYPE_UNSIGNED (typex)); ! ! /* But now perhaps TYPEX is as wide as INPREC. ! In that case, do nothing special here. ! (Otherwise would recurse infinitely in convert. */ ! if (TYPE_PRECISION (typex) != inprec) ! { ! /* Don't do unsigned arithmetic where signed was wanted, ! or vice versa. ! Exception: if both of the original operands were ! unsigned then we can safely do the work as unsigned. ! Exception: shift operations take their type solely ! from the first argument. ! Exception: the LSHIFT_EXPR case above requires that ! we perform this operation unsigned lest we produce ! signed-overflow undefinedness. ! And we may need to do it as unsigned ! if we truncate to the original size. */ ! if (TYPE_UNSIGNED (TREE_TYPE (expr)) ! || (TYPE_UNSIGNED (TREE_TYPE (arg0)) ! && (TYPE_UNSIGNED (TREE_TYPE (arg1)) ! || ex_form == LSHIFT_EXPR ! || ex_form == RSHIFT_EXPR ! || ex_form == LROTATE_EXPR ! || ex_form == RROTATE_EXPR)) ! || ex_form == LSHIFT_EXPR ! /* If we have !flag_wrapv, and either ARG0 or ! ARG1 is of a signed type, we have to do ! PLUS_EXPR, MINUS_EXPR or MULT_EXPR in an unsigned ! type in case the operation in outprec precision ! could overflow. Otherwise, we would introduce ! signed-overflow undefinedness. */ ! || ((!TYPE_OVERFLOW_WRAPS (TREE_TYPE (arg0)) ! || !TYPE_OVERFLOW_WRAPS (TREE_TYPE (arg1))) ! && ((TYPE_PRECISION (TREE_TYPE (arg0)) * 2u ! > outprec) ! || (TYPE_PRECISION (TREE_TYPE (arg1)) * 2u ! > outprec)) ! && (ex_form == PLUS_EXPR ! || ex_form == MINUS_EXPR ! || ex_form == MULT_EXPR))) ! { ! if (!TYPE_UNSIGNED (typex)) ! typex = unsigned_type_for (typex); ! } ! else ! { ! if (TYPE_UNSIGNED (typex)) ! typex = signed_type_for (typex); ! } ! /* We should do away with all this once we have a proper ! type promotion/demotion pass, see PR45397. */ ! expr = maybe_fold_build2_loc (dofold, loc, ex_form, typex, ! convert (typex, arg0), ! convert (typex, arg1)); ! return convert (type, expr); ! } } } break; --- 868,877 ---- || inprec > TYPE_PRECISION (TREE_TYPE (arg0)) || inprec > TYPE_PRECISION (TREE_TYPE (arg1))) { ! tree tem = do_narrow (loc, ex_form, type, arg0, arg1, ! expr, inprec, outprec, dofold); ! if (tem) ! return tem; } } break; Index: gcc/testsuite/gcc.dg/torture/pr80341.c =================================================================== *** gcc/testsuite/gcc.dg/torture/pr80341.c (nonexistent) --- gcc/testsuite/gcc.dg/torture/pr80341.c (working copy) *************** *** 0 **** --- 1,18 ---- + /* { dg-do run } */ + + const signed char c = -84; + signed char s; + + void + foo () + { + s = (unsigned short) c / -55; + } + + int + main () + { + foo (); + if (s != 90) + __builtin_abort (); + }