[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