[llvm] ffb3277 - [SimplifyCFG] Improve store speculation check

Nikita Popov via llvm-commits llvm-commits at lists.llvm.org
Mon Jul 26 06:03:31 PDT 2021


Author: Nikita Popov
Date: 2021-07-26T15:01:00+02:00
New Revision: ffb3277b0036909a8e622d5758a1e2850eabfd19

URL: https://github.com/llvm/llvm-project/commit/ffb3277b0036909a8e622d5758a1e2850eabfd19
DIFF: https://github.com/llvm/llvm-project/commit/ffb3277b0036909a8e622d5758a1e2850eabfd19.diff

LOG: [SimplifyCFG] Improve store speculation check

isSafeToSpeculateStore() looks for a preceding store to the same
location to make sure that introducing a new store of the same
value is safe. It currently bails on intervening mayHaveSideEffect()
instructions. However, I believe just checking mayWriteToMemory()
is sufficient there -- we just need to make sure that we know which
value was stored, we don't care if we can unwind in the meantime.

While looking into this, I started having some doubts about the
correctness of the transform with regard to thread safety. While
we don't try to hoist non-simple stores, I believe we also need
to make sure that the preceding store is simple as well. Otherwise
we could introduce a spurious non-atomic write after an atomic write
-- under our memory model this would result in a subsequent undef
atomic read, even if the second write stores the same value as the
first.

Example: https://alive2.llvm.org/ce/z/q_3YAL

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

Added: 
    

Modified: 
    llvm/lib/Transforms/Utils/SimplifyCFG.cpp
    llvm/test/Transforms/SimplifyCFG/speculate-store.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
index 452db31ca288..455e9ec47754 100644
--- a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
+++ b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
@@ -2240,13 +2240,15 @@ static Value *isSafeToSpeculateStore(Instruction *I, BasicBlock *BrBB,
     --MaxNumInstToLookAt;
 
     // Could be calling an instruction that affects memory like free().
-    if (CurI.mayHaveSideEffects() && !isa<StoreInst>(CurI))
+    if (CurI.mayWriteToMemory() && !isa<StoreInst>(CurI))
       return nullptr;
 
     if (auto *SI = dyn_cast<StoreInst>(&CurI)) {
-      // Found the previous store make sure it stores to the same location.
+      // Found the previous store to same location and type. Make sure it is
+      // simple, to avoid introducing a spurious non-atomic write after an
+      // atomic write.
       if (SI->getPointerOperand() == StorePtr &&
-          SI->getValueOperand()->getType() == StoreTy)
+          SI->getValueOperand()->getType() == StoreTy && SI->isSimple())
         // Found the previous store, return its value operand.
         return SI->getValueOperand();
       return nullptr; // Unknown store.

diff  --git a/llvm/test/Transforms/SimplifyCFG/speculate-store.ll b/llvm/test/Transforms/SimplifyCFG/speculate-store.ll
index 854ca7527a85..8ceba7df8cbb 100644
--- a/llvm/test/Transforms/SimplifyCFG/speculate-store.ll
+++ b/llvm/test/Transforms/SimplifyCFG/speculate-store.ll
@@ -135,13 +135,11 @@ ret.end:
 
 define void @readonly_call(ptr %ptr, i1 %cmp) {
 ; CHECK-LABEL: @readonly_call(
+; CHECK-NEXT:  ret.end:
 ; CHECK-NEXT:    store i32 0, ptr [[PTR:%.*]], align 4
 ; CHECK-NEXT:    call void @unknown_fun() #[[ATTR0:[0-9]+]]
-; CHECK-NEXT:    br i1 [[CMP:%.*]], label [[IF_THEN:%.*]], label [[RET_END:%.*]]
-; CHECK:       if.then:
-; CHECK-NEXT:    store i32 1, ptr [[PTR]], align 4
-; CHECK-NEXT:    br label [[RET_END]]
-; CHECK:       ret.end:
+; CHECK-NEXT:    [[SPEC_STORE_SELECT:%.*]] = select i1 [[CMP:%.*]], i32 1, i32 0
+; CHECK-NEXT:    store i32 [[SPEC_STORE_SELECT]], ptr [[PTR]], align 4
 ; CHECK-NEXT:    ret void
 ;
   store i32 0, ptr %ptr
@@ -158,10 +156,12 @@ ret.end:
 
 define void @atomic_and_simple(ptr %ptr, i1 %cmp) {
 ; CHECK-LABEL: @atomic_and_simple(
-; CHECK-NEXT:  ret.end:
 ; CHECK-NEXT:    store atomic i32 0, ptr [[PTR:%.*]] seq_cst, align 4
-; CHECK-NEXT:    [[SPEC_STORE_SELECT:%.*]] = select i1 [[CMP:%.*]], i32 1, i32 0
-; CHECK-NEXT:    store i32 [[SPEC_STORE_SELECT]], ptr [[PTR]], align 4
+; CHECK-NEXT:    br i1 [[CMP:%.*]], label [[IF_THEN:%.*]], label [[RET_END:%.*]]
+; CHECK:       if.then:
+; CHECK-NEXT:    store i32 1, ptr [[PTR]], align 4
+; CHECK-NEXT:    br label [[RET_END]]
+; CHECK:       ret.end:
 ; CHECK-NEXT:    ret void
 ;
   store atomic i32 0, ptr %ptr seq_cst, align 4


        


More information about the llvm-commits mailing list