[docs] Add LICENSE.txt to the root of the mono-repo
[llvm-project.git] / llvm / test / Transforms / GVN / fence.ll
blob8d618e0d4ed982652a14ce42cde88099b31e8950
1 ; RUN: opt -S -basic-aa -gvn < %s | FileCheck %s
3 @a = external constant i32
4 ; We can value forward across the fence since we can (semantically) 
5 ; reorder the following load before the fence.
6 define i32 @test(i32* %addr.i) {
7 ; CHECK-LABEL: @test
8 ; CHECK: store
9 ; CHECK: fence
10 ; CHECK-NOT: load
11 ; CHECK: ret
12   store i32 5, i32* %addr.i, align 4
13   fence release
14   %a = load i32, i32* %addr.i, align 4
15   ret i32 %a
18 ; Same as above
19 define i32 @test2(i32* %addr.i) {
20 ; CHECK-LABEL: @test2
21 ; CHECK-NEXT: fence
22 ; CHECK-NOT: load
23 ; CHECK: ret
24   %a = load i32, i32* %addr.i, align 4
25   fence release
26   %a2 = load i32, i32* %addr.i, align 4
27   %res = sub i32 %a, %a2
28   ret i32 %res
31 ; We can not value forward across an acquire barrier since we might
32 ; be syncronizing with another thread storing to the same variable
33 ; followed by a release fence.  This is not so much enforcing an
34 ; ordering property (though it is that too), but a liveness 
35 ; property.  We expect to eventually see the value of store by
36 ; another thread when spinning on that location.  
37 define i32 @test3(i32* noalias %addr.i, i32* noalias %otheraddr) {
38 ; CHECK-LABEL: @test3
39 ; CHECK: load
40 ; CHECK: fence
41 ; CHECK: load
42 ; CHECK: ret i32 %res
43   ; the following code is intented to model the unrolling of
44   ; two iterations in a spin loop of the form:
45   ;   do { fence acquire: tmp = *%addr.i; ) while (!tmp);
46   ; It's hopefully clear that allowing PRE to turn this into:
47   ;   if (!*%addr.i) while(true) {} would be unfortunate
48   fence acquire
49   %a = load i32, i32* %addr.i, align 4
50   fence acquire
51   %a2 = load i32, i32* %addr.i, align 4
52   %res = sub i32 %a, %a2
53   ret i32 %res
56 ; We can forward the value forward the load
57 ; across both the fences, because the load is from
58 ; a constant memory location.
59 define i32 @test4(i32* %addr) {
60 ; CHECK-LABEL: @test4
61 ; CHECK-NOT: load
62 ; CHECK: fence release
63 ; CHECK: store
64 ; CHECK: fence seq_cst
65 ; CHECK: ret i32 0
66   %var = load i32, i32* @a
67   fence release
68   store i32 42, i32* %addr, align 8
69   fence seq_cst
70   %var2 = load i32, i32* @a
71   %var3 = sub i32 %var, %var2
72   ret i32 %var3
75 ; Another example of why forwarding across an acquire fence is problematic
76 ; can be seen in a normal locking operation.  Say we had:
77 ; *p = 5; unlock(l); lock(l); use(p);
78 ; forwarding the store to p would be invalid.  A reasonable implementation
79 ; of unlock and lock might be:
80 ; unlock() { atomicrmw sub %l, 1 unordered; fence release }
81 ; lock() { 
82 ;   do {
83 ;     %res = cmpxchg %p, 0, 1, monotonic monotonic
84 ;   } while(!%res.success)
85 ;   fence acquire;
86 ; }
87 ; Given we chose to forward across the release fence, we clearly can't forward
88 ; across the acquire fence as well.