Index: lib/Transforms/IPO/LowerTypeTests.cpp =================================================================== --- lib/Transforms/IPO/LowerTypeTests.cpp +++ lib/Transforms/IPO/LowerTypeTests.cpp @@ -956,6 +956,18 @@ FDecl = Function::Create(F->getFunctionType(), GlobalValue::ExternalLinkage, Name, &M); FDecl->setVisibility(Visibility); + + // Delete aliases pointing to this function, they'll be re-created in the + // merged output + for (auto &U : F->uses()) { + if (auto *A = dyn_cast(U.getUser())) { + Function *AliasDecl = Function::Create( + F->getFunctionType(), GlobalValue::ExternalLinkage, "", &M); + AliasDecl->takeName(A); + A->replaceAllUsesWith(AliasDecl); + A->eraseFromParent(); + } + } } else { // Function definition without type metadata, where some other translation // unit contained a declaration with type metadata. This normally happens @@ -1673,6 +1685,49 @@ } } + // Parse alias data to 1) remove aliases from the list of exported functions + // and 2) save which aliases should be created after the jump table functions + // they point to are created. + struct AliasInfo { + StringRef AliasName; + StringRef Aliasee; + GlobalValue::VisibilityTypes Visibility; + bool Weak; + }; + std::vector Aliases; + 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 (!ExportedFunctions.count(Aliasee) || + ExportedFunctions[Aliasee].Linkage != CFL_Definition) + continue; + + if (ExportedFunctions.count(AliasName)) { + ExportedFunctions.erase(AliasName); + M.getFunction(AliasName)->removeFromParent(); + } + + GlobalValue::VisibilityTypes Visibility = + static_cast( + cast(AliasMD->getOperand(2)) + ->getValue() + ->getUniqueInteger() + .getZExtValue()); + bool Weak = + static_cast(cast(AliasMD->getOperand(3)) + ->getValue() + ->getUniqueInteger() + .getZExtValue()); + + Aliases.push_back({AliasName, Aliasee, Visibility, Weak}); + } + } + } + for (GlobalObject &GO : M.global_objects()) { if (isa(GO) && GO.isDeclarationForLinker()) continue; @@ -1804,6 +1859,18 @@ allocateByteArrays(); + std::sort(Aliases.begin(), Aliases.end(), [](AliasInfo A1, AliasInfo A2) { + return A1.AliasName.equals_lower(A2.AliasName); + }); + for (auto &A : Aliases) { + if (!M.getNamedAlias(A.Aliasee)) + continue; + auto *Alias = GlobalAlias::create(A.AliasName, M.getNamedAlias(A.Aliasee)); + Alias->setVisibility(A.Visibility); + if (A.Weak) + Alias->setLinkage(GlobalValue::WeakAnyLinkage); + } + return true; } Index: lib/Transforms/IPO/ThinLTOBitcodeWriter.cpp =================================================================== --- lib/Transforms/IPO/ThinLTOBitcodeWriter.cpp +++ lib/Transforms/IPO/ThinLTOBitcodeWriter.cpp @@ -357,6 +357,31 @@ NMD->addOperand(MD); } + SmallVector FunctionAliases; + for (auto &A : M.aliases()) { + if (!isa(A.getAliasee())) + continue; + + auto *F = cast(A.getAliasee()); + auto &Ctx = MergedM->getContext(); + SmallVector Elts; + + Elts.push_back(MDString::get(Ctx, A.getName())); + Elts.push_back(MDString::get(Ctx, F->getName())); + Elts.push_back(ConstantAsMetadata::get( + llvm::ConstantInt::get(Type::getInt8Ty(Ctx), A.getVisibility()))); + Elts.push_back(ConstantAsMetadata::get( + llvm::ConstantInt::get(Type::getInt8Ty(Ctx), A.isWeakForLinker()))); + + FunctionAliases.push_back(MDTuple::get(Ctx, Elts)); + } + + if (!FunctionAliases.empty()) { + NamedMDNode *NMD = MergedM->getOrInsertNamedMetadata("aliases"); + for (auto MD : FunctionAliases) + NMD->addOperand(MD); + } + simplifyExternals(*MergedM); // FIXME: Try to re-use BSI and PFI from the original module here. Index: test/Transforms/LowerTypeTests/Inputs/import-alias.yaml =================================================================== --- /dev/null +++ test/Transforms/LowerTypeTests/Inputs/import-alias.yaml @@ -0,0 +1,11 @@ +--- +TypeIdMap: + typeid1: + TTRes: + Kind: AllOnes + SizeM1BitWidth: 7 +WithGlobalValueDeadStripping: false +CfiFunctionDefs: + - f +CfiFunctionDecls: +... Index: test/Transforms/LowerTypeTests/export-alias.ll =================================================================== --- /dev/null +++ test/Transforms/LowerTypeTests/export-alias.ll @@ -0,0 +1,21 @@ +; RUN: opt -S %s -lowertypetests -lowertypetests-summary-action=export -lowertypetests-read-summary=%S/Inputs/use-typeid1-typeid2.yaml | FileCheck %s +; +; CHECK: @alias1 = weak alias void (), void ()* @f +; CHECK: @alias2 = hidden alias void (), void ()* @f +; CHECK: declare !type !1 void @alias3() +; CHECK-NOT: @alias3 = alias + +target triple = "x86_64-unknown-linux" + +!cfi.functions = !{!0, !2, !3} +!aliases = !{!4, !5, !6} + +!0 = !{!"f", 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", !"f", i8 0, i8 1} +!5 = !{!"alias2", !"f", i8 1, i8 0} +!6 = !{!"alias3", !"not_present", i8 0, i8 0} Index: test/Transforms/LowerTypeTests/import-alias.ll =================================================================== --- /dev/null +++ test/Transforms/LowerTypeTests/import-alias.ll @@ -0,0 +1,30 @@ +; RUN: opt -S %s -lowertypetests -lowertypetests-summary-action=import -lowertypetests-read-summary=%S/Inputs/import-alias.yaml | FileCheck %s +; +; Check that the definitions for @f and @f_alias are removed from this module +; but @g_alias remains. +; +; CHECK: @g_alias = alias void (), void ()* @g +; CHECK: define hidden void @f.cfi +; CHECK: declare void @f() +; CHECK: declare void @f_alias() + +target triple = "x86_64-unknown-linux" + +@f_alias = alias void (), void ()* @f +@g_alias = alias void (), void ()* @g + +; Definition moved to the merged module +define void @f() { + ret void +} + +; Definition not moved to the merged module +define void @g() { + ret void +} + +define void @uses_aliases() { + call void @f_alias() + call void @g_alias() + ret void +}