From d4efc3e097f40afbe8ae275150f49bb08fc04572 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Tue, 15 Oct 2024 02:41:43 +0900 Subject: [PATCH] [Coverage][WebAssembly] Add initial support for WebAssembly/WASI (#111332) Currently, WebAssembly/WASI target does not provide direct support for code coverage. This patch set fixes several issues to unlock the feature. The main changes are: 1. Port `compiler-rt/lib/profile` to WebAssembly/WASI. 2. Adjust profile metadata sections for Wasm object file format. - [CodeGen] Emit `__llvm_covmap` and `__llvm_covfun` as custom sections instead of data segments. - [lld] Align the interval space of custom sections at link time. - [llvm-cov] Copy misaligned custom section data if the start address is not aligned. - [llvm-cov] Read `__llvm_prf_names` from data segments 3. [clang] Link with profile runtime libraries if requested See each commit message for more details and rationale. This is part of the effort to add code coverage support in Wasm target of Swift toolchain. --- clang/lib/Driver/ToolChains/WebAssembly.cpp | 2 + .../cmake/Modules/AllSupportedArchDefs.cmake | 2 +- compiler-rt/cmake/config-ix.cmake | 2 +- compiler-rt/lib/profile/CMakeLists.txt | 24 +++++ compiler-rt/lib/profile/GCDAProfiling.c | 2 +- .../lib/profile/InstrProfilingPlatformLinux.c | 8 +- .../lib/profile/InstrProfilingPlatformOther.c | 3 +- compiler-rt/lib/profile/InstrProfilingPort.h | 2 +- compiler-rt/lib/profile/InstrProfilingUtil.c | 12 ++- lld/test/wasm/custom-section-align.s | 31 +++++++ lld/wasm/InputChunks.h | 10 +- lld/wasm/InputFiles.cpp | 18 +++- lld/wasm/OutputSections.cpp | 1 + .../Coverage/CoverageMappingReader.h | 13 ++- .../CodeGen/TargetLoweringObjectFileImpl.cpp | 6 +- llvm/lib/MC/MCContext.cpp | 5 + .../Coverage/CoverageMappingReader.cpp | 87 +++++++++++++++--- .../Instrumentation/InstrProfiling.cpp | 5 +- llvm/test/CodeGen/WebAssembly/profile.ll | 47 ++++++++++ .../InstrProfiling/profiling.ll | 7 +- .../llvm-cov/Inputs/binary-formats.v6.wasm32 | Bin 0 -> 87781 bytes .../Inputs/binary-formats.wasm.proftext | 4 + llvm/test/tools/llvm-cov/binary-formats.c | 7 ++ 23 files changed, 253 insertions(+), 45 deletions(-) create mode 100644 lld/test/wasm/custom-section-align.s create mode 100644 llvm/test/CodeGen/WebAssembly/profile.ll create mode 100755 llvm/test/tools/llvm-cov/Inputs/binary-formats.v6.wasm32 create mode 100644 llvm/test/tools/llvm-cov/Inputs/binary-formats.wasm.proftext diff --git a/clang/lib/Driver/ToolChains/WebAssembly.cpp b/clang/lib/Driver/ToolChains/WebAssembly.cpp index 9aec11e69fde1..44a6894d30fb2 100644 --- a/clang/lib/Driver/ToolChains/WebAssembly.cpp +++ b/clang/lib/Driver/ToolChains/WebAssembly.cpp @@ -163,6 +163,8 @@ void wasm::Linker::ConstructJob(Compilation &C, const JobAction &JA, AddRunTimeLibs(ToolChain, ToolChain.getDriver(), CmdArgs, Args); } + ToolChain.addProfileRTLibs(Args, CmdArgs); + CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); diff --git a/compiler-rt/cmake/Modules/AllSupportedArchDefs.cmake b/compiler-rt/cmake/Modules/AllSupportedArchDefs.cmake index 809e927715691..d00d39518104b 100644 --- a/compiler-rt/cmake/Modules/AllSupportedArchDefs.cmake +++ b/compiler-rt/cmake/Modules/AllSupportedArchDefs.cmake @@ -77,7 +77,7 @@ set(ALL_HWASAN_SUPPORTED_ARCH ${X86_64} ${ARM64} ${RISCV64}) set(ALL_MEMPROF_SUPPORTED_ARCH ${X86_64}) set(ALL_PROFILE_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM32} ${ARM64} ${PPC32} ${PPC64} ${MIPS32} ${MIPS64} ${S390X} ${SPARC} ${SPARCV9} ${HEXAGON} - ${RISCV32} ${RISCV64} ${LOONGARCH64}) + ${RISCV32} ${RISCV64} ${LOONGARCH64} ${WASM32}) set(ALL_CTX_PROFILE_SUPPORTED_ARCH ${X86_64}) if (OS_NAME MATCHES "FreeBSD") set(ALL_TSAN_SUPPORTED_ARCH ${X86_64} ${MIPS64} ${ARM64}) diff --git a/compiler-rt/cmake/config-ix.cmake b/compiler-rt/cmake/config-ix.cmake index a93a88a920500..a494e0532a50b 100644 --- a/compiler-rt/cmake/config-ix.cmake +++ b/compiler-rt/cmake/config-ix.cmake @@ -822,7 +822,7 @@ else() endif() if (PROFILE_SUPPORTED_ARCH AND NOT LLVM_USE_SANITIZER AND - OS_NAME MATCHES "Darwin|Linux|FreeBSD|Windows|Android|Fuchsia|SunOS|NetBSD|AIX") + OS_NAME MATCHES "Darwin|Linux|FreeBSD|Windows|Android|Fuchsia|SunOS|NetBSD|AIX|WASI") set(COMPILER_RT_HAS_PROFILE TRUE) else() set(COMPILER_RT_HAS_PROFILE FALSE) diff --git a/compiler-rt/lib/profile/CMakeLists.txt b/compiler-rt/lib/profile/CMakeLists.txt index 2617841296720..ac1451c8ceed1 100644 --- a/compiler-rt/lib/profile/CMakeLists.txt +++ b/compiler-rt/lib/profile/CMakeLists.txt @@ -38,6 +38,17 @@ int main() { " COMPILER_RT_TARGET_HAS_FCNTL_LCK) +CHECK_CXX_SOURCE_COMPILES(" +#include + +int fd; +int main() { + flock(fd, LOCK_EX); + return 0; +} + +" COMPILER_RT_TARGET_HAS_FLOCK) + CHECK_CXX_SOURCE_COMPILES(" #include int main() { @@ -93,6 +104,13 @@ if(FUCHSIA OR UNIX) -Wno-pedantic) endif() +if(CMAKE_SYSTEM_NAME STREQUAL "WASI") + set(EXTRA_FLAGS + ${EXTRA_FLAGS} + -D_WASI_EMULATED_MMAN + -D_WASI_EMULATED_GETPID) +endif() + if(COMPILER_RT_TARGET_HAS_ATOMICS) set(EXTRA_FLAGS ${EXTRA_FLAGS} @@ -105,6 +123,12 @@ if(COMPILER_RT_TARGET_HAS_FCNTL_LCK) -DCOMPILER_RT_HAS_FCNTL_LCK=1) endif() +if(COMPILER_RT_TARGET_HAS_FLOCK) + set(EXTRA_FLAGS + ${EXTRA_FLAGS} + -DCOMPILER_RT_HAS_FLOCK=1) +endif() + if(COMPILER_RT_TARGET_HAS_UNAME) set(EXTRA_FLAGS ${EXTRA_FLAGS} diff --git a/compiler-rt/lib/profile/GCDAProfiling.c b/compiler-rt/lib/profile/GCDAProfiling.c index d6e2175169e4a..f67d95d21a7b5 100644 --- a/compiler-rt/lib/profile/GCDAProfiling.c +++ b/compiler-rt/lib/profile/GCDAProfiling.c @@ -584,7 +584,7 @@ void llvm_reset_counters(void) { } } -#if !defined(_WIN32) +#if !defined(_WIN32) && !defined(__wasm__) COMPILER_RT_VISIBILITY pid_t __gcov_fork() { pid_t parent_pid = getpid(); diff --git a/compiler-rt/lib/profile/InstrProfilingPlatformLinux.c b/compiler-rt/lib/profile/InstrProfilingPlatformLinux.c index b766436497b74..02f23379ce98b 100644 --- a/compiler-rt/lib/profile/InstrProfilingPlatformLinux.c +++ b/compiler-rt/lib/profile/InstrProfilingPlatformLinux.c @@ -6,11 +6,11 @@ |* \*===----------------------------------------------------------------------===*/ -#if defined(__linux__) || defined(__FreeBSD__) || defined(__Fuchsia__) || \ - (defined(__sun__) && defined(__svr4__)) || defined(__NetBSD__) || \ - defined(_AIX) +#if defined(__linux__) || defined(__FreeBSD__) || defined(__Fuchsia__) || \ + (defined(__sun__) && defined(__svr4__)) || defined(__NetBSD__) || \ + defined(_AIX) || defined(__wasm__) -#if !defined(_AIX) +#if !defined(_AIX) && !defined(__wasm__) #include #include #endif diff --git a/compiler-rt/lib/profile/InstrProfilingPlatformOther.c b/compiler-rt/lib/profile/InstrProfilingPlatformOther.c index aa79a5641ceca..52e82273f8aad 100644 --- a/compiler-rt/lib/profile/InstrProfilingPlatformOther.c +++ b/compiler-rt/lib/profile/InstrProfilingPlatformOther.c @@ -8,7 +8,8 @@ #if !defined(__APPLE__) && !defined(__linux__) && !defined(__FreeBSD__) && \ !defined(__Fuchsia__) && !(defined(__sun__) && defined(__svr4__)) && \ - !defined(__NetBSD__) && !defined(_WIN32) && !defined(_AIX) + !defined(__NetBSD__) && !defined(_WIN32) && !defined(_AIX) && \ + !defined(__wasm__) #include #include diff --git a/compiler-rt/lib/profile/InstrProfilingPort.h b/compiler-rt/lib/profile/InstrProfilingPort.h index f77699ee8d59c..66d697885eaee 100644 --- a/compiler-rt/lib/profile/InstrProfilingPort.h +++ b/compiler-rt/lib/profile/InstrProfilingPort.h @@ -54,7 +54,7 @@ #endif #define COMPILER_RT_MAX_HOSTLEN 128 -#ifdef __ORBIS__ +#if defined(__ORBIS__) || defined(__wasi__) #define COMPILER_RT_GETHOSTNAME(Name, Len) ((void)(Name), (void)(Len), (-1)) #else #define COMPILER_RT_GETHOSTNAME(Name, Len) lprofGetHostName(Name, Len) diff --git a/compiler-rt/lib/profile/InstrProfilingUtil.c b/compiler-rt/lib/profile/InstrProfilingUtil.c index 642393d432d7e..95ec4080ba250 100644 --- a/compiler-rt/lib/profile/InstrProfilingUtil.c +++ b/compiler-rt/lib/profile/InstrProfilingUtil.c @@ -152,9 +152,11 @@ COMPILER_RT_VISIBILITY int lprofLockFd(int fd) { } } return 0; -#else +#elif defined(COMPILER_RT_HAS_FLOCK) flock(fd, LOCK_EX); return 0; +#else + return 0; #endif } @@ -177,9 +179,11 @@ COMPILER_RT_VISIBILITY int lprofUnlockFd(int fd) { } } return 0; -#else +#elif defined(COMPILER_RT_HAS_FLOCK) flock(fd, LOCK_UN); return 0; +#else + return 0; #endif } @@ -353,8 +357,8 @@ COMPILER_RT_VISIBILITY void lprofRestoreSigKill(void) { COMPILER_RT_VISIBILITY int lprofReleaseMemoryPagesToOS(uintptr_t Begin, uintptr_t End) { -#if defined(__ve__) - // VE doesn't support madvise. +#if defined(__ve__) || defined(__wasi__) + // VE and WASI doesn't support madvise. return 0; #else size_t PageSize = getpagesize(); diff --git a/lld/test/wasm/custom-section-align.s b/lld/test/wasm/custom-section-align.s new file mode 100644 index 0000000000000..0e46177f4cdb7 --- /dev/null +++ b/lld/test/wasm/custom-section-align.s @@ -0,0 +1,31 @@ +# RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown -o %t.o %s +# RUN: wasm-ld --no-entry %t.o -o %t.wasm +# RUN: obj2yaml %t.wasm | FileCheck %s + +# Check that "__llvm_covfun" custom section is aligned to 8 bytes. + + .section .custom_section.__llvm_covfun,"GR",@,__covrec_A + .int32 1 + .int8 2 +# pad .int8 0 +# .int8 0 +# .int8 0 + + .section .custom_section.__llvm_covfun,"GR",@,__covrec_B + .int32 3 + +# CHECK: - Type: CUSTOM +# CHECK-NEXT: Name: __llvm_covfun +# CHECK-NEXT: Payload: '010000000200000003000000' + +# Check that regular custom sections are not aligned. + .section .custom_section.foo,"GR",@,foo_A + .int32 1 + .int8 2 + + .section .custom_section.foo,"GR",@,foo_B + .int32 3 + +# CHECK: - Type: CUSTOM +# CHECK-NEXT: Name: foo +# CHECK-NEXT: Payload: '010000000203000000' diff --git a/lld/wasm/InputChunks.h b/lld/wasm/InputChunks.h index 14eb008c212fb..d6769bcf5c823 100644 --- a/lld/wasm/InputChunks.h +++ b/lld/wasm/InputChunks.h @@ -177,8 +177,9 @@ class MergeInputChunk : public InputChunk { inputSectionOffset = seg.SectionOffset; } - MergeInputChunk(const WasmSection &s, ObjFile *f) - : InputChunk(f, Merge, s.Name, 0, llvm::wasm::WASM_SEG_FLAG_STRINGS) { + MergeInputChunk(const WasmSection &s, ObjFile *f, uint32_t alignment) + : InputChunk(f, Merge, s.Name, alignment, + llvm::wasm::WASM_SEG_FLAG_STRINGS) { assert(s.Type == llvm::wasm::WASM_SEC_CUSTOM); comdat = s.Comdat; rawData = s.Content; @@ -234,6 +235,7 @@ class SyntheticMergedChunk : public InputChunk { void addMergeChunk(MergeInputChunk *ms) { comdat = ms->getComdat(); + alignment = std::max(alignment, ms->alignment); ms->parent = this; chunks.push_back(ms); } @@ -337,8 +339,8 @@ class SyntheticFunction : public InputFunction { // Represents a single Wasm Section within an input file. class InputSection : public InputChunk { public: - InputSection(const WasmSection &s, ObjFile *f) - : InputChunk(f, InputChunk::Section, s.Name), + InputSection(const WasmSection &s, ObjFile *f, uint32_t alignment) + : InputChunk(f, InputChunk::Section, s.Name, alignment), tombstoneValue(getTombstoneForSection(s.Name)), section(s) { assert(section.Type == llvm::wasm::WASM_SEC_CUSTOM); comdat = section.Comdat; diff --git a/lld/wasm/InputFiles.cpp b/lld/wasm/InputFiles.cpp index de8e707ab2b49..420865e2aea8e 100644 --- a/lld/wasm/InputFiles.cpp +++ b/lld/wasm/InputFiles.cpp @@ -18,6 +18,7 @@ #include "llvm/BinaryFormat/Wasm.h" #include "llvm/Object/Binary.h" #include "llvm/Object/Wasm.h" +#include "llvm/ProfileData/InstrProf.h" #include "llvm/Support/Path.h" #include "llvm/Support/TarWriter.h" #include "llvm/Support/raw_ostream.h" @@ -451,6 +452,18 @@ void SharedFile::parse() { } } +// Returns the alignment for a custom section. This is used to concatenate +// custom sections with the same name into a single custom section. +static uint32_t getCustomSectionAlignment(const WasmSection &sec) { + // TODO: Add a section attribute for alignment in the linking spec. + if (sec.Name == getInstrProfSectionName(IPSK_covfun, Triple::Wasm) || + sec.Name == getInstrProfSectionName(IPSK_covmap, Triple::Wasm)) { + // llvm-cov assumes that coverage metadata sections are 8-byte aligned. + return 8; + } + return 1; +} + WasmFileBase::WasmFileBase(Kind k, MemoryBufferRef m) : InputFile(k, m) { // Parse a memory buffer as a wasm file. LLVM_DEBUG(dbgs() << "Reading object: " << toString(this) << "\n"); @@ -520,10 +533,11 @@ void ObjFile::parse(bool ignoreComdats) { dataSection = §ion; } else if (section.Type == WASM_SEC_CUSTOM) { InputChunk *customSec; + uint32_t alignment = getCustomSectionAlignment(section); if (shouldMerge(section)) - customSec = make(section, this); + customSec = make(section, this, alignment); else - customSec = make(section, this); + customSec = make(section, this, alignment); customSec->discarded = isExcludedByComdat(customSec); customSections.emplace_back(customSec); customSections.back()->setRelocations(section.Relocations); diff --git a/lld/wasm/OutputSections.cpp b/lld/wasm/OutputSections.cpp index b0b2446cb56bf..e4f75829ec4c3 100644 --- a/lld/wasm/OutputSections.cpp +++ b/lld/wasm/OutputSections.cpp @@ -244,6 +244,7 @@ void CustomSection::finalizeContents() { for (InputChunk *section : inputSections) { assert(!section->discarded); + payloadSize = alignTo(payloadSize, section->alignment); section->outSecOff = payloadSize; payloadSize += section->getSize(); } diff --git a/llvm/include/llvm/ProfileData/Coverage/CoverageMappingReader.h b/llvm/include/llvm/ProfileData/Coverage/CoverageMappingReader.h index f05b90114d75a..886b4d3d6894d 100644 --- a/llvm/include/llvm/ProfileData/Coverage/CoverageMappingReader.h +++ b/llvm/include/llvm/ProfileData/Coverage/CoverageMappingReader.h @@ -180,6 +180,7 @@ class BinaryCoverageReader : public CoverageMappingReader { }; using FuncRecordsStorage = std::unique_ptr; + using CoverageMapCopyStorage = std::unique_ptr; private: std::vector Filenames; @@ -195,9 +196,16 @@ class BinaryCoverageReader : public CoverageMappingReader { // D69471, which can split up function records into multiple sections on ELF. FuncRecordsStorage FuncRecords; + // Used to tie the lifetimes of an optional copy of the coverage mapping data + // to the lifetime of this BinaryCoverageReader instance. Needed to support + // Wasm object format, which might require realignment of section contents. + CoverageMapCopyStorage CoverageMapCopy; + BinaryCoverageReader(std::unique_ptr Symtab, - FuncRecordsStorage &&FuncRecords) - : ProfileNames(std::move(Symtab)), FuncRecords(std::move(FuncRecords)) {} + FuncRecordsStorage &&FuncRecords, + CoverageMapCopyStorage &&CoverageMapCopy) + : ProfileNames(std::move(Symtab)), FuncRecords(std::move(FuncRecords)), + CoverageMapCopy(std::move(CoverageMapCopy)) {} public: BinaryCoverageReader(const BinaryCoverageReader &) = delete; @@ -212,6 +220,7 @@ class BinaryCoverageReader : public CoverageMappingReader { static Expected> createCoverageReaderFromBuffer( StringRef Coverage, FuncRecordsStorage &&FuncRecords, + CoverageMapCopyStorage &&CoverageMap, std::unique_ptr ProfileNamesPtr, uint8_t BytesInAddress, llvm::endianness Endian, StringRef CompilationDir = ""); diff --git a/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp b/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp index 0d3e4ba5662e0..ce50a3c19ffe0 100644 --- a/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp +++ b/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp @@ -2171,7 +2171,11 @@ MCSection *TargetLoweringObjectFileWasm::getExplicitSectionGlobal( // This could be avoided if all data segements (the wasm sense) were // represented as their own sections (in the llvm sense). // TODO(sbc): https://github.com/WebAssembly/tool-conventions/issues/138 - if (Name == ".llvmcmd" || Name == ".llvmbc") + if (Name == getInstrProfSectionName(IPSK_covmap, Triple::Wasm, + /*AddSegmentInfo=*/false) || + Name == getInstrProfSectionName(IPSK_covfun, Triple::Wasm, + /*AddSegmentInfo=*/false) || + Name == ".llvmbc" || Name == ".llvmcmd") Kind = SectionKind::getMetadata(); StringRef Group = ""; diff --git a/llvm/lib/MC/MCContext.cpp b/llvm/lib/MC/MCContext.cpp index ac3946b6ef46f..b97f9d9f5fed0 100644 --- a/llvm/lib/MC/MCContext.cpp +++ b/llvm/lib/MC/MCContext.cpp @@ -757,6 +757,11 @@ MCSectionWasm *MCContext::getWasmSection(const Twine &Section, SectionKind K, if (!Group.isTriviallyEmpty() && !Group.str().empty()) { GroupSym = cast(getOrCreateSymbol(Group)); GroupSym->setComdat(true); + if (K.isMetadata() && !GroupSym->getType().has_value()) { + // Comdat group symbol associated with a custom section is a section + // symbol (not a data symbol). + GroupSym->setType(wasm::WASM_SYMBOL_TYPE_SECTION); + } } return getWasmSection(Section, K, Flags, GroupSym, UniqueID); diff --git a/llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp b/llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp index bc4e780fb67a6..461fc43d32f8d 100644 --- a/llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp +++ b/llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp @@ -18,12 +18,14 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/Statistic.h" #include "llvm/ADT/StringRef.h" +#include "llvm/BinaryFormat/Wasm.h" #include "llvm/Object/Archive.h" #include "llvm/Object/Binary.h" #include "llvm/Object/COFF.h" #include "llvm/Object/Error.h" #include "llvm/Object/MachOUniversal.h" #include "llvm/Object/ObjectFile.h" +#include "llvm/Object/Wasm.h" #include "llvm/ProfileData/InstrProf.h" #include "llvm/Support/Casting.h" #include "llvm/Support/Compression.h" @@ -894,13 +896,15 @@ static Error readCoverageMappingData( Expected> BinaryCoverageReader::createCoverageReaderFromBuffer( StringRef Coverage, FuncRecordsStorage &&FuncRecords, + CoverageMapCopyStorage &&CoverageMap, std::unique_ptr ProfileNamesPtr, uint8_t BytesInAddress, llvm::endianness Endian, StringRef CompilationDir) { if (ProfileNamesPtr == nullptr) return make_error(coveragemap_error::malformed, "Caller must provide ProfileNames"); - std::unique_ptr Reader(new BinaryCoverageReader( - std::move(ProfileNamesPtr), std::move(FuncRecords))); + std::unique_ptr Reader( + new BinaryCoverageReader(std::move(ProfileNamesPtr), + std::move(FuncRecords), std::move(CoverageMap))); InstrProfSymtab &ProfileNames = *Reader->ProfileNames; StringRef FuncRecordsRef = Reader->FuncRecords->getBuffer(); if (BytesInAddress == 4 && Endian == llvm::endianness::little) { @@ -1035,8 +1039,8 @@ loadTestingFormat(StringRef Data, StringRef CompilationDir) { MemoryBuffer::getMemBuffer(Data); return BinaryCoverageReader::createCoverageReaderFromBuffer( - CoverageMapping, std::move(CoverageRecords), std::move(ProfileNames), - BytesInAddress, Endian, CompilationDir); + CoverageMapping, std::move(CoverageRecords), nullptr, + std::move(ProfileNames), BytesInAddress, Endian, CompilationDir); } /// Find all sections that match \p IPSK name. There may be more than one if @@ -1075,6 +1079,53 @@ lookupSections(ObjectFile &OF, InstrProfSectKind IPSK) { return Sections; } +/// Find a section that matches \p Name and is allocatable at runtime. +/// +/// Returns the contents of the section and its start offset in the object file. +static Expected> +lookupAllocatableSection(ObjectFile &OF, InstrProfSectKind IPSK) { + // On Wasm, allocatable sections can live only in data segments. + if (auto *WOF = dyn_cast(&OF)) { + std::vector Segments; + auto ObjFormat = OF.getTripleObjectFormat(); + auto Name = + getInstrProfSectionName(IPSK, ObjFormat, /*AddSegmentInfo=*/false); + for (const auto &DebugName : WOF->debugNames()) { + if (DebugName.Type != wasm::NameType::DATA_SEGMENT || + DebugName.Name != Name) + continue; + if (DebugName.Index >= WOF->dataSegments().size()) + return make_error(coveragemap_error::malformed); + auto &Segment = WOF->dataSegments()[DebugName.Index]; + Segments.push_back(&Segment); + } + if (Segments.empty()) + return make_error(coveragemap_error::no_data_found); + if (Segments.size() != 1) + return make_error(coveragemap_error::malformed); + + const auto &Segment = *Segments.front(); + auto &Data = Segment.Data; + StringRef Content(reinterpret_cast(Data.Content.data()), + Data.Content.size()); + return std::make_pair(Content, Segment.SectionOffset); + } + + // On other object file types, delegate to lookupSections to find the section. + auto Sections = lookupSections(OF, IPSK); + if (!Sections) + return Sections.takeError(); + if (Sections->size() != 1) + return make_error( + coveragemap_error::malformed, + "the size of coverage mapping section is not one"); + auto &Section = Sections->front(); + auto ContentsOrErr = Section.getContents(); + if (!ContentsOrErr) + return ContentsOrErr.takeError(); + return std::make_pair(*ContentsOrErr, Section.getAddress()); +} + static Expected> loadBinaryFormat(std::unique_ptr Bin, StringRef Arch, StringRef CompilationDir = "", @@ -1105,23 +1156,20 @@ loadBinaryFormat(std::unique_ptr Bin, StringRef Arch, // Look for the sections that we are interested in. auto ProfileNames = std::make_unique(); - std::vector NamesSectionRefs; // If IPSK_name is not found, fallback to search for IPK_covname, which is // used when binary correlation is enabled. - auto NamesSection = lookupSections(*OF, IPSK_name); + auto NamesSection = lookupAllocatableSection(*OF, IPSK_name); if (auto E = NamesSection.takeError()) { consumeError(std::move(E)); - NamesSection = lookupSections(*OF, IPSK_covname); + NamesSection = lookupAllocatableSection(*OF, IPSK_covname); if (auto E = NamesSection.takeError()) return std::move(E); } - NamesSectionRefs = *NamesSection; - if (NamesSectionRefs.size() != 1) - return make_error( - coveragemap_error::malformed, - "the size of coverage mapping section is not one"); - if (Error E = ProfileNames->create(NamesSectionRefs.back())) + uint64_t NamesAddress; + StringRef NamesContent; + std::tie(NamesContent, NamesAddress) = *NamesSection; + if (Error E = ProfileNames->create(NamesContent, NamesAddress)) return std::move(E); auto CoverageSection = lookupSections(*OF, IPSK_covmap); @@ -1136,6 +1184,15 @@ loadBinaryFormat(std::unique_ptr Bin, StringRef Arch, return CoverageMappingOrErr.takeError(); StringRef CoverageMapping = CoverageMappingOrErr.get(); + // If the coverage mapping section is not aligned to 8 bytes, copy it to a + // new buffer that is. Wasm format typically has unaligned section contents + // because it doesn't have a good way to insert padding bytes. + std::unique_ptr CoverageMapCopy; + if (!isAddrAligned(Align(8), CoverageMapping.data())) { + CoverageMapCopy = MemoryBuffer::getMemBufferCopy(CoverageMapping); + CoverageMapping = CoverageMapCopy->getBuffer(); + } + // Look for the coverage records section (Version4 only). auto CoverageRecordsSections = lookupSections(*OF, IPSK_covfun); @@ -1184,8 +1241,8 @@ loadBinaryFormat(std::unique_ptr Bin, StringRef Arch, *BinaryID = getBuildID(OF.get()); return BinaryCoverageReader::createCoverageReaderFromBuffer( - CoverageMapping, std::move(FuncRecords), std::move(ProfileNames), - BytesInAddress, Endian, CompilationDir); + CoverageMapping, std::move(FuncRecords), std::move(CoverageMapCopy), + std::move(ProfileNames), BytesInAddress, Endian, CompilationDir); } /// Determine whether \p Arch is invalid or empty, given \p Bin. diff --git a/llvm/lib/Transforms/Instrumentation/InstrProfiling.cpp b/llvm/lib/Transforms/Instrumentation/InstrProfiling.cpp index 1c95a4606ecc5..929c787442057 100644 --- a/llvm/lib/Transforms/Instrumentation/InstrProfiling.cpp +++ b/llvm/lib/Transforms/Instrumentation/InstrProfiling.cpp @@ -1406,9 +1406,10 @@ static inline Constant *getFuncAddrForProfData(Function *Fn) { static bool needsRuntimeRegistrationOfSectionRange(const Triple &TT) { // compiler-rt uses linker support to get data/counters/name start/end for - // ELF, COFF, Mach-O and XCOFF. + // ELF, COFF, Mach-O, XCOFF, and Wasm. if (TT.isOSBinFormatELF() || TT.isOSBinFormatCOFF() || - TT.isOSBinFormatMachO() || TT.isOSBinFormatXCOFF()) + TT.isOSBinFormatMachO() || TT.isOSBinFormatXCOFF() || + TT.isOSBinFormatWasm()) return false; return true; diff --git a/llvm/test/CodeGen/WebAssembly/profile.ll b/llvm/test/CodeGen/WebAssembly/profile.ll new file mode 100644 index 0000000000000..27802cc3bf356 --- /dev/null +++ b/llvm/test/CodeGen/WebAssembly/profile.ll @@ -0,0 +1,47 @@ +; RUN: llc < %s --filetype=obj | obj2yaml | FileCheck %s + +target triple = "wasm32-unknown-unknown" + +$__covrec_A = comdat any +$__covrec_B = comdat any + +@__covrec_A = linkonce_odr hidden constant <{ i64, i32, i64, i64, [4 x i8] }> <{ + i64 -1978722966671112904, + i32 4, + i64 0, + i64 -8102528905418564625, + [4 x i8] c"\01\01\04\11" +}>, section "__llvm_covfun", comdat, align 8 +@__covrec_B = linkonce_odr hidden constant <{ i64, i32, i64, i64, [4 x i8] }> <{ + i64 8006510647218728891, + i32 9, + i64 0, + i64 -8102528905418564625, + [4 x i8] c"\01\01\00\01" +}>, section "__llvm_covfun", comdat, align 8 +@__llvm_coverage_mapping = private constant { { i32, i32, i32, i32 }, [4 x i8] } { + { i32, i32, i32, i32 } { i32 0, i32 87, i32 0, i32 5 }, + [4 x i8] c"\01\01\00\02" +}, section "__llvm_covmap", align 8 + +; CHECK: - Type: CUSTOM +; CHECK-NEXT: Name: __llvm_covfun +; CHECK-NEXT: Payload: 3845A90EF2298AE4040000000000000000000000EF1B31BAE3088E8F01010411 +; CHECK-NEXT: - Type: CUSTOM +; CHECK-NEXT: Name: __llvm_covfun +; CHECK-NEXT: Payload: BBEFDA6903D71C6F090000000000000000000000EF1B31BAE3088E8F01010001 +; CHECK-NEXT: - Type: CUSTOM +; CHECK-NEXT: Name: __llvm_covmap +; CHECK-NEXT: Payload: '0000000057000000000000000500000001010002' +; CHECK-NEXT: - Type: CUSTOM +; CHECK-NEXT: Name: linking +; CHECK-NEXT: Version: 2 +; CHECK-NEXT: Comdats: +; CHECK-NEXT: - Name: __covrec_A +; CHECK-NEXT: Entries: +; CHECK-NEXT: - Kind: SECTION +; CHECK-NEXT: Index: 1 +; CHECK-NEXT: - Name: __covrec_B +; CHECK-NEXT: Entries: +; CHECK-NEXT: - Kind: SECTION +; CHECK-NEXT: Index: 2 diff --git a/llvm/test/Instrumentation/InstrProfiling/profiling.ll b/llvm/test/Instrumentation/InstrProfiling/profiling.ll index e7678a9dce089..74dd54cef50fb 100644 --- a/llvm/test/Instrumentation/InstrProfiling/profiling.ll +++ b/llvm/test/Instrumentation/InstrProfiling/profiling.ll @@ -114,11 +114,6 @@ declare void @llvm.instrprof.increment(ptr, i64, i32, i32) ; PS: %[[REG:.*]] = load i32, ptr @__llvm_profile_runtime ; XCOFF-NOT: define .* __llvm_profile_runtime_user -; WASM: define internal void @__llvm_profile_register_functions() unnamed_addr { -; WASM-NEXT: call void @__llvm_profile_register_function(ptr @__profd_foo) -; WASM-NEXT: call void @__llvm_profile_register_function(ptr @__profd_foo_weak) -; WASM: call void @__llvm_profile_register_names_function(ptr @__llvm_prf_nm -; WASM-NEXT: ret void -; WASM-NEXT: } +; WASM-NOT: internal void @__llvm_profile_register_functions() ; XCOFF-NOT: internal void @__llvm_profile_register_functions() diff --git a/llvm/test/tools/llvm-cov/Inputs/binary-formats.v6.wasm32 b/llvm/test/tools/llvm-cov/Inputs/binary-formats.v6.wasm32 new file mode 100755 index 0000000000000000000000000000000000000000..5a606d5a2f69fd150690bd17ebb9d922cc17c383 GIT binary patch literal 87781 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 V(uIr%G*R2WW4KLte}K5~{{w2iz+3