1*9880d681SAndroid Build Coastguard Worker; RUN: opt -S -basicaa -gvn < %s | FileCheck %s 2*9880d681SAndroid Build Coastguard Worker 3*9880d681SAndroid Build Coastguard Worker; We can value forward across the fence since we can (semantically) 4*9880d681SAndroid Build Coastguard Worker; reorder the following load before the fence. 5*9880d681SAndroid Build Coastguard Workerdefine i32 @test(i32* %addr.i) { 6*9880d681SAndroid Build Coastguard Worker; CHECK-LABEL: @test 7*9880d681SAndroid Build Coastguard Worker; CHECK: store 8*9880d681SAndroid Build Coastguard Worker; CHECK: fence 9*9880d681SAndroid Build Coastguard Worker; CHECK-NOT: load 10*9880d681SAndroid Build Coastguard Worker; CHECK: ret 11*9880d681SAndroid Build Coastguard Worker store i32 5, i32* %addr.i, align 4 12*9880d681SAndroid Build Coastguard Worker fence release 13*9880d681SAndroid Build Coastguard Worker %a = load i32, i32* %addr.i, align 4 14*9880d681SAndroid Build Coastguard Worker ret i32 %a 15*9880d681SAndroid Build Coastguard Worker} 16*9880d681SAndroid Build Coastguard Worker 17*9880d681SAndroid Build Coastguard Worker; Same as above 18*9880d681SAndroid Build Coastguard Workerdefine i32 @test2(i32* %addr.i) { 19*9880d681SAndroid Build Coastguard Worker; CHECK-LABEL: @test2 20*9880d681SAndroid Build Coastguard Worker; CHECK-NEXT: fence 21*9880d681SAndroid Build Coastguard Worker; CHECK-NOT: load 22*9880d681SAndroid Build Coastguard Worker; CHECK: ret 23*9880d681SAndroid Build Coastguard Worker %a = load i32, i32* %addr.i, align 4 24*9880d681SAndroid Build Coastguard Worker fence release 25*9880d681SAndroid Build Coastguard Worker %a2 = load i32, i32* %addr.i, align 4 26*9880d681SAndroid Build Coastguard Worker %res = sub i32 %a, %a2 27*9880d681SAndroid Build Coastguard Worker ret i32 %res 28*9880d681SAndroid Build Coastguard Worker} 29*9880d681SAndroid Build Coastguard Worker 30*9880d681SAndroid Build Coastguard Worker; We can not value forward across an acquire barrier since we might 31*9880d681SAndroid Build Coastguard Worker; be syncronizing with another thread storing to the same variable 32*9880d681SAndroid Build Coastguard Worker; followed by a release fence. This is not so much enforcing an 33*9880d681SAndroid Build Coastguard Worker; ordering property (though it is that too), but a liveness 34*9880d681SAndroid Build Coastguard Worker; property. We expect to eventually see the value of store by 35*9880d681SAndroid Build Coastguard Worker; another thread when spinning on that location. 36*9880d681SAndroid Build Coastguard Workerdefine i32 @test3(i32* noalias %addr.i, i32* noalias %otheraddr) { 37*9880d681SAndroid Build Coastguard Worker; CHECK-LABEL: @test3 38*9880d681SAndroid Build Coastguard Worker; CHECK: load 39*9880d681SAndroid Build Coastguard Worker; CHECK: fence 40*9880d681SAndroid Build Coastguard Worker; CHECK: load 41*9880d681SAndroid Build Coastguard Worker; CHECK: ret i32 %res 42*9880d681SAndroid Build Coastguard Worker ; the following code is intented to model the unrolling of 43*9880d681SAndroid Build Coastguard Worker ; two iterations in a spin loop of the form: 44*9880d681SAndroid Build Coastguard Worker ; do { fence acquire: tmp = *%addr.i; ) while (!tmp); 45*9880d681SAndroid Build Coastguard Worker ; It's hopefully clear that allowing PRE to turn this into: 46*9880d681SAndroid Build Coastguard Worker ; if (!*%addr.i) while(true) {} would be unfortunate 47*9880d681SAndroid Build Coastguard Worker fence acquire 48*9880d681SAndroid Build Coastguard Worker %a = load i32, i32* %addr.i, align 4 49*9880d681SAndroid Build Coastguard Worker fence acquire 50*9880d681SAndroid Build Coastguard Worker %a2 = load i32, i32* %addr.i, align 4 51*9880d681SAndroid Build Coastguard Worker %res = sub i32 %a, %a2 52*9880d681SAndroid Build Coastguard Worker ret i32 %res 53*9880d681SAndroid Build Coastguard Worker} 54*9880d681SAndroid Build Coastguard Worker 55*9880d681SAndroid Build Coastguard Worker; Another example of why forwarding across an acquire fence is problematic 56*9880d681SAndroid Build Coastguard Worker; can be seen in a normal locking operation. Say we had: 57*9880d681SAndroid Build Coastguard Worker; *p = 5; unlock(l); lock(l); use(p); 58*9880d681SAndroid Build Coastguard Worker; forwarding the store to p would be invalid. A reasonable implementation 59*9880d681SAndroid Build Coastguard Worker; of unlock and lock might be: 60*9880d681SAndroid Build Coastguard Worker; unlock() { atomicrmw sub %l, 1 unordered; fence release } 61*9880d681SAndroid Build Coastguard Worker; lock() { 62*9880d681SAndroid Build Coastguard Worker; do { 63*9880d681SAndroid Build Coastguard Worker; %res = cmpxchg %p, 0, 1, monotonic monotonic 64*9880d681SAndroid Build Coastguard Worker; } while(!%res.success) 65*9880d681SAndroid Build Coastguard Worker; fence acquire; 66*9880d681SAndroid Build Coastguard Worker; } 67*9880d681SAndroid Build Coastguard Worker; Given we chose to forward across the release fence, we clearly can't forward 68*9880d681SAndroid Build Coastguard Worker; across the acquire fence as well. 69*9880d681SAndroid Build Coastguard Worker 70