Patch Detail
get:
Show a patch.
patch:
Update a patch.
put:
Update a patch.
GET /api/patches/2231302/?format=api
{ "id": 2231302, "url": "http://patchwork.ozlabs.org/api/patches/2231302/?format=api", "web_url": "http://patchwork.ozlabs.org/project/gcc/patch/DI6KI7UV67P0.34JJS8EFC64T9@gmail.com/", "project": { "id": 17, "url": "http://patchwork.ozlabs.org/api/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": "<DI6KI7UV67P0.34JJS8EFC64T9@gmail.com>", "list_archive_url": null, "date": "2026-04-30T14:43:31", "name": "backprop: Add demand-bit handling. [PR113487]", "commit_ref": null, "pull_url": null, "state": "new", "archived": false, "hash": "ab9de38cbec30094c69a9a630a0c01ac7578c36a", "submitter": { "id": 86205, "url": "http://patchwork.ozlabs.org/api/people/86205/?format=api", "name": "Robin Dapp", "email": "rdapp.gcc@gmail.com" }, "delegate": null, "mbox": "http://patchwork.ozlabs.org/project/gcc/patch/DI6KI7UV67P0.34JJS8EFC64T9@gmail.com/mbox/", "series": [ { "id": 502318, "url": "http://patchwork.ozlabs.org/api/series/502318/?format=api", "web_url": "http://patchwork.ozlabs.org/project/gcc/list/?series=502318", "date": "2026-04-30T14:43:31", "name": "backprop: Add demand-bit handling. [PR113487]", "version": 1, "mbox": "http://patchwork.ozlabs.org/series/502318/mbox/" } ], "comments": "http://patchwork.ozlabs.org/api/patches/2231302/comments/", "check": "pending", "checks": "http://patchwork.ozlabs.org/api/patches/2231302/checks/", "tags": {}, "related": [], "headers": { "Return-Path": "<gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org>", "X-Original-To": [ "incoming@patchwork.ozlabs.org", "gcc-patches@gcc.gnu.org" ], "Delivered-To": [ "patchwork-incoming@legolas.ozlabs.org", "gcc-patches@gcc.gnu.org" ], "Authentication-Results": [ "legolas.ozlabs.org;\n\tdkim=pass (2048-bit key;\n unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256\n header.s=20251104 header.b=lhtLzTzo;\n\tdkim-atps=neutral", "legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org\n (client-ip=2620:52:6:3111::32; helo=vm01.sourceware.org;\n envelope-from=gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org;\n receiver=patchwork.ozlabs.org)", "sourceware.org;\n\tdkim=pass (2048-bit key,\n unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256\n header.s=20251104 header.b=lhtLzTzo", "sourceware.org;\n dmarc=pass (p=none dis=none) header.from=gmail.com", "sourceware.org; spf=pass smtp.mailfrom=gmail.com", "server2.sourceware.org;\n arc=none smtp.remote-ip=209.85.128.46" ], "Received": [ "from vm01.sourceware.org (vm01.sourceware.org\n [IPv6:2620:52:6:3111::32])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange x25519 server-signature ECDSA (secp384r1) server-digest SHA384)\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4g5xkx4rd9z1yJr\n\tfor <incoming@patchwork.ozlabs.org>; Fri, 01 May 2026 00:44:09 +1000 (AEST)", "from vm01.sourceware.org (localhost [127.0.0.1])\n\tby sourceware.org (Postfix) with ESMTP id 976D143B5522\n\tfor <incoming@patchwork.ozlabs.org>; Thu, 30 Apr 2026 14:44:07 +0000 (GMT)", "from mail-wm1-f46.google.com (mail-wm1-f46.google.com\n [209.85.128.46])\n by sourceware.org (Postfix) with ESMTPS id EEB844BB3BE3\n for <gcc-patches@gcc.gnu.org>; Thu, 30 Apr 2026 14:43:34 +0000 (GMT)", "by mail-wm1-f46.google.com with SMTP id\n 5b1f17b1804b1-483487335c2so11527105e9.2\n for <gcc-patches@gcc.gnu.org>; Thu, 30 Apr 2026 07:43:34 -0700 (PDT)", "from localhost (ip-085-216-098-084.um25.pools.vodafone-ip.de.\n [85.216.98.84]) by smtp.gmail.com with ESMTPSA id\n 5b1f17b1804b1-48a7b900af7sm45025615e9.1.2026.04.30.07.43.32\n (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128);\n Thu, 30 Apr 2026 07:43:32 -0700 (PDT)" ], "DKIM-Filter": [ "OpenDKIM Filter v2.11.0 sourceware.org 976D143B5522", "OpenDKIM Filter v2.11.0 sourceware.org EEB844BB3BE3" ], "DMARC-Filter": "OpenDMARC Filter v1.4.2 sourceware.org EEB844BB3BE3", "ARC-Filter": "OpenARC Filter v1.0.0 sourceware.org EEB844BB3BE3", "ARC-Seal": "i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1777560215; cv=none;\n b=mzqbmzs2LxzuLAwXRYU15XMaUua/QPc4ZNN2GgmeAL8zOBUL0SuhMZK97C/d2lw4FAzlk1fH9A9QumwKap3hv1e6FyFK1GM0q6B0V+T2YuYGVD7Mu/UhAl8UXGCKxi8T5oe8qsLmZ9IE68imOEt3OptsjGZwqVZCMQej8I44nvE=", "ARC-Message-Signature": "i=1; a=rsa-sha256; d=sourceware.org; s=key;\n t=1777560215; c=relaxed/simple;\n bh=h/d0bZeK+6QJMIwTdNV8OtPB56nGCQBcnL7yJ+0LB/U=;\n h=DKIM-Signature:Mime-Version:Date:Message-Id:To:From:Subject;\n b=Egbh404SG6XKNgccTxJptEqXPTxHvgMm36ioybhJxT5XliC1ZAyzMW/kf4TlE3MqEySmipdSLzX2kL5I3QoZfvOryQEPRHXEya8DxqC1zUzJdKgUBk7jp/mZXrGJ93EgwDzntTzKnpdeoTPzCIdc9Z+w4ir4ZdROt9OgGo8aExk=", "ARC-Authentication-Results": "i=1; server2.sourceware.org", "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=gmail.com; s=20251104; t=1777560213; x=1778165013; darn=gcc.gnu.org;\n h=subject:from:to:cc:message-id:date:content-transfer-encoding\n :mime-version:from:to:cc:subject:date:message-id:reply-to;\n bh=+dLOsJbnxI4Hr9Dfv1tMi7/0qPaTFpWiEVJvX+XoceY=;\n b=lhtLzTzo4EXuZGTfG/1sqAoawQ2hzB9/jcv9g2WRSHule9EHyO/BQZCxMqZvLoCjnH\n kitTgWh6gvY4a5seB2smB5/vgmciHzMSz0JIrKfklLw6W+SEDFFb+WLHmNmVkXjJ9APs\n TuL+EWGXoPCJPOTBV1NXHRNB1j7jVXkngfX9YwggaquUAc9KH7o+AASsDLmgVjt4doFi\n NqVq1Gfuo+L529TuBvuZkjZbWSZuCpQtvQLNMiNIjs8XicOpm5gl826Ak0B7rbKPkKG9\n rw732pGhe0jIiGnMpWaE6S+tC9XTbtCrjV7O5lnVNRsFbXsAxOaTSEFsKf8j8zzshCFP\n 2xKA==", "X-Google-DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=1e100.net; s=20251104; t=1777560213; x=1778165013;\n h=subject:from:to:cc:message-id:date:content-transfer-encoding\n :mime-version:x-gm-gg:x-gm-message-state:from:to:cc:subject:date\n :message-id:reply-to;\n bh=+dLOsJbnxI4Hr9Dfv1tMi7/0qPaTFpWiEVJvX+XoceY=;\n b=cMMRSCbv0tnokC6tY3JWsok33dOPUpRX3/cldXljXBisXWUNecgGviE6uT8mFMw9La\n z9byUulPEHWdak3FE0MQKjAJ+5DFYrwoDz5jLwFa5YO9tFqWaWUb9FM+Rb/emIL/sjNY\n kNElIM0QgyYtcXTJHqhA0FKNuAh/UHtz/tt3FL6uSJjMjPXtuKOcWdytnPF0vY5Vnb/l\n 44oa7tgx704QXudvvcm0PmgUHw2nZN8VMKXSuFEMRMSBC7nYIBpNBiEKBy6LeMwwleJO\n aPBDcXmMzc91rI1G4ekI2vqXEffoopblessUJoLTsyojFuUiPueC0RWJl0vq2JjQ7a3K\n lqYw==", "X-Gm-Message-State": "AOJu0Yz3yPC2q3z3k1qaCNUq3BvCUSZElfR0ZiYJY0iA4mTsUjMra4fC\n L0pryKqH63b4DIh4j2BniBVdoMsOHt/LAQJG9oa//SOz07YU5mOacQ3Y+ZjThw==", "X-Gm-Gg": "AeBDieuUw2wEyAB5+aJzZZAG4l403Icv5vDmrQcBtDGUHPCUhP8XydxjtlzMq1QPaGC\n chtHHh63cgeNNg+dfLTNQymZfuSRm0iaqiUEwY+61Kgfuv4nP6D5a7paxuoFaCDI2tjujmoFlNT\n dCk6l8eeKsowflwOAzfA+iYSciy7USJnb/HuMHx+EESB9nQq/FZpG9ZJ45HHamJumF18SwaaLT8\n 0/qu+8Z34c7/JDPMvBjbXJXs5+5ZxZoO6v9aFxvG83wgmSOImLCpoFuqUX0yUQRM4AKr8BGuP5t\n a5J5qvaKGMtqIf4Uvjy8x8dDqk22WfPAhYrNMCN5noMAURA0JlZOqqU9PmLyd+P2X6z78rNVBfZ\n KPlQpxdiiDGz8iwpndht9bHOFBo/V7W449sKgXsVFi3t/DIQ2FI9zPWiuVOM6nDcNLmxA8TzWC7\n 474DCwRxsLC1zXXhfwMM3/Wq+nQlge43Ck/hL9PTxrtujYpzuz63nuq7Q6Tt5WESuM4YfTShcI5\n FZDXkM=", "X-Received": "by 2002:a05:600c:a119:b0:48a:75b9:5e07 with SMTP id\n 5b1f17b1804b1-48a844f4de3mr41437385e9.11.1777560212921;\n Thu, 30 Apr 2026 07:43:32 -0700 (PDT)", "Mime-Version": "1.0", "Content-Transfer-Encoding": "quoted-printable", "Content-Type": "text/plain; charset=UTF-8", "Date": "Thu, 30 Apr 2026 16:43:31 +0200", "Message-Id": "<DI6KI7UV67P0.34JJS8EFC64T9@gmail.com>", "Cc": "\"Robin Dapp\" <rdapp.gcc@gmail.com>", "To": "\"gcc-patches\" <gcc-patches@gcc.gnu.org>, \"Richard Sandiford\"\n <rdsandiford@googlemail.com>", "From": "\"Robin Dapp\" <rdapp.gcc@gmail.com>", "Subject": "[PATCH] backprop: Add demand-bit handling. [PR113487]", "X-BeenThere": "gcc-patches@gcc.gnu.org", "X-Mailman-Version": "2.1.30", "Precedence": "list", "List-Id": "Gcc-patches mailing list <gcc-patches.gcc.gnu.org>", "List-Unsubscribe": "<https://gcc.gnu.org/mailman/options/gcc-patches>,\n <mailto:gcc-patches-request@gcc.gnu.org?subject=unsubscribe>", "List-Archive": "<https://gcc.gnu.org/pipermail/gcc-patches/>", "List-Post": "<mailto:gcc-patches@gcc.gnu.org>", "List-Help": "<mailto:gcc-patches-request@gcc.gnu.org?subject=help>", "List-Subscribe": "<https://gcc.gnu.org/mailman/listinfo/gcc-patches>,\n <mailto:gcc-patches-request@gcc.gnu.org?subject=subscribe>", "Errors-To": "gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org" }, "content": "Hi,\n\nThis patch adds backpropagation of demand-bit information to the\nbackprop pass. It is intended to catch cases like this\n\n int\n foo (int in)\n {\n int a = in & 0xff;\n int b = a << 1;\n int c = b & 0xf;\n return c;\n }\n\nwhere we can propagate B's demand of 0xf back to IN and elide the\n& 0xff masking. This works in situations where forward-looking\noptimizations like in match.pd fail, for example due to non-single\nuse.\n\nI tried to keep the implementation simple at first, but it grew\nover time and now handles BIT_AND_EXPR, BIT_IOR_EXPR, BIT_XOR_EXPR,\nMULT_EXPR, LSHIFT_EXPR, RSHIFT_EXPR, and PLUS_EXPR, MINUS_EXPR.\n\nThe most important case is surely eliding masks: Once the demand has reached\na BIT_AND_EXPR and we see that it does not exceed what we mask off anyway, we\nelide it. In SPECint 2017 this hits a couple hundred times, predominantly gcc \nand perlbench, albeit not in very hot code paths.\n\nBootstrapped and regtested on x86, power10, and aarch64.\nRegtested on riscv64.\n\nRegards\n Robin\n\n\tPR tree-optimization/113487\n\tPR tree-optimization/122209\n\ngcc/ChangeLog:\n\n\t* gimple-ssa-backprop.cc (usage_info::intersection_identity):\n\tAdd demand-bit handling.\n\t(usage_info::is_useful): Ditto.\n\t(dump_usage_info): Log demand bits.\n\t(backprop::process_assign_use): Handle demand bits.\n\t(backprop::process_phi_use): Ditto.\n\t(backprop::intersect_uses): Ditto.\n\t(backprop::process_var): Ditto.\n\t(backprop::optimize_assign): Elide mask if possible.\n\ngcc/testsuite/ChangeLog:\n\n\t* gcc.dg/tree-ssa/backprop-bits-1.c: New test.\n\t* gcc.dg/tree-ssa/backprop-bits-2.c: New test.\n\t* gcc.dg/tree-ssa/backprop-bits-3.c: New test.\n\t* gcc.dg/tree-ssa/backprop-bits-4.c: New test.\n\t* gcc.dg/tree-ssa/backprop-bits-5.c: New test.\n\t* gcc.dg/tree-ssa/backprop-bits-6.c: New test.\n\t* gcc.dg/tree-ssa/backprop-bits-7.c: New test.\n\t* gcc.dg/tree-ssa/backprop-bits-8.c: New test.\n---\n gcc/gimple-ssa-backprop.cc | 435 ++++++++++++++++--\n .../gcc.dg/tree-ssa/backprop-bits-1.c | 16 +\n .../gcc.dg/tree-ssa/backprop-bits-2.c | 29 ++\n .../gcc.dg/tree-ssa/backprop-bits-3.c | 29 ++\n .../gcc.dg/tree-ssa/backprop-bits-4.c | 34 ++\n .../gcc.dg/tree-ssa/backprop-bits-5.c | 39 ++\n .../gcc.dg/tree-ssa/backprop-bits-6.c | 18 +\n .../gcc.dg/tree-ssa/backprop-bits-7.c | 41 ++\n .../gcc.dg/tree-ssa/backprop-bits-8.c | 31 ++\n 9 files changed, 643 insertions(+), 29 deletions(-)\n create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/backprop-bits-1.c\n create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/backprop-bits-2.c\n create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/backprop-bits-3.c\n create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/backprop-bits-4.c\n create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/backprop-bits-5.c\n create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/backprop-bits-6.c\n create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/backprop-bits-7.c\n create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/backprop-bits-8.c", "diff": "diff --git a/gcc/gimple-ssa-backprop.cc b/gcc/gimple-ssa-backprop.cc\nindex 3ac44116d27..0e36489691b 100644\n--- a/gcc/gimple-ssa-backprop.cc\n+++ b/gcc/gimple-ssa-backprop.cc\n@@ -23,12 +23,13 @@ along with GCC; see the file COPYING3. If not see\n fully or partially dead code, but the main focus is simplifying\n computations.\n \n- At the moment the pass only handles one piece of information: whether the\n- sign of a value matters, and therefore whether sign-changing operations\n- can be skipped. The pass could be extended to more interesting\n- information in future, such as which bits of an integer are significant.\n+ The pass only handles two distinct properties:\n+ (a) Whether the sign of a value matters, and therefore whether\n+\t sign-changing operations can be skipped.\n+ (b) The bits a variable demands. This opens up possibilities to\n+\t elide redundant bit masking.\n \n- For example, take the function:\n+ For an example of (a), take the function:\n \n double\n f (double *a, int n, double start)\n@@ -48,6 +49,28 @@ along with GCC; see the file COPYING3. If not see\n with start. Since there are no other uses of the fabs result,\n the call would get deleted as dead.\n \n+ A typical case for (b) is:\n+\n+ void use (unsigned);\n+\n+ void\n+ foo (unsigned x)\n+ {\n+ unsigned a = x & 0xff;\n+ unsigned b = a * 4;\n+ use (b & 0x10);\n+ use (b & 0xe0);\n+ }\n+\n+ Both use sites of B mask it and we cannot look through the multiplication to\n+ elide the masking directly (via e.g. match.pd or ccp). Seeing the demand\n+ on B (= 0xf0), we can back-propagate it to B's definition and deduce which\n+ bits A demands (= 0xf0 >> 2 = 0x3c).\n+ Then, continuing at A's definition we see that there is no bit demand\n+ outside of 0xff, so no necessary bit the mask would clear. As a\n+ consequence, the masking can be elided.\n+\n+\n The algorithm is:\n \n (1) Do a post-order traversal of the blocks in the function, walking\n@@ -110,9 +133,9 @@ namespace {\n class usage_info\n {\n public:\n- usage_info () : flag_word (0) {}\n+ usage_info () : flag_word (0), needed_bits (-1) {}\n+\n usage_info &operator &= (const usage_info &);\n- usage_info operator & (const usage_info &) const;\n bool operator == (const usage_info &) const;\n bool operator != (const usage_info &) const;\n bool is_useful () const;\n@@ -129,6 +152,9 @@ public:\n /* All the flag bits as a single int. */\n unsigned int flag_word;\n };\n+\n+ /* The live bits. */\n+ widest_int needed_bits;\n };\n \n /* Return an X such that X & Y == Y for all Y. This is the most\n@@ -139,6 +165,7 @@ usage_info::intersection_identity ()\n {\n usage_info ret;\n ret.flag_word = -1;\n+ ret.needed_bits = 0;\n return ret;\n }\n \n@@ -149,24 +176,15 @@ usage_info &\n usage_info::operator &= (const usage_info &other)\n {\n flag_word &= other.flag_word;\n+ needed_bits = needed_bits | other.needed_bits;\n return *this;\n }\n \n-/* Return the intersection of *THIS and OTHER, i.e. a structure that\n- describes all uses covered by *THIS and OTHER. */\n-\n-usage_info\n-usage_info::operator & (const usage_info &other) const\n-{\n- usage_info info (*this);\n- info &= other;\n- return info;\n-}\n-\n bool\n usage_info::operator == (const usage_info &other) const\n {\n- return flag_word == other.flag_word;\n+ return flag_word == other.flag_word\n+ && needed_bits == other.needed_bits;\n }\n \n bool\n@@ -180,7 +198,7 @@ usage_info::operator != (const usage_info &other) const\n bool\n usage_info::is_useful () const\n {\n- return flag_word != 0;\n+ return flag_word != 0 || needed_bits != -1;\n }\n \n /* Start a dump line about SSA name VAR. */\n@@ -203,6 +221,18 @@ dump_usage_info (FILE *file, tree var, usage_info *info)\n dump_usage_prefix (file, var);\n fprintf (file, \"sign bit not important\\n\");\n }\n+ if (info->needed_bits != -1)\n+ {\n+ tree type = TREE_TYPE (var);\n+ if (VECTOR_TYPE_P (type))\n+\ttype = TREE_TYPE (type);\n+ unsigned prec = TYPE_PRECISION (type);\n+ wide_int mask = wide_int::from (info->needed_bits, prec, UNSIGNED);\n+ dump_usage_prefix (file, var);\n+ fprintf (file, \"demand bit mask: \");\n+ print_hex (mask, file);\n+ fprintf (file, \"\\n\");\n+ }\n }\n \n /* Represents one execution of the pass. */\n@@ -233,6 +263,7 @@ private:\n void complete_change (gimple *);\n void optimize_builtin_call (gcall *, tree, const usage_info *);\n void replace_assign_rhs (gassign *, tree, tree, tree, tree);\n+ void build_nop_rhs (gassign *, tree);\n void optimize_assign (gassign *, tree, const usage_info *);\n void optimize_phi (gphi *, tree, const usage_info *);\n \n@@ -417,7 +448,12 @@ void\n backprop::process_assign_use (gassign *assign, tree rhs, usage_info *info)\n {\n tree lhs = gimple_assign_lhs (assign);\n- switch (gimple_assign_rhs_code (assign))\n+ const usage_info *lhs_info = lookup_operand (lhs);\n+ info->needed_bits = -1;\n+\n+ tree_code code = gimple_assign_rhs_code (assign);\n+\n+ switch (code)\n {\n case ABS_EXPR:\n case ABSU_EXPR:\n@@ -430,17 +466,56 @@ backprop::process_assign_use (gassign *assign, tree rhs, usage_info *info)\n \t to C and D. */\n if (rhs != gimple_assign_rhs1 (assign))\n \t{\n-\t const usage_info *lhs_info = lookup_operand (lhs);\n \t if (lhs_info)\n \t *info = *lhs_info;\n \t}\n break;\n \n case MULT_EXPR:\n- /* In X * X, the sign of X doesn't matter. */\n- if (gimple_assign_rhs1 (assign) == rhs\n-\t && gimple_assign_rhs2 (assign) == rhs)\n-\tinfo->flags.ignore_sign = true;\n+\t{\n+\t /* In X * X, the sign of X doesn't matter. */\n+\t if (gimple_assign_rhs1 (assign) == rhs\n+\t && gimple_assign_rhs2 (assign) == rhs)\n+\t info->flags.ignore_sign = true;\n+\n+\t tree type = TREE_TYPE (lhs);\n+\t if (VECTOR_TYPE_P (type))\n+\t type = TREE_TYPE (type);\n+\n+\t tree other = (rhs == gimple_assign_rhs1 (assign))\n+\t\t ? gimple_assign_rhs2 (assign)\n+\t\t : gimple_assign_rhs1 (assign);\n+\t wide_int nz;\n+\n+\t /* Given the output demand, we assume that all input bits not\n+\t higher than the output's highest set bit can contribute to the\n+\t output. If we know that a number of low bits are zero, we\n+\t have a lower bound on the bits.\n+\t For a multiplication by a power of two there is no carry and\n+\t we can simply shift the output.\n+\t */\n+\t if (INTEGRAL_TYPE_P (type) && lhs_info\n+\t && lhs_info->needed_bits != -1\n+\t && (nz = get_nonzero_bits (other)).get_precision () != 0)\n+\t {\n+\t widest_int wnz = widest_int::from (nz, UNSIGNED);\n+\t HOST_WIDE_INT lo = wi::ctz (wnz);\n+\t HOST_WIDE_INT hi = wi::floor_log2 (lhs_info->needed_bits);\n+\n+\t if (wnz == 0)\n+\t\tinfo->needed_bits = 0;\n+\t else if (wi::popcount (wnz) == 1)\n+\t\tinfo->needed_bits = lo > 0\n+\t\t ? wi::lrshift (lhs_info->needed_bits, lo)\n+\t\t : lhs_info->needed_bits;\n+\t else if (hi < lo)\n+\t\tinfo->needed_bits = 0;\n+\t else\n+\t\tinfo->needed_bits\n+\t\t = wi::mask<widest_int> (hi - lo + 1, false);\n+\t }\n+\t}\n+\n /* Fall through. */\n \n case NEGATE_EXPR:\n@@ -449,12 +524,203 @@ backprop::process_assign_use (gassign *assign, tree rhs, usage_info *info)\n \t doesn't matter either. */\n if (FLOAT_TYPE_P (TREE_TYPE (rhs)))\n \t{\n-\t const usage_info *lhs_info = lookup_operand (lhs);\n \t if (lhs_info)\n \t info->flags.ignore_sign = lhs_info->flags.ignore_sign;\n \t}\n break;\n \n+ case TRUNC_DIV_EXPR:\n+\t{\n+\t tree type = TREE_TYPE (rhs);\n+\t if (VECTOR_TYPE_P (type))\n+\t type = TREE_TYPE (type);\n+\t if (!INTEGRAL_TYPE_P (type) || !TYPE_UNSIGNED (type))\n+\t break;\n+\n+\t tree rhs1 = gimple_assign_rhs1 (assign);\n+\t tree rhs2 = gimple_assign_rhs2 (assign);\n+\t if (rhs != rhs1 || TREE_CODE (rhs2) != INTEGER_CST)\n+\t break;\n+\n+\t if (!lhs_info || lhs_info->needed_bits == -1)\n+\t break;\n+\n+\t widest_int div = widest_int::from (wi::to_wide (rhs2), UNSIGNED);\n+\t if (div == 0)\n+\t break;\n+\n+\t /* Opposite to multiplication, with division at least all LHS bits\n+\t contribute. As the input is not smaller than the output, the\n+\t RHS determines the number of bits that contribute on top,\n+\t with the highest bit marking the upper bound.\n+\n+\t An example is that we're looking for IN's bits that could\n+\t contribute to the known bits of A:\n+\n+\t char a = in / 3;\n+\t\t |\n+\t 0b00001101 = ? / 3\n+\n+\t =>\n+\n+\t 0b00001101 = 0b00??1101 / 3\n+\n+\t So the lower bits come from the output (A), while the next higher\n+\t ones come from the division by 3. */\n+\n+\t HOST_WIDE_INT log_k = wi::exact_log2 (div);\n+\t if (log_k >= 0)\n+\t info->needed_bits = wi::lshift (lhs_info->needed_bits, log_k);\n+\t else\n+\t {\n+\t HOST_WIDE_INT needed_out\n+\t\t= wi::floor_log2 (lhs_info->needed_bits);\n+\t HOST_WIDE_INT needed_cst = wi::floor_log2 (div - 1) + 1;\n+\t HOST_WIDE_INT width = needed_out + needed_cst + 1;\n+\t unsigned prec = TYPE_PRECISION (type);\n+\t if (width >= (HOST_WIDE_INT) prec)\n+\t\tinfo->needed_bits = -1;\n+\t else\n+\t\tinfo->needed_bits = wi::mask<widest_int> (width, false);\n+\t }\n+\t}\n+ break;\n+\n+ case BIT_AND_EXPR:\n+\t{\n+\t if (lhs_info)\n+\t info->needed_bits = lhs_info->needed_bits;\n+\n+\t tree other;\n+\t if (rhs == gimple_assign_rhs1 (assign))\n+\t other = gimple_assign_rhs2 (assign);\n+\t else\n+\t other = gimple_assign_rhs1 (assign);\n+\n+\t wide_int nz = get_nonzero_bits (other);\n+\t widest_int wnz (-1);\n+\t if (nz.get_precision () != 0)\n+\t wnz = widest_int::from (nz, UNSIGNED);\n+\t info->needed_bits &= wnz;\n+\t}\n+ break;\n+\n+ case LSHIFT_EXPR:\n+ case RSHIFT_EXPR:\n+ if (rhs == gimple_assign_rhs1 (assign))\n+\t{\n+\t tree rhs2 = gimple_assign_rhs2 (assign);\n+\t if (TREE_CODE (rhs2) == INTEGER_CST\n+\t && lhs_info)\n+\t {\n+\t info->needed_bits = lhs_info->needed_bits;\n+\t widest_int shift_count\n+\t\t= widest_int::from (wi::to_wide (rhs2), UNSIGNED);\n+\n+\t if (code == LSHIFT_EXPR)\n+\t\tinfo->needed_bits = wi::lrshift (info->needed_bits,\n+\t\t\t\t\t\t shift_count);\n+\t else\n+\t\t{\n+\t\t if (TYPE_UNSIGNED (TREE_TYPE (rhs)))\n+\t\t info->needed_bits = wi::lshift (info->needed_bits,\n+\t\t\t\t\t\t shift_count);\n+\t\t /* ??? Treat sign extension conservatively for now. */\n+\t\t else\n+\t\t info->needed_bits = -1;\n+\t\t}\n+\t }\n+\t}\n+ break;\n+\n+ case PLUS_EXPR:\n+ case MINUS_EXPR:\n+ if (rhs == gimple_assign_rhs1 (assign)\n+\t || rhs == gimple_assign_rhs2 (assign))\n+\t{\n+\t if (lhs_info)\n+\t info->needed_bits = lhs_info->needed_bits;\n+\n+\t tree type = TREE_TYPE (rhs);\n+\t if (VECTOR_TYPE_P (type))\n+\t type = TREE_TYPE (type);\n+\n+\t if (info->needed_bits != -1)\n+\t {\n+\t int hi = wi::floor_log2 (info->needed_bits);\n+\t info->needed_bits = wi::mask<widest_int> (hi + 1, false);\n+\t }\n+\t}\n+ break;\n+\n+ case LROTATE_EXPR:\n+ case RROTATE_EXPR:\n+ if (rhs == gimple_assign_rhs1 (assign))\n+\t{\n+\t tree rhs2 = gimple_assign_rhs2 (assign);\n+\t tree type = TREE_TYPE (rhs);\n+\t if (VECTOR_TYPE_P (type))\n+\t type = TREE_TYPE (type);\n+\t HOST_WIDE_INT prec = TYPE_PRECISION (type);\n+\n+\t if (TREE_CODE (rhs2) == INTEGER_CST)\n+\t {\n+\t widest_int count\n+\t\t= widest_int::from (wi::to_wide (rhs2), UNSIGNED);\n+\n+\t if (lhs_info)\n+\t\tinfo->needed_bits = lhs_info->needed_bits;\n+\n+\t if (code == LROTATE_EXPR)\n+\t\tinfo->needed_bits = wi::rrotate (info->needed_bits, count,\n+\t\t\t\t\t\t prec);\n+\t else\n+\t\tinfo->needed_bits = wi::lrotate (info->needed_bits, count,\n+\t\t\t\t\t\t prec);\n+\t }\n+\t}\n+ break;\n+\n+ case NOP_EXPR:\n+ case CONVERT_EXPR:\n+\t{\n+\t tree rhs1 = gimple_assign_rhs1 (assign);\n+\t tree rhs_type = TREE_TYPE (rhs1);\n+\t tree lhs_type = TREE_TYPE (lhs);\n+\t if (VECTOR_TYPE_P (lhs_type))\n+\t {\n+\t lhs_type = TREE_TYPE (lhs_type);\n+\t rhs_type = TREE_TYPE (rhs_type);\n+\t }\n+\n+\t if (!INTEGRAL_TYPE_P (lhs_type) || !INTEGRAL_TYPE_P (rhs_type)\n+\t || !lhs_info)\n+\t break;\n+\n+\t HOST_WIDE_INT rhs_prec = TYPE_PRECISION (rhs_type);\n+\t HOST_WIDE_INT lhs_prec = TYPE_PRECISION (lhs_type);\n+\n+\t if (lhs_prec <= rhs_prec)\n+\t info->needed_bits = lhs_info->needed_bits;\n+\t else if (TYPE_UNSIGNED (rhs_type))\n+\t info->needed_bits\n+\t = lhs_info->needed_bits & wi::mask<widest_int> (rhs_prec, false);\n+\t else\n+\t /* As in the RSHIFT case above, treat sign extension\n+\t conservatively for now. */\n+\t info->needed_bits = -1;\n+\t}\n+ break;\n+\n+ /* The following expressions don't affect the needed bits so we can just\n+\t pass through the output. */\n+ case BIT_IOR_EXPR:\n+ case BIT_XOR_EXPR:\n+ case BIT_NOT_EXPR:\n+ if (lhs_info)\n+\tinfo->needed_bits = lhs_info->needed_bits;\n+ break;\n+\n default:\n break;\n }\n@@ -468,6 +734,8 @@ backprop::process_phi_use (gphi *phi, usage_info *info)\n tree result = gimple_phi_result (phi);\n if (const usage_info *result_info = lookup_operand (result))\n *info = *result_info;\n+ else\n+ info->needed_bits = -1;\n }\n \n /* Make INFO describe all uses of RHS in STMT. */\n@@ -601,7 +869,10 @@ backprop::process_var (tree var)\n else if (info != *map_info)\n \t{\n \t /* Recording information that is less optimistic than before. */\n-\t gcc_checking_assert ((info & *map_info) == info);\n+\t gcc_checking_assert ((info.flag_word & map_info->flag_word)\n+\t\t\t == info.flag_word\n+\t\t\t && (map_info->needed_bits\n+\t\t\t\t | info.needed_bits) == info.needed_bits);\n \t *map_info = info;\n \t if (dump_file && (dump_flags & TDF_DETAILS))\n \t dump_var_info (var, map_info, \"Updating information\");\n@@ -813,13 +1084,24 @@ backprop::replace_assign_rhs (gassign *assign, tree lhs, tree rhs1,\n complete_change (assign);\n }\n \n+void\n+backprop::build_nop_rhs (gassign *assign, tree lhs)\n+{\n+ prepare_change (lhs);\n+ gimple_stmt_iterator gsi = gsi_for_stmt (assign);\n+ gimple_assign_set_rhs_from_tree (&gsi, gimple_assign_rhs1\n+\t\t\t\t (assign));\n+ complete_change (assign);\n+}\n+\n /* Optimize ASSIGN, an assignment to LHS, on the basis that INFO\n describes all uses of LHS. */\n \n void\n backprop::optimize_assign (gassign *assign, tree lhs, const usage_info *info)\n {\n- switch (gimple_assign_rhs_code (assign))\n+ tree_code code = gimple_assign_rhs_code (assign);\n+ switch (code)\n {\n case MULT_EXPR:\n case RDIV_EXPR:\n@@ -842,6 +1124,101 @@ backprop::optimize_assign (gassign *assign, tree lhs, const usage_info *info)\n \t\t\t strip_sign_op (gimple_assign_rhs3 (assign)));\n break;\n \n+ case BIT_AND_EXPR:\n+ case BIT_IOR_EXPR:\n+ case BIT_XOR_EXPR:\n+ if (info->needed_bits != -1)\n+\t{\n+\t tree rhs2 = gimple_assign_rhs2 (assign);\n+\t if (TREE_CODE (rhs2) == INTEGER_CST)\n+\t {\n+\t bool elide_p = false;\n+\t widest_int mask\n+\t\t= widest_int::from (wi::to_wide (rhs2), UNSIGNED);\n+\n+\t /* If we mask off bits that are being discarded later on anyway,\n+\t\t we can elide the mask. */\n+\t if (code == BIT_AND_EXPR\n+\t\t && (info->needed_bits & ~mask) == 0)\n+\t\telide_p = true;\n+\n+\t /* For IOR and XOR it's the other way around. If all we modify\n+\t\t is a range outside of the needed bits, elide. */\n+\t if ((code == BIT_IOR_EXPR || code == BIT_XOR_EXPR)\n+\t\t && (info->needed_bits & mask) == 0)\n+\t\telide_p = true;\n+\n+\t if (elide_p)\n+\t\t{\n+\t\t /* Just make the assignment a nop here. */\n+\t\t if (dump_file && (dump_flags & TDF_DETAILS))\n+\t\t {\n+\t\t fprintf (dump_file, \"Eliding redundant mask in \");\n+\t\t print_gimple_stmt (dump_file, assign, 0, TDF_SLIM);\n+\t\t }\n+\n+\t\t build_nop_rhs (assign, lhs);\n+\t\t}\n+\t }\n+\t}\n+ break;\n+\n+ case PLUS_EXPR:\n+ case MINUS_EXPR:\n+ if (info->needed_bits != -1)\n+\t{\n+\t tree rhs2 = gimple_assign_rhs2 (assign);\n+\t wide_int nz = get_nonzero_bits (rhs2);\n+\t widest_int wnz (-1);\n+\t if (nz.get_precision ())\n+\t wnz = widest_int::from (nz, UNSIGNED);\n+\n+\t widest_int shared_bits = info->needed_bits & wnz;\n+\t if (shared_bits == 0\n+\t && wi::ctz (wnz) > wi::floor_log2 (info->needed_bits))\n+\t {\n+\t if (dump_file && (dump_flags & TDF_DETAILS))\n+\t\t{\n+\t\t fprintf (dump_file, \"Eliding redundant\"\n+\t\t\t\t \" addition/subtraction in \");\n+\t\t print_gimple_stmt (dump_file, assign, 0, TDF_SLIM);\n+\t\t}\n+\n+\t build_nop_rhs (assign, lhs);\n+\t }\n+\t}\n+ break;\n+\n+ case LSHIFT_EXPR:\n+ if (info->needed_bits != -1)\n+\t{\n+\t tree rhs2 = gimple_assign_rhs2 (assign);\n+\t if (TREE_CODE (rhs2) == INTEGER_CST)\n+\t {\n+\t widest_int shift_count\n+\t\t= widest_int::from (wi::to_wide (rhs2), UNSIGNED);\n+\n+\t widest_int shifted\n+\t\t= wi::lrshift (info->needed_bits, shift_count);\n+\n+\t if (shifted == 0)\n+\t\t{\n+\t\t if (dump_file && (dump_flags & TDF_DETAILS))\n+\t\t {\n+\t\t fprintf (dump_file, \"Eliding redundant shift in \");\n+\t\t print_gimple_stmt (dump_file, assign, 0, TDF_SLIM);\n+\t\t }\n+\n+\t\t prepare_change (lhs);\n+\t\t gimple_stmt_iterator gsi = gsi_for_stmt (assign);\n+\t\t gimple_assign_set_rhs_from_tree\n+\t\t (&gsi, build_zero_cst (TREE_TYPE (lhs)));\n+\t\t complete_change (assign);\n+\t\t}\n+\t }\n+\t}\n+ break;\n+\n default:\n break;\n }\ndiff --git a/gcc/testsuite/gcc.dg/tree-ssa/backprop-bits-1.c b/gcc/testsuite/gcc.dg/tree-ssa/backprop-bits-1.c\nnew file mode 100644\nindex 00000000000..e46adce4bdb\n--- /dev/null\n+++ b/gcc/testsuite/gcc.dg/tree-ssa/backprop-bits-1.c\n@@ -0,0 +1,16 @@\n+/* { dg-do compile } */\n+/* { dg-additional-options \"-O -fdump-tree-backprop-details\" } */\n+\n+#include <stdbool.h>\n+\n+void use (unsigned);\n+\n+void\n+src (bool c, unsigned a, unsigned b) {\n+ unsigned s = c ? a & 24 : b & 25;\n+ use(s & 8);\n+ use(s & 16);\n+}\n+\n+/* { dg-final { scan-tree-dump-not \" s_8 = a_7(D) & 24;\" \"backprop\" } } */\n+/* { dg-final { scan-tree-dump-not \" s_6 = b_5(D) & 25;\" \"backprop\" } } */\ndiff --git a/gcc/testsuite/gcc.dg/tree-ssa/backprop-bits-2.c b/gcc/testsuite/gcc.dg/tree-ssa/backprop-bits-2.c\nnew file mode 100644\nindex 00000000000..3a4af6b8a10\n--- /dev/null\n+++ b/gcc/testsuite/gcc.dg/tree-ssa/backprop-bits-2.c\n@@ -0,0 +1,29 @@\n+/* { dg-do compile } */\n+/* { dg-additional-options \"-O -fdump-tree-optimized\" } */\n+\n+int\n+foo (int t)\n+{\n+ t += 3 + 3 * t;\n+ t &= 0xFFF;\n+ t += 3 + 3 * t;\n+ t &= 0xFFF;\n+ t += 3 + 3 * t;\n+ t &= 0xFFF;\n+ t += 3 + 3 * t;\n+ t &= 0xFFF;\n+ t += 3 + 3 * t;\n+ t &= 0xFFF;\n+ t += 3 + 3 * t;\n+ t &= 0xFFF;\n+ t += 3 + 3 * t;\n+ t &= 0xFFF;\n+ t += 3 + 3 * t;\n+ t &= 0xFFF;\n+ t += 3 + 3 * t;\n+ t &= 0xFFF;\n+\n+ return t;\n+}\n+\n+/* { dg-final { scan-tree-dump \"4095\" \"optimized\" } } */\ndiff --git a/gcc/testsuite/gcc.dg/tree-ssa/backprop-bits-3.c b/gcc/testsuite/gcc.dg/tree-ssa/backprop-bits-3.c\nnew file mode 100644\nindex 00000000000..d7b573edf88\n--- /dev/null\n+++ b/gcc/testsuite/gcc.dg/tree-ssa/backprop-bits-3.c\n@@ -0,0 +1,29 @@\n+/* { dg-do compile { target bitint } } */\n+/* { dg-additional-options \"-O -fdump-tree-optimized\" } */\n+\n+int\n+foo (int t)\n+{\n+ t += 3 + 3 * t;\n+ t &= 0xFFF;\n+ t += 3 + 3 * t;\n+ t &= 0xFFF;\n+ t += 3 + 3 * t;\n+ t &= 0xFFF;\n+ t += 3 + 3 * t;\n+ t &= 0xFFF;\n+ t += 3 + 3 * t;\n+ t &= 0xFFF;\n+ t += 3 + 3 * t;\n+ t &= 0xFFF;\n+ t += 3 + 3 * t;\n+ t &= 0xFFF;\n+ t += 3 + 3 * t;\n+ t &= 0xFFF;\n+ t += 3 + 3 * t;\n+ t &= 0xFFF;\n+\n+ return t;\n+}\n+\n+/* { dg-final { scan-tree-dump \"return\" \"optimized\" } } */\ndiff --git a/gcc/testsuite/gcc.dg/tree-ssa/backprop-bits-4.c b/gcc/testsuite/gcc.dg/tree-ssa/backprop-bits-4.c\nnew file mode 100644\nindex 00000000000..7fcc90c7adf\n--- /dev/null\n+++ b/gcc/testsuite/gcc.dg/tree-ssa/backprop-bits-4.c\n@@ -0,0 +1,34 @@\n+/* { dg-do compile } */\n+/* { dg-additional-options \"-O -fdump-tree-backprop-details -std=gnu99\" } */\n+\n+void use (unsigned);\n+\n+void\n+foo (unsigned x)\n+{\n+ unsigned a = x & 0xff;\n+ unsigned b = a * 4;\n+ use (b & 0x10);\n+ use (b & 0xe0);\n+}\n+\n+void\n+bar (unsigned x)\n+{\n+ unsigned a = x & 0xff;\n+ unsigned b = a / 3;\n+ use (b & 0x3);\n+ use (b & 0xc);\n+}\n+\n+void\n+baz (unsigned x)\n+{\n+ unsigned a = x & 0xffff;\n+ unsigned a2 = a * 2;\n+ unsigned b = a2 & 0xff;\n+ use (b & 0x3);\n+ use (b & 0xc);\n+}\n+\n+/* { dg-final { scan-tree-dump-times \"Eliding redundant mask\" 3 \"backprop\" } } */\ndiff --git a/gcc/testsuite/gcc.dg/tree-ssa/backprop-bits-5.c b/gcc/testsuite/gcc.dg/tree-ssa/backprop-bits-5.c\nnew file mode 100644\nindex 00000000000..7a0ab3ade7d\n--- /dev/null\n+++ b/gcc/testsuite/gcc.dg/tree-ssa/backprop-bits-5.c\n@@ -0,0 +1,39 @@\n+/* { dg-do compile } */\n+/* { dg-additional-options \"-O -fdump-tree-backprop-details -std=gnu99\" } */\n+\n+void use (unsigned);\n+\n+void\n+foo (unsigned x)\n+{\n+ unsigned a = x & 0xff;\n+ use (a & 0xf);\n+ use (a);\n+}\n+\n+void\n+bar (unsigned x, unsigned y)\n+{\n+ unsigned a = x & 0xff;\n+ unsigned b = a + y;\n+ use (b & 0xf);\n+}\n+\n+void\n+baz (unsigned x, unsigned s)\n+{\n+ unsigned a = x & 0xff;\n+ unsigned b = a << s;\n+ use (b & 0xf);\n+}\n+\n+unsigned\n+baf (unsigned x, int n)\n+{\n+ unsigned a = x & 0xff;\n+ for (int i = 0; i < n; i++)\n+ a = (a + 1) & 0xff;\n+ return a;\n+}\n+\n+/* { dg-final { scan-tree-dump-not \"Eliding redundant mask\" \"backprop\" } } */\ndiff --git a/gcc/testsuite/gcc.dg/tree-ssa/backprop-bits-6.c b/gcc/testsuite/gcc.dg/tree-ssa/backprop-bits-6.c\nnew file mode 100644\nindex 00000000000..6cedb819c81\n--- /dev/null\n+++ b/gcc/testsuite/gcc.dg/tree-ssa/backprop-bits-6.c\n@@ -0,0 +1,18 @@\n+/* { dg-do compile } */\n+/* { dg-additional-options \"-O -fdump-tree-backprop-details -std=gnu99\" } */\n+\n+void use (unsigned);\n+\n+void\n+f_phi (int c, unsigned x, unsigned y)\n+{\n+ unsigned t;\n+ if (c)\n+ t = x & 0xff;\n+ else\n+ t = y & 0xff;\n+ use (t & 0x3);\n+ use (t & 0xc);\n+}\n+\n+/* { dg-final { scan-tree-dump-times \"Eliding redundant mask\" 2 \"backprop\" } } */\ndiff --git a/gcc/testsuite/gcc.dg/tree-ssa/backprop-bits-7.c b/gcc/testsuite/gcc.dg/tree-ssa/backprop-bits-7.c\nnew file mode 100644\nindex 00000000000..795e461160f\n--- /dev/null\n+++ b/gcc/testsuite/gcc.dg/tree-ssa/backprop-bits-7.c\n@@ -0,0 +1,41 @@\n+/* { dg-do compile } */\n+/* { dg-additional-options \"-O -fdump-tree-backprop-details -std=gnu99\" } */\n+\n+void use (unsigned);\n+\n+void\n+foo (unsigned x)\n+{\n+ unsigned a = x | 0xff00;\n+ unsigned b = a * 2;\n+ use (b & 0x3);\n+ use (b & 0xc);\n+}\n+\n+void\n+bar (unsigned x)\n+{\n+ unsigned a = x ^ 0xff00;\n+ unsigned b = a * 2;\n+ use (b & 0x3);\n+ use (b & 0xc);\n+}\n+\n+void\n+baz (unsigned x)\n+{\n+ unsigned a = x | 0x18;\n+ use (a & 0x3);\n+ use (a & 0xc);\n+}\n+\n+void\n+baf (unsigned x)\n+{\n+ unsigned a = x ^ 0x18;\n+ use (a & 0x3);\n+ use (a & 0xc);\n+}\n+\n+/* foo and bar can be simplified by eliding the IOR. baz and baf can't. */\n+/* { dg-final { scan-tree-dump-times \"Eliding redundant\" 2 \"backprop\" } } */\ndiff --git a/gcc/testsuite/gcc.dg/tree-ssa/backprop-bits-8.c b/gcc/testsuite/gcc.dg/tree-ssa/backprop-bits-8.c\nnew file mode 100644\nindex 00000000000..3f66c4f84a6\n--- /dev/null\n+++ b/gcc/testsuite/gcc.dg/tree-ssa/backprop-bits-8.c\n@@ -0,0 +1,31 @@\n+/* { dg-do compile } */\n+/* { dg-additional-options \"-O -fdump-tree-backprop-details -std=gnu99\" } */\n+\n+void use (unsigned);\n+\n+void\n+foo (unsigned x)\n+{\n+ unsigned b = x + 0xff00;\n+ use (b & 0x1);\n+ use (b & 0xe);\n+}\n+\n+void\n+bar (unsigned x, unsigned y)\n+{\n+ unsigned m = y & 0xFF00;\n+ unsigned b = x - m;\n+ use (b & 0xf);\n+ use (b & 0xf0);\n+}\n+\n+void\n+baz (unsigned x)\n+{\n+ unsigned a = x << 8;\n+ unsigned b = a / 3;\n+ use (b & 0x3);\n+}\n+\n+/* { dg-final { scan-tree-dump-times \"Eliding redundant\" 3 \"backprop\" } } */\n", "prefixes": [] }