diff --git a/llvm/lib/Analysis/Loads.cpp b/llvm/lib/Analysis/Loads.cpp --- a/llvm/lib/Analysis/Loads.cpp +++ b/llvm/lib/Analysis/Loads.cpp @@ -664,6 +664,37 @@ return nullptr; } +static bool mayOverlapLoadedMemory(const StoreInst *Store, const LoadInst *Load, + const DataLayout &DL) { + if (Store->getValueOperand() != Load) { + return true; + } + auto *Ty = Load->getType(); + if (Ty->isScalableTy()) { + return true; + } + auto AlignValue = Load->getAlign().value(); + if (Store->getAlign().value() != AlignValue) { + return true; + } + auto TyStoreSize = DL.getTypeStoreSize(Ty).getFixedSize(); + if (TyStoreSize > AlignValue) { + return true; + } + return false; +} + +static bool writesUnchangedLoadedValueToSameLocation(const Instruction *Inst, + const Value *Available, + const DataLayout &DL) { + auto *Store = dyn_cast_or_null(Inst); + auto *Load = dyn_cast_or_null(Available); + if (!Store || !Load || mayOverlapLoadedMemory(Store, Load, DL)) { + return false; + } + return true; +} + Value *llvm::FindAvailableLoadedValue(LoadInst *Load, AAResults &AA, bool *IsLoadCSE, unsigned MaxInstsToScan) { @@ -701,9 +732,13 @@ // did not modify the memory location. if (Available) { MemoryLocation Loc = MemoryLocation::get(Load); - for (Instruction *Inst : MustNotAliasInsts) + for (Instruction *Inst : MustNotAliasInsts) { + if (writesUnchangedLoadedValueToSameLocation(Inst, Available, DL)) { + continue; + } if (isModSet(AA.getModRefInfo(Inst, Loc))) return nullptr; + } } return Available; diff --git a/llvm/test/Transforms/InstCombine/load-elimination.ll b/llvm/test/Transforms/InstCombine/load-elimination.ll --- a/llvm/test/Transforms/InstCombine/load-elimination.ll +++ b/llvm/test/Transforms/InstCombine/load-elimination.ll @@ -6,8 +6,7 @@ ; CHECK-NEXT: entry: ; CHECK-NEXT: [[TMP0:%.*]] = load i8, ptr [[C:%.*]], align 1 ; CHECK-NEXT: store i8 [[TMP0]], ptr [[A:%.*]], align 1 -; CHECK-NEXT: [[TMP1:%.*]] = load i8, ptr [[C]], align 1 -; CHECK-NEXT: store i8 [[TMP1]], ptr [[B:%.*]], align 1 +; CHECK-NEXT: store i8 [[TMP0]], ptr [[B:%.*]], align 1 ; CHECK-NEXT: ret void ; entry: @@ -23,8 +22,7 @@ ; CHECK-NEXT: entry: ; CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[C:%.*]], align 4 ; CHECK-NEXT: store i32 [[TMP0]], ptr [[A:%.*]], align 4 -; CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[C]], align 4 -; CHECK-NEXT: store i32 [[TMP1]], ptr [[B:%.*]], align 4 +; CHECK-NEXT: store i32 [[TMP0]], ptr [[B:%.*]], align 4 ; CHECK-NEXT: ret void ; entry: @@ -61,8 +59,7 @@ ; CHECK-NEXT: entry: ; CHECK-NEXT: [[X1:%.*]] = load float, ptr [[X:%.*]], align 4 ; CHECK-NEXT: store float [[X1]], ptr [[A:%.*]], align 4 -; CHECK-NEXT: [[X2:%.*]] = load float, ptr [[X]], align 4 -; CHECK-NEXT: store float [[X2]], ptr [[C:%.*]], align 4 +; CHECK-NEXT: store float [[X1]], ptr [[C:%.*]], align 4 ; CHECK-NEXT: ret void ; entry: diff --git a/llvm/test/Transforms/InstCombine/load.ll b/llvm/test/Transforms/InstCombine/load.ll --- a/llvm/test/Transforms/InstCombine/load.ll +++ b/llvm/test/Transforms/InstCombine/load.ll @@ -213,9 +213,7 @@ ; CHECK-NEXT: [[X1:%.*]] = load float, ptr [[X:%.*]], align 4 ; CHECK-NEXT: store float [[X1]], ptr [[A:%.*]], align 4 ; CHECK-NEXT: store float [[X1]], ptr [[B:%.*]], align 4 -; CHECK-NEXT: [[X2:%.*]] = load float, ptr [[X]], align 4 -; CHECK-NEXT: store float [[X2]], ptr [[B]], align 4 -; CHECK-NEXT: store float [[X2]], ptr [[C:%.*]], align 4 +; CHECK-NEXT: store float [[X1]], ptr [[C:%.*]], align 4 ; CHECK-NEXT: ret void ; entry: @@ -238,9 +236,7 @@ ; CHECK-NEXT: [[X1:%.*]] = load <4 x i8>, ptr [[X:%.*]], align 4 ; CHECK-NEXT: store <4 x i8> [[X1]], ptr [[A:%.*]], align 4 ; CHECK-NEXT: store <4 x i8> [[X1]], ptr [[B:%.*]], align 4 -; CHECK-NEXT: [[X2:%.*]] = load <4 x i8>, ptr [[X]], align 4 -; CHECK-NEXT: store <4 x i8> [[X2]], ptr [[B]], align 4 -; CHECK-NEXT: store <4 x i8> [[X2]], ptr [[C:%.*]], align 4 +; CHECK-NEXT: store <4 x i8> [[X1]], ptr [[C:%.*]], align 4 ; CHECK-NEXT: ret void ; entry: