Skip to content

Commit ffb3277

Browse files
committed
[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
1 parent e484e1a commit ffb3277

File tree

2 files changed

+13
-11
lines changed

2 files changed

+13
-11
lines changed

llvm/lib/Transforms/Utils/SimplifyCFG.cpp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2240,13 +2240,15 @@ static Value *isSafeToSpeculateStore(Instruction *I, BasicBlock *BrBB,
22402240
--MaxNumInstToLookAt;
22412241

22422242
// Could be calling an instruction that affects memory like free().
2243-
if (CurI.mayHaveSideEffects() && !isa<StoreInst>(CurI))
2243+
if (CurI.mayWriteToMemory() && !isa<StoreInst>(CurI))
22442244
return nullptr;
22452245

22462246
if (auto *SI = dyn_cast<StoreInst>(&CurI)) {
2247-
// Found the previous store make sure it stores to the same location.
2247+
// Found the previous store to same location and type. Make sure it is
2248+
// simple, to avoid introducing a spurious non-atomic write after an
2249+
// atomic write.
22482250
if (SI->getPointerOperand() == StorePtr &&
2249-
SI->getValueOperand()->getType() == StoreTy)
2251+
SI->getValueOperand()->getType() == StoreTy && SI->isSimple())
22502252
// Found the previous store, return its value operand.
22512253
return SI->getValueOperand();
22522254
return nullptr; // Unknown store.

llvm/test/Transforms/SimplifyCFG/speculate-store.ll

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -135,13 +135,11 @@ ret.end:
135135

136136
define void @readonly_call(ptr %ptr, i1 %cmp) {
137137
; CHECK-LABEL: @readonly_call(
138+
; CHECK-NEXT: ret.end:
138139
; CHECK-NEXT: store i32 0, ptr [[PTR:%.*]], align 4
139140
; CHECK-NEXT: call void @unknown_fun() #[[ATTR0:[0-9]+]]
140-
; CHECK-NEXT: br i1 [[CMP:%.*]], label [[IF_THEN:%.*]], label [[RET_END:%.*]]
141-
; CHECK: if.then:
142-
; CHECK-NEXT: store i32 1, ptr [[PTR]], align 4
143-
; CHECK-NEXT: br label [[RET_END]]
144-
; CHECK: ret.end:
141+
; CHECK-NEXT: [[SPEC_STORE_SELECT:%.*]] = select i1 [[CMP:%.*]], i32 1, i32 0
142+
; CHECK-NEXT: store i32 [[SPEC_STORE_SELECT]], ptr [[PTR]], align 4
145143
; CHECK-NEXT: ret void
146144
;
147145
store i32 0, ptr %ptr
@@ -158,10 +156,12 @@ ret.end:
158156

159157
define void @atomic_and_simple(ptr %ptr, i1 %cmp) {
160158
; CHECK-LABEL: @atomic_and_simple(
161-
; CHECK-NEXT: ret.end:
162159
; CHECK-NEXT: store atomic i32 0, ptr [[PTR:%.*]] seq_cst, align 4
163-
; CHECK-NEXT: [[SPEC_STORE_SELECT:%.*]] = select i1 [[CMP:%.*]], i32 1, i32 0
164-
; CHECK-NEXT: store i32 [[SPEC_STORE_SELECT]], ptr [[PTR]], align 4
160+
; CHECK-NEXT: br i1 [[CMP:%.*]], label [[IF_THEN:%.*]], label [[RET_END:%.*]]
161+
; CHECK: if.then:
162+
; CHECK-NEXT: store i32 1, ptr [[PTR]], align 4
163+
; CHECK-NEXT: br label [[RET_END]]
164+
; CHECK: ret.end:
165165
; CHECK-NEXT: ret void
166166
;
167167
store atomic i32 0, ptr %ptr seq_cst, align 4

0 commit comments

Comments
 (0)