diff --git a/llvm/lib/Analysis/Loads.cpp b/llvm/lib/Analysis/Loads.cpp index 21503ef668be..c5d231367331 100644 --- a/llvm/lib/Analysis/Loads.cpp +++ b/llvm/lib/Analysis/Loads.cpp @@ -416,6 +416,14 @@ Value *llvm::FindAvailableLoadedValue(LoadInst *Load, BasicBlock *ScanBB, Value *Ptr = Load->getPointerOperand(); Type *AccessTy = Load->getType(); + // We can never remove a volatile load + if (Load->isVolatile()) + return nullptr; + + // Anything stronger than unordered is currently unimplemented. + if (!Load->isUnordered()) + return nullptr; + const DataLayout &DL = ScanBB->getModule()->getDataLayout(); // Try to get the store size for the type. @@ -445,6 +453,12 @@ Value *llvm::FindAvailableLoadedValue(LoadInst *Load, BasicBlock *ScanBB, if (AreEquivalentAddressValues( LI->getPointerOperand()->stripPointerCasts(), StrippedPtr) && CastInst::isBitOrNoopPointerCastable(LI->getType(), AccessTy, DL)) { + + // We can value forward from an atomic to a non-atomic, but not the + // other way around. + if (LI->isAtomic() < Load->isAtomic()) + return nullptr; + if (AATags) LI->getAAMetadata(*AATags); return LI; @@ -458,6 +472,12 @@ Value *llvm::FindAvailableLoadedValue(LoadInst *Load, BasicBlock *ScanBB, if (AreEquivalentAddressValues(StorePtr, StrippedPtr) && CastInst::isBitOrNoopPointerCastable(SI->getValueOperand()->getType(), AccessTy, DL)) { + + // We can value forward from an atomic to a non-atomic, but not the + // other way around. + if (SI->isAtomic() < Load->isAtomic()) + return nullptr; + if (AATags) SI->getAAMetadata(*AATags); return SI->getOperand(0); diff --git a/llvm/test/Transforms/InstCombine/atomic.ll b/llvm/test/Transforms/InstCombine/atomic.ll index 5754a5a4ba56..bf576ba4b3a9 100644 --- a/llvm/test/Transforms/InstCombine/atomic.ll +++ b/llvm/test/Transforms/InstCombine/atomic.ll @@ -5,8 +5,8 @@ target triple = "x86_64-apple-macosx10.7.0" ; Check transforms involving atomic operations -define i32 @test2(i32* %p) { -; CHECK-LABEL: define i32 @test2( +define i32 @test1(i32* %p) { +; CHECK-LABEL: define i32 @test1( ; CHECK: %x = load atomic i32, i32* %p seq_cst, align 4 ; CHECK: shl i32 %x, 1 %x = load atomic i32, i32* %p seq_cst, align 4 @@ -14,3 +14,49 @@ define i32 @test2(i32* %p) { %z = add i32 %x, %y ret i32 %z } + +define i32 @test2(i32* %p) { +; CHECK-LABEL: define i32 @test2( +; CHECK: %x = load volatile i32, i32* %p, align 4 +; CHECK: %y = load volatile i32, i32* %p, align 4 + %x = load volatile i32, i32* %p, align 4 + %y = load volatile i32, i32* %p, align 4 + %z = add i32 %x, %y + ret i32 %z +} + +; The exact semantics of mixing volatile and non-volatile on the same +; memory location are a bit unclear, but conservatively, we know we don't +; want to remove the volatile. +define i32 @test3(i32* %p) { +; CHECK-LABEL: define i32 @test3( +; CHECK: %x = load volatile i32, i32* %p, align 4 + %x = load volatile i32, i32* %p, align 4 + %y = load i32, i32* %p, align 4 + %z = add i32 %x, %y + ret i32 %z +} + +; FIXME: Forwarding from a stronger atomic is fine +define i32 @test4(i32* %p) { +; CHECK-LABEL: define i32 @test4( +; CHECK: %x = load atomic i32, i32* %p seq_cst, align 4 +; CHECK: %y = load atomic i32, i32* %p unordered, align 4 + %x = load atomic i32, i32* %p seq_cst, align 4 + %y = load atomic i32, i32* %p unordered, align 4 + %z = add i32 %x, %y + ret i32 %z +} + +; Forwarding from a non-atomic is not. (The earlier load +; could in priciple be promoted to atomic and then forwarded, +; but we can't just drop the atomic from the load.) +define i32 @test5(i32* %p) { +; CHECK-LABEL: define i32 @test5( +; CHECK: %x = load atomic i32, i32* %p unordered, align 4 + %x = load atomic i32, i32* %p unordered, align 4 + %y = load i32, i32* %p, align 4 + %z = add i32 %x, %y + ret i32 %z +} +