mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2025-01-31 20:51:52 +01:00
[CaptureTracking] Volatile operations capture their memory location
The memory location that corresponds to a volatile operation is very special. They are observed by the machine in ways which we cannot reason about. Differential Revision: http://reviews.llvm.org/D20555 llvm-svn: 270879
This commit is contained in:
parent
b0b1ecdbc5
commit
89a8ea9137
@ -1037,7 +1037,8 @@ Currently, only the following parameter attributes are defined:
|
||||
``nocapture``
|
||||
This indicates that the callee does not make any copies of the
|
||||
pointer that outlive the callee itself. This is not a valid
|
||||
attribute for return values.
|
||||
attribute for return values. Addresses used in volatile operations
|
||||
are considered to be captured.
|
||||
|
||||
.. _nest:
|
||||
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include "llvm/IR/Constants.h"
|
||||
#include "llvm/IR/Dominators.h"
|
||||
#include "llvm/IR/Instructions.h"
|
||||
#include "llvm/IR/IntrinsicInst.h"
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
@ -242,6 +243,13 @@ void llvm::PointerMayBeCaptured(const Value *V, CaptureTracker *Tracker) {
|
||||
if (CS.onlyReadsMemory() && CS.doesNotThrow() && I->getType()->isVoidTy())
|
||||
break;
|
||||
|
||||
// Volatile operations effectively capture the memory location that they
|
||||
// load and store to.
|
||||
if (auto *MI = dyn_cast<MemIntrinsic>(I))
|
||||
if (MI->isVolatile())
|
||||
if (Tracker->captured(U))
|
||||
return;
|
||||
|
||||
// Not captured if only passed via 'nocapture' arguments. Note that
|
||||
// calling a function pointer does not in itself cause the pointer to
|
||||
// be captured. This is a subtle point considering that (for example)
|
||||
@ -259,29 +267,46 @@ void llvm::PointerMayBeCaptured(const Value *V, CaptureTracker *Tracker) {
|
||||
break;
|
||||
}
|
||||
case Instruction::Load:
|
||||
// Loading from a pointer does not cause it to be captured.
|
||||
// Volatile loads make the address observable.
|
||||
if (cast<LoadInst>(I)->isVolatile())
|
||||
if (Tracker->captured(U))
|
||||
return;
|
||||
break;
|
||||
case Instruction::VAArg:
|
||||
// "va-arg" from a pointer does not cause it to be captured.
|
||||
break;
|
||||
case Instruction::Store:
|
||||
if (V == I->getOperand(0))
|
||||
// Stored the pointer - conservatively assume it may be captured.
|
||||
if (Tracker->captured(U))
|
||||
return;
|
||||
// Storing to the pointee does not cause the pointer to be captured.
|
||||
break;
|
||||
case Instruction::AtomicRMW:
|
||||
case Instruction::AtomicCmpXchg:
|
||||
// atomicrmw and cmpxchg conceptually include both a load and store from
|
||||
// the same location. As with a store, the location being accessed is
|
||||
// not captured, but the value being stored is. (For cmpxchg, we
|
||||
// probably don't need to capture the original comparison value, but for
|
||||
// the moment, let's be conservative.)
|
||||
if (V != I->getOperand(0))
|
||||
// Volatile stores make the address observable.
|
||||
if (V == I->getOperand(0) || cast<StoreInst>(I)->isVolatile())
|
||||
if (Tracker->captured(U))
|
||||
return;
|
||||
break;
|
||||
case Instruction::AtomicRMW: {
|
||||
// atomicrmw conceptually includes both a load and store from
|
||||
// the same location.
|
||||
// As with a store, the location being accessed is not captured,
|
||||
// but the value being stored is.
|
||||
// Volatile stores make the address observable.
|
||||
auto *ARMWI = cast<AtomicRMWInst>(I);
|
||||
if (ARMWI->getValOperand() == V || ARMWI->isVolatile())
|
||||
if (Tracker->captured(U))
|
||||
return;
|
||||
break;
|
||||
}
|
||||
case Instruction::AtomicCmpXchg: {
|
||||
// cmpxchg conceptually includes both a load and store from
|
||||
// the same location.
|
||||
// As with a store, the location being accessed is not captured,
|
||||
// but the value being stored is.
|
||||
// Volatile stores make the address observable.
|
||||
auto *ACXI = cast<AtomicCmpXchgInst>(I);
|
||||
if (ACXI->getCompareOperand() == V || ACXI->getNewValOperand() == V ||
|
||||
ACXI->isVolatile())
|
||||
if (Tracker->captured(U))
|
||||
return;
|
||||
break;
|
||||
}
|
||||
case Instruction::BitCast:
|
||||
case Instruction::GetElementPtr:
|
||||
case Instruction::PHI:
|
||||
|
@ -210,3 +210,11 @@ define void @test_atomicrmw(i32* %p) {
|
||||
atomicrmw add i32* %p, i32 1 seq_cst
|
||||
ret void
|
||||
}
|
||||
|
||||
; CHECK: define void @test_volatile(i32* %x)
|
||||
define void @test_volatile(i32* %x) {
|
||||
entry:
|
||||
%gep = getelementptr i32, i32* %x, i64 1
|
||||
store volatile i32 0, i32* %gep, align 4
|
||||
ret void
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user