From patchwork Tue Aug 29 05:07:12 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jeff Law X-Patchwork-Id: 806946 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=gcc.gnu.org (client-ip=209.132.180.131; helo=sourceware.org; envelope-from=gcc-patches-return-461060-incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b="adI7YL03"; dkim-atps=neutral Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3xhGq14ybVz9sRV for ; Tue, 29 Aug 2017 15:07:39 +1000 (AEST) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :subject:to:message-id:date:mime-version:content-type; q=dns; s= default; b=vhhIj9RKkScrjt4TR0D/c9smxTAZoSGGwM1jielkfI3/RFHHqjSUD PS2/UQ2/IoL0blQHNvNkFUBubEm+y9nGI7VK1bTwBA8GtRu4eBSBkicTA/XK9Yo/ UfWbw6nwf/Eet14RfO7dG0nJ1Hw9BSbDK01t/Apy/gbhG2SdwmJb9I= 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:from :subject:to:message-id:date:mime-version:content-type; s= default; bh=Wqo4/JnKQY/CD5O3LcnxV7xAtsw=; b=adI7YL03xtl7alT29/7o KsKI+QQKthYaaUuhTy32CPVB7ugV7shJUerunqz8oNUYN6fH2KCvNgqDQbQZUe7y kyDvrArGAci5DXr0uubRZM3GGZ2l6FkS6VVZxI1V6BijVjp4GiJtdRx+8IkH8i0A o18LPkEwjKXCwt9u4JkKR8E= Received: (qmail 127126 invoked by alias); 29 Aug 2017 05:07:28 -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 126325 invoked by uid 89); 29 Aug 2017 05:07:27 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-25.9 required=5.0 tests=BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, KAM_LAZY_DOMAIN_SECURITY, RP_MATCHES_RCVD, SPF_HELO_PASS autolearn=ham version=3.3.2 spammy=arms, AUX 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 ESMTP; Tue, 29 Aug 2017 05:07:16 +0000 Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.phx2.redhat.com [10.5.11.16]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 39BD881DE1 for ; Tue, 29 Aug 2017 05:07:15 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com 39BD881DE1 Authentication-Results: ext-mx01.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx01.extmail.prod.ext.phx2.redhat.com; spf=fail smtp.mailfrom=law@redhat.com Received: from localhost.localdomain (ovpn-112-9.rdu2.redhat.com [10.10.112.9]) by smtp.corp.redhat.com (Postfix) with ESMTP id E275C5C269 for ; Tue, 29 Aug 2017 05:07:13 +0000 (UTC) From: Jeff Law Subject: Improve DOM's ability to derive equivalences when traversing edges To: gcc-patches Message-ID: <6eee6bd5-cb64-925f-dfcd-e0dbdfbb835d@redhat.com> Date: Mon, 28 Aug 2017 23:07:12 -0600 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101 Thunderbird/52.2.1 MIME-Version: 1.0 X-IsSubscribed: yes This is a two part patchkit to improve DOM's ability to derive constant equivalences that arise as a result of traversing a particular edge in the CFG. Until now we only allowed a single NAME = NAME|CONST equivalence to be associated with an edge in the CFG. Patch #1 generalizes that code so that we can record multiple simple equivalences on an edge. Much like expression equivalences, we just shove them into a vec and iterate on the vec in the appropriate places. Patch #2 has the interesting bits. Back in the gcc-7 effort I added the ability to look at the operands of a BIT_IOR_EXPR that had a zero result. In that case each operand of the BIT_IOR must have a zero value. This was to address a missed optimization regression bug during stage4. The plan was always to add analogous BIT_AND support, but I didn't feel like handling BIT_AND was appropriate at the time (no bz entry and no regressions related to that capability). I'd also had the sense that further improvements could be made here. For example, it is common for the BIT_IOR or BIT_AND to be fed by a comparison and we ought to be able to record the result of the comparison. If the comparison happened to be an equality test, then we may ultimately derive a constant for on operand of the equality test as well. It also seemed like the NOP/CONVERT_EXPR handling could be incorporated into such a change. So I pulled together some instrumentation. Lots of things generate equivalences -- but a much smaller subset of those equivalences are ultimately useful. Probably the most surprising was BIT_XOR, which allows us to generate all kinds of equivalences, but none that were useful for ultimate simplification in any of the tests I looked at. The most subtle was COND_EXPRs. We might have something like res = (a != 5) ? x : 1; We can't actually derive anything useful for "a" here, even if we know the result is one. That's because "x" could have the value 1. So you end up only being able to derive equivalences for COND_EXPRs when both arms have a constant value. That restriction dramatically reduces the utility of handling COND_EXPR -- to the point where I'm not including it. So what we end up with is BIT_AND/BIT_IOR, conversions, plus/minus, comparisons and neg/not. So when we determine that a particular SSA_NAME has a constant value, we look at the defining statement and essentially try to derive a value for the input operand(s) based on knowing the result value. If we can derive a constant value for an input operand, we record that value and recurse. In cases where we walk backwards to a condition. We will record the condition into the available expression table. The code is written such that if we find cases where the equivalences for other nodes are useful, they're easy to add. These equivalences are most useful to the threader, but I've seen them help in other cases as well. There's a half-dozen or so new tests reduced from GCC itself. Bootstrapped and regression tested on x86_64, lightly tested on ppc64le via bootstrapping and running the new tests to verify they do the right thing on a !logical_op_short_circuit target. Installing on the trunk. Jeff commit 506ac60cacbc4c4e5e166513ea83c1d2e14eaf3b Author: law Date: Tue Aug 29 05:03:22 2017 +0000 * tree-ssa-dom.c (class edge_info): Changed from a struct to a class. Add ctor/dtor, methods and data members. (edge_info::edge_info): Renamed from allocate_edge_info. Initialize additional members. (edge_info::~edge_info): New. (free_dom_edge_info): Delete the edge info. (record_edge_info): Use new class & associated member functions. Tighten forms for testing for edge equivalences. (record_temporary_equivalences): Iterate over the simple equivalences rather than assuming there's only one per edge. (cprop_into_successor_phis): Iterate over the simple equivalences rather than assuming there's only one per edge. (optimize_stmt): Use operand_equal_p rather than pointer equality for mini-DSE code. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@251396 138bc75d-0d04-0410-961f-82ee72b054a4 commit a370df2c52074abbb044d1921a0c7df235758050 Author: law Date: Tue Aug 29 05:03:36 2017 +0000 * tree-ssa-dom.c (edge_info::record_simple_equiv): Call derive_equivalences. (derive_equivalences_from_bit_ior, record_temporary_equivalences): Code moved into.... (edge_info::derive_equivalences): New private member function * gcc.dg/torture/pr57214.c: Fix type of loop counter. * gcc.dg/tree-ssa/ssa-sink-16.c: Disable DOM. * gcc.dg/tree-ssa/ssa-dom-thread-11.c: New test. * gcc.dg/tree-ssa/ssa-dom-thread-12.c: New test. * gcc.dg/tree-ssa/ssa-dom-thread-13.c: New test. * gcc.dg/tree-ssa/ssa-dom-thread-14.c: New test. * gcc.dg/tree-ssa/ssa-dom-thread-15.c: New test. * gcc.dg/tree-ssa/ssa-dom-thread-16.c: New test. * gcc.dg/tree-ssa/ssa-dom-thread-17.c: New test. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@251397 138bc75d-0d04-0410-961f-82ee72b054a4 diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 258d4242f30..9a60a80b746 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,11 @@ 2017-08-28 Jeff Law + * tree-ssa-dom.c (edge_info::record_simple_equiv): Call + derive_equivalences. + (derive_equivalences_from_bit_ior, record_temporary_equivalences): + Code moved into.... + (edge_info::derive_equivalences): New private member function + * tree-ssa-dom.c (class edge_info): Changed from a struct to a class. Add ctor/dtor, methods and data members. (edge_info::edge_info): Renamed from allocate_edge_info. diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index cfe90904f6d..0ffc4f9a70f 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,15 @@ +2017-08-28 Jeff Law + + * gcc.dg/torture/pr57214.c: Fix type of loop counter. + * gcc.dg/tree-ssa/ssa-sink-16.c: Disable DOM. + * gcc.dg/tree-ssa/ssa-dom-thread-11.c: New test. + * gcc.dg/tree-ssa/ssa-dom-thread-12.c: New test. + * gcc.dg/tree-ssa/ssa-dom-thread-13.c: New test. + * gcc.dg/tree-ssa/ssa-dom-thread-14.c: New test. + * gcc.dg/tree-ssa/ssa-dom-thread-15.c: New test. + * gcc.dg/tree-ssa/ssa-dom-thread-16.c: New test. + * gcc.dg/tree-ssa/ssa-dom-thread-17.c: New test. + 2017-08-28 Janus Weil PR fortran/81770 diff --git a/gcc/testsuite/gcc.dg/torture/pr57214.c b/gcc/testsuite/gcc.dg/torture/pr57214.c index d51067d95d8..c697f84514e 100644 --- a/gcc/testsuite/gcc.dg/torture/pr57214.c +++ b/gcc/testsuite/gcc.dg/torture/pr57214.c @@ -15,7 +15,7 @@ bar (_Bool b) b = 1; baz (); x = 0; - int i; + unsigned int i; while (buf[i] && i) i++; foo (); diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-11.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-11.c new file mode 100644 index 00000000000..f42d64bed71 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-11.c @@ -0,0 +1,18 @@ +/* { dg-do compile { target { ! logical_op_short_circuit } } } */ +/* { dg-options "-O2 -fdump-tree-dom2-details" } */ + +static int *bb_ticks; +extern void frob (void); +void +mark_target_live_regs (int b, int block, int bb_tick) +{ + if (b == block && b != -1 && bb_tick == bb_ticks[b]) + return; + if (b != -1) + frob (); +} + +/* When the first two conditionals in the first IF are true, but + the third conditional is false, then there's a jump threading + opportunity to bypass the second IF statement. */ +/* { dg-final { scan-tree-dump-times "Threaded" 1 "dom2"} } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-12.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-12.c new file mode 100644 index 00000000000..63bd12a06a4 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-12.c @@ -0,0 +1,36 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-dom2-details -w" } */ +typedef long unsigned int size_t; +union tree_node; +typedef union tree_node *tree; +typedef union gimple_statement_d *gimple; +typedef const union gimple_statement_d *const_gimple; +union gimple_statement_d +{ + unsigned num_ops; + tree exp; +}; + +unsigned int x; +static inline tree +gimple_op (const_gimple gs, unsigned i) +{ + if (!(i < gs->num_ops)) + abort (); + return gs->exp; +} + +unsigned char +scan_function (gimple stmt) +{ + unsigned i; + for (i = 0; i < stmt->num_ops - 3 ; i++) + gimple_call_arg (stmt, i); + gimple_op (stmt, 1); +} + +/* The test which bypasses the loop is simplified prior to DOM to check + that stmt->num_ops - 3 != 0. When that test is false, we can derive + a value for stmt->num_ops. That in turn allows us to thread the jump + for the conditional at the start of the call to gimple_op. */ +/* { dg-final { scan-tree-dump-times "Threaded" 1 "dom2"} } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-13.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-13.c new file mode 100644 index 00000000000..209c40d4c95 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-13.c @@ -0,0 +1,46 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-dom2-details -w" } */ + +union tree_node; +typedef union tree_node *tree; +extern unsigned char tree_contains_struct[0xdead][64]; +struct tree_base +{ + int code:16; +}; +struct tree_typed +{ + tree type; +}; +struct tree_type_common +{ + tree main_variant; +}; +extern tree build_target_option_node (void); +union tree_node +{ + struct tree_base base; + struct tree_typed typed; + struct tree_type_common type_common; +}; +tree +convert (tree type, tree expr) +{ + tree e = expr; + int code = (type)->base.code; + const char *invalid_conv_diag; + tree ret; + if (tree_contains_struct[expr->base.code][(42)] != 1) + abort (); + if (type->type_common.main_variant == expr->typed.type->type_common.main_variant + && (expr->typed.type->base.code != 123 + || e->base.code == 456)) + return arf (); + if (expr->typed.type->base.code == 42) + error ("void value not ignored as it ought to be"); +} + +/* When the *->base.code tests in the second IF statement are false, we + know that expr->typed.base->base.code has the value 123. That allows + us to thread the test for the final IF statement on that path. */ +/* { dg-final { scan-tree-dump-times "Threaded" 1 "dom2"} } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-14.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-14.c new file mode 100644 index 00000000000..2d97f86fa28 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-14.c @@ -0,0 +1,40 @@ +/* { dg-do compile { target { ! logical_op_short_circuit } } } */ +/* { dg-options "-O2 -fdump-tree-dom2-details -w" } */ + +enum optab_methods +{ + OPTAB_DIRECT, + OPTAB_LIB, + OPTAB_WIDEN, + OPTAB_LIB_WIDEN, + OPTAB_MUST_WIDEN +}; +struct optab_d { }; +typedef struct optab_d *optab; +void +expand_shift_1 (int code, int unsignedp, int rotate, + optab lshift_optab, optab rshift_arith_optab) +{ + int left = (code == 42 || code == 0xde); + int attempt; + enum optab_methods methods; + if (attempt == 0) + methods = OPTAB_DIRECT; + else if (attempt == 1) + methods = OPTAB_WIDEN; + if ((!unsignedp || (!left && methods == OPTAB_WIDEN))) + { + enum optab_methods methods1 = methods; + if (unsignedp) + methods1 = OPTAB_MUST_WIDEN; + expand_binop (left ? lshift_optab : rshift_arith_optab, + unsignedp, methods1); + } +} + +/* When UNSIGNEDP is true, LEFT is false and METHOD == OPTAB_WIDEN + we will enter the TRUE arm of the conditional and we can thread + the test to compute the first first argument of the expand_binop + call if we look backwards through the boolean logicals. */ +/* { dg-final { scan-tree-dump-times "Threaded" 1 "dom2"} } */ + diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-15.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-15.c new file mode 100644 index 00000000000..df6a9b32eb1 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-15.c @@ -0,0 +1,67 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-dom2-details -w" } */ +struct rtx_def; +typedef struct rtx_def *rtx; +struct machine_frame_state +{ + rtx cfa_reg; + long sp_offset; +}; +struct machine_function { + struct machine_frame_state fs; +}; +enum global_rtl_index +{ + GR_PC, + GR_CC0, + GR_RETURN, + GR_SIMPLE_RETURN, + GR_STACK_POINTER, + GR_FRAME_POINTER, + GR_HARD_FRAME_POINTER, + GR_ARG_POINTER, + GR_VIRTUAL_INCOMING_ARGS, + GR_VIRTUAL_STACK_ARGS, + GR_VIRTUAL_STACK_DYNAMIC, + GR_VIRTUAL_OUTGOING_ARGS, + GR_VIRTUAL_CFA, + GR_VIRTUAL_PREFERRED_STACK_BOUNDARY, + GR_MAX +}; +struct target_rtl { + rtx x_global_rtl[GR_MAX]; +}; +extern struct target_rtl default_target_rtl; +struct function { + struct machine_function * machine; +}; +extern struct function *cfun; +struct ix86_frame +{ + long stack_pointer_offset; +}; +void +ix86_expand_prologue (void) +{ + struct machine_function *m = (cfun + 0)->machine; + struct ix86_frame frame; + long allocate; + allocate = frame.stack_pointer_offset - m->fs.sp_offset; + if (allocate == 0) + ; + else if (!ix86_target_stack_probe ()) + { + pro_epilogue_adjust_stack ((((&default_target_rtl)->x_global_rtl)[GR_STACK_POINTER]), (((&default_target_rtl)->x_global_rtl)[GR_STACK_POINTER]), + gen_rtx_CONST_INT ((-allocate)), -1, + m->fs.cfa_reg == (((&default_target_rtl)->x_global_rtl)[GR_STACK_POINTER])); + } + ((void)(!(m->fs.sp_offset == frame.stack_pointer_offset) ? fancy_abort ("../../gcc-4.7.3/gcc/config/i386/i386.c", 10435, __FUNCTION__), 0 : 0)); +} + +/* In the case where ALLOCATE is zero, we know that sp_offset and + stack_poitner_offset within their respective structures are the + same. That allows us to thread the jump from the true arm of the + first IF conditional around the test controlling the call to + fancy_abort. */ +/* { dg-final { scan-tree-dump-times "Threaded" 1 "dom2"} } */ + diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-16.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-16.c new file mode 100644 index 00000000000..e2e0d20fb9f --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-16.c @@ -0,0 +1,17 @@ +/* { dg-do compile { target { ! logical_op_short_circuit } } } */ +/* { dg-options "-O2 -fdump-tree-dom2-details -w" } */ +unsigned char +validate_subreg (unsigned int offset, unsigned int isize, unsigned int osize, int zz, int qq) +{ +if (osize >= (((zz & (1L << 2)) != 0) ? 8 : 4) && isize >= osize) + ; + else if (qq == 99) + return 0; + if (osize > isize) + return offset == 0; + return 1; +} +/* When we test isize >= osize in the first IF conditional and it is + false and qq != 99, then we can thread the osize > isize test of + the second conditional. */ +/* { dg-final { scan-tree-dump-times "Threaded" 1 "dom2"} } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-17.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-17.c new file mode 100644 index 00000000000..2c5c5a6cf94 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-17.c @@ -0,0 +1,44 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-dom2 -w" } */ + +struct rtx_def; +typedef struct rtx_def *rtx; +struct reload +{ + rtx in; + rtx reg_rtx; +}; +extern struct reload rld[(2 * 30 * (2 + 1))]; +static rtx find_dummy_reload (rtx); +extern int frob (); +extern int arf (); +int +push_reload (rtx in, rtx out +) +{ + int i; + if (out != 0 && in != out) + { + rld[i].reg_rtx = find_dummy_reload (out); + if (rld[i].reg_rtx == out) + rld[i].in = out; + } +} +rtx +find_dummy_reload (rtx real_out) +{ + unsigned int nwords = frob (); + unsigned int regno = frob (); + unsigned int i; + for (i = 0; i < nwords; i++) + if (arf ()) + break; + if (i == nwords) + return real_out; + return 0; +} + +/* In the case where the call to find_dummy_reload returns 0, + the final test in push_reload will never be true and it will + be eliminated. */ +/* { dg-final { scan-tree-dump-not "out_\[^\n\r]+ == 0" "dom2"} } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-sink-16.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-sink-16.c index 1b94c336806..610c8d60ebe 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/ssa-sink-16.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-sink-16.c @@ -1,6 +1,6 @@ /* { dg-do compile } */ -/* Note PRE rotates the loop and blocks the sinking opportunity. */ -/* { dg-options "-O2 -fno-tree-pre -fdump-tree-sink -fdump-tree-optimized" } */ +/* Note PRE and DOM jump threading rotate the loop and blocks the sinking opportunity. */ +/* { dg-options "-O2 -fno-tree-pre -fno-tree-dominator-opts -fdump-tree-sink -fdump-tree-optimized" } */ int f(int n) { diff --git a/gcc/tree-ssa-dom.c b/gcc/tree-ssa-dom.c index 403485b3c55..d91766e902e 100644 --- a/gcc/tree-ssa-dom.c +++ b/gcc/tree-ssa-dom.c @@ -136,19 +136,240 @@ edge_info::edge_info (edge e) } /* Destructor just needs to release the vectors. */ + edge_info::~edge_info (void) { this->cond_equivalences.release (); this->simple_equivalences.release (); } -/* Record that LHS is known to be equal to RHS at runtime when the - edge associated with THIS is traversed. */ +/* NAME is known to have the value VALUE, which must be a constant. + + Walk through its use-def chain to see if there are other equivalences + we might be able to derive. + + RECURSION_LIMIT controls how far back we recurse through the use-def + chains. */ + +void +edge_info::derive_equivalences (tree name, tree value, int recursion_limit) +{ + if (TREE_CODE (name) != SSA_NAME || TREE_CODE (value) != INTEGER_CST) + return; + + /* This records the equivalence for the toplevel object. Do + this before checking the recursion limit. */ + simple_equivalences.safe_push (equiv_pair (name, value)); + + /* Limit how far up the use-def chains we are willing to walk. */ + if (recursion_limit == 0) + return; + + /* We can walk up the use-def chains to potentially find more + equivalences. */ + gimple *def_stmt = SSA_NAME_DEF_STMT (name); + if (is_gimple_assign (def_stmt)) + { + /* We know the result of DEF_STMT was zero. See if that allows + us to deduce anything about the SSA_NAMEs used on the RHS. */ + enum tree_code code = gimple_assign_rhs_code (def_stmt); + switch (code) + { + case BIT_IOR_EXPR: + if (integer_zerop (value)) + { + tree rhs1 = gimple_assign_rhs1 (def_stmt); + tree rhs2 = gimple_assign_rhs2 (def_stmt); + + value = build_zero_cst (TREE_TYPE (rhs1)); + derive_equivalences (rhs1, value, recursion_limit - 1); + value = build_zero_cst (TREE_TYPE (rhs2)); + derive_equivalences (rhs2, value, recursion_limit - 1); + } + break; + + /* We know the result of DEF_STMT was one. See if that allows + us to deduce anything about the SSA_NAMEs used on the RHS. */ + case BIT_AND_EXPR: + if (!integer_zerop (value)) + { + tree rhs1 = gimple_assign_rhs1 (def_stmt); + tree rhs2 = gimple_assign_rhs2 (def_stmt); + + /* If either operand has a boolean range, then we + know its value must be one, otherwise we just know it + is nonzero. The former is clearly useful, I haven't + seen cases where the latter is helpful yet. */ + if (TREE_CODE (rhs1) == SSA_NAME) + { + if (ssa_name_has_boolean_range (rhs1)) + { + value = build_one_cst (TREE_TYPE (rhs1)); + derive_equivalences (rhs1, value, recursion_limit - 1); + } + } + if (TREE_CODE (rhs2) == SSA_NAME) + { + if (ssa_name_has_boolean_range (rhs2)) + { + value = build_one_cst (TREE_TYPE (rhs2)); + derive_equivalences (rhs2, value, recursion_limit - 1); + } + } + } + break; + + /* If LHS is an SSA_NAME and RHS is a constant integer and LHS was + set via a widening type conversion, then we may be able to record + additional equivalences. */ + case NOP_EXPR: + case CONVERT_EXPR: + { + tree rhs = gimple_assign_rhs1 (def_stmt); + tree rhs_type = TREE_TYPE (rhs); + if (INTEGRAL_TYPE_P (rhs_type) + && (TYPE_PRECISION (TREE_TYPE (name)) + >= TYPE_PRECISION (rhs_type)) + && int_fits_type_p (value, rhs_type)) + derive_equivalences (rhs, + fold_convert (rhs_type, value), + recursion_limit - 1); + break; + } + + /* We can invert the operation of these codes trivially if + one of the RHS operands is a constant to produce a known + value for the other RHS operand. */ + case POINTER_PLUS_EXPR: + case PLUS_EXPR: + { + tree rhs1 = gimple_assign_rhs1 (def_stmt); + tree rhs2 = gimple_assign_rhs2 (def_stmt); + + /* If either argument is a constant, then we can compute + a constant value for the nonconstant argument. */ + if (TREE_CODE (rhs1) == INTEGER_CST + && TREE_CODE (rhs2) == SSA_NAME) + derive_equivalences (rhs2, + fold_binary (MINUS_EXPR, TREE_TYPE (rhs1), + value, rhs1), + recursion_limit - 1); + else if (TREE_CODE (rhs2) == INTEGER_CST + && TREE_CODE (rhs1) == SSA_NAME) + derive_equivalences (rhs1, + fold_binary (MINUS_EXPR, TREE_TYPE (rhs1), + value, rhs2), + recursion_limit - 1); + break; + } + + /* If one of the operands is a constant, then we can compute + the value of the other operand. If both operands are + SSA_NAMEs, then they must be equal if the result is zero. */ + case MINUS_EXPR: + { + tree rhs1 = gimple_assign_rhs1 (def_stmt); + tree rhs2 = gimple_assign_rhs2 (def_stmt); + + /* If either argument is a constant, then we can compute + a constant value for the nonconstant argument. */ + if (TREE_CODE (rhs1) == INTEGER_CST + && TREE_CODE (rhs2) == SSA_NAME) + derive_equivalences (rhs2, + fold_binary (MINUS_EXPR, TREE_TYPE (rhs1), + rhs1, value), + recursion_limit - 1); + else if (TREE_CODE (rhs2) == INTEGER_CST + && TREE_CODE (rhs1) == SSA_NAME) + derive_equivalences (rhs1, + fold_binary (PLUS_EXPR, TREE_TYPE (rhs1), + value, rhs2), + recursion_limit - 1); + else if (integer_zerop (value)) + { + tree cond = build2 (EQ_EXPR, boolean_type_node, + gimple_assign_rhs1 (def_stmt), + gimple_assign_rhs2 (def_stmt)); + tree inverted = invert_truthvalue (cond); + record_conditions (&this->cond_equivalences, cond, inverted); + } + break; + } + + + case EQ_EXPR: + case NE_EXPR: + { + if ((code == EQ_EXPR && integer_onep (value)) + || (code == NE_EXPR && integer_zerop (value))) + { + tree rhs1 = gimple_assign_rhs1 (def_stmt); + tree rhs2 = gimple_assign_rhs2 (def_stmt); + + /* If either argument is a constant, then record the + other argument as being the same as that constant. + + If neither operand is a constant, then we have a + conditional name == name equivalence. */ + if (TREE_CODE (rhs1) == INTEGER_CST) + derive_equivalences (rhs2, rhs1, recursion_limit - 1); + else if (TREE_CODE (rhs2) == INTEGER_CST) + derive_equivalences (rhs1, rhs2, recursion_limit - 1); + } + else + { + tree cond = build2 (code, boolean_type_node, + gimple_assign_rhs1 (def_stmt), + gimple_assign_rhs2 (def_stmt)); + tree inverted = invert_truthvalue (cond); + if (integer_zerop (value)) + std::swap (cond, inverted); + record_conditions (&this->cond_equivalences, cond, inverted); + } + break; + } + + /* For BIT_NOT and NEGATE, we can just apply the operation to the + VALUE to get the new equivalence. It will always be a constant + so we can recurse. */ + case BIT_NOT_EXPR: + case NEGATE_EXPR: + { + tree rhs = gimple_assign_rhs1 (def_stmt); + tree res = fold_build1 (code, TREE_TYPE (rhs), value); + derive_equivalences (rhs, res, recursion_limit - 1); + break; + } + + default: + { + if (TREE_CODE_CLASS (code) == tcc_comparison) + { + tree cond = build2 (code, boolean_type_node, + gimple_assign_rhs1 (def_stmt), + gimple_assign_rhs2 (def_stmt)); + tree inverted = invert_truthvalue (cond); + if (integer_zerop (value)) + std::swap (cond, inverted); + record_conditions (&this->cond_equivalences, cond, inverted); + break; + } + break; + } + } + } +} void edge_info::record_simple_equiv (tree lhs, tree rhs) { - simple_equivalences.safe_push (equiv_pair (lhs, rhs)); + /* If the RHS is a constant, then we may be able to derive + further equivalences. Else just record the name = name + equivalence. */ + if (TREE_CODE (rhs) == INTEGER_CST) + derive_equivalences (lhs, rhs, 4); + else + simple_equivalences.safe_push (equiv_pair (lhs, rhs)); } /* Free the edge_info data attached to E, if it exists. */ @@ -702,42 +923,6 @@ back_propagate_equivalences (tree lhs, edge e, BITMAP_FREE (domby); } -/* Record NAME has the value zero and if NAME was set from a BIT_IOR_EXPR - recurse into both operands recording their values as zero too. - RECURSION_DEPTH controls how far back we recurse through the operands - of the BIT_IOR_EXPR. */ - -static void -derive_equivalences_from_bit_ior (tree name, - const_and_copies *const_and_copies, - int recursion_limit) -{ - if (recursion_limit == 0) - return; - - if (TREE_CODE (name) == SSA_NAME) - { - tree value = build_zero_cst (TREE_TYPE (name)); - - /* This records the equivalence for the toplevel object. */ - record_equality (name, value, const_and_copies); - - /* And we can recurse into each operand to potentially find more - equivalences. */ - gimple *def_stmt = SSA_NAME_DEF_STMT (name); - if (is_gimple_assign (def_stmt) - && gimple_assign_rhs_code (def_stmt) == BIT_IOR_EXPR) - { - derive_equivalences_from_bit_ior (gimple_assign_rhs1 (def_stmt), - const_and_copies, - recursion_limit - 1); - derive_equivalences_from_bit_ior (gimple_assign_rhs2 (def_stmt), - const_and_copies, - recursion_limit - 1); - } - } -} - /* Record into CONST_AND_COPIES and AVAIL_EXPRS_STACK any equivalences implied by traversing edge E (which are cached in E->aux). @@ -758,28 +943,7 @@ record_temporary_equivalences (edge e, /* If we have 0 = COND or 1 = COND equivalences, record them into our expression hash tables. */ for (i = 0; edge_info->cond_equivalences.iterate (i, &eq); ++i) - { - avail_exprs_stack->record_cond (eq); - - /* If the condition is testing that X == 0 is true or X != 0 is false - and X is set from a BIT_IOR_EXPR, then we can record equivalences - for the operands of the BIT_IOR_EXPR (and recurse on those). */ - tree op0 = eq->cond.ops.binary.opnd0; - tree op1 = eq->cond.ops.binary.opnd1; - if (TREE_CODE (op0) == SSA_NAME && integer_zerop (op1)) - { - enum tree_code code = eq->cond.ops.binary.op; - if ((code == EQ_EXPR && eq->value == boolean_true_node) - || (code == NE_EXPR && eq->value == boolean_false_node)) - derive_equivalences_from_bit_ior (op0, const_and_copies, 4); - - /* TODO: We could handle BIT_AND_EXPR in a similar fashion - recording that the operands have a nonzero value. */ - - /* TODO: We can handle more cases here, particularly when OP0 is - known to have a boolean range. */ - } - } + avail_exprs_stack->record_cond (eq); edge_info::equiv_pair *seq; for (i = 0; edge_info->simple_equivalences.iterate (i, &seq); ++i) @@ -806,42 +970,13 @@ record_temporary_equivalences (edge e, int lhs_cost = estimate_num_insns (lhs_def, &eni_size_weights); if (rhs_cost > lhs_cost) - record_equality (rhs, lhs, const_and_copies); + record_equality (rhs, lhs, const_and_copies); else if (rhs_cost < lhs_cost) - record_equality (lhs, rhs, const_and_copies); + record_equality (lhs, rhs, const_and_copies); } else record_equality (lhs, rhs, const_and_copies); - /* If LHS is an SSA_NAME and RHS is a constant integer and LHS was - set via a widening type conversion, then we may be able to record - additional equivalences. */ - if (TREE_CODE (rhs) == INTEGER_CST) - { - gimple *defstmt = SSA_NAME_DEF_STMT (lhs); - - if (defstmt - && is_gimple_assign (defstmt) - && CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (defstmt))) - { - tree old_rhs = gimple_assign_rhs1 (defstmt); - - /* If the conversion widens the original value and - the constant is in the range of the type of OLD_RHS, - then convert the constant and record the equivalence. - - Note that int_fits_type_p does not check the precision - if the upper and lower bounds are OK. */ - if (INTEGRAL_TYPE_P (TREE_TYPE (old_rhs)) - && (TYPE_PRECISION (TREE_TYPE (lhs)) - > TYPE_PRECISION (TREE_TYPE (old_rhs))) - && int_fits_type_p (rhs, TREE_TYPE (old_rhs))) - { - tree newval = fold_convert (TREE_TYPE (old_rhs), rhs); - record_equality (old_rhs, newval, const_and_copies); - } - } - } /* Any equivalence found for LHS may result in additional equivalences for other uses of LHS that we have already diff --git a/gcc/ChangeLog b/gcc/ChangeLog index abe7d855260..258d4242f30 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,20 @@ +2017-08-28 Jeff Law + + * tree-ssa-dom.c (class edge_info): Changed from a struct + to a class. Add ctor/dtor, methods and data members. + (edge_info::edge_info): Renamed from allocate_edge_info. + Initialize additional members. + (edge_info::~edge_info): New. + (free_dom_edge_info): Delete the edge info. + (record_edge_info): Use new class & associated member functions. + Tighten forms for testing for edge equivalences. + (record_temporary_equivalences): Iterate over the simple + equivalences rather than assuming there's only one per edge. + (cprop_into_successor_phis): Iterate over the simple + equivalences rather than assuming there's only one per edge. + (optimize_stmt): Use operand_equal_p rather than pointer + equality for mini-DSE code. + 2017-08-28 Nathan Sidwell * gcc.c (execute): Fold SIGPIPE handling into switch diff --git a/gcc/tree-ssa-dom.c b/gcc/tree-ssa-dom.c index 407a4ef97d2..403485b3c55 100644 --- a/gcc/tree-ssa-dom.c +++ b/gcc/tree-ssa-dom.c @@ -58,17 +58,28 @@ along with GCC; see the file COPYING3. If not see These structures live for a single iteration of the dominator optimizer in the edge's AUX field. At the end of an iteration we free each of these structures. */ - -struct edge_info +class edge_info { - /* If this edge creates a simple equivalence, the LHS and RHS of - the equivalence will be stored here. */ - tree lhs; - tree rhs; + public: + typedef std::pair equiv_pair; + edge_info (edge); + ~edge_info (); + + /* Record a simple LHS = RHS equivalence. This may trigger + calls to derive_equivalences. */ + void record_simple_equiv (tree, tree); + + /* If traversing this edge creates simple equivalences, we store + them as LHS/RHS pairs within this vector. */ + vec simple_equivalences; /* Traversing an edge may also indicate one or more particular conditions are true or false. */ vec cond_equivalences; + + private: + /* Derive equivalences by walking the use-def chains. */ + void derive_equivalences (tree, tree, int); }; /* Track whether or not we have changed the control flow graph. */ @@ -109,36 +120,46 @@ static edge single_incoming_edge_ignoring_loop_edges (basic_block); static void dump_dominator_optimization_stats (FILE *file, hash_table *); +/* Constructor for EDGE_INFO. An EDGE_INFO instance is always + associated with an edge E. */ -/* Free the edge_info data attached to E, if it exists. */ - -void -free_dom_edge_info (edge e) +edge_info::edge_info (edge e) { - struct edge_info *edge_info = (struct edge_info *)e->aux; + /* Free the old one associated with E, if it exists and + associate our new object with E. */ + free_dom_edge_info (e); + e->aux = this; - if (edge_info) - { - edge_info->cond_equivalences.release (); - free (edge_info); - } + /* And initialize the embedded vectors. */ + simple_equivalences = vNULL; + cond_equivalences = vNULL; } -/* Allocate an EDGE_INFO for edge E and attach it to E. - Return the new EDGE_INFO structure. */ +/* Destructor just needs to release the vectors. */ +edge_info::~edge_info (void) +{ + this->cond_equivalences.release (); + this->simple_equivalences.release (); +} + +/* Record that LHS is known to be equal to RHS at runtime when the + edge associated with THIS is traversed. */ -static struct edge_info * -allocate_edge_info (edge e) +void +edge_info::record_simple_equiv (tree lhs, tree rhs) { - struct edge_info *edge_info; + simple_equivalences.safe_push (equiv_pair (lhs, rhs)); +} - /* Free the old one, if it exists. */ - free_dom_edge_info (e); +/* Free the edge_info data attached to E, if it exists. */ - edge_info = XCNEW (struct edge_info); +void +free_dom_edge_info (edge e) +{ + class edge_info *edge_info = (struct edge_info *)e->aux; - e->aux = edge_info; - return edge_info; + if (edge_info) + delete edge_info; } /* Free all EDGE_INFO structures associated with edges in the CFG. @@ -171,7 +192,7 @@ static void record_edge_info (basic_block bb) { gimple_stmt_iterator gsi = gsi_last_bb (bb); - struct edge_info *edge_info; + class edge_info *edge_info; if (! gsi_end_p (gsi)) { @@ -212,9 +233,8 @@ record_edge_info (basic_block bb) { tree x = fold_convert_loc (loc, TREE_TYPE (index), CASE_LOW (label)); - edge_info = allocate_edge_info (e); - edge_info->lhs = index; - edge_info->rhs = x; + edge_info = new class edge_info (e); + edge_info->record_simple_equiv (index, x); } } free (info); @@ -251,28 +271,32 @@ record_edge_info (basic_block bb) if (code == EQ_EXPR) { - edge_info = allocate_edge_info (true_edge); - edge_info->lhs = op0; - edge_info->rhs = (integer_zerop (op1) ? false_val : true_val); - - edge_info = allocate_edge_info (false_edge); - edge_info->lhs = op0; - edge_info->rhs = (integer_zerop (op1) ? true_val : false_val); + edge_info = new class edge_info (true_edge); + edge_info->record_simple_equiv (op0, + (integer_zerop (op1) + ? false_val : true_val)); + edge_info = new class edge_info (false_edge); + edge_info->record_simple_equiv (op0, + (integer_zerop (op1) + ? true_val : false_val)); } else { - edge_info = allocate_edge_info (true_edge); - edge_info->lhs = op0; - edge_info->rhs = (integer_zerop (op1) ? true_val : false_val); - - edge_info = allocate_edge_info (false_edge); - edge_info->lhs = op0; - edge_info->rhs = (integer_zerop (op1) ? false_val : true_val); + edge_info = new class edge_info (true_edge); + edge_info->record_simple_equiv (op0, + (integer_zerop (op1) + ? true_val : false_val)); + edge_info = new class edge_info (false_edge); + edge_info->record_simple_equiv (op0, + (integer_zerop (op1) + ? false_val : true_val)); } } + /* This can show up in the IL as a result of copy propagation + it will eventually be canonicalized, but we have to cope + with this case within the pass. */ else if (is_gimple_min_invariant (op0) - && (TREE_CODE (op1) == SSA_NAME - || is_gimple_min_invariant (op1))) + && TREE_CODE (op1) == SSA_NAME) { tree cond = build2 (code, boolean_type_node, op0, op1); tree inverted = invert_truthvalue_loc (loc, cond); @@ -281,23 +305,17 @@ record_edge_info (basic_block bb) && real_zerop (op0)); struct edge_info *edge_info; - edge_info = allocate_edge_info (true_edge); + edge_info = new class edge_info (true_edge); record_conditions (&edge_info->cond_equivalences, cond, inverted); if (can_infer_simple_equiv && code == EQ_EXPR) - { - edge_info->lhs = op1; - edge_info->rhs = op0; - } + edge_info->record_simple_equiv (op1, op0); - edge_info = allocate_edge_info (false_edge); + edge_info = new class edge_info (false_edge); record_conditions (&edge_info->cond_equivalences, inverted, cond); if (can_infer_simple_equiv && TREE_CODE (inverted) == EQ_EXPR) - { - edge_info->lhs = op1; - edge_info->rhs = op0; - } + edge_info->record_simple_equiv (op1, op0); } else if (TREE_CODE (op0) == SSA_NAME @@ -311,27 +329,19 @@ record_edge_info (basic_block bb) && (TREE_CODE (op1) == SSA_NAME || real_zerop (op1))); struct edge_info *edge_info; - edge_info = allocate_edge_info (true_edge); + edge_info = new class edge_info (true_edge); record_conditions (&edge_info->cond_equivalences, cond, inverted); if (can_infer_simple_equiv && code == EQ_EXPR) - { - edge_info->lhs = op0; - edge_info->rhs = op1; - } + edge_info->record_simple_equiv (op0, op1); - edge_info = allocate_edge_info (false_edge); + edge_info = new class edge_info (false_edge); record_conditions (&edge_info->cond_equivalences, inverted, cond); if (can_infer_simple_equiv && TREE_CODE (inverted) == EQ_EXPR) - { - edge_info->lhs = op0; - edge_info->rhs = op1; - } + edge_info->record_simple_equiv (op0, op1); } } - - /* ??? TRUTH_NOT_EXPR can create an equivalence too. */ } } @@ -738,7 +748,7 @@ record_temporary_equivalences (edge e, class avail_exprs_stack *avail_exprs_stack) { int i; - struct edge_info *edge_info = (struct edge_info *) e->aux; + class edge_info *edge_info = (class edge_info *) e->aux; /* If we have info associated with this edge, record it into our equivalence tables. */ @@ -771,68 +781,73 @@ record_temporary_equivalences (edge e, } } - tree lhs = edge_info->lhs; - if (!lhs || TREE_CODE (lhs) != SSA_NAME) - return; + edge_info::equiv_pair *seq; + for (i = 0; edge_info->simple_equivalences.iterate (i, &seq); ++i) + { + tree lhs = seq->first; + if (!lhs || TREE_CODE (lhs) != SSA_NAME) + continue; - /* Record the simple NAME = VALUE equivalence. */ - tree rhs = edge_info->rhs; + /* Record the simple NAME = VALUE equivalence. */ + tree rhs = seq->second; - /* If this is a SSA_NAME = SSA_NAME equivalence and one operand is - cheaper to compute than the other, then set up the equivalence - such that we replace the expensive one with the cheap one. + /* If this is a SSA_NAME = SSA_NAME equivalence and one operand is + cheaper to compute than the other, then set up the equivalence + such that we replace the expensive one with the cheap one. - If they are the same cost to compute, then do not record anything. */ - if (TREE_CODE (lhs) == SSA_NAME && TREE_CODE (rhs) == SSA_NAME) - { - gimple *rhs_def = SSA_NAME_DEF_STMT (rhs); - int rhs_cost = estimate_num_insns (rhs_def, &eni_size_weights); + If they are the same cost to compute, then do not record + anything. */ + if (TREE_CODE (lhs) == SSA_NAME && TREE_CODE (rhs) == SSA_NAME) + { + gimple *rhs_def = SSA_NAME_DEF_STMT (rhs); + int rhs_cost = estimate_num_insns (rhs_def, &eni_size_weights); - gimple *lhs_def = SSA_NAME_DEF_STMT (lhs); - int lhs_cost = estimate_num_insns (lhs_def, &eni_size_weights); + gimple *lhs_def = SSA_NAME_DEF_STMT (lhs); + int lhs_cost = estimate_num_insns (lhs_def, &eni_size_weights); - if (rhs_cost > lhs_cost) - record_equality (rhs, lhs, const_and_copies); - else if (rhs_cost < lhs_cost) + if (rhs_cost > lhs_cost) + record_equality (rhs, lhs, const_and_copies); + else if (rhs_cost < lhs_cost) + record_equality (lhs, rhs, const_and_copies); + } + else record_equality (lhs, rhs, const_and_copies); - } - else - record_equality (lhs, rhs, const_and_copies); - /* If LHS is an SSA_NAME and RHS is a constant integer and LHS was - set via a widening type conversion, then we may be able to record - additional equivalences. */ - if (TREE_CODE (rhs) == INTEGER_CST) - { - gimple *defstmt = SSA_NAME_DEF_STMT (lhs); - - if (defstmt - && is_gimple_assign (defstmt) - && CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (defstmt))) + /* If LHS is an SSA_NAME and RHS is a constant integer and LHS was + set via a widening type conversion, then we may be able to record + additional equivalences. */ + if (TREE_CODE (rhs) == INTEGER_CST) { - tree old_rhs = gimple_assign_rhs1 (defstmt); - - /* If the conversion widens the original value and - the constant is in the range of the type of OLD_RHS, - then convert the constant and record the equivalence. - - Note that int_fits_type_p does not check the precision - if the upper and lower bounds are OK. */ - if (INTEGRAL_TYPE_P (TREE_TYPE (old_rhs)) - && (TYPE_PRECISION (TREE_TYPE (lhs)) - > TYPE_PRECISION (TREE_TYPE (old_rhs))) - && int_fits_type_p (rhs, TREE_TYPE (old_rhs))) + gimple *defstmt = SSA_NAME_DEF_STMT (lhs); + + if (defstmt + && is_gimple_assign (defstmt) + && CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (defstmt))) { - tree newval = fold_convert (TREE_TYPE (old_rhs), rhs); - record_equality (old_rhs, newval, const_and_copies); + tree old_rhs = gimple_assign_rhs1 (defstmt); + + /* If the conversion widens the original value and + the constant is in the range of the type of OLD_RHS, + then convert the constant and record the equivalence. + + Note that int_fits_type_p does not check the precision + if the upper and lower bounds are OK. */ + if (INTEGRAL_TYPE_P (TREE_TYPE (old_rhs)) + && (TYPE_PRECISION (TREE_TYPE (lhs)) + > TYPE_PRECISION (TREE_TYPE (old_rhs))) + && int_fits_type_p (rhs, TREE_TYPE (old_rhs))) + { + tree newval = fold_convert (TREE_TYPE (old_rhs), rhs); + record_equality (old_rhs, newval, const_and_copies); + } } } - } - /* Any equivalence found for LHS may result in additional - equivalences for other uses of LHS that we have already - processed. */ - back_propagate_equivalences (lhs, e, const_and_copies); + /* Any equivalence found for LHS may result in additional + equivalences for other uses of LHS that we have already + processed. */ + back_propagate_equivalences (lhs, e, const_and_copies); + } } } @@ -1124,14 +1139,20 @@ cprop_into_successor_phis (basic_block bb, Don't bother with [01] = COND equivalences, they're not useful here. */ - struct edge_info *edge_info = (struct edge_info *) e->aux; + class edge_info *edge_info = (class edge_info *) e->aux; + if (edge_info) { - tree lhs = edge_info->lhs; - tree rhs = edge_info->rhs; + edge_info::equiv_pair *seq; + for (int i = 0; edge_info->simple_equivalences.iterate (i, &seq); ++i) + { + tree lhs = seq->first; + tree rhs = seq->second; + + if (lhs && TREE_CODE (lhs) == SSA_NAME) + const_and_copies->record_const_or_copy (lhs, rhs); + } - if (lhs && TREE_CODE (lhs) == SSA_NAME) - const_and_copies->record_const_or_copy (lhs, rhs); } indx = e->dest_idx; @@ -1701,8 +1722,7 @@ optimize_stmt (basic_block bb, gimple_stmt_iterator si, gimple_set_vuse (new_stmt, gimple_vuse (stmt)); cached_lhs = avail_exprs_stack->lookup_avail_expr (new_stmt, false, false); - if (cached_lhs - && rhs == cached_lhs) + if (cached_lhs && operand_equal_p (rhs, cached_lhs, 0)) { basic_block bb = gimple_bb (stmt); unlink_stmt_vdef (stmt);