Index: include/llvm/Bitcode/BitcodeWriter.h =================================================================== --- include/llvm/Bitcode/BitcodeWriter.h +++ include/llvm/Bitcode/BitcodeWriter.h @@ -67,6 +67,10 @@ void writeModule(const Module *M, bool ShouldPreserveUseListOrder = false, const ModuleSummaryIndex *Index = nullptr, bool GenerateHash = false, ModuleHash *ModHash = nullptr); + + void writeIndex( + const ModuleSummaryIndex *Index, + const std::map *ModuleToSummariesForIndex); }; /// \brief Write the specified module to the specified raw output stream. Index: include/llvm/Bitcode/LLVMBitCodes.h =================================================================== --- include/llvm/Bitcode/LLVMBitCodes.h +++ include/llvm/Bitcode/LLVMBitCodes.h @@ -240,6 +240,11 @@ // summaries, but it can also appear in per-module summaries for PGO data. // [valueid, guid] FS_VALUE_GUID = 16, + // The list of functions with CFI jump tables. Names are pairs of (strtab + // offset, length). The first numdefs names are for definitions (i.e. local + // functions), the rest are external functions. + // [numdefs, numdefs x name, n x name] + FS_CFI_FUNCTIONS = 17, }; enum MetadataCodes { Index: include/llvm/IR/ModuleSummaryIndex.h =================================================================== --- include/llvm/IR/ModuleSummaryIndex.h +++ include/llvm/IR/ModuleSummaryIndex.h @@ -35,6 +35,7 @@ #include #include #include +#include namespace llvm { @@ -542,6 +543,9 @@ /// considered live. bool WithGlobalValueDeadStripping = false; + std::set CfiFunctionDefs; + std::set CfiFunctionDecls; + // YAML I/O support. friend yaml::MappingTraits; @@ -592,6 +596,12 @@ return I == OidGuidMap.end() ? 0 : I->second; } + std::set &cfiFunctionDefs() { return CfiFunctionDefs; } + const std::set &cfiFunctionDefs() const { return CfiFunctionDefs; } + + std::set &cfiFunctionDecls() { return CfiFunctionDecls; } + const std::set &cfiFunctionDecls() const { return CfiFunctionDecls; } + /// Add a global value summary for a value of the given name. void addGlobalValueSummary(StringRef ValueName, std::unique_ptr Summary) { Index: include/llvm/IR/ModuleSummaryIndexYAML.h =================================================================== --- include/llvm/IR/ModuleSummaryIndexYAML.h +++ include/llvm/IR/ModuleSummaryIndexYAML.h @@ -188,10 +188,35 @@ LLVM_YAML_IS_STRING_MAP(TypeIdSummary) LLVM_YAML_IS_SEQUENCE_VECTOR(FunctionSummaryYaml) +LLVM_YAML_IS_SEQUENCE_VECTOR(std::string) namespace llvm { namespace yaml { +struct StringSetYaml { + std::vector V; + StringSetYaml() {} + StringSetYaml(const std::set& S) { + for (auto &Str : S) + V.push_back(Str); + } + void ToSet(std::set& S) { + for (auto &Str : V) + S.insert(Str); + } +}; + +template<> struct SequenceTraits { + static size_t size(IO &io, StringSetYaml &seq) { + return seq.V.size(); + } + static std::string &element(IO &io, StringSetYaml &seq, size_t index) { + if (index >= seq.V.size()) + seq.V.resize(index + 1); + return seq.V[index]; + } +}; + // FIXME: Add YAML mappings for the rest of the module summary. template <> struct CustomMappingTraits { static void inputOne(IO &io, StringRef Key, GlobalValueSummaryMapTy &V) { @@ -240,6 +265,22 @@ io.mapOptional("TypeIdMap", index.TypeIdMap); io.mapOptional("WithGlobalValueDeadStripping", index.WithGlobalValueDeadStripping); + + if (io.outputting()) { + StringSetYaml CfiFunctionDefs(index.CfiFunctionDefs); + io.mapOptional("CfiFunctionDefs", CfiFunctionDefs); + + StringSetYaml CfiFunctionDecls(index.CfiFunctionDecls); + io.mapOptional("CfiFunctionDecls", CfiFunctionDecls); + } else { + StringSetYaml CfiFunctionDefs; + io.mapOptional("CfiFunctionDefs", CfiFunctionDefs); + CfiFunctionDefs.ToSet(index.CfiFunctionDefs); + + StringSetYaml CfiFunctionDecls; + io.mapOptional("CfiFunctionDecls", CfiFunctionDecls); + CfiFunctionDecls.ToSet(index.CfiFunctionDecls); + } } }; Index: include/llvm/Support/YAMLTraits.h =================================================================== --- include/llvm/Support/YAMLTraits.h +++ include/llvm/Support/YAMLTraits.h @@ -658,7 +658,8 @@ typename std::enable_if::value, void>::type mapOptionalWithContext(const char *Key, T &Val, Context &Ctx) { // omit key/value instead of outputting empty sequence - if (this->canElideEmptySequence() && !(Val.begin() != Val.end())) + if (this->canElideEmptySequence() && + SequenceTraits::size(*this, Val) == 0) return; this->processKey(Key, Val, false, Ctx); } Index: lib/Bitcode/Reader/BitcodeReader.cpp =================================================================== --- lib/Bitcode/Reader/BitcodeReader.cpp +++ lib/Bitcode/Reader/BitcodeReader.cpp @@ -5251,6 +5251,19 @@ {{Record[0], Record[1]}, {Record.begin() + 2, Record.end()}}); break; } + case bitc::FS_CFI_FUNCTIONS: { + std::set &CfiFunctionDefs = TheIndex.cfiFunctionDefs(); + std::set &CfiFunctionDecls = TheIndex.cfiFunctionDecls(); + unsigned NumDefs = Record[0]; + for (unsigned I = 1, N = 0; I != Record.size(); I += 2, N++) { + StringRef Name{Strtab.data() + Record[I], Record[I+1]}; + if (N < NumDefs) + CfiFunctionDefs.insert(Name); + else + CfiFunctionDecls.insert(Name); + } + break; + } } } llvm_unreachable("Exit infinite loop"); Index: lib/Bitcode/Writer/BitcodeWriter.cpp =================================================================== --- lib/Bitcode/Writer/BitcodeWriter.cpp +++ lib/Bitcode/Writer/BitcodeWriter.cpp @@ -77,10 +77,13 @@ /// 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 @@ /// Pointer to the buffer allocated by caller for bitcode writing. const SmallVectorImpl &Buffer; - StringTableBuilder &StrtabBuilder; - /// The Module to write to bitcode. const Module &M; @@ -142,8 +143,8 @@ 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 @@ /// 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 *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,22 @@ MaybeEmitOriginalName(*AS); } + const std::set &CfiFunctionDefs = Index.cfiFunctionDefs(); + const std::set &CfiFunctionDecls = Index.cfiFunctionDecls(); + if (!CfiFunctionDefs.empty() || !CfiFunctionDecls.empty()) { + NameVals.push_back(CfiFunctionDefs.size()); + for (auto &S : CfiFunctionDefs) { + NameVals.push_back(StrtabBuilder.add(S)); + NameVals.push_back(S.size()); + } + for (auto &S : CfiFunctionDecls) { + NameVals.push_back(StrtabBuilder.add(S)); + NameVals.push_back(S.size()); + } + Stream.EmitRecord(bitc::FS_CFI_FUNCTIONS, NameVals); + NameVals.clear(); + } + Stream.ExitBlock(); } @@ -3829,6 +3847,13 @@ ModuleWriter.write(); } +void BitcodeWriter::writeIndex( + const ModuleSummaryIndex *Index, + const std::map *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 +3905,9 @@ SmallVector 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()); } Index: lib/Transforms/IPO/CrossDSOCFI.cpp =================================================================== --- lib/Transforms/IPO/CrossDSOCFI.cpp +++ lib/Transforms/IPO/CrossDSOCFI.cpp @@ -95,6 +95,17 @@ } } + 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(Func->getOperand(I).get()))) + TypeIds.insert(TypeId->getZExtValue()); + } + } + LLVMContext &Ctx = M.getContext(); Constant *C = M.getOrInsertFunction( "__cfi_check", Type::getVoidTy(Ctx), Type::getInt64Ty(Ctx), Index: lib/Transforms/IPO/LowerTypeTests.cpp =================================================================== --- lib/Transforms/IPO/LowerTypeTests.cpp +++ lib/Transforms/IPO/LowerTypeTests.cpp @@ -206,17 +206,26 @@ class GlobalTypeMember final : TrailingObjects { 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) const { return NTypes; } public: static GlobalTypeMember *create(BumpPtrAllocator &Alloc, GlobalObject *GO, + bool IsDefinition, bool IsExported, ArrayRef Types) { auto *GTM = static_cast(Alloc.Allocate( totalSizeToAlloc(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()); return GTM; @@ -224,6 +233,12 @@ GlobalObject *getGlobal() const { return GO; } + bool isDefinition() const { + return IsDefinition; + } + bool isExported() const { + return IsExported; + } ArrayRef types() const { return makeArrayRef(getTrailingObjects(), NTypes); } @@ -294,6 +309,7 @@ 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 +836,41 @@ 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 TypeIds, Constant *CombinedGlobalAddr, const DenseMap &GlobalLayout) { @@ -1143,7 +1194,6 @@ // 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 +1217,7 @@ // references to the original functions with references to the aliases. for (unsigned I = 0; I != Functions.size(); ++I) { Function *F = cast(Functions[I]->getGlobal()); + bool IsDefinition = Functions[I]->isDefinition(); Constant *CombinedGlobalElemPtr = ConstantExpr::getBitCast( ConstantExpr::getInBoundsGetElementPtr( @@ -1174,7 +1225,18 @@ ArrayRef{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 +1244,8 @@ } 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()) @@ -1350,18 +1411,47 @@ return Changed; } +static bool IsFunctionLive(StringRef Name, const ModuleSummaryIndex *Summary) { + auto GUID = GlobalValue::getGUID(GlobalValue::dropLLVMManglingEscape(Name)); + ValueInfo Info = Summary->getValueInfo(GUID); + if (!Info) + return true; + const auto &SummaryList = Info.getSummaryList(); + if (SummaryList.empty()) + return true; + return Summary->isGlobalValueLive(SummaryList[0].get()); +} + 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((*UI++).getUser()); - importTypeTest(CI); + if (TypeTestFunc) { + for (auto UI = TypeTestFunc->use_begin(), UE = TypeTestFunc->use_end(); + UI != UE;) { + auto *CI = cast((*UI++).getUser()); + importTypeTest(CI); + } } + + SmallVector Defs; + SmallVector Decls; + for (auto &F : M) { + 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 +1477,54 @@ llvm::DenseMap TypeIdInfo; unsigned I = 0; SmallVector Types; + + DenseMap> ExportedFunctions; + if (ExportSummary) { + NamedMDNode *CfiFunctionsMD = M.getNamedMetadata("cfi.functions"); + if (CfiFunctionsMD) { + for (auto FuncMD : CfiFunctionsMD->operands()) { + assert(FuncMD->getNumOperands() >= 2); + StringRef FunctionName = + cast(FuncMD->getOperand(0))->getString(); + if (!IsFunctionLive(FunctionName, ExportSummary)) { + continue; + } + unsigned Linkage = cast(FuncMD->getOperand(1)) + ->getValue() + ->getUniqueInteger() + .getZExtValue(); + bool isDefinition = Linkage == 0; + auto &V = ExportedFunctions[FunctionName]; + if (isDefinition >= V.first) + V = {isDefinition, FuncMD}; + } + + for (auto &P : ExportedFunctions) { + StringRef FunctionName = P.first; + // bool isDefinition = P.second.first; + MDNode *FuncMD = P.second.second; + unsigned Linkage = cast(FuncMD->getOperand(1)) + ->getValue() + ->getUniqueInteger() + .getZExtValue(); + + Function *F = M.getFunction(FunctionName); + if (!F) + F = Function::Create( + FunctionType::get(Type::getVoidTy(M.getContext()), false), + GlobalVariable::ExternalLinkage, FunctionName, &M); + + if (Linkage == 2) // weak + F->setLinkage(GlobalValue::ExternalWeakLinkage); + + SmallVector Types; + for (unsigned I = 2; I < FuncMD->getNumOperands(); ++I) + F->addMetadata(LLVMContext::MD_type, + *cast(FuncMD->getOperand(I).get())); + } + } + } + for (GlobalObject &GO : M.global_objects()) { if (isa(GO) && GO.isDeclarationForLinker()) continue; @@ -1396,7 +1534,16 @@ if (Types.empty()) continue; - auto *GTM = GlobalTypeMember::create(Alloc, &GO, Types); + bool IsDefinition = !GO.isDeclarationForLinker(); + bool IsExported = false; + if (isa(GO) && ExportedFunctions.count(GO.getName())) { + bool IsExportedDefinition = ExportedFunctions[GO.getName()].first; + IsDefinition |= IsExportedDefinition; + IsExported = true; + } + + auto *GTM = + GlobalTypeMember::create(Alloc, &GO, IsDefinition, IsExported, Types); for (MDNode *Type : Types) { verifyTypeMDNode(&GO, Type); auto &Info = TypeIdInfo[cast(Type)->getOperand(1)]; Index: lib/Transforms/IPO/ThinLTOBitcodeWriter.cpp =================================================================== --- lib/Transforms/IPO/ThinLTOBitcodeWriter.cpp +++ lib/Transforms/IPO/ThinLTOBitcodeWriter.cpp @@ -33,6 +33,12 @@ // 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) { + NamedMDNode *CfiFunctionsMD = ImportM.getNamedMetadata("cfi.functions"); + DenseMap CfiFunctions; + if (CfiFunctionsMD) + for (auto MD : CfiFunctionsMD->operands()) + CfiFunctions[cast(MD->getOperand(0))->getString()] = MD; + DenseMap RenamedComdats; for (auto &ExportGV : ExportM.global_values()) { if (!ExportGV.hasLocalLinkage()) @@ -40,7 +46,8 @@ auto Name = ExportGV.getName(); GlobalValue *ImportGV = ImportM.getNamedValue(Name); - if (!ImportGV || ImportGV->use_empty()) + bool HasMetadataRef = CfiFunctions.count(Name); + if ((!ImportGV || ImportGV->use_empty()) && !HasMetadataRef) continue; std::string NewName = (Name + ModuleId).str(); @@ -53,8 +60,19 @@ 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 (HasMetadataRef) { + MDNode *&ImportMD = CfiFunctions[Name]; + SmallVector Ops; + Ops.push_back(MDString::get(ImportM.getContext(), NewName)); + for (unsigned I = 1; I < ImportMD->getNumOperands(); ++I) + Ops.push_back(ImportMD->getOperand(I)); + ImportMD = MDTuple::get(ImportM.getContext(), Ops); + // Don't bother updating CfiFunctions key. + } } if (!RenamedComdats.empty()) @@ -64,6 +82,12 @@ if (Replacement != RenamedComdats.end()) GO.setComdat(Replacement->second); } + + if(CfiFunctionsMD) { + CfiFunctionsMD->clearOperands(); + for (auto I : CfiFunctions) + CfiFunctionsMD->addOperand(I.second); + } } // Promote all internal (i.e. distinct) type ids used by the module by replacing @@ -296,6 +320,37 @@ F.setComdat(nullptr); } + + SmallVector CfiFunctions; + for (auto &F : M) { + if (!F.hasLocalLinkage() || F.hasAddressTaken()) { + SmallVector Types; + F.getMetadata(LLVMContext::MD_type, Types); + if (Types.empty()) + continue; + + auto &Ctx = MergedM->getContext(); + SmallVector Elts; + Elts.push_back(MDString::get(Ctx, F.getName())); + unsigned Linkage = + F.isDeclarationForLinker() ? (F.isWeakForLinker() ? 2 : 1) : 0; + Elts.push_back(ConstantAsMetadata::get( + llvm::ConstantInt::get(Type::getInt8Ty(Ctx), Linkage))); + for (auto Type : Types) + Elts.push_back(Type); + + MDNode *MDF = MDTuple::get(Ctx, Elts); + CfiFunctions.push_back(MDF); + } + } + + if(!CfiFunctions.empty()) { + NamedMDNode *NMD = MergedM->getOrInsertNamedMetadata("cfi.functions"); + for (auto MD : CfiFunctions) + NMD->addOperand(MD); + } + + // 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) { Index: test/ThinLTO/X86/cfi-icall.ll =================================================================== --- /dev/null +++ test/ThinLTO/X86/cfi-icall.ll @@ -0,0 +1,25 @@ +; RUN: opt -thinlto-bc %s -o %t1.bc +; RUN: llvm-lto2 run -thinlto-distributed-indexes %t1.bc -o %t.out -save-temps \ +; RUN: -r %t1.bc,foo,plx +; RUN: llvm-bcanalyzer -dump %t.out.index.bc | FileCheck %s --check-prefix=COMBINED + +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +define void @foo() !type !0 { +entry: + ret void +} + +!llvm.module.flags = !{!1} + +!0 = !{i64 0, i64 1234} +!1 = !{i32 4, !"Cross-DSO CFI", i32 1} + +; COMBINED: +; COMBINED: + +; COMBINED: blob data = 'foo' +; COMBINED-NEXT: Index: test/Transforms/LowerTypeTests/Inputs/import-icall.yaml =================================================================== --- /dev/null +++ test/Transforms/LowerTypeTests/Inputs/import-icall.yaml @@ -0,0 +1,19 @@ +--- +TypeIdMap: + typeid1: + TTRes: + Kind: AllOnes + SizeM1BitWidth: 7 + typeid2: + TTRes: + Kind: Single + SizeM1BitWidth: 0 +WithGlobalValueDeadStripping: false +CfiFunctionDefs: + - local_a + - local_b + - does_not_exist +CfiFunctionDecls: + - external + - external_weak +... Index: test/Transforms/LowerTypeTests/export-icall.ll =================================================================== --- /dev/null +++ test/Transforms/LowerTypeTests/export-icall.ll @@ -0,0 +1,62 @@ +; RUN: opt -S -lowertypetests -lowertypetests-summary-action=export -lowertypetests-read-summary=%S/Inputs/use-typeid1-typeid2.yaml -lowertypetests-write-summary=%t < %s | FileCheck %s +; RUN: FileCheck --check-prefix=SUMMARY %s < %t + +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +define void @h(i8 %x) !type !2 { + ret void +} + +!cfi.functions = !{!0, !1, !3, !4, !5, !6} + +!0 = !{!"h", i8 0, !2} +!1 = !{!"h", i8 1, !2} +!2 = !{i64 0, !"typeid1"} +!3 = !{!"f", i8 0, !2} +!4 = !{!"external", i8 1, !2} +!5 = !{!"external_weak", i8 2, !2} +!6 = !{!"g", i8 0, !7} +!7 = !{i64 0, !"typeid2"} + + +; CHECK: @__typeid_typeid1_global_addr = hidden alias i8, bitcast (void ()* [[JT1:.*]] to i8*) +; CHECK: @__typeid_typeid1_align = hidden alias i8, inttoptr (i8 3 to i8*) +; CHECK: @__typeid_typeid1_size_m1 = hidden alias i8, inttoptr (i64 3 to i8*) + +; CHECK: @h = alias void (i8), bitcast (void ()* [[JT1]] to void (i8)*) +; CHECK: @external.cfi_jt = hidden alias void (), {{.*}}getelementptr {{.*}}void ()* [[JT1]] +; CHECK: @f = alias void (), {{.*}}getelementptr {{.*}}void ()* [[JT1]] +; CHECK: @external_weak.cfi_jt = hidden alias void (), {{.*}}getelementptr {{.*}}void ()* [[JT1]] + +; CHECK: @__typeid_typeid2_global_addr = hidden alias i8, bitcast (void ()* [[JT2:.*]] to i8*) + +; CHECK: @g = alias void (), void ()* [[JT2]] + +; CHECK: define internal void @h.cfi(i8 {{.*}}) !type !{{.*}} +; CHECK: declare !type !{{.*}} void @external() +; CHECK: declare !type !{{.*}} void @f.cfi() +; CHECK: declare !type !{{.*}} void @external_weak() +; CHECK: declare !type !{{.*}} void @g.cfi() + + +; SUMMARY: TypeIdMap: +; SUMMARY-NEXT: typeid1: +; SUMMARY-NEXT: TTRes: +; SUMMARY-NEXT: Kind: AllOnes +; SUMMARY-NEXT: SizeM1BitWidth: 7 +; SUMMARY-NEXT: WPDRes: +; SUMMARY-NEXT: typeid2: +; SUMMARY-NEXT: TTRes: +; SUMMARY-NEXT: Kind: Single +; SUMMARY-NEXT: SizeM1BitWidth: 0 +; SUMMARY-NEXT: WPDRes: + +; SUMMARY: CfiFunctionDefs: +; SUMMARY-NEXT: - f +; SUMMARY-NEXT: - g +; SUMMARY-NEXT: - h +; SUMMARY-NEXT: CfiFunctionDecls: +; SUMMARY-NEXT: - external +; SUMMARY-NEXT: - external_weak +; SUMMARY-NEXT: ... Index: test/Transforms/LowerTypeTests/import-icall.ll =================================================================== --- /dev/null +++ test/Transforms/LowerTypeTests/import-icall.ll @@ -0,0 +1,35 @@ +; RUN: opt -S -lowertypetests -lowertypetests-summary-action=import -lowertypetests-read-summary=%S/Inputs/import-icall.yaml < %s | FileCheck %s + +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +define i8 @local_a() { + call void @external() + call void @external_weak() + ret i8 1 +} + +define i8 @local_b() { + %x = call i8 @local_a() + ret i8 %x +} + + +declare void @external() +declare extern_weak void @external_weak() + +; CHECK: define hidden i8 @local_a.cfi() { +; CHECK-NEXT: call void @external.cfi_jt() +; CHECK-NEXT: call void select (i1 icmp ne (void ()* @external_weak, void ()* null), void ()* @external_weak.cfi_jt, void ()* null)() +; CHECK-NEXT: ret i8 1 +; CHECK-NEXT: } + +; CHECK: define hidden i8 @local_b.cfi() { +; CHECK-NEXT: call i8 @local_a() + +; CHECK: declare void @external() +; CHECK: declare extern_weak void @external_weak() +; CHECK: declare i8 @local_a() +; CHECK: declare i8 @local_b() +; CHECK: declare hidden void @external.cfi_jt() +; CHECK: declare hidden void @external_weak.cfi_jt() Index: tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp =================================================================== --- tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp +++ tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp @@ -320,6 +320,7 @@ STRINGIFY_CODE(FS, TYPE_TEST_ASSUME_CONST_VCALL) STRINGIFY_CODE(FS, TYPE_CHECKED_LOAD_CONST_VCALL) STRINGIFY_CODE(FS, VALUE_GUID) + STRINGIFY_CODE(FS, CFI_FUNCTIONS) } case bitc::METADATA_ATTACHMENT_ID: switch(CodeID) {