Index: include/llvm/Analysis/AliasAnalysis.h =================================================================== --- include/llvm/Analysis/AliasAnalysis.h +++ include/llvm/Analysis/AliasAnalysis.h @@ -443,11 +443,7 @@ /// getModRefInfo (for fences) - Return information about whether /// a particular store modifies or reads the specified memory location. - ModRefInfo getModRefInfo(const FenceInst *S, const MemoryLocation &Loc) { - // Conservatively correct. (We could possibly be a bit smarter if - // Loc is a alloca that doesn't escape.) - return MRI_ModRef; - } + ModRefInfo getModRefInfo(const FenceInst *S, const MemoryLocation &Loc); /// getModRefInfo (for fences) - A convenience wrapper. ModRefInfo getModRefInfo(const FenceInst *S, const Value *P, uint64_t Size) { Index: lib/Analysis/AliasAnalysis.cpp =================================================================== --- lib/Analysis/AliasAnalysis.cpp +++ lib/Analysis/AliasAnalysis.cpp @@ -367,6 +367,14 @@ return MRI_Mod; } +ModRefInfo AAResults::getModRefInfo(const FenceInst *S, const MemoryLocation &Loc) { + // If we know that the location is a constant memory location, the fence + // cannot modify this location. + if (Loc.Ptr && pointsToConstantMemory(Loc)) + return MRI_Ref; + return MRI_ModRef; +} + ModRefInfo AAResults::getModRefInfo(const VAArgInst *V, const MemoryLocation &Loc) { Index: test/Transforms/GVN/fence.ll =================================================================== --- test/Transforms/GVN/fence.ll +++ test/Transforms/GVN/fence.ll @@ -1,5 +1,6 @@ ; RUN: opt -S -basicaa -gvn < %s | FileCheck %s +@a = external constant i32 ; We can value forward across the fence since we can (semantically) ; reorder the following load before the fence. define i32 @test(i32* %addr.i) { @@ -52,6 +53,25 @@ ret i32 %res } +; We can forward the value forward the load +; across both the fences, because the load is from +; a constant memory location. +define i32 @test4(i32* %addr) { +; CHECK-LABEL: @test4 +; CHECK-NOT: load +; CHECK: fence release +; CHECK: store +; CHECK: fence seq_cst +; CHECK: ret i32 0 + %var = load i32, i32* @a + fence release + store i32 42, i32* %addr, align 8 + fence seq_cst + %var2 = load i32, i32* @a + %var3 = sub i32 %var, %var2 + ret i32 %var3 +} + ; Another example of why forwarding across an acquire fence is problematic ; can be seen in a normal locking operation. Say we had: ; *p = 5; unlock(l); lock(l); use(p); Index: test/Transforms/NewGVN/fence.ll =================================================================== --- test/Transforms/NewGVN/fence.ll +++ test/Transforms/NewGVN/fence.ll @@ -1,6 +1,7 @@ ; XFAIL: * ; RUN: opt -S -basicaa -newgvn < %s | FileCheck %s +@a = external constant i32 ; We can value forward across the fence since we can (semantically) ; reorder the following load before the fence. define i32 @test(i32* %addr.i) { @@ -53,6 +54,25 @@ ret i32 %res } +; We can forward the value forward the load +; across both the fences, because the load is from +; a constant memory location. +define i32 @test4(i32* %addr) { +; CHECK-LABEL: @test4 +; CHECK-NOT: load +; CHECK: fence release +; CHECK: store +; CHECK: fence seq_cst +; CHECK: ret i32 0 + %var = load i32, i32* @a + fence release + store i32 42, i32* %addr, align 8 + fence seq_cst + %var2 = load i32, i32* @a + %var3 = sub i32 %var, %var2 + ret i32 %var3 +} + ; Another example of why forwarding across an acquire fence is problematic ; can be seen in a normal locking operation. Say we had: ; *p = 5; unlock(l); lock(l); use(p);