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