Index: llvm/include/llvm/Analysis/Loads.h =================================================================== --- llvm/include/llvm/Analysis/Loads.h +++ llvm/include/llvm/Analysis/Loads.h @@ -180,7 +180,7 @@ /// reject all invalid cases yet, but will be made stricter in the future. In /// particular this means returning true means unknown if replacement is safe. bool canReplacePointersIfEqual(Value *A, Value *B, const DataLayout &DL, - Instruction *CtxI); + Instruction *CtxI, AAResults *AA = nullptr); } #endif Index: llvm/lib/Analysis/Loads.cpp =================================================================== --- llvm/lib/Analysis/Loads.cpp +++ llvm/lib/Analysis/Loads.cpp @@ -685,7 +685,7 @@ } bool llvm::canReplacePointersIfEqual(Value *A, Value *B, const DataLayout &DL, - Instruction *CtxI) { + Instruction *CtxI, AAResults *AA) { Type *Ty = A->getType(); assert(Ty == B->getType() && Ty->isPointerTy() && "values must have matching pointer types"); @@ -693,6 +693,11 @@ // NOTE: The checks in the function are incomplete and currently miss illegal // cases! The current implementation is a starting point and the // implementation should be made stricter over time. + + // Do not replace pointers if they are known noalias. + if (AA && AA->alias(A, B) == AliasResult::NoAlias) + return false; + if (auto *C = dyn_cast(B)) { // Do not allow replacing a pointer with a constant pointer, unless it is // either null or at least one byte is dereferenceable. Index: llvm/unittests/Analysis/LoadsTest.cpp =================================================================== --- llvm/unittests/Analysis/LoadsTest.cpp +++ llvm/unittests/Analysis/LoadsTest.cpp @@ -7,8 +7,12 @@ //===----------------------------------------------------------------------===// #include "llvm/Analysis/Loads.h" +#include "llvm/Analysis/AssumptionCache.h" +#include "llvm/Analysis/BasicAliasAnalysis.h" +#include "llvm/Analysis/TargetLibraryInfo.h" #include "llvm/AsmParser/Parser.h" #include "llvm/IR/Constants.h" +#include "llvm/IR/Dominators.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" @@ -71,7 +75,7 @@ declare void @use(i32*) -define void @f(i32* %p) { +define void @f(i32* %p, i32* noalias %p1) { call void @use(i32* getelementptr inbounds ([1 x i32], [1 x i32]* @y, i64 0, i64 0)) call void @use(i32* getelementptr inbounds (i32, i32* getelementptr inbounds ([1 x i32], [1 x i32]* @x, i64 0, i64 0), i64 1)) ret void @@ -83,16 +87,34 @@ auto *F = dyn_cast(GV); ASSERT_TRUE(F); + DominatorTree DT(*F); + TargetLibraryInfoImpl TLII; + TargetLibraryInfo TLI(TLII); + AssumptionCache AC(*F); + AAResults AA(TLI); + BasicAAResult BAA(DL, *F, TLI, AC, &DT); + AA.addAAResult(BAA); + // NOTE: the implementation of canReplacePointersIfEqual is incomplete. // Currently the only the cases it returns false for are really sound and // returning true means unknown. Value *P = &*F->arg_begin(); + Value *NoAliasPtr = F->getArg(1); + auto InstIter = F->front().begin(); Value *ConstDerefPtr = *cast(&*InstIter)->arg_begin(); // ConstDerefPtr is a constant pointer that is provably de-referenceable. We // can replace an arbitrary pointer with it. EXPECT_TRUE(canReplacePointersIfEqual(P, ConstDerefPtr, DL, nullptr)); + // Do not replace pointers if they are known noalias. + EXPECT_FALSE( + canReplacePointersIfEqual(NoAliasPtr, ConstDerefPtr, DL, nullptr, &AA)); + EXPECT_FALSE( + canReplacePointersIfEqual(ConstDerefPtr, NoAliasPtr, DL, nullptr, &AA)); + EXPECT_FALSE(canReplacePointersIfEqual(P, NoAliasPtr, DL, nullptr, &AA)); + EXPECT_FALSE(canReplacePointersIfEqual(NoAliasPtr, P, DL, nullptr, &AA)); + ++InstIter; Value *ConstUnDerefPtr = *cast(&*InstIter)->arg_begin(); // ConstUndDerefPtr is a constant pointer that is provably not