diff --git a/clang/lib/CodeGen/ItaniumCXXABI.cpp b/clang/lib/CodeGen/ItaniumCXXABI.cpp --- a/clang/lib/CodeGen/ItaniumCXXABI.cpp +++ b/clang/lib/CodeGen/ItaniumCXXABI.cpp @@ -1587,12 +1587,14 @@ // All parameters are already in place except VTT, which goes after 'this'. // These are Clang types, so we don't need to worry about sret yet. - // Check if we need to add a VTT parameter (which has type void **). + // Check if we need to add a VTT parameter (which has type global void **). if ((isa(GD.getDecl()) ? GD.getCtorType() == Ctor_Base : GD.getDtorType() == Dtor_Base) && cast(GD.getDecl())->getParent()->getNumVBases() != 0) { + LangAS AS = CGM.GetGlobalVarAddressSpace(nullptr); + QualType Q = Context.getAddrSpaceQualType(Context.VoidPtrTy, AS); ArgTys.insert(ArgTys.begin() + 1, - Context.getPointerType(Context.VoidPtrTy)); + Context.getPointerType(CanQualType::CreateUnsafe(Q))); return AddedStructorArgCounts::prefix(1); } return AddedStructorArgCounts{}; @@ -1625,7 +1627,9 @@ ASTContext &Context = getContext(); // FIXME: avoid the fake decl - QualType T = Context.getPointerType(Context.VoidPtrTy); + LangAS AS = CGM.GetGlobalVarAddressSpace(nullptr); + QualType Q = Context.getAddrSpaceQualType(Context.VoidPtrTy, AS); + QualType T = Context.getPointerType(Q); auto *VTTDecl = ImplicitParamDecl::Create( Context, /*DC=*/nullptr, MD->getLocation(), &Context.Idents.get("vtt"), T, ImplicitParamDecl::CXXVTT); @@ -1667,10 +1671,14 @@ if (!NeedsVTTParameter(GlobalDecl(D, Type))) return AddedStructorArgs{}; - // Insert the implicit 'vtt' argument as the second argument. + // Insert the implicit 'vtt' argument as the second argument. Make sure to + // correctly reflect its address space, which can differ from generic on + // some targets. llvm::Value *VTT = CGF.GetVTTParameter(GlobalDecl(D, Type), ForVirtualBase, Delegating); - QualType VTTTy = getContext().getPointerType(getContext().VoidPtrTy); + LangAS AS = CGM.GetGlobalVarAddressSpace(nullptr); + QualType Q = getContext().getAddrSpaceQualType(getContext().VoidPtrTy, AS); + QualType VTTTy = getContext().getPointerType(Q); return AddedStructorArgs::prefix({{VTT, VTTTy}}); } diff --git a/clang/test/CodeGenCXX/vtt-address-space.cpp b/clang/test/CodeGenCXX/vtt-address-space.cpp new file mode 100644 --- /dev/null +++ b/clang/test/CodeGenCXX/vtt-address-space.cpp @@ -0,0 +1,30 @@ +// RUN: %clang_cc1 %s -triple=amdgcn-amd-amdhsa -std=c++11 -emit-llvm -o - | FileCheck %s +// This is temporarily disabled as it requires fixing typeinfo & vptr handling +// as well; it will be enabled once those fixes are in. +// XFAIL: * + +// This is the sample from the C++ Itanium ABI, p2.6.2. +namespace Test { + class A1 { int i; }; + class A2 { int i; virtual void f(); }; + class V1 : public A1, public A2 { int i; }; + class B1 { int i; }; + class B2 { int i; }; + class V2 : public B1, public B2, public virtual V1 { int i; }; + class V3 { virtual void g(); }; + class C1 : public virtual V1 { int i; }; + class C2 : public virtual V3, virtual V2 { int i; }; + class X1 { int i; }; + class C3 : public X1 { int i; }; + class D : public C1, public C2, public C3 { int i; }; + + D d; +} + +// CHECK: @_ZTTN4Test1DE = linkonce_odr unnamed_addr addrspace(1) constant [13 x ptr] [ptr addrspacecast (ptr addrspace(1) getelementptr inbounds ({ [5 x ptr], [7 x ptr], [4 x ptr], [3 x ptr] }, ptr addrspace(1) @_ZTVN4Test1DE, i32 0, inrange i32 0, i32 5) to ptr), ptr addrspacecast (ptr addrspace(1) getelementptr inbounds ({ [3 x ptr], [4 x ptr] }, ptr addrspace(1) @_ZTCN4Test1DE0_NS_2C1E, i32 0, inrange i32 0, i32 3) to ptr), ptr addrspacecast (ptr addrspace(1) getelementptr inbounds ({ [3 x ptr], [4 x ptr] }, ptr addrspace(1) @_ZTCN4Test1DE0_NS_2C1E, i32 0, inrange i32 1, i32 3) to ptr), ptr addrspacecast (ptr addrspace(1) getelementptr inbounds ({ [7 x ptr], [3 x ptr], [4 x ptr] }, ptr addrspace(1) @_ZTCN4Test1DE16_NS_2C2E, i32 0, inrange i32 0, i32 6) to ptr), ptr addrspacecast (ptr addrspace(1) getelementptr inbounds ({ [7 x ptr], [3 x ptr], [4 x ptr] }, ptr addrspace(1) @_ZTCN4Test1DE16_NS_2C2E, i32 0, inrange i32 0, i32 6) to ptr), ptr addrspacecast (ptr addrspace(1) getelementptr inbounds ({ [7 x ptr], [3 x ptr], [4 x ptr] }, ptr addrspace(1) @_ZTCN4Test1DE16_NS_2C2E, i32 0, inrange i32 1, i32 3) to ptr), ptr addrspacecast (ptr addrspace(1) getelementptr inbounds ({ [7 x ptr], [3 x ptr], [4 x ptr] }, ptr addrspace(1) @_ZTCN4Test1DE16_NS_2C2E, i32 0, inrange i32 2, i32 3) to ptr), ptr addrspacecast (ptr addrspace(1) getelementptr inbounds ({ [5 x ptr], [7 x ptr], [4 x ptr], [3 x ptr] }, ptr addrspace(1) @_ZTVN4Test1DE, i32 0, inrange i32 2, i32 3) to ptr), ptr addrspacecast (ptr addrspace(1) getelementptr inbounds ({ [5 x ptr], [7 x ptr], [4 x ptr], [3 x ptr] }, ptr addrspace(1) @_ZTVN4Test1DE, i32 0, inrange i32 1, i32 6) to ptr), ptr addrspacecast (ptr addrspace(1) getelementptr inbounds ({ [5 x ptr], [7 x ptr], [4 x ptr], [3 x ptr] }, ptr addrspace(1) @_ZTVN4Test1DE, i32 0, inrange i32 1, i32 6) to ptr), ptr addrspacecast (ptr addrspace(1) getelementptr inbounds ({ [5 x ptr], [7 x ptr], [4 x ptr], [3 x ptr] }, ptr addrspace(1) @_ZTVN4Test1DE, i32 0, inrange i32 3, i32 3) to ptr), ptr addrspacecast (ptr addrspace(1) getelementptr inbounds ({ [3 x ptr], [4 x ptr] }, ptr addrspace(1) @_ZTCN4Test1DE64_NS_2V2E, i32 0, inrange i32 0, i32 3) to ptr), ptr addrspacecast (ptr addrspace(1) getelementptr inbounds ({ [3 x ptr], [4 x ptr] }, ptr addrspace(1) @_ZTCN4Test1DE64_NS_2V2E, i32 0, inrange i32 1, i32 3) to ptr)], comdat, align 8 +// CHECK: call void @_ZN4Test2V2C2Ev(ptr noundef nonnull align 8 dereferenceable(20) %2, ptr addrspace(1) noundef getelementptr inbounds ([13 x ptr], ptr addrspace(1) @_ZTTN4Test1DE, i64 0, i64 11)) +// CHECK: call void @_ZN4Test2C1C2Ev(ptr noundef nonnull align 8 dereferenceable(12) %this1, ptr addrspace(1) noundef getelementptr inbounds ([13 x ptr], ptr addrspace(1) @_ZTTN4Test1DE, i64 0, i64 1)) +// CHECK: call void @_ZN4Test2C2C2Ev(ptr noundef nonnull align 8 dereferenceable(12) %3, ptr addrspace(1) noundef getelementptr inbounds ([13 x ptr], ptr addrspace(1) @_ZTTN4Test1DE, i64 0, i64 3)) +// CHECK-NEXT: define linkonce_odr void @_ZN4Test2V2C2Ev(ptr noundef nonnull align 8 dereferenceable(20) %this, ptr addrspace(1) noundef %vtt) +// CHECK-NEXT: define linkonce_odr void @_ZN4Test2C1C2Ev(ptr noundef nonnull align 8 dereferenceable(12) %this, ptr addrspace(1) noundef %vtt) +// CHECK-NEXT: define linkonce_odr void @_ZN4Test2C2C2Ev(ptr noundef nonnull align 8 dereferenceable(12) %this, ptr addrspace(1) noundef %vtt)