<table border="1" cellspacing="0" cellpadding="8">
    <tr>
        <th>Issue</th>
        <td>
            <a href=https://github.com/llvm/llvm-project/issues/97252>97252</a>
        </td>
    </tr>

    <tr>
        <th>Summary</th>
        <td>
            [DSE] misoptimized deleted store before non-inlined sync
        </td>
    </tr>

    <tr>
      <th>Labels</th>
      <td>
            new issue
      </td>
    </tr>

    <tr>
      <th>Assignees</th>
      <td>
      </td>
    </tr>

    <tr>
      <th>Reporter</th>
      <td>
          jacobly0
      </td>
    </tr>
</table>

<pre>
    ```llvm
@non_atomic = internal global i8 0
@atomic = internal global i8 0

define void @thread_a() {
 store i8 1, ptr @non_atomic
  call void @sync()
  store i8 2, ptr @non_atomic
  ret void
}

define internal void @sync() noinline {
  store atomic i8 1, ptr @atomic seq_cst, align 1
  br label %1

1:
  %2 = load atomic i8, ptr @atomic seq_cst, align 1
  %3 = icmp ne i8 %2, 0
  br i1 %3, label %1, label %4

4:
  ret void
}

define i8 @thread_b() {
  br label %1

1:
  %2 = load atomic i8, ptr @atomic seq_cst, align 1
  %3 = icmp eq i8 %2, 0
 br i1 %3, label %1, label %4

4:
  %5 = load i8, ptr @non_atomic
 store atomic i8 0, ptr @atomic seq_cst, align 1
  ret i8 %5
}
```
```
$ opt --version
LLVM (http://llvm.org/):
 LLVM version 18.1.5
  DEBUG build with assertions.
  Default target: x86_64-unknown-linux-gnu
  Host CPU: znver4
$ opt repro.ll -passes='require<globals-aa>,function-attrs,dse' -debug-only dse
Trying to eliminate MemoryDefs killed by 1 = MemoryDef(liveOnEntry) (  store i8 1, ptr @non_atomic, align 1)
  trying to get dominating access
   visiting 0 = MemoryDef(liveOnEntry)
   ...  found LiveOnEntryDef
  finished walk
Trying to eliminate MemoryDefs killed by 3 = MemoryDef(2) (  store i8 2, ptr @non_atomic, align 1)
  trying to get dominating access
 visiting 2 = MemoryDef(1) (  call void @sync())
   visiting 1 = MemoryDef(liveOnEntry) (  store i8 1, ptr @non_atomic, align 1)
  Checking for reads of 1 = MemoryDef(liveOnEntry) (  store i8 1, ptr @non_atomic, align 1)
   2 = MemoryDef(1) (  call void @sync())
   3 = MemoryDef(2) ( store i8 2, ptr @non_atomic, align 1)
    ... skipping killing def/dom access
 Checking if we can kill 1 = MemoryDef(liveOnEntry) (  store i8 1, ptr @non_atomic, align 1)
DSE: Remove Dead Store:
  DEAD:   store i8 1, ptr @non_atomic, align 1
  KILLER:   store i8 2, ptr @non_atomic, align 1
  trying to get dominating access
   visiting 0 = MemoryDef(liveOnEntry)
   ...  found LiveOnEntryDef
  finished walk
<snip>
```
```llvm
; ModuleID = 'repro.ll'
source_filename = "repro.ll"

@non_atomic = internal global i8 0
@atomic = internal global i8 0

; Function Attrs: nofree norecurse nounwind memory(readwrite, inaccessiblemem: none)
define void @thread_a() #0 {
  call void @sync()
  store i8 2, ptr @non_atomic, align 1
  ret void
}

; Function Attrs: nofree noinline norecurse nounwind memory(readwrite, argmem: none, inaccessiblemem: none)
define internal void @sync() #1 {
  store atomic i8 1, ptr @atomic seq_cst, align 1
  br label %1

1:                                                ; preds = %1, %0
  %2 = load atomic i8, ptr @atomic seq_cst, align 1
  %3 = icmp ne i8 %2, 0
  br i1 %3, label %1, label %4

4: ; preds = %1
  ret void
}

; Function Attrs: nofree norecurse nounwind memory(readwrite, argmem: none, inaccessiblemem: none)
define i8 @thread_b() #2 {
  br label %1

1:                                                ; preds = %1, %0
  %2 = load atomic i8, ptr @atomic seq_cst, align 1
  %3 = icmp eq i8 %2, 0
  br i1 %3, label %1, label %4

4: ; preds = %1
  %5 = load i8, ptr @non_atomic, align 1
  store atomic i8 0, ptr @atomic seq_cst, align 1
  ret i8 %5
}

attributes #0 = { nofree norecurse nounwind memory(readwrite, inaccessiblemem: none) }
attributes #1 = { nofree noinline norecurse nounwind memory(readwrite, argmem: none, inaccessiblemem: none) }
attributes #2 = { nofree norecurse nounwind memory(readwrite, argmem: none, inaccessiblemem: none) }
```
A store is deleted even though it happens-before a read of that value in another thread which happens-before the killer store, through the following happens-before chain:
 * `store i8 1, ptr @non_atomic` in `@thread_a` (deleted store)
 * `store atomic i8 1, ptr @atomic seq_cst` in `@thread_a` &rightarrow; `@sync`
 * `%2 = load atomic i8, ptr @atomic seq_cst` that loads `1` in `@thread_b`
 * `%5 = load i8, ptr @non_atomic` in `@thread_b` (misoptimization loads `0` instead of `1`)
 * `store atomic i8 0, ptr @atomic seq_cst` in `@thread_b`
 * `%2 = load atomic i8, ptr @atomic seq_cst` that loads `0` in `@thread_a` &rightarrow; `@sync`
 * `store i8 2, ptr @non_atomic` in `@thread_a` (killer store)
</pre>
<img width="1px" height="1px" alt="" src="http://email.email.llvm.org/o/eJzUWN9z2j4S_2vEyw6MLNv8eOAhCcld59K5m_Z6rxnZXmM1suRKMpT-9TeyjYFAAmmSu287HQj2_vjsZ1erlbi1YqkQ5yS-JvFiwGtXaDP_zlOdyA0dJDrbzMmYtv-lXJWELgi9IhFVWj1wp0uRAgkXIJRDo7iEpdQJlyCmQHvZy-SazwxzoRBWWmRAIuoKgzx74IRNCZsBmVy3YmCdNui1A8JuoHIGDjB1UpByKXtjdqPS1tD2dW-FvWjFoGuMdEAnixOI-8COvYHSQkkvtMPfue6YeRJH99Tij4fUOv-CS7FUEGyVEwOSJyiBsDjYBxOQ8GorRFjMGs6l5tnO02v8EBaHbdrSsgLVUOXNelG6B0YEjah_vIdr_1e0jzLaQ3kRt9O9WkiOauH_RAf-OEXH29ggLI53IA_QHZXl0wqirwnF096ij58yv13up3-yCHTlYDhcobFCq_bx_f1_PgNh08K5yofD7gi78_1ipM2y-TXbRdkId-oQTEfBKN7CWtxef_sbJLWQGayFK4Bbi8YJreyol8Gc19KB42aJjoRX8HM6fhhHw1o9Kr1WQylU_XO4VPVW4-_aOrj51zcv-0ut0ESHwRisjB5JCcPK-7MkXBA2MfijFgZJeNP2KjvknIS3hN3ktUo9piF3zljCbjKLhE1gmGFSL4dayQ34R42Tf5uNUEtwGlCKUijuED5jqc1mgbmFRyElZpBsIGgS378ibCrFCv-pbpUzm6bi2RTONr69VO_6nOsxLNFBphsY_glPU7R2KwYrYUXznJ7B0muMRiOAXNcqg_udhFfpJHKhhC0wgzWXj69kJDxCwY55eKZ1v4GHngV25D_o_T-3s-xx09v5wMzeFJg-eh-5NuD7owWdf6TDt5LyQk5_K6VtCdpHUVWeBl88_jvzpu8yXR6mtqdL5LBGSLlqND6OsMXXW991vmCpVwgL5Bl89Vb2ev7i9mrhZV5lv9P9x6f7-9svT7TP0_eXbAskvLFKVL7FvrgR7Y2h4TV81lkt8dOiQdZ07baXEzZphayuTYoPuZCoeImdHNvJsf3N-OMmWw_2rts44KrZOMIrUDo3iKC0wbQ21v9Vq7VQGZQNy4RN_apeG-HQZ1CoNjcikVhi2ZpQ2HN_Zn5mId0fnN44Hp8eK56d5s4w0M3IF1PBzfKAgYvJeWlUJywM_jdjOrzyn2evMpjZroLbkZKwmP4ZA_-pAN6haj68WE6ePVjILj6A_AGJPn2Uef9EX3a8OUb7UUed5tMP8SKpHdquP3rQk-t3bM3Qezz0FRz7-sgm-BwM9tsh_573Jxt7f5ljIUOJDjPAFSpwha6XBQgHBa8qVHaYYN7UQTPo-jnXFdzBisvaN3XgSrsCDbSLFdaFSIunuq7A9oBhWq8esytM48m_y7WUeu1nnSeKacGF2k1thF0BGdNzE9uYemA-1L29eEz9OLmNtYMxO2X4on3neR9jI5aF48botV-TrUiz2W2537p7dUcZ05Z8L2-9heAUjuSUows6wDOmPG2lsLpyohS_eLMj9ABoq2VdVxsdprPMvtBLLo3ojdTRd0nhuWHthVI8XBCzQTYPs1k44wOcB5NgNqXxOJoOivmY5knEMh4ls5AHUYg5y8eMRzGdslmUxgMxZ5RFdEIDGkYTNh3NppRmSZgljOaTeByRiGLJhRxt74YGwtoa57MJi9mg2VNscxnNmMI1NC_9hB4vBmbudYZJvbQkolJYZ3dWnHCyucX25614AbsqwQwOVhp061lpNWybbQaez0Ft5LxwrrL9_dVSuKJORqkuu8us7mtYGf0dU0fYXQPQEnbXBrCas_8GAAD___AN4Hw">