diff options
Diffstat (limited to 'llvm/lib')
| -rw-r--r-- | llvm/lib/Bitcode/Reader/BitcodeReader.cpp | 12 | ||||
| -rw-r--r-- | llvm/lib/Bitcode/Writer/BitcodeWriter.cpp | 50 | ||||
| -rw-r--r-- | llvm/lib/IR/ModuleSummaryIndex.cpp | 7 | ||||
| -rw-r--r-- | llvm/lib/Transforms/IPO/CrossDSOCFI.cpp | 11 | ||||
| -rw-r--r-- | llvm/lib/Transforms/IPO/LowerTypeTests.cpp | 166 | ||||
| -rw-r--r-- | llvm/lib/Transforms/IPO/ThinLTOBitcodeWriter.cpp | 50 | 
6 files changed, 264 insertions, 32 deletions
diff --git a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp index e732daaea2e..f944cc8c955 100644 --- a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp +++ b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp @@ -5252,6 +5252,18 @@ Error ModuleSummaryIndexBitcodeReader::parseEntireSummary(unsigned ID) {            {{Record[0], Record[1]}, {Record.begin() + 2, Record.end()}});        break;      } +    case bitc::FS_CFI_FUNCTION_DEFS: { +      std::set<std::string> &CfiFunctionDefs = TheIndex.cfiFunctionDefs(); +      for (unsigned I = 0; I != Record.size(); I += 2) +        CfiFunctionDefs.insert({Strtab.data() + Record[I], Record[I+1]}); +      break; +    } +    case bitc::FS_CFI_FUNCTION_DECLS: { +      std::set<std::string> &CfiFunctionDecls = TheIndex.cfiFunctionDecls(); +      for (unsigned I = 0; I != Record.size(); I += 2) +        CfiFunctionDecls.insert({Strtab.data() + Record[I], Record[I+1]}); +      break; +    }      }    }    llvm_unreachable("Exit infinite loop"); diff --git a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp index e679424bf1f..feeba31908a 100644 --- a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp +++ b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp @@ -77,10 +77,13 @@ protected:    /// The stream created and owned by the client.    BitstreamWriter &Stream; +  StringTableBuilder &StrtabBuilder; +  public:    /// Constructs a BitcodeWriterBase object that writes to the provided    /// \p Stream. -  BitcodeWriterBase(BitstreamWriter &Stream) : Stream(Stream) {} +  BitcodeWriterBase(BitstreamWriter &Stream, StringTableBuilder &StrtabBuilder) +      : Stream(Stream), StrtabBuilder(StrtabBuilder) {}  protected:    void writeBitcodeHeader(); @@ -97,8 +100,6 @@ class ModuleBitcodeWriter : public BitcodeWriterBase {    /// Pointer to the buffer allocated by caller for bitcode writing.    const SmallVectorImpl<char> &Buffer; -  StringTableBuilder &StrtabBuilder; -    /// The Module to write to bitcode.    const Module &M; @@ -142,8 +143,8 @@ public:                        BitstreamWriter &Stream, bool ShouldPreserveUseListOrder,                        const ModuleSummaryIndex *Index, bool GenerateHash,                        ModuleHash *ModHash = nullptr) -      : BitcodeWriterBase(Stream), Buffer(Buffer), StrtabBuilder(StrtabBuilder), -        M(*M), VE(*M, ShouldPreserveUseListOrder), Index(Index), +      : BitcodeWriterBase(Stream, StrtabBuilder), Buffer(Buffer), M(*M), +        VE(*M, ShouldPreserveUseListOrder), Index(Index),          GenerateHash(GenerateHash), ModHash(ModHash),          BitcodeStartBit(Stream.GetCurrentBitNo()) {      // Assign ValueIds to any callee values in the index that came from @@ -331,10 +332,11 @@ public:    /// Constructs a IndexBitcodeWriter object for the given combined index,    /// writing to the provided \p Buffer. When writing a subset of the index    /// for a distributed backend, provide a \p ModuleToSummariesForIndex map. -  IndexBitcodeWriter(BitstreamWriter &Stream, const ModuleSummaryIndex &Index, +  IndexBitcodeWriter(BitstreamWriter &Stream, StringTableBuilder &StrtabBuilder, +                     const ModuleSummaryIndex &Index,                       const std::map<std::string, GVSummaryMapTy>                           *ModuleToSummariesForIndex = nullptr) -      : BitcodeWriterBase(Stream), Index(Index), +      : BitcodeWriterBase(Stream, StrtabBuilder), Index(Index),          ModuleToSummariesForIndex(ModuleToSummariesForIndex) {      // Assign unique value ids to all summaries to be written, for use      // in writing out the call graph edges. Save the mapping from GUID @@ -3595,6 +3597,24 @@ void IndexBitcodeWriter::writeCombinedGlobalValueSummary() {      MaybeEmitOriginalName(*AS);    } +  if (!Index.cfiFunctionDefs().empty()) { +    for (auto &S : Index.cfiFunctionDefs()) { +      NameVals.push_back(StrtabBuilder.add(S)); +      NameVals.push_back(S.size()); +    } +    Stream.EmitRecord(bitc::FS_CFI_FUNCTION_DEFS, NameVals); +    NameVals.clear(); +  } + +  if (!Index.cfiFunctionDecls().empty()) { +    for (auto &S : Index.cfiFunctionDecls()) { +      NameVals.push_back(StrtabBuilder.add(S)); +      NameVals.push_back(S.size()); +    } +    Stream.EmitRecord(bitc::FS_CFI_FUNCTION_DECLS, NameVals); +    NameVals.clear(); +  } +    Stream.ExitBlock();  } @@ -3829,6 +3849,14 @@ void BitcodeWriter::writeModule(const Module *M,    ModuleWriter.write();  } +void BitcodeWriter::writeIndex( +    const ModuleSummaryIndex *Index, +    const std::map<std::string, GVSummaryMapTy> *ModuleToSummariesForIndex) { +  IndexBitcodeWriter IndexWriter(*Stream, StrtabBuilder, *Index, +                                 ModuleToSummariesForIndex); +  IndexWriter.write(); +} +  /// WriteBitcodeToFile - Write the specified module to the specified output  /// stream.  void llvm::WriteBitcodeToFile(const Module *M, raw_ostream &Out, @@ -3880,11 +3908,9 @@ void llvm::WriteIndexToFile(    SmallVector<char, 0> Buffer;    Buffer.reserve(256 * 1024); -  BitstreamWriter Stream(Buffer); -  writeBitcodeHeader(Stream); - -  IndexBitcodeWriter IndexWriter(Stream, Index, ModuleToSummariesForIndex); -  IndexWriter.write(); +  BitcodeWriter Writer(Buffer); +  Writer.writeIndex(&Index, ModuleToSummariesForIndex); +  Writer.writeStrtab();    Out.write((char *)&Buffer.front(), Buffer.size());  } diff --git a/llvm/lib/IR/ModuleSummaryIndex.cpp b/llvm/lib/IR/ModuleSummaryIndex.cpp index 721d4d47e36..51c4bae3332 100644 --- a/llvm/lib/IR/ModuleSummaryIndex.cpp +++ b/llvm/lib/IR/ModuleSummaryIndex.cpp @@ -60,8 +60,11 @@ ModuleSummaryIndex::getGlobalValueSummary(uint64_t ValueGUID,  bool ModuleSummaryIndex::isGUIDLive(GlobalValue::GUID GUID) const {    auto VI = getValueInfo(GUID);    if (!VI) -    return false; -  for (auto &I : VI.getSummaryList()) +    return true; +  const auto &SummaryList = VI.getSummaryList(); +  if (SummaryList.empty()) +    return true; +  for (auto &I : SummaryList)      if (isGlobalValueLive(I.get()))        return true;    return false; diff --git a/llvm/lib/Transforms/IPO/CrossDSOCFI.cpp b/llvm/lib/Transforms/IPO/CrossDSOCFI.cpp index 1b111de0615..d94aa5da856 100644 --- a/llvm/lib/Transforms/IPO/CrossDSOCFI.cpp +++ b/llvm/lib/Transforms/IPO/CrossDSOCFI.cpp @@ -95,6 +95,17 @@ void CrossDSOCFI::buildCFICheck(Module &M) {      }    } +  NamedMDNode *CfiFunctionsMD = M.getNamedMetadata("cfi.functions"); +  if (CfiFunctionsMD) { +    for (auto Func : CfiFunctionsMD->operands()) { +      assert(Func->getNumOperands() >= 2); +      for (unsigned I = 2; I < Func->getNumOperands(); ++I) +        if (ConstantInt *TypeId = +                extractNumericTypeId(cast<MDNode>(Func->getOperand(I).get()))) +          TypeIds.insert(TypeId->getZExtValue()); +    } +  } +    LLVMContext &Ctx = M.getContext();    Constant *C = M.getOrInsertFunction(        "__cfi_check", Type::getVoidTy(Ctx), Type::getInt64Ty(Ctx), diff --git a/llvm/lib/Transforms/IPO/LowerTypeTests.cpp b/llvm/lib/Transforms/IPO/LowerTypeTests.cpp index 90896d285f5..b406c22c69d 100644 --- a/llvm/lib/Transforms/IPO/LowerTypeTests.cpp +++ b/llvm/lib/Transforms/IPO/LowerTypeTests.cpp @@ -17,6 +17,7 @@  #include "llvm/ADT/SetVector.h"  #include "llvm/ADT/Statistic.h"  #include "llvm/ADT/Triple.h" +#include "llvm/Analysis/TypeMetadataUtils.h"  #include "llvm/IR/Constant.h"  #include "llvm/IR/Constants.h"  #include "llvm/IR/Function.h" @@ -206,17 +207,26 @@ struct ByteArrayInfo {  class GlobalTypeMember final : TrailingObjects<GlobalTypeMember, MDNode *> {    GlobalObject *GO;    size_t NTypes; +  // For functions: true if this is a definition (either in the merged module or +  // in one of the thinlto modules). +  bool IsDefinition; +  // For functions: true if this function is either defined or used in a thinlto +  // module and its jumptable entry needs to be exported to thinlto backends. +  bool IsExported;    friend TrailingObjects;    size_t numTrailingObjects(OverloadToken<MDNode *>) const { return NTypes; }  public:    static GlobalTypeMember *create(BumpPtrAllocator &Alloc, GlobalObject *GO, +                                  bool IsDefinition, bool IsExported,                                    ArrayRef<MDNode *> Types) {      auto *GTM = static_cast<GlobalTypeMember *>(Alloc.Allocate(          totalSizeToAlloc<MDNode *>(Types.size()), alignof(GlobalTypeMember)));      GTM->GO = GO;      GTM->NTypes = Types.size(); +    GTM->IsDefinition = IsDefinition; +    GTM->IsExported = IsExported;      std::uninitialized_copy(Types.begin(), Types.end(),                              GTM->getTrailingObjects<MDNode *>());      return GTM; @@ -224,6 +234,12 @@ public:    GlobalObject *getGlobal() const {      return GO;    } +  bool isDefinition() const { +    return IsDefinition; +  } +  bool isExported() const { +    return IsExported; +  }    ArrayRef<MDNode *> types() const {      return makeArrayRef(getTrailingObjects<MDNode *>(), NTypes);    } @@ -294,6 +310,7 @@ class LowerTypeTestsModule {    void exportTypeId(StringRef TypeId, const TypeIdLowering &TIL);    TypeIdLowering importTypeId(StringRef TypeId);    void importTypeTest(CallInst *CI); +  void importFunction(Function *F, bool isDefinition);    BitSetInfo    buildBitSet(Metadata *TypeId, @@ -820,6 +837,41 @@ void LowerTypeTestsModule::importTypeTest(CallInst *CI) {    CI->eraseFromParent();  } +// ThinLTO backend: the function F has a jump table entry; update this module +// accordingly. isDefinition describes the type of the jump table entry. +void LowerTypeTestsModule::importFunction(Function *F, bool isDefinition) { +  assert(F->getType()->getAddressSpace() == 0); + +  // Declaration of a local function - nothing to do. +  if (F->isDeclarationForLinker() && isDefinition) +    return; + +  GlobalValue::VisibilityTypes Visibility = F->getVisibility(); +  std::string Name = F->getName(); +  Function *FDecl; + +  if (F->isDeclarationForLinker() && !isDefinition) { +    // Declaration of an external function. +    FDecl = Function::Create(F->getFunctionType(), GlobalValue::ExternalLinkage, +                             Name + ".cfi_jt", &M); +    FDecl->setVisibility(GlobalValue::HiddenVisibility); +  } else { +    // Definition. +    assert(isDefinition); +    F->setName(Name + ".cfi"); +    F->setLinkage(GlobalValue::ExternalLinkage); +    F->setVisibility(GlobalValue::HiddenVisibility); +    FDecl = Function::Create(F->getFunctionType(), GlobalValue::ExternalLinkage, +                             Name, &M); +    FDecl->setVisibility(Visibility); +  } + +  if (F->isWeakForLinker()) +    replaceWeakDeclarationWithJumpTablePtr(F, FDecl); +  else +    F->replaceAllUsesWith(FDecl); +} +  void LowerTypeTestsModule::lowerTypeTestCalls(      ArrayRef<Metadata *> TypeIds, Constant *CombinedGlobalAddr,      const DenseMap<GlobalTypeMember *, uint64_t> &GlobalLayout) { @@ -1143,7 +1195,6 @@ void LowerTypeTestsModule::buildBitSetsFromFunctionsNative(    // arithmetic that we normally use for globals.    // FIXME: find a better way to represent the jumptable in the IR. -    assert(!Functions.empty());    // Build a simple layout based on the regular layout of jump tables. @@ -1167,6 +1218,7 @@ void LowerTypeTestsModule::buildBitSetsFromFunctionsNative(    // references to the original functions with references to the aliases.    for (unsigned I = 0; I != Functions.size(); ++I) {      Function *F = cast<Function>(Functions[I]->getGlobal()); +    bool IsDefinition = Functions[I]->isDefinition();      Constant *CombinedGlobalElemPtr = ConstantExpr::getBitCast(          ConstantExpr::getInBoundsGetElementPtr( @@ -1174,7 +1226,18 @@ void LowerTypeTestsModule::buildBitSetsFromFunctionsNative(              ArrayRef<Constant *>{ConstantInt::get(IntPtrTy, 0),                                   ConstantInt::get(IntPtrTy, I)}),          F->getType()); -    if (F->isDeclarationForLinker()) { +    if (Functions[I]->isExported()) { +      if (IsDefinition) { +        ExportSummary->cfiFunctionDefs().insert(F->getName()); +      } else { +        GlobalAlias *JtAlias = GlobalAlias::create( +            F->getValueType(), 0, GlobalValue::ExternalLinkage, +            F->getName() + ".cfi_jt", CombinedGlobalElemPtr, &M); +        JtAlias->setVisibility(GlobalValue::HiddenVisibility); +        ExportSummary->cfiFunctionDecls().insert(F->getName()); +      } +    } +    if (!IsDefinition) {        if (F->isWeakForLinker())          replaceWeakDeclarationWithJumpTablePtr(F, CombinedGlobalElemPtr);        else @@ -1182,9 +1245,8 @@ void LowerTypeTestsModule::buildBitSetsFromFunctionsNative(      } else {        assert(F->getType()->getAddressSpace() == 0); -      GlobalAlias *FAlias = GlobalAlias::create(F->getValueType(), 0, -                                                F->getLinkage(), "", -                                                CombinedGlobalElemPtr, &M); +      GlobalAlias *FAlias = GlobalAlias::create( +          F->getValueType(), 0, F->getLinkage(), "", CombinedGlobalElemPtr, &M);        FAlias->setVisibility(F->getVisibility());        FAlias->takeName(F);        if (FAlias->hasName()) @@ -1353,15 +1415,37 @@ bool LowerTypeTestsModule::runForTesting(Module &M) {  bool LowerTypeTestsModule::lower() {    Function *TypeTestFunc =        M.getFunction(Intrinsic::getName(Intrinsic::type_test)); -  if ((!TypeTestFunc || TypeTestFunc->use_empty()) && !ExportSummary) +  if ((!TypeTestFunc || TypeTestFunc->use_empty()) && !ExportSummary && +      !ImportSummary)      return false;    if (ImportSummary) { -    for (auto UI = TypeTestFunc->use_begin(), UE = TypeTestFunc->use_end(); -         UI != UE;) { -      auto *CI = cast<CallInst>((*UI++).getUser()); -      importTypeTest(CI); +    if (TypeTestFunc) { +      for (auto UI = TypeTestFunc->use_begin(), UE = TypeTestFunc->use_end(); +           UI != UE;) { +        auto *CI = cast<CallInst>((*UI++).getUser()); +        importTypeTest(CI); +      } +    } + +    SmallVector<Function *, 8> Defs; +    SmallVector<Function *, 8> Decls; +    for (auto &F : M) { +      // CFI functions are either external, or promoted. A local function may +      // have the same name, but it's not the one we are looking for. +      if (F.hasLocalLinkage()) +        continue; +      if (ImportSummary->cfiFunctionDefs().count(F.getName())) +        Defs.push_back(&F); +      else if (ImportSummary->cfiFunctionDecls().count(F.getName())) +        Decls.push_back(&F);      } + +    for (auto F : Defs) +      importFunction(F, /*isDefinition*/ true); +    for (auto F : Decls) +      importFunction(F, /*isDefinition*/ false); +      return true;    } @@ -1387,6 +1471,58 @@ bool LowerTypeTestsModule::lower() {    llvm::DenseMap<Metadata *, TIInfo> TypeIdInfo;    unsigned I = 0;    SmallVector<MDNode *, 2> Types; + +  struct ExportedFunctionInfo { +    CfiFunctionLinkage Linkage; +    MDNode *FuncMD; // {name, linkage, type[, type...]} +  }; +  DenseMap<StringRef, ExportedFunctionInfo> ExportedFunctions; +  if (ExportSummary) { +    NamedMDNode *CfiFunctionsMD = M.getNamedMetadata("cfi.functions"); +    if (CfiFunctionsMD) { +      for (auto FuncMD : CfiFunctionsMD->operands()) { +        assert(FuncMD->getNumOperands() >= 2); +        StringRef FunctionName = +            cast<MDString>(FuncMD->getOperand(0))->getString(); +        if (!ExportSummary->isGUIDLive(GlobalValue::getGUID( +                GlobalValue::dropLLVMManglingEscape(FunctionName)))) +          continue; +        CfiFunctionLinkage Linkage = static_cast<CfiFunctionLinkage>( +            cast<ConstantAsMetadata>(FuncMD->getOperand(1)) +                ->getValue() +                ->getUniqueInteger() +                .getZExtValue()); +        auto P = ExportedFunctions.insert({FunctionName, {Linkage, FuncMD}}); +        if (!P.second && P.first->second.Linkage != CFL_Definition) +          P.first->second = {Linkage, FuncMD}; +      } + +      for (const auto &P : ExportedFunctions) { +        StringRef FunctionName = P.first; +        CfiFunctionLinkage Linkage = P.second.Linkage; +        MDNode *FuncMD = P.second.FuncMD; +        Function *F = M.getFunction(FunctionName); +        if (!F) +          F = Function::Create( +              FunctionType::get(Type::getVoidTy(M.getContext()), false), +              GlobalVariable::ExternalLinkage, FunctionName, &M); + +        if (Linkage == CFL_Definition) +          F->eraseMetadata(LLVMContext::MD_type); + +        if (F->isDeclaration()) { +          if (Linkage == CFL_WeakDeclaration) +            F->setLinkage(GlobalValue::ExternalWeakLinkage); + +          SmallVector<MDNode *, 2> Types; +          for (unsigned I = 2; I < FuncMD->getNumOperands(); ++I) +            F->addMetadata(LLVMContext::MD_type, +                           *cast<MDNode>(FuncMD->getOperand(I).get())); +        } +      } +    } +  } +    for (GlobalObject &GO : M.global_objects()) {      if (isa<GlobalVariable>(GO) && GO.isDeclarationForLinker())        continue; @@ -1396,7 +1532,15 @@ bool LowerTypeTestsModule::lower() {      if (Types.empty())        continue; -    auto *GTM = GlobalTypeMember::create(Alloc, &GO, Types); +    bool IsDefinition = !GO.isDeclarationForLinker(); +    bool IsExported = false; +    if (isa<Function>(GO) && ExportedFunctions.count(GO.getName())) { +      IsDefinition |= ExportedFunctions[GO.getName()].Linkage == CFL_Definition; +      IsExported = true; +    } + +    auto *GTM = +        GlobalTypeMember::create(Alloc, &GO, IsDefinition, IsExported, Types);      for (MDNode *Type : Types) {        verifyTypeMDNode(&GO, Type);        auto &Info = TypeIdInfo[cast<MDNode>(Type)->getOperand(1)]; diff --git a/llvm/lib/Transforms/IPO/ThinLTOBitcodeWriter.cpp b/llvm/lib/Transforms/IPO/ThinLTOBitcodeWriter.cpp index a7bcc7cc553..802f470ffe1 100644 --- a/llvm/lib/Transforms/IPO/ThinLTOBitcodeWriter.cpp +++ b/llvm/lib/Transforms/IPO/ThinLTOBitcodeWriter.cpp @@ -32,7 +32,8 @@ namespace {  // Promote each local-linkage entity defined by ExportM and used by ImportM by  // changing visibility and appending the given ModuleId. -void promoteInternals(Module &ExportM, Module &ImportM, StringRef ModuleId) { +void promoteInternals(Module &ExportM, Module &ImportM, StringRef ModuleId, +                      SetVector<GlobalValue *> &PromoteExtra) {    DenseMap<const Comdat *, Comdat *> RenamedComdats;    for (auto &ExportGV : ExportM.global_values()) {      if (!ExportGV.hasLocalLinkage()) @@ -40,7 +41,7 @@ void promoteInternals(Module &ExportM, Module &ImportM, StringRef ModuleId) {      auto Name = ExportGV.getName();      GlobalValue *ImportGV = ImportM.getNamedValue(Name); -    if (!ImportGV || ImportGV->use_empty()) +    if ((!ImportGV || ImportGV->use_empty()) && !PromoteExtra.count(&ExportGV))        continue;      std::string NewName = (Name + ModuleId).str(); @@ -53,8 +54,10 @@ void promoteInternals(Module &ExportM, Module &ImportM, StringRef ModuleId) {      ExportGV.setLinkage(GlobalValue::ExternalLinkage);      ExportGV.setVisibility(GlobalValue::HiddenVisibility); -    ImportGV->setName(NewName); -    ImportGV->setVisibility(GlobalValue::HiddenVisibility); +    if (ImportGV) { +      ImportGV->setName(NewName); +      ImportGV->setVisibility(GlobalValue::HiddenVisibility); +    }    }    if (!RenamedComdats.empty()) @@ -296,6 +299,11 @@ void splitAndWriteThinLTOBitcode(        F.setComdat(nullptr);      } +  SetVector<GlobalValue *> CfiFunctions; +  for (auto &F : M) +    if ((!F.hasLocalLinkage() || F.hasAddressTaken()) && HasTypeMetadata(&F)) +      CfiFunctions.insert(&F); +    // Remove all globals with type metadata, globals with comdats that live in    // MergedM, and aliases pointing to such globals from the thin LTO module.    filterModule(&M, [&](const GlobalValue *GV) { @@ -308,11 +316,39 @@ void splitAndWriteThinLTOBitcode(      return true;    }); -  promoteInternals(*MergedM, M, ModuleId); -  promoteInternals(M, *MergedM, ModuleId); +  promoteInternals(*MergedM, M, ModuleId, CfiFunctions); +  promoteInternals(M, *MergedM, ModuleId, CfiFunctions); + +  SmallVector<MDNode *, 8> CfiFunctionMDs; +  for (auto V : CfiFunctions) { +    Function &F = *cast<Function>(V); +    SmallVector<MDNode *, 2> Types; +    F.getMetadata(LLVMContext::MD_type, Types); + +    auto &Ctx = MergedM->getContext(); +    SmallVector<Metadata *, 4> Elts; +    Elts.push_back(MDString::get(Ctx, F.getName())); +    CfiFunctionLinkage Linkage; +    if (!F.isDeclarationForLinker()) +      Linkage = CFL_Definition; +    else if (F.isWeakForLinker()) +      Linkage = CFL_WeakDeclaration; +    else +      Linkage = CFL_Declaration; +    Elts.push_back(ConstantAsMetadata::get( +        llvm::ConstantInt::get(Type::getInt8Ty(Ctx), Linkage))); +    for (auto Type : Types) +      Elts.push_back(Type); +    CfiFunctionMDs.push_back(MDTuple::get(Ctx, Elts)); +  } -  simplifyExternals(*MergedM); +  if(!CfiFunctionMDs.empty()) { +    NamedMDNode *NMD = MergedM->getOrInsertNamedMetadata("cfi.functions"); +    for (auto MD : CfiFunctionMDs) +      NMD->addOperand(MD); +  } +  simplifyExternals(*MergedM);    // FIXME: Try to re-use BSI and PFI from the original module here.    ProfileSummaryInfo PSI(M);  | 

