Index: lib/CodeGen/CGDecl.cpp =================================================================== --- lib/CodeGen/CGDecl.cpp +++ lib/CodeGen/CGDecl.cpp @@ -1102,6 +1102,22 @@ address = Address(vla, alignment); } + // Alloca always returns a pointer in alloca address space, which may + // be different from the type defined by the language. For example, + // in C++ the auto variables are in the default address space. Therefore + // cast alloca to the expected address space when necessary. + auto Addr = address.getPointer(); + auto AddrTy = cast(Addr->getType()); + auto ExpectedAddrSpace = CGM.getTypes().getVariableType(D)->getAddressSpace(); + // OpenCL automatic variable in constant address space is emitted in + // alloca address space, which cannot be casted to constant address space. + if (AddrTy->getAddressSpace() != ExpectedAddrSpace && + Ty.getAddressSpace() != LangAS::opencl_constant) { + address = Address(Builder.CreateAddrSpaceCast(Addr, + AddrTy->getElementType()->getPointerTo(ExpectedAddrSpace)), + address.getAlignment()); + } + setAddrOfLocalVar(&D, address); emission.Addr = address; Index: lib/CodeGen/CodeGenTypes.h =================================================================== --- lib/CodeGen/CodeGenTypes.h +++ lib/CodeGen/CodeGenTypes.h @@ -196,6 +196,9 @@ /// memory representation is usually i8 or i32, depending on the target. llvm::Type *ConvertTypeForMem(QualType T); + /// Get the LLVM pointer type of a variable. + llvm::PointerType *getVariableType(VarDecl D); + /// GetFunctionType - Get the LLVM function type for \arg Info. llvm::FunctionType *GetFunctionType(const CGFunctionInfo &Info); Index: lib/CodeGen/CodeGenTypes.cpp =================================================================== --- lib/CodeGen/CodeGenTypes.cpp +++ lib/CodeGen/CodeGenTypes.cpp @@ -92,6 +92,11 @@ (unsigned)Context.getTypeSize(T)); } +llvm::PointerType *CodeGenTypes::getVariableType(VarDecl D) { + auto Ty = D.getType(); + return ConvertTypeForMem(Ty)->getPointerTo( + getContext().getTargetAddressSpace(Ty)); +} /// isRecordLayoutComplete - Return true if the specified type is already /// completely laid out. Index: test/CodeGen/address-space.c =================================================================== --- test/CodeGen/address-space.c +++ test/CodeGen/address-space.c @@ -40,8 +40,10 @@ } MyStruct; // CHECK-LABEL: define void @test4( -// CHECK: call void @llvm.memcpy.p0i8.p2i8 -// CHECK: call void @llvm.memcpy.p2i8.p0i8 +// GIZ: call void @llvm.memcpy.p0i8.p2i8 +// GIZ: call void @llvm.memcpy.p2i8.p0i8 +// PIZ: call void @llvm.memcpy.p4i8.p2i8 +// PIZ: call void @llvm.memcpy.p2i8.p4i8 void test4(MyStruct __attribute__((address_space(2))) *pPtr) { MyStruct s = pPtr[0]; pPtr[0] = s; Index: test/CodeGenCXX/amdgcn-automatic-variable.cpp =================================================================== --- /dev/null +++ test/CodeGenCXX/amdgcn-automatic-variable.cpp @@ -0,0 +1,52 @@ +// RUN: %clang_cc1 -O0 -triple amdgcn---amdgiz -emit-llvm %s -o - | FileCheck %s + +// CHECK-LABEL: define void @_Z5func1Pi(i32* %x) +void func1(int *x) { + // CHECK: %[[x_addr:.*]] = alloca i32*{{.*}}addrspace(5) + // CHECK: store i32* %x, i32* addrspace(5)* %[[x_addr]] + // CHECK: %[[r0:.*]] = load i32*, i32* addrspace(5)* %[[x_addr]] + // CHECK: store i32 1, i32* %[[r0]] + *x = 1; +} + +// CHECK-LABEL: define void @_Z5func2v() +void func2(void) { + // CHECK: %lv1 = alloca i32, align 4, addrspace(5) + // CHECK: %lv2 = alloca i32, align 4, addrspace(5) + // CHECK: %la = alloca [100 x i32], align 4, addrspace(5) + // CHECK: %lp1 = alloca i32*, align 4, addrspace(5) + // CHECK: %lp2 = alloca i32*, align 4, addrspace(5) + // CHECK: %lvc = alloca i32, align 4, addrspace(5) + + // CHECK: %[[r0:.*]] = addrspacecast i32 addrspace(5)* %lv1 to i32* + // CHECK: store i32 1, i32* %[[r0]] + // CHECK: %[[r1:.*]] = addrspacecast i32 addrspace(5)* %lv2 to i32* + // CHECK: store i32 2, i32* %[[r1]] + int lv1; + lv1 = 1; + int lv2 = 2; + + // CHECK: %[[r2:.*]] = addrspacecast [100 x i32] addrspace(5)* %la to [100 x i32]* + // CHECK: %[[arrayidx:.*]] = getelementptr inbounds [100 x i32], [100 x i32]* %[[r2]], i64 0, i64 0 + // CHECK: store i32 3, i32* %[[arrayidx]], align 4 + int la[100]; + la[0] = 3; + + // CHECK: %[[r3:.*]] = addrspacecast i32* addrspace(5)* %lp1 to i32** + // CHECK: store i32* %[[r0]], i32** %[[r3]], align 4 + int *lp1 = &lv1; + + // CHECK: %[[r4:.*]] = addrspacecast i32* addrspace(5)* %lp2 to i32** + // CHECK: %[[arraydecay:.*]] = getelementptr inbounds [100 x i32], [100 x i32]* %[[r2]], i32 0, i32 0 + // CHECK: store i32* %[[arraydecay]], i32** %[[r4]], align 4 + int *lp2 = la; + + // CHECK: call void @_Z5func1Pi(i32* %[[r0]]) + func1(&lv1); + + // CHECK: %[[r5:.*]] = addrspacecast i32 addrspace(5)* %lvc to i32* + // CHECK: store i32 4, i32* %[[r5]] + // CHECK: store i32 4, i32* %[[r0]] + const int lvc = 4; + lv1 = lvc; +}