Patch Detail
get:
Show a patch.
patch:
Update a patch.
put:
Update a patch.
GET /api/patches/2227586/?format=api
{ "id": 2227586, "url": "http://patchwork.ozlabs.org/api/patches/2227586/?format=api", "web_url": "http://patchwork.ozlabs.org/project/gcc/patch/20260424010631.1327080-1-hongtao.liu@intel.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": "<20260424010631.1327080-1-hongtao.liu@intel.com>", "list_archive_url": null, "date": "2026-04-24T01:06:31", "name": "[v3] dse: Invalidate stale REG_EQUAL/REG_EQUIV notes after deleting stores [PR124894]", "commit_ref": null, "pull_url": null, "state": "new", "archived": false, "hash": "3d1de7532e5dcc4b1f87617248889e761ee194e8", "submitter": { "id": 79166, "url": "http://patchwork.ozlabs.org/api/people/79166/?format=api", "name": "liuhongt", "email": "hongtao.liu@intel.com" }, "delegate": null, "mbox": "http://patchwork.ozlabs.org/project/gcc/patch/20260424010631.1327080-1-hongtao.liu@intel.com/mbox/", "series": [ { "id": 501272, "url": "http://patchwork.ozlabs.org/api/series/501272/?format=api", "web_url": "http://patchwork.ozlabs.org/project/gcc/list/?series=501272", "date": "2026-04-24T01:06:31", "name": "[v3] dse: Invalidate stale REG_EQUAL/REG_EQUIV notes after deleting stores [PR124894]", "version": 3, "mbox": "http://patchwork.ozlabs.org/series/501272/mbox/" } ], "comments": "http://patchwork.ozlabs.org/api/patches/2227586/comments/", "check": "pending", "checks": "http://patchwork.ozlabs.org/api/patches/2227586/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=intel.com header.i=@intel.com header.a=rsa-sha256\n header.s=Intel header.b=HaeKoob2;\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=intel.com header.i=@intel.com header.a=rsa-sha256\n header.s=Intel header.b=HaeKoob2", "sourceware.org;\n dmarc=pass (p=none dis=none) header.from=intel.com", "sourceware.org; spf=pass smtp.mailfrom=intel.com", "server2.sourceware.org;\n arc=none smtp.remote-ip=198.175.65.20" ], "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 4g1vtx664Bz1y2d\n\tfor <incoming@patchwork.ozlabs.org>; Fri, 24 Apr 2026 11:07:04 +1000 (AEST)", "from vm01.sourceware.org (localhost [127.0.0.1])\n\tby sourceware.org (Postfix) with ESMTP id 78BF54B99F7A\n\tfor <incoming@patchwork.ozlabs.org>; Fri, 24 Apr 2026 01:07:02 +0000 (GMT)", "from mgamail.intel.com (mgamail.intel.com [198.175.65.20])\n by sourceware.org (Postfix) with ESMTPS id 201AA4B99F4F\n for <gcc-patches@gcc.gnu.org>; Fri, 24 Apr 2026 01:06:33 +0000 (GMT)", "from fmviesa007.fm.intel.com ([10.60.135.147])\n by orvoesa112.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384;\n 23 Apr 2026 18:06:31 -0700", "from scymds03.sc.intel.com ([10.148.94.166])\n by fmviesa007.fm.intel.com with ESMTP; 23 Apr 2026 18:06:31 -0700", "from jfel-spr-6155.jf.intel.com (jfel-spr-6155.jf.intel.com\n [10.165.119.109])\n by scymds03.sc.intel.com (Postfix) with ESMTP id 34BC6520D;\n Thu, 23 Apr 2026 18:06:31 -0700 (PDT)" ], "DKIM-Filter": [ "OpenDKIM Filter v2.11.0 sourceware.org 78BF54B99F7A", "OpenDKIM Filter v2.11.0 sourceware.org 201AA4B99F4F" ], "DMARC-Filter": "OpenDMARC Filter v1.4.2 sourceware.org 201AA4B99F4F", "ARC-Filter": "OpenARC Filter v1.0.0 sourceware.org 201AA4B99F4F", "ARC-Seal": "i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1776992793; cv=none;\n b=gS3QKzt2ie0U9ONaOuX4lU4FGAHQQBhwtIrDrIGnRxDZeeEs/iJEKRuHNUty7EeHJAow1wQlPJBqlFmFTqPIapZ7S8q68AmIt+ONEhA1zIk8iyhX3hVzwl5luEfbD8d/U1Pi1krICc+9Chyg/o3mHbhClgXwlnC9HNiBN0V/uIo=", "ARC-Message-Signature": "i=1; a=rsa-sha256; d=sourceware.org; s=key;\n t=1776992793; c=relaxed/simple;\n bh=/dKkhLNQyCeD8IAKO+r93qN4o6Zn7BHYQszVQvYw670=;\n h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version;\n b=X3uBxY9ohhzDDCL/ywePvEebcwNnQR6S7ojOC5otC9o4iHTYI6rGVG5D+yQP7wlQUXAWBNTba7qRZsSsV9swne02N28fmcN/GZp8Qh/+o/s8lS+xlTE6IrXr3fbpdyxWVvb1YwV3/prjnmNcwQcB43SZge44YpbidfxFHgudHSc=", "ARC-Authentication-Results": "i=1; server2.sourceware.org", "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/simple;\n d=intel.com; i=@intel.com; q=dns/txt; s=Intel;\n t=1776992793; x=1808528793;\n h=from:to:cc:subject:date:message-id:reply-to:mime-version:\n content-transfer-encoding;\n bh=/dKkhLNQyCeD8IAKO+r93qN4o6Zn7BHYQszVQvYw670=;\n b=HaeKoob2K7Gl4KnAI+V07LyOUxRuFvL+NEeZsc2BT5yGXGxhvY7tfihu\n UdESvE08VGwZ78nsi5EjtacWsIQUEyieviLacSvwn6K3LN0Boqt2W/zCJ\n VVzZ7F7gdpEERaGwieJRx7zx+XzhFx8EOR6/iRBBGwMx5hOel9/VynKdO\n dGr1Jj+B65/XrXjD/I5zJH/A2g6tBLPlu6MtMPExTEHrtpHluKwViUhT4\n MosBtYKBsr1xwu7tSbW7FGtfctN6GqZbksWoELyw8EDTLOI8QKAgeehz0\n ggdp6XaihHYHlpykJd/tYDgJLEV81VaL/4Eo3YCgYfvUXV2DyP2LIENj2 w==;", "X-CSE-ConnectionGUID": [ "XV9x2PtWRh67rT157Rat+Q==", "H2TksSP2QjO0rnqyZY+8yg==" ], "X-CSE-MsgGUID": [ "UDBGviOzQ/2cJ5Inopg+tg==", "jJS4dMMERv+zMeKh8IpdwQ==" ], "X-IronPort-AV": [ "E=McAfee;i=\"6800,10657,11765\"; a=\"77673449\"", "E=Sophos;i=\"6.23,195,1770624000\"; d=\"scan'208\";a=\"77673449\"", "E=Sophos;i=\"6.23,195,1770624000\"; d=\"scan'208\";a=\"229623364\"" ], "X-ExtLoop1": "1", "From": "liuhongt <hongtao.liu@intel.com>", "To": "gcc-patches@gcc.gnu.org", "Cc": "rdsandiford@googlemail.com, andrew.pinski@oss.qualcomm.com,\n ebotcazou@libertysurf.fr, rguenther@suse.de, jeffrey.law@oss.qualcomm.com,\n \"Claude Opus 4 . 6\" <noreply@anthropic.com>", "Subject": "[PATCH v3] dse: Invalidate stale REG_EQUAL/REG_EQUIV notes after\n deleting stores [PR124894]", "Date": "Thu, 23 Apr 2026 18:06:31 -0700", "Message-Id": "<20260424010631.1327080-1-hongtao.liu@intel.com>", "X-Mailer": "git-send-email 2.34.1", "MIME-Version": "1.0", "Content-Transfer-Encoding": "8bit", "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>", "Reply-To": "87eck8of6d.fsf@googlemail.com", "Errors-To": "gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org" }, "content": "> >> Fix this by not creating REG_EQUAL notes that reference non-read-only\n> >> MEMs in add_equal_note. Read-only MEMs (such as constant pool\n> >> references) are safe since their contents cannot change. REG_EQUAL\n> >> notes are just optimization hints, so not adding them is always safe.\n> > I don't think this is the right fix. If DSE does something that\n> > invalidates a note, DSE should be the one to remove the note.\n> > There's nothing intrinsically wrong with a REG_EQUAL note that\n> > references non-constant memory.\n> Agreed on all points.\nChanged in V3.\n\nBootstrapped and regtested on x86_64-pc-linux-gnu{-m32,}\nOk for main trunk?\n\nWhen DSE deletes a dead store, any REG_EQUAL/REG_EQUIV notes on insns\nreachable from the store that reference the stored memory become\nsemantically stale: the note assumes the memory holds the stored\nvalue, but after the store is removed the memory holds a different\n(older) value.\n\nThis becomes a correctness problem when a downstream pass propagates\ninto such a note and simplifies it. For example, late-combine can\nsubstitute a register source into the note, producing an expression\nlike (minus (mem[X]) (mem[X])) that simplify_binary_operation folds\nto zero. IRA then promotes REG_EQUAL(0) to REG_EQUIV(0), and reload\neliminates the computation entirely, producing wrong code.\n\nFix this by:\n\n1. During dse_step1's scan of each BB, record the insns that carry a\n REG_EQUAL/REG_EQUIV note whose value contains a MEM subexpression.\n The per-BB list is stored on dse_bb_info_type in forward program\n order.\n\n2. When delete_dead_store_insn removes a dead store, invalidate\n aliasing notes in two phases:\n - Within the store's own BB, walk forward via NEXT_INSN starting\n at the store.\n - For every CFG-reachable successor BB, walk that BB's recorded\n mem_equiv_note_insns list.\n\nRecording during scan_insn avoids re-scanning BB insns on every\ndeletion for successor BBs; the per-deletion cost is proportional to\nthe number of candidate notes rather than the number of insns. This\nmirrors what store-motion already does in remove_reachable_equiv_notes\nbut reuses DSE's own per-BB scan.\n\nbb_table is switched from XNEWVEC to XCNEWVEC so that bb_table[i] is\nNULL for successor blocks not yet scanned when a store is deleted in dse_step1.\notherwise remove_aliasing_equiv_notes would dereference uninitialized\npointers.\n\ngcc/ChangeLog:\n\n\tPR rtl-optimization/124894\n\t* dse.cc (dse_bb_info_type::mem_equiv_note_insns): New field.\n\t(maybe_drop_aliasing_equiv_note): New function: drop an insn's\n\tREG_EQUAL/REG_EQUIV note if it aliases the deleted store.\n\t(remove_aliasing_equiv_notes): New function: walk NEXT_INSN\n\twithin the store's BB; walk recorded lists in CFG successors.\n\t(delete_dead_store_insn): Invalidate stale REG_EQUAL/REG_EQUIV\n\tnotes reachable from the deleted store.\n\t(dse_step0): Zero-initialize bb_table via XCNEWVEC.\n\t(scan_insn): Record insns with MEM-containing REG_EQUAL or\n\tREG_EQUIV notes.\n\t(dse_step7): Release per-BB note insn vectors.\n\ngcc/testsuite/ChangeLog:\n\n\tPR rtl-optimization/124894\n\t* gcc.dg/pr124894.c: New test.\n\nAssisted-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>\n---\n gcc/dse.cc | 119 +++++++++++++++++++++++++++++++-\n gcc/testsuite/gcc.dg/pr124894.c | 36 ++++++++++\n 2 files changed, 154 insertions(+), 1 deletion(-)\n create mode 100644 gcc/testsuite/gcc.dg/pr124894.c", "diff": "diff --git a/gcc/dse.cc b/gcc/dse.cc\nindex 847a8ff148a..064abd17e4c 100644\n--- a/gcc/dse.cc\n+++ b/gcc/dse.cc\n@@ -484,6 +484,13 @@ struct dse_bb_info_type\n to assure that shift and/or add sequences that are inserted do not\n accidentally clobber live hard regs. */\n bitmap regs_live;\n+\n+ /* The list of insns in this block that carry a REG_EQUAL or\n+ REG_EQUIV note whose value contains a MEM subexpression. These\n+ are candidates for note invalidation when DSE deletes a dead\n+ store that could alias one of the notes' MEMs. The list is\n+ populated in forward program order by scan_insn. */\n+ vec<rtx_insn *> mem_equiv_note_insns;\n };\n \n typedef struct dse_bb_info_type *bb_info_t;\n@@ -712,7 +719,7 @@ dse_step0 (void)\n \n rtx_group_table = new hash_table<invariant_group_base_hasher> (11);\n \n- bb_table = XNEWVEC (bb_info_t, last_basic_block_for_fn (cfun));\n+ bb_table = XCNEWVEC (bb_info_t, last_basic_block_for_fn (cfun));\n rtx_group_next_id = 0;\n \n stores_off_frame_dead_at_return = !cfun->stdarg;\n@@ -894,6 +901,93 @@ check_for_inc_dec (rtx_insn *insn)\n return true;\n }\n \n+/* If INSN has a REG_EQUAL/REG_EQUIV note whose value references a MEM\n+ that may alias STORE_MEM, remove that note. Because notes are\n+ installed via set_unique_reg_note, an insn has at most one such\n+ note, so find_reg_equal_equiv_note suffices. */\n+\n+static void\n+maybe_drop_aliasing_equiv_note (rtx_insn *insn, rtx store_mem)\n+{\n+ if (!insn || !NONDEBUG_INSN_P (insn))\n+ return;\n+\n+ rtx note = find_reg_equal_equiv_note (insn);\n+ if (!note)\n+ return;\n+\n+ subrtx_iterator::array_type array;\n+ FOR_EACH_SUBRTX (iter, array, XEXP (note, 0), NONCONST)\n+ {\n+ const_rtx sub = *iter;\n+ if (MEM_P (sub)\n+\t && true_dependence (store_mem, GET_MODE (store_mem), sub))\n+\t{\n+\t if (dump_file && (dump_flags & TDF_DETAILS))\n+\t fprintf (dump_file,\n+\t\t \" dropping stale REG_EQUAL note at insn %d\\n\",\n+\t\t INSN_UID (insn));\n+\t remove_note (insn, note);\n+\t return;\n+\t}\n+ }\n+}\n+\n+/* When deleting a dead store to STORE_MEM at STORE_INSN, invalidate\n+ any REG_EQUAL/REG_EQUIV notes that reference a MEM aliasing\n+ STORE_MEM and are reachable from STORE_INSN. Within STORE_INSN's\n+ own BB, walk forward via NEXT_INSN starting from STORE_INSN. For\n+ CFG-reachable successor BBs, walk the recorded\n+ MEM_EQUIV_NOTE_INSNS list built during scan_insn. Such notes\n+ become stale once the store is removed, because the memory then\n+ holds a different (older) value than what the note assumes. Later\n+ passes (e.g. late-combine) may otherwise propagate into the note\n+ and produce incorrect simplifications (e.g. (minus (mem) (mem))\n+ -> 0). */\n+\n+static void\n+remove_aliasing_equiv_notes (rtx_insn *store_insn, rtx store_mem)\n+{\n+ basic_block store_bb = BLOCK_FOR_INSN (store_insn);\n+\n+ /* Walk forward within the store's own BB via NEXT_INSN. */\n+ for (rtx_insn *insn = NEXT_INSN (store_insn);\n+ insn && insn != NEXT_INSN (BB_END (store_bb));\n+ insn = NEXT_INSN (insn))\n+ maybe_drop_aliasing_equiv_note (insn, store_mem);\n+\n+ /* For successor BBs, use the recorded list populated by scan_insn\n+ rather than re-walking each BB's insns. */\n+ auto_sbitmap visited (last_basic_block_for_fn (cfun));\n+ bitmap_clear (visited);\n+ bitmap_set_bit (visited, store_bb->index);\n+\n+ auto_vec<basic_block, 16> worklist;\n+ edge e;\n+ edge_iterator ei;\n+ FOR_EACH_EDGE (e, ei, store_bb->succs)\n+ if (e->dest != EXIT_BLOCK_PTR_FOR_FN (cfun)\n+\t&& bitmap_set_bit (visited, e->dest->index))\n+ worklist.safe_push (e->dest);\n+\n+ while (!worklist.is_empty ())\n+ {\n+ basic_block bb = worklist.pop ();\n+ bb_info_t succ_bb_info = bb_table[bb->index];\n+ if (succ_bb_info)\n+\t{\n+\t unsigned i;\n+\t rtx_insn *insn;\n+\t FOR_EACH_VEC_ELT (succ_bb_info->mem_equiv_note_insns, i, insn)\n+\t maybe_drop_aliasing_equiv_note (insn, store_mem);\n+\t}\n+ FOR_EACH_EDGE (e, ei, bb->succs)\n+\tif (e->dest != EXIT_BLOCK_PTR_FOR_FN (cfun)\n+\t && bitmap_set_bit (visited, e->dest->index))\n+\t worklist.safe_push (e->dest);\n+ }\n+}\n+\n /* Delete the insn and free all of the fields inside INSN_INFO. */\n \n static void\n@@ -910,6 +1004,16 @@ delete_dead_store_insn (insn_info_t insn_info)\n fprintf (dump_file, \"Locally deleting insn %d\\n\",\n \t INSN_UID (insn_info->insn));\n \n+ /* Before freeing the store info, invalidate any REG_EQUAL/REG_EQUIV\n+ notes on later insns that reference memory aliased by this store.\n+ The notes become semantically stale once the store is gone.\n+ A deletable insn contains exactly one mem set (plus clobbers), so\n+ just skip the clobbers to find it. */\n+ store_info *si = insn_info->store_rec;\n+ while (!si->is_set)\n+ si = si->next;\n+ remove_aliasing_equiv_notes (insn_info->insn, si->mem);\n+\n free_store_info (insn_info);\n read_info = insn_info->read_rec;\n \n@@ -2534,6 +2638,13 @@ scan_insn (bb_info_t bb_info, rtx_insn *insn, int max_active_local_stores)\n return;\n }\n \n+ /* Remember insns whose REG_EQUAL/REG_EQUIV note references a MEM\n+ subexpression. If DSE later deletes a store that may alias such\n+ a MEM, delete_dead_store_insn will invalidate the stale note. */\n+ if (rtx note = find_reg_equal_equiv_note (insn))\n+ if (contains_mem_rtx_p (XEXP (note, 0)))\n+ bb_info->mem_equiv_note_insns.safe_push (insn);\n+\n /* Look at all of the uses in the insn. */\n note_uses (&PATTERN (insn), check_mem_read_use, bb_info);\n \n@@ -3686,6 +3797,12 @@ dse_step6 (void)\n static void\n dse_step7 (void)\n {\n+ /* Release per-BB vectors holding recorded REG_EQUAL note insns. */\n+ basic_block bb;\n+ FOR_ALL_BB_FN (bb, cfun)\n+ if (bb_table[bb->index])\n+ bb_table[bb->index]->mem_equiv_note_insns.release ();\n+\n bitmap_obstack_release (&dse_bitmap_obstack);\n obstack_free (&dse_obstack, NULL);\n \ndiff --git a/gcc/testsuite/gcc.dg/pr124894.c b/gcc/testsuite/gcc.dg/pr124894.c\nnew file mode 100644\nindex 00000000000..f906169c699\n--- /dev/null\n+++ b/gcc/testsuite/gcc.dg/pr124894.c\n@@ -0,0 +1,36 @@\n+/* { dg-do run } */\n+/* { dg-require-effective-target int128 } */\n+/* { dg-require-effective-target lp64 } */\n+/* { dg-options \"-O2 -fno-strict-aliasing\" } */\n+\n+/* PR rtl-optimization/124894 */\n+/* DSE can delete a store after forward-substituting the stored value into\n+ a load, leaving a stale MEM in a REG_EQUAL note. Late-combine must not\n+ propagate into such notes, as the resulting simplification (e.g.\n+ (minus (mem) (mem)) -> 0) would be wrong. */\n+\n+short s;\n+__int128 z;\n+long g;\n+\n+__attribute__((noipa)) long\n+foo (short a)\n+{\n+ long t = 0;\n+ char c = *(char *) __builtin_memset (&z, 2, 6);\n+ __builtin_memset (&s, c, 2);\n+ __builtin_memmove (&t, &g, 4);\n+ long u = -t;\n+ long v = *(long *) __builtin_memset (&t, a | 6, 8);\n+ __int128 w = z % s;\n+ long r = w + t + u + v;\n+ return r;\n+}\n+\n+int\n+main ()\n+{\n+ long x = foo (0);\n+ if (x != 0x0c0c0c0c0c0c0c0c)\n+ __builtin_abort ();\n+}\n", "prefixes": [ "v3" ] }