llvm/test/Transforms/GVN/fence.ll
Anna Thomas aaeaea1399 [AliasAnalysis] Fences do not modify constant memory location
Summary:
Fence instructions are currently marked as `ModRef` for all memory locations.

We can improve this for constant memory locations (such as constant globals),
since fence instructions cannot modify these locations.

This helps us to forward constant loads across fences (added test case in GVN).
There were no changes in behaviour for similar test cases in early-cse and licm.

Reviewers: dberlin, sanjoy, reames

Subscribers: llvm-commits

Differential Revision: https://reviews.llvm.org/D28914

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@292546 91177308-0d34-0410-b5e6-96231b3b80d8
2017-01-20 00:21:33 +00:00

90 lines
2.6 KiB
LLVM

; 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) {
; CHECK-LABEL: @test
; CHECK: store
; CHECK: fence
; CHECK-NOT: load
; CHECK: ret
store i32 5, i32* %addr.i, align 4
fence release
%a = load i32, i32* %addr.i, align 4
ret i32 %a
}
; Same as above
define i32 @test2(i32* %addr.i) {
; CHECK-LABEL: @test2
; CHECK-NEXT: fence
; CHECK-NOT: load
; CHECK: ret
%a = load i32, i32* %addr.i, align 4
fence release
%a2 = load i32, i32* %addr.i, align 4
%res = sub i32 %a, %a2
ret i32 %res
}
; We can not value forward across an acquire barrier since we might
; be syncronizing with another thread storing to the same variable
; followed by a release fence. This is not so much enforcing an
; ordering property (though it is that too), but a liveness
; property. We expect to eventually see the value of store by
; another thread when spinning on that location.
define i32 @test3(i32* noalias %addr.i, i32* noalias %otheraddr) {
; CHECK-LABEL: @test3
; CHECK: load
; CHECK: fence
; CHECK: load
; CHECK: ret i32 %res
; the following code is intented to model the unrolling of
; two iterations in a spin loop of the form:
; do { fence acquire: tmp = *%addr.i; ) while (!tmp);
; It's hopefully clear that allowing PRE to turn this into:
; if (!*%addr.i) while(true) {} would be unfortunate
fence acquire
%a = load i32, i32* %addr.i, align 4
fence acquire
%a2 = load i32, i32* %addr.i, align 4
%res = sub i32 %a, %a2
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);
; forwarding the store to p would be invalid. A reasonable implementation
; of unlock and lock might be:
; unlock() { atomicrmw sub %l, 1 unordered; fence release }
; lock() {
; do {
; %res = cmpxchg %p, 0, 1, monotonic monotonic
; } while(!%res.success)
; fence acquire;
; }
; Given we chose to forward across the release fence, we clearly can't forward
; across the acquire fence as well.