From patchwork Fri Dec 6 04:24:02 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kugan Vivekanandarajah X-Patchwork-Id: 297567 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id E256E2C0092 for ; Fri, 6 Dec 2013 15:24:38 +1100 (EST) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender :message-id:date:from:mime-version:to:cc:subject:references :in-reply-to:content-type; q=dns; s=default; b=nyxJAzR88YdTWQQzs 47nSGPq9BFDvUgn2A7wqe+LBnBFuoUTLWm0k3XqQ1RmbcyI1cGohaBzrFcve3Epl /kyE5BJQ/s19jnbRMyO+kHgGYktnKDzZabSo/Dw2hf1eiIgWND0rctm9NzACaUbB zcXH6raizGSn5kBJpQ/sPNXcu0= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender :message-id:date:from:mime-version:to:cc:subject:references :in-reply-to:content-type; s=default; bh=ArIZ83a4le8zltKCEVWoyQL t8jg=; b=t3apj1Iyjgycw8SLUMtIS9o6gost/17T9qMQXHtfbOb/Ozuws4Z+sDk j9gqIaRzcjyy6m98nTShWp5qEo+CQnY+f2S2KKaE6RG1FwSxXqAR022qPm9b6xeM mu3+pyPnN3jXgPCyITRUSMO4iFkiwbKam7oXjYIonmJ5Jccv/2Ps= Received: (qmail 21761 invoked by alias); 6 Dec 2013 04:24:30 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 21686 invoked by uid 89); 6 Dec 2013 04:24:23 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-1.9 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_NONE, SPF_PASS autolearn=ham version=3.3.2 X-HELO: mail-pd0-f179.google.com Received: from Unknown (HELO mail-pd0-f179.google.com) (209.85.192.179) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES128-SHA encrypted) ESMTPS; Fri, 06 Dec 2013 04:24:21 +0000 Received: by mail-pd0-f179.google.com with SMTP id r10so300938pdi.38 for ; Thu, 05 Dec 2013 20:24:13 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:message-id:date:from:user-agent:mime-version:to :cc:subject:references:in-reply-to:content-type; bh=/P14pRvk1QM1dp757BK9RYpCOylJEDRhCN3tPU3FIIo=; b=WkoKImzmZXJSem+qmePn2FdPYbUHJRw06w6jVJmXhYfR8879iUE+V1jh9UOHcTHhnq mNTEtNko7oneYzF9fP0xZ+c8FR5+rsk1ljENWryJ56uK0Yy0sOyHNK+Dftx227Br0eId 1Cbkj/EBMDMJ57DGZ5jQAZemS0aMfag5Cmu/E+5QrtDkSHmBQ90NGXoQarscGh2A3B9p AXvBALFsd8yBGAg9wUs9ZRI6xlDqbYewjGL5TTDt8V1ujVvZ8YiKnfdsW21kYqLAjywK lxoRMv49D0+S4fYQlyCevusj1pgidOt1RE04YKo8dlBPiJOB7TpDnc9yCanvs1W4wUqc 7T4g== X-Gm-Message-State: ALoCoQmBuKiS7z20hHETUPkH58pkxmiXyGFHOPWZFpCxxvAv4bNRR/71S2MEK9wSZfgN7u4zsi1z X-Received: by 10.68.111.33 with SMTP id if1mr1595302pbb.31.1386303852866; Thu, 05 Dec 2013 20:24:12 -0800 (PST) Received: from [192.168.0.100] ([1.147.244.199]) by mx.google.com with ESMTPSA id lh13sm63853415pab.4.2013.12.05.20.24.09 for (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Thu, 05 Dec 2013 20:24:11 -0800 (PST) Message-ID: <52A15162.40302@linaro.org> Date: Fri, 06 Dec 2013 15:24:02 +1100 From: Kugan User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:24.0) Gecko/20100101 Thunderbird/24.1.0 MIME-Version: 1.0 To: Richard Biener CC: Eric Botcazou , gcc-patches@gcc.gnu.org, steven@gcc.gnu.org Subject: Re: [PING^2][PATCH][2 of 2] RTL expansion for zero sign extension elimination with VRP References: <51ABFC6E.30205@linaro.org> <1726629.C2vZH2NXuZ@polaris> <520B31F5.7020200@linaro.org> <52245B58.6090507@linaro.org> <5253B4FA.9090203@linaro.org> <525D153A.1030808@linaro.org> <525DDC09.9090509@linaro.org> <526761C7.1060007@linaro.org> In-Reply-To: <526761C7.1060007@linaro.org> X-IsSubscribed: yes >>>> tem = (char) 255 + (char) 1; >> >> tem is always of type 'char' in GIMPLE (even if later promoted >> via PROMOTE_MODE) the value-range is a 'char' value-range and thus >> never will exceed [CHAR_MIN, CHAR_MAX]. The only way you can >> use that directly is if you can rely on undefined behavior >> happening for signed overflow - but if you argue that way you >> can simply _always_ drop the (sext:SI (subreg:QI part and you >> do not need value ranges for this. For unsigned operations >> for example [250, 254] + [8, 10] will simply wrap to [3, 7] >> (if I got the math correct) which is inside your [CHAR_MIN + 1, >> CHAR_MAX - 1] but if performed in SImode you can get 259 and >> thus clearly you cannot drop the (zext:SI (subreg:QI parts. >> The same applies to signed types if you do not want to rely >> on signed overflow being undefined of course. >> > > Thanks for the explanation. I now get it and I will rework the patch. > I have attempted to implement what Richard suggested. If you think this is what you want, I will go ahead and implement the missing gimple binary statements. Thanks again. Kugan diff --git a/gcc/cfgexpand.c b/gcc/cfgexpand.c index 98983f4..60ce54b 100644 --- a/gcc/cfgexpand.c +++ b/gcc/cfgexpand.c @@ -3236,6 +3236,20 @@ expand_gimple_stmt_1 (gimple stmt) if (temp == target) ; + /* If the value in SUBREG of temp fits that SUBREG (does not + overflow) and is assigned to target SUBREG of the same mode + without sign conversion, we can skip the SUBREG + and extension. */ + else if (promoted + && is_assigned_exp_fit_type (lhs) + && (GET_CODE (temp) == SUBREG) + && (GET_MODE_PRECISION (GET_MODE (SUBREG_REG (temp))) + >= GET_MODE_PRECISION (GET_MODE (target))) + && (GET_MODE (SUBREG_REG (target)) + == GET_MODE (SUBREG_REG (temp)))) + { + emit_move_insn (SUBREG_REG (target), SUBREG_REG (temp)); + } else if (promoted) { int unsignedp = SUBREG_PROMOTED_UNSIGNED_P (target); diff --git a/gcc/dojump.c b/gcc/dojump.c index 2aef34d..0f3aeae 100644 --- a/gcc/dojump.c +++ b/gcc/dojump.c @@ -1143,6 +1143,62 @@ do_compare_and_jump (tree treeop0, tree treeop1, enum rtx_code signed_code, type = TREE_TYPE (treeop0); mode = TYPE_MODE (type); + + /* Is zero/sign extension redundant. */ + bool op0_ext_redundant = false; + bool op1_ext_redundant = false; + + /* If promoted and the value in SUBREG of op0 fits (does not overflow), + it is a candidate for extension elimination. */ + if (GET_CODE (op0) == SUBREG && SUBREG_PROMOTED_VAR_P (op0)) + op0_ext_redundant = is_assigned_exp_fit_type (treeop0); + + /* If promoted and the value in SUBREG of op1 fits (does not overflow), + it is a candidate for extension elimination. */ + if (GET_CODE (op1) == SUBREG && SUBREG_PROMOTED_VAR_P (op1)) + op1_ext_redundant = is_assigned_exp_fit_type (treeop1); + + /* If zero/sign extension is redundant, generate RTL + for operands without zero/sign extension. */ + if ((op0_ext_redundant || TREE_CODE (treeop0) == INTEGER_CST) + && (op1_ext_redundant || TREE_CODE (treeop1) == INTEGER_CST)) + { + if ((TREE_CODE (treeop1) == INTEGER_CST) + && (!mode_signbit_p (GET_MODE (op1), op1))) + { + /* First operand is constant and signbit is not set (not + represented in RTL as a negative constant). */ + rtx new_op0 = gen_reg_rtx (GET_MODE (SUBREG_REG (op0))); + emit_move_insn (new_op0, SUBREG_REG (op0)); + op0 = new_op0; + } + else if ((TREE_CODE (treeop0) == INTEGER_CST) + && (!mode_signbit_p (GET_MODE (op0), op0))) + { + /* Other operand is constant and signbit is not set (not + represented in RTL as a negative constant). */ + rtx new_op1 = gen_reg_rtx (GET_MODE (SUBREG_REG (op1))); + + emit_move_insn (new_op1, SUBREG_REG (op1)); + op1 = new_op1; + } + else if ((TREE_CODE (treeop0) != INTEGER_CST) + && (TREE_CODE (treeop1) != INTEGER_CST) + && (GET_MODE (op0) == GET_MODE (op1)) + && (GET_MODE (SUBREG_REG (op0)) == GET_MODE (SUBREG_REG (op1)))) + { + /* If both comapre registers fits SUBREG and of the + same mode. */ + rtx new_op0 = gen_reg_rtx (GET_MODE (SUBREG_REG (op0))); + rtx new_op1 = gen_reg_rtx (GET_MODE (SUBREG_REG (op1))); + + emit_move_insn (new_op0, SUBREG_REG (op0)); + emit_move_insn (new_op1, SUBREG_REG (op1)); + op0 = new_op0; + op1 = new_op1; + } + } + if (TREE_CODE (treeop0) == INTEGER_CST && (TREE_CODE (treeop1) != INTEGER_CST || (GET_MODE_BITSIZE (mode) diff --git a/gcc/tree.c b/gcc/tree.c index d363cfc..d22630a 100644 --- a/gcc/tree.c +++ b/gcc/tree.c @@ -408,6 +408,156 @@ tree_node_structure_for_code (enum tree_code code) } } +/* Check expression value for overflow in tcc_binary. */ +static bool +is_binary_expr_fit_type (enum tree_code stmt_code, + tree lhs, double_int min1, double_int max1, + double_int min2, double_int max2) +{ + double_int dmin, dmax; + double_int type_max = tree_to_double_int (TYPE_MAX_VALUE (TREE_TYPE (lhs))); + double_int type_min = tree_to_double_int (TYPE_MIN_VALUE (TREE_TYPE (lhs))); + bool uns = TYPE_UNSIGNED (TREE_TYPE (lhs)); + + switch (stmt_code) + { + case PLUS_EXPR: + dmin = min1 + min2; + dmax = max1 + max2; + break; + case MINUS_EXPR: + dmin = min1 - min2; + dmax = max1 - max2; + break; + default: + return false; + } + + if (dmin.cmp (type_min, uns) == -1) + return false; + else if (dmin.cmp (type_max, uns) == 1) + return false; + if (dmax.cmp (type_min, uns) == -1) + return false; + else if (dmax.cmp (type_max, uns) == 1) + return false; + return true; +} + +/* Check gimple assign stmt and see if zero/sign extension is + redundant. i.e. if an assignment gimple statement has RHS expression + value that can fit in LHS type, subreg and extension to fit can be + redundant. Zero/sign extensions in this case can be removed. */ + +bool +is_assigned_exp_fit_type (tree lhs) +{ + double_int type_min, type_max; + double_int min1, max1, min2, max2; + enum tree_code stmt_code; + tree rhs1, rhs2; + gimple stmt = SSA_NAME_DEF_STMT (lhs); + double_int msb_val; + + if (gimple_code (stmt) != GIMPLE_ASSIGN) + return false; + + stmt_code = gimple_assign_rhs_code (stmt); + rhs1 = gimple_assign_rhs1 (stmt); + bool uns = TYPE_UNSIGNED (TREE_TYPE (lhs)); + + /* We remove extension for non-pointer and integral stmts. */ + if (!INTEGRAL_TYPE_P (TREE_TYPE (lhs)) + || POINTER_TYPE_P (TREE_TYPE (lhs))) + return false; + + type_max = tree_to_double_int (TYPE_MAX_VALUE (TREE_TYPE (lhs))); + type_min = tree_to_double_int (TYPE_MIN_VALUE (TREE_TYPE (lhs))); + + if (uns) + msb_val = type_max.rshift (1); + else + msb_val = type_max + double_int_one; + + if (TREE_CODE_CLASS (stmt_code) == tcc_unary) + { + /* Get the value range. */ + if (TREE_CODE (rhs1) == INTEGER_CST) + { + min1 = tree_to_double_int (rhs1); + max1 = tree_to_double_int (rhs1); + } + else if (get_range_info (rhs1, &min1, &max1) != VR_RANGE) + { + return false; + } + + switch (stmt_code) + { + case VIEW_CONVERT_EXPR: + case CONVERT_EXPR: + case NOP_EXPR: + if ((TYPE_UNSIGNED (TREE_TYPE (lhs)) + != TYPE_UNSIGNED (TREE_TYPE (rhs1))) + && (TYPE_PRECISION (TREE_TYPE (lhs)) + != TYPE_PRECISION (TREE_TYPE (rhs1)))) + return false; + + if (!uns && min1.cmp (msb_val, uns) == 1 + && max1.cmp (msb_val, uns) == 1) + { + min1 = min1.sext (TYPE_PRECISION (TREE_TYPE (rhs1))); + max1 = max1.sext (TYPE_PRECISION (TREE_TYPE (rhs1))); + } + + /* If rhs value range fits lhs type, zero/sign extension is + redundant. */ + if (max1.cmp (type_max, uns) != 1 + && (type_min.cmp (min1, uns)) != 1) + return true; + else + return false; + + case NEGATE_EXPR: + return is_binary_expr_fit_type (MINUS_EXPR, lhs, double_int_zero, + double_int_zero, min1, max1); + default: + return false; + } + } + + if (TREE_CODE_CLASS (stmt_code) == tcc_binary) + { + double_int const_val; + rhs2 = gimple_assign_rhs2 (stmt); + + /* Get the value range. */ + if (TREE_CODE (rhs1) == INTEGER_CST) + { + min1 = tree_to_double_int (rhs1); + max1 = tree_to_double_int (rhs1); + } + else if (get_range_info (rhs1, &min1, &max1) != VR_RANGE) + { + return false; + } + + /* Get the value range. */ + if (TREE_CODE (rhs2) == INTEGER_CST) + { + min2 = tree_to_double_int (rhs2); + max2 = tree_to_double_int (rhs2); + } + else if (get_range_info (rhs2, &min2, &max2) != VR_RANGE) + { + return false; + } + + return is_binary_expr_fit_type (stmt_code, lhs, min1, max1, min2, max2); + } + + return false; +} /* Initialize tree_contains_struct to describe the hierarchy of tree nodes. */ diff --git a/gcc/tree.h b/gcc/tree.h index 88c8d56..11a286c 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -4134,6 +4134,7 @@ extern tree lhd_gcc_personality (void); extern void assign_assembler_name_if_neeeded (tree); extern void warn_deprecated_use (tree, tree); extern void cache_integer_cst (tree); +extern bool is_assigned_exp_fit_type (tree lhs); /* Compare and hash for any structure which begins with a canonical pointer. Assumes all pointers are interchangeable, which is sort