mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-22 02:33:06 +01:00
[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
This commit is contained in:
parent
d43867c3c3
commit
845ad210b0
@ -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.
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user