https://github.com/kateinoigakukun updated https://github.com/llvm/llvm-project/pull/111332
>From 605e1ad180c9f75fd59d8b783ae2041cbaf34e50 Mon Sep 17 00:00:00 2001 From: Yuta Saito <kateinoigaku...@gmail.com> Date: Sat, 5 Oct 2024 16:54:57 +0000 Subject: [PATCH 1/7] [compiler-rt][profile] Add initial support for WebAssembly/WASI 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 --- .../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 +- compiler-rt/lib/profile/InstrProfilingPort.h | 2 +- compiler-rt/lib/profile/InstrProfilingUtil.c | 12 ++++++---- 6 files changed, 36 insertions(+), 8 deletions(-) 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/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(); >From 5939422c1022d8d85355a800ea7341d56c0378bb Mon Sep 17 00:00:00 2001 From: Yuta Saito <kateinoigaku...@gmail.com> Date: Sat, 5 Oct 2024 17:08:14 +0000 Subject: [PATCH 2/7] [compiler-rt][profile] Use encapsulation symbols for Wasm format 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. --- compiler-rt/lib/profile/InstrProfilingPlatformLinux.c | 8 ++++---- compiler-rt/lib/profile/InstrProfilingPlatformOther.c | 3 ++- llvm/lib/Transforms/Instrumentation/InstrProfiling.cpp | 5 +++-- llvm/test/Instrumentation/InstrProfiling/profiling.ll | 7 +------ 4 files changed, 10 insertions(+), 13 deletions(-) diff --git a/compiler-rt/lib/profile/InstrProfilingPlatformLinux.c b/compiler-rt/lib/profile/InstrProfilingPlatformLinux.c index b766436497b741..02f23379ce98bf 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 <elf.h> #include <link.h> #endif diff --git a/compiler-rt/lib/profile/InstrProfilingPlatformOther.c b/compiler-rt/lib/profile/InstrProfilingPlatformOther.c index aa79a5641ceca6..52e82273f8aade 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 <stdlib.h> #include <stdio.h> diff --git a/llvm/lib/Transforms/Instrumentation/InstrProfiling.cpp b/llvm/lib/Transforms/Instrumentation/InstrProfiling.cpp index 1c95a4606ecc56..929c787442057a 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/Instrumentation/InstrProfiling/profiling.ll b/llvm/test/Instrumentation/InstrProfiling/profiling.ll index e7678a9dce0891..74dd54cef50fb5 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() >From 141f533bb4b5bcf73aacfbca53eee5b8e8dee067 Mon Sep 17 00:00:00 2001 From: Yuta Saito <kateinoigaku...@gmail.com> Date: Sat, 5 Oct 2024 17:23:53 +0000 Subject: [PATCH 3/7] [WebAssembly] Emit `__llvm_covmap` and `__llvm_covfun` as custom sections 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"). --- .../CodeGen/TargetLoweringObjectFileImpl.cpp | 6 ++- llvm/lib/MC/MCContext.cpp | 5 ++ llvm/test/CodeGen/WebAssembly/profile.ll | 47 +++++++++++++++++++ 3 files changed, 57 insertions(+), 1 deletion(-) create mode 100644 llvm/test/CodeGen/WebAssembly/profile.ll 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/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: - 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 >From 29cc14ffa418bf61ed677b5495a4606de660bf8d Mon Sep 17 00:00:00 2001 From: Yuta Saito <kateinoigaku...@gmail.com> Date: Sat, 5 Oct 2024 17:40:17 +0000 Subject: [PATCH 4/7] [wasm-ld][Coverage] Align `__llvm_{covfun,covmap}` sections to 8 bytes 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. --- lld/test/wasm/custom-section-align.s | 31 ++++++++++++++++++++++++++++ lld/wasm/InputChunks.h | 10 +++++---- lld/wasm/InputFiles.cpp | 18 ++++++++++++++-- lld/wasm/OutputSections.cpp | 1 + 4 files changed, 54 insertions(+), 6 deletions(-) create mode 100644 lld/test/wasm/custom-section-align.s 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(); } >From f2ad45c9e45708d02810d38680e3e5bfd811b425 Mon Sep 17 00:00:00 2001 From: Yuta Saito <kateinoigaku...@gmail.com> Date: Sun, 6 Oct 2024 09:24:58 +0000 Subject: [PATCH 5/7] [llvm-cov][WebAssembly] Align coverage mapping section to 8 bytes 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. --- .../Coverage/CoverageMappingReader.h | 13 +++++++++-- .../Coverage/CoverageMappingReader.cpp | 23 ++++++++++++++----- 2 files changed, 28 insertions(+), 8 deletions(-) diff --git a/llvm/include/llvm/ProfileData/Coverage/CoverageMappingReader.h b/llvm/include/llvm/ProfileData/Coverage/CoverageMappingReader.h index f05b90114d75a6..886b4d3d6894dc 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<MemoryBuffer>; + using CoverageMapCopyStorage = std::unique_ptr<MemoryBuffer>; private: std::vector<std::string> 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<InstrProfSymtab> 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<std::unique_ptr<BinaryCoverageReader>> createCoverageReaderFromBuffer( StringRef Coverage, FuncRecordsStorage &&FuncRecords, + CoverageMapCopyStorage &&CoverageMap, std::unique_ptr<InstrProfSymtab> ProfileNamesPtr, uint8_t BytesInAddress, llvm::endianness Endian, StringRef CompilationDir = ""); diff --git a/llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp b/llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp index bc4e780fb67a60..8881bffe41c57c 100644 --- a/llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp +++ b/llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp @@ -894,13 +894,15 @@ static Error readCoverageMappingData( Expected<std::unique_ptr<BinaryCoverageReader>> BinaryCoverageReader::createCoverageReaderFromBuffer( StringRef Coverage, FuncRecordsStorage &&FuncRecords, + CoverageMapCopyStorage &&CoverageMap, std::unique_ptr<InstrProfSymtab> ProfileNamesPtr, uint8_t BytesInAddress, llvm::endianness Endian, StringRef CompilationDir) { if (ProfileNamesPtr == nullptr) return make_error<CoverageMapError>(coveragemap_error::malformed, "Caller must provide ProfileNames"); - std::unique_ptr<BinaryCoverageReader> Reader(new BinaryCoverageReader( - std::move(ProfileNamesPtr), std::move(FuncRecords))); + std::unique_ptr<BinaryCoverageReader> 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 +1037,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 @@ -1136,6 +1138,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> 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 +1195,8 @@ loadBinaryFormat(std::unique_ptr<Binary> 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. >From 641dd03d2a61ca49934a73fbc831bcb23cb6c772 Mon Sep 17 00:00:00 2001 From: Yuta Saito <kateinoigaku...@gmail.com> Date: Sat, 5 Oct 2024 17:33:58 +0000 Subject: [PATCH 6/7] [llvm-cov][WebAssembly] Read `__llvm_prf_names` from data segments 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. --- .../Coverage/CoverageMappingReader.cpp | 64 +++++++++++++++--- .../llvm-cov/Inputs/binary-formats.v6.wasm32 | Bin 0 -> 87834 bytes .../Inputs/binary-formats.wasm.proftext | 4 ++ llvm/test/tools/llvm-cov/binary-formats.c | 6 ++ 4 files changed, 65 insertions(+), 9 deletions(-) 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/llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp b/llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp index 8881bffe41c57c..461fc43d32f8df 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" @@ -1077,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<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 = "", @@ -1107,23 +1156,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); 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..37a25088b99edb56649f399b9e54258d0f68d76e GIT binary patch literal 87834 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 Q>~8Dkz82yAKH|dv4{GV#wg3PC literal 0 HcmV?d00001 diff --git a/llvm/test/tools/llvm-cov/Inputs/binary-formats.wasm.proftext b/llvm/test/tools/llvm-cov/Inputs/binary-formats.wasm.proftext new file mode 100644 index 00000000000000..20fc3816c2255a --- /dev/null +++ b/llvm/test/tools/llvm-cov/Inputs/binary-formats.wasm.proftext @@ -0,0 +1,4 @@ +__main_argc_argv +0x0 +1 +100 diff --git a/llvm/test/tools/llvm-cov/binary-formats.c b/llvm/test/tools/llvm-cov/binary-formats.c index a5bfc012860ec3..5f52694559d3b2 100644 --- a/llvm/test/tools/llvm-cov/binary-formats.c +++ b/llvm/test/tools/llvm-cov/binary-formats.c @@ -10,4 +10,10 @@ int main(int argc, const char *argv[]) {} // RUN: llvm-cov show %S/Inputs/binary-formats.v3.macho64l -instr-profile %t.profdata -path-equivalence=/tmp,%S %s | FileCheck %s // RUN: llvm-cov show %S/Inputs/binary-formats.v6.linux64l -instr-profile %t.profdata -path-equivalence=/tmp,%S %s | FileCheck %s +// RUN: llvm-profdata merge %S/Inputs/binary-formats.wasm.proftext -o %t.wasm.profdata +// NOTE: The wasm binary is built with the following command: +// clang -target wasm32-unknown-wasi %s -o %S/Inputs/binary-formats.v6.wasm32 \ +// -fprofile-instr-generate -fcoverage-mapping -lwasi-emulated-getpid -lwasi-emulated-mman +// RUN: llvm-cov show %S/Inputs/binary-formats.v6.wasm32 -instr-profile %t.wasm.profdata -path-equivalence=/tmp,%S %s | FileCheck %s + // RUN: llvm-cov export %S/Inputs/binary-formats.macho64l -instr-profile %t.profdata | FileCheck %S/Inputs/binary-formats.canonical.json >From ca1c78b79159ed421345575845ecc51d255477f9 Mon Sep 17 00:00:00 2001 From: Yuta Saito <kateinoigaku...@gmail.com> Date: Sun, 6 Oct 2024 04:22:12 +0000 Subject: [PATCH 7/7] [clang][WebAssembly] Link with profile runtime libraries if requested 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 ``` --- clang/lib/Driver/ToolChains/WebAssembly.cpp | 2 ++ 1 file changed, 2 insertions(+) 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()); _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits