brintos

brintos / llvm-project-archived public Read only

0
0
Text · 3.2 KiB · f2b1538 Raw
97 lines · plain
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 22; RUN: opt -S -passes=gvn < %s | FileCheck %s3 4@a = external constant i325; We can value forward across the fence since we can (semantically)6; reorder the following load before the fence.7define i32 @test(ptr %addr.i) {8; CHECK-LABEL: define i32 @test9; CHECK-SAME: (ptr [[ADDR_I:%.*]]) {10; CHECK-NEXT:    store i32 5, ptr [[ADDR_I]], align 411; CHECK-NEXT:    fence release12; CHECK-NEXT:    ret i32 513;14  store i32 5, ptr %addr.i, align 415  fence release16  %a = load i32, ptr %addr.i, align 417  ret i32 %a18}19 20; Same as above21define i32 @test2(ptr %addr.i) {22; CHECK-LABEL: define i32 @test223; CHECK-SAME: (ptr [[ADDR_I:%.*]]) {24; CHECK-NEXT:    fence release25; CHECK-NEXT:    ret i32 026;27  %a = load i32, ptr %addr.i, align 428  fence release29  %a2 = load i32, ptr %addr.i, align 430  %res = sub i32 %a, %a231  ret i32 %res32}33 34; We can not value forward across an acquire barrier since we might35; be syncronizing with another thread storing to the same variable36; followed by a release fence.  This is not so much enforcing an37; ordering property (though it is that too), but a liveness38; property.  We expect to eventually see the value of store by39; another thread when spinning on that location.40define i32 @test3(ptr noalias %addr.i, ptr noalias %otheraddr) {41; CHECK-LABEL: define i32 @test342; CHECK-SAME: (ptr noalias [[ADDR_I:%.*]], ptr noalias [[OTHERADDR:%.*]]) {43; CHECK-NEXT:    fence acquire44; CHECK-NEXT:    [[A:%.*]] = load i32, ptr [[ADDR_I]], align 445; CHECK-NEXT:    fence acquire46; CHECK-NEXT:    [[A2:%.*]] = load i32, ptr [[ADDR_I]], align 447; CHECK-NEXT:    [[RES:%.*]] = sub i32 [[A]], [[A2]]48; CHECK-NEXT:    ret i32 [[RES]]49;50  ; the following code is intented to model the unrolling of51  ; two iterations in a spin loop of the form:52  ;   do { fence acquire: tmp = *%addr.i; ) while (!tmp);53  ; It's hopefully clear that allowing PRE to turn this into:54  ;   if (!*%addr.i) while(true) {} would be unfortunate55  fence acquire56  %a = load i32, ptr %addr.i, align 457  fence acquire58  %a2 = load i32, ptr %addr.i, align 459  %res = sub i32 %a, %a260  ret i32 %res61}62 63; We can forward the value forward the load64; across both the fences, because the load is from65; a constant memory location.66define i32 @test4(ptr %addr) {67; CHECK-LABEL: define i32 @test468; CHECK-SAME: (ptr [[ADDR:%.*]]) {69; CHECK-NEXT:    fence release70; CHECK-NEXT:    store i32 42, ptr [[ADDR]], align 871; CHECK-NEXT:    fence seq_cst72; CHECK-NEXT:    ret i32 073;74  %var = load i32, ptr @a75  fence release76  store i32 42, ptr %addr, align 877  fence seq_cst78  %var2 = load i32, ptr @a79  %var3 = sub i32 %var, %var280  ret i32 %var381}82 83; Another example of why forwarding across an acquire fence is problematic84; can be seen in a normal locking operation.  Say we had:85; *p = 5; unlock(l); lock(l); use(p);86; forwarding the store to p would be invalid.  A reasonable implementation87; of unlock and lock might be:88; unlock() { atomicrmw sub %l, 1 unordered; fence release }89; lock() {90;   do {91;     %res = cmpxchg %p, 0, 1, monotonic monotonic92;   } while(!%res.success)93;   fence acquire;94; }95; Given we chose to forward across the release fence, we clearly can't forward96; across the acquire fence as well.97