diff --git a/llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp b/llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp --- a/llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp +++ b/llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp @@ -1861,8 +1861,23 @@ // We are searching for the definition of the store's destination. // So, if that is the same definition as the load, then this is a // noop. Otherwise, fail. - if (LoadAccess != Current) + if (LoadAccess != Current) { + auto *CurrentStoreI = + dyn_cast(cast(Current)->getMemoryInst()); + if (CurrentStoreI && CurrentStoreI->getOperand(0) == LoadI) { + // For noop store of the form of LoadI and StoreI, + // An invariant should be kept is that the memory state of the + // related MemoryLoc before LoadI is the same as before StoreI. + // Here the definition of the store's destination is different + // with the definition of the load's destination, which it seems + // that the invariant mentioned above is broken. But the + // definition of the store's destination would write a value that + // is LoadI, actually, the invariant is still kept. So skip in + // this case. + continue; + } return false; + } } return true; } diff --git a/llvm/test/Transforms/DeadStoreElimination/stores-of-existing-values.ll b/llvm/test/Transforms/DeadStoreElimination/stores-of-existing-values.ll --- a/llvm/test/Transforms/DeadStoreElimination/stores-of-existing-values.ll +++ b/llvm/test/Transforms/DeadStoreElimination/stores-of-existing-values.ll @@ -612,12 +612,10 @@ ; CHECK-LABEL: @pr49927( ; CHECK-NEXT: [[V:%.*]] = load i32, i32* [[P:%.*]], align 4 ; CHECK-NEXT: store i32 [[V]], i32* [[Q:%.*]], align 4 -; CHECK-NEXT: store i32 [[V]], i32* [[P]], align 4 ; CHECK-NEXT: ret void ; %v = load i32, i32* %p, align 4 store i32 %v, i32* %q, align 4 - ; FIXME: this store can be eliminated store i32 %v, i32* %p, align 4 ret void }