[lld] [Coverage][WebAssembly] Discard InstrProf sections if object not live (PR #172023)
via llvm-commits
llvm-commits at lists.llvm.org
Fri Dec 19 03:57:29 PST 2025
https://github.com/Spxg updated https://github.com/llvm/llvm-project/pull/172023
>From 13c8aefa79b6e098d1b1015506993888d37e33b3 Mon Sep 17 00:00:00 2001
From: Spxg <unsafe at outlook.es>
Date: Sat, 13 Dec 2025 10:39:01 +0800
Subject: [PATCH 1/3] [Coverage][WebAssembly] Discard InstrProf sections if
object not live
---
lld/wasm/InputFiles.h | 2 ++
lld/wasm/MarkLive.cpp | 1 +
lld/wasm/Writer.cpp | 8 ++++++++
3 files changed, 11 insertions(+)
diff --git a/lld/wasm/InputFiles.h b/lld/wasm/InputFiles.h
index fd7fcb13f4426..10ebd701a75c0 100644
--- a/lld/wasm/InputFiles.h
+++ b/lld/wasm/InputFiles.h
@@ -121,6 +121,8 @@ class ObjFile : public WasmFileBase {
// Maps input type indices to output type indices
std::vector<uint32_t> typeMap;
std::vector<bool> typeIsUsed;
+ // Does object implicitly mark Live
+ bool markImplicitLive = false;
// Maps function indices to table indices
std::vector<uint32_t> tableEntries;
std::vector<uint32_t> tableEntriesRel;
diff --git a/lld/wasm/MarkLive.cpp b/lld/wasm/MarkLive.cpp
index 2b2cf19f14b30..31cf703694f11 100644
--- a/lld/wasm/MarkLive.cpp
+++ b/lld/wasm/MarkLive.cpp
@@ -71,6 +71,7 @@ void MarkLive::enqueue(Symbol *sym) {
enqueueInitFunctions(obj);
// Mark retained segments in the object that defines this symbol live.
enqueueRetainedSegments(obj);
+ obj->markImplicitLive = true;
}
}
diff --git a/lld/wasm/Writer.cpp b/lld/wasm/Writer.cpp
index 9a5b56fc52e2f..6f9e7f6a260ad 100644
--- a/lld/wasm/Writer.cpp
+++ b/lld/wasm/Writer.cpp
@@ -26,6 +26,7 @@
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/BinaryFormat/Wasm.h"
+#include "llvm/ProfileData/InstrProf.h"
#include "llvm/Support/FileOutputBuffer.h"
#include "llvm/Support/FormatVariadic.h"
#include "llvm/Support/Parallel.h"
@@ -153,6 +154,13 @@ void Writer::calculateCustomSections() {
// Strip debug section in that option was specified.
if (stripDebug && name.starts_with(".debug_"))
continue;
+ // If the object segment isn't mark live, discard `__llvm_covfun` and `__llvm_covmap`
+ // sections since `__llvm_prf_*` segments have already been discarded.
+ bool markSegmentLive = file->isLive() || file->markImplicitLive;
+ if (!markSegmentLive &&
+ (name == getInstrProfSectionName(IPSK_covfun, Triple::Wasm) ||
+ name == getInstrProfSectionName(IPSK_covmap, Triple::Wasm)))
+ continue;
// Otherwise include custom sections by default and concatenate their
// contents.
customSectionMapping[name].push_back(section);
>From 5127a43754948d875297fbff7ad3aeec205781b7 Mon Sep 17 00:00:00 2001
From: Spxg <unsafe at outlook.es>
Date: Thu, 18 Dec 2025 21:59:38 +0800
Subject: [PATCH 2/3] Add malformed profile test
---
lld/test/wasm/Inputs/instr-prof.ll | 13 +++++++
lld/test/wasm/Inputs/malformed-prf1.ll | 48 ++++++++++++++++++++++++++
lld/test/wasm/Inputs/malformed-prf2.ll | 44 +++++++++++++++++++++++
lld/test/wasm/malformed-prf.test | 5 +++
4 files changed, 110 insertions(+)
create mode 100644 lld/test/wasm/Inputs/instr-prof.ll
create mode 100644 lld/test/wasm/Inputs/malformed-prf1.ll
create mode 100644 lld/test/wasm/Inputs/malformed-prf2.ll
create mode 100644 lld/test/wasm/malformed-prf.test
diff --git a/lld/test/wasm/Inputs/instr-prof.ll b/lld/test/wasm/Inputs/instr-prof.ll
new file mode 100644
index 0000000000000..ca32cd4c21ce1
--- /dev/null
+++ b/lld/test/wasm/Inputs/instr-prof.ll
@@ -0,0 +1,13 @@
+; ModuleID = 'instr-prof.c'
+source_filename = "instr-prof.c"
+target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-i128:128-n32:64-S128-ni:1:10:20"
+target triple = "wasm32-unknown-unknown"
+
+ at __llvm_profile_runtime = hidden global i32 0, align 4
+
+!llvm.module.flags = !{!0, !1}
+!llvm.ident = !{!2}
+
+!0 = !{i32 2, !"EnableValueProfiling", i32 0}
+!1 = !{i32 1, !"wchar_size", i32 4}
+!2 = !{!"clang version 21.1.6"}
diff --git a/lld/test/wasm/Inputs/malformed-prf1.ll b/lld/test/wasm/Inputs/malformed-prf1.ll
new file mode 100644
index 0000000000000..9151f922dec23
--- /dev/null
+++ b/lld/test/wasm/Inputs/malformed-prf1.ll
@@ -0,0 +1,48 @@
+; ModuleID = 'malformed-prf1.c'
+source_filename = "malformed-prf1.c"
+target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-i128:128-n32:64-S128-ni:1:10:20"
+target triple = "wasm32-unknown-unknown"
+
+$__llvm_profile_runtime_user = comdat any
+
+$__covrec_5CF8C24CDB18BDACu = comdat any
+
+ at __covrec_5CF8C24CDB18BDACu = linkonce_odr hidden constant <{ i64, i32, i64, i64, [9 x i8] }> <{ i64 6699318081062747564, i32 9, i64 0, i64 -8255375002284483420, [9 x i8] c"\01\01\00\01\01\03\0C\02\02" }>, section "__llvm_covfun", comdat, align 8
+ at __llvm_coverage_mapping = private constant { { i32, i32, i32, i32 }, [76 x i8] } { { i32, i32, i32, i32 } { i32 0, i32 76, i32 0, i32 6 }, [76 x i8] c"\02EIx\DA\0D\CA\D1\09\800\0C\05\C0\15\\D\1F\E2\14\8E\11\DA\94\22MS\92T\D7\B7\9F\07w\A1\AA0f%\F3\0E\E3\A1h\ED\95}\98>\9Cb!#\D8\03\1F\B9\E0\EEc\86oB\AD\A8\09\E7\D5\CAy\A4\1F\85E\19\B0" }, section "__llvm_covmap", align 8
+ at __llvm_profile_runtime = external hidden global i32
+ at __profc_foo = private global [1 x i64] zeroinitializer, section "__llvm_prf_cnts", align 8
+ at __profd_foo = private global { i64, i64, i32, i32, ptr, ptr, i32, [3 x i16], i32 } { i64 6699318081062747564, i64 0, i32 sub (i32 ptrtoint (ptr @__profc_foo to i32), i32 ptrtoint (ptr @__profd_foo to i32)), i32 0, ptr null, ptr null, i32 1, [3 x i16] zeroinitializer, i32 0 }, section "__llvm_prf_data", align 8
+ at __llvm_prf_nm = private constant [13 x i8] c"\03\0Bx\DAK\CB\CF\07\00\02\82\01E", section "__llvm_prf_names", align 1
+ at llvm.used = appending global [5 x ptr] [ptr @__covrec_5CF8C24CDB18BDACu, ptr @__llvm_coverage_mapping, ptr @__llvm_profile_runtime_user, ptr @__profd_foo, ptr @__llvm_prf_nm], section "llvm.metadata"
+
+; Function Attrs: noinline nounwind optnone
+define hidden void @foo() #0 {
+ %1 = load i64, ptr @__profc_foo, align 8
+ %2 = add i64 %1, 1
+ store i64 %2, ptr @__profc_foo, align 8
+ call void @bar()
+ ret void
+}
+
+; Function Attrs: nounwind
+declare void @llvm.instrprof.increment(ptr, i64, i32, i32) #1
+
+declare void @bar(...) #2
+
+; Function Attrs: noinline
+define linkonce_odr hidden i32 @__llvm_profile_runtime_user() #3 comdat {
+ %1 = load i32, ptr @__llvm_profile_runtime, align 4
+ ret i32 %1
+}
+
+attributes #0 = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="generic" "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+multivalue,+mutable-globals,+nontrapping-fptoint,+reference-types,+sign-ext" }
+attributes #1 = { nounwind }
+attributes #2 = { "no-prototype" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="generic" "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+multivalue,+mutable-globals,+nontrapping-fptoint,+reference-types,+sign-ext" }
+attributes #3 = { noinline }
+
+!llvm.module.flags = !{!0, !1}
+!llvm.ident = !{!2}
+
+!0 = !{i32 2, !"EnableValueProfiling", i32 0}
+!1 = !{i32 1, !"wchar_size", i32 4}
+!2 = !{!"clang version 21.1.6"}
diff --git a/lld/test/wasm/Inputs/malformed-prf2.ll b/lld/test/wasm/Inputs/malformed-prf2.ll
new file mode 100644
index 0000000000000..9831e17c7c862
--- /dev/null
+++ b/lld/test/wasm/Inputs/malformed-prf2.ll
@@ -0,0 +1,44 @@
+; ModuleID = 'malformed-prf2.c'
+source_filename = "malformed-prf2.c"
+target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-i128:128-n32:64-S128-ni:1:10:20"
+target triple = "wasm32-unknown-unknown"
+
+$__llvm_profile_runtime_user = comdat any
+
+$__covrec_E413754A191DB537u = comdat any
+
+ at __covrec_E413754A191DB537u = linkonce_odr hidden constant <{ i64, i32, i64, i64, [9 x i8] }> <{ i64 -2012135647395072713, i32 9, i64 0, i64 -3975376370493289617, [9 x i8] c"\01\01\00\01\01\01\0C\00\0E" }>, section "__llvm_covfun", comdat, align 8
+ at __llvm_coverage_mapping = private constant { { i32, i32, i32, i32 }, [76 x i8] } { { i32, i32, i32, i32 } { i32 0, i32 76, i32 0, i32 6 }, [76 x i8] c"\02EIx\DA\0D\CA\D1\09\800\0C\05\C0\15\\D\1F\E8\14\8E\11\DA\94\22MS\92T\D7\B7\9F\07w\A1\AA0f%\F3\0E\E3\A1h\ED\95}\98>\9Cb!#\D8\03\1F\B9\E0\EEc\86oB\AD\A8\09\E7\D5\CAy\A4\1F\85H\19\B1" }, section "__llvm_covmap", align 8
+ at __llvm_profile_runtime = external hidden global i32
+ at __profc_bar = private global [1 x i64] zeroinitializer, section "__llvm_prf_cnts", align 8
+ at __profd_bar = private global { i64, i64, i32, i32, ptr, ptr, i32, [3 x i16], i32 } { i64 -2012135647395072713, i64 0, i32 sub (i32 ptrtoint (ptr @__profc_bar to i32), i32 ptrtoint (ptr @__profd_bar to i32)), i32 0, ptr null, ptr null, i32 1, [3 x i16] zeroinitializer, i32 0 }, section "__llvm_prf_data", align 8
+ at __llvm_prf_nm = private constant [13 x i8] c"\03\0Bx\DAKJ,\02\00\02]\016", section "__llvm_prf_names", align 1
+ at llvm.used = appending global [5 x ptr] [ptr @__covrec_E413754A191DB537u, ptr @__llvm_coverage_mapping, ptr @__llvm_profile_runtime_user, ptr @__profd_bar, ptr @__llvm_prf_nm], section "llvm.metadata"
+
+; Function Attrs: noinline nounwind optnone
+define hidden void @bar() #0 {
+ %1 = load i64, ptr @__profc_bar, align 8
+ %2 = add i64 %1, 1
+ store i64 %2, ptr @__profc_bar, align 8
+ ret void
+}
+
+; Function Attrs: nounwind
+declare void @llvm.instrprof.increment(ptr, i64, i32, i32) #1
+
+; Function Attrs: noinline
+define linkonce_odr hidden i32 @__llvm_profile_runtime_user() #2 comdat {
+ %1 = load i32, ptr @__llvm_profile_runtime, align 4
+ ret i32 %1
+}
+
+attributes #0 = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="generic" "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+multivalue,+mutable-globals,+nontrapping-fptoint,+reference-types,+sign-ext" }
+attributes #1 = { nounwind }
+attributes #2 = { noinline }
+
+!llvm.module.flags = !{!0, !1}
+!llvm.ident = !{!2}
+
+!0 = !{i32 2, !"EnableValueProfiling", i32 0}
+!1 = !{i32 1, !"wchar_size", i32 4}
+!2 = !{!"clang version 21.1.6"}
diff --git a/lld/test/wasm/malformed-prf.test b/lld/test/wasm/malformed-prf.test
new file mode 100644
index 0000000000000..0bce308fa0e6f
--- /dev/null
+++ b/lld/test/wasm/malformed-prf.test
@@ -0,0 +1,5 @@
+RUN: llc -filetype=obj %p/Inputs/instr-prof.ll -o %t.instr-prof.o
+RUN: llc -filetype=obj %p/Inputs/malformed-prf1.ll -o %t.malformed-prf1.o
+RUN: llc -filetype=obj %p/Inputs/malformed-prf2.ll -o %t.malformed-prf2.o
+RUN: wasm-ld -o %t.wasm %t.instr-prof.o %t.malformed-prf1.o --start-lib %t.malformed-prf2.o --end-lib --gc-sections --no-entry
+RUN: llvm-cov export --object %t.wasm --empty-profile
>From 9cd2356adac70335eb8efa4f7ffa1bb94a286a3e Mon Sep 17 00:00:00 2001
From: Spxg <unsafe at outlook.es>
Date: Fri, 19 Dec 2025 19:56:53 +0800
Subject: [PATCH 3/3] Rename and describe the test
---
lld/test/wasm/Inputs/instr-prof.ll | 13 -------------
lld/test/wasm/malformed-prf.ll | 28 ++++++++++++++++++++++++++++
lld/test/wasm/malformed-prf.test | 5 -----
3 files changed, 28 insertions(+), 18 deletions(-)
delete mode 100644 lld/test/wasm/Inputs/instr-prof.ll
create mode 100644 lld/test/wasm/malformed-prf.ll
delete mode 100644 lld/test/wasm/malformed-prf.test
diff --git a/lld/test/wasm/Inputs/instr-prof.ll b/lld/test/wasm/Inputs/instr-prof.ll
deleted file mode 100644
index ca32cd4c21ce1..0000000000000
--- a/lld/test/wasm/Inputs/instr-prof.ll
+++ /dev/null
@@ -1,13 +0,0 @@
-; ModuleID = 'instr-prof.c'
-source_filename = "instr-prof.c"
-target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-i128:128-n32:64-S128-ni:1:10:20"
-target triple = "wasm32-unknown-unknown"
-
- at __llvm_profile_runtime = hidden global i32 0, align 4
-
-!llvm.module.flags = !{!0, !1}
-!llvm.ident = !{!2}
-
-!0 = !{i32 2, !"EnableValueProfiling", i32 0}
-!1 = !{i32 1, !"wchar_size", i32 4}
-!2 = !{!"clang version 21.1.6"}
diff --git a/lld/test/wasm/malformed-prf.ll b/lld/test/wasm/malformed-prf.ll
new file mode 100644
index 0000000000000..cdda45083dc80
--- /dev/null
+++ b/lld/test/wasm/malformed-prf.ll
@@ -0,0 +1,28 @@
+; RUN: llc -filetype=obj %s -o %t.instr-prof.o
+; RUN: llc -filetype=obj %p/Inputs/malformed-prf1.ll -o %t.malformed-prf1.o
+; RUN: llc -filetype=obj %p/Inputs/malformed-prf2.ll -o %t.malformed-prf2.o
+; RUN: wasm-ld -o %t.wasm %t.instr-prof.o %t.malformed-prf1.o --start-lib %t.malformed-prf2.o --end-lib --gc-sections --no-entry
+; RUN: llvm-cov export --object %t.wasm --empty-profile
+
+; 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.
+;
+; WASM stores `__llvm_covfun` in custom section, while `__llvm_prf_names` is stored in the DATA section.
+; The former not be GC, whereas the latter may be GC, causing llvm-cov execution to fail.
+;
+; Now, __llvm_covfun and __llvm_covmap will be discarded if the object is not live and make llvm-cov work.
+
+; ModuleID = 'instr-prof.c'
+source_filename = "instr-prof.c"
+target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-i128:128-n32:64-S128-ni:1:10:20"
+target triple = "wasm32-unknown-unknown"
+
+ at __llvm_profile_runtime = hidden global i32 0, align 4
+
+!llvm.module.flags = !{!0, !1}
+!llvm.ident = !{!2}
+
+!0 = !{i32 2, !"EnableValueProfiling", i32 0}
+!1 = !{i32 1, !"wchar_size", i32 4}
+!2 = !{!"clang version 21.1.6"}
+
diff --git a/lld/test/wasm/malformed-prf.test b/lld/test/wasm/malformed-prf.test
deleted file mode 100644
index 0bce308fa0e6f..0000000000000
--- a/lld/test/wasm/malformed-prf.test
+++ /dev/null
@@ -1,5 +0,0 @@
-RUN: llc -filetype=obj %p/Inputs/instr-prof.ll -o %t.instr-prof.o
-RUN: llc -filetype=obj %p/Inputs/malformed-prf1.ll -o %t.malformed-prf1.o
-RUN: llc -filetype=obj %p/Inputs/malformed-prf2.ll -o %t.malformed-prf2.o
-RUN: wasm-ld -o %t.wasm %t.instr-prof.o %t.malformed-prf1.o --start-lib %t.malformed-prf2.o --end-lib --gc-sections --no-entry
-RUN: llvm-cov export --object %t.wasm --empty-profile
More information about the llvm-commits
mailing list