diff --git a/clang/test/CodeGenCXX/vcall-visibility-metadata.cpp b/clang/test/CodeGenCXX/vcall-visibility-metadata.cpp --- a/clang/test/CodeGenCXX/vcall-visibility-metadata.cpp +++ b/clang/test/CodeGenCXX/vcall-visibility-metadata.cpp @@ -1,6 +1,9 @@ // RUN: %clang_cc1 -flto -flto-unit -triple x86_64-unknown-linux -emit-llvm -fvirtual-function-elimination -fwhole-program-vtables -o - %s | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-VFE // RUN: %clang_cc1 -flto -flto-unit -triple x86_64-unknown-linux -emit-llvm -fwhole-program-vtables -o - %s | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-NOVFE +// Check that in ThinLTO we also get vcall_visibility summary entries in the bitcode +// RUN: %clang_cc1 -flto=thin -flto-unit -triple x86_64-unknown-linux -emit-llvm-bc -fwhole-program-vtables -o - %s | llvm-dis -o - | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-NOVFE --check-prefix=CHECK-SUMMARY + // Anonymous namespace. namespace { @@ -88,3 +91,11 @@ // CHECK-DAG: [[VIS_TU]] = !{i64 2} // CHECK-VFE-DAG: !{i32 1, !"Virtual Function Elim", i32 1} // CHECK-NOVFE-DAG: !{i32 1, !"Virtual Function Elim", i32 0} + +// CHECK-SUMMARY-DAG: gv: (name: "_ZTV1B", {{.*}} vcall_visibility: 1 +// CHECK-SUMMARY-DAG: gv: (name: "_ZTVN12_GLOBAL__N_11FE", {{.*}} vcall_visibility: 0 +// CHECK-SUMMARY-DAG: gv: (name: "_ZTV1D", {{.*}} vcall_visibility: 0 +// CHECK-SUMMARY-DAG: gv: (name: "_ZTV1C", {{.*}} vcall_visibility: 0 +// CHECK-SUMMARY-DAG: gv: (name: "_ZTV1E", {{.*}} vcall_visibility: 0 +// CHECK-SUMMARY-DAG: gv: (name: "_ZTVN12_GLOBAL__N_11AE", {{.*}} vcall_visibility: 2 +// CHECK-SUMMARY-DAG: gv: (name: "_ZTVN12_GLOBAL__N_11GE", {{.*}} vcall_visibility: 1 diff --git a/llvm/include/llvm/IR/ModuleSummaryIndex.h b/llvm/include/llvm/IR/ModuleSummaryIndex.h --- a/llvm/include/llvm/IR/ModuleSummaryIndex.h +++ b/llvm/include/llvm/IR/ModuleSummaryIndex.h @@ -757,14 +757,20 @@ public: struct GVarFlags { - GVarFlags(bool ReadOnly, bool WriteOnly) - : MaybeReadOnly(ReadOnly), MaybeWriteOnly(WriteOnly) {} + GVarFlags( + bool ReadOnly, bool WriteOnly, + GlobalObject::VCallVisibility Vis = GlobalObject::VCallVisibilityPublic) + : MaybeReadOnly(ReadOnly), MaybeWriteOnly(WriteOnly), + VCallVisibility(Vis) {} // In permodule summaries both MaybeReadOnly and MaybeWriteOnly // bits are set, because attribute propagation occurs later on // thin link phase. unsigned MaybeReadOnly : 1; unsigned MaybeWriteOnly : 1; + // Set from metadata on vtable definitions during the module summary + // analysis. + unsigned VCallVisibility : 2; } VarFlags; GlobalVarSummary(GVFlags Flags, GVarFlags VarFlags, @@ -782,6 +788,12 @@ void setWriteOnly(bool WO) { VarFlags.MaybeWriteOnly = WO; } bool maybeReadOnly() const { return VarFlags.MaybeReadOnly; } bool maybeWriteOnly() const { return VarFlags.MaybeWriteOnly; } + void setVCallVisibility(GlobalObject::VCallVisibility Vis) { + VarFlags.VCallVisibility = Vis; + } + GlobalObject::VCallVisibility getVCallVisibility() const { + return (GlobalObject::VCallVisibility)VarFlags.VCallVisibility; + } void setVTableFuncs(VTableFuncList Funcs) { assert(!VTableFuncs); diff --git a/llvm/lib/Analysis/ModuleSummaryAnalysis.cpp b/llvm/lib/Analysis/ModuleSummaryAnalysis.cpp --- a/llvm/lib/Analysis/ModuleSummaryAnalysis.cpp +++ b/llvm/lib/Analysis/ModuleSummaryAnalysis.cpp @@ -599,7 +599,8 @@ bool CanBeInternalized = !V.hasComdat() && !V.hasAppendingLinkage() && !V.isInterposable() && !V.hasAvailableExternallyLinkage() && !V.hasDLLExportStorageClass(); - GlobalVarSummary::GVarFlags VarFlags(CanBeInternalized, CanBeInternalized); + GlobalVarSummary::GVarFlags VarFlags(CanBeInternalized, CanBeInternalized, + V.getVCallVisibility()); auto GVarSummary = std::make_unique(Flags, VarFlags, RefEdges.takeVector()); if (NonRenamableLocal) diff --git a/llvm/lib/AsmParser/LLLexer.cpp b/llvm/lib/AsmParser/LLLexer.cpp --- a/llvm/lib/AsmParser/LLLexer.cpp +++ b/llvm/lib/AsmParser/LLLexer.cpp @@ -788,6 +788,7 @@ KEYWORD(sizeM1); KEYWORD(bitMask); KEYWORD(inlineBits); + KEYWORD(vcall_visibility); KEYWORD(wpdResolutions); KEYWORD(wpdRes); KEYWORD(indir); diff --git a/llvm/lib/AsmParser/LLParser.cpp b/llvm/lib/AsmParser/LLParser.cpp --- a/llvm/lib/AsmParser/LLParser.cpp +++ b/llvm/lib/AsmParser/LLParser.cpp @@ -8856,6 +8856,11 @@ return true; GVarFlags.MaybeWriteOnly = Flag; break; + case lltok::kw_vcall_visibility: + if (ParseRest(Flag)) + return true; + GVarFlags.VCallVisibility = Flag; + break; default: return Error(Lex.getLoc(), "expected gvar flag type"); } diff --git a/llvm/lib/AsmParser/LLToken.h b/llvm/lib/AsmParser/LLToken.h --- a/llvm/lib/AsmParser/LLToken.h +++ b/llvm/lib/AsmParser/LLToken.h @@ -421,6 +421,7 @@ kw_sizeM1, kw_bitMask, kw_inlineBits, + kw_vcall_visibility, kw_wpdResolutions, kw_wpdRes, kw_indir, diff --git a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp --- a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp +++ b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp @@ -985,8 +985,9 @@ // Decode the flags for GlobalVariable in the summary static GlobalVarSummary::GVarFlags getDecodedGVarFlags(uint64_t RawFlags) { - return GlobalVarSummary::GVarFlags((RawFlags & 0x1) ? true : false, - (RawFlags & 0x2) ? true : false); + return GlobalVarSummary::GVarFlags( + (RawFlags & 0x1) ? true : false, (RawFlags & 0x2) ? true : false, + (GlobalObject::VCallVisibility)(RawFlags >> 2)); } static GlobalValue::VisibilityTypes getDecodedVisibility(unsigned Val) { diff --git a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp --- a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp +++ b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp @@ -1028,7 +1028,8 @@ } static uint64_t getEncodedGVarFlags(GlobalVarSummary::GVarFlags Flags) { - uint64_t RawFlags = Flags.MaybeReadOnly | (Flags.MaybeWriteOnly << 1); + uint64_t RawFlags = Flags.MaybeReadOnly | (Flags.MaybeWriteOnly << 1) | + Flags.VCallVisibility << 2; return RawFlags; } diff --git a/llvm/lib/IR/AsmWriter.cpp b/llvm/lib/IR/AsmWriter.cpp --- a/llvm/lib/IR/AsmWriter.cpp +++ b/llvm/lib/IR/AsmWriter.cpp @@ -2896,10 +2896,14 @@ } void AssemblyWriter::printGlobalVarSummary(const GlobalVarSummary *GS) { + auto VTableFuncs = GS->vTableFuncs(); Out << ", varFlags: (readonly: " << GS->VarFlags.MaybeReadOnly << ", " - << "writeonly: " << GS->VarFlags.MaybeWriteOnly << ")"; + << "writeonly: " << GS->VarFlags.MaybeWriteOnly; + if (!VTableFuncs.empty()) + Out << ", " + << "vcall_visibility: " << GS->VarFlags.VCallVisibility; + Out << ")"; - auto VTableFuncs = GS->vTableFuncs(); if (!VTableFuncs.empty()) { Out << ", vTableFuncs: ("; FieldSeparator FS; diff --git a/llvm/test/Assembler/thinlto-vtable-summary.ll b/llvm/test/Assembler/thinlto-vtable-summary.ll --- a/llvm/test/Assembler/thinlto-vtable-summary.ll +++ b/llvm/test/Assembler/thinlto-vtable-summary.ll @@ -29,9 +29,9 @@ ^0 = module: (path: "", hash: (0, 0, 0, 0, 0)) ^1 = gv: (name: "_ZN1A1nEi") ; guid = 1621563287929432257 -^2 = gv: (name: "_ZTV1B", summaries: (variable: (module: ^0, flags: (linkage: external, notEligibleToImport: 0, live: 0, dsoLocal: 0, canAutoHide: 0), varFlags: (readonly: 0, writeonly: 0), vTableFuncs: ((virtFunc: ^3, offset: 16), (virtFunc: ^1, offset: 24)), refs: (^3, ^1)))) ; guid = 5283576821522790367 +^2 = gv: (name: "_ZTV1B", summaries: (variable: (module: ^0, flags: (linkage: external, notEligibleToImport: 0, live: 0, dsoLocal: 0, canAutoHide: 0), varFlags: (readonly: 0, writeonly: 0, vcall_visibility: 0), vTableFuncs: ((virtFunc: ^3, offset: 16), (virtFunc: ^1, offset: 24)), refs: (^3, ^1)))) ; guid = 5283576821522790367 ^3 = gv: (name: "_ZN1B1fEi") ; guid = 7162046368816414394 -^4 = gv: (name: "_ZTV1C", summaries: (variable: (module: ^0, flags: (linkage: external, notEligibleToImport: 0, live: 0, dsoLocal: 0, canAutoHide: 0), varFlags: (readonly: 0, writeonly: 0), vTableFuncs: ((virtFunc: ^5, offset: 16), (virtFunc: ^1, offset: 24)), refs: (^1, ^5)))) ; guid = 13624023785555846296 +^4 = gv: (name: "_ZTV1C", summaries: (variable: (module: ^0, flags: (linkage: external, notEligibleToImport: 0, live: 0, dsoLocal: 0, canAutoHide: 0), varFlags: (readonly: 0, writeonly: 0, vcall_visibility: 0), vTableFuncs: ((virtFunc: ^5, offset: 16), (virtFunc: ^1, offset: 24)), refs: (^1, ^5)))) ; guid = 13624023785555846296 ^5 = gv: (name: "_ZN1C1fEi") ; guid = 14876272565662207556 ^6 = typeidCompatibleVTable: (name: "_ZTS1A", summary: ((offset: 16, ^2), (offset: 16, ^4))) ; guid = 7004155349499253778 ^7 = typeidCompatibleVTable: (name: "_ZTS1B", summary: ((offset: 16, ^2))) ; guid = 6203814149063363976