https://gcc.gnu.org/bugzilla/show_bug.cgi?id=128575

            Bug ID: 128575
           Summary: dse_optimize_redundant_stores omits
                    gimple_has_volatile_ops(use_stmt) and deletes
                    subsequent volatile zeroing stores (*(volatile T *)p =
                    0) when preceded by a zero store to the same address
           Product: gcc
           Version: 16.2.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: tree-optimization
          Assignee: unassigned at gcc dot gnu.org
          Reporter: 220245569 at seu dot edu.cn
                CC: 220255623 at seu dot edu.cn, jianhao.xu at seu dot edu.cn
  Target Milestone: ---
            Target: *-*-*

Reproducer
----------
$ cat trigger.c
void scrub_int(int *p) {
    *p = 0;
    *(volatile int *)p = 0;
}

Compile command / flags:
$ x86_64-linux-gnu-gcc -O2 -fdump-tree-dse1-details -S trigger.c -o trigger.s
$ grep "Deleted redundant" trigger.c.*dse1*

Observed output (GCC 16.2.0):
Assembly:
scrub_int:
        movl    $0, (%rdi)
        ret
dse1 dump:
  Deleted redundant store: MEM[(volatile int *)p_2(D)] ={v} 0;

Expected behavior:
A volatile store (MEM[(volatile T *)p] ={v} 0) has observable side effects
required by the C/C++ abstract machine (C23 5.1.2.3 / 6.7.3) and must never be
deleted as redundant by DSE.

Root cause
----------
Source location: gcc/tree-ssa-dse.cc:903-946 (dse_optimize_redundant_stores) vs
1488 (dse_optimize_stmt) and gcc/tree-ssa-sccvn.cc:7377

In pass_dse (gcc/tree-ssa-dse.cc), the main dead-store elimination driver
dse_optimize_stmt (line 1488) explicitly guards against touching volatile
statements: 'if (gimple_has_volatile_ops (stmt)) return;' (and SCCVN's
eliminate_dom_walker::eliminate_stmt at tree-ssa-sccvn.cc:7377 likewise checks
'!gimple_has_volatile_ops (stmt)'). However, when a non-volatile zeroing store
(e.g. *p = 0 or memset(p, 0, n) or = {}) is visited in dse_optimize_stmt, it
calls dse_optimize_redundant_stores (stmt) (tree-ssa-dse.cc:903-946), which
walks forward over dominated virtual-def stores (use_stmt) that also store zero
to the same bytes and deletes use_stmt via delete_dead_or_redundant_assignment
(&gsi, "redundant", ...). Crucially, dse_optimize_redundant_stores never checks
'if (gimple_has_volatile_ops (use_stmt)) continue;'! As a result, when a
non-volatile zero write is followed by an explicit volatile scrub write
(*(volatile int *)p = 0), dse1 deletes the volatile store!

Impact:
Eliminates explicit volatile memory/MMIO/cryptographic zeroing stores (such as
volatile-pointer zeroing idioms used to scrub secrets or trigger twice-written
hardware MMIO registers) whenever preceded by an ordinary zero store to the
same address.

Suggested Fix
-------------
In gcc/tree-ssa-dse.cc:918 (dse_optimize_redundant_stores), add 'if
(gimple_has_volatile_ops (use_stmt)) break;' (or continue) before inspecting or
deleting use_stmt.

Reply via email to