From 8a0c382025096002aecab8597694eaf516da8387 Mon Sep 17 00:00:00 2001 From: Mike Rice Date: Tue, 20 Feb 2024 16:54:43 -0800 Subject: [PATCH] Revert "[sycl-web] Fit LIT tests failures in CodeGenSYCL. (#10820)" This reverts commit 66c18fee337fdf04f04f48e0fefb68157915b8a8. This relands the upstream code from 8acdcf4016876d122733991561be706b64026e73. --- clang/lib/CodeGen/CGVTT.cpp | 13 +- clang/lib/CodeGen/CGVTables.cpp | 32 +- clang/lib/CodeGen/CodeGenModule.cpp | 2 +- clang/lib/CodeGen/ItaniumCXXABI.cpp | 34 +-- .../CodeGenCXX/dynamic-cast-address-space.cpp | 2 - .../CodeGenCXX/vtable-align-address-space.cpp | 13 + .../vtable-assume-load-address-space.cpp | 288 ++++++++++++++++++ .../vtable-consteval-address-space.cpp | 44 +++ .../vtable-constexpr-address-space.cpp | 27 ++ .../vtable-key-function-address-space.cpp | 33 ++ .../vtable-layout-extreme-address-space.cpp | 210 +++++++++++++ .../vtable-linkage-address-space.cpp | 217 +++++++++++++ ...e-pointer-initialization-address-space.cpp | 60 ++++ clang/test/CodeGenCXX/vtt-address-space.cpp | 17 +- .../CodeGenCXX/vtt-layout-address-space.cpp | 89 ++++++ clang/test/Headers/hip-header.hip | 21 +- 16 files changed, 1051 insertions(+), 51 deletions(-) create mode 100644 clang/test/CodeGenCXX/vtable-align-address-space.cpp create mode 100644 clang/test/CodeGenCXX/vtable-assume-load-address-space.cpp create mode 100644 clang/test/CodeGenCXX/vtable-consteval-address-space.cpp create mode 100644 clang/test/CodeGenCXX/vtable-constexpr-address-space.cpp create mode 100644 clang/test/CodeGenCXX/vtable-key-function-address-space.cpp create mode 100644 clang/test/CodeGenCXX/vtable-layout-extreme-address-space.cpp create mode 100644 clang/test/CodeGenCXX/vtable-linkage-address-space.cpp create mode 100644 clang/test/CodeGenCXX/vtable-pointer-initialization-address-space.cpp create mode 100644 clang/test/CodeGenCXX/vtt-layout-address-space.cpp diff --git a/clang/lib/CodeGen/CGVTT.cpp b/clang/lib/CodeGen/CGVTT.cpp index bceeb3aab0f3d..1d3f14f1c5344 100644 --- a/clang/lib/CodeGen/CGVTT.cpp +++ b/clang/lib/CodeGen/CGVTT.cpp @@ -42,8 +42,8 @@ CodeGenVTables::EmitVTTDefinition(llvm::GlobalVariable *VTT, llvm::GlobalVariable::LinkageTypes Linkage, const CXXRecordDecl *RD) { VTTBuilder Builder(CGM.getContext(), RD, /*GenerateDefinition=*/true); - llvm::ArrayType *ArrayType = - llvm::ArrayType::get(CGM.DefaultInt8PtrTy, Builder.getVTTComponents().size()); + llvm::ArrayType *ArrayType = llvm::ArrayType::get( + CGM.GlobalsInt8PtrTy, Builder.getVTTComponents().size()); SmallVector VTables; SmallVector VTableAddressPoints; @@ -81,9 +81,6 @@ CodeGenVTables::EmitVTTDefinition(llvm::GlobalVariable *VTT, VTable->getValueType(), VTable, Idxs, /*InBounds=*/true, /*InRangeIndex=*/1); - Init = llvm::ConstantExpr::getPointerBitCastOrAddrSpaceCast( - Init, CGM.Int8PtrTy); - VTTComponents.push_back(Init); } @@ -117,9 +114,9 @@ llvm::GlobalVariable *CodeGenVTables::GetAddrOfVTT(const CXXRecordDecl *RD) { VTTBuilder Builder(CGM.getContext(), RD, /*GenerateDefinition=*/false); - llvm::ArrayType *ArrayType = - llvm::ArrayType::get(CGM.Int8PtrTy, Builder.getVTTComponents().size()); - llvm::Align Align = CGM.getDataLayout().getABITypeAlign(CGM.Int8PtrTy); + llvm::ArrayType *ArrayType = llvm::ArrayType::get( + CGM.GlobalsInt8PtrTy, Builder.getVTTComponents().size()); + llvm::Align Align = CGM.getDataLayout().getABITypeAlign(CGM.GlobalsInt8PtrTy); llvm::GlobalVariable *GV = CGM.CreateOrReplaceCXXRuntimeVariable( Name, ArrayType, llvm::GlobalValue::ExternalLinkage, Align); diff --git a/clang/lib/CodeGen/CGVTables.cpp b/clang/lib/CodeGen/CGVTables.cpp index 913c24bc7e859..8dee3f74b44b4 100644 --- a/clang/lib/CodeGen/CGVTables.cpp +++ b/clang/lib/CodeGen/CGVTables.cpp @@ -692,7 +692,7 @@ bool CodeGenVTables::useRelativeLayout() const { llvm::Type *CodeGenModule::getVTableComponentType() const { if (UseRelativeLayout(*this)) return Int32Ty; - return Int8PtrTy; + return GlobalsInt8PtrTy; } llvm::Type *CodeGenVTables::getVTableComponentType() const { @@ -704,7 +704,7 @@ static void AddPointerLayoutOffset(const CodeGenModule &CGM, CharUnits offset) { builder.add(llvm::ConstantExpr::getIntToPtr( llvm::ConstantInt::get(CGM.PtrDiffTy, offset.getQuantity()), - CGM.Int8PtrTy)); + CGM.GlobalsInt8PtrTy)); } static void AddRelativeLayoutOffset(const CodeGenModule &CGM, @@ -741,7 +741,7 @@ void CodeGenVTables::addVTableComponent(ConstantArrayBuilder &builder, vtableHasLocalLinkage, /*isCompleteDtor=*/false); else - return builder.add(llvm::ConstantExpr::getBitCast(rtti, CGM.Int8PtrTy)); + return builder.add(rtti); case VTableComponent::CK_FunctionPointer: case VTableComponent::CK_CompleteDtorPointer: @@ -760,7 +760,8 @@ void CodeGenVTables::addVTableComponent(ConstantArrayBuilder &builder, ? MD->hasAttr() : (MD->hasAttr() || !MD->hasAttr()); if (!CanEmitMethod) - return builder.add(llvm::ConstantExpr::getNullValue(CGM.Int8PtrTy)); + return builder.add( + llvm::ConstantExpr::getNullValue(CGM.GlobalsInt8PtrTy)); // Method is acceptable, continue processing as usual. } @@ -773,20 +774,20 @@ void CodeGenVTables::addVTableComponent(ConstantArrayBuilder &builder, // with the local symbol. As a temporary solution, fill these components // with zero. We shouldn't be calling these in the first place anyway. if (useRelativeLayout()) - return llvm::ConstantPointerNull::get(CGM.Int8PtrTy); + return llvm::ConstantPointerNull::get(CGM.GlobalsInt8PtrTy); // For NVPTX devices in OpenMP emit special functon as null pointers, // otherwise linking ends up with unresolved references. if (CGM.getLangOpts().OpenMP && CGM.getLangOpts().OpenMPIsTargetDevice && CGM.getTriple().isNVPTX()) - return llvm::ConstantPointerNull::get(CGM.Int8PtrTy); + return llvm::ConstantPointerNull::get(CGM.GlobalsInt8PtrTy); llvm::FunctionType *fnTy = llvm::FunctionType::get(CGM.VoidTy, /*isVarArg=*/false); llvm::Constant *fn = cast( CGM.CreateRuntimeFunction(fnTy, name).getCallee()); if (auto f = dyn_cast(fn)) f->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global); - return llvm::ConstantExpr::getBitCast(fn, CGM.Int8PtrTy); + return fn; }; llvm::Constant *fnPtr; @@ -824,15 +825,26 @@ void CodeGenVTables::addVTableComponent(ConstantArrayBuilder &builder, return addRelativeComponent( builder, fnPtr, vtableAddressPoint, vtableHasLocalLinkage, component.getKind() == VTableComponent::CK_CompleteDtorPointer); - } else - return builder.add(llvm::ConstantExpr::getBitCast(fnPtr, CGM.Int8PtrTy)); + } else { + // TODO: this icky and only exists due to functions being in the generic + // address space, rather than the global one, even though they are + // globals; fixing said issue might be intrusive, and will be done + // later. + unsigned FnAS = fnPtr->getType()->getPointerAddressSpace(); + unsigned GVAS = CGM.GlobalsInt8PtrTy->getPointerAddressSpace(); + + if (FnAS != GVAS) + fnPtr = + llvm::ConstantExpr::getAddrSpaceCast(fnPtr, CGM.GlobalsInt8PtrTy); + return builder.add(fnPtr); + } } case VTableComponent::CK_UnusedFunctionPointer: if (useRelativeLayout()) return builder.add(llvm::ConstantExpr::getNullValue(CGM.Int32Ty)); else - return builder.addNullPointer(CGM.Int8PtrTy); + return builder.addNullPointer(CGM.GlobalsInt8PtrTy); } llvm_unreachable("Unexpected vtable component kind"); diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index 133b39bc8fc46..1c5b7149dbf51 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -7982,7 +7982,7 @@ llvm::Constant *CodeGenModule::GetAddrOfRTTIDescriptor(QualType Ty, // FIXME: should we even be calling this method if RTTI is disabled // and it's not for EH? if (!shouldEmitRTTI(ForEH)) - return llvm::Constant::getNullValue(Int8PtrTy); + return llvm::Constant::getNullValue(GlobalsInt8PtrTy); if (ForEH && Ty->isObjCObjectPointerType() && LangOpts.ObjCRuntime.isGNUFamily()) diff --git a/clang/lib/CodeGen/ItaniumCXXABI.cpp b/clang/lib/CodeGen/ItaniumCXXABI.cpp index bc197762278ed..ef18a057f2a73 100644 --- a/clang/lib/CodeGen/ItaniumCXXABI.cpp +++ b/clang/lib/CodeGen/ItaniumCXXABI.cpp @@ -670,7 +670,7 @@ CGCallee ItaniumCXXABI::EmitLoadOfMemberFunctionPointer( CGF.EmitBlock(FnVirtual); // Cast the adjusted this to a pointer to vtable pointer and load. - llvm::Type *VTableTy = Builder.getInt8PtrTy(); + llvm::Type *VTableTy = CGF.CGM.GlobalsInt8PtrTy; CharUnits VTablePtrAlign = CGF.CGM.getDynamicOffsetAlignment(ThisAddr.getAlignment(), RD, CGF.getPointerAlign()); @@ -1942,11 +1942,11 @@ llvm::Value *ItaniumCXXABI::getVTableAddressPointInStructorWithVTT( /// Load the VTT. llvm::Value *VTT = CGF.LoadCXXVTT(); if (VirtualPointerIndex) - VTT = CGF.Builder.CreateConstInBoundsGEP1_64( - CGF.VoidPtrTy, VTT, VirtualPointerIndex); + VTT = CGF.Builder.CreateConstInBoundsGEP1_64(CGF.GlobalsVoidPtrTy, VTT, + VirtualPointerIndex); // And load the address point from the VTT. - return CGF.Builder.CreateAlignedLoad(CGF.VoidPtrTy, VTT, + return CGF.Builder.CreateAlignedLoad(CGF.GlobalsVoidPtrTy, VTT, CGF.getPointerAlign()); } @@ -1974,12 +1974,13 @@ llvm::GlobalVariable *ItaniumCXXABI::getAddrOfVTable(const CXXRecordDecl *RD, CGM.getItaniumVTableContext().getVTableLayout(RD); llvm::Type *VTableType = CGM.getVTables().getVTableType(VTLayout); - // Use pointer alignment for the vtable. Otherwise we would align them based - // on the size of the initializer which doesn't make sense as only single - // values are read. + // Use pointer to global alignment for the vtable. Otherwise we would align + // them based on the size of the initializer which doesn't make sense as only + // single values are read. + LangAS AS = CGM.GetGlobalVarAddressSpace(nullptr); unsigned PAlign = CGM.getItaniumVTableContext().isRelativeLayout() ? 32 - : CGM.getTarget().getPointerAlign(LangAS::Default); + : CGM.getTarget().getPointerAlign(AS); VTable = CGM.CreateOrReplaceCXXRuntimeVariable( Name, VTableType, llvm::GlobalValue::ExternalLinkage, @@ -3281,10 +3282,9 @@ ItaniumRTTIBuilder::GetAddrOfExternalRTTIDescriptor(QualType Ty) { // Note for the future: If we would ever like to do deferred emission of // RTTI, check if emitting vtables opportunistically need any adjustment. - GV = new llvm::GlobalVariable(CGM.getModule(), CGM.Int8PtrTy, - /*isConstant=*/true, - llvm::GlobalValue::ExternalLinkage, nullptr, - Name); + GV = new llvm::GlobalVariable( + CGM.getModule(), CGM.GlobalsInt8PtrTy, + /*isConstant=*/true, llvm::GlobalValue::ExternalLinkage, nullptr, Name); const CXXRecordDecl *RD = Ty->getAsCXXRecordDecl(); CGM.setGVProperties(GV, RD); // Import the typeinfo symbol when all non-inline virtual methods are @@ -3680,8 +3680,8 @@ void ItaniumRTTIBuilder::BuildVTablePointer(const Type *Ty) { if (CGM.getItaniumVTableContext().isRelativeLayout()) VTable = CGM.getModule().getNamedAlias(VTableName); if (!VTable) { - llvm::Type *Ty = llvm::ArrayType::get(CGM.DefaultInt8PtrTy, 0); - VTable = CGM.CreateRuntimeVariable(Ty, VTableName); + llvm::Type *Ty = llvm::ArrayType::get(CGM.GlobalsInt8PtrTy, 0); + VTable = CGM.getModule().getOrInsertGlobal(VTableName, Ty); } CGM.setDSOLocal(cast(VTable->stripPointerCasts())); @@ -3698,7 +3698,7 @@ void ItaniumRTTIBuilder::BuildVTablePointer(const Type *Ty) { llvm::ConstantExpr::getInBoundsGetElementPtr(CGM.Int8Ty, VTable, Eight); } else { llvm::Constant *Two = llvm::ConstantInt::get(PtrDiffTy, 2); - VTable = llvm::ConstantExpr::getInBoundsGetElementPtr(CGM.DefaultInt8PtrTy, + VTable = llvm::ConstantExpr::getInBoundsGetElementPtr(CGM.GlobalsInt8PtrTy, VTable, Two); } @@ -3835,7 +3835,7 @@ llvm::Constant *ItaniumRTTIBuilder::BuildTypeInfo( llvm::ConstantInt::get(CGM.Int64Ty, ((uint64_t)1) << 63); TypeNameField = llvm::ConstantExpr::getAdd(TypeNameField, flag); TypeNameField = - llvm::ConstantExpr::getIntToPtr(TypeNameField, CGM.Int8PtrTy); + llvm::ConstantExpr::getIntToPtr(TypeNameField, CGM.GlobalsInt8PtrTy); } else { TypeNameField = TypeName; } @@ -3965,7 +3965,7 @@ llvm::Constant *ItaniumRTTIBuilder::BuildTypeInfo( GV->setComdat(M.getOrInsertComdat(GV->getName())); CharUnits Align = CGM.getContext().toCharUnitsFromBits( - CGM.getTarget().getPointerAlign(LangAS::Default)); + CGM.getTarget().getPointerAlign(CGM.GetGlobalVarAddressSpace(nullptr))); GV->setAlignment(Align.getAsAlign()); // The Itanium ABI specifies that type_info objects must be globally diff --git a/clang/test/CodeGenCXX/dynamic-cast-address-space.cpp b/clang/test/CodeGenCXX/dynamic-cast-address-space.cpp index e891566df8117..83a408984b760 100644 --- a/clang/test/CodeGenCXX/dynamic-cast-address-space.cpp +++ b/clang/test/CodeGenCXX/dynamic-cast-address-space.cpp @@ -1,5 +1,3 @@ -// XFAIL: * -// // RUN: %clang_cc1 -I%S %s -triple amdgcn-amd-amdhsa -emit-llvm -fcxx-exceptions -fexceptions -o - | FileCheck %s struct A { virtual void f(); }; struct B : A { }; diff --git a/clang/test/CodeGenCXX/vtable-align-address-space.cpp b/clang/test/CodeGenCXX/vtable-align-address-space.cpp new file mode 100644 index 0000000000000..5eac0bd75dc5e --- /dev/null +++ b/clang/test/CodeGenCXX/vtable-align-address-space.cpp @@ -0,0 +1,13 @@ +// RUN: %clang_cc1 %s -triple=amdgcn-amd-amdhsa -std=c++11 -emit-llvm -o - | FileCheck %s + +struct A { + virtual void f(); + virtual void g(); + virtual void h(); +}; + +void A::f() {} + +// CHECK: @_ZTV1A ={{.*}} unnamed_addr addrspace(1) constant { [5 x ptr addrspace(1)] } { [5 x ptr addrspace(1)] [ptr addrspace(1) null, ptr addrspace(1) @_ZTI1A, ptr addrspace(1) addrspacecast (ptr @_ZN1A1fEv to ptr addrspace(1)), ptr addrspace(1) addrspacecast (ptr @_ZN1A1gEv to ptr addrspace(1)), ptr addrspace(1) addrspacecast (ptr @_ZN1A1hEv to ptr addrspace(1))] +// CHECK: @_ZTS1A ={{.*}} constant [3 x i8] c"1A\00", align 1 +// CHECK: @_ZTI1A ={{.*}} addrspace(1) constant { ptr addrspace(1), ptr addrspace(1) } { ptr addrspace(1) getelementptr inbounds (ptr addrspace(1), ptr addrspace(1) @_ZTVN10__cxxabiv117__class_type_infoE, i64 2), ptr addrspace(1) @_ZTS1A }, align 8 diff --git a/clang/test/CodeGenCXX/vtable-assume-load-address-space.cpp b/clang/test/CodeGenCXX/vtable-assume-load-address-space.cpp new file mode 100644 index 0000000000000..251d12bbb62f3 --- /dev/null +++ b/clang/test/CodeGenCXX/vtable-assume-load-address-space.cpp @@ -0,0 +1,288 @@ +// RUN: %clang_cc1 %s -triple=amdgcn-amd-amdhsa -std=c++11 -emit-llvm -o %t.ll -O1 -disable-llvm-passes -fms-extensions -fstrict-vtable-pointers +// FIXME: Assume load should not require -fstrict-vtable-pointers + +// RUN: FileCheck --check-prefix=CHECK1 --input-file=%t.ll %s +// RUN: FileCheck --check-prefix=CHECK2 --input-file=%t.ll %s +// RUN: FileCheck --check-prefix=CHECK3 --input-file=%t.ll %s +// RUN: FileCheck --check-prefix=CHECK4 --input-file=%t.ll %s +// RUN: FileCheck --check-prefix=CHECK5 --input-file=%t.ll %s +// RUN: FileCheck --check-prefix=CHECK6 --input-file=%t.ll %s +// RUN: FileCheck --check-prefix=CHECK7 --input-file=%t.ll %s +// RUN: FileCheck --check-prefix=CHECK8 --input-file=%t.ll %s +namespace test1 { + +struct A { + A(); + virtual void foo(); +}; + +struct B : A { + virtual void foo(); +}; + +void g(A *a) { a->foo(); } + +// CHECK1-LABEL: define{{.*}} void @_ZN5test14fooAEv() +// CHECK1: call void @_ZN5test11AC1Ev(ptr +// CHECK1: %[[VTABLE:.*]] = load ptr addrspace(1), ptr %{{.*}} +// CHECK1: %[[CMP:.*]] = icmp eq ptr addrspace(1) %[[VTABLE]], getelementptr inbounds ({ [3 x ptr addrspace(1)] }, ptr addrspace(1) @_ZTVN5test11AE, i32 0, inrange i32 0, i32 2) +// CHECK1: call void @llvm.assume(i1 %[[CMP]]) +// CHECK1-LABEL: {{^}}} + +void fooA() { + A a; + g(&a); +} + +// CHECK1-LABEL: define{{.*}} void @_ZN5test14fooBEv() +// CHECK1: call void @_ZN5test11BC1Ev(ptr {{[^,]*}} %{{.*}}) +// CHECK1: %[[VTABLE:.*]] = load ptr addrspace(1), ptr %{{.*}} +// CHECK1: %[[CMP:.*]] = icmp eq ptr addrspace(1) %[[VTABLE]], getelementptr inbounds ({ [3 x ptr addrspace(1)] }, ptr addrspace(1) @_ZTVN5test11BE, i32 0, inrange i32 0, i32 2) +// CHECK1: call void @llvm.assume(i1 %[[CMP]]) +// CHECK1-LABEL: {{^}}} + +void fooB() { + B b; + g(&b); +} +// there should not be any assumes in the ctor that calls base ctor +// CHECK1-LABEL: define linkonce_odr void @_ZN5test11BC2Ev(ptr +// CHECK1-NOT: @llvm.assume( +// CHECK1-LABEL: {{^}}} +} +namespace test2 { +struct A { + A(); + virtual void foo(); +}; + +struct B { + B(); + virtual void bar(); +}; + +struct C : A, B { + C(); + virtual void foo(); +}; +void g(A *a) { a->foo(); } +void h(B *b) { b->bar(); } + +// CHECK2-LABEL: define{{.*}} void @_ZN5test24testEv() +// CHECK2: call void @_ZN5test21CC1Ev(ptr +// CHECK2: %[[VTABLE:.*]] = load ptr addrspace(1), ptr {{.*}} +// CHECK2: %[[CMP:.*]] = icmp eq ptr addrspace(1) %[[VTABLE]], getelementptr inbounds ({ [3 x ptr addrspace(1)], [3 x ptr addrspace(1)] }, ptr addrspace(1) @_ZTVN5test21CE, i32 0, inrange i32 0, i32 2) +// CHECK2: call void @llvm.assume(i1 %[[CMP]]) + +// CHECK2: %[[ADD_PTR:.*]] = getelementptr inbounds i8, ptr %{{.*}}, i64 8 +// CHECK2: %[[VTABLE2:.*]] = load ptr addrspace(1), ptr %[[ADD_PTR]] +// CHECK2: %[[CMP2:.*]] = icmp eq ptr addrspace(1) %[[VTABLE2]], getelementptr inbounds ({ [3 x ptr addrspace(1)], [3 x ptr addrspace(1)] }, ptr addrspace(1) @_ZTVN5test21CE, i32 0, inrange i32 1, i32 2) +// CHECK2: call void @llvm.assume(i1 %[[CMP2]]) + +// CHECK2: call void @_ZN5test21gEPNS_1AE( +// CHECK2-LABEL: {{^}}} + +void test() { + C c; + g(&c); + h(&c); +} +} + +namespace test3 { +struct A { + A(); +}; + +struct B : A { + B(); + virtual void foo(); +}; + +struct C : virtual A, B { + C(); + virtual void foo(); +}; +void g(B *a) { a->foo(); } + +// CHECK3-LABEL: define{{.*}} void @_ZN5test34testEv() +// CHECK3: call void @_ZN5test31CC1Ev(ptr +// CHECK3: %[[CMP:.*]] = icmp eq ptr addrspace(1) %{{.*}}, getelementptr inbounds ({ [4 x ptr addrspace(1)] }, ptr addrspace(1) @_ZTVN5test31CE, i32 0, inrange i32 0, i32 3) +// CHECK3: call void @llvm.assume(i1 %[[CMP]]) +// CHECK3-LABLEL: } +void test() { + C c; + g(&c); +} +} // test3 + +namespace test4 { +struct A { + A(); + virtual void foo(); +}; + +struct B : virtual A { + B(); + virtual void foo(); +}; +struct C : B { + C(); + virtual void foo(); +}; + +void g(C *c) { c->foo(); } + +// CHECK4-LABEL: define{{.*}} void @_ZN5test44testEv() +// CHECK4: call void @_ZN5test41CC1Ev(ptr +// CHECK4: %[[VTABLE:.*]] = load ptr addrspace(1), ptr %{{.*}} +// CHECK4: %[[CMP:.*]] = icmp eq ptr addrspace(1) %[[VTABLE]], getelementptr inbounds ({ [5 x ptr addrspace(1)] }, ptr addrspace(1) @_ZTVN5test41CE, i32 0, inrange i32 0, i32 4) +// CHECK4: call void @llvm.assume(i1 %[[CMP]] + +// CHECK4: %[[VTABLE2:.*]] = load ptr addrspace(1), ptr %{{.*}} +// CHECK4: %[[CMP2:.*]] = icmp eq ptr addrspace(1) %[[VTABLE2]], getelementptr inbounds ({ [5 x ptr addrspace(1)] }, ptr addrspace(1) @_ZTVN5test41CE, i32 0, inrange i32 0, i32 4) +// CHECK4: call void @llvm.assume(i1 %[[CMP2]]) +// CHECK4-LABEL: {{^}}} + +void test() { + C c; + g(&c); +} +} // test4 + +namespace test6 { +struct A { + A(); + virtual void foo(); + virtual ~A() {} +}; +struct B : A { + B(); +}; +// FIXME: Because A's vtable is external, and no virtual functions are hidden, +// it's safe to generate assumption loads. +// CHECK5-LABEL: define{{.*}} void @_ZN5test61gEv() +// CHECK5: call void @_ZN5test61AC1Ev( +// CHECK5-NOT: call void @llvm.assume( + +// We can't emit assumption loads for B, because if we would refer to vtable +// it would refer to functions that will not be able to find (like implicit +// inline destructor). + +// CHECK5-LABEL: call void @_ZN5test61BC1Ev( +// CHECK5-NOT: call void @llvm.assume( +// CHECK5-LABEL: {{^}}} +void g() { + A *a = new A; + B *b = new B; +} +} + +namespace test7 { +// Because A's key function is defined here, vtable is generated in this TU +// CHECK6: @_ZTVN5test71AE ={{.*}} unnamed_addr addrspace(1) constant +struct A { + A(); + virtual void foo(); + virtual void bar(); +}; +void A::foo() {} + +// CHECK6-LABEL: define{{.*}} void @_ZN5test71gEv() +// CHECK6: call void @_ZN5test71AC1Ev( +// CHECK6: call void @llvm.assume( +// CHECK6-LABEL: {{^}}} +void g() { + A *a = new A(); + a->bar(); +} +} + +namespace test8 { + +struct A { + virtual void foo(); + virtual void bar(); +}; + +// CHECK7-DAG: @_ZTVN5test81BE = available_externally unnamed_addr addrspace(1) constant +struct B : A { + B(); + void foo(); + void bar(); +}; + +// CHECK7-DAG: @_ZTVN5test81CE = linkonce_odr unnamed_addr addrspace(1) constant +struct C : A { + C(); + void bar(); + void foo() {} +}; +inline void C::bar() {} + +struct D : A { + D(); + void foo(); + void inline bar(); +}; +void D::bar() {} + +// CHECK7-DAG: @_ZTVN5test81EE = linkonce_odr unnamed_addr addrspace(1) constant +struct E : A { + E(); +}; + +// CHECK7-LABEL: define{{.*}} void @_ZN5test81bEv() +// CHECK7: call void @llvm.assume( +// CHECK7-LABEL: {{^}}} +void b() { + B b; + b.bar(); +} + +// FIXME: C has inline virtual functions which prohibits as from generating +// assumption loads, but because vtable is generated in this TU (key function +// defined here) it would be correct to refer to it. +// CHECK7-LABEL: define{{.*}} void @_ZN5test81cEv() +// CHECK7-NOT: call void @llvm.assume( +// CHECK7-LABEL: {{^}}} +void c() { + C c; + c.bar(); +} + +// FIXME: We could generate assumption loads here. +// CHECK7-LABEL: define{{.*}} void @_ZN5test81dEv() +// CHECK7-NOT: call void @llvm.assume( +// CHECK7-LABEL: {{^}}} +void d() { + D d; + d.bar(); +} + +// CHECK7-LABEL: define{{.*}} void @_ZN5test81eEv() +// CHECK7: call void @llvm.assume( +// CHECK7-LABEL: {{^}}} +void e() { + E e; + e.bar(); +} +} + +namespace test9 { + +struct S { + S(); + __attribute__((visibility("hidden"))) virtual void doStuff(); +}; + +// CHECK8-LABEL: define{{.*}} void @_ZN5test94testEv() +// CHECK8-NOT: @llvm.assume( +// CHECK8: } +void test() { + S *s = new S(); + s->doStuff(); + delete s; +} +} + diff --git a/clang/test/CodeGenCXX/vtable-consteval-address-space.cpp b/clang/test/CodeGenCXX/vtable-consteval-address-space.cpp new file mode 100644 index 0000000000000..bf91e8736b43d --- /dev/null +++ b/clang/test/CodeGenCXX/vtable-consteval-address-space.cpp @@ -0,0 +1,44 @@ +// RUN: %clang_cc1 -std=c++20 -triple=amdgcn-amd-amdhsa %s -emit-llvm -o - | FileCheck %s --check-prefix=ITANIUM --implicit-check-not=DoNotEmit + +// FIXME: The MSVC ABI rule in use here was discussed with MS folks prior to +// them implementing virtual consteval functions, but we do not know for sure +// if this is the ABI rule they will use. + +// ITANIUM-DAG: @_ZTV1A = {{.*}} addrspace(1) constant { [2 x ptr addrspace(1)] } {{.*}} null, {{.*}} @_ZTI1A +struct A { + virtual consteval void DoNotEmit_f() {} +}; +// ITANIUM-DAG: @a = addrspace(1) global { {{.*}} ptr addrspace(1) @_ZTV1A, +A a; + +// ITANIUM-DAG: @_ZTV1B = {{.*}} addrspace(1) constant { [4 x ptr addrspace(1)] } {{.*}} addrspace(1) null, ptr addrspace(1) @_ZTI1B, ptr addrspace(1) addrspacecast (ptr @_ZN1B1fEv to ptr addrspace(1)), ptr addrspace(1) addrspacecast (ptr @_ZN1B1hEv to ptr addrspace(1)) +struct B { + virtual void f() {} + virtual consteval void DoNotEmit_g() {} + virtual void h() {} +}; +// ITANIUM-DAG: @b = addrspace(1) global { {{.*}} @_ZTV1B, +B b; + +// ITANIUM-DAG: @_ZTV1C = {{.*}} addrspace(1) constant { [4 x ptr addrspace(1)] } {{.*}} addrspace(1) null, ptr addrspace(1) @_ZTI1C, ptr addrspace(1) addrspacecast (ptr @_ZN1CD1Ev to ptr addrspace(1)), ptr addrspace(1) addrspacecast (ptr @_ZN1CD0Ev to ptr addrspace(1)) +struct C { + virtual ~C() = default; + virtual consteval C &operator=(const C&) = default; +}; +// ITANIUM-DAG: @c = addrspace(1) global { {{.*}} @_ZTV1C, +C c; + +// ITANIUM-DAG: @_ZTV1D = {{.*}} addrspace(1) constant { [4 x ptr addrspace(1)] } {{.*}} addrspace(1) null, ptr addrspace(1) @_ZTI1D, ptr addrspace(1) addrspacecast (ptr @_ZN1DD1Ev to ptr addrspace(1)), ptr addrspace(1) addrspacecast (ptr @_ZN1DD0Ev to ptr addrspace(1)) +struct D : C {}; +// ITANIUM-DAG: @d = addrspace(1) global { ptr addrspace(1) } { {{.*}} @_ZTV1D, +D d; + +// ITANIUM-DAG: @_ZTV1E = {{.*}} addrspace(1) constant { [3 x ptr addrspace(1)] } {{.*}} addrspace(1) null, ptr addrspace(1) @_ZTI1E, ptr addrspace(1) addrspacecast (ptr @_ZN1E1fEv to ptr addrspace(1)) +struct E { virtual void f() {} }; +// ITANIUM-DAG: @e = addrspace(1) global { {{.*}} @_ZTV1E, +E e; + +// ITANIUM-DAG: @_ZTV1F = {{.*}} addrspace(1) constant { [3 x ptr addrspace(1)] } {{.*}} addrspace(1) null, ptr addrspace(1) @_ZTI1F, ptr addrspace(1) addrspacecast (ptr @_ZN1E1fEv to ptr addrspace(1)) +struct F : E { virtual consteval void DoNotEmit_g(); }; +// ITANIUM-DAG: @f = addrspace(1) global { ptr addrspace(1) } { {{.*}} @_ZTV1F, +F f; diff --git a/clang/test/CodeGenCXX/vtable-constexpr-address-space.cpp b/clang/test/CodeGenCXX/vtable-constexpr-address-space.cpp new file mode 100644 index 0000000000000..67746328ce0aa --- /dev/null +++ b/clang/test/CodeGenCXX/vtable-constexpr-address-space.cpp @@ -0,0 +1,27 @@ +// RUN: %clang_cc1 -std=c++20 -triple=amdgcn-amd-amdhsa %s -emit-llvm -o - | FileCheck %s --implicit-check-not=DoNotEmit + +// constexpr virtual functions can be called at runtime and go in the vtable as +// normal. But they are implicitly inline so are never the key function. + +struct DoNotEmit { + virtual constexpr void f(); +}; +constexpr void DoNotEmit::f() {} + +// CHECK-DAG: @_ZTV1B = {{.*}} addrspace(1) constant { [3 x ptr addrspace(1)] } { {{.*}} null, {{.*}} @_ZTI1B, {{.*}} @_ZN1B1fEv +struct B { + // CHECK-DAG: define {{.*}} @_ZN1B1fEv + virtual constexpr void f() {} +}; +B b; + +struct CBase { + virtual constexpr void f(); // not key function +}; + +// CHECK-DAG: @_ZTV1C = {{.*}} addrspace(1) constant {{.*}} null, {{.*}} @_ZTI1C, {{.*}} @_ZN1C1fEv +struct C : CBase { + void f(); // key function +}; +// CHECK-DAG: define {{.*}} @_ZN1C1fEv +void C::f() {} diff --git a/clang/test/CodeGenCXX/vtable-key-function-address-space.cpp b/clang/test/CodeGenCXX/vtable-key-function-address-space.cpp new file mode 100644 index 0000000000000..2163bfaadbfb7 --- /dev/null +++ b/clang/test/CodeGenCXX/vtable-key-function-address-space.cpp @@ -0,0 +1,33 @@ +// RUN: %clang_cc1 %s -triple=amdgcn-amd-amdhsa -emit-llvm -o - | FileCheck %s +// PR5697 +namespace PR5697 { +struct A { + virtual void f() { } + A(); + A(int); +}; + +// A does not have a key function, so the first constructor we emit should +// cause the vtable to be defined (without assertions.) +// CHECK: @_ZTVN6PR56971AE = linkonce_odr unnamed_addr addrspace(1) constant +A::A() { } +A::A(int) { } +} + +// Make sure that we don't assert when building the vtable for a class +// template specialization or explicit instantiation with a key +// function. +template +struct Base { + virtual ~Base(); +}; + +template +struct Derived : public Base { }; + +template<> +struct Derived : public Base { + virtual void anchor(); +}; + +void Derived::anchor() { } diff --git a/clang/test/CodeGenCXX/vtable-layout-extreme-address-space.cpp b/clang/test/CodeGenCXX/vtable-layout-extreme-address-space.cpp new file mode 100644 index 0000000000000..8bc9dd9d46c92 --- /dev/null +++ b/clang/test/CodeGenCXX/vtable-layout-extreme-address-space.cpp @@ -0,0 +1,210 @@ +// RUN: %clang_cc1 %s -triple=amdgcn-amd-amdhsa -std=c++11 -emit-llvm-only -fdump-vtable-layouts 2>&1 | FileCheck %s + +// A collection of big class hierarchies and their vtables. + +namespace Test1 { + +class C0 +{ +}; +class C1 + : virtual public C0 +{ + int k0; +}; +class C2 + : public C0 + , virtual public C1 +{ + int k0; +}; +class C3 + : virtual public C0 + , virtual public C1 + , public C2 +{ + int k0; + int k1; + int k2; + int k3; +}; +class C4 + : public C2 + , virtual public C3 + , public C0 +{ + int k0; +}; +class C5 + : public C0 + , virtual public C4 + , public C2 + , public C1 + , virtual public C3 +{ + int k0; +}; +class C6 + : virtual public C3 + , public C0 + , public C5 + , public C4 + , public C1 +{ + int k0; +}; +class C7 + : virtual public C5 + , virtual public C6 + , virtual public C3 + , public C4 + , virtual public C2 +{ + int k0; + int k1; +}; +class C8 + : public C7 + , public C5 + , public C3 + , virtual public C4 + , public C1 + , public C2 +{ + int k0; + int k1; +}; + +// CHECK: Vtable for 'Test1::C9' (87 entries). +// CHECK-NEXT: 0 | vbase_offset (344) +// CHECK-NEXT: 1 | vbase_offset (312) +// CHECK-NEXT: 2 | vbase_offset (184) +// CHECK-NEXT: 3 | vbase_offset (168) +// CHECK-NEXT: 4 | vbase_offset (120) +// CHECK-NEXT: 5 | vbase_offset (48) +// CHECK-NEXT: 6 | vbase_offset (148) +// CHECK-NEXT: 7 | vbase_offset (152) +// CHECK-NEXT: 8 | offset_to_top (0) +// CHECK-NEXT: 9 | Test1::C9 RTTI +// CHECK-NEXT: -- (Test1::C2, 0) vtable address -- +// CHECK-NEXT: -- (Test1::C9, 0) vtable address -- +// CHECK-NEXT: 10 | void Test1::C9::f() +// CHECK-NEXT: 11 | vbase_offset (104) +// CHECK-NEXT: 12 | vbase_offset (132) +// CHECK-NEXT: 13 | vbase_offset (136) +// CHECK-NEXT: 14 | offset_to_top (-16) +// CHECK-NEXT: 15 | Test1::C9 RTTI +// CHECK-NEXT: -- (Test1::C2, 16) vtable address -- +// CHECK-NEXT: -- (Test1::C4, 16) vtable address -- +// CHECK-NEXT: 16 | vbase_offset (72) +// CHECK-NEXT: 17 | vbase_offset (120) +// CHECK-NEXT: 18 | vbase_offset (100) +// CHECK-NEXT: 19 | vbase_offset (104) +// CHECK-NEXT: 20 | offset_to_top (-48) +// CHECK-NEXT: 21 | Test1::C9 RTTI +// CHECK-NEXT: -- (Test1::C2, 48) vtable address -- +// CHECK-NEXT: -- (Test1::C5, 48) vtable address -- +// CHECK-NEXT: -- (Test1::C6, 48) vtable address -- +// CHECK-NEXT: 22 | vbase_offset (84) +// CHECK-NEXT: 23 | offset_to_top (-64) +// CHECK-NEXT: 24 | Test1::C9 RTTI +// CHECK-NEXT: -- (Test1::C1, 64) vtable address -- +// CHECK-NEXT: 25 | vbase_offset (32) +// CHECK-NEXT: 26 | vbase_offset (60) +// CHECK-NEXT: 27 | vbase_offset (64) +// CHECK-NEXT: 28 | offset_to_top (-88) +// CHECK-NEXT: 29 | Test1::C9 RTTI +// CHECK-NEXT: -- (Test1::C2, 88) vtable address -- +// CHECK-NEXT: -- (Test1::C4, 88) vtable address -- +// CHECK-NEXT: 30 | vbase_offset (44) +// CHECK-NEXT: 31 | offset_to_top (-104) +// CHECK-NEXT: 32 | Test1::C9 RTTI +// CHECK-NEXT: -- (Test1::C1, 104) vtable address -- +// CHECK-NEXT: 33 | vbase_offset (28) +// CHECK-NEXT: 34 | vbase_offset (32) +// CHECK-NEXT: 35 | offset_to_top (-120) +// CHECK-NEXT: 36 | Test1::C9 RTTI +// CHECK-NEXT: -- (Test1::C2, 120) vtable address -- +// CHECK-NEXT: -- (Test1::C3, 120) vtable address -- +// CHECK-NEXT: 37 | vbase_offset (-4) +// CHECK-NEXT: 38 | offset_to_top (-152) +// CHECK-NEXT: 39 | Test1::C9 RTTI +// CHECK-NEXT: -- (Test1::C1, 152) vtable address -- +// CHECK-NEXT: 40 | vbase_offset (-48) +// CHECK-NEXT: 41 | vbase_offset (-20) +// CHECK-NEXT: 42 | vbase_offset (-16) +// CHECK-NEXT: 43 | offset_to_top (-168) +// CHECK-NEXT: 44 | Test1::C9 RTTI +// CHECK-NEXT: -- (Test1::C2, 168) vtable address -- +// CHECK-NEXT: -- (Test1::C4, 168) vtable address -- +// CHECK-NEXT: 45 | vbase_offset (160) +// CHECK-NEXT: 46 | vbase_offset (-136) +// CHECK-NEXT: 47 | vbase_offset (-16) +// CHECK-NEXT: 48 | vbase_offset (128) +// CHECK-NEXT: 49 | vbase_offset (-64) +// CHECK-NEXT: 50 | vbase_offset (-36) +// CHECK-NEXT: 51 | vbase_offset (-32) +// CHECK-NEXT: 52 | offset_to_top (-184) +// CHECK-NEXT: 53 | Test1::C9 RTTI +// CHECK-NEXT: -- (Test1::C2, 184) vtable address -- +// CHECK-NEXT: -- (Test1::C4, 184) vtable address -- +// CHECK-NEXT: -- (Test1::C7, 184) vtable address -- +// CHECK-NEXT: -- (Test1::C8, 184) vtable address -- +// CHECK-NEXT: 54 | vbase_offset (-88) +// CHECK-NEXT: 55 | vbase_offset (-40) +// CHECK-NEXT: 56 | vbase_offset (-60) +// CHECK-NEXT: 57 | vbase_offset (-56) +// CHECK-NEXT: 58 | offset_to_top (-208) +// CHECK-NEXT: 59 | Test1::C9 RTTI +// CHECK-NEXT: -- (Test1::C2, 208) vtable address -- +// CHECK-NEXT: -- (Test1::C5, 208) vtable address -- +// CHECK-NEXT: 60 | vbase_offset (-76) +// CHECK-NEXT: 61 | offset_to_top (-224) +// CHECK-NEXT: 62 | Test1::C9 RTTI +// CHECK-NEXT: -- (Test1::C1, 224) vtable address -- +// CHECK-NEXT: 63 | vbase_offset (-92) +// CHECK-NEXT: 64 | vbase_offset (-88) +// CHECK-NEXT: 65 | offset_to_top (-240) +// CHECK-NEXT: 66 | Test1::C9 RTTI +// CHECK-NEXT: -- (Test1::C2, 240) vtable address -- +// CHECK-NEXT: -- (Test1::C3, 240) vtable address -- +// CHECK-NEXT: 67 | vbase_offset (-124) +// CHECK-NEXT: 68 | offset_to_top (-272) +// CHECK-NEXT: 69 | Test1::C9 RTTI +// CHECK-NEXT: -- (Test1::C1, 272) vtable address -- +// CHECK-NEXT: 70 | vbase_offset (-140) +// CHECK-NEXT: 71 | vbase_offset (-136) +// CHECK-NEXT: 72 | offset_to_top (-288) +// CHECK-NEXT: 73 | Test1::C9 RTTI +// CHECK-NEXT: -- (Test1::C2, 288) vtable address -- +// CHECK-NEXT: 74 | vbase_offset (-192) +// CHECK-NEXT: 75 | vbase_offset (-144) +// CHECK-NEXT: 76 | vbase_offset (-164) +// CHECK-NEXT: 77 | vbase_offset (-160) +// CHECK-NEXT: 78 | offset_to_top (-312) +// CHECK-NEXT: 79 | Test1::C9 RTTI +// CHECK-NEXT: -- (Test1::C2, 312) vtable address -- +// CHECK-NEXT: -- (Test1::C5, 312) vtable address -- +// CHECK-NEXT: 80 | vbase_offset (-180) +// CHECK-NEXT: 81 | offset_to_top (-328) +// CHECK-NEXT: 82 | Test1::C9 RTTI +// CHECK-NEXT: -- (Test1::C1, 328) vtable address -- +// CHECK-NEXT: 83 | vbase_offset (-196) +// CHECK-NEXT: 84 | vbase_offset (-192) +// CHECK-NEXT: 85 | offset_to_top (-344) +// CHECK-NEXT: 86 | Test1::C9 RTTI +class C9 + : virtual public C6 + , public C2 + , public C4 + , virtual public C8 +{ + int k0; + int k1; + int k2; + int k3; + virtual void f(); +}; +void C9::f() { } + +} diff --git a/clang/test/CodeGenCXX/vtable-linkage-address-space.cpp b/clang/test/CodeGenCXX/vtable-linkage-address-space.cpp new file mode 100644 index 0000000000000..988dfb254c0db --- /dev/null +++ b/clang/test/CodeGenCXX/vtable-linkage-address-space.cpp @@ -0,0 +1,217 @@ +// RUN: %clang_cc1 %s -triple=amdgcn-amd-amdhsa -emit-llvm -o %t +// RUN: %clang_cc1 %s -triple=amdgcn-amd-amdhsa -emit-llvm -std=c++03 -o %t.03 +// RUN: %clang_cc1 %s -triple=amdgcn-amd-amdhsa -emit-llvm -std=c++11 -o %t.11 +// RUN: %clang_cc1 %s -triple=amdgcn-amd-amdhsa -disable-llvm-passes -O3 -emit-llvm -o %t.opt +// RUN: FileCheck %s < %t +// RUN: FileCheck %s < %t.03 +// RUN: FileCheck %s < %t.11 +// RUN: FileCheck --check-prefix=CHECK-OPT %s < %t.opt + +namespace { + struct A { + virtual void f() { } + }; +} + +void f() { A b; } + +struct B { + B(); + virtual void f(); +}; + +B::B() { } + +struct C : virtual B { + C(); + virtual void f() { } +}; + +C::C() { } + +struct D { + virtual void f(); +}; + +void D::f() { } + +static struct : D { } e; + +// Force 'e' to be constructed and therefore have a vtable defined. +void use_e() { + e.f(); +} + +// The destructor is the key function. +template +struct E { + virtual ~E(); +}; + +template E::~E() { } + +// Anchor is the key function +template<> +struct E { + virtual void anchor(); +}; + +void E::anchor() { } + +template struct E; +extern template struct E; + +void use_E() { + E ei; + (void)ei; + E el; + (void)el; +} + +// No key function +template +struct F { + virtual void foo() { } +}; + +// No key function +template<> +struct F { + virtual void foo() { } +}; + +template struct F; +extern template struct F; + +void use_F() { + F fc; + fc.foo(); + F fi; + fi.foo(); + F fl; + (void)fl; +} + +// B has a key function that is not defined in this translation unit so its vtable +// has external linkage. +// CHECK-DAG: @_ZTV1B = external unnamed_addr addrspace(1) constant + +// C has no key function, so its vtable should have weak_odr linkage +// and hidden visibility (rdar://problem/7523229). +// CHECK-DAG: @_ZTV1C = linkonce_odr unnamed_addr addrspace(1) constant {{.*}}, comdat, align 8{{$}} +// CHECK-DAG: @_ZTS1C = linkonce_odr addrspace(1) constant {{.*}}, comdat, align 1{{$}} +// CHECK-DAG: @_ZTI1C = linkonce_odr addrspace(1) constant {{.*}}, comdat, align 8{{$}} +// CHECK-DAG: @_ZTT1C = linkonce_odr unnamed_addr addrspace(1) constant {{.*}}, comdat, align 8{{$}} + +// D has a key function that is defined in this translation unit so its vtable is +// defined in the translation unit. +// CHECK-DAG: @_ZTV1D ={{.*}} unnamed_addr addrspace(1) constant +// CHECK-DAG: @_ZTS1D ={{.*}} addrspace(1) constant +// CHECK-DAG: @_ZTI1D ={{.*}} addrspace(1) constant + +// E is an explicit specialization with a key function defined +// in this translation unit, so its vtable should have external +// linkage. +// CHECK-DAG: @_ZTV1EIcE ={{.*}} unnamed_addr addrspace(1) constant +// CHECK-DAG: @_ZTS1EIcE ={{.*}} addrspace(1) constant +// CHECK-DAG: @_ZTI1EIcE ={{.*}} addrspace(1) constant + +// E is an explicit template instantiation with a key function +// defined in this translation unit, so its vtable should have +// weak_odr linkage. +// CHECK-DAG: @_ZTV1EIsE = weak_odr unnamed_addr addrspace(1) constant {{.*}}, comdat, +// CHECK-DAG: @_ZTS1EIsE = weak_odr addrspace(1) constant {{.*}}, comdat, align 1{{$}} +// CHECK-DAG: @_ZTI1EIsE = weak_odr addrspace(1) constant {{.*}}, comdat, align 8{{$}} + +// F is an explicit template instantiation without a key +// function, so its vtable should have weak_odr linkage +// CHECK-DAG: @_ZTV1FIsE = weak_odr unnamed_addr addrspace(1) constant {{.*}}, comdat, +// CHECK-DAG: @_ZTS1FIsE = weak_odr addrspace(1) constant {{.*}}, comdat, align 1{{$}} +// CHECK-DAG: @_ZTI1FIsE = weak_odr addrspace(1) constant {{.*}}, comdat, align 8{{$}} + +// E is an implicit template instantiation with a key function +// defined in this translation unit, so its vtable should have +// linkonce_odr linkage. +// CHECK-DAG: @_ZTV1EIlE = linkonce_odr unnamed_addr addrspace(1) constant {{.*}}, comdat, +// CHECK-DAG: @_ZTS1EIlE = linkonce_odr addrspace(1) constant {{.*}}, comdat, align 1{{$}} +// CHECK-DAG: @_ZTI1EIlE = linkonce_odr addrspace(1) constant {{.*}}, comdat, align 8{{$}} + +// F is an implicit template instantiation with no key function, +// so its vtable should have linkonce_odr linkage. +// CHECK-DAG: @_ZTV1FIlE = linkonce_odr unnamed_addr addrspace(1) constant {{.*}}, comdat, +// CHECK-DAG: @_ZTS1FIlE = linkonce_odr addrspace(1) constant {{.*}}, comdat, align 1{{$}} +// CHECK-DAG: @_ZTI1FIlE = linkonce_odr addrspace(1) constant {{.*}}, comdat, align 8{{$}} + +// F is an explicit template instantiation declaration without a +// key function, so its vtable should have external linkage. +// CHECK-DAG: @_ZTV1FIiE = external unnamed_addr addrspace(1) constant +// CHECK-OPT-DAG: @_ZTV1FIiE = available_externally unnamed_addr addrspace(1) constant + +// E is an explicit template instantiation declaration. It has a +// key function is not instantiated, so we know that vtable definition +// will be generated in TU where key function will be defined +// so we can mark it as external (without optimizations) and +// available_externally (with optimizations) because all of the inline +// virtual functions have been emitted. +// CHECK-DAG: @_ZTV1EIiE = external unnamed_addr addrspace(1) constant +// CHECK-OPT-DAG: @_ZTV1EIiE = available_externally unnamed_addr addrspace(1) constant + +// The anonymous struct for e has no linkage, so the vtable should have +// internal linkage. +// CHECK-DAG: @"_ZTV3$_0" = internal unnamed_addr addrspace(1) constant +// CHECK-DAG: @"_ZTS3$_0" = internal addrspace(1) constant +// CHECK-DAG: @"_ZTI3$_0" = internal addrspace(1) constant + +// The A vtable should have internal linkage since it is inside an anonymous +// namespace. +// CHECK-DAG: @_ZTVN12_GLOBAL__N_11AE = internal unnamed_addr addrspace(1) constant +// CHECK-DAG: @_ZTSN12_GLOBAL__N_11AE = internal addrspace(1) constant +// CHECK-DAG: @_ZTIN12_GLOBAL__N_11AE = internal addrspace(1) constant + +// F is an explicit specialization without a key function, so +// its vtable should have linkonce_odr linkage. +// CHECK-DAG: @_ZTV1FIcE = linkonce_odr unnamed_addr addrspace(1) constant {{.*}}, comdat, +// CHECK-DAG: @_ZTS1FIcE = linkonce_odr addrspace(1) constant {{.*}}, comdat, align 1{{$}} +// CHECK-DAG: @_ZTI1FIcE = linkonce_odr addrspace(1) constant {{.*}}, comdat, align 8{{$}} + +// CHECK-DAG: @_ZTV1GIiE = linkonce_odr unnamed_addr addrspace(1) constant {{.*}}, comdat, +template +class G { +public: + G() {} + virtual void f0(); + virtual void f1(); +}; +template <> +void G::f1() {} +template +void G::f0() {} +void G_f0() { new G(); } + +// H has a key function without a body but it's a template instantiation +// so its VTable must be emitted. +// CHECK-DAG: @_ZTV1HIiE = linkonce_odr unnamed_addr addrspace(1) constant {{.*}}, comdat, +template +class H { +public: + virtual ~H(); +}; + +void use_H() { + H h; +} + +// I has an explicit instantiation declaration and needs a VTT and +// construction vtables. + +// CHECK-DAG: @_ZTV1IIiE = external unnamed_addr addrspace(1) constant +// CHECK-DAG: @_ZTT1IIiE = external unnamed_addr addrspace(1) constant +// CHECK-NOT: @_ZTC1IIiE +// +// CHECK-OPT-DAG: @_ZTV1IIiE = available_externally unnamed_addr addrspace(1) constant +// CHECK-OPT-DAG: @_ZTT1IIiE = available_externally unnamed_addr addrspace(1) constant +struct VBase1 { virtual void f(); }; struct VBase2 : virtual VBase1 {}; +template +struct I : VBase2 {}; +extern template struct I; +I i; diff --git a/clang/test/CodeGenCXX/vtable-pointer-initialization-address-space.cpp b/clang/test/CodeGenCXX/vtable-pointer-initialization-address-space.cpp new file mode 100644 index 0000000000000..247864862fecf --- /dev/null +++ b/clang/test/CodeGenCXX/vtable-pointer-initialization-address-space.cpp @@ -0,0 +1,60 @@ +// RUN: %clang_cc1 %s -triple=amdgcn-amd-amdhsa -std=c++11 -emit-llvm -o - | FileCheck %s + +struct Field { + Field(); + ~Field(); +}; + +struct Base { + Base(); + ~Base(); +}; + +struct A : Base { + A(); + ~A(); + + virtual void f(); + + Field field; +}; + +// CHECK-LABEL: define{{.*}} void @_ZN1AC2Ev(ptr {{[^,]*}} %this) unnamed_addr +// CHECK: call void @_ZN4BaseC2Ev( +// CHECK: store ptr addrspace(1) getelementptr inbounds ({ [3 x ptr addrspace(1)] }, ptr addrspace(1) @_ZTV1A, i32 0, inrange i32 0, i32 2) +// CHECK: call void @_ZN5FieldC1Ev( +// CHECK: ret void +A::A() { } + +// CHECK-LABEL: define{{.*}} void @_ZN1AD2Ev(ptr {{[^,]*}} %this) unnamed_addr +// CHECK: store ptr addrspace(1) getelementptr inbounds ({ [3 x ptr addrspace(1)] }, ptr addrspace(1) @_ZTV1A, i32 0, inrange i32 0, i32 2) +// CHECK: call void @_ZN5FieldD1Ev( +// CHECK: call void @_ZN4BaseD2Ev( +// CHECK: ret void +A::~A() { } + +struct B : Base { + virtual void f(); + + Field field; +}; + +void f() { B b; } + +// CHECK-LABEL: define linkonce_odr void @_ZN1BC1Ev(ptr {{[^,]*}} %this) unnamed_addr +// CHECK: call void @_ZN1BC2Ev( + +// CHECK-LABEL: define linkonce_odr void @_ZN1BD1Ev(ptr {{[^,]*}} %this) unnamed_addr +// CHECK: call void @_ZN1BD2Ev( + +// CHECK-LABEL: define linkonce_odr void @_ZN1BC2Ev(ptr {{[^,]*}} %this) unnamed_addr +// CHECK: call void @_ZN4BaseC2Ev( +// CHECK: store ptr addrspace(1) getelementptr inbounds ({ [3 x ptr addrspace(1)] }, ptr addrspace(1) @_ZTV1B, i32 0, inrange i32 0, i32 2) +// CHECK: call void @_ZN5FieldC1Ev +// CHECK: ret void + +// CHECK-LABEL: define linkonce_odr void @_ZN1BD2Ev(ptr {{[^,]*}} %this) unnamed_addr +// CHECK: store ptr addrspace(1) getelementptr inbounds ({ [3 x ptr addrspace(1)] }, ptr addrspace(1) @_ZTV1B, i32 0, inrange i32 0, i32 2) +// CHECK: call void @_ZN5FieldD1Ev( +// CHECK: call void @_ZN4BaseD2Ev( +// CHECK: ret void diff --git a/clang/test/CodeGenCXX/vtt-address-space.cpp b/clang/test/CodeGenCXX/vtt-address-space.cpp index 595587923d5f6..e567ae49811a4 100644 --- a/clang/test/CodeGenCXX/vtt-address-space.cpp +++ b/clang/test/CodeGenCXX/vtt-address-space.cpp @@ -1,7 +1,4 @@ // 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 { @@ -21,10 +18,10 @@ namespace Test { 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) +// CHECK: linkonce_odr unnamed_addr addrspace(1) constant [13 x ptr addrspace(1)] [ptr addrspace(1) getelementptr inbounds ({ [5 x ptr addrspace(1)], [7 x ptr addrspace(1)], [4 x ptr addrspace(1)], [3 x ptr addrspace(1)] }, ptr addrspace(1) @_ZTVN4Test1DE, i32 0, inrange i32 0, i32 5), ptr addrspace(1) getelementptr inbounds ({ [3 x ptr addrspace(1)], [4 x ptr addrspace(1)] }, ptr addrspace(1) @_ZTCN4Test1DE0_NS_2C1E, i32 0, inrange i32 0, i32 3), ptr addrspace(1) getelementptr inbounds ({ [3 x ptr addrspace(1)], [4 x ptr addrspace(1)] }, ptr addrspace(1) @_ZTCN4Test1DE0_NS_2C1E, i32 0, inrange i32 1, i32 3), ptr addrspace(1) getelementptr inbounds ({ [7 x ptr addrspace(1)], [3 x ptr addrspace(1)], [4 x ptr addrspace(1)] }, ptr addrspace(1) @_ZTCN4Test1DE16_NS_2C2E, i32 0, inrange i32 0, i32 6), ptr addrspace(1) getelementptr inbounds ({ [7 x ptr addrspace(1)], [3 x ptr addrspace(1)], [4 x ptr addrspace(1)] }, ptr addrspace(1) @_ZTCN4Test1DE16_NS_2C2E, i32 0, inrange i32 0, i32 6), ptr addrspace(1) getelementptr inbounds ({ [7 x ptr addrspace(1)], [3 x ptr addrspace(1)], [4 x ptr addrspace(1)] }, ptr addrspace(1) @_ZTCN4Test1DE16_NS_2C2E, i32 0, inrange i32 1, i32 3), ptr addrspace(1) getelementptr inbounds ({ [7 x ptr addrspace(1)], [3 x ptr addrspace(1)], [4 x ptr addrspace(1)] }, ptr addrspace(1) @_ZTCN4Test1DE16_NS_2C2E, i32 0, inrange i32 2, i32 3), ptr addrspace(1) getelementptr inbounds ({ [5 x ptr addrspace(1)], [7 x ptr addrspace(1)], [4 x ptr addrspace(1)], [3 x ptr addrspace(1)] }, ptr addrspace(1) @_ZTVN4Test1DE, i32 0, inrange i32 2, i32 3), ptr addrspace(1) getelementptr inbounds ({ [5 x ptr addrspace(1)], [7 x ptr addrspace(1)], [4 x ptr addrspace(1)], [3 x ptr addrspace(1)] }, ptr addrspace(1) @_ZTVN4Test1DE, i32 0, inrange i32 1, i32 6), ptr addrspace(1) getelementptr inbounds ({ [5 x ptr addrspace(1)], [7 x ptr addrspace(1)], [4 x ptr addrspace(1)], [3 x ptr addrspace(1)] }, ptr addrspace(1) @_ZTVN4Test1DE, i32 0, inrange i32 1, i32 6), ptr addrspace(1) getelementptr inbounds ({ [5 x ptr addrspace(1)], [7 x ptr addrspace(1)], [4 x ptr addrspace(1)], [3 x ptr addrspace(1)] }, ptr addrspace(1) @_ZTVN4Test1DE, i32 0, inrange i32 3, i32 3), ptr addrspace(1) getelementptr inbounds ({ [3 x ptr addrspace(1)], [4 x ptr addrspace(1)] }, ptr addrspace(1) @_ZTCN4Test1DE64_NS_2V2E, i32 0, inrange i32 0, i32 3), ptr addrspace(1) getelementptr inbounds ({ [3 x ptr addrspace(1)], [4 x ptr addrspace(1)] }, ptr addrspace(1) @_ZTCN4Test1DE64_NS_2V2E, i32 0, inrange i32 1, i32 3)], comdat, align 8 +// CHECK: call void @_ZN4Test2V2C2Ev(ptr noundef nonnull align 8 dereferenceable(20) %2, ptr addrspace(1) noundef getelementptr inbounds ([13 x ptr addrspace(1)], 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 addrspace(1)], 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 addrspace(1)], ptr addrspace(1) @_ZTTN4Test1DE, i64 0, i64 3)) +// CHECK: define linkonce_odr void @_ZN4Test2V2C2Ev(ptr noundef nonnull align 8 dereferenceable(20) %this, ptr addrspace(1) noundef %vtt) +// CHECK: define linkonce_odr void @_ZN4Test2C1C2Ev(ptr noundef nonnull align 8 dereferenceable(12) %this, ptr addrspace(1) noundef %vtt) +// CHECK: define linkonce_odr void @_ZN4Test2C2C2Ev(ptr noundef nonnull align 8 dereferenceable(12) %this, ptr addrspace(1) noundef %vtt) diff --git a/clang/test/CodeGenCXX/vtt-layout-address-space.cpp b/clang/test/CodeGenCXX/vtt-layout-address-space.cpp new file mode 100644 index 0000000000000..2f80c9ec5f9fe --- /dev/null +++ b/clang/test/CodeGenCXX/vtt-layout-address-space.cpp @@ -0,0 +1,89 @@ +// RUN: %clang_cc1 %s -triple=amdgcn-amd-amdhsa -std=c++11 -emit-llvm -o - | FileCheck %s + +// Test1::B should just have a single entry in its VTT, which points to the vtable. +namespace Test1 { +struct A { }; + +struct B : virtual A { + virtual void f(); +}; + +void B::f() { } +} + +// Check that we don't add a secondary virtual pointer for Test2::A, since Test2::A doesn't have any virtual member functions or bases. +namespace Test2 { + struct A { }; + + struct B : A { virtual void f(); }; + struct C : virtual B { }; + + C c; +} + +// This is the sample from the C++ Itanium ABI, p2.6.2. +namespace Test3 { + 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; +} + +// This is the sample from the C++ Itanium ABI, p2.6.2, with the change suggested +// (making A2 a virtual base of V1) +namespace Test4 { + class A1 { int i; }; + class A2 { int i; virtual void f(); }; + class V1 : public A1, public virtual 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; +} + +namespace Test5 { + struct A { + virtual void f() = 0; + virtual void anchor(); + }; + + void A::anchor() { + } +} + +namespace Test6 { + struct A { + virtual void f() = delete; + virtual void anchor(); + }; + + void A::anchor() { + } +} + +// CHECK: @_ZTTN5Test11BE ={{.*}} unnamed_addr addrspace(1) constant [1 x ptr addrspace(1)] [ptr addrspace(1) getelementptr inbounds ({ [4 x ptr addrspace(1)] }, ptr addrspace(1) @_ZTVN5Test11BE, i32 0, inrange i32 0, i32 3)] +// CHECK: @_ZTVN5Test51AE ={{.*}} unnamed_addr addrspace(1) constant { [4 x ptr addrspace(1)] } { [4 x ptr addrspace(1)] [ptr addrspace(1) null, ptr addrspace(1) @_ZTIN5Test51AE, ptr addrspace(1) addrspacecast (ptr @__cxa_pure_virtual to ptr addrspace(1)), ptr addrspace(1) addrspacecast (ptr @_ZN5Test51A6anchorEv to ptr addrspace(1))] } +// CHECK: @_ZTVN5Test61AE ={{.*}} unnamed_addr addrspace(1) constant { [4 x ptr addrspace(1)] } { [4 x ptr addrspace(1)] [ptr addrspace(1) null, ptr addrspace(1) @_ZTIN5Test61AE, ptr addrspace(1) addrspacecast (ptr @__cxa_deleted_virtual to ptr addrspace(1)), ptr addrspace(1) addrspacecast (ptr @_ZN5Test61A6anchorEv to ptr addrspace(1))] } +// CHECK: @_ZTTN5Test21CE = linkonce_odr unnamed_addr addrspace(1) constant [2 x ptr addrspace(1)] [ptr addrspace(1) getelementptr inbounds ({ [5 x ptr addrspace(1)] }, ptr addrspace(1) @_ZTVN5Test21CE, i32 0, inrange i32 0, i32 4), ptr addrspace(1) getelementptr inbounds ({ [5 x ptr addrspace(1)] }, ptr addrspace(1) @_ZTVN5Test21CE, i32 0, inrange i32 0, i32 4)] +// CHECK: @_ZTTN5Test31DE = linkonce_odr unnamed_addr addrspace(1) constant [13 x ptr addrspace(1)] [ptr addrspace(1) getelementptr inbounds ({ [5 x ptr addrspace(1)], [7 x ptr addrspace(1)], [4 x ptr addrspace(1)], [3 x ptr addrspace(1)] }, ptr addrspace(1) @_ZTVN5Test31DE, i32 0, inrange i32 0, i32 5), ptr addrspace(1) getelementptr inbounds ({ [3 x ptr addrspace(1)], [4 x ptr addrspace(1)] }, ptr addrspace(1) @_ZTCN5Test31DE0_NS_2C1E, i32 0, inrange i32 0, i32 3), ptr addrspace(1) getelementptr inbounds ({ [3 x ptr addrspace(1)], [4 x ptr addrspace(1)] }, ptr addrspace(1) @_ZTCN5Test31DE0_NS_2C1E, i32 0, inrange i32 1, i32 3), ptr addrspace(1) getelementptr inbounds ({ [7 x ptr addrspace(1)], [3 x ptr addrspace(1)], [4 x ptr addrspace(1)] }, ptr addrspace(1) @_ZTCN5Test31DE16_NS_2C2E, i32 0, inrange i32 0, i32 6), ptr addrspace(1) getelementptr inbounds ({ [7 x ptr addrspace(1)], [3 x ptr addrspace(1)], [4 x ptr addrspace(1)] }, ptr addrspace(1) @_ZTCN5Test31DE16_NS_2C2E, i32 0, inrange i32 0, i32 6), ptr addrspace(1) getelementptr inbounds ({ [7 x ptr addrspace(1)], [3 x ptr addrspace(1)], [4 x ptr addrspace(1)] }, ptr addrspace(1) @_ZTCN5Test31DE16_NS_2C2E, i32 0, inrange i32 1, i32 3), ptr addrspace(1) getelementptr inbounds ({ [7 x ptr addrspace(1)], [3 x ptr addrspace(1)], [4 x ptr addrspace(1)] }, ptr addrspace(1) @_ZTCN5Test31DE16_NS_2C2E, i32 0, inrange i32 2, i32 3), ptr addrspace(1) getelementptr inbounds ({ [5 x ptr addrspace(1)], [7 x ptr addrspace(1)], [4 x ptr addrspace(1)], [3 x ptr addrspace(1)] }, ptr addrspace(1) @_ZTVN5Test31DE, i32 0, inrange i32 2, i32 3), ptr addrspace(1) getelementptr inbounds ({ [5 x ptr addrspace(1)], [7 x ptr addrspace(1)], [4 x ptr addrspace(1)], [3 x ptr addrspace(1)] }, ptr addrspace(1) @_ZTVN5Test31DE, i32 0, inrange i32 1, i32 6), ptr addrspace(1) getelementptr inbounds ({ [5 x ptr addrspace(1)], [7 x ptr addrspace(1)], [4 x ptr addrspace(1)], [3 x ptr addrspace(1)] }, ptr addrspace(1) @_ZTVN5Test31DE, i32 0, inrange i32 1, i32 6), ptr addrspace(1) getelementptr inbounds ({ [5 x ptr addrspace(1)], [7 x ptr addrspace(1)], [4 x ptr addrspace(1)], [3 x ptr addrspace(1)] }, ptr addrspace(1) @_ZTVN5Test31DE, i32 0, inrange i32 3, i32 3), ptr addrspace(1) getelementptr inbounds ({ [3 x ptr addrspace(1)], [4 x ptr addrspace(1)] }, ptr addrspace(1) @_ZTCN5Test31DE64_NS_2V2E, i32 0, inrange i32 0, i32 3), ptr addrspace(1) getelementptr inbounds ({ [3 x ptr addrspace(1)], [4 x ptr addrspace(1)] }, ptr addrspace(1) @_ZTCN5Test31DE64_NS_2V2E, i32 0, inrange i32 1, i32 3)] +// CHECK: @_ZTVN5Test41DE = linkonce_odr unnamed_addr addrspace(1) constant { [6 x ptr addrspace(1)], [8 x ptr addrspace(1)], [3 x ptr addrspace(1)], [4 x ptr addrspace(1)], [4 x ptr addrspace(1)] } { [6 x ptr addrspace(1)] [ptr addrspace(1) inttoptr (i64 72 to ptr addrspace(1)), ptr addrspace(1) inttoptr (i64 16 to ptr addrspace(1)), ptr addrspace(1) inttoptr (i64 56 to ptr addrspace(1)), ptr addrspace(1) inttoptr (i64 40 to ptr addrspace(1)), ptr addrspace(1) null, ptr addrspace(1) @_ZTIN5Test41DE], [8 x ptr addrspace(1)] [ptr addrspace(1) inttoptr (i64 40 to ptr addrspace(1)), ptr addrspace(1) inttoptr (i64 24 to ptr addrspace(1)), ptr addrspace(1) inttoptr (i64 56 to ptr addrspace(1)), ptr addrspace(1) null, ptr addrspace(1) null, ptr addrspace(1) inttoptr (i64 -16 to ptr addrspace(1)), ptr addrspace(1) @_ZTIN5Test41DE, ptr addrspace(1) addrspacecast (ptr @_ZN5Test42V31gEv to ptr addrspace(1))], [3 x ptr addrspace(1)] [ptr addrspace(1) inttoptr (i64 16 to ptr addrspace(1)), ptr addrspace(1) inttoptr (i64 -40 to ptr addrspace(1)), ptr addrspace(1) @_ZTIN5Test41DE], [4 x ptr addrspace(1)] [ptr addrspace(1) null, ptr addrspace(1) inttoptr (i64 -56 to ptr addrspace(1)), ptr addrspace(1) @_ZTIN5Test41DE, ptr addrspace(1) addrspacecast (ptr @_ZN5Test42A21fEv to ptr addrspace(1))], [4 x ptr addrspace(1)] [ptr addrspace(1) inttoptr (i64 -16 to ptr addrspace(1)), ptr addrspace(1) inttoptr (i64 -32 to ptr addrspace(1)), ptr addrspace(1) inttoptr (i64 -72 to ptr addrspace(1)), ptr addrspace(1) @_ZTIN5Test41DE] } +// CHECK: @_ZTTN5Test41DE = linkonce_odr unnamed_addr addrspace(1) constant [19 x ptr addrspace(1)] [ptr addrspace(1) getelementptr inbounds ({ [6 x ptr addrspace(1)], [8 x ptr addrspace(1)], [3 x ptr addrspace(1)], [4 x ptr addrspace(1)], [4 x ptr addrspace(1)] }, ptr addrspace(1) @_ZTVN5Test41DE, i32 0, inrange i32 0, i32 6), ptr addrspace(1) getelementptr inbounds ({ [4 x ptr addrspace(1)], [3 x ptr addrspace(1)], [4 x ptr addrspace(1)] }, ptr addrspace(1) @_ZTCN5Test41DE0_NS_2C1E, i32 0, inrange i32 0, i32 4), ptr addrspace(1) getelementptr inbounds ({ [4 x ptr addrspace(1)], [3 x ptr addrspace(1)], [4 x ptr addrspace(1)] }, ptr addrspace(1) @_ZTCN5Test41DE0_NS_2C1E, i32 0, inrange i32 1, i32 3), ptr addrspace(1) getelementptr inbounds ({ [4 x ptr addrspace(1)], [3 x ptr addrspace(1)], [4 x ptr addrspace(1)] }, ptr addrspace(1) @_ZTCN5Test41DE0_NS_2C1E, i32 0, inrange i32 2, i32 3), ptr addrspace(1) getelementptr inbounds ({ [8 x ptr addrspace(1)], [4 x ptr addrspace(1)], [3 x ptr addrspace(1)], [4 x ptr addrspace(1)] }, ptr addrspace(1) @_ZTCN5Test41DE16_NS_2C2E, i32 0, inrange i32 0, i32 7), ptr addrspace(1) getelementptr inbounds ({ [8 x ptr addrspace(1)], [4 x ptr addrspace(1)], [3 x ptr addrspace(1)], [4 x ptr addrspace(1)] }, ptr addrspace(1) @_ZTCN5Test41DE16_NS_2C2E, i32 0, inrange i32 0, i32 7), ptr addrspace(1) getelementptr inbounds ({ [8 x ptr addrspace(1)], [4 x ptr addrspace(1)], [3 x ptr addrspace(1)], [4 x ptr addrspace(1)] }, ptr addrspace(1) @_ZTCN5Test41DE16_NS_2C2E, i32 0, inrange i32 1, i32 4), ptr addrspace(1) getelementptr inbounds ({ [8 x ptr addrspace(1)], [4 x ptr addrspace(1)], [3 x ptr addrspace(1)], [4 x ptr addrspace(1)] }, ptr addrspace(1) @_ZTCN5Test41DE16_NS_2C2E, i32 0, inrange i32 2, i32 3), ptr addrspace(1) getelementptr inbounds ({ [8 x ptr addrspace(1)], [4 x ptr addrspace(1)], [3 x ptr addrspace(1)], [4 x ptr addrspace(1)] }, ptr addrspace(1) @_ZTCN5Test41DE16_NS_2C2E, i32 0, inrange i32 3, i32 3), ptr addrspace(1) getelementptr inbounds ({ [6 x ptr addrspace(1)], [8 x ptr addrspace(1)], [3 x ptr addrspace(1)], [4 x ptr addrspace(1)], [4 x ptr addrspace(1)] }, ptr addrspace(1) @_ZTVN5Test41DE, i32 0, inrange i32 2, i32 3), ptr addrspace(1) getelementptr inbounds ({ [6 x ptr addrspace(1)], [8 x ptr addrspace(1)], [3 x ptr addrspace(1)], [4 x ptr addrspace(1)], [4 x ptr addrspace(1)] }, ptr addrspace(1) @_ZTVN5Test41DE, i32 0, inrange i32 3, i32 3), ptr addrspace(1) getelementptr inbounds ({ [6 x ptr addrspace(1)], [8 x ptr addrspace(1)], [3 x ptr addrspace(1)], [4 x ptr addrspace(1)], [4 x ptr addrspace(1)] }, ptr addrspace(1) @_ZTVN5Test41DE, i32 0, inrange i32 1, i32 7), ptr addrspace(1) getelementptr inbounds ({ [6 x ptr addrspace(1)], [8 x ptr addrspace(1)], [3 x ptr addrspace(1)], [4 x ptr addrspace(1)], [4 x ptr addrspace(1)] }, ptr addrspace(1) @_ZTVN5Test41DE, i32 0, inrange i32 1, i32 7), ptr addrspace(1) getelementptr inbounds ({ [6 x ptr addrspace(1)], [8 x ptr addrspace(1)], [3 x ptr addrspace(1)], [4 x ptr addrspace(1)], [4 x ptr addrspace(1)] }, ptr addrspace(1) @_ZTVN5Test41DE, i32 0, inrange i32 4, i32 4), ptr addrspace(1) getelementptr inbounds ({ [3 x ptr addrspace(1)], [4 x ptr addrspace(1)] }, ptr addrspace(1) @_ZTCN5Test41DE40_NS_2V1E, i32 0, inrange i32 0, i32 3), ptr addrspace(1) getelementptr inbounds ({ [3 x ptr addrspace(1)], [4 x ptr addrspace(1)] }, ptr addrspace(1) @_ZTCN5Test41DE40_NS_2V1E, i32 0, inrange i32 1, i32 3), ptr addrspace(1) getelementptr inbounds ({ [4 x ptr addrspace(1)], [3 x ptr addrspace(1)], [4 x ptr addrspace(1)] }, ptr addrspace(1) @_ZTCN5Test41DE72_NS_2V2E, i32 0, inrange i32 0, i32 4), ptr addrspace(1) getelementptr inbounds ({ [4 x ptr addrspace(1)], [3 x ptr addrspace(1)], [4 x ptr addrspace(1)] }, ptr addrspace(1) @_ZTCN5Test41DE72_NS_2V2E, i32 0, inrange i32 1, i32 3), ptr addrspace(1) getelementptr inbounds ({ [4 x ptr addrspace(1)], [3 x ptr addrspace(1)], [4 x ptr addrspace(1)] }, ptr addrspace(1) @_ZTCN5Test41DE72_NS_2V2E, i32 0, inrange i32 2, i32 3)] +// CHECK: declare void @__cxa_pure_virtual() unnamed_addr +// CHECK: declare void @__cxa_deleted_virtual() unnamed_addr diff --git a/clang/test/Headers/hip-header.hip b/clang/test/Headers/hip-header.hip index 154929fab4f15..146a43b643dba 100644 --- a/clang/test/Headers/hip-header.hip +++ b/clang/test/Headers/hip-header.hip @@ -57,6 +57,22 @@ // expected-no-diagnostics +// Check handling of overriden, implicitly __host__ dtor (should emit as a +// nullptr to global) + +struct vbase { + virtual ~vbase(); +}; + +template +struct vderived : public vbase { + ~vderived(); +}; + +template struct vderived; + +// CHECK: @_ZTV8vderivedIvE = weak_odr unnamed_addr addrspace(1) constant { [4 x ptr addrspace(1)] } zeroinitializer, comdat, align 8 + // Check support for pure and deleted virtual functions struct base { __host__ @@ -74,9 +90,8 @@ struct derived:base { __device__ void test_vf() { derived d; } -// CHECK: @_ZTV7derived = linkonce_odr unnamed_addr addrspace(1) constant { [4 x ptr] } { [4 x ptr] [ptr null, ptr null, ptr @_ZN7derived2pvEv, ptr @__cxa_deleted_virtual] }, comdat, align 8 -// CHECK: @_ZTV4base = linkonce_odr unnamed_addr addrspace(1) constant { [4 x ptr] } { [4 x ptr] [ptr null, ptr null, ptr @__cxa_pure_virtual, ptr @__cxa_deleted_virtual] }, comdat, align 8 - +// CHECK: @_ZTV7derived = linkonce_odr unnamed_addr addrspace(1) constant { [4 x ptr addrspace(1)] } { [4 x ptr addrspace(1)] [ptr addrspace(1) null, ptr addrspace(1) null, ptr addrspace(1) addrspacecast (ptr @_ZN7derived2pvEv to ptr addrspace(1)), ptr addrspace(1) addrspacecast (ptr @__cxa_deleted_virtual to ptr addrspace(1))] }, comdat, align 8 +// CHECK: @_ZTV4base = linkonce_odr unnamed_addr addrspace(1) constant { [4 x ptr addrspace(1)] } { [4 x ptr addrspace(1)] [ptr addrspace(1) null, ptr addrspace(1) null, ptr addrspace(1) addrspacecast (ptr @__cxa_pure_virtual to ptr addrspace(1)), ptr addrspace(1) addrspacecast (ptr @__cxa_deleted_virtual to ptr addrspace(1))] }, comdat, align 8 // CHECK: define{{.*}}void @__cxa_pure_virtual() // CHECK: define{{.*}}void @__cxa_deleted_virtual()