diff --git a/clang/test/CodeGen/thinlto-distributed-cfi-devirt.ll b/clang/test/CodeGen/thinlto-distributed-cfi-devirt.ll --- a/clang/test/CodeGen/thinlto-distributed-cfi-devirt.ll +++ b/clang/test/CodeGen/thinlto-distributed-cfi-devirt.ll @@ -36,7 +36,7 @@ ; Round trip it through llvm-as ; RUN: llvm-dis %t.o.thinlto.bc -o - | llvm-as -o - | llvm-dis -o - | FileCheck %s --check-prefix=CHECK-DIS ; CHECK-DIS: ^0 = module: (path: "{{.*}}thinlto-distributed-cfi-devirt.ll.tmp.o", hash: ({{.*}}, {{.*}}, {{.*}}, {{.*}}, {{.*}})) -; CHECK-DIS: ^1 = gv: (guid: 8346051122425466633, summaries: (function: (module: ^0, flags: (linkage: external, visibility: default, notEligibleToImport: 0, live: 1, dsoLocal: 0, canAutoHide: 0), insts: 18, funcFlags: (readNone: 0, readOnly: 0, noRecurse: 0, returnDoesNotAlias: 0, noInline: 0, alwaysInline: 0, noUnwind: 0, mayThrow: 0, hasUnknownCall: 1), typeIdInfo: (typeTests: (^2), typeCheckedLoadVCalls: (vFuncId: (^2, offset: 8), vFuncId: (^2, offset: 0)))))) +; CHECK-DIS: ^1 = gv: (guid: 8346051122425466633, summaries: (function: (module: ^0, flags: (linkage: external, visibility: default, notEligibleToImport: 0, live: 1, dsoLocal: 0, canAutoHide: 0), insts: 18, funcFlags: (readNone: 0, readOnly: 0, noRecurse: 0, returnDoesNotAlias: 0, noInline: 0, alwaysInline: 0, noUnwind: 0, mayThrow: 0, hasUnknownCall: 1, mustBeUnreachable: 0), typeIdInfo: (typeTests: (^2), typeCheckedLoadVCalls: (vFuncId: (^2, offset: 8), vFuncId: (^2, offset: 0)))))) ; CHECK-DIS: ^2 = typeid: (name: "_ZTS1A", summary: (typeTestRes: (kind: allOnes, sizeM1BitWidth: 7), wpdResolutions: ((offset: 0, wpdRes: (kind: branchFunnel)), (offset: 8, wpdRes: (kind: singleImpl, singleImplName: "_ZN1A1nEi"))))) ; guid = 7004155349499253778 ; RUN: %clang_cc1 -triple x86_64-grtev4-linux-gnu \ diff --git a/clang/test/CodeGen/thinlto-distributed-cfi.ll b/clang/test/CodeGen/thinlto-distributed-cfi.ll --- a/clang/test/CodeGen/thinlto-distributed-cfi.ll +++ b/clang/test/CodeGen/thinlto-distributed-cfi.ll @@ -24,7 +24,7 @@ ; Round trip it through llvm-as ; RUN: llvm-dis %t.o.thinlto.bc -o - | llvm-as -o - | llvm-dis -o - | FileCheck %s --check-prefix=CHECK-DIS ; CHECK-DIS: ^0 = module: (path: "{{.*}}thinlto-distributed-cfi.ll.tmp.o", hash: ({{.*}}, {{.*}}, {{.*}}, {{.*}}, {{.*}})) -; CHECK-DIS: ^1 = gv: (guid: 8346051122425466633, summaries: (function: (module: ^0, flags: (linkage: external, visibility: default, notEligibleToImport: 0, live: 1, dsoLocal: 0, canAutoHide: 0), insts: 7, funcFlags: (readNone: 0, readOnly: 0, noRecurse: 1, returnDoesNotAlias: 0, noInline: 0, alwaysInline: 0, noUnwind: 1, mayThrow: 0, hasUnknownCall: 0), typeIdInfo: (typeTests: (^2))))) +; CHECK-DIS: ^1 = gv: (guid: 8346051122425466633, summaries: (function: (module: ^0, flags: (linkage: external, visibility: default, notEligibleToImport: 0, live: 1, dsoLocal: 0, canAutoHide: 0), insts: 7, funcFlags: (readNone: 0, readOnly: 0, noRecurse: 1, returnDoesNotAlias: 0, noInline: 0, alwaysInline: 0, noUnwind: 1, mayThrow: 0, hasUnknownCall: 0, mustBeUnreachable: 0), typeIdInfo: (typeTests: (^2))))) ; CHECK-DIS: ^2 = typeid: (name: "_ZTS1A", summary: (typeTestRes: (kind: single, sizeM1BitWidth: 0))) ; guid = 7004155349499253778 ; RUN: %clang_cc1 -triple x86_64-grtev4-linux-gnu \ diff --git a/clang/test/CodeGen/thinlto-funcattr-prop.ll b/clang/test/CodeGen/thinlto-funcattr-prop.ll --- a/clang/test/CodeGen/thinlto-funcattr-prop.ll +++ b/clang/test/CodeGen/thinlto-funcattr-prop.ll @@ -17,7 +17,7 @@ ;; Summary for call_extern. Note that llvm-lto2 writes out the index before propagation occurs so call_extern doesn't have its flags updated. ; CHECK-INDEX: ^2 = gv: (guid: 13959900437860518209, summaries: (function: (module: ^0, flags: (linkage: external, visibility: default, notEligibleToImport: 0, live: 1, dsoLocal: 1, canAutoHide: 0), insts: 2, calls: ((callee: ^3))))) ;; Summary for extern -; CHECK-INDEX: ^3 = gv: (guid: 14959766916849974397, summaries: (function: (module: ^1, flags: (linkage: external, visibility: default, notEligibleToImport: 0, live: 1, dsoLocal: 0, canAutoHide: 0), insts: 1, funcFlags: (readNone: 0, readOnly: 0, noRecurse: 1, returnDoesNotAlias: 0, noInline: 0, alwaysInline: 0, noUnwind: 1, mayThrow: 0, hasUnknownCall: 0)))) +; CHECK-INDEX: ^3 = gv: (guid: 14959766916849974397, summaries: (function: (module: ^1, flags: (linkage: external, visibility: default, notEligibleToImport: 0, live: 1, dsoLocal: 0, canAutoHide: 0), insts: 1, funcFlags: (readNone: 0, readOnly: 0, noRecurse: 1, returnDoesNotAlias: 0, noInline: 0, alwaysInline: 0, noUnwind: 1, mayThrow: 0, hasUnknownCall: 0, mustBeUnreachable: 0)))) ;--- a.ll target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" diff --git a/llvm/include/llvm/AsmParser/LLToken.h b/llvm/include/llvm/AsmParser/LLToken.h --- a/llvm/include/llvm/AsmParser/LLToken.h +++ b/llvm/include/llvm/AsmParser/LLToken.h @@ -407,6 +407,7 @@ kw_noUnwind, kw_mayThrow, kw_hasUnknownCall, + kw_mustBeUnreachable, kw_calls, kw_callee, kw_params, 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 @@ -581,6 +581,13 @@ // If there are calls to unknown targets (e.g. indirect) unsigned HasUnknownCall : 1; + // Indicate if a function must be an unreachable function. + // + // This bit is sufficient but not necessary; + // if this bit is on, the function must be regarded as unreachable; + // if this bit is off, the function might be reachable or unreachable. + unsigned MustBeUnreachable : 1; + FFlags &operator&=(const FFlags &RHS) { this->ReadNone &= RHS.ReadNone; this->ReadOnly &= RHS.ReadOnly; @@ -591,13 +598,15 @@ this->NoUnwind &= RHS.NoUnwind; this->MayThrow &= RHS.MayThrow; this->HasUnknownCall &= RHS.HasUnknownCall; + this->MustBeUnreachable &= RHS.MustBeUnreachable; return *this; } bool anyFlagSet() { return this->ReadNone | this->ReadOnly | this->NoRecurse | this->ReturnDoesNotAlias | this->NoInline | this->AlwaysInline | - this->NoUnwind | this->MayThrow | this->HasUnknownCall; + this->NoUnwind | this->MayThrow | this->HasUnknownCall | + this->MustBeUnreachable; } operator std::string() { @@ -613,6 +622,7 @@ OS << ", noUnwind: " << this->NoUnwind; OS << ", mayThrow: " << this->MayThrow; OS << ", hasUnknownCall: " << this->HasUnknownCall; + OS << ", mustBeUnreachable: " << this->MustBeUnreachable; OS << ")"; return OS.str(); } 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 @@ -234,6 +234,26 @@ return false; } +// Returns true if `F` must be an unreachable function. +// +// Note if this helper function returns true, `F` is guaranteed +// to be unreachable; if it returns false, `F` might still +// be unreachble but not covered by this helper function. +static bool mustBeUnreachableFunction(const Function &F) { + if (!F.empty()) { + const BasicBlock &entryBlock = F.getEntryBlock(); + // A function must be unreachable if its entry block + // ends with an 'unreachable'. + if (!entryBlock.empty()) { + const Instruction *inst = &(*entryBlock.rbegin()); + if (inst->getOpcode() == Instruction::Unreachable) { + return true; + } + } + } + return false; +} + static void computeFunctionSummary( ModuleSummaryIndex &Index, const Module &M, const Function &F, BlockFrequencyInfo *BFI, ProfileSummaryInfo *PSI, DominatorTree &DT, @@ -488,7 +508,8 @@ // Don't try to import functions with noinline attribute. F.getAttributes().hasFnAttr(Attribute::NoInline), F.hasFnAttribute(Attribute::AlwaysInline), - F.hasFnAttribute(Attribute::NoUnwind), MayThrow, HasUnknownCall}; + F.hasFnAttribute(Attribute::NoUnwind), MayThrow, HasUnknownCall, + mustBeUnreachableFunction(F)}; std::vector ParamAccesses; if (auto *SSI = GetSSICallback(F)) ParamAccesses = SSI->getParamAccesses(Index); @@ -737,7 +758,8 @@ F->hasFnAttribute(Attribute::AlwaysInline), F->hasFnAttribute(Attribute::NoUnwind), /* MayThrow */ true, - /* HasUnknownCall */ true}, + /* HasUnknownCall */ true, + /* MustBeUnreachable */ false}, /*EntryCount=*/0, ArrayRef{}, ArrayRef{}, ArrayRef{}, 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 @@ -773,6 +773,7 @@ KEYWORD(noUnwind); KEYWORD(mayThrow); KEYWORD(hasUnknownCall); + KEYWORD(mustBeUnreachable); KEYWORD(calls); KEYWORD(callee); KEYWORD(params); 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 @@ -8534,6 +8534,7 @@ /// [',' 'noUnwind' ':' Flag]? ')' /// [',' 'mayThrow' ':' Flag]? ')' /// [',' 'hasUnknownCall' ':' Flag]? ')' +/// [',' 'mustBeUnreachable' ':' Flag]? ')' bool LLParser::parseOptionalFFlags(FunctionSummary::FFlags &FFlags) { assert(Lex.getKind() == lltok::kw_funcFlags); @@ -8600,6 +8601,12 @@ return true; FFlags.HasUnknownCall = Val; break; + case lltok::kw_mustBeUnreachable: + Lex.Lex(); + if (parseToken(lltok::colon, "expected ':'") || parseFlag(Val)) + return true; + FFlags.MustBeUnreachable = Val; + break; default: return error(Lex.getLoc(), "expected function flag type"); } 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 @@ -932,6 +932,7 @@ Flags.NoUnwind = (RawFlags >> 6) & 0x1; Flags.MayThrow = (RawFlags >> 7) & 0x1; Flags.HasUnknownCall = (RawFlags >> 8) & 0x1; + Flags.MustBeUnreachable = (RawFlags >> 9) & 0x1; return Flags; } 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 @@ -1066,6 +1066,7 @@ RawFlags |= (Flags.NoUnwind << 6); RawFlags |= (Flags.MayThrow << 7); RawFlags |= (Flags.HasUnknownCall << 8); + RawFlags |= (Flags.MustBeUnreachable << 9); return RawFlags; } diff --git a/llvm/lib/IR/ModuleSummaryIndex.cpp b/llvm/lib/IR/ModuleSummaryIndex.cpp --- a/llvm/lib/IR/ModuleSummaryIndex.cpp +++ b/llvm/lib/IR/ModuleSummaryIndex.cpp @@ -447,11 +447,17 @@ static std::string fflagsToString(FunctionSummary::FFlags F) { auto FlagValue = [](unsigned V) { return V ? '1' : '0'; }; - char FlagRep[] = {FlagValue(F.ReadNone), FlagValue(F.ReadOnly), - FlagValue(F.NoRecurse), FlagValue(F.ReturnDoesNotAlias), - FlagValue(F.NoInline), FlagValue(F.AlwaysInline), - FlagValue(F.NoUnwind), FlagValue(F.MayThrow), - FlagValue(F.HasUnknownCall), 0}; + char FlagRep[] = {FlagValue(F.ReadNone), + FlagValue(F.ReadOnly), + FlagValue(F.NoRecurse), + FlagValue(F.ReturnDoesNotAlias), + FlagValue(F.NoInline), + FlagValue(F.AlwaysInline), + FlagValue(F.NoUnwind), + FlagValue(F.MayThrow), + FlagValue(F.HasUnknownCall), + FlagValue(F.MustBeUnreachable), + 0}; return FlagRep; } diff --git a/llvm/lib/Transforms/IPO/WholeProgramDevirt.cpp b/llvm/lib/Transforms/IPO/WholeProgramDevirt.cpp --- a/llvm/lib/Transforms/IPO/WholeProgramDevirt.cpp +++ b/llvm/lib/Transforms/IPO/WholeProgramDevirt.cpp @@ -562,17 +562,19 @@ void buildTypeIdentifierMap( std::vector &Bits, DenseMap> &TypeIdMap); - bool - tryFindVirtualCallTargets(std::vector &TargetsForSlot, - const std::set &TypeMemberInfos, - uint64_t ByteOffset); + + bool tryFindVirtualCallTargets( + std::vector &TargetsForSlot, + const std::set &TypeMemberInfos, uint64_t ByteOffset, + ModuleSummaryIndex *ExportSummary, const bool IsExported); void applySingleImplDevirt(VTableSlotInfo &SlotInfo, Constant *TheFn, bool &IsExported); bool trySingleImplDevirt(ModuleSummaryIndex *ExportSummary, MutableArrayRef TargetsForSlot, VTableSlotInfo &SlotInfo, - WholeProgramDevirtResolution *Res); + WholeProgramDevirtResolution *Res, + const bool preComputedIsExported); void applyICallBranchFunnel(VTableSlotInfo &SlotInfo, Constant *JT, bool &IsExported); @@ -646,6 +648,20 @@ runForTesting(Module &M, function_ref AARGetter, function_ref OREGetter, function_ref LookupDomTree); + + // Returns true if the function is unreachable from reading function + // summaries. + // + // In particular, identifies a function as unreachable if and only if + // 1) All summaries are live. + // 2) All summaries are function summaries. + // 3) All function summaries indicate it's unreachable. + // + // FIXME: When ExportSummary is absent or not expected to be present (e.g., + // regular LTO), analyze function reachability from IR. + static bool mustBeUnreachableFunction(Function *TheFn, + ModuleSummaryIndex *ExportSummary, + bool IsExported); }; struct DevirtIndex { @@ -933,6 +949,69 @@ return Changed; } +bool DevirtModule::mustBeUnreachableFunction(Function *TheFn, + ModuleSummaryIndex *ExportSummary, + bool IsExported) { + // ExportSummary is absent, so analyze IR directly. + if (ExportSummary == nullptr) { + if (!TheFn->empty()) { + const BasicBlock &entryBlock = TheFn->getEntryBlock(); + // A function must be unreachable if its basic block + // ends with an 'unreachable'. + if (!entryBlock.empty()) { + const Instruction *inst = &(*entryBlock.rbegin()); + if (inst->getOpcode() == Instruction::Unreachable) { + return true; + } + } + } + return false; + } + assert((TheFn != nullptr) && "Caller guarantees that TheFn is not nullptr"); + + // If a function will be exported, use external linkage to get its + // global identifier. + const std::string rewrittenFuncGlobalIdentifier = + GlobalValue::getGlobalIdentifier(TheFn->getName(), + IsExported ? GlobalValue::ExternalLinkage + : TheFn->getLinkage(), + TheFn->getParent()->getSourceFileName()); + + if (ValueInfo TheFnVI = ExportSummary->getValueInfo( + GlobalValue::getGUID(rewrittenFuncGlobalIdentifier))) { + if (TheFnVI.getSummaryList().empty()) { + return false; + } + bool AllSummariesAreFunctionSummary = true; + bool AllSummariesAreLive = true; + bool AllFunctionSummariesIndicateUnreachable = true; + for (auto &Summary : TheFnVI.getSummaryList()) { + if (!Summary->isLive()) { + AllSummariesAreLive = false; + break; + } + if (auto *FS = dyn_cast(Summary.get())) { + if (!FS->fflags().MustBeUnreachable) { + AllFunctionSummariesIndicateUnreachable = false; + break; + } + } else { + AllSummariesAreFunctionSummary = false; + break; + } + } + // Identifies a function as unreachable if and only if + // 1) All summaries are live. + // 2) All summaries are function summaries. + // 3) All function summaries indicate it's unreachable. + if (AllSummariesAreLive && AllSummariesAreFunctionSummary && + AllFunctionSummariesIndicateUnreachable) { + return true; + } + } + return false; +} + void DevirtModule::buildTypeIdentifierMap( std::vector &Bits, DenseMap> &TypeIdMap) { @@ -969,7 +1048,8 @@ bool DevirtModule::tryFindVirtualCallTargets( std::vector &TargetsForSlot, - const std::set &TypeMemberInfos, uint64_t ByteOffset) { + const std::set &TypeMemberInfos, uint64_t ByteOffset, + ModuleSummaryIndex *ExportSummary, const bool IsExported) { for (const TypeMemberInfo &TM : TypeMemberInfos) { if (!TM.Bits->GV->isConstant()) return false; @@ -997,6 +1077,12 @@ if (Fn->getName() == "__cxa_pure_virtual") continue; + // We can disregard unreachable functions as possible call targets, as + // unreachable functions shouldn't be called. + if (mustBeUnreachableFunction(Fn, ExportSummary, IsExported)) { + continue; + } + TargetsForSlot.push_back({Fn, &TM}); } @@ -1141,7 +1227,7 @@ bool DevirtModule::trySingleImplDevirt( ModuleSummaryIndex *ExportSummary, MutableArrayRef TargetsForSlot, VTableSlotInfo &SlotInfo, - WholeProgramDevirtResolution *Res) { + WholeProgramDevirtResolution *Res, const bool preComputedIsExported) { // See if the program contains a single implementation of this virtual // function. Function *TheFn = TargetsForSlot[0].Fn; @@ -2118,6 +2204,21 @@ bool DidVirtualConstProp = false; std::map DevirtTargets; for (auto &S : CallSlots) { + + // Compute whether a function should be exported or not to + // get its linkage type. + // Linkage type is used to compute a functions GUID. + bool precomputedIsExported = false; + VTableSlotInfo &vtableSlotInfo = S.second; + if (vtableSlotInfo.CSInfo.isExported()) { + precomputedIsExported = true; + } + for (auto &P : vtableSlotInfo.ConstCSInfo) { + if (P.second.isExported()) { + precomputedIsExported = true; + } + } + // Search each of the members of the type identifier for the virtual // function implementation at offset S.first.ByteOffset, and add to // TargetsForSlot. @@ -2137,9 +2238,11 @@ cast(S.first.TypeID)->getString()) .WPDRes[S.first.ByteOffset]; if (tryFindVirtualCallTargets(TargetsForSlot, TypeMemberInfos, - S.first.ByteOffset)) { + S.first.ByteOffset, ExportSummary, + precomputedIsExported)) { - if (!trySingleImplDevirt(ExportSummary, TargetsForSlot, S.second, Res)) { + if (!trySingleImplDevirt(ExportSummary, TargetsForSlot, S.second, Res, + precomputedIsExported)) { DidVirtualConstProp |= tryVirtualConstProp(TargetsForSlot, S.second, Res, S.first); diff --git a/llvm/test/Assembler/thinlto-summary.ll b/llvm/test/Assembler/thinlto-summary.ll --- a/llvm/test/Assembler/thinlto-summary.ll +++ b/llvm/test/Assembler/thinlto-summary.ll @@ -82,9 +82,9 @@ ; CHECK: ^12 = gv: (guid: 11, summaries: (variable: (module: ^0, flags: (linkage: appending, visibility: default, notEligibleToImport: 0, live: 0, dsoLocal: 0, canAutoHide: 0), varFlags: (readonly: 0, writeonly: 0, constant: 0), refs: (^4)))) ; CHECK: ^13 = gv: (guid: 12, summaries: (variable: (module: ^0, flags: (linkage: external, visibility: default, notEligibleToImport: 0, live: 0, dsoLocal: 0, canAutoHide: 0), varFlags: (readonly: 1, writeonly: 0, constant: 0)))) ; CHECK: ^14 = gv: (guid: 13, summaries: (variable: (module: ^0, flags: (linkage: external, visibility: default, notEligibleToImport: 0, live: 0, dsoLocal: 1, canAutoHide: 0), varFlags: (readonly: 0, writeonly: 0, constant: 0)))) -; CHECK: ^15 = gv: (guid: 14, summaries: (function: (module: ^1, flags: (linkage: external, visibility: default, notEligibleToImport: 1, live: 1, dsoLocal: 0, canAutoHide: 0), insts: 1, funcFlags: (readNone: 0, readOnly: 0, noRecurse: 0, returnDoesNotAlias: 0, noInline: 1, alwaysInline: 0, noUnwind: 0, mayThrow: 0, hasUnknownCall: 0)))) -; CHECK: ^16 = gv: (guid: 15, summaries: (function: (module: ^1, flags: (linkage: external, visibility: default, notEligibleToImport: 0, live: 0, dsoLocal: 0, canAutoHide: 0), insts: 1, funcFlags: (readNone: 1, readOnly: 0, noRecurse: 1, returnDoesNotAlias: 0, noInline: 0, alwaysInline: 1, noUnwind: 1, mayThrow: 1, hasUnknownCall: 1)))) -; CHECK: ^17 = gv: (guid: 16, summaries: (function: (module: ^1, flags: (linkage: external, visibility: default, notEligibleToImport: 0, live: 0, dsoLocal: 0, canAutoHide: 0), insts: 1, funcFlags: (readNone: 0, readOnly: 1, noRecurse: 0, returnDoesNotAlias: 1, noInline: 0, alwaysInline: 0, noUnwind: 0, mayThrow: 0, hasUnknownCall: 0), calls: ((callee: ^15))))) +; CHECK: ^15 = gv: (guid: 14, summaries: (function: (module: ^1, flags: (linkage: external, visibility: default, notEligibleToImport: 1, live: 1, dsoLocal: 0, canAutoHide: 0), insts: 1, funcFlags: (readNone: 0, readOnly: 0, noRecurse: 0, returnDoesNotAlias: 0, noInline: 1, alwaysInline: 0, noUnwind: 0, mayThrow: 0, hasUnknownCall: 0, mustBeUnreachable: 0)))) +; CHECK: ^16 = gv: (guid: 15, summaries: (function: (module: ^1, flags: (linkage: external, visibility: default, notEligibleToImport: 0, live: 0, dsoLocal: 0, canAutoHide: 0), insts: 1, funcFlags: (readNone: 1, readOnly: 0, noRecurse: 1, returnDoesNotAlias: 0, noInline: 0, alwaysInline: 1, noUnwind: 1, mayThrow: 1, hasUnknownCall: 1, mustBeUnreachable: 0)))) +; CHECK: ^17 = gv: (guid: 16, summaries: (function: (module: ^1, flags: (linkage: external, visibility: default, notEligibleToImport: 0, live: 0, dsoLocal: 0, canAutoHide: 0), insts: 1, funcFlags: (readNone: 0, readOnly: 1, noRecurse: 0, returnDoesNotAlias: 1, noInline: 0, alwaysInline: 0, noUnwind: 0, mayThrow: 0, hasUnknownCall: 0, mustBeUnreachable: 0), calls: ((callee: ^15))))) ; CHECK: ^18 = gv: (guid: 17, summaries: (alias: (module: ^0, flags: (linkage: external, visibility: default, notEligibleToImport: 0, live: 0, dsoLocal: 1, canAutoHide: 0), aliasee: ^14))) ; CHECK: ^19 = gv: (guid: 18, summaries: (function: (module: ^0, flags: (linkage: external, visibility: default, notEligibleToImport: 0, live: 0, dsoLocal: 0, canAutoHide: 0), insts: 4, typeIdInfo: (typeTests: (^24, ^26))))) ; CHECK: ^20 = gv: (guid: 19, summaries: (function: (module: ^0, flags: (linkage: external, visibility: default, notEligibleToImport: 0, live: 0, dsoLocal: 0, canAutoHide: 0), insts: 8, typeIdInfo: (typeTestAssumeVCalls: (vFuncId: (^27, offset: 16)))))) diff --git a/llvm/test/Bitcode/thinlto-function-summary-refgraph.ll b/llvm/test/Bitcode/thinlto-function-summary-refgraph.ll --- a/llvm/test/Bitcode/thinlto-function-summary-refgraph.ll +++ b/llvm/test/Bitcode/thinlto-function-summary-refgraph.ll @@ -158,7 +158,7 @@ ; DIS-DAG: = gv: (name: "globalvar", summaries: (variable: (module: ^0, flags: (linkage: external, visibility: default, notEligibleToImport: 0, live: 0, dsoLocal: 0, canAutoHide: 0), varFlags: (readonly: 1, writeonly: 0, constant: 1)))) ; guid = 12887606300320728018 ; DIS-DAG: = gv: (name: "func2") ; guid = 14069196320850861797 ; DIS-DAG: = gv: (name: "llvm.ctpop.i8") ; guid = 15254915475081819833 -; DIS-DAG: = gv: (name: "main", summaries: (function: (module: ^0, flags: (linkage: external, visibility: default, notEligibleToImport: 0, live: 0, dsoLocal: 0, canAutoHide: 0), insts: 9, funcFlags: (readNone: 0, readOnly: 0, noRecurse: 0, returnDoesNotAlias: 0, noInline: 0, alwaysInline: 0, noUnwind: 0, mayThrow: 0, hasUnknownCall: 1), calls: ((callee: ^{{.*}})), refs: (^{{.*}})))) ; guid = 15822663052811949562 +; DIS-DAG: = gv: (name: "main", summaries: (function: (module: ^0, flags: (linkage: external, visibility: default, notEligibleToImport: 0, live: 0, dsoLocal: 0, canAutoHide: 0), insts: 9, funcFlags: (readNone: 0, readOnly: 0, noRecurse: 0, returnDoesNotAlias: 0, noInline: 0, alwaysInline: 0, noUnwind: 0, mayThrow: 0, hasUnknownCall: 1, mustBeUnreachable: 0), calls: ((callee: ^{{.*}})), refs: (^{{.*}})))) ; guid = 15822663052811949562 ; DIS-DAG: = gv: (name: "bar", summaries: (variable: (module: ^0, flags: (linkage: external, visibility: default, notEligibleToImport: 0, live: 0, dsoLocal: 0, canAutoHide: 0), varFlags: (readonly: 1, writeonly: 1, constant: 0), refs: (^{{.*}})))) ; guid = 16434608426314478903 ; Don't try to match the exact GUID. Since it is private, the file path ; will get hashed, and that will be test dependent. diff --git a/llvm/test/Bitcode/thinlto-type-vcalls.ll b/llvm/test/Bitcode/thinlto-type-vcalls.ll --- a/llvm/test/Bitcode/thinlto-type-vcalls.ll +++ b/llvm/test/Bitcode/thinlto-type-vcalls.ll @@ -112,19 +112,19 @@ ; DIS: ^0 = module: (path: "{{.*}}", hash: (0, 0, 0, 0, 0)) ; DIS: ^1 = gv: (name: "llvm.type.test") ; guid = 608142985856744218 -; DIS: ^2 = gv: (name: "f1", summaries: (function: (module: ^0, flags: (linkage: external, visibility: default, notEligibleToImport: 0, live: 0, dsoLocal: 0, canAutoHide: 0), insts: 8, funcFlags: (readNone: 0, readOnly: 0, noRecurse: 0, returnDoesNotAlias: 0, noInline: 0, alwaysInline: 0, noUnwind: 0, mayThrow: 0, hasUnknownCall: 1), typeIdInfo: (typeTestAssumeVCalls: (vFuncId: (guid: 6699318081062747564, offset: 16)))))) ; guid = 2072045998141807037 -; DIS: ^3 = gv: (name: "f3", summaries: (function: (module: ^0, flags: (linkage: external, visibility: default, notEligibleToImport: 0, live: 0, dsoLocal: 0, canAutoHide: 0), insts: 5, funcFlags: (readNone: 0, readOnly: 0, noRecurse: 0, returnDoesNotAlias: 0, noInline: 0, alwaysInline: 0, noUnwind: 0, mayThrow: 0, hasUnknownCall: 1), typeIdInfo: (typeCheckedLoadVCalls: (vFuncId: (guid: 6699318081062747564, offset: 16)))))) ; guid = 4197650231481825559 +; DIS: ^2 = gv: (name: "f1", summaries: (function: (module: ^0, flags: (linkage: external, visibility: default, notEligibleToImport: 0, live: 0, dsoLocal: 0, canAutoHide: 0), insts: 8, funcFlags: (readNone: 0, readOnly: 0, noRecurse: 0, returnDoesNotAlias: 0, noInline: 0, alwaysInline: 0, noUnwind: 0, mayThrow: 0, hasUnknownCall: 1, mustBeUnreachable: 0), typeIdInfo: (typeTestAssumeVCalls: (vFuncId: (guid: 6699318081062747564, offset: 16)))))) ; guid = 2072045998141807037 +; DIS: ^3 = gv: (name: "f3", summaries: (function: (module: ^0, flags: (linkage: external, visibility: default, notEligibleToImport: 0, live: 0, dsoLocal: 0, canAutoHide: 0), insts: 5, funcFlags: (readNone: 0, readOnly: 0, noRecurse: 0, returnDoesNotAlias: 0, noInline: 0, alwaysInline: 0, noUnwind: 0, mayThrow: 0, hasUnknownCall: 1, mustBeUnreachable: 0), typeIdInfo: (typeCheckedLoadVCalls: (vFuncId: (guid: 6699318081062747564, offset: 16)))))) ; guid = 4197650231481825559 ; DIS: ^4 = gv: (name: "llvm.type.checked.load") ; guid = 5568222536364573403 ; DIS: ^5 = gv: (name: "llvm.assume") ; guid = 6385187066495850096 -; DIS: ^6 = gv: (name: "f2", summaries: (function: (module: ^0, flags: (linkage: external, visibility: default, notEligibleToImport: 0, live: 0, dsoLocal: 0, canAutoHide: 0), insts: 15, funcFlags: (readNone: 0, readOnly: 0, noRecurse: 0, returnDoesNotAlias: 0, noInline: 0, alwaysInline: 0, noUnwind: 0, mayThrow: 0, hasUnknownCall: 1), typeIdInfo: (typeTestAssumeVCalls: (vFuncId: (guid: 6699318081062747564, offset: 24), vFuncId: (guid: 16434608426314478903, offset: 32)))))) ; guid = 8471399308421654326 -; DIS: ^7 = gv: (name: "f4", summaries: (function: (module: ^0, flags: (linkage: external, visibility: default, notEligibleToImport: 0, live: 0, dsoLocal: 0, canAutoHide: 0), insts: 15, funcFlags: (readNone: 0, readOnly: 0, noRecurse: 0, returnDoesNotAlias: 0, noInline: 0, alwaysInline: 0, noUnwind: 0, mayThrow: 0, hasUnknownCall: 1), typeIdInfo: (typeTestAssumeConstVCalls: ((vFuncId: (guid: 6699318081062747564, offset: 16), args: (42)), (vFuncId: (guid: 6699318081062747564, offset: 24), args: (43))))))) ; guid = 10064745020953272174 -; DIS: ^8 = gv: (name: "f5", summaries: (function: (module: ^0, flags: (linkage: external, visibility: default, notEligibleToImport: 0, live: 0, dsoLocal: 0, canAutoHide: 0), insts: 5, funcFlags: (readNone: 0, readOnly: 0, noRecurse: 0, returnDoesNotAlias: 0, noInline: 0, alwaysInline: 0, noUnwind: 0, mayThrow: 0, hasUnknownCall: 1), typeIdInfo: (typeCheckedLoadConstVCalls: ((vFuncId: (guid: 6699318081062747564, offset: 16), args: (42))))))) ; guid = 11686717102184386164 +; DIS: ^6 = gv: (name: "f2", summaries: (function: (module: ^0, flags: (linkage: external, visibility: default, notEligibleToImport: 0, live: 0, dsoLocal: 0, canAutoHide: 0), insts: 15, funcFlags: (readNone: 0, readOnly: 0, noRecurse: 0, returnDoesNotAlias: 0, noInline: 0, alwaysInline: 0, noUnwind: 0, mayThrow: 0, hasUnknownCall: 1, mustBeUnreachable: 0), typeIdInfo: (typeTestAssumeVCalls: (vFuncId: (guid: 6699318081062747564, offset: 24), vFuncId: (guid: 16434608426314478903, offset: 32)))))) ; guid = 8471399308421654326 +; DIS: ^7 = gv: (name: "f4", summaries: (function: (module: ^0, flags: (linkage: external, visibility: default, notEligibleToImport: 0, live: 0, dsoLocal: 0, canAutoHide: 0), insts: 15, funcFlags: (readNone: 0, readOnly: 0, noRecurse: 0, returnDoesNotAlias: 0, noInline: 0, alwaysInline: 0, noUnwind: 0, mayThrow: 0, hasUnknownCall: 1, mustBeUnreachable: 0), typeIdInfo: (typeTestAssumeConstVCalls: ((vFuncId: (guid: 6699318081062747564, offset: 16), args: (42)), (vFuncId: (guid: 6699318081062747564, offset: 24), args: (43))))))) ; guid = 10064745020953272174 +; DIS: ^8 = gv: (name: "f5", summaries: (function: (module: ^0, flags: (linkage: external, visibility: default, notEligibleToImport: 0, live: 0, dsoLocal: 0, canAutoHide: 0), insts: 5, funcFlags: (readNone: 0, readOnly: 0, noRecurse: 0, returnDoesNotAlias: 0, noInline: 0, alwaysInline: 0, noUnwind: 0, mayThrow: 0, hasUnknownCall: 1, mustBeUnreachable: 0), typeIdInfo: (typeCheckedLoadConstVCalls: ((vFuncId: (guid: 6699318081062747564, offset: 16), args: (42))))))) ; guid = 11686717102184386164 ; DIS: ^9 = gv: (name: "f6", summaries: (function: (module: ^0, flags: (linkage: external, visibility: default, notEligibleToImport: 0, live: 0, dsoLocal: 0, canAutoHide: 0), insts: 2, typeIdInfo: (typeTests: (7546896869197086323))))) ; guid = 11834966808443348068 ; COMBINED-DIS: ^0 = module: (path: "{{.*}}thinlto-type-vcalls.ll.tmp.o", hash: (0, 0, 0, 0, 0)) -; COMBINED-DIS: ^1 = gv: (guid: 2072045998141807037, summaries: (function: (module: ^0, flags: (linkage: external, visibility: default, notEligibleToImport: 0, live: 0, dsoLocal: 0, canAutoHide: 0), insts: 8, funcFlags: (readNone: 0, readOnly: 0, noRecurse: 0, returnDoesNotAlias: 0, noInline: 0, alwaysInline: 0, noUnwind: 0, mayThrow: 0, hasUnknownCall: 1), typeIdInfo: (typeTestAssumeVCalls: (vFuncId: (guid: 6699318081062747564, offset: 16)))))) -; COMBINED-DIS: ^2 = gv: (guid: 4197650231481825559, summaries: (function: (module: ^0, flags: (linkage: external, visibility: default, notEligibleToImport: 0, live: 0, dsoLocal: 0, canAutoHide: 0), insts: 5, funcFlags: (readNone: 0, readOnly: 0, noRecurse: 0, returnDoesNotAlias: 0, noInline: 0, alwaysInline: 0, noUnwind: 0, mayThrow: 0, hasUnknownCall: 1), typeIdInfo: (typeCheckedLoadVCalls: (vFuncId: (guid: 6699318081062747564, offset: 16)))))) -; COMBINED-DIS: ^3 = gv: (guid: 8471399308421654326, summaries: (function: (module: ^0, flags: (linkage: external, visibility: default, notEligibleToImport: 0, live: 0, dsoLocal: 0, canAutoHide: 0), insts: 15, funcFlags: (readNone: 0, readOnly: 0, noRecurse: 0, returnDoesNotAlias: 0, noInline: 0, alwaysInline: 0, noUnwind: 0, mayThrow: 0, hasUnknownCall: 1), typeIdInfo: (typeTestAssumeVCalls: (vFuncId: (guid: 6699318081062747564, offset: 24), vFuncId: (guid: 16434608426314478903, offset: 32)))))) -; COMBINED-DIS: ^4 = gv: (guid: 10064745020953272174, summaries: (function: (module: ^0, flags: (linkage: external, visibility: default, notEligibleToImport: 0, live: 0, dsoLocal: 0, canAutoHide: 0), insts: 15, funcFlags: (readNone: 0, readOnly: 0, noRecurse: 0, returnDoesNotAlias: 0, noInline: 0, alwaysInline: 0, noUnwind: 0, mayThrow: 0, hasUnknownCall: 1), typeIdInfo: (typeTestAssumeConstVCalls: ((vFuncId: (guid: 6699318081062747564, offset: 16), args: (42)), (vFuncId: (guid: 6699318081062747564, offset: 24), args: (43))))))) -; COMBINED-DIS: ^5 = gv: (guid: 11686717102184386164, summaries: (function: (module: ^0, flags: (linkage: external, visibility: default, notEligibleToImport: 0, live: 0, dsoLocal: 0, canAutoHide: 0), insts: 5, funcFlags: (readNone: 0, readOnly: 0, noRecurse: 0, returnDoesNotAlias: 0, noInline: 0, alwaysInline: 0, noUnwind: 0, mayThrow: 0, hasUnknownCall: 1), typeIdInfo: (typeCheckedLoadConstVCalls: ((vFuncId: (guid: 6699318081062747564, offset: 16), args: (42))))))) +; COMBINED-DIS: ^1 = gv: (guid: 2072045998141807037, summaries: (function: (module: ^0, flags: (linkage: external, visibility: default, notEligibleToImport: 0, live: 0, dsoLocal: 0, canAutoHide: 0), insts: 8, funcFlags: (readNone: 0, readOnly: 0, noRecurse: 0, returnDoesNotAlias: 0, noInline: 0, alwaysInline: 0, noUnwind: 0, mayThrow: 0, hasUnknownCall: 1, mustBeUnreachable: 0), typeIdInfo: (typeTestAssumeVCalls: (vFuncId: (guid: 6699318081062747564, offset: 16)))))) +; COMBINED-DIS: ^2 = gv: (guid: 4197650231481825559, summaries: (function: (module: ^0, flags: (linkage: external, visibility: default, notEligibleToImport: 0, live: 0, dsoLocal: 0, canAutoHide: 0), insts: 5, funcFlags: (readNone: 0, readOnly: 0, noRecurse: 0, returnDoesNotAlias: 0, noInline: 0, alwaysInline: 0, noUnwind: 0, mayThrow: 0, hasUnknownCall: 1, mustBeUnreachable: 0), typeIdInfo: (typeCheckedLoadVCalls: (vFuncId: (guid: 6699318081062747564, offset: 16)))))) +; COMBINED-DIS: ^3 = gv: (guid: 8471399308421654326, summaries: (function: (module: ^0, flags: (linkage: external, visibility: default, notEligibleToImport: 0, live: 0, dsoLocal: 0, canAutoHide: 0), insts: 15, funcFlags: (readNone: 0, readOnly: 0, noRecurse: 0, returnDoesNotAlias: 0, noInline: 0, alwaysInline: 0, noUnwind: 0, mayThrow: 0, hasUnknownCall: 1, mustBeUnreachable: 0), typeIdInfo: (typeTestAssumeVCalls: (vFuncId: (guid: 6699318081062747564, offset: 24), vFuncId: (guid: 16434608426314478903, offset: 32)))))) +; COMBINED-DIS: ^4 = gv: (guid: 10064745020953272174, summaries: (function: (module: ^0, flags: (linkage: external, visibility: default, notEligibleToImport: 0, live: 0, dsoLocal: 0, canAutoHide: 0), insts: 15, funcFlags: (readNone: 0, readOnly: 0, noRecurse: 0, returnDoesNotAlias: 0, noInline: 0, alwaysInline: 0, noUnwind: 0, mayThrow: 0, hasUnknownCall: 1, mustBeUnreachable: 0), typeIdInfo: (typeTestAssumeConstVCalls: ((vFuncId: (guid: 6699318081062747564, offset: 16), args: (42)), (vFuncId: (guid: 6699318081062747564, offset: 24), args: (43))))))) +; COMBINED-DIS: ^5 = gv: (guid: 11686717102184386164, summaries: (function: (module: ^0, flags: (linkage: external, visibility: default, notEligibleToImport: 0, live: 0, dsoLocal: 0, canAutoHide: 0), insts: 5, funcFlags: (readNone: 0, readOnly: 0, noRecurse: 0, returnDoesNotAlias: 0, noInline: 0, alwaysInline: 0, noUnwind: 0, mayThrow: 0, hasUnknownCall: 1, mustBeUnreachable: 0), typeIdInfo: (typeCheckedLoadConstVCalls: ((vFuncId: (guid: 6699318081062747564, offset: 16), args: (42))))))) ; COMBINED-DIS: ^6 = gv: (guid: 11834966808443348068, summaries: (function: (module: ^0, flags: (linkage: external, visibility: default, notEligibleToImport: 0, live: 0, dsoLocal: 0, canAutoHide: 0), insts: 2, typeIdInfo: (typeTests: (7546896869197086323))))) diff --git a/llvm/test/ThinLTO/X86/Inputs/d1.ll b/llvm/test/ThinLTO/X86/Inputs/d1.ll new file mode 100644 --- /dev/null +++ b/llvm/test/ThinLTO/X86/Inputs/d1.ll @@ -0,0 +1,204 @@ +; ModuleID = '/usr/local/google/home/mingmingl/test/d1.cc' +source_filename = "/usr/local/google/home/mingmingl/test/d1.cc" +target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +%class.Derived = type { %class.Base } +%class.Base = type { i32 (...)** } + +$_ZN7DerivedD2Ev = comdat any + +$_ZN7DerivedD0Ev = comdat any + +$__clang_call_terminate = comdat any + +$_ZN4BaseD2Ev = comdat any + +$_ZN4BaseD0Ev = comdat any + +$_ZTS4Base = comdat any + +$_ZTI4Base = comdat any + +$_ZTV4Base = comdat any + +@.str = private unnamed_addr constant [12 x i8] c"Derived::x\0A\00", align 1 +@_ZTV7Derived = hidden unnamed_addr constant { [5 x i8*] } { [5 x i8*] [i8* null, i8* bitcast ({ i8*, i8*, i8* }* @_ZTI7Derived to i8*), i8* bitcast (void (%class.Derived*)* @_ZN7DerivedD2Ev to i8*), i8* bitcast (void (%class.Derived*)* @_ZN7DerivedD0Ev to i8*), i8* bitcast (void (%class.Derived*)* @_ZN7Derived1xEv to i8*)] }, align 8, !type !0, !type !1, !type !2, !type !3, !vcall_visibility !4 +@_ZTVN10__cxxabiv120__si_class_type_infoE = external dso_local global i8* +@_ZTS7Derived = hidden constant [9 x i8] c"7Derived\00", align 1 +@_ZTVN10__cxxabiv117__class_type_infoE = external dso_local global i8* +@_ZTS4Base = linkonce_odr hidden constant [6 x i8] c"4Base\00", comdat, align 1 +@_ZTI4Base = linkonce_odr hidden constant { i8*, i8* } { i8* bitcast (i8** getelementptr inbounds (i8*, i8** @_ZTVN10__cxxabiv117__class_type_infoE, i64 2) to i8*), i8* getelementptr inbounds ([6 x i8], [6 x i8]* @_ZTS4Base, i32 0, i32 0) }, comdat, align 8 +@_ZTI7Derived = hidden constant { i8*, i8*, i8* } { i8* bitcast (i8** getelementptr inbounds (i8*, i8** @_ZTVN10__cxxabiv120__si_class_type_infoE, i64 2) to i8*), i8* getelementptr inbounds ([9 x i8], [9 x i8]* @_ZTS7Derived, i32 0, i32 0), i8* bitcast ({ i8*, i8* }* @_ZTI4Base to i8*) }, align 8 +@.str.1 = private unnamed_addr constant [24 x i8] c"In Derived::~Derived()\0A\00", align 1 +@_ZTV4Base = linkonce_odr hidden unnamed_addr constant { [5 x i8*] } { [5 x i8*] [i8* null, i8* bitcast ({ i8*, i8* }* @_ZTI4Base to i8*), i8* bitcast (void (%class.Base*)* @_ZN4BaseD2Ev to i8*), i8* bitcast (void (%class.Base*)* @_ZN4BaseD0Ev to i8*), i8* bitcast (void ()* @__cxa_pure_virtual to i8*)] }, comdat, align 8, !type !0, !type !1, !vcall_visibility !4 +@.str.2 = private unnamed_addr constant [18 x i8] c"In Base::~Base()\0A\00", align 1 + +; Function Attrs: mustprogress noinline optnone uwtable +define hidden void @_ZN7Derived1xEv(%class.Derived* nonnull align 8 dereferenceable(8) %this) unnamed_addr #0 align 2 { +entry: + %this.addr = alloca %class.Derived*, align 8 + store %class.Derived* %this, %class.Derived** %this.addr, align 8 + %this1 = load %class.Derived*, %class.Derived** %this.addr, align 8 + %call = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([12 x i8], [12 x i8]* @.str, i64 0, i64 0)) + ret void +} + +declare dso_local i32 @printf(i8*, ...) #1 + +; Function Attrs: mustprogress noinline nounwind optnone uwtable +define hidden void @_Z3fooP4Base(%class.Base* %b) #2 { +entry: + %b.addr = alloca %class.Base*, align 8 + store %class.Base* %b, %class.Base** %b.addr, align 8 + %0 = load %class.Base*, %class.Base** %b.addr, align 8 + %isnull = icmp eq %class.Base* %0, null + br i1 %isnull, label %delete.end, label %delete.notnull + +delete.notnull: ; preds = %entry + %1 = bitcast %class.Base* %0 to void (%class.Base*)*** + %vtable = load void (%class.Base*)**, void (%class.Base*)*** %1, align 8 + %2 = bitcast void (%class.Base*)** %vtable to i8* + %3 = call i1 @llvm.type.test(i8* %2, metadata !"_ZTS4Base") + call void @llvm.assume(i1 %3) + %vfn = getelementptr inbounds void (%class.Base*)*, void (%class.Base*)** %vtable, i64 1 + %4 = load void (%class.Base*)*, void (%class.Base*)** %vfn, align 8 + call void %4(%class.Base* nonnull align 8 dereferenceable(8) %0) #9 + br label %delete.end + +delete.end: ; preds = %delete.notnull, %entry + ret void +} + +; Function Attrs: nofree nosync nounwind readnone speculatable willreturn +declare i1 @llvm.type.test(i8*, metadata) #3 + +; Function Attrs: inaccessiblememonly nofree nosync nounwind willreturn +declare void @llvm.assume(i1 noundef) #4 + +; Function Attrs: noinline nounwind optnone uwtable +define linkonce_odr hidden void @_ZN7DerivedD2Ev(%class.Derived* nonnull align 8 dereferenceable(8) %this) unnamed_addr #5 comdat align 2 personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) { +entry: + %this.addr = alloca %class.Derived*, align 8 + %exn.slot = alloca i8*, align 8 + %ehselector.slot = alloca i32, align 4 + store %class.Derived* %this, %class.Derived** %this.addr, align 8 + %this1 = load %class.Derived*, %class.Derived** %this.addr, align 8 + %0 = bitcast %class.Derived* %this1 to i32 (...)*** + store i32 (...)** bitcast (i8** getelementptr inbounds ({ [5 x i8*] }, { [5 x i8*] }* @_ZTV7Derived, i32 0, inrange i32 0, i32 2) to i32 (...)**), i32 (...)*** %0, align 8 + %call = invoke i32 (i8*, ...) @printf(i8* getelementptr inbounds ([24 x i8], [24 x i8]* @.str.1, i64 0, i64 0)) + to label %invoke.cont unwind label %lpad + +invoke.cont: ; preds = %entry + %1 = bitcast %class.Derived* %this1 to %class.Base* + call void @_ZN4BaseD2Ev(%class.Base* nonnull align 8 dereferenceable(8) %1) #9 + ret void + +lpad: ; preds = %entry + %2 = landingpad { i8*, i32 } + catch i8* null + %3 = extractvalue { i8*, i32 } %2, 0 + store i8* %3, i8** %exn.slot, align 8 + %4 = extractvalue { i8*, i32 } %2, 1 + store i32 %4, i32* %ehselector.slot, align 4 + %5 = bitcast %class.Derived* %this1 to %class.Base* + call void @_ZN4BaseD2Ev(%class.Base* nonnull align 8 dereferenceable(8) %5) #9 + br label %terminate.handler + +terminate.handler: ; preds = %lpad + %exn = load i8*, i8** %exn.slot, align 8 + call void @__clang_call_terminate(i8* %exn) #10 + unreachable +} + +; Function Attrs: noinline nounwind optnone uwtable +define linkonce_odr hidden void @_ZN7DerivedD0Ev(%class.Derived* nonnull align 8 dereferenceable(8) %this) unnamed_addr #5 comdat align 2 { +entry: + %this.addr = alloca %class.Derived*, align 8 + store %class.Derived* %this, %class.Derived** %this.addr, align 8 + %this1 = load %class.Derived*, %class.Derived** %this.addr, align 8 + call void @_ZN7DerivedD2Ev(%class.Derived* nonnull align 8 dereferenceable(8) %this1) #9 + %0 = bitcast %class.Derived* %this1 to i8* + call void @_ZdlPv(i8* %0) #11 + ret void +} + +declare dso_local i32 @__gxx_personality_v0(...) + +; Function Attrs: noinline noreturn nounwind +define linkonce_odr hidden void @__clang_call_terminate(i8* %0) #6 comdat { + %2 = call i8* @__cxa_begin_catch(i8* %0) #9 + call void @_ZSt9terminatev() #10 + unreachable +} + +declare dso_local i8* @__cxa_begin_catch(i8*) + +declare dso_local void @_ZSt9terminatev() + +; Function Attrs: noinline nounwind optnone uwtable +define linkonce_odr hidden void @_ZN4BaseD2Ev(%class.Base* nonnull align 8 dereferenceable(8) %this) unnamed_addr #5 comdat align 2 personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) { +entry: + %this.addr = alloca %class.Base*, align 8 + store %class.Base* %this, %class.Base** %this.addr, align 8 + %this1 = load %class.Base*, %class.Base** %this.addr, align 8 + %0 = bitcast %class.Base* %this1 to i32 (...)*** + store i32 (...)** bitcast (i8** getelementptr inbounds ({ [5 x i8*] }, { [5 x i8*] }* @_ZTV4Base, i32 0, inrange i32 0, i32 2) to i32 (...)**), i32 (...)*** %0, align 8 + %call = invoke i32 (i8*, ...) @printf(i8* getelementptr inbounds ([18 x i8], [18 x i8]* @.str.2, i64 0, i64 0)) + to label %invoke.cont unwind label %terminate.lpad + +invoke.cont: ; preds = %entry + ret void + +terminate.lpad: ; preds = %entry + %1 = landingpad { i8*, i32 } + catch i8* null + %2 = extractvalue { i8*, i32 } %1, 0 + call void @__clang_call_terminate(i8* %2) #10 + unreachable +} + +; Function Attrs: noinline nounwind optnone uwtable +define linkonce_odr hidden void @_ZN4BaseD0Ev(%class.Base* nonnull align 8 dereferenceable(8) %this) unnamed_addr #5 comdat align 2 { +entry: + %this.addr = alloca %class.Base*, align 8 + store %class.Base* %this, %class.Base** %this.addr, align 8 + %this1 = load %class.Base*, %class.Base** %this.addr, align 8 + call void @llvm.trap() #10 + unreachable +} + +declare dso_local void @__cxa_pure_virtual() unnamed_addr + +; Function Attrs: cold noreturn nounwind +declare void @llvm.trap() #7 + +; Function Attrs: nobuiltin nounwind +declare dso_local void @_ZdlPv(i8*) #8 + +attributes #0 = { mustprogress noinline optnone uwtable "frame-pointer"="all" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" } +attributes #1 = { "frame-pointer"="all" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" } +attributes #2 = { mustprogress noinline nounwind optnone uwtable "frame-pointer"="all" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" } +attributes #3 = { nofree nosync nounwind readnone speculatable willreturn } +attributes #4 = { inaccessiblememonly nofree nosync nounwind willreturn } +attributes #5 = { noinline nounwind optnone uwtable "frame-pointer"="all" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" } +attributes #6 = { noinline noreturn nounwind } +attributes #7 = { cold noreturn nounwind } +attributes #8 = { nobuiltin nounwind "frame-pointer"="all" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" } +attributes #9 = { nounwind } +attributes #10 = { noreturn nounwind } +attributes #11 = { builtin nounwind } + +!llvm.module.flags = !{!5, !6, !7, !8} +!llvm.ident = !{!9} + +!0 = !{i64 16, !"_ZTS4Base"} +!1 = !{i64 32, !"_ZTSM4BaseFvvE.virtual"} +!2 = !{i64 16, !"_ZTS7Derived"} +!3 = !{i64 32, !"_ZTSM7DerivedFvvE.virtual"} +!4 = !{i64 1} +!5 = !{i32 1, !"wchar_size", i32 4} +!6 = !{i32 1, !"Virtual Function Elim", i32 0} +!7 = !{i32 7, !"uwtable", i32 1} +!8 = !{i32 7, !"frame-pointer", i32 2} +!9 = !{!"clang version 14.0.0 (https://github.com/llvm/llvm-project.git f6ae8e8cc7f495dad86e97bd9bbd828f9079fc9b)"} diff --git a/llvm/test/ThinLTO/X86/d.ll b/llvm/test/ThinLTO/X86/d.ll new file mode 100644 --- /dev/null +++ b/llvm/test/ThinLTO/X86/d.ll @@ -0,0 +1,237 @@ +; RUN: opt -thinlto-bc -thinlto-split-lto-unit %s -o %t-main.bc +; RUN: opt -thinlto-bc -thinlto-split-lto-unit %p/Inputs/d1.ll -o %t-foo.bc +; RUN: llvm-lto2 run -save-temps %t-main.bc %t-foo.bc -pass-remarks=. -o %t \ +; RUN: -whole-program-visibility \ +; RUN: -r=%t-foo.bc,_ZN7Derived1xEv,pl \ +; RUN: -r=%t-foo.bc,printf, \ +; RUN: -r=%t-foo.bc,_Z3fooP4Base,pl \ +; RUN: -r=%t-foo.bc,_ZN7DerivedD2Ev,pl \ +; RUN: -r=%t-foo.bc,_ZN7DerivedD0Ev,pl \ +; RUN: -r=%t-foo.bc,__gxx_personality_v0, \ +; RUN: -r=%t-foo.bc,__clang_call_terminate,pl \ +; RUN: -r=%t-foo.bc,__cxa_begin_catch, \ +; RUN: -r=%t-foo.bc,_ZSt9terminatev, \ +; RUN: -r=%t-foo.bc,_ZN4BaseD2Ev,pl \ +; RUN: -r=%t-foo.bc,_ZN4BaseD0Ev,pl \ +; RUN: -r=%t-foo.bc,__cxa_pure_virtual, \ +; RUN: -r=%t-foo.bc,_ZdlPv, \ +; RUN: -r=%t-foo.bc,_ZTV7Derived,l \ +; RUN: -r=%t-foo.bc,_ZTVN10__cxxabiv120__si_class_type_infoE, \ +; RUN: -r=%t-foo.bc,_ZTS7Derived,pl \ +; RUN: -r=%t-foo.bc,_ZTVN10__cxxabiv117__class_type_infoE, \ +; RUN: -r=%t-foo.bc,_ZTS4Base,pl \ +; RUN: -r=%t-foo.bc,_ZTI4Base,pl \ +; RUN: -r=%t-foo.bc,_ZTI7Derived,pl \ +; RUN: -r=%t-foo.bc,_ZTV4Base,l \ +; RUN: -r=%t-foo.bc,__cxa_pure_virtual, \ +; RUN: -r=%t-foo.bc,_ZN7Derived1xEv, \ +; RUN: -r=%t-foo.bc,_ZN7DerivedD2Ev, \ +; RUN: -r=%t-foo.bc,_ZN7DerivedD0Ev, \ +; RUN: -r=%t-foo.bc,_ZN4BaseD2Ev, \ +; RUN: -r=%t-foo.bc,_ZN4BaseD0Ev, \ +; RUN: -r=%t-foo.bc,_ZTV7Derived,pl \ +; RUN: -r=%t-foo.bc,_ZTI4Base, \ +; RUN: -r=%t-foo.bc,_ZTI7Derived, \ +; RUN: -r=%t-foo.bc,_ZTV4Base,pl \ +; RUN: -r=%t-main.bc,main,plx \ +; RUN: -r=%t-main.bc,_Znwm,pl \ +; RUN: -r=%t-main.bc,_ZN7DerivedC2Ev,pl \ +; RUN: -r=%t-main.bc,__gxx_personality_v0, \ +; RUN: -r=%t-main.bc,_ZdlPv, \ +; RUN: -r=%t-main.bc,_Z3fooP4Base, \ +; RUN: -r=%t-main.bc,_ZN4BaseC2Ev,pl \ +; RUN: -r=%t-main.bc,_ZN4BaseD2Ev, \ +; RUN: -r=%t-main.bc,_ZN4BaseD0Ev, \ +; RUN: -r=%t-main.bc,__cxa_pure_virtual, \ +; RUN: -r=%t-main.bc,printf, \ +; RUN: -r=%t-main.bc,__clang_call_terminate, \ +; RUN: -r=%t-main.bc,__cxa_begin_catch, \ +; RUN: -r=%t-main.bc,_ZSt9terminatev, \ +; RUN: -r=%t-main.bc,_ZTV7Derived, \ +; RUN: -r=%t-main.bc,_ZTV4Base, \ +; RUN: -r=%t-main.bc,_ZTVN10__cxxabiv117__class_type_infoE, \ +; RUN: -r=%t-main.bc,_ZTS4Base, \ +; RUN: -r=%t-main.bc,_ZTI4Base, \ +; RUN: -r=%t-main.bc,__cxa_pure_virtual, \ +; RUN: -r=%t-main.bc,_ZN4BaseD2Ev, \ +; RUN: -r=%t-main.bc,_ZN4BaseD0Ev, \ +; RUN: -r=%t-main.bc,_ZTV4Base, \ +; RUN: -r=%t-main.bc,_ZTI4Base, 2>&1 | FileCheck %s --check-prefix=REMARK + +; REMARK-COUNT-1: single-impl: devirtualized a call to _ZN7DerivedD0Ev + +; ModuleID = 'd2.cc' +source_filename = "d2.cc" +target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +%class.Derived = type { %class.Base } +%class.Base = type { i32 (...)** } + +$_ZN7DerivedC2Ev = comdat any + +$_ZN4BaseC2Ev = comdat any + +$_ZN4BaseD2Ev = comdat any + +$_ZN4BaseD0Ev = comdat any + +$__clang_call_terminate = comdat any + +$_ZTV4Base = comdat any + +$_ZTS4Base = comdat any + +$_ZTI4Base = comdat any + +@_ZTV7Derived = external dso_local unnamed_addr constant { [5 x i8*] }, align 8 +@_ZTV4Base = linkonce_odr hidden unnamed_addr constant { [5 x i8*] } { [5 x i8*] [i8* null, i8* bitcast ({ i8*, i8* }* @_ZTI4Base to i8*), i8* bitcast (void (%class.Base*)* @_ZN4BaseD2Ev to i8*), i8* bitcast (void (%class.Base*)* @_ZN4BaseD0Ev to i8*), i8* bitcast (void ()* @__cxa_pure_virtual to i8*)] }, comdat, align 8, !type !0, !type !1, !vcall_visibility !2 +@_ZTVN10__cxxabiv117__class_type_infoE = external dso_local global i8* +@_ZTS4Base = linkonce_odr hidden constant [6 x i8] c"4Base\00", comdat, align 1 +@_ZTI4Base = linkonce_odr hidden constant { i8*, i8* } { i8* bitcast (i8** getelementptr inbounds (i8*, i8** @_ZTVN10__cxxabiv117__class_type_infoE, i64 2) to i8*), i8* getelementptr inbounds ([6 x i8], [6 x i8]* @_ZTS4Base, i32 0, i32 0) }, comdat, align 8 +@.str = private unnamed_addr constant [18 x i8] c"In Base::~Base()\0A\00", align 1 + +; Function Attrs: mustprogress noinline norecurse optnone uwtable +define hidden i32 @main() #0 personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) { +entry: + %d = alloca %class.Derived*, align 8 + %exn.slot = alloca i8*, align 8 + %ehselector.slot = alloca i32, align 4 + %call = call noalias nonnull i8* @_Znwm(i64 8) #8 + %0 = bitcast i8* %call to %class.Derived* + invoke void @_ZN7DerivedC2Ev(%class.Derived* nonnull align 8 dereferenceable(8) %0) + to label %invoke.cont unwind label %lpad + +invoke.cont: ; preds = %entry + store %class.Derived* %0, %class.Derived** %d, align 8 + %1 = load %class.Derived*, %class.Derived** %d, align 8 + %2 = bitcast %class.Derived* %1 to %class.Base* + call void @_Z3fooP4Base(%class.Base* %2) + ret i32 0 + +lpad: ; preds = %entry + %3 = landingpad { i8*, i32 } + cleanup + %4 = extractvalue { i8*, i32 } %3, 0 + store i8* %4, i8** %exn.slot, align 8 + %5 = extractvalue { i8*, i32 } %3, 1 + store i32 %5, i32* %ehselector.slot, align 4 + call void @_ZdlPv(i8* %call) #9 + br label %eh.resume + +eh.resume: ; preds = %lpad + %exn = load i8*, i8** %exn.slot, align 8 + %sel = load i32, i32* %ehselector.slot, align 4 + %lpad.val = insertvalue { i8*, i32 } undef, i8* %exn, 0 + %lpad.val1 = insertvalue { i8*, i32 } %lpad.val, i32 %sel, 1 + resume { i8*, i32 } %lpad.val1 +} + +; Function Attrs: nobuiltin allocsize(0) +declare dso_local nonnull i8* @_Znwm(i64) #1 + +; Function Attrs: noinline optnone uwtable +define linkonce_odr hidden void @_ZN7DerivedC2Ev(%class.Derived* nonnull align 8 dereferenceable(8) %this) unnamed_addr #2 comdat align 2 { +entry: + %this.addr = alloca %class.Derived*, align 8 + store %class.Derived* %this, %class.Derived** %this.addr, align 8 + %this1 = load %class.Derived*, %class.Derived** %this.addr, align 8 + %0 = bitcast %class.Derived* %this1 to %class.Base* + call void @_ZN4BaseC2Ev(%class.Base* nonnull align 8 dereferenceable(8) %0) + %1 = bitcast %class.Derived* %this1 to i32 (...)*** + store i32 (...)** bitcast (i8** getelementptr inbounds ({ [5 x i8*] }, { [5 x i8*] }* @_ZTV7Derived, i32 0, inrange i32 0, i32 2) to i32 (...)**), i32 (...)*** %1, align 8 + ret void +} + +declare dso_local i32 @__gxx_personality_v0(...) + +; Function Attrs: nobuiltin nounwind +declare dso_local void @_ZdlPv(i8*) #3 + +declare dso_local void @_Z3fooP4Base(%class.Base*) #4 + +; Function Attrs: noinline nounwind optnone uwtable +define linkonce_odr hidden void @_ZN4BaseC2Ev(%class.Base* nonnull align 8 dereferenceable(8) %this) unnamed_addr #5 comdat align 2 { +entry: + %this.addr = alloca %class.Base*, align 8 + store %class.Base* %this, %class.Base** %this.addr, align 8 + %this1 = load %class.Base*, %class.Base** %this.addr, align 8 + %0 = bitcast %class.Base* %this1 to i32 (...)*** + store i32 (...)** bitcast (i8** getelementptr inbounds ({ [5 x i8*] }, { [5 x i8*] }* @_ZTV4Base, i32 0, inrange i32 0, i32 2) to i32 (...)**), i32 (...)*** %0, align 8 + ret void +} + +; Function Attrs: noinline nounwind optnone uwtable +define linkonce_odr hidden void @_ZN4BaseD2Ev(%class.Base* nonnull align 8 dereferenceable(8) %this) unnamed_addr #5 comdat align 2 personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) { +entry: + %this.addr = alloca %class.Base*, align 8 + store %class.Base* %this, %class.Base** %this.addr, align 8 + %this1 = load %class.Base*, %class.Base** %this.addr, align 8 + %0 = bitcast %class.Base* %this1 to i32 (...)*** + store i32 (...)** bitcast (i8** getelementptr inbounds ({ [5 x i8*] }, { [5 x i8*] }* @_ZTV4Base, i32 0, inrange i32 0, i32 2) to i32 (...)**), i32 (...)*** %0, align 8 + %call = invoke i32 (i8*, ...) @printf(i8* getelementptr inbounds ([18 x i8], [18 x i8]* @.str, i64 0, i64 0)) + to label %invoke.cont unwind label %terminate.lpad + +invoke.cont: ; preds = %entry + ret void + +terminate.lpad: ; preds = %entry + %1 = landingpad { i8*, i32 } + catch i8* null + %2 = extractvalue { i8*, i32 } %1, 0 + call void @__clang_call_terminate(i8* %2) #10 + unreachable +} + +; Function Attrs: noinline nounwind optnone uwtable +define linkonce_odr hidden void @_ZN4BaseD0Ev(%class.Base* nonnull align 8 dereferenceable(8) %this) unnamed_addr #5 comdat align 2 { +entry: + %this.addr = alloca %class.Base*, align 8 + store %class.Base* %this, %class.Base** %this.addr, align 8 + %this1 = load %class.Base*, %class.Base** %this.addr, align 8 + call void @llvm.trap() #10 + unreachable +} + +declare dso_local void @__cxa_pure_virtual() unnamed_addr + +declare dso_local i32 @printf(i8*, ...) #4 + +; Function Attrs: noinline noreturn nounwind +define linkonce_odr hidden void @__clang_call_terminate(i8* %0) #6 comdat { + %2 = call i8* @__cxa_begin_catch(i8* %0) #11 + call void @_ZSt9terminatev() #10 + unreachable +} + +declare dso_local i8* @__cxa_begin_catch(i8*) + +declare dso_local void @_ZSt9terminatev() + +; Function Attrs: cold noreturn nounwind +declare void @llvm.trap() #7 + +attributes #0 = { mustprogress noinline norecurse optnone uwtable "frame-pointer"="all" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" } +attributes #1 = { nobuiltin allocsize(0) "frame-pointer"="all" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" } +attributes #2 = { noinline optnone uwtable "frame-pointer"="all" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" } +attributes #3 = { nobuiltin nounwind "frame-pointer"="all" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" } +attributes #4 = { "frame-pointer"="all" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" } +attributes #5 = { noinline nounwind optnone uwtable "frame-pointer"="all" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" } +attributes #6 = { noinline noreturn nounwind } +attributes #7 = { cold noreturn nounwind } +attributes #8 = { builtin allocsize(0) } +attributes #9 = { builtin nounwind } +attributes #10 = { noreturn nounwind } +attributes #11 = { nounwind } + +!llvm.module.flags = !{!3, !4, !5, !6} +!llvm.ident = !{!7} + +!0 = !{i64 16, !"_ZTS4Base"} +!1 = !{i64 32, !"_ZTSM4BaseFvvE.virtual"} +!2 = !{i64 1} +!3 = !{i32 1, !"wchar_size", i32 4} +!4 = !{i32 1, !"Virtual Function Elim", i32 0} +!5 = !{i32 7, !"uwtable", i32 1} +!6 = !{i32 7, !"frame-pointer", i32 2} +!7 = !{!"clang version 14.0.0 (https://github.com/llvm/llvm-project.git f6ae8e8cc7f495dad86e97bd9bbd828f9079fc9b)"} diff --git a/llvm/test/ThinLTO/X86/devirt_single_hybrid.ll b/llvm/test/ThinLTO/X86/devirt_single_hybrid.ll --- a/llvm/test/ThinLTO/X86/devirt_single_hybrid.ll +++ b/llvm/test/ThinLTO/X86/devirt_single_hybrid.ll @@ -22,7 +22,7 @@ ; RUN: llvm-dis %t.1.3.import.bc -o - | FileCheck %s --check-prefix=IMPORT ; RUN: llvm-dis %t.1.5.precodegen.bc -o - | FileCheck %s --check-prefix=CODEGEN -; REMARK-COUNT-3: single-impl: devirtualized a call to _ZNK1A1fEv +; REMARK-COUNT-5: single-impl: devirtualized a call to _ZNK1A1fEv ; IMPORT: define available_externally hidden i32 @_ZNK1A1fEv(%struct.A* %this) ; IMPORT-NEXT: entry: diff --git a/llvm/test/ThinLTO/X86/dot-dumper.ll b/llvm/test/ThinLTO/X86/dot-dumper.ll --- a/llvm/test/ThinLTO/X86/dot-dumper.ll +++ b/llvm/test/ThinLTO/X86/dot-dumper.ll @@ -21,7 +21,7 @@ ; PERMODULE-NEXT: label = ""; ; PERMODULE-NEXT: node [style=filled,fillcolor=lightblue]; ; PERMODULE-NEXT: M0_[[MAIN_ALIAS:[0-9]+]] [style="dotted,filled",shape="box",label="main_alias",fillcolor="red"]; // alias, dead -; PERMODULE-NEXT: M0_[[MAIN:[0-9]+]] [shape="record",label="main|extern (inst: 4, ffl: 000000000)}",fillcolor="red"]; // function, dead +; PERMODULE-NEXT: M0_[[MAIN:[0-9]+]] [shape="record",label="main|extern (inst: 4, ffl: 0000000000)}",fillcolor="red"]; // function, dead ; PERMODULE-NEXT: // Edges: ; PERMODULE-NEXT: M0_[[MAIN_ALIAS]] -> M0_[[MAIN]] [style=dotted]; // alias ; PERMODULE-NEXT: } @@ -40,7 +40,7 @@ ; COMBINED-NEXT: label = "dot-dumper{{.*}}1.bc"; ; COMBINED-NEXT: node [style=filled,fillcolor=lightblue]; ; COMBINED-NEXT: M0_[[MAIN_ALIAS:[0-9]+]] [style="dotted,filled",shape="box",label="main_alias",fillcolor="red"]; // alias, dead -; COMBINED-NEXT: M0_[[MAIN:[0-9]+]] [shape="record",label="main|extern (inst: 4, ffl: 000000000)}"]; // function, preserved +; COMBINED-NEXT: M0_[[MAIN:[0-9]+]] [shape="record",label="main|extern (inst: 4, ffl: 0000000000)}"]; // function, preserved ; COMBINED-NEXT: // Edges: ; COMBINED-NEXT: M0_[[MAIN_ALIAS]] -> M0_[[MAIN]] [style=dotted]; // alias ; COMBINED-NEXT: } @@ -50,10 +50,10 @@ ; COMBINED-NEXT: color = lightgrey; ; COMBINED-NEXT: label = "dot-dumper{{.*}}2.bc"; ; COMBINED-NEXT: node [style=filled,fillcolor=lightblue]; -; COMBINED-NEXT: M1_[[FOO:[0-9]+]] [shape="record",label="foo|extern (inst: 4, ffl: 000010000)}"]; // function +; COMBINED-NEXT: M1_[[FOO:[0-9]+]] [shape="record",label="foo|extern (inst: 4, ffl: 0000100000)}"]; // function ; COMBINED-NEXT: M1_[[A:[0-9]+]] [shape="Mrecord",label="A|extern}"]; // variable, immutable ; COMBINED-NEXT: M1_[[B:[0-9]+]] [shape="Mrecord",label="B|extern}"]; // variable, immutable, constant -; COMBINED-NEXT: M1_{{[0-9]+}} [shape="record",label="bar|extern (inst: 1, ffl: 000000000)}",fillcolor="red"]; // function, dead +; COMBINED-NEXT: M1_{{[0-9]+}} [shape="record",label="bar|extern (inst: 1, ffl: 0000000000)}",fillcolor="red"]; // function, dead ; COMBINED-NEXT: // Edges: ; COMBINED-NEXT: M1_[[FOO]] -> M1_[[B]] [style=dashed,color=forestgreen]; // const-ref ; COMBINED-NEXT: M1_[[FOO]] -> M1_[[A]] [style=dashed,color=forestgreen]; // const-ref diff --git a/llvm/test/ThinLTO/X86/dot-dumper2.ll b/llvm/test/ThinLTO/X86/dot-dumper2.ll --- a/llvm/test/ThinLTO/X86/dot-dumper2.ll +++ b/llvm/test/ThinLTO/X86/dot-dumper2.ll @@ -15,7 +15,7 @@ ; COMBINED-NEXT: color = lightgrey; ; COMBINED-NEXT: label = ; COMBINED-NEXT: node [style=filled,fillcolor=lightblue]; -; COMBINED-NEXT: M0_[[MAIN:[0-9]+]] [shape="record",label="main|extern (inst: 2, ffl: 000000000)}"]; // function +; COMBINED-NEXT: M0_[[MAIN:[0-9]+]] [shape="record",label="main|extern (inst: 2, ffl: 0000000000)}"]; // function ; COMBINED-NEXT: // Edges: ; COMBINED-NEXT: } ; COMBINED-NEXT: // Module: diff --git a/llvm/test/ThinLTO/X86/funcattrs-prop-maythrow.ll b/llvm/test/ThinLTO/X86/funcattrs-prop-maythrow.ll --- a/llvm/test/ThinLTO/X86/funcattrs-prop-maythrow.ll +++ b/llvm/test/ThinLTO/X86/funcattrs-prop-maythrow.ll @@ -48,9 +48,9 @@ ; CHECK-DAG: attributes [[ATTR_NOUNWIND]] = { norecurse nounwind } ; CHECK-DAG: attributes [[ATTR_MAYTHROW]] = { norecurse } -; SUMMARY-DAG: = gv: (name: "cleanupret", summaries: (function: (module: ^0, flags: (linkage: external, visibility: default, notEligibleToImport: 0, live: 0, dsoLocal: 0, canAutoHide: 0), insts: 4, funcFlags: (readNone: 0, readOnly: 0, noRecurse: 0, returnDoesNotAlias: 0, noInline: 0, alwaysInline: 0, noUnwind: 0, mayThrow: 1, hasUnknownCall: 0), calls: ((callee: ^{{.*}})), refs: (^{{.*}})))) -; SUMMARY-DAG: = gv: (name: "resume", summaries: (function: (module: ^0, flags: (linkage: external, visibility: default, notEligibleToImport: 0, live: 0, dsoLocal: 0, canAutoHide: 0), insts: 4, funcFlags: (readNone: 0, readOnly: 0, noRecurse: 0, returnDoesNotAlias: 0, noInline: 0, alwaysInline: 0, noUnwind: 0, mayThrow: 1, hasUnknownCall: 0), calls: ((callee: ^{{.*}})), refs: (^{{.*}})))) -; SUMMARY-DAG: = gv: (name: "catchret", summaries: (function: (module: ^0, flags: (linkage: external, visibility: default, notEligibleToImport: 0, live: 0, dsoLocal: 0, canAutoHide: 0), insts: 5, funcFlags: (readNone: 0, readOnly: 0, noRecurse: 0, returnDoesNotAlias: 0, noInline: 0, alwaysInline: 0, noUnwind: 0, mayThrow: 1, hasUnknownCall: 0), calls: ((callee: ^{{.*}})), refs: (^{{.*}})))) +; SUMMARY-DAG: = gv: (name: "cleanupret", summaries: (function: (module: ^0, flags: (linkage: external, visibility: default, notEligibleToImport: 0, live: 0, dsoLocal: 0, canAutoHide: 0), insts: 4, funcFlags: (readNone: 0, readOnly: 0, noRecurse: 0, returnDoesNotAlias: 0, noInline: 0, alwaysInline: 0, noUnwind: 0, mayThrow: 1, hasUnknownCall: 0, mustBeUnreachable: 0), calls: ((callee: ^{{.*}})), refs: (^{{.*}})))) +; SUMMARY-DAG: = gv: (name: "resume", summaries: (function: (module: ^0, flags: (linkage: external, visibility: default, notEligibleToImport: 0, live: 0, dsoLocal: 0, canAutoHide: 0), insts: 4, funcFlags: (readNone: 0, readOnly: 0, noRecurse: 0, returnDoesNotAlias: 0, noInline: 0, alwaysInline: 0, noUnwind: 0, mayThrow: 1, hasUnknownCall: 0, mustBeUnreachable: 0), calls: ((callee: ^{{.*}})), refs: (^{{.*}})))) +; SUMMARY-DAG: = gv: (name: "catchret", summaries: (function: (module: ^0, flags: (linkage: external, visibility: default, notEligibleToImport: 0, live: 0, dsoLocal: 0, canAutoHide: 0), insts: 5, funcFlags: (readNone: 0, readOnly: 0, noRecurse: 0, returnDoesNotAlias: 0, noInline: 0, alwaysInline: 0, noUnwind: 0, mayThrow: 1, hasUnknownCall: 0, mustBeUnreachable: 0), calls: ((callee: ^{{.*}})), refs: (^{{.*}})))) ;--- callees.ll target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" diff --git a/llvm/test/ThinLTO/X86/funcimport_alwaysinline.ll b/llvm/test/ThinLTO/X86/funcimport_alwaysinline.ll --- a/llvm/test/ThinLTO/X86/funcimport_alwaysinline.ll +++ b/llvm/test/ThinLTO/X86/funcimport_alwaysinline.ll @@ -23,4 +23,4 @@ } attributes #0 = { alwaysinline nounwind uwtable } -; CHECK2: ^2 = gv: (guid: {{.*}}, summaries: (function: (module: ^0, flags: (linkage: external, visibility: default, notEligibleToImport: 0, live: 1, dsoLocal: 1, canAutoHide: 0), insts: 1, funcFlags: (readNone: 0, readOnly: 0, noRecurse: 0, returnDoesNotAlias: 0, noInline: 0, alwaysInline: 1, noUnwind: 1, mayThrow: 0, hasUnknownCall: 0)))) +; CHECK2: ^2 = gv: (guid: {{.*}}, summaries: (function: (module: ^0, flags: (linkage: external, visibility: default, notEligibleToImport: 0, live: 1, dsoLocal: 1, canAutoHide: 0), insts: 1, funcFlags: (readNone: 0, readOnly: 0, noRecurse: 0, returnDoesNotAlias: 0, noInline: 0, alwaysInline: 1, noUnwind: 1, mayThrow: 0, hasUnknownCall: 0, mustBeUnreachable: 0))))