diff --git a/llvm/include/llvm/LTO/LTO.h b/llvm/include/llvm/LTO/LTO.h index acc78bba43c61..323c478691a92 100644 --- a/llvm/include/llvm/LTO/LTO.h +++ b/llvm/include/llvm/LTO/LTO.h @@ -546,10 +546,12 @@ class LTO { // resolutions used by a single input module. Functions return ranges refering // to the resolutions for the remaining modules in the InputFile. Expected> - addModule(InputFile &Input, unsigned ModI, ArrayRef Res); + addModule(InputFile &Input, ArrayRef InputRes, + unsigned ModI, ArrayRef Res); Expected>> - addRegularLTO(BitcodeModule BM, ArrayRef Syms, + addRegularLTO(InputFile &Input, ArrayRef InputRes, + BitcodeModule BM, ArrayRef Syms, ArrayRef Res); Error linkRegularLTO(RegularLTOState::AddedModule Mod, bool LivenessFromIndex); diff --git a/llvm/lib/LTO/LTO.cpp b/llvm/lib/LTO/LTO.cpp index 7f07568ae3ede..814bb2a8b2352 100644 --- a/llvm/lib/LTO/LTO.cpp +++ b/llvm/lib/LTO/LTO.cpp @@ -743,8 +743,9 @@ Error LTO::add(std::unique_ptr Input, Conf.VisibilityScheme = Config::ELF; } + ArrayRef InputRes = Res; for (unsigned I = 0; I != Input->Mods.size(); ++I) { - if (auto Err = addModule(*Input, I, Res).moveInto(Res)) + if (auto Err = addModule(*Input, InputRes, I, Res).moveInto(Res)) return Err; } @@ -753,8 +754,8 @@ Error LTO::add(std::unique_ptr Input, } Expected> -LTO::addModule(InputFile &Input, unsigned ModI, - ArrayRef Res) { +LTO::addModule(InputFile &Input, ArrayRef InputRes, + unsigned ModI, ArrayRef Res) { Expected LTOInfo = Input.Mods[ModI].getLTOInfo(); if (!LTOInfo) return LTOInfo.takeError(); @@ -791,7 +792,7 @@ LTO::addModule(InputFile &Input, unsigned ModI, return addThinLTO(BM, ModSyms, Res); RegularLTO.EmptyCombinedModule = false; - auto ModOrErr = addRegularLTO(BM, ModSyms, Res); + auto ModOrErr = addRegularLTO(Input, InputRes, BM, ModSyms, Res); if (!ModOrErr) return ModOrErr.takeError(); Res = ModOrErr->second; @@ -846,7 +847,8 @@ handleNonPrevailingComdat(GlobalValue &GV, // linkRegularLTO. Expected< std::pair>> -LTO::addRegularLTO(BitcodeModule BM, ArrayRef Syms, +LTO::addRegularLTO(InputFile &Input, ArrayRef InputRes, + BitcodeModule BM, ArrayRef Syms, ArrayRef Res) { RegularLTOState::AddedModule Mod; Expected> MOrErr = @@ -860,13 +862,34 @@ LTO::addRegularLTO(BitcodeModule BM, ArrayRef Syms, if (Error Err = M.materializeMetadata()) return std::move(Err); - // If cfi.functions is present and we are in regular LTO mode, LowerTypeTests - // will rename local functions in the merged module as ".1". - // This causes linking errors, since other parts of the module expect the - // original function name. - if (LTOMode == LTOK_UnifiedRegular) + if (LTOMode == LTOK_UnifiedRegular) { + // cfi.functions metadata is intended to be used with ThinLTO and may + // trigger invalid IR transformations if they are present when doing regular + // LTO, so delete it. if (NamedMDNode *CfiFunctionsMD = M.getNamedMetadata("cfi.functions")) M.eraseNamedMetadata(CfiFunctionsMD); + } else if (NamedMDNode *AliasesMD = M.getNamedMetadata("aliases")) { + // Delete aliases entries for non-prevailing symbols on the ThinLTO side of + // this input file. + DenseSet Prevailing; + for (auto [I, R] : zip(Input.symbols(), Res)) + if (R.Prevailing && !I.getIRName().empty()) + Prevailing.insert(I.getIRName()); + std::vector AliasGroups; + for (MDNode *AliasGroup : AliasesMD->operands()) { + std::vector Aliases; + for (Metadata *Alias : AliasGroup->operands()) { + if (isa(Alias) && + Prevailing.count(cast(Alias)->getString())) + Aliases.push_back(Alias); + } + if (Aliases.size() > 1) + AliasGroups.push_back(MDTuple::get(RegularLTO.Ctx, Aliases)); + } + AliasesMD->clearOperands(); + for (MDNode *G : AliasGroups) + AliasesMD->addOperand(G); + } UpgradeDebugInfo(M); diff --git a/llvm/lib/Transforms/IPO/LowerTypeTests.cpp b/llvm/lib/Transforms/IPO/LowerTypeTests.cpp index 486205c8a3848..57844a10aa9c5 100644 --- a/llvm/lib/Transforms/IPO/LowerTypeTests.cpp +++ b/llvm/lib/Transforms/IPO/LowerTypeTests.cpp @@ -502,8 +502,7 @@ class LowerTypeTestsModule { uint8_t *exportTypeId(StringRef TypeId, const TypeIdLowering &TIL); TypeIdLowering importTypeId(StringRef TypeId); void importTypeTest(CallInst *CI); - void importFunction(Function *F, bool isJumpTableCanonical, - std::vector &AliasesToErase); + void importFunction(Function *F, bool isJumpTableCanonical); BitSetInfo buildBitSet(Metadata *TypeId, @@ -1103,9 +1102,8 @@ void LowerTypeTestsModule::maybeReplaceComdat(Function *F, // ThinLTO backend: the function F has a jump table entry; update this module // accordingly. isJumpTableCanonical describes the type of the jump table entry. -void LowerTypeTestsModule::importFunction( - Function *F, bool isJumpTableCanonical, - std::vector &AliasesToErase) { +void LowerTypeTestsModule::importFunction(Function *F, + bool isJumpTableCanonical) { assert(F->getType()->getAddressSpace() == 0); GlobalValue::VisibilityTypes Visibility = F->getVisibility(); @@ -1135,23 +1133,23 @@ void LowerTypeTestsModule::importFunction( } else { F->setName(Name + ".cfi"); maybeReplaceComdat(F, Name); - F->setLinkage(GlobalValue::ExternalLinkage); FDecl = Function::Create(F->getFunctionType(), GlobalValue::ExternalLinkage, F->getAddressSpace(), Name, &M); FDecl->setVisibility(Visibility); Visibility = GlobalValue::HiddenVisibility; - // Delete aliases pointing to this function, they'll be re-created in the - // merged output. Don't do it yet though because ScopedSaveAliaseesAndUsed - // will want to reset the aliasees first. + // Update aliases pointing to this function to also include the ".cfi" suffix, + // We expect the jump table entry to either point to the real function or an + // alias. Redirect all other users to the jump table entry. for (auto &U : F->uses()) { if (auto *A = dyn_cast(U.getUser())) { + std::string AliasName = A->getName().str() + ".cfi"; Function *AliasDecl = Function::Create( F->getFunctionType(), GlobalValue::ExternalLinkage, F->getAddressSpace(), "", &M); AliasDecl->takeName(A); A->replaceAllUsesWith(AliasDecl); - AliasesToErase.push_back(A); + A->setName(AliasName); } } } @@ -2077,16 +2075,13 @@ bool LowerTypeTestsModule::lower() { Decls.push_back(&F); } - std::vector AliasesToErase; { ScopedSaveAliaseesAndUsed S(M); for (auto *F : Defs) - importFunction(F, /*isJumpTableCanonical*/ true, AliasesToErase); + importFunction(F, /*isJumpTableCanonical*/ true); for (auto *F : Decls) - importFunction(F, /*isJumpTableCanonical*/ false, AliasesToErase); + importFunction(F, /*isJumpTableCanonical*/ false); } - for (GlobalAlias *GA : AliasesToErase) - GA->eraseFromParent(); return true; } @@ -2137,6 +2132,18 @@ bool LowerTypeTestsModule::lower() { if (auto Alias = dyn_cast(RefGVS.get())) AddressTaken.insert(Alias->getAliaseeGUID()); } + auto IsAddressTaken = [&](GlobalValue::GUID GUID) { + if (AddressTaken.count(GUID)) + return true; + auto VI = ExportSummary->getValueInfo(GUID); + if (!VI) + return false; + for (auto &I : VI.getSummaryList()) + if (auto Alias = dyn_cast(I.get())) + if (AddressTaken.count(Alias->getAliaseeGUID())) + return true; + return false; + }; for (auto *FuncMD : CfiFunctionsMD->operands()) { assert(FuncMD->getNumOperands() >= 2); StringRef FunctionName = @@ -2153,7 +2160,7 @@ bool LowerTypeTestsModule::lower() { // have no live references (and are not exported with cross-DSO CFI.) if (!ExportSummary->isGUIDLive(GUID)) continue; - if (!AddressTaken.count(GUID)) { + if (!IsAddressTaken(GUID)) { if (!CrossDsoCfi || Linkage != CFL_Definition) continue; @@ -2227,6 +2234,43 @@ bool LowerTypeTestsModule::lower() { } } + struct AliasToCreate { + Function *Alias; + std::string TargetName; + }; + std::vector AliasesToCreate; + + // Parse alias data to replace stand-in function declarations for aliases + // with an alias to the intended target. + if (ExportSummary) { + if (NamedMDNode *AliasesMD = M.getNamedMetadata("aliases")) { + for (auto *AliasMD : AliasesMD->operands()) { + SmallVector Aliases; + for (Metadata *MD : AliasMD->operands()) { + auto *MDS = dyn_cast(MD); + if (!MDS) + continue; + StringRef AliasName = MDS->getString(); + if (!ExportedFunctions.count(AliasName)) + continue; + auto *AliasF = M.getFunction(AliasName); + if (AliasF) + Aliases.push_back(AliasF); + } + + if (Aliases.empty()) + continue; + + for (unsigned I = 1; I != Aliases.size(); ++I) { + auto *AliasF = Aliases[I]; + ExportedFunctions.erase(AliasF->getName()); + AliasesToCreate.push_back( + {AliasF, std::string(Aliases[0]->getName())}); + } + } + } + } + DenseMap GlobalTypeMembers; for (GlobalObject &GO : M.global_objects()) { if (isa(GO) && GO.isDeclarationForLinker()) @@ -2414,47 +2458,16 @@ bool LowerTypeTestsModule::lower() { allocateByteArrays(); - // Parse alias data to replace stand-in function declarations for aliases - // with an alias to the intended target. - if (ExportSummary) { - if (NamedMDNode *AliasesMD = M.getNamedMetadata("aliases")) { - for (auto *AliasMD : AliasesMD->operands()) { - assert(AliasMD->getNumOperands() >= 4); - StringRef AliasName = - cast(AliasMD->getOperand(0))->getString(); - StringRef Aliasee = cast(AliasMD->getOperand(1))->getString(); - - if (auto It = ExportedFunctions.find(Aliasee); - It == ExportedFunctions.end() || - It->second.Linkage != CFL_Definition || !M.getNamedAlias(Aliasee)) - continue; - - GlobalValue::VisibilityTypes Visibility = - static_cast( - cast(AliasMD->getOperand(2)) - ->getValue() - ->getUniqueInteger() - .getZExtValue()); - bool Weak = - static_cast(cast(AliasMD->getOperand(3)) - ->getValue() - ->getUniqueInteger() - .getZExtValue()); - - auto *Alias = GlobalAlias::create("", M.getNamedAlias(Aliasee)); - Alias->setVisibility(Visibility); - if (Weak) - Alias->setLinkage(GlobalValue::WeakAnyLinkage); - - if (auto *F = M.getFunction(AliasName)) { - Alias->takeName(F); - F->replaceAllUsesWith(Alias); - F->eraseFromParent(); - } else { - Alias->setName(AliasName); - } - } - } + for (auto A : AliasesToCreate) { + auto *Target = M.getNamedValue(A.TargetName); + if (!isa(Target)) + continue; + auto *AliasGA = GlobalAlias::create("", Target); + AliasGA->setVisibility(A.Alias->getVisibility()); + AliasGA->setLinkage(A.Alias->getLinkage()); + AliasGA->takeName(A.Alias); + A.Alias->replaceAllUsesWith(AliasGA); + A.Alias->eraseFromParent(); } // Emit .symver directives for exported functions, if they exist. diff --git a/llvm/lib/Transforms/IPO/ThinLTOBitcodeWriter.cpp b/llvm/lib/Transforms/IPO/ThinLTOBitcodeWriter.cpp index e276376f21583..4387c3827c015 100644 --- a/llvm/lib/Transforms/IPO/ThinLTOBitcodeWriter.cpp +++ b/llvm/lib/Transforms/IPO/ThinLTOBitcodeWriter.cpp @@ -384,6 +384,10 @@ void splitAndWriteThinLTOBitcode( for (auto &F : M) if ((!F.hasLocalLinkage() || F.hasAddressTaken()) && HasTypeMetadata(&F)) CfiFunctions.insert(&F); + for (auto &A : M.aliases()) + if (auto *F = dyn_cast(A.getAliasee())) + if (HasTypeMetadata(F)) + CfiFunctions.insert(&A); // Remove all globals with type metadata, globals with comdats that live in // MergedM, and aliases pointing to such globals from the thin LTO module. @@ -403,12 +407,12 @@ void splitAndWriteThinLTOBitcode( auto &Ctx = MergedM->getContext(); SmallVector CfiFunctionMDs; for (auto *V : CfiFunctions) { - Function &F = *cast(V); + Function &F = *cast(V->getAliaseeObject()); SmallVector Types; F.getMetadata(LLVMContext::MD_type, Types); SmallVector Elts; - Elts.push_back(MDString::get(Ctx, F.getName())); + Elts.push_back(MDString::get(Ctx, V->getName())); CfiFunctionLinkage Linkage; if (lowertypetests::isJumpTableCanonical(&F)) Linkage = CFL_Definition; @@ -428,29 +432,24 @@ void splitAndWriteThinLTOBitcode( NMD->addOperand(MD); } - SmallVector FunctionAliases; + MapVector> FunctionAliases; for (auto &A : M.aliases()) { if (!isa(A.getAliasee())) continue; auto *F = cast(A.getAliasee()); - - Metadata *Elts[] = { - MDString::get(Ctx, A.getName()), - MDString::get(Ctx, F->getName()), - ConstantAsMetadata::get( - ConstantInt::get(Type::getInt8Ty(Ctx), A.getVisibility())), - ConstantAsMetadata::get( - ConstantInt::get(Type::getInt8Ty(Ctx), A.isWeakForLinker())), - }; - - FunctionAliases.push_back(MDTuple::get(Ctx, Elts)); + FunctionAliases[F].push_back(&A); } if (!FunctionAliases.empty()) { NamedMDNode *NMD = MergedM->getOrInsertNamedMetadata("aliases"); - for (auto *MD : FunctionAliases) - NMD->addOperand(MD); + for (auto &Alias : FunctionAliases) { + SmallVector Elts; + Elts.push_back(MDString::get(Ctx, Alias.first->getName())); + for (auto *A : Alias.second) + Elts.push_back(MDString::get(Ctx, A->getName())); + NMD->addOperand(MDTuple::get(Ctx, Elts)); + } } SmallVector Symvers; diff --git a/llvm/test/Transforms/LowerTypeTests/Inputs/exported-funcs.yaml b/llvm/test/Transforms/LowerTypeTests/Inputs/exported-funcs.yaml index 5457e36573bb7..81df2f198f91b 100644 --- a/llvm/test/Transforms/LowerTypeTests/Inputs/exported-funcs.yaml +++ b/llvm/test/Transforms/LowerTypeTests/Inputs/exported-funcs.yaml @@ -19,4 +19,12 @@ GlobalValueMap: 15859245615183425489: # guid("internal") - Linkage: 7 # internal Live: true + 1062103744896965210: # guid("alias1") + - Linkage: 4 # weak + Live: true + Aliasee: 16594175687743574550 # guid("external_addrtaken") + 2510616090736846890: # guid("alias2") + - Linkage: 0 # weak + Live: true + Aliasee: 16594175687743574550 # guid("external_addrtaken") ... diff --git a/llvm/test/Transforms/LowerTypeTests/export-alias.ll b/llvm/test/Transforms/LowerTypeTests/export-alias.ll index 45b4db63def18..25d34833c82c3 100644 --- a/llvm/test/Transforms/LowerTypeTests/export-alias.ll +++ b/llvm/test/Transforms/LowerTypeTests/export-alias.ll @@ -1,21 +1,19 @@ ; RUN: opt -S %s -passes=lowertypetests -lowertypetests-summary-action=export -lowertypetests-read-summary=%S/Inputs/exported-funcs.yaml | FileCheck %s ; -; CHECK: @alias1 = weak alias [8 x i8], ptr @external_addrtaken -; CHECK: @alias2 = hidden alias [8 x i8], ptr @external_addrtaken +; CHECK: @alias1 = alias [8 x i8], ptr @external_addrtaken +; CHECK: @alias2 = alias [8 x i8], ptr @external_addrtaken ; CHECK-NOT: @alias3 = alias ; CHECK-NOT: @not_present target triple = "x86_64-unknown-linux" -!cfi.functions = !{!0, !2, !3} -!aliases = !{!4, !5, !6} +!cfi.functions = !{!0, !2, !3, !4} +!aliases = !{!5, !6} !0 = !{!"external_addrtaken", i8 0, !1} !1 = !{i64 0, !"typeid1"} -!2 = !{!"alias1", i8 1, !1} -; alias2 not included here, this could happen if the only reference to alias2 -; is in a module compiled without cfi-icall -!3 = !{!"alias3", i8 1, !1} -!4 = !{!"alias1", !"external_addrtaken", i8 0, i8 1} -!5 = !{!"alias2", !"external_addrtaken", i8 1, i8 0} -!6 = !{!"alias3", !"not_present", i8 0, i8 0} +!2 = !{!"alias1", i8 0, !1} +!3 = !{!"alias2", i8 0, !1} +!4 = !{!"alias3", i8 0, !1} +!5 = !{!"external_addrtaken", !"alias1", !"alias2"} +!6 = !{!"not_present", !"alias3"} diff --git a/llvm/test/Transforms/ThinLTOBitcodeWriter/function-alias.ll b/llvm/test/Transforms/ThinLTOBitcodeWriter/function-alias.ll index efc04e99f0459..74693c1312b01 100644 --- a/llvm/test/Transforms/ThinLTOBitcodeWriter/function-alias.ll +++ b/llvm/test/Transforms/ThinLTOBitcodeWriter/function-alias.ll @@ -7,11 +7,16 @@ define hidden void @Func() !type !0 { ret void } -; CHECK1: !aliases = !{![[A1:[0-9]+]], ![[A2:[0-9]+]], ![[A3:[0-9]+]]} +; CHECK1: !cfi.functions = !{![[F1:[0-9]+]], ![[F2:[0-9]+]], ![[F3:[0-9]+]], ![[F4:[0-9]+]]} +; CHECK1: !aliases = !{![[A:[0-9]+]]} -; CHECK1: ![[A1]] = !{!"Alias", !"Func", i8 1, i8 0} -; CHECK1: ![[A2]] = !{!"Hidden_Alias", !"Func", i8 1, i8 0} -; CHECK1: ![[A3]] = !{!"Weak_Alias", !"Func", i8 0, i8 1} +; CHECK1: ![[F1]] = !{!"Func", i8 0, ![[T:[0-9]+]]} +; CHECK1: ![[T]] = !{i64 0, !"_ZTSFvvE"} +; CHECK1: ![[F2]] = !{!"Alias", i8 0, ![[T]]} +; CHECK1: ![[F3]] = !{!"Hidden_Alias", i8 0, ![[T]]} +; CHECK1: ![[F4]] = !{!"Weak_Alias", i8 0, ![[T]]} +; +; CHECK1: ![[A]] = !{!"Func", !"Alias", !"Hidden_Alias", !"Weak_Alias"} @Alias = hidden alias void (), ptr @Func @Hidden_Alias = hidden alias void (), ptr @Func @Weak_Alias = weak alias void (), ptr @Func