Index: cfe/trunk/lib/CodeGen/CGCall.cpp =================================================================== --- cfe/trunk/lib/CodeGen/CGCall.cpp +++ cfe/trunk/lib/CodeGen/CGCall.cpp @@ -3812,16 +3812,17 @@ // If the call returns a temporary with struct return, create a temporary // alloca to hold the result, unless one is given to us. Address SRetPtr = Address::invalid(); + Address SRetAlloca = Address::invalid(); llvm::Value *UnusedReturnSizePtr = nullptr; if (RetAI.isIndirect() || RetAI.isInAlloca() || RetAI.isCoerceAndExpand()) { if (!ReturnValue.isNull()) { SRetPtr = ReturnValue.getValue(); } else { - SRetPtr = CreateMemTemp(RetTy); + SRetPtr = CreateMemTemp(RetTy, "tmp", &SRetAlloca); if (HaveInsertPoint() && ReturnValue.isUnused()) { uint64_t size = CGM.getDataLayout().getTypeAllocSize(ConvertTypeForMem(RetTy)); - UnusedReturnSizePtr = EmitLifetimeStart(size, SRetPtr.getPointer()); + UnusedReturnSizePtr = EmitLifetimeStart(size, SRetAlloca.getPointer()); } } if (IRFunctionArgs.hasSRetArg()) { @@ -3888,7 +3889,8 @@ if (!I->isAggregate()) { // Make a temporary alloca to pass the argument. Address Addr = CreateMemTemp(I->Ty, ArgInfo.getIndirectAlign(), - "indirect-arg-temp", false); + "indirect-arg-temp", /*Alloca=*/nullptr, + /*Cast=*/false); IRCallArgs[FirstIRArg] = Addr.getPointer(); I->copyInto(*this, Addr); @@ -3934,7 +3936,8 @@ if (NeedCopy) { // Create an aligned temporary, and copy to it. Address AI = CreateMemTemp(I->Ty, ArgInfo.getIndirectAlign(), - "byval-temp", false); + "byval-temp", /*Alloca=*/nullptr, + /*Cast=*/false); IRCallArgs[FirstIRArg] = AI.getPointer(); I->copyInto(*this, AI); } else { @@ -4062,6 +4065,7 @@ llvm::Value *tempSize = nullptr; Address addr = Address::invalid(); + Address AllocaAddr = Address::invalid(); if (I->isAggregate()) { addr = I->hasLValue() ? I->getKnownLValue().getAddress() : I->getKnownRValue().getAggregateAddress(); @@ -4076,9 +4080,11 @@ // Materialize to a temporary. addr = CreateTempAlloca(RV.getScalarVal()->getType(), - CharUnits::fromQuantity(std::max(layout->getAlignment(), - scalarAlign))); - tempSize = EmitLifetimeStart(scalarSize, addr.getPointer()); + CharUnits::fromQuantity(std::max( + layout->getAlignment(), scalarAlign)), + "tmp", + /*ArraySize=*/nullptr, &AllocaAddr); + tempSize = EmitLifetimeStart(scalarSize, AllocaAddr.getPointer()); Builder.CreateStore(RV.getScalarVal(), addr); } @@ -4096,7 +4102,7 @@ assert(IRArgPos == FirstIRArg + NumIRArgs); if (tempSize) { - EmitLifetimeEnd(tempSize, addr.getPointer()); + EmitLifetimeEnd(tempSize, AllocaAddr.getPointer()); } break; @@ -4258,7 +4264,7 @@ // pop this cleanup later on. Being eager about this is OK, since this // temporary is 'invisible' outside of the callee. if (UnusedReturnSizePtr) - pushFullExprCleanup(NormalEHLifetimeMarker, SRetPtr, + pushFullExprCleanup(NormalEHLifetimeMarker, SRetAlloca, UnusedReturnSizePtr); llvm::BasicBlock *InvokeDest = CannotThrow ? nullptr : getInvokeDest(); Index: cfe/trunk/lib/CodeGen/CGDecl.cpp =================================================================== --- cfe/trunk/lib/CodeGen/CGDecl.cpp +++ cfe/trunk/lib/CodeGen/CGDecl.cpp @@ -965,6 +965,9 @@ if (!ShouldEmitLifetimeMarkers) return nullptr; + assert(Addr->getType()->getPointerAddressSpace() == + CGM.getDataLayout().getAllocaAddrSpace() && + "Pointer should be in alloca address space"); llvm::Value *SizeV = llvm::ConstantInt::get(Int64Ty, Size); Addr = Builder.CreateBitCast(Addr, AllocaInt8PtrTy); llvm::CallInst *C = @@ -974,6 +977,9 @@ } void CodeGenFunction::EmitLifetimeEnd(llvm::Value *Size, llvm::Value *Addr) { + assert(Addr->getType()->getPointerAddressSpace() == + CGM.getDataLayout().getAllocaAddrSpace() && + "Pointer should be in alloca address space"); Addr = Builder.CreateBitCast(Addr, AllocaInt8PtrTy); llvm::CallInst *C = Builder.CreateCall(CGM.getLLVMLifetimeEndFn(), {Size, Addr}); @@ -1058,6 +1064,7 @@ codegenoptions::LimitedDebugInfo; Address address = Address::invalid(); + Address AllocaAddr = Address::invalid(); if (Ty->isConstantSizeType()) { bool NRVO = getLangOpts().ElideConstructors && D.isNRVOVariable(); @@ -1148,7 +1155,8 @@ // Create the alloca. Note that we set the name separately from // building the instruction so that it's there even in no-asserts // builds. - address = CreateTempAlloca(allocaTy, allocaAlignment, D.getName()); + address = CreateTempAlloca(allocaTy, allocaAlignment, D.getName(), + /*ArraySize=*/nullptr, &AllocaAddr); // Don't emit lifetime markers for MSVC catch parameters. The lifetime of // the catch parameter starts in the catchpad instruction, and we can't @@ -1176,7 +1184,7 @@ !(!getLangOpts().CPlusPlus && hasLabelBeenSeenInCurrentScope())) { uint64_t size = CGM.getDataLayout().getTypeAllocSize(allocaTy); emission.SizeForLifetimeMarkers = - EmitLifetimeStart(size, address.getPointer()); + EmitLifetimeStart(size, AllocaAddr.getPointer()); } } else { assert(!emission.useLifetimeMarkers()); @@ -1205,7 +1213,8 @@ llvm::Type *llvmTy = ConvertTypeForMem(VlaSize.Type); // Allocate memory for the array. - address = CreateTempAlloca(llvmTy, alignment, "vla", VlaSize.NumElts); + address = CreateTempAlloca(llvmTy, alignment, "vla", VlaSize.NumElts, + &AllocaAddr); // If we have debug info enabled, properly describe the VLA dimensions for // this type by registering the vla size expression for each of the @@ -1215,6 +1224,7 @@ setAddrOfLocalVar(&D, address); emission.Addr = address; + emission.AllocaAddr = AllocaAddr; // Emit debug info for local var declaration. if (EmitDebugInfo && HaveInsertPoint()) { @@ -1228,7 +1238,7 @@ // Make sure we call @llvm.lifetime.end. if (emission.useLifetimeMarkers()) EHStack.pushCleanup(NormalEHLifetimeMarker, - emission.getAllocatedAddress(), + emission.getOriginalAllocatedAddress(), emission.getSizeForLifetimeMarkers()); return emission; Index: cfe/trunk/lib/CodeGen/CGExpr.cpp =================================================================== --- cfe/trunk/lib/CodeGen/CGExpr.cpp +++ cfe/trunk/lib/CodeGen/CGExpr.cpp @@ -64,9 +64,12 @@ Address CodeGenFunction::CreateTempAlloca(llvm::Type *Ty, CharUnits Align, const Twine &Name, llvm::Value *ArraySize, + Address *AllocaAddr, bool CastToDefaultAddrSpace) { auto Alloca = CreateTempAlloca(Ty, Name, ArraySize); Alloca->setAlignment(Align.getQuantity()); + if (AllocaAddr) + *AllocaAddr = Address(Alloca, Align); llvm::Value *V = Alloca; // Alloca always returns a pointer in alloca address space, which may // be different from the type defined by the language. For example, @@ -125,16 +128,18 @@ } Address CodeGenFunction::CreateMemTemp(QualType Ty, const Twine &Name, + Address *Alloca, bool CastToDefaultAddrSpace) { // FIXME: Should we prefer the preferred type alignment here? - return CreateMemTemp(Ty, getContext().getTypeAlignInChars(Ty), Name, + return CreateMemTemp(Ty, getContext().getTypeAlignInChars(Ty), Name, Alloca, CastToDefaultAddrSpace); } Address CodeGenFunction::CreateMemTemp(QualType Ty, CharUnits Align, - const Twine &Name, + const Twine &Name, Address *Alloca, bool CastToDefaultAddrSpace) { - return CreateTempAlloca(ConvertTypeForMem(Ty), Align, Name, nullptr, + return CreateTempAlloca(ConvertTypeForMem(Ty), Align, Name, + /*ArraySize=*/nullptr, Alloca, CastToDefaultAddrSpace); } @@ -348,7 +353,8 @@ static Address createReferenceTemporary(CodeGenFunction &CGF, const MaterializeTemporaryExpr *M, - const Expr *Inner) { + const Expr *Inner, + Address *Alloca = nullptr) { auto &TCG = CGF.getTargetHooks(); switch (M->getStorageDuration()) { case SD_FullExpression: @@ -381,7 +387,7 @@ return Address(C, alignment); } } - return CGF.CreateMemTemp(Ty, "ref.tmp"); + return CGF.CreateMemTemp(Ty, "ref.tmp", Alloca); } case SD_Thread: case SD_Static: @@ -458,7 +464,8 @@ } // Create and initialize the reference temporary. - Address Object = createReferenceTemporary(*this, M, E); + Address Alloca = Address::invalid(); + Address Object = createReferenceTemporary(*this, M, E, &Alloca); if (auto *Var = dyn_cast( Object.getPointer()->stripPointerCasts())) { Object = Address(llvm::ConstantExpr::getBitCast( @@ -477,13 +484,13 @@ case SD_Automatic: case SD_FullExpression: if (auto *Size = EmitLifetimeStart( - CGM.getDataLayout().getTypeAllocSize(Object.getElementType()), - Object.getPointer())) { + CGM.getDataLayout().getTypeAllocSize(Alloca.getElementType()), + Alloca.getPointer())) { if (M->getStorageDuration() == SD_Automatic) pushCleanupAfterFullExpr(NormalEHLifetimeMarker, - Object, Size); + Alloca, Size); else - pushFullExprCleanup(NormalEHLifetimeMarker, Object, + pushFullExprCleanup(NormalEHLifetimeMarker, Alloca, Size); } break; Index: cfe/trunk/lib/CodeGen/CGExprAgg.cpp =================================================================== --- cfe/trunk/lib/CodeGen/CGExprAgg.cpp +++ cfe/trunk/lib/CodeGen/CGExprAgg.cpp @@ -253,6 +253,7 @@ (RequiresDestruction && !Dest.getAddress().isValid()); Address RetAddr = Address::invalid(); + Address RetAllocaAddr = Address::invalid(); EHScopeStack::stable_iterator LifetimeEndBlock; llvm::Value *LifetimeSizePtr = nullptr; @@ -260,10 +261,10 @@ if (!UseTemp) { RetAddr = Dest.getAddress(); } else { - RetAddr = CGF.CreateMemTemp(RetTy); + RetAddr = CGF.CreateMemTemp(RetTy, "tmp", &RetAllocaAddr); uint64_t Size = CGF.CGM.getDataLayout().getTypeAllocSize(CGF.ConvertTypeForMem(RetTy)); - LifetimeSizePtr = CGF.EmitLifetimeStart(Size, RetAddr.getPointer()); + LifetimeSizePtr = CGF.EmitLifetimeStart(Size, RetAllocaAddr.getPointer()); if (LifetimeSizePtr) { LifetimeStartInst = cast(std::prev(Builder.GetInsertPoint())); @@ -272,7 +273,7 @@ "Last insertion wasn't a lifetime.start?"); CGF.pushFullExprCleanup( - NormalEHLifetimeMarker, RetAddr, LifetimeSizePtr); + NormalEHLifetimeMarker, RetAllocaAddr, LifetimeSizePtr); LifetimeEndBlock = CGF.EHStack.stable_begin(); } } @@ -294,7 +295,7 @@ // Since we're not guaranteed to be in an ExprWithCleanups, clean up // eagerly. CGF.DeactivateCleanupBlock(LifetimeEndBlock, LifetimeStartInst); - CGF.EmitLifetimeEnd(LifetimeSizePtr, RetAddr.getPointer()); + CGF.EmitLifetimeEnd(LifetimeSizePtr, RetAllocaAddr.getPointer()); } } Index: cfe/trunk/lib/CodeGen/CodeGenFunction.h =================================================================== --- cfe/trunk/lib/CodeGen/CodeGenFunction.h +++ cfe/trunk/lib/CodeGen/CodeGenFunction.h @@ -2023,11 +2023,14 @@ /// various ways, this function will perform the cast by default. The cast /// may be avoided by passing false as \p CastToDefaultAddrSpace; this is /// more efficient if the caller knows that the address will not be exposed. + /// The original alloca instruction is returned through \p Alloca if it is + /// not nullptr. llvm::AllocaInst *CreateTempAlloca(llvm::Type *Ty, const Twine &Name = "tmp", llvm::Value *ArraySize = nullptr); Address CreateTempAlloca(llvm::Type *Ty, CharUnits align, const Twine &Name = "tmp", llvm::Value *ArraySize = nullptr, + Address *Alloca = nullptr, bool CastToDefaultAddrSpace = true); /// CreateDefaultAlignedTempAlloca - This creates an alloca with the @@ -2064,10 +2067,13 @@ /// CreateMemTemp - Create a temporary memory object of the given type, with /// appropriate alignment. Cast it to the default address space if - /// \p CastToDefaultAddrSpace is true. + /// \p CastToDefaultAddrSpace is true. Returns the original alloca + /// instruction by \p Alloca if it is not nullptr. Address CreateMemTemp(QualType T, const Twine &Name = "tmp", + Address *Alloca = nullptr, bool CastToDefaultAddrSpace = true); Address CreateMemTemp(QualType T, CharUnits Align, const Twine &Name = "tmp", + Address *Alloca = nullptr, bool CastToDefaultAddrSpace = true); /// CreateAggTemp - Create a temporary memory object for the given @@ -2515,7 +2521,9 @@ const VarDecl *Variable; - /// The address of the alloca. Invalid if the variable was emitted + /// The address of the alloca for languages with explicit address space + /// (e.g. OpenCL) or alloca casted to generic pointer for address space + /// agnostic languages (e.g. C++). Invalid if the variable was emitted /// as a global constant. Address Addr; @@ -2531,13 +2539,19 @@ /// Non-null if we should use lifetime annotations. llvm::Value *SizeForLifetimeMarkers; + /// Address with original alloca instruction. Invalid if the variable was + /// emitted as a global constant. + Address AllocaAddr; + struct Invalid {}; - AutoVarEmission(Invalid) : Variable(nullptr), Addr(Address::invalid()) {} + AutoVarEmission(Invalid) + : Variable(nullptr), Addr(Address::invalid()), + AllocaAddr(Address::invalid()) {} AutoVarEmission(const VarDecl &variable) - : Variable(&variable), Addr(Address::invalid()), NRVOFlag(nullptr), - IsByRef(false), IsConstantAggregate(false), - SizeForLifetimeMarkers(nullptr) {} + : Variable(&variable), Addr(Address::invalid()), NRVOFlag(nullptr), + IsByRef(false), IsConstantAggregate(false), + SizeForLifetimeMarkers(nullptr), AllocaAddr(Address::invalid()) {} bool wasEmittedAsGlobal() const { return !Addr.isValid(); } @@ -2553,11 +2567,15 @@ } /// Returns the raw, allocated address, which is not necessarily - /// the address of the object itself. + /// the address of the object itself. It is casted to default + /// address space for address space agnostic languages. Address getAllocatedAddress() const { return Addr; } + /// Returns the address for the original alloca instruction. + Address getOriginalAllocatedAddress() const { return AllocaAddr; } + /// Returns the address of the object within this declaration. /// Note that this does not chase the forwarding pointer for /// __block decls. Index: cfe/trunk/test/CodeGenCXX/amdgcn_declspec_get.cpp =================================================================== --- cfe/trunk/test/CodeGenCXX/amdgcn_declspec_get.cpp +++ cfe/trunk/test/CodeGenCXX/amdgcn_declspec_get.cpp @@ -0,0 +1,27 @@ +// RUN: %clang_cc1 -triple amdgcn-amd-amdhsa -emit-llvm -O3 -fdeclspec \ +// RUN: -disable-llvm-passes -o - %s | FileCheck %s + +int get_x(); + +struct A { + __declspec(property(get = _get_x)) int x; + static int _get_x(void) { + return get_x(); + }; +}; + +extern const A a; + +// CHECK-LABEL: define void @_Z4testv() +// CHECK: %i = alloca i32, align 4, addrspace(5) +// CHECK: %[[ii:.*]] = addrspacecast i32 addrspace(5)* %i to i32* +// CHECK: %[[cast:.*]] = bitcast i32 addrspace(5)* %i to i8 addrspace(5)* +// CHECK: call void @llvm.lifetime.start.p5i8(i64 4, i8 addrspace(5)* %[[cast]]) +// CHECK: %call = call i32 @_ZN1A6_get_xEv() +// CHECK: store i32 %call, i32* %[[ii]] +// CHECK: %[[cast2:.*]] = bitcast i32 addrspace(5)* %i to i8 addrspace(5)* +// CHECK: call void @llvm.lifetime.end.p5i8(i64 4, i8 addrspace(5)* %[[cast2]]) +void test() +{ + int i = a.x; +}