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,9 +757,10 @@ public: struct GVarFlags { - GVarFlags(bool ReadOnly, bool WriteOnly, bool Constant) + GVarFlags(bool ReadOnly, bool WriteOnly, bool Constant, + GlobalObject::VCallVisibility Vis) : MaybeReadOnly(ReadOnly), MaybeWriteOnly(WriteOnly), - Constant(Constant) {} + Constant(Constant), VCallVisibility(Vis) {} // If true indicates that this global variable might be accessed // purely by non-volatile load instructions. This in turn means @@ -780,6 +781,9 @@ // opportunity to make some extra optimizations. Readonly constants // are also internalized. unsigned Constant : 1; + // Set from metadata on vtable definitions during the module summary + // analysis. + unsigned VCallVisibility : 2; } VarFlags; GlobalVarSummary(GVFlags Flags, GVarFlags VarFlags, @@ -798,6 +802,12 @@ bool maybeReadOnly() const { return VarFlags.MaybeReadOnly; } bool maybeWriteOnly() const { return VarFlags.MaybeWriteOnly; } bool isConstant() const { return VarFlags.Constant; } + 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 @@ -600,8 +600,9 @@ !V.hasComdat() && !V.hasAppendingLinkage() && !V.isInterposable() && !V.hasAvailableExternallyLinkage() && !V.hasDLLExportStorageClass(); bool Constant = V.isConstant(); - GlobalVarSummary::GVarFlags VarFlags( - CanBeInternalized, Constant ? false : CanBeInternalized, Constant); + GlobalVarSummary::GVarFlags VarFlags(CanBeInternalized, + Constant ? false : CanBeInternalized, + Constant, V.getVCallVisibility()); auto GVarSummary = std::make_unique(Flags, VarFlags, RefEdges.takeVector()); if (NonRenamableLocal) @@ -722,7 +723,8 @@ std::make_unique( GVFlags, GlobalVarSummary::GVarFlags( - false, false, cast(GV)->isConstant()), + false, false, cast(GV)->isConstant(), + GlobalObject::VCallVisibilityPublic), ArrayRef{}); Index.addGlobalValueSummary(*GV, std::move(Summary)); } 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 @@ -8154,7 +8154,8 @@ /*Live=*/false, /*IsLocal=*/false, /*CanAutoHide=*/false); GlobalVarSummary::GVarFlags GVarFlags(/*ReadOnly*/ false, /* WriteOnly */ false, - /* Constant */ false); + /* Constant */ false, + GlobalObject::VCallVisibilityPublic); std::vector Refs; VTableFuncList VTableFuncs; if (ParseToken(lltok::colon, "expected ':' here") || @@ -8861,6 +8862,11 @@ return true; GVarFlags.Constant = 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,9 +985,10 @@ // 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, - (RawFlags & 0x4) ? true : false); + return GlobalVarSummary::GVarFlags( + (RawFlags & 0x1) ? true : false, (RawFlags & 0x2) ? true : false, + (RawFlags & 0x4) ? true : false, + (GlobalObject::VCallVisibility)(RawFlags >> 3)); } static GlobalValue::VisibilityTypes getDecodedVisibility(unsigned Val) { @@ -5969,7 +5970,8 @@ unsigned RefArrayStart = 2; GlobalVarSummary::GVarFlags GVF(/* ReadOnly */ false, /* WriteOnly */ false, - /* Constant */ false); + /* Constant */ false, + GlobalObject::VCallVisibilityPublic); auto Flags = getDecodedGVSummaryFlags(RawFlags, Version); if (Version >= 5) { GVF = getDecodedGVarFlags(Record[2]); @@ -6106,7 +6108,8 @@ unsigned RefArrayStart = 3; GlobalVarSummary::GVarFlags GVF(/* ReadOnly */ false, /* WriteOnly */ false, - /* Constant */ false); + /* Constant */ false, + GlobalObject::VCallVisibilityPublic); auto Flags = getDecodedGVSummaryFlags(RawFlags, Version); if (Version >= 5) { GVF = getDecodedGVarFlags(Record[3]); 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,8 +1028,8 @@ } static uint64_t getEncodedGVarFlags(GlobalVarSummary::GVarFlags Flags) { - uint64_t RawFlags = - Flags.MaybeReadOnly | (Flags.MaybeWriteOnly << 1) | (Flags.Constant << 2); + uint64_t RawFlags = Flags.MaybeReadOnly | (Flags.MaybeWriteOnly << 1) | + (Flags.Constant << 2) | Flags.VCallVisibility << 3; 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 @@ -2900,11 +2900,15 @@ } void AssemblyWriter::printGlobalVarSummary(const GlobalVarSummary *GS) { + auto VTableFuncs = GS->vTableFuncs(); Out << ", varFlags: (readonly: " << GS->VarFlags.MaybeReadOnly << ", " << "writeonly: " << GS->VarFlags.MaybeWriteOnly << ", " - << "constant: " << GS->VarFlags.Constant << ")"; + << "constant: " << GS->VarFlags.Constant; + 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, constant: 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, constant: 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, constant: 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, constant: 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