[lld] [llvm] [Coverage][WebAssembly] Keep InstrProf segments during gc (PR #172023)
via llvm-commits
llvm-commits at lists.llvm.org
Fri Dec 12 16:58:04 PST 2025
https://github.com/Spxg updated https://github.com/llvm/llvm-project/pull/172023
>From 70373ad39da974f2d0e09aa4cc56c77df89ba7e8 Mon Sep 17 00:00:00 2001
From: Spxg <unsafe at outlook.es>
Date: Fri, 12 Dec 2025 23:05:13 +0800
Subject: [PATCH 1/2] [Coverage][WebAssembly] Keep InstrProf segments during gc
Every covfun record holds a hash of its symbol name, and `llvm-cov`
will exit fatally if it can't resolve that hash back to an entry in
the binary's `__llvm_prf_names` linker section.
However, WASM stores `__llvm_covfun` in `CustomSection`, while
`__llvm_prf_names` is stored in the `DATA` section. The former cannot be
GC, whereas the latter may be GC, causing `llvm-cov` execution to fail.
This flag records whether it is an `InstrProfSegment` so that it can be
enqueued during GC.
---
lld/wasm/InputChunks.h | 3 +++
lld/wasm/InputFiles.cpp | 17 +++++++++++++++++
lld/wasm/MarkLive.cpp | 13 ++++++++++++-
llvm/include/llvm/BinaryFormat/Wasm.h | 1 +
4 files changed, 33 insertions(+), 1 deletion(-)
diff --git a/lld/wasm/InputChunks.h b/lld/wasm/InputChunks.h
index 1fe78d76631f1..7cc49da1064fc 100644
--- a/lld/wasm/InputChunks.h
+++ b/lld/wasm/InputChunks.h
@@ -83,6 +83,9 @@ class InputChunk {
bool isTLS() const { return flags & llvm::wasm::WASM_SEG_FLAG_TLS; }
bool isRetained() const { return flags & llvm::wasm::WASM_SEG_FLAG_RETAIN; }
+ bool isInstrProfSegment() const {
+ return flags & llvm::wasm::WASM_SEG_FLAG_PRF;
+ }
ObjFile *file;
OutputSection *outputSec = nullptr;
diff --git a/lld/wasm/InputFiles.cpp b/lld/wasm/InputFiles.cpp
index 387b5eb10ba2f..fedaa4b737e07 100644
--- a/lld/wasm/InputFiles.cpp
+++ b/lld/wasm/InputFiles.cpp
@@ -577,6 +577,23 @@ void ObjFile::parse(bool ignoreComdats) {
if (!seg->isTLS() &&
(seg->name.starts_with(".tdata") || seg->name.starts_with(".tbss")))
seg->flags |= WASM_SEG_FLAG_TLS;
+
+ // Every covfun record holds a hash of its symbol name, and `llvm-cov`
+ // will exit fatally if it can't resolve that hash back to an entry in
+ // the binary's `__llvm_prf_names` linker section.
+ //
+ // However, WASM stores `__llvm_covfun` in `CustomSection`, while
+ // `__llvm_prf_names` is stored in the `DATA` section. The former cannot be
+ // GC, whereas the latter may be GC, causing `llvm-cov` execution to fail.
+ //
+ // This flag records whether it is an `InstrProfSegment` so that it can be
+ // enqueued during GC.
+ if (seg->name == getInstrProfSectionName(IPSK_name, Triple::Wasm) ||
+ seg->name == getInstrProfSectionName(IPSK_cnts, Triple::Wasm) ||
+ seg->name == getInstrProfSectionName(IPSK_data, Triple::Wasm)) {
+ seg->flags |= WASM_SEG_FLAG_PRF;
+ }
+
segments.emplace_back(seg);
}
setRelocs(segments, dataSection);
diff --git a/lld/wasm/MarkLive.cpp b/lld/wasm/MarkLive.cpp
index 2b2cf19f14b30..c51214b6920cf 100644
--- a/lld/wasm/MarkLive.cpp
+++ b/lld/wasm/MarkLive.cpp
@@ -43,6 +43,7 @@ class MarkLive {
void enqueue(InputChunk *chunk);
void enqueueInitFunctions(const ObjFile *sym);
void enqueueRetainedSegments(const ObjFile *file);
+ void enqueueInstrProfSegments(const ObjFile *file);
void mark();
bool isCallCtorsLive();
@@ -104,6 +105,13 @@ void MarkLive::enqueueRetainedSegments(const ObjFile *file) {
enqueue(chunk);
}
+// Mark instr profile segments.
+void MarkLive::enqueueInstrProfSegments(const ObjFile *file) {
+ for (InputChunk *chunk : file->segments)
+ if (chunk->isInstrProfSegment())
+ enqueue(chunk);
+}
+
void MarkLive::run() {
// Add GC root symbols.
if (!ctx.arg.entry.empty())
@@ -117,7 +125,9 @@ void MarkLive::run() {
if (ctx.sym.callDtors)
enqueue(ctx.sym.callDtors);
- for (const ObjFile *obj : ctx.objectFiles)
+ for (const ObjFile *obj : ctx.objectFiles) {
+ // Enqueue instr profile segments
+ enqueueInstrProfSegments(obj);
if (obj->isLive()) {
// Enqueue constructors in objects explicitly live from the command-line.
enqueueInitFunctions(obj);
@@ -125,6 +135,7 @@ void MarkLive::run() {
// command-line.
enqueueRetainedSegments(obj);
}
+ }
mark();
diff --git a/llvm/include/llvm/BinaryFormat/Wasm.h b/llvm/include/llvm/BinaryFormat/Wasm.h
index cf90a43d0d7e8..1f76330a29efb 100644
--- a/llvm/include/llvm/BinaryFormat/Wasm.h
+++ b/llvm/include/llvm/BinaryFormat/Wasm.h
@@ -229,6 +229,7 @@ enum WasmSegmentFlag : unsigned {
WASM_SEG_FLAG_STRINGS = 0x1,
WASM_SEG_FLAG_TLS = 0x2,
WASM_SEG_FLAG_RETAIN = 0x4,
+ WASM_SEG_FLAG_PRF = 0x8,
};
// Kinds of tag attributes.
>From b08f524dddb2c76be50ff7e5a1084978b8f68eae Mon Sep 17 00:00:00 2001
From: Spxg <unsafe at outlook.es>
Date: Sat, 13 Dec 2025 08:56:57 +0800
Subject: [PATCH 2/2] Remove `WASM_SEG_FLAG_PRF`
---
lld/wasm/InputChunks.h | 4 +---
lld/wasm/InputFiles.cpp | 8 +++-----
lld/wasm/MarkLive.cpp | 2 +-
llvm/include/llvm/BinaryFormat/Wasm.h | 1 -
4 files changed, 5 insertions(+), 10 deletions(-)
diff --git a/lld/wasm/InputChunks.h b/lld/wasm/InputChunks.h
index 7cc49da1064fc..8b9539769f3c8 100644
--- a/lld/wasm/InputChunks.h
+++ b/lld/wasm/InputChunks.h
@@ -83,9 +83,6 @@ class InputChunk {
bool isTLS() const { return flags & llvm::wasm::WASM_SEG_FLAG_TLS; }
bool isRetained() const { return flags & llvm::wasm::WASM_SEG_FLAG_RETAIN; }
- bool isInstrProfSegment() const {
- return flags & llvm::wasm::WASM_SEG_FLAG_PRF;
- }
ObjFile *file;
OutputSection *outputSec = nullptr;
@@ -93,6 +90,7 @@ class InputChunk {
uint32_t inputSectionOffset = 0;
uint32_t alignment;
uint32_t flags;
+ bool isInstrProfSegment = false;
// Only applies to data segments.
uint32_t outputSegmentOffset = 0;
diff --git a/lld/wasm/InputFiles.cpp b/lld/wasm/InputFiles.cpp
index fedaa4b737e07..b3aea10da90ad 100644
--- a/lld/wasm/InputFiles.cpp
+++ b/lld/wasm/InputFiles.cpp
@@ -562,7 +562,6 @@ void ObjFile::parse(bool ignoreComdats) {
typeMap.resize(getWasmObj()->types().size());
typeIsUsed.resize(getWasmObj()->types().size(), false);
-
// Populate `Segments`.
for (const WasmSegment &s : wasmObj->dataSegments()) {
InputChunk *seg;
@@ -588,11 +587,10 @@ void ObjFile::parse(bool ignoreComdats) {
//
// This flag records whether it is an `InstrProfSegment` so that it can be
// enqueued during GC.
- if (seg->name == getInstrProfSectionName(IPSK_name, Triple::Wasm) ||
+ seg->isInstrProfSegment =
+ seg->name == getInstrProfSectionName(IPSK_name, Triple::Wasm) ||
seg->name == getInstrProfSectionName(IPSK_cnts, Triple::Wasm) ||
- seg->name == getInstrProfSectionName(IPSK_data, Triple::Wasm)) {
- seg->flags |= WASM_SEG_FLAG_PRF;
- }
+ seg->name == getInstrProfSectionName(IPSK_data, Triple::Wasm);
segments.emplace_back(seg);
}
diff --git a/lld/wasm/MarkLive.cpp b/lld/wasm/MarkLive.cpp
index c51214b6920cf..d9a87c4030ec8 100644
--- a/lld/wasm/MarkLive.cpp
+++ b/lld/wasm/MarkLive.cpp
@@ -108,7 +108,7 @@ void MarkLive::enqueueRetainedSegments(const ObjFile *file) {
// Mark instr profile segments.
void MarkLive::enqueueInstrProfSegments(const ObjFile *file) {
for (InputChunk *chunk : file->segments)
- if (chunk->isInstrProfSegment())
+ if (chunk->isInstrProfSegment)
enqueue(chunk);
}
diff --git a/llvm/include/llvm/BinaryFormat/Wasm.h b/llvm/include/llvm/BinaryFormat/Wasm.h
index 1f76330a29efb..cf90a43d0d7e8 100644
--- a/llvm/include/llvm/BinaryFormat/Wasm.h
+++ b/llvm/include/llvm/BinaryFormat/Wasm.h
@@ -229,7 +229,6 @@ enum WasmSegmentFlag : unsigned {
WASM_SEG_FLAG_STRINGS = 0x1,
WASM_SEG_FLAG_TLS = 0x2,
WASM_SEG_FLAG_RETAIN = 0x4,
- WASM_SEG_FLAG_PRF = 0x8,
};
// Kinds of tag attributes.
More information about the llvm-commits
mailing list