{"id":2227586,"url":"http://patchwork.ozlabs.org/api/patches/2227586/?format=json","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=json","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=json","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=json","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"]}