diff --git a/llvm/include/llvm/ObjectYAML/CovMap.h b/llvm/include/llvm/ObjectYAML/CovMap.h new file mode 100644 index 0000000000000..913cb6060f7a8 --- /dev/null +++ b/llvm/include/llvm/ObjectYAML/CovMap.h @@ -0,0 +1,212 @@ +//===- CovMap.h - ObjectYAML Interface for coverage map ---------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// - llvm::coverage::yaml +// +// Describes binary file formats and YAML structures of coverage map. +// +// - llvm::yaml +// +// Attachments for YAMLTraits. +// +// - llvm::covmap +// +// Provides YAML encoder for coverage map. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_OBJECTYAML_COVMAP_H +#define LLVM_OBJECTYAML_COVMAP_H + +#include "llvm/ADT/StringRef.h" +#include "llvm/ObjectYAML/ELFYAML.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/YAMLTraits.h" +#include +#include +#include +#include +#include +#include +#include + +namespace llvm { +class raw_ostream; +} // namespace llvm + +namespace llvm::coverage::yaml { + +/// Base Counter, corresponding to coverage::Counter. +struct CounterTy { + enum TagTy : uint8_t { + Zero = 0, + Ref, + Sub, + Add, + }; + + TagTy Tag; + uint64_t Val; + + virtual ~CounterTy() {} + + virtual void mapping(llvm::yaml::IO &IO); + + void encode(raw_ostream &OS) const; +}; + +/// Holds a pair of both hands but doesn't hold ops(add or sub). +/// Ops is stored in CounterTy::Tag. +using ExpressionTy = std::array; + +/// {True, False} +using BranchTy = std::array; + +/// {ID, TrueID, FalseID} +/// Note: This has +1 offset unlike mcdc::ConditionID. +using MCDCBranchTy = std::array; + +struct DecisionTy { + uint64_t BIdx; ///< Bitmap index + uint64_t NC; ///< NumConds + + void mapping(llvm::yaml::IO &IO); + + void encode(raw_ostream &OS) const; +}; + +/// {LineStart, ColumnStart, LineEnd, ColumnEnd} +using LocTy = std::array; + +/// Region record. +/// CounterTy is enhanced if Tag is Zero and Val is not zero. +struct RecTy : CounterTy { + enum ExtTagTy : uint8_t { + Skip = 2, + Branch = 4, + Decision = 5, + MCDCBranch = 6, + }; + + /// This is optional in detailed view. + std::optional ExtTag; + + // Options for extensions. + std::optional Expansion; ///< Doesn't have ExtTag. + std::optional BranchOpt; ///< Optionally has MCDC. + std::optional MCDC; + std::optional DecisionOpt; + + /// True or None. + /// Stored in ColumnEnd:31. + std::optional isGap; + + LocTy dLoc; ///< Differential line numbers. + + void mapping(llvm::yaml::IO &IO) override; + + void encode(raw_ostream &OS) const; +}; + +/// {NumRecs, Recs...} +struct FileRecsTy { + std::vector Recs; + + void mapping(llvm::yaml::IO &IO); +}; + +/// An element of CovFun array. +struct CovFunTy { + llvm::yaml::Hex64 NameRef; ///< Hash value of the symbol. + llvm::yaml::Hex64 FuncHash; ///< Signature of this function. + llvm::yaml::Hex64 FilenamesRef; ///< Pointer to CovMap + std::vector FileIDs; ///< Resolved by CovMap + std::vector Expressions; + std::vector Files; ///< 2-dimension array of Recs. + + void mapping(llvm::yaml::IO &IO); + + void encode(raw_ostream &OS, endianness Endianness) const; +}; + +/// An element of CovMap array. +struct CovMapTy { + /// This is the key of CovMap but not present in the file + /// format. Calculate and store with Filenames. + llvm::yaml::Hex64 FilenamesRef; + + uint32_t Version; + + /// Raw Filenames (and storage of Files) + std::vector Filenames; + + void mapping(llvm::yaml::IO &IO); + + /// Encode Filenames. This is mostly used just to obtain FilenamesRef. + std::pair encodeFilenames(bool Compress = false) const; + + void encode(raw_ostream &OS, endianness Endianness) const; +}; + +} // namespace llvm::coverage::yaml + +LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::coverage::yaml::CovMapTy) +LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::coverage::yaml::CovFunTy) +LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::coverage::yaml::ExpressionTy) +LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::coverage::yaml::RecTy) +LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::coverage::yaml::FileRecsTy) +LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(llvm::coverage::yaml::CounterTy) + +#define LLVM_COVERAGE_YAML_ELEM_MAPPING(Ty) \ + namespace llvm::yaml { \ + template <> struct MappingTraits { \ + static void mapping(IO &IO, llvm::coverage::yaml::Ty &Obj) { \ + Obj.mapping(IO); \ + } \ + }; \ + } + +/// `Flow` is used for emission of a compact oneliner for RecTy. +#define LLVM_COVERAGE_YAML_ELEM_MAPPING_FLOW(Ty) \ + namespace llvm::yaml { \ + template <> struct MappingTraits { \ + static void mapping(IO &IO, llvm::coverage::yaml::Ty &Obj) { \ + Obj.mapping(IO); \ + (void)flow; \ + } \ + static const bool flow = true; \ + }; \ + } + +#define LLVM_COVERAGE_YAML_ENUM(Ty) \ + namespace llvm::yaml { \ + template <> struct ScalarEnumerationTraits { \ + static void enumeration(IO &IO, llvm::coverage::yaml::Ty &Value); \ + }; \ + } + +LLVM_COVERAGE_YAML_ENUM(CounterTy::TagTy) +LLVM_COVERAGE_YAML_ENUM(RecTy::ExtTagTy) +LLVM_COVERAGE_YAML_ELEM_MAPPING_FLOW(CounterTy) +LLVM_COVERAGE_YAML_ELEM_MAPPING_FLOW(DecisionTy) +LLVM_COVERAGE_YAML_ELEM_MAPPING_FLOW(RecTy) +LLVM_COVERAGE_YAML_ELEM_MAPPING(FileRecsTy) +LLVM_COVERAGE_YAML_ELEM_MAPPING(CovFunTy) +LLVM_COVERAGE_YAML_ELEM_MAPPING(CovMapTy) + +namespace llvm::covmap { + +/// Returns whether Name is interested. +bool nameMatches(StringRef Name); + +/// Returns a new ELFYAML Object. +std::unique_ptr make_unique(StringRef Name); + +} // namespace llvm::covmap + +#endif // LLVM_OBJECTYAML_COVMAP_H diff --git a/llvm/include/llvm/ObjectYAML/ELFYAML.h b/llvm/include/llvm/ObjectYAML/ELFYAML.h index dfdfa055d65fa..e9bb7621b20d9 100644 --- a/llvm/include/llvm/ObjectYAML/ELFYAML.h +++ b/llvm/include/llvm/ObjectYAML/ELFYAML.h @@ -229,6 +229,7 @@ struct Chunk { DependentLibraries, CallGraphProfile, BBAddrMap, + CovMapBase, // Special chunks. SpecialChunksStart, @@ -398,6 +399,19 @@ struct RawContentSection : Section { std::optional> ContentBuf; }; +struct CovMapSectionBase : Section { + std::optional Info; + + CovMapSectionBase() : Section(ChunkKind::CovMapBase) {} + + virtual void mapping(yaml::IO &IO) = 0; + virtual Error encode(raw_ostream &OS, endianness Endianness) const = 0; + + static bool classof(const Chunk *S) { + return S->Kind == ChunkKind::CovMapBase; + } +}; + struct NoBitsSection : Section { NoBitsSection() : Section(ChunkKind::NoBits) {} diff --git a/llvm/lib/ObjectYAML/CMakeLists.txt b/llvm/lib/ObjectYAML/CMakeLists.txt index b36974d47d9f8..11054a1e91388 100644 --- a/llvm/lib/ObjectYAML/CMakeLists.txt +++ b/llvm/lib/ObjectYAML/CMakeLists.txt @@ -7,6 +7,7 @@ add_llvm_component_library(LLVMObjectYAML CodeViewYAMLTypes.cpp COFFEmitter.cpp COFFYAML.cpp + CovMap.cpp DWARFEmitter.cpp DWARFYAML.cpp DXContainerEmitter.cpp @@ -34,7 +35,9 @@ add_llvm_component_library(LLVMObjectYAML LINK_COMPONENTS BinaryFormat + Coverage Object + ProfileData Support TargetParser DebugInfoCodeView diff --git a/llvm/lib/ObjectYAML/CovMap.cpp b/llvm/lib/ObjectYAML/CovMap.cpp new file mode 100644 index 0000000000000..3ad809f61bb0a --- /dev/null +++ b/llvm/lib/ObjectYAML/CovMap.cpp @@ -0,0 +1,307 @@ +//===- CovMap.cpp - ObjectYAML Interface for coverage map -----------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Implementations of CovMap and encoder. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ObjectYAML/CovMap.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ObjectYAML/ELFYAML.h" +#include "llvm/ProfileData/Coverage/CoverageMappingWriter.h" +#include "llvm/ProfileData/InstrProf.h" +#include "llvm/Support/Alignment.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/LEB128.h" +#include "llvm/Support/YAMLTraits.h" +#include "llvm/Support/raw_ostream.h" +#include +#include +#include +#include +#include + +#define COVMAP_V3 + +using namespace llvm; +using namespace llvm::coverage::yaml; +using namespace llvm::covmap; + +void CounterTy::encode(raw_ostream &OS) const { + encodeULEB128(Tag | (Val << 2), OS); +} + +void DecisionTy::encode(raw_ostream &OS) const { + encodeULEB128(BIdx, OS); + encodeULEB128(NC, OS); +} + +void RecTy::encode(raw_ostream &OS) const { + if (Expansion) { + encodeULEB128(4 + (*Expansion << 3), OS); + } else if (ExtTag && *ExtTag == Skip) { + encodeULEB128(2 << 3, OS); + } else if (DecisionOpt) { + assert(!ExtTag || *ExtTag == Decision); + encodeULEB128(5 << 3, OS); + DecisionOpt->encode(OS); + } else if (MCDC) { + assert(!ExtTag || *ExtTag == MCDCBranch); + assert(BranchOpt); + encodeULEB128(6 << 3, OS); + (*BranchOpt)[0].encode(OS); + (*BranchOpt)[1].encode(OS); + encodeULEB128((*MCDC)[0], OS); + encodeULEB128((*MCDC)[1], OS); + encodeULEB128((*MCDC)[2], OS); + } else if (BranchOpt) { + assert(!ExtTag || *ExtTag == Branch); + encodeULEB128(4 << 3, OS); + (*BranchOpt)[0].encode(OS); + (*BranchOpt)[1].encode(OS); + } else { + // Non-tag CounterTy + CounterTy::encode(OS); + } + + assert((!isGap || *isGap) && "Don't set isGap=false"); + uint32_t Gap = (isGap ? (1u << 31) : 0u); + encodeULEB128(dLoc[0], OS); + encodeULEB128(dLoc[1], OS); + encodeULEB128(dLoc[2], OS); + encodeULEB128(dLoc[3] | Gap, OS); +} + +void CovFunTy::encode(raw_ostream &OS, endianness Endianness) const { + // Encode Body in advance since DataSize should be known. + std::string Body; + raw_string_ostream SS(Body); + + encodeULEB128(FileIDs.size(), SS); + for (auto I : FileIDs) + encodeULEB128(I, SS); + + encodeULEB128(Expressions.size(), SS); + for (const auto &[LHS, RHS] : Expressions) { + LHS.encode(SS); + RHS.encode(SS); + } + + for (const auto &File : Files) { + encodeULEB128(File.Recs.size(), SS); + for (const auto &Rec : File.Recs) + Rec.encode(SS); + } + + // Emit the Header + uint64_t NameRef = this->NameRef; + uint32_t DataSize = Body.size(); + uint64_t FuncHash = this->FuncHash; + char CoverageMapping = 0; // dummy + uint64_t FilenamesRef = this->FilenamesRef; + +#define COVMAP_FUNC_RECORD(Type, LLVMType, Name, Initializer) \ + if (sizeof(Name) > 1) { \ + Type t = support::endian::byte_swap(Name, Endianness); \ + OS << StringRef(reinterpret_cast(&t), sizeof(t)); \ + } +#include "llvm/ProfileData/InstrProfData.inc" + + // Emit the body. + OS << std::move(Body); +} + +std::pair +CovMapTy::encodeFilenames(bool Compress) const { + std::string FilenamesBlob; + llvm::raw_string_ostream OS(FilenamesBlob); + CoverageFilenamesSectionWriter(this->Filenames).write(OS, Compress); + + return {llvm::IndexedInstrProf::ComputeHash(FilenamesBlob), FilenamesBlob}; +} + +void CovMapTy::encode(raw_ostream &OS, endianness Endianness) const { + auto [FilenamesRef, FilenamesBlob] = encodeFilenames(); + + uint32_t NRecords = 0; + uint32_t FilenamesSize = FilenamesBlob.size(); + uint32_t CoverageSize = 0; + uint32_t Version = this->Version; + struct { +#define COVMAP_HEADER(Type, LLVMType, Name, Initializer) Type Name; +#include "llvm/ProfileData/InstrProfData.inc" + } CovMapHeader = { +#define COVMAP_HEADER(Type, LLVMType, Name, Initializer) \ + support::endian::byte_swap(Name, Endianness), +#include "llvm/ProfileData/InstrProfData.inc" + }; + StringRef HeaderBytes(reinterpret_cast(&CovMapHeader), + sizeof(CovMapHeader)); + OS << HeaderBytes; + + // llvm_covmap's alignment + FilenamesBlob.resize(llvm::alignTo(FilenamesBlob.size(), sizeof(uint32_t))); + OS << FilenamesBlob; +} + +void CounterTy::mapping(llvm::yaml::IO &IO) { + IO.mapRequired("Tag", Tag); + IO.mapRequired("Val", Val); +} + +void DecisionTy::mapping(llvm::yaml::IO &IO) { + IO.mapRequired("BIdx", BIdx); + IO.mapRequired("NCond", NC); +} + +void RecTy::mapping(llvm::yaml::IO &IO) { + IO.mapRequired("dLoc", dLoc); + IO.mapOptional("isGap", isGap); + CounterTy::mapping(IO); + IO.mapOptional("ExtTag", ExtTag); + IO.mapOptional("Expansion", Expansion); + IO.mapOptional("Branch", BranchOpt); + IO.mapOptional("MCDC", MCDC); + IO.mapOptional("Decision", DecisionOpt); +} + +void FileRecsTy::mapping(llvm::yaml::IO &IO) { + IO.mapRequired("Regions", Recs); +} + +void CovFunTy::mapping(llvm::yaml::IO &IO) { + IO.mapRequired("NameRef", NameRef); + IO.mapRequired("FuncHash", FuncHash); + IO.mapRequired("FilenamesRef", FilenamesRef); + IO.mapRequired("FileIDs", FileIDs); + IO.mapRequired("Expressions", Expressions); + IO.mapRequired("Files", Files); +} + +void CovMapTy::mapping(llvm::yaml::IO &IO) { + IO.mapRequired("FilenamesRef", FilenamesRef); + IO.mapRequired("Version", Version); + IO.mapRequired("Filenames", Filenames); +} + +#define ECase(N, X) IO.enumCase(Value, #X, N::X) + +void llvm::yaml::ScalarEnumerationTraits::enumeration( + llvm::yaml::IO &IO, CounterTy::TagTy &Value) { + ECase(CounterTy, Zero); + ECase(CounterTy, Ref); + ECase(CounterTy, Sub); + ECase(CounterTy, Add); +} + +void llvm::yaml::ScalarEnumerationTraits::enumeration( + llvm::yaml::IO &IO, RecTy::ExtTagTy &Value) { + ECase(RecTy, Skip); + ECase(RecTy, Branch); + ECase(RecTy, Decision); + ECase(RecTy, MCDCBranch); +} + +namespace { + +struct PrfNamesSection : ELFYAML::CovMapSectionBase { + using PrfNamesTy = SmallVector; + SmallVector PrfNames; + + PrfNamesSection() { Name = "__llvm_prf_names"; } + static bool nameMatches(StringRef Name) { return Name == "__llvm_prf_names"; } + static bool classof(const Chunk *S) { + return (isa(S) && nameMatches(S->Name)); + } + + void mapping(llvm::yaml::IO &IO) override { + IO.mapOptional("PrfNames", PrfNames); + } + + Error encode(raw_ostream &OS, endianness Endianness) const override { + for (const auto &Names : PrfNames) { + std::string Result; + if (auto E = + collectGlobalObjectNameStrings(Names, + /*doCompression=*/false, Result)) + return E; + OS << Result; + } + return Error::success(); + } +}; + +struct CovMapSection : ELFYAML::CovMapSectionBase { + std::vector CovMaps; + + CovMapSection() { Name = "__llvm_covmap"; } + static bool nameMatches(StringRef Name) { return Name == "__llvm_covmap"; } + static bool classof(const Chunk *S) { + return (isa(S) && nameMatches(S->Name)); + } + + void mapping(llvm::yaml::IO &IO) override { + IO.mapOptional("CovMap", CovMaps); + } + + Error encode(raw_ostream &OS, endianness Endianness) const override { + auto BaseOffset = OS.tell(); + for (const auto &CovMap : CovMaps) { + OS.write_zeros(llvm::offsetToAlignment(OS.tell() - BaseOffset, + llvm::Align(AddressAlign.value))); + CovMap.encode(OS, Endianness); + } + return Error::success(); + } +}; + +struct CovFunSection : ELFYAML::CovMapSectionBase { + std::vector CovFuns; + + CovFunSection() { Name = "__llvm_covfun"; } + static bool nameMatches(StringRef Name) { + return Name.starts_with("__llvm_covfun"); + } + static bool classof(const Chunk *S) { + return (isa(S) && nameMatches(S->Name)); + } + + void mapping(llvm::yaml::IO &IO) override { + IO.mapOptional("CovFun", CovFuns); + } + + Error encode(raw_ostream &OS, endianness Endianness) const override { + auto BaseOffset = OS.tell(); + for (auto [I, CovFun] : enumerate(CovFuns)) { + OS.write_zeros(llvm::offsetToAlignment(OS.tell() - BaseOffset, + llvm::Align(AddressAlign.value))); + CovFun.encode(OS, Endianness); + } + return Error::success(); + } +}; +} // namespace + +bool covmap::nameMatches(StringRef Name) { + return (PrfNamesSection::nameMatches(Name) || + CovMapSection::nameMatches(Name) || CovFunSection::nameMatches(Name)); +} + +std::unique_ptr +covmap::make_unique(StringRef Name) { + if (PrfNamesSection::nameMatches(Name)) + return std::make_unique(); + else if (CovMapSection::nameMatches(Name)) + return std::make_unique(); + else if (CovFunSection::nameMatches(Name)) + return std::make_unique(); + + return nullptr; +} + +LLVM_YAML_IS_SEQUENCE_VECTOR(PrfNamesSection::PrfNamesTy) diff --git a/llvm/lib/ObjectYAML/ELFEmitter.cpp b/llvm/lib/ObjectYAML/ELFEmitter.cpp index 9ae76a71ede5e..e55daa72b3cee 100644 --- a/llvm/lib/ObjectYAML/ELFEmitter.cpp +++ b/llvm/lib/ObjectYAML/ELFEmitter.cpp @@ -18,6 +18,7 @@ #include "llvm/BinaryFormat/ELF.h" #include "llvm/MC/StringTableBuilder.h" #include "llvm/Object/ELFTypes.h" +#include "llvm/ObjectYAML/CovMap.h" #include "llvm/ObjectYAML/DWARFEmitter.h" #include "llvm/ObjectYAML/DWARFYAML.h" #include "llvm/ObjectYAML/ELFYAML.h" @@ -66,6 +67,13 @@ class ContiguousBlobAccumulator { uint64_t getOffset() const { return InitialOffset + OS.tell(); } void writeBlobToStream(raw_ostream &Out) const { Out << OS.str(); } + uint64_t checkAndTell(uint64_t Base) { + uint64_t Offset = OS.tell() - Base; + if (checkLimit(Offset)) + return Offset; + return 0; + } + Error takeLimitError() { // Request to write 0 bytes to check we did not reach the limit. checkLimit(0); @@ -308,6 +316,9 @@ template class ELFState { void writeSectionContent(Elf_Shdr &SHeader, const ELFYAML::CallGraphProfileSection &Section, ContiguousBlobAccumulator &CBA); + void writeSectionContent(Elf_Shdr &SHeader, + const ELFYAML::CovMapSectionBase &Section, + ContiguousBlobAccumulator &CBA); void writeFill(ELFYAML::Fill &Fill, ContiguousBlobAccumulator &CBA); @@ -894,6 +905,8 @@ void ELFState::initSectionHeaders(std::vector &SHeaders, writeSectionContent(SHeader, *S, CBA); } else if (auto S = dyn_cast(Sec)) { writeSectionContent(SHeader, *S, CBA); + } else if (auto S = dyn_cast(Sec)) { + writeSectionContent(SHeader, *S, CBA); } else { llvm_unreachable("Unknown section type"); } @@ -1903,6 +1916,24 @@ void ELFState::writeSectionContent(Elf_Shdr &SHeader, Section.HashValues->size() * 4; } +template +void ELFState::writeSectionContent( + Elf_Shdr &SHeader, const ELFYAML::CovMapSectionBase &Section, + ContiguousBlobAccumulator &CBA) { + if (Section.Info) + SHeader.sh_info = *Section.Info; + + if (Section.Content) + return; + + auto &OS = *CBA.getRawOS(0); + auto BaseOffset = OS.tell(); + if (auto E = Section.encode(OS, ELFT::Endianness)) + reportError(std::move(E)); + + SHeader.sh_size = CBA.checkAndTell(BaseOffset); +} + template void ELFState::writeFill(ELFYAML::Fill &Fill, ContiguousBlobAccumulator &CBA) { diff --git a/llvm/lib/ObjectYAML/ELFYAML.cpp b/llvm/lib/ObjectYAML/ELFYAML.cpp index 539834fc8d4db..0b7cead2d6d19 100644 --- a/llvm/lib/ObjectYAML/ELFYAML.cpp +++ b/llvm/lib/ObjectYAML/ELFYAML.cpp @@ -15,12 +15,13 @@ #include "llvm/ADT/MapVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/BinaryFormat/ELF.h" +#include "llvm/ObjectYAML/CovMap.h" #include "llvm/Support/ARMEHABI.h" #include "llvm/Support/Casting.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/MipsABIFlags.h" -#include "llvm/Support/YAMLTraits.h" #include "llvm/Support/WithColor.h" +#include "llvm/Support/YAMLTraits.h" #include #include #include @@ -1425,6 +1426,12 @@ static void sectionMapping(IO &IO, ELFYAML::RawContentSection &Section) { IO.mapOptional("Info", Section.Info); } +static void sectionMapping(IO &IO, ELFYAML::CovMapSectionBase &Section) { + commonSectionMapping(IO, Section); + Section.mapping(IO); + IO.mapOptional("Info", Section.Info); +} + static void sectionMapping(IO &IO, ELFYAML::BBAddrMapSection &Section) { commonSectionMapping(IO, Section); IO.mapOptional("Content", Section.Content); @@ -1734,11 +1741,16 @@ void MappingTraits>::mapping( if (ELFYAML::StackSizesSection::nameMatches(Name)) Section = std::make_unique(); else + Section = covmap::make_unique(Name); + + if (!Section) Section = std::make_unique(); } if (auto S = dyn_cast(Section.get())) sectionMapping(IO, *S); + else if (auto S = dyn_cast(Section.get())) + sectionMapping(IO, *S); else sectionMapping(IO, *cast(Section.get())); } diff --git a/llvm/test/tools/obj2yaml/ELF/covmap-be.yaml b/llvm/test/tools/obj2yaml/ELF/covmap-be.yaml new file mode 100644 index 0000000000000..465808442fb7c --- /dev/null +++ b/llvm/test/tools/obj2yaml/ELF/covmap-be.yaml @@ -0,0 +1,81 @@ +# RUN: yaml2obj %s -o %t.o +# RUN: obj2yaml %t.o > %t.plain.yaml +# RUN: yaml2obj %t.plain.yaml -o - | cmp %t.o - + +# FIXME: This is synthetically created. s/ELFDATA2LSB/ELF2DATAMSB/ s/EM_X86_64/EM_PPC64/ +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2MSB + OSABI: ELFOSABI_GNU + Type: ET_REL + Machine: EM_PPC64 + SectionHeaderStringTable: .strtab +Sections: + - Name: __llvm_covfun + Type: SHT_PROGBITS + Flags: [ SHF_GNU_RETAIN ] + AddressAlign: 0x8 + CovFun: + - NameRef: 0xA72DB7A33048E6A3 + FuncHash: 0xAFC772D567676299 + FilenamesRef: 0x70DA2CAFD8CE198E + FileIDs: [ 1, 1 ] + Expressions: + - [ { Tag: Ref, Val: 0 }, { Tag: Ref, Val: 1 } ] + - [ { Tag: Add, Val: 0 }, { Tag: Ref, Val: 2 } ] + - [ { Tag: Add, Val: 0 }, { Tag: Ref, Val: 2 } ] + - [ { Tag: Add, Val: 0 }, { Tag: Ref, Val: 2 } ] + - [ { Tag: Ref, Val: 0 }, { Tag: Ref, Val: 2 } ] + - [ { Tag: Ref, Val: 0 }, { Tag: Ref, Val: 2 } ] + - [ { Tag: Ref, Val: 0 }, { Tag: Ref, Val: 2 } ] + - [ { Tag: Add, Val: 0 }, { Tag: Ref, Val: 5 } ] + Files: + - Regions: + - { dLoc: [ 3, 17, 11, 2 ], Tag: Ref, Val: 0 } + - { dLoc: [ 3, 6, 5, 4 ], Tag: Add, Val: 0 } + - { dLoc: [ 1, 9, 0, 13 ], Tag: Zero, Val: 3, Expansion: 1 } + - { dLoc: [ 0, 23, 1, 7 ], isGap: true, Tag: Ref, Val: 2 } + - { dLoc: [ 1, 7, 0, 16 ], Tag: Ref, Val: 2 } + - { dLoc: [ 0, 17, 2, 5 ], isGap: true, Tag: Sub, Val: 3 } + - { dLoc: [ 1, 1, 0, 1 ], Tag: Zero, Val: 4, ExtTag: Skip } + - { dLoc: [ 1, 5, 1, 4 ], Tag: Sub, Val: 3 } + - { dLoc: [ 1, 12, 0, 17 ], Tag: Sub, Val: 3 } + - { dLoc: [ 0, 12, 0, 17 ], Tag: Zero, Val: 8, ExtTag: Branch, Branch: [ { Tag: Ref, Val: 1 }, { Tag: Sub, Val: 6 } ] } + - { dLoc: [ 0, 19, 1, 3 ], isGap: true, Tag: Sub, Val: 6 } + - { dLoc: [ 1, 3, 0, 11 ], Tag: Sub, Val: 6 } + - { dLoc: [ 0, 12, 1, 3 ], isGap: true, Tag: Zero, Val: 0 } + - { dLoc: [ 1, 3, 0, 12 ], Tag: Zero, Val: 0 } + - Regions: + - { dLoc: [ 1, 17, 0, 41 ], Tag: Add, Val: 0 } + - { dLoc: [ 0, 18, 0, 32 ], Tag: Add, Val: 0 } + - { dLoc: [ 0, 18, 0, 40 ], Tag: Zero, Val: 10, ExtTag: Decision, Decision: { BIdx: 5, NCond: 3 } } + - { dLoc: [ 0, 19, 0, 22 ], Tag: Add, Val: 0 } + - { dLoc: [ 0, 19, 0, 22 ], Tag: Zero, Val: 12, ExtTag: MCDCBranch, Branch: [ { Tag: Sub, Val: 7 }, { Tag: Ref, Val: 5 } ], MCDC: [ 1, 2, 3 ] } + - { dLoc: [ 0, 26, 0, 31 ], Tag: Ref, Val: 5 } + - { dLoc: [ 0, 26, 0, 31 ], Tag: Zero, Val: 12, ExtTag: MCDCBranch, Branch: [ { Tag: Zero, Val: 0 }, { Tag: Ref, Val: 6 } ], MCDC: [ 3, 2, 0 ] } + - { dLoc: [ 0, 36, 0, 40 ], Tag: Ref, Val: 3 } + - { dLoc: [ 0, 36, 0, 40 ], Tag: Zero, Val: 12, ExtTag: MCDCBranch, Branch: [ { Tag: Ref, Val: 4 }, { Tag: Zero, Val: 0 } ], MCDC: [ 2, 0, 0 ] } + - Name: __llvm_covmap + Type: SHT_PROGBITS + Flags: [ SHF_GNU_RETAIN ] + AddressAlign: 0x8 + CovMap: + - FilenamesRef: 0x70DA2CAFD8CE198E + Version: 6 + Filenames: + - '' + - func.cpp + - Name: __llvm_prf_names + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC, SHF_GNU_RETAIN ] + AddressAlign: 0x1 + PrfNames: + - - _Z4funci + - Type: SectionHeaderTable + Sections: + - Name: .strtab + - Name: __llvm_covfun + - Name: __llvm_covmap + - Name: __llvm_prf_names +... diff --git a/llvm/test/tools/obj2yaml/ELF/covmap.yaml b/llvm/test/tools/obj2yaml/ELF/covmap.yaml new file mode 100644 index 0000000000000..8edd884849cc5 --- /dev/null +++ b/llvm/test/tools/obj2yaml/ELF/covmap.yaml @@ -0,0 +1,104 @@ +# RUN: yaml2obj %s -o %t.o +# RUN: obj2yaml %t.o | tee %t.plain.yaml | FileCheck %s --check-prefixes=CHECK,PLAIN +# RUN: yaml2obj %t.plain.yaml -o - | cmp %t.o - + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + OSABI: ELFOSABI_GNU + Type: ET_REL + Machine: EM_X86_64 + SectionHeaderStringTable: .strtab +Sections: +# CHECK: __llvm_covfun + - Name: __llvm_covfun + Type: SHT_PROGBITS + Flags: [ SHF_GNU_RETAIN ] + AddressAlign: 0x8 +# PLAIN: Content: + CovFun: + - NameRef: 0xA72DB7A33048E6A3 + FuncHash: 0xAFC772D567676299 + FilenamesRef: 0x70DA2CAFD8CE198E + FileIDs: [ 1, 1 ] + Expressions: + - [ { Tag: Ref, Val: 0 }, { Tag: Ref, Val: 1 } ] + - [ { Tag: Add, Val: 0 }, { Tag: Ref, Val: 2 } ] + - [ { Tag: Add, Val: 0 }, { Tag: Ref, Val: 2 } ] + - [ { Tag: Add, Val: 0 }, { Tag: Ref, Val: 2 } ] + - [ { Tag: Ref, Val: 0 }, { Tag: Ref, Val: 2 } ] + - [ { Tag: Ref, Val: 0 }, { Tag: Ref, Val: 2 } ] + - [ { Tag: Ref, Val: 0 }, { Tag: Ref, Val: 2 } ] + - [ { Tag: Add, Val: 0 }, { Tag: Ref, Val: 5 } ] + Files: + - Regions: + - { dLoc: [ 3, 17, 11, 2 ], Tag: Ref, Val: 0 } + - { dLoc: [ 3, 6, 5, 4 ], Tag: Add, Val: 0 } + - { dLoc: [ 1, 9, 0, 13 ], Tag: Zero, Val: 3, Expansion: 1 } + - { dLoc: [ 0, 23, 1, 7 ], isGap: true, Tag: Ref, Val: 2 } + - { dLoc: [ 1, 7, 0, 16 ], Tag: Ref, Val: 2 } + - { dLoc: [ 0, 17, 2, 5 ], isGap: true, Tag: Sub, Val: 3 } + - { dLoc: [ 1, 1, 0, 1 ], Tag: Zero, Val: 4, ExtTag: Skip } + - { dLoc: [ 1, 5, 1, 4 ], Tag: Sub, Val: 3 } + - { dLoc: [ 1, 12, 0, 17 ], Tag: Sub, Val: 3 } + - { dLoc: [ 0, 12, 0, 17 ], Tag: Zero, Val: 8, ExtTag: Branch, Branch: [ { Tag: Ref, Val: 1 }, { Tag: Sub, Val: 6 } ] } + - { dLoc: [ 0, 19, 1, 3 ], isGap: true, Tag: Sub, Val: 6 } + - { dLoc: [ 1, 3, 0, 11 ], Tag: Sub, Val: 6 } + - { dLoc: [ 0, 12, 1, 3 ], isGap: true, Tag: Zero, Val: 0 } + - { dLoc: [ 1, 3, 0, 12 ], Tag: Zero, Val: 0 } + - Regions: + - { dLoc: [ 1, 17, 0, 41 ], Tag: Add, Val: 0 } + - { dLoc: [ 0, 18, 0, 32 ], Tag: Add, Val: 0 } + - { dLoc: [ 0, 18, 0, 40 ], Tag: Zero, Val: 10, ExtTag: Decision, Decision: { BIdx: 5, NCond: 3 } } + - { dLoc: [ 0, 19, 0, 22 ], Tag: Add, Val: 0 } + - { dLoc: [ 0, 19, 0, 22 ], Tag: Zero, Val: 12, ExtTag: MCDCBranch, Branch: [ { Tag: Sub, Val: 7 }, { Tag: Ref, Val: 5 } ], MCDC: [ 1, 2, 3 ] } + - { dLoc: [ 0, 26, 0, 31 ], Tag: Ref, Val: 5 } + - { dLoc: [ 0, 26, 0, 31 ], Tag: Zero, Val: 12, ExtTag: MCDCBranch, Branch: [ { Tag: Zero, Val: 0 }, { Tag: Ref, Val: 6 } ], MCDC: [ 3, 2, 0 ] } + - { dLoc: [ 0, 36, 0, 40 ], Tag: Ref, Val: 3 } + - { dLoc: [ 0, 36, 0, 40 ], Tag: Zero, Val: 12, ExtTag: MCDCBranch, Branch: [ { Tag: Ref, Val: 4 }, { Tag: Zero, Val: 0 } ], MCDC: [ 2, 0, 0 ] } +# CHECK: __llvm_covmap + - Name: __llvm_covmap + Type: SHT_PROGBITS + Flags: [ SHF_GNU_RETAIN ] + AddressAlign: 0x8 +# PLAIN: Content: + CovMap: + - FilenamesRef: 0x70DA2CAFD8CE198E + Version: 6 + Filenames: + - '' + - func.cpp +# CHECK: __llvm_prf_names + - Name: __llvm_prf_names + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC, SHF_GNU_RETAIN ] + AddressAlign: 0x1 +# PLAIN-NOT: CovFun: +# PLAIN-NOT: CovMap: +# PLAIN-NOT: PrfNames: +# PLAIN: Content: + PrfNames: + - - _Z4funci + - Type: SectionHeaderTable + Sections: + - Name: .strtab + - Name: __llvm_covfun + - Name: __llvm_covmap + - Name: __llvm_prf_names +... + +# #define EXPR(x) (((x) || false) && true) +# +# int func(int a) { +# int r = 0; +# int i = 0; +# do { +# if (EXPR(30 <= i)) +# return -1; +# +# r += i++; +# } while (i < a); +# return r; +# return -1; +# } diff --git a/utils/bazel/llvm-project-overlay/llvm/BUILD.bazel b/utils/bazel/llvm-project-overlay/llvm/BUILD.bazel index 2f50dfb1c5802..10ef327e02b9a 100644 --- a/utils/bazel/llvm-project-overlay/llvm/BUILD.bazel +++ b/utils/bazel/llvm-project-overlay/llvm/BUILD.bazel @@ -1124,9 +1124,11 @@ cc_library( copts = llvm_copts, deps = [ ":BinaryFormat", + ":Coverage", ":DebugInfoCodeView", ":MC", ":Object", + ":ProfileData", ":Support", ":TargetParser", ],