Index: llvm/trunk/docs/LangRef.rst =================================================================== --- llvm/trunk/docs/LangRef.rst +++ llvm/trunk/docs/LangRef.rst @@ -1037,7 +1037,8 @@ ``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: Index: llvm/trunk/lib/Analysis/CaptureTracking.cpp =================================================================== --- llvm/trunk/lib/Analysis/CaptureTracking.cpp +++ llvm/trunk/lib/Analysis/CaptureTracking.cpp @@ -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 @@ 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(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 @@ break; } case Instruction::Load: - // Loading from a pointer does not cause it to be captured. + // Volatile loads make the address observable. + if (cast(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. + // Volatile stores make the address observable. + if (V == I->getOperand(0) || cast(I)->isVolatile()) 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)) + 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(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(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: Index: llvm/trunk/test/Transforms/FunctionAttrs/nocapture.ll =================================================================== --- llvm/trunk/test/Transforms/FunctionAttrs/nocapture.ll +++ llvm/trunk/test/Transforms/FunctionAttrs/nocapture.ll @@ -210,3 +210,11 @@ 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 +}