Bug type: crash
Component: DeadStoreElimination
Bug location: llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp: eliminateRedundantStoresOfExistingValues
Issue title: [DSE] crash on applying * to std::nullopt
Labels: crash
llvm:transforms
Reported by: eaeltsin

[reduced5.zip](https://github.com/llvm/llvm-project/files/15433764/reduced5.zip)

The command
```
opt -passes=dse reduced5.ll
```
fails occasionally. Debug version reliably complains
```
include/c++/v1/optional:805: assertion this->has_value() failed: optional operator* called on a disengaged value
```
with stack trace
```
    frame #3: 0x00005555663c6a43 opt`std::__u::optional<llvm::MemoryLocation>::operator*(this= Has Value=false ) && at optional:805:5
    frame #4: 0x00005555663c4d58 opt`(anonymous namespace)::DSEState::eliminateRedundantStoresOfExistingValues(this=0x00007fffffff9130)::'lambda'()::operator()() const at DeadStoreElimination.cpp:2119:39
    frame #5: 0x00005555663bf842 opt`(anonymous namespace)::DSEState::eliminateRedundantStoresOfExistingValues(this=0x00007fffffff9960) at DeadStoreElimination.cpp:2132:12
    frame #6: 0x00005555663b8956 opt`(anonymous namespace)::eliminateDeadStores(F=0x000033187fe3e008, AA=0x000033187feaafc8, MSSA=0x000033187fe603f0, DT=0x000033187fef6d78, PDT=0x000033187fed18d0, TLI=0x000033187fe0cd18, LI=0x000033187fe11cc8) at DeadStoreElimination.cpp:2332:23
    frame #7: 0x00005555663b6b3e opt`llvm::DSEPass::run(this=0x000033187fe08ad8, F=0x000033187fe3e008, AM=0x00007fffffffc1d8) at DeadStoreElimination.cpp:2355:18
```

The local fix is
```
==== llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp#184
# action=edit type=text
--- llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp	2024-04-15 20:27:56.000000000 -0700
+++ llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp	2024-05-24 04:36:17.000000000 -0700
@@ -2109,10 +2109,12 @@
         if (auto *MemSetI = dyn_cast<MemSetInst>(UpperInst)) {
           if (auto *SI = dyn_cast<StoreInst>(DefInst)) {
             // MemSetInst must have a write location.
-            MemoryLocation UpperLoc = *getLocForWrite(UpperInst);
+            auto UpperLoc = getLocForWrite(UpperInst);
+            if (!UpperLoc)
+              return false;
             int64_t InstWriteOffset = 0;
             int64_t DepWriteOffset = 0;
-            auto OR = isOverwrite(UpperInst, DefInst, UpperLoc, *MaybeDefLoc,
+            auto OR = isOverwrite(UpperInst, DefInst, *UpperLoc, *MaybeDefLoc,
                                   InstWriteOffset, DepWriteOffset);
             Value *StoredByte = isBytewiseValue(SI->getValueOperand(), DL);
             return StoredByte && StoredByte == MemSetI->getOperand(1) &&
```
which basically reverts a piece of https://github.com/llvm/llvm-project/commit/81d69e1bda9e4b6a83f29ba1f614e43ab4700972

Looks like the actual problem happened earlier?

Please take a look, this is blocking us significantly.



Comments: author: eaeltsin
body: @nikic @fhahn FYI

the reproducer was cooked by @alinas 


Fix patch:
commit 243ffbdf8b25285d04ee4393e86094312cb7c64f
Author: eaeltsin <109593613+eaeltsin@users.noreply.github.com>
Date:   Mon May 27 09:26:44 2024 +0200

    [DSE] Check write location in IsRedundantStore (#93400)
    
    Fix https://github.com/llvm/llvm-project/issues/93298.

diff --git a/llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp b/llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp
index ed4212d29cef..172cce2cfa38 100644
--- a/llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp
+++ b/llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp
@@ -2109,10 +2109,12 @@ struct DSEState {
         if (auto *MemSetI = dyn_cast<MemSetInst>(UpperInst)) {
           if (auto *SI = dyn_cast<StoreInst>(DefInst)) {
             // MemSetInst must have a write location.
-            MemoryLocation UpperLoc = *getLocForWrite(UpperInst);
+            auto UpperLoc = getLocForWrite(UpperInst);
+            if (!UpperLoc)
+              return false;
             int64_t InstWriteOffset = 0;
             int64_t DepWriteOffset = 0;
-            auto OR = isOverwrite(UpperInst, DefInst, UpperLoc, *MaybeDefLoc,
+            auto OR = isOverwrite(UpperInst, DefInst, *UpperLoc, *MaybeDefLoc,
                                   InstWriteOffset, DepWriteOffset);
             Value *StoredByte = isBytewiseValue(SI->getValueOperand(), DL);
             return StoredByte && StoredByte == MemSetI->getOperand(1) &&


Regression tests:
file: llvm/test/Transforms/DeadStoreElimination/simple.ll
commands: opt < %s -passes=dse -S
opt < %s -aa-pipeline=basic-aa -passes=dse -S
tests: test_name: test48
test_body: target datalayout = "E-p:64:64:64-a0:0:8-f32:32:32-f64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-v64:64:64-v128:128:128"

define i32 @test48(ptr %P, ptr noalias %Q, ptr %R) {
  store i32 1, ptr %Q, align 4
  store i32 2, ptr %P, align 4
  store i32 3, ptr %Q, align 4
  %l = load i32, ptr %R, align 4
  ret i32 %l
}

test_name: test49
test_body: target datalayout = "E-p:64:64:64-a0:0:8-f32:32:32-f64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-v64:64:64-v128:128:128"

; Function Attrs: nocallback nofree nounwind willreturn memory(argmem: write)
declare void @llvm.memset.p0.i64(ptr nocapture writeonly, i8, i64, i1 immarg) #0

define void @test49() {
bb:
  call void @llvm.memset.p0.i64(ptr readonly null, i8 0, i64 0, i1 false)
  store ptr null, ptr null, align 8
  ret void
}

attributes #0 = { nocallback nofree nounwind willreturn memory(argmem: write) }