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 @@ -373,6 +373,28 @@ ScanFrom, MaxInstsToScan, AA, IsLoad, NumScanedInst); } +// Check if the load and the store have the same base, constant offsets and +// non-overlapping access ranges. +static bool AreNonOverlapSameBaseLoadAndStore( + Value *LoadPtr, Type *LoadTy, Value *StorePtr, Type *StoreTy, + const DataLayout &DL) { + APInt LoadOffset(DL.getTypeSizeInBits(LoadPtr->getType()), 0); + APInt StoreOffset(DL.getTypeSizeInBits(StorePtr->getType()), 0); + Value *LoadBase = LoadPtr->stripAndAccumulateConstantOffsets( + DL, LoadOffset, /* AllowNonInbounds */ false); + Value *StoreBase = StorePtr->stripAndAccumulateConstantOffsets( + DL, StoreOffset, /* AllowNonInbounds */ false); + if (LoadBase != StoreBase) + return false; + auto LoadAccessSize = LocationSize::precise(DL.getTypeStoreSize(LoadTy)); + auto StoreAccessSize = LocationSize::precise(DL.getTypeStoreSize(StoreTy)); + ConstantRange LoadRange(LoadOffset, + LoadOffset + LoadAccessSize.toRaw()); + ConstantRange StoreRange(StoreOffset, + StoreOffset + StoreAccessSize.toRaw()); + return LoadRange.intersectWith(StoreRange).isEmptySet(); +} + Value *llvm::FindAvailablePtrLoadStore(Value *Ptr, Type *AccessTy, bool AtLeastAtomic, BasicBlock *ScanBB, BasicBlock::iterator &ScanFrom, @@ -451,6 +473,17 @@ StrippedPtr != StorePtr) continue; + if (!AA) { + // When AA isn't available, but if the load and the store have the same + // base, constant offsets and non-overlapping access ranges, ignore the + // store. This is a simple form of alias analysis that is used by the + // inliner. FIXME: use BasicAA if possible. + if (AreNonOverlapSameBaseLoadAndStore( + Ptr, AccessTy, SI->getPointerOperand(), + SI->getValueOperand()->getType(), DL)) + continue; + } + // If we have alias analysis and it says the store won't modify the loaded // value, ignore the store. if (AA && !isModSet(AA->getModRefInfo(SI, StrippedPtr, AccessSize))) diff --git a/llvm/unittests/Analysis/CMakeLists.txt b/llvm/unittests/Analysis/CMakeLists.txt --- a/llvm/unittests/Analysis/CMakeLists.txt +++ b/llvm/unittests/Analysis/CMakeLists.txt @@ -20,6 +20,7 @@ GlobalsModRefTest.cpp IVDescriptorsTest.cpp LazyCallGraphTest.cpp + LoadsTest.cpp LoopInfoTest.cpp MemoryBuiltinsTest.cpp MemorySSATest.cpp diff --git a/llvm/unittests/Analysis/LoadsTest.cpp b/llvm/unittests/Analysis/LoadsTest.cpp new file mode 100644 --- /dev/null +++ b/llvm/unittests/Analysis/LoadsTest.cpp @@ -0,0 +1,61 @@ +//===- LoadsTest.cpp - local load analysis unit tests ---------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/Analysis/Loads.h" +#include "llvm/AsmParser/Parser.h" +#include "llvm/IR/Instructions.h" +#include "llvm/IR/LLVMContext.h" +#include "llvm/IR/Module.h" +#include "llvm/Support/SourceMgr.h" +#include "gtest/gtest.h" + +using namespace llvm; + +static std::unique_ptr parseIR(LLVMContext &C, const char *IR) { + SMDiagnostic Err; + std::unique_ptr Mod = parseAssemblyString(IR, Err, C); + if (!Mod) + Err.print("AnalysisTests", errs()); + return Mod; +} + +TEST(LoadsTest, FindAvailableLoadedValueSameBasePtrConstantOffsetsNullAA) { + LLVMContext C; + std::unique_ptr M = parseIR(C, + R"IR( +%class = type <{ i32, i32 }> + +define i32 @f() { +entry: + %o = alloca %class + %f1 = getelementptr inbounds %class, %class* %o, i32 0, i32 0 + store i32 42, i32* %f1 + %f2 = getelementptr inbounds %class, %class* %o, i32 0, i32 1 + store i32 43, i32* %f2 + %v = load i32, i32* %f1 + ret i32 %v +} +)IR"); + auto *GV = M->getNamedValue("f"); + ASSERT_TRUE(GV); + auto *F = dyn_cast(GV); + ASSERT_TRUE(F); + Instruction *Inst = &F->front().front(); + auto *AI = dyn_cast(Inst); + ASSERT_TRUE(AI); + Inst = &*++F->front().rbegin(); + auto *LI = dyn_cast(Inst); + ASSERT_TRUE(LI); + BasicBlock::iterator BBI(LI); + Value *Loaded = FindAvailableLoadedValue( + LI, LI->getParent(), BBI, 0, nullptr, nullptr); + ASSERT_TRUE(Loaded); + auto *CI = dyn_cast(Loaded); + ASSERT_TRUE(CI); + ASSERT_TRUE(CI->equalsInt(42)); +}