Index: clang/lib/CodeGen/CGVTables.cpp =================================================================== --- clang/lib/CodeGen/CGVTables.cpp +++ clang/lib/CodeGen/CGVTables.cpp @@ -1255,12 +1255,15 @@ CharUnits PointerWidth = Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerWidth(0)); - typedef std::pair AddressPoint; + // tuple of {base, address point, vtable end} + typedef std::tuple AddressPoint; std::vector AddressPoints; - for (auto &&AP : VTLayout.getAddressPoints()) - AddressPoints.push_back(std::make_pair( - AP.first.getBase(), VTLayout.getVTableOffset(AP.second.VTableIndex) + - AP.second.AddressPointIndex)); + for (auto &&AP : VTLayout.getAddressPoints()) { + unsigned VTableOffset = VTLayout.getVTableOffset(AP.second.VTableIndex); + unsigned APOffset = VTableOffset + AP.second.AddressPointIndex; + unsigned End = VTableOffset + VTLayout.getVTableSize(AP.second.VTableIndex); + AddressPoints.push_back(std::make_tuple(AP.first.getBase(), APOffset, End)); + } // Sort the address points for determinism. llvm::sort(AddressPoints, [this](const AddressPoint &AP1, @@ -1271,13 +1274,13 @@ std::string S1; llvm::raw_string_ostream O1(S1); getCXXABI().getMangleContext().mangleTypeName( - QualType(AP1.first->getTypeForDecl(), 0), O1); + QualType(std::get<0>(AP1)->getTypeForDecl(), 0), O1); O1.flush(); std::string S2; llvm::raw_string_ostream O2(S2); getCXXABI().getMangleContext().mangleTypeName( - QualType(AP2.first->getTypeForDecl(), 0), O2); + QualType(std::get<0>(AP2)->getTypeForDecl(), 0), O2); O2.flush(); if (S1 < S2) @@ -1285,13 +1288,14 @@ if (S1 != S2) return false; - return AP1.second < AP2.second; + return std::get<1>(AP1) < std::get<1>(AP2); }); ArrayRef Comps = VTLayout.vtable_components(); for (auto AP : AddressPoints) { // Create type metadata for the address point. - AddVTableTypeMetadata(VTable, PointerWidth * AP.second, AP.first); + AddVTableTypeMetadata(VTable, PointerWidth * std::get<1>(AP), + std::get<0>(AP)); // The class associated with each address point could also potentially be // used for indirect calls via a member function pointer, so we need to @@ -1303,7 +1307,7 @@ llvm::Metadata *MD = CreateMetadataIdentifierForVirtualMemPtrType( Context.getMemberPointerType( Comps[I].getFunctionDecl()->getType(), - Context.getRecordType(AP.first).getTypePtr())); + Context.getRecordType(std::get<0>(AP)).getTypePtr())); VTable->addTypeMetadata((PointerWidth * I).getQuantity(), MD); } } @@ -1313,7 +1317,33 @@ llvm::DenseSet Visited; llvm::GlobalObject::VCallVisibility TypeVis = GetVCallVisibilityLevel(RD, Visited); - if (TypeVis != llvm::GlobalObject::VCallVisibilityPublic) - VTable->setVCallVisibilityMetadata(TypeVis); + if (TypeVis != llvm::GlobalObject::VCallVisibilityPublic) { + std::set VisitedAddressPointOffsets; + for (auto AP : AddressPoints) { + size_t AddressPointOffset = std::get<1>(AP); + size_t VTableEnd = std::get<2>(AP); + + if (VisitedAddressPointOffsets.count(AddressPointOffset)) + continue; + VisitedAddressPointOffsets.insert(AddressPointOffset); + + // Create !vcall_visibility metadata describing the range of + // [address point, vtable end). + VTable->addMetadata( + llvm::LLVMContext::MD_vcall_visibility, + *llvm::MDNode::get( + getLLVMContext(), + { + llvm::ConstantAsMetadata::get(llvm::ConstantInt::get( + llvm::Type::getInt64Ty(getLLVMContext()), TypeVis)), + llvm::ConstantAsMetadata::get(llvm::ConstantInt::get( + llvm::Type::getInt64Ty(getLLVMContext()), + (PointerWidth * AddressPointOffset).getQuantity())), + llvm::ConstantAsMetadata::get(llvm::ConstantInt::get( + llvm::Type::getInt64Ty(getLLVMContext()), + (PointerWidth * VTableEnd).getQuantity())), + })); + } + } } } Index: clang/test/CodeGenCXX/vcall-visibility-metadata-ranges.cpp =================================================================== --- /dev/null +++ clang/test/CodeGenCXX/vcall-visibility-metadata-ranges.cpp @@ -0,0 +1,85 @@ +// RUN: %clang_cc1 -flto -flto-unit -triple x86_64-unknown-linux -emit-llvm -fvirtual-function-elimination -fwhole-program-vtables -fno-rtti -o - %s | FileCheck %s + +// +// (1) Base class with DSO visibility +// + +class __attribute__((visibility("hidden"))) Base1 { + virtual void baseFunc() { } +}; +void *new_Base1() { return new Base1(); } + +// CHECK: @_ZTV5Base1 = {{.*}} constant { [3 x i8*] } { [3 x i8*] [ +// CHECK-SAME: i8* null +// CHECK-SAME: i8* null +// CHECK-SAME: i8* bitcast (void (%class.Base1*)* @_ZN5Base18baseFuncEv to i8*) +// CHECK-SAME: ] }, {{.*}} !vcall_visibility [[VIS_BASE1:![0-9]+]] + + + +// +// (2) A subclass with TU visibility, so the vtable should have one part with DSO visibility (from the superclass) and one part with TU visibility +// + +namespace { +class Sub : public Base1 { + virtual void baseFunc() { } + virtual void subOnlyFunc() { } +}; +} +void *new_Sub() { return new Sub(); } + +// CHECK: @_ZTVN12_GLOBAL__N_13SubE = {{.*}} constant { [4 x i8*] } { [4 x i8*] [ +// CHECK-SAME: i8* null +// CHECK-SAME: i8* null +// CHECK-SAME: i8* bitcast (void (%"class.(anonymous namespace)::Sub"*)* @_ZN12_GLOBAL__N_13Sub8baseFuncEv to i8*) +// CHECK-SAME: i8* bitcast (void (%"class.(anonymous namespace)::Sub"*)* @_ZN12_GLOBAL__N_13Sub11subOnlyFuncEv to i8*) +// CHECK-SAME: ] }, {{.*}}, !vcall_visibility [[VIS_SUB:![0-9]+]] + + + +// +// (3) A subclass with multiple inheritance +// + +namespace { +struct __attribute__((visibility("hidden"))) Base2 { + virtual void secondBaseFunc() { } +}; +} +void *new_Base2() { return new Base2(); } + +namespace { +class MultipleInheritanceSub : public Base1, public Base2 { + virtual void baseFunc() { } + virtual void secondBaseFunc() { } + virtual void anotherSubOnlyFunc() { } +}; +} +void *new_MultipleInheritanceSub() { return new MultipleInheritanceSub(); } + +// CHECK: @_ZTVN12_GLOBAL__N_122MultipleInheritanceSubE = {{.*}} constant { [5 x i8*], [3 x i8*] } { +// CHECK-SAME: [5 x i8*] [ +// CHECK-SAME: i8* null, +// CHECK-SAME i8* null, +// CHECK-SAME: i8* bitcast (void (%"class.(anonymous namespace)::MultipleInheritanceSub"*)* @_ZN12_GLOBAL__N_122MultipleInheritanceSub8baseFuncEv to i8*), +// CHECK-SAME: i8* bitcast (void (%"class.(anonymous namespace)::MultipleInheritanceSub"*)* @_ZN12_GLOBAL__N_122MultipleInheritanceSub14secondBaseFuncEv to i8*), +// CHECK-SAME: i8* bitcast (void (%"class.(anonymous namespace)::MultipleInheritanceSub"*)* @_ZN12_GLOBAL__N_122MultipleInheritanceSub18anotherSubOnlyFuncEv to i8*) +// CHECK-SAME: ], +// CHECK-SAME: [3 x i8*] [ +// CHECK-SAME: i8* inttoptr (i64 -8 to i8*), +// CHECK-SAME: i8* null, +// CHECK-SAME: i8* bitcast (void (%"class.(anonymous namespace)::MultipleInheritanceSub"*)* @_ZThn8_N12_GLOBAL__N_122MultipleInheritanceSub14secondBaseFuncEv to i8*) +// CHECK-SAME: ] +// CHECK-SAME: }, {{.*}}, !vcall_visibility [[VIS_MUL_BASE1:![0-9]+]], !vcall_visibility [[VIS_MUL_BASE2:![0-9]+]] + + + +// +// Metadata +// + +// CHECK-DAG: [[VIS_BASE1]] = !{i64 1, i64 16, i64 24} +// CHECK-DAG: [[VIS_SUB]] = !{i64 1, i64 16, i64 32} +// CHECK-DAG: [[VIS_MUL_BASE1]] = !{i64 1, i64 16, i64 40} +// CHECK-DAG: [[VIS_MUL_BASE2]] = !{i64 1, i64 56, i64 64} Index: clang/test/CodeGenCXX/vcall-visibility-metadata.cpp =================================================================== --- clang/test/CodeGenCXX/vcall-visibility-metadata.cpp +++ clang/test/CodeGenCXX/vcall-visibility-metadata.cpp @@ -8,7 +8,7 @@ // Anonymous namespace. namespace { -// CHECK: @_ZTVN12_GLOBAL__N_11AE = {{.*}} !vcall_visibility [[VIS_TU:![0-9]+]] +// CHECK: @_ZTVN12_GLOBAL__N_11AE = {{.*}} !vcall_visibility [[VIS_TU_A:![0-9]+]] // CHECK-MS: @anon.{{.*}} = private unnamed_addr constant {{.*}}struct.(anonymous namespace)::A{{.*}} !vcall_visibility [[VIS_TU:![0-9]+]] struct A { A() {} @@ -21,7 +21,7 @@ // Hidden visibility. -// CHECK: @_ZTV1B = {{.*}} !vcall_visibility [[VIS_DSO:![0-9]+]] +// CHECK: @_ZTV1B = {{.*}} !vcall_visibility [[VIS_DSO_B:![0-9]+]] // CHECK-MS: @anon.{{.*}} = private unnamed_addr constant {{.*}}struct.B{{.*}} !vcall_visibility [[VIS_DSO:![0-9]+]] struct __attribute__((visibility("hidden"))) B { B() {} @@ -100,8 +100,8 @@ // CHECK-MS-DAG: [[VIS_DSO]] = !{i64 1} // CHECK-MS-DAG: [[VIS_TU]] = !{i64 2} -// CHECK-DAG: [[VIS_DSO]] = !{i64 1} -// CHECK-DAG: [[VIS_TU]] = !{i64 2} +// CHECK-DAG: [[VIS_DSO_B]] = !{i64 1, i64 16, i64 24} +// CHECK-DAG: [[VIS_TU_A]] = !{i64 2, i64 16, i64 24} // CHECK-VFE-DAG: !{i32 1, !"Virtual Function Elim", i32 1} // CHECK-NOVFE-DAG: !{i32 1, !"Virtual Function Elim", i32 0}