-
Notifications
You must be signed in to change notification settings - Fork 12.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Coverage][WebAssembly] Add initial support for WebAssembly/WASI #111332
[Coverage][WebAssembly] Add initial support for WebAssembly/WASI #111332
Conversation
This patch adds initial support for WebAssembly/WASI to the profile runtime library on the top of wasi-libc. This is a part of the ongoing patch series to add coverage support for WebAssembly/WASI. The patch includes the following changes: * Add wasm32-wasi to the list of supported architectures/OSes. * Exclude unsupported features for WASI: flock, madvise, uname. * Enable some user-space emulation provided by wasi-libc: mmap, getpid
@llvm/pr-subscribers-mc @llvm/pr-subscribers-backend-webassembly Author: Yuta Saito (kateinoigakukun) ChangesCurrently, WebAssembly/WASI target does not provide direct support for code coverage.
See each commit message for more details and rationale. Patch is 22.72 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/111332.diff 21 Files Affected:
diff --git a/clang/lib/Driver/ToolChains/WebAssembly.cpp b/clang/lib/Driver/ToolChains/WebAssembly.cpp
index 9aec11e69fde1d..44a6894d30fb29 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 809e9277156912..d00d39518104bf 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 a93a88a9205001..a494e0532a50bc 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 ef23492514898b..a6402f80b890a2 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 <sys/file.h>
+
+int fd;
+int main() {
+ flock(fd, LOCK_EX);
+ return 0;
+}
+
+" COMPILER_RT_TARGET_HAS_FLOCK)
+
CHECK_CXX_SOURCE_COMPILES("
#include <sys/utsname.h>
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 d6e2175169e4a5..a207ddf97c8831 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(__wasi__)
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 b766436497b741..a9791eebabc9df 100644
--- a/compiler-rt/lib/profile/InstrProfilingPlatformLinux.c
+++ b/compiler-rt/lib/profile/InstrProfilingPlatformLinux.c
@@ -8,9 +8,9 @@
#if defined(__linux__) || defined(__FreeBSD__) || defined(__Fuchsia__) || \
(defined(__sun__) && defined(__svr4__)) || defined(__NetBSD__) || \
- defined(_AIX)
+ defined(_AIX) || defined(__wasm__)
-#if !defined(_AIX)
+#if !defined(_AIX) && !defined(__wasm__)
#include <elf.h>
#include <link.h>
#endif
diff --git a/compiler-rt/lib/profile/InstrProfilingPlatformOther.c b/compiler-rt/lib/profile/InstrProfilingPlatformOther.c
index aa79a5641ceca6..e873e9ffbfc6d7 100644
--- a/compiler-rt/lib/profile/InstrProfilingPlatformOther.c
+++ b/compiler-rt/lib/profile/InstrProfilingPlatformOther.c
@@ -8,7 +8,7 @@
#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 <stdlib.h>
#include <stdio.h>
diff --git a/compiler-rt/lib/profile/InstrProfilingPort.h b/compiler-rt/lib/profile/InstrProfilingPort.h
index ed0905cc5f2022..8715a3b0d2a6f0 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 642393d432d7ea..95ec4080ba2504 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 00000000000000..0e46177f4cdb79
--- /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 14eb008c212fb5..d6769bcf5c8232 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 de8e707ab2b497..a60deba9113cd4 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<MergeInputChunk>(section, this);
+ customSec = make<MergeInputChunk>(section, this, alignment);
else
- customSec = make<InputSection>(section, this);
+ customSec = make<InputSection>(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 b0b2446cb56bfc..e4f75829ec4c3e 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/lib/CodeGen/TargetLoweringObjectFileImpl.cpp b/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp
index 0d3e4ba5662e01..ce50a3c19ffe04 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 ac3946b6ef46f3..b97f9d9f5fed0f 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<MCSymbolWasm>(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 bc4e780fb67a60..347578ad5fbfbe 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"
@@ -1075,6 +1077,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<std::pair<StringRef, uint64_t>>
+lookupAllocatableSection(ObjectFile &OF, InstrProfSectKind IPSK) {
+ // On Wasm, allocatable sections can live only in data segments.
+ if (auto *WOF = dyn_cast<WasmObjectFile>(&OF)) {
+ std::vector<const WasmSegment *> 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<CoverageMapError>(coveragemap_error::malformed);
+ auto &Segment = WOF->dataSegments()[DebugName.Index];
+ Segments.push_back(&Segment);
+ }
+ if (Segments.empty())
+ return make_error<CoverageMapError>(coveragemap_error::no_data_found);
+ if (Segments.size() != 1)
+ return make_error<CoverageMapError>(coveragemap_error::malformed);
+
+ const auto &Segment = *Segments.front();
+ auto &Data = Segment.Data;
+ StringRef Content(reinterpret_cast<const char *>(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<CoverageMapError>(
+ 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<std::unique_ptr<BinaryCoverageReader>>
loadBinaryFormat(std::unique_ptr<Binary> Bin, StringRef Arch,
StringRef CompilationDir = "",
@@ -1105,23 +1154,20 @@ loadBinaryFormat(std::unique_ptr<Binary> Bin, StringRef Arch,
// Look for the sections that we are interested in.
auto ProfileNames = std::make_unique<InstrProfSymtab>();
- std::vector<SectionRef> 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<CoverageMapError>(
- 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 +1182,15 @@ loadBinaryFormat(std::unique_ptr<Binary> 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<MemoryBuffer> CoverageMappingBufferOwner;
+ if (!isAddrAligned(Align(8), CoverageMapping.data())) {
+ CoverageMappingBufferOwner = MemoryBuffer::getMemBufferCopy(CoverageMapping);
+ CoverageMapping = CoverageMappingBufferOwner->getBuffer();
+ }
+
// Look for the coverage records section (Version4 only).
auto CoverageRecordsSections = lookupSections(*OF, IPSK_covfun);
diff --git a/llvm/lib/Transforms/Instrumentation/InstrProfiling.cpp b/llvm/lib/Transforms/Instrumentation/InstrProfiling.cpp
index 1c95a4606ecc56..b875f851a57e9f 100644
--- a/llvm/lib/Transforms/Instrumentation/InstrProfiling.cpp
+++ b/llvm/lib/Transforms/Instrumentation/InstrProfiling.cpp
@@ -1406,9 +1406,9 @@ 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 00000000000000..27802cc3bf3567
--- /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: - T...
[truncated]
|
@llvm/pr-subscribers-lld-wasm Author: Yuta Saito (kateinoigakukun) ChangesCurrently, WebAssembly/WASI target does not provide direct support for code coverage.
See each commit message for more details and rationale. Patch is 22.72 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/111332.diff 21 Files Affected:
diff --git a/clang/lib/Driver/ToolChains/WebAssembly.cpp b/clang/lib/Driver/ToolChains/WebAssembly.cpp
index 9aec11e69fde1d..44a6894d30fb29 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 809e9277156912..d00d39518104bf 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 a93a88a9205001..a494e0532a50bc 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 ef23492514898b..a6402f80b890a2 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 <sys/file.h>
+
+int fd;
+int main() {
+ flock(fd, LOCK_EX);
+ return 0;
+}
+
+" COMPILER_RT_TARGET_HAS_FLOCK)
+
CHECK_CXX_SOURCE_COMPILES("
#include <sys/utsname.h>
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 d6e2175169e4a5..a207ddf97c8831 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(__wasi__)
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 b766436497b741..a9791eebabc9df 100644
--- a/compiler-rt/lib/profile/InstrProfilingPlatformLinux.c
+++ b/compiler-rt/lib/profile/InstrProfilingPlatformLinux.c
@@ -8,9 +8,9 @@
#if defined(__linux__) || defined(__FreeBSD__) || defined(__Fuchsia__) || \
(defined(__sun__) && defined(__svr4__)) || defined(__NetBSD__) || \
- defined(_AIX)
+ defined(_AIX) || defined(__wasm__)
-#if !defined(_AIX)
+#if !defined(_AIX) && !defined(__wasm__)
#include <elf.h>
#include <link.h>
#endif
diff --git a/compiler-rt/lib/profile/InstrProfilingPlatformOther.c b/compiler-rt/lib/profile/InstrProfilingPlatformOther.c
index aa79a5641ceca6..e873e9ffbfc6d7 100644
--- a/compiler-rt/lib/profile/InstrProfilingPlatformOther.c
+++ b/compiler-rt/lib/profile/InstrProfilingPlatformOther.c
@@ -8,7 +8,7 @@
#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 <stdlib.h>
#include <stdio.h>
diff --git a/compiler-rt/lib/profile/InstrProfilingPort.h b/compiler-rt/lib/profile/InstrProfilingPort.h
index ed0905cc5f2022..8715a3b0d2a6f0 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 642393d432d7ea..95ec4080ba2504 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 00000000000000..0e46177f4cdb79
--- /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 14eb008c212fb5..d6769bcf5c8232 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 de8e707ab2b497..a60deba9113cd4 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<MergeInputChunk>(section, this);
+ customSec = make<MergeInputChunk>(section, this, alignment);
else
- customSec = make<InputSection>(section, this);
+ customSec = make<InputSection>(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 b0b2446cb56bfc..e4f75829ec4c3e 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/lib/CodeGen/TargetLoweringObjectFileImpl.cpp b/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp
index 0d3e4ba5662e01..ce50a3c19ffe04 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 ac3946b6ef46f3..b97f9d9f5fed0f 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<MCSymbolWasm>(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 bc4e780fb67a60..347578ad5fbfbe 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"
@@ -1075,6 +1077,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<std::pair<StringRef, uint64_t>>
+lookupAllocatableSection(ObjectFile &OF, InstrProfSectKind IPSK) {
+ // On Wasm, allocatable sections can live only in data segments.
+ if (auto *WOF = dyn_cast<WasmObjectFile>(&OF)) {
+ std::vector<const WasmSegment *> 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<CoverageMapError>(coveragemap_error::malformed);
+ auto &Segment = WOF->dataSegments()[DebugName.Index];
+ Segments.push_back(&Segment);
+ }
+ if (Segments.empty())
+ return make_error<CoverageMapError>(coveragemap_error::no_data_found);
+ if (Segments.size() != 1)
+ return make_error<CoverageMapError>(coveragemap_error::malformed);
+
+ const auto &Segment = *Segments.front();
+ auto &Data = Segment.Data;
+ StringRef Content(reinterpret_cast<const char *>(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<CoverageMapError>(
+ 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<std::unique_ptr<BinaryCoverageReader>>
loadBinaryFormat(std::unique_ptr<Binary> Bin, StringRef Arch,
StringRef CompilationDir = "",
@@ -1105,23 +1154,20 @@ loadBinaryFormat(std::unique_ptr<Binary> Bin, StringRef Arch,
// Look for the sections that we are interested in.
auto ProfileNames = std::make_unique<InstrProfSymtab>();
- std::vector<SectionRef> 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<CoverageMapError>(
- 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 +1182,15 @@ loadBinaryFormat(std::unique_ptr<Binary> 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<MemoryBuffer> CoverageMappingBufferOwner;
+ if (!isAddrAligned(Align(8), CoverageMapping.data())) {
+ CoverageMappingBufferOwner = MemoryBuffer::getMemBufferCopy(CoverageMapping);
+ CoverageMapping = CoverageMappingBufferOwner->getBuffer();
+ }
+
// Look for the coverage records section (Version4 only).
auto CoverageRecordsSections = lookupSections(*OF, IPSK_covfun);
diff --git a/llvm/lib/Transforms/Instrumentation/InstrProfiling.cpp b/llvm/lib/Transforms/Instrumentation/InstrProfiling.cpp
index 1c95a4606ecc56..b875f851a57e9f 100644
--- a/llvm/lib/Transforms/Instrumentation/InstrProfiling.cpp
+++ b/llvm/lib/Transforms/Instrumentation/InstrProfiling.cpp
@@ -1406,9 +1406,9 @@ 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 00000000000000..27802cc3bf3567
--- /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: - T...
[truncated]
|
✅ With the latest revision this PR passed the C/C++ code formatter. |
ed504c7
to
ef76026
Compare
Use `InstrProfilingPlatformLinux.c` for Wasm as well as Wasm format has encapsulation symbols (`__start_` and `__stop_`) similar to ELF. This unlocks several additional profile features like value profiling.
…ions This patch makes `__llvm_covmap` and `__llvm_covfun` as custom sections in the wasm object file because they will not be referenced at runtime but just used by `llvm-cov` post-processing tools. The same approach is used in the ELF object file to emit them without `SHF_ALLOC` flag. Those sections have their associated comdat group symbols, which are section symbols (not data symbols) in the wasm object file. This patch also sets the symbol type explicitly not to hit an assertion in the `WasmObjectWriter::writeOneObject` ("data symbols must live in a data section").
This patch aligns the `__llvm_{covfun,covmap}` sections to 8 bytes at the linking stage. This is required because llvm-cov assumes that records in the sections are 8-byte aligned. Unfortunately, custom sections does not have an alignment attribute in the WebAssembly linking spec, so we temporarily do a special case for the metadata sections. In the future, we should generalize this to support alignment for relocatable custom sections.
Wasm format does not have a good way to insert padding bytes to align the start of a section contents because the size of each section header depends on the size of the section contents (leb128 encoding). This design makes it difficult to align section contents to a specific alignment to load them by post-processing tools like llvm-cov. This patch copies the coverage mapping section to a new buffer that is aligned to 8 bytes if the original section is not aligned. This is not an ideal solution but it works for now.
ca1c78b
to
779d88c
Compare
On WebAssembly, most coverage metadata contents read by llvm-cov (like `__llvm_covmap` and `__llvm_covfun`) are stored in custom sections because they are not referenced at runtime. However, `__llvm_prf_names` is referenced at runtime by the profile runtime library and is read by llvm-cov post-processing tools, so it needs to be stored in a data segment, which is allocatable at runtime and accessible by tools as long as "name" section is present in the binary. This patch changes the way llvm-cov reads `__llvm_prf_names` on WebAssembly. Instead of looking for a section, it looks for a data segment with the same name.
This patch teaches the WebAssembly toolchain to link with the profile runtime libraries if profile instrumentation is requested. With this change, the following command will work with profile rt installed: ``` $ clang -target wasm32-unknown-wasi -fprofile-instr-generate \ -lwasi-emulated-getpid -lwasi-emulated-mman -o foo.wasm foo.c ```
779d88c
to
07bb6c2
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lld changes lgtm
LLVM Buildbot has detected a new failure on builder Full details are available at: https://lab.llvm.org/buildbot/#/builders/107/builds/3945 Here is the relevant piece of the build log for the reference
|
LLVM Buildbot has detected a new failure on builder Full details are available at: https://lab.llvm.org/buildbot/#/builders/145/builds/2476 Here is the relevant piece of the build log for the reference
|
LLVM Buildbot has detected a new failure on builder Full details are available at: https://lab.llvm.org/buildbot/#/builders/151/builds/2770 Here is the relevant piece of the build log for the reference
|
I bisected a bustage building clang with PGO on Windows to this change. While building clang with a profile-generate-enabled build of clang to gather a profile, the compiler crashes with:
In the rare case where it doesn't crash, after the successful build,
|
@glandium Thank you for sharing. I'm trying to reproduce the issue on my side. |
@glandium Would you mind sharing CMake configuration? or is there any CI with that setup? |
LLVM Buildbot has detected a new failure on builder Full details are available at: https://lab.llvm.org/buildbot/#/builders/126/builds/809 Here is the relevant piece of the build log for the reference
|
These are the relevant cmake commands from our CI:
The following configures the build that fails, using the clang built with the above configuration:
|
I also bisected errors on Windows, down to this commit. The errors show up when running the compiler-rt testsuite, like this: https://github.com/mstorsjo/llvm-mingw/actions/runs/11356888872/job/31598676534 This can be reproduced with something as small as |
This issue can be reproduced with a few prebuilt files: https://martin.st/temp/profile/ Download those three files, build
Before this breaking change, you'll get this:
After this change, you instead get this:
Can someone revert this change to get things back into working order? |
…ments" (#112520) This reverts commit efc9dd4 in order to fix Windows test failure: #111332 (comment)
…m#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.
…m#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.
…ments" (llvm#112520) This reverts commit efc9dd4 in order to fix Windows test failure: llvm#111332 (comment)
Hi. this change caused chromium windows pgo build to fail: https://issues.chromium.org/issues/373478548 and we see the profile runtime error message:
Looks like profile writing race condition. Though this change touched compiler-rt/lib/profile/InstrProfilingUtil.c, I don't see how this will affect windows. |
perhaps the |
Oh, I see, there are windows version of |
Given there's already an implementation of llvm-project/compiler-rt/lib/profile/CMakeLists.txt Lines 41 to 50 in 7dc2542
|
I would expect that #112695 fixes that issue. |
…m#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.
…ments" (llvm#112520) This reverts commit efc9dd4 in order to fix Windows test failure: llvm#111332 (comment)
…m#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.
…ments" (llvm#112520) This reverts commit efc9dd4 in order to fix Windows test failure: llvm#111332 (comment)
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:
compiler-rt/lib/profile
to WebAssembly/WASI.__llvm_covmap
and__llvm_covfun
as custom sections instead of data segments.__llvm_prf_names
from data segmentsSee 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.