-
Notifications
You must be signed in to change notification settings - Fork 15.2k
[profcheck] Propagate profile metadata to Wrapper function in optimize mode of ExpandVariadic. #168161
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
base: main
Are you sure you want to change the base?
[profcheck] Propagate profile metadata to Wrapper function in optimize mode of ExpandVariadic. #168161
Conversation
|
@llvm/pr-subscribers-llvm-transforms Author: Jin Huang (jinhuang1102) ChangesThis PR fixes the issue where profile metadata ( In optimize mode, the pass splits the original variadic function into two parts:
During this process, the basic blocks and associated metadata are spliced into the This change explicitly copies the Full diff: https://github.com/llvm/llvm-project/pull/168161.diff 4 Files Affected:
diff --git a/llvm/lib/Transforms/IPO/ExpandVariadics.cpp b/llvm/lib/Transforms/IPO/ExpandVariadics.cpp
index 6a11aec6c5cb0..d76172c5f7004 100644
--- a/llvm/lib/Transforms/IPO/ExpandVariadics.cpp
+++ b/llvm/lib/Transforms/IPO/ExpandVariadics.cpp
@@ -422,6 +422,13 @@ bool ExpandVariadics::runOnFunction(Module &M, IRBuilder<> &Builder,
assert(VariadicWrapperDefine == VariadicWrapper);
assert(!VariadicWrapper->isDeclaration());
+ // Add the prof metadata from the original function to the wrapper. Because
+ // FixedArityReplacement is the owner of original function's prof metadata
+ // after the splice, we need to transfer it to VariadicWrapper.
+ if (MDNode *ProfMD =
+ FixedArityReplacement->getMetadata(LLVMContext::MD_prof))
+ VariadicWrapper->setMetadata(LLVMContext::MD_prof, ProfMD);
+
// We now have:
// 1. the original function, now as a declaration with no uses
// 2. a variadic function that unconditionally calls a fixed arity replacement
diff --git a/llvm/test/Transforms/ExpandVariadics/expand-va-intrinsic-split-linkage.ll b/llvm/test/Transforms/ExpandVariadics/expand-va-intrinsic-split-linkage.ll
index 736b07276cebf..5d8f256480924 100644
--- a/llvm/test/Transforms/ExpandVariadics/expand-va-intrinsic-split-linkage.ll
+++ b/llvm/test/Transforms/ExpandVariadics/expand-va-intrinsic-split-linkage.ll
@@ -1,4 +1,4 @@
-; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: -p --function-signature
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: -p --function-signature --check-globals
; RUN: opt -mtriple=wasm32-unknown-unknown -S --passes=expand-variadics --expand-variadics-override=optimize < %s | FileCheck %s --check-prefixes=OPT
; RUN: opt -mtriple=wasm32-unknown-unknown -S --passes=expand-variadics --expand-variadics-override=lowering < %s | FileCheck %s --check-prefixes=ABI
; REQUIRES: webassembly-registered-target
@@ -21,8 +21,8 @@ declare void @llvm.va_start(ptr)
declare void @llvm.va_end(ptr)
declare void @decl_simple(...)
-define void @defn_simple(...) {
-; OPT-LABEL: define {{[^@]+}}@defn_simple(...) {
+define void @defn_simple(...) !prof !0 {
+; OPT-LABEL: define {{[^@]+}}@defn_simple(...) !prof !0 {
; OPT-NEXT: entry:
; OPT-NEXT: %va_start = alloca ptr, align 4
; OPT-NEXT: call void @llvm.lifetime.start.p0(ptr %va_start)
@@ -32,7 +32,7 @@ define void @defn_simple(...) {
; OPT-NEXT: call void @llvm.lifetime.end.p0(ptr %va_start)
; OPT-NEXT: ret void
;
-; ABI-LABEL: define {{[^@]+}}@defn_simple(ptr %varargs) {
+; ABI-LABEL: define {{[^@]+}}@defn_simple(ptr %varargs) !prof !0 {
; ABI-NEXT: %va = alloca ptr, align 4
; ABI-NEXT: store ptr %varargs, ptr %va, align 4
; ABI-NEXT: call void @sink_valist(ptr %va)
@@ -46,8 +46,8 @@ define void @defn_simple(...) {
}
; no declare for private
-define private void @defn_private_simple(...) {
-; OPT-LABEL: define {{[^@]+}}@defn_private_simple(...) {
+define private void @defn_private_simple(...) !prof !0 {
+; OPT-LABEL: define {{[^@]+}}@defn_private_simple(...) !prof !0 {
; OPT-NEXT: entry:
; OPT-NEXT: %va_start = alloca ptr, align 4
; OPT-NEXT: call void @llvm.lifetime.start.p0(ptr %va_start)
@@ -57,7 +57,7 @@ define private void @defn_private_simple(...) {
; OPT-NEXT: call void @llvm.lifetime.end.p0(ptr %va_start)
; OPT-NEXT: ret void
;
-; ABI-LABEL: define {{[^@]+}}@defn_private_simple(ptr %varargs) {
+; ABI-LABEL: define {{[^@]+}}@defn_private_simple(ptr %varargs) !prof !0 {
; ABI-NEXT: %va = alloca ptr, align 4
; ABI-NEXT: store ptr %varargs, ptr %va, align 4
; ABI-NEXT: call void @sink_valist(ptr %va)
@@ -71,8 +71,8 @@ define private void @defn_private_simple(...) {
}
; no declare for internal
-define internal void @defn_internal_simple(...) {
-; OPT-LABEL: define {{[^@]+}}@defn_internal_simple(...) {
+define internal void @defn_internal_simple(...) !prof !0 {
+; OPT-LABEL: define {{[^@]+}}@defn_internal_simple(...) !prof !0 {
; OPT-NEXT: entry:
; OPT-NEXT: %va_start = alloca ptr, align 4
; OPT-NEXT: call void @llvm.lifetime.start.p0(ptr %va_start)
@@ -82,7 +82,7 @@ define internal void @defn_internal_simple(...) {
; OPT-NEXT: call void @llvm.lifetime.end.p0(ptr %va_start)
; OPT-NEXT: ret void
;
-; ABI-LABEL: define {{[^@]+}}@defn_internal_simple(ptr %varargs) {
+; ABI-LABEL: define {{[^@]+}}@defn_internal_simple(ptr %varargs) !prof !0 {
; ABI-NEXT: %va = alloca ptr, align 4
; ABI-NEXT: store ptr %varargs, ptr %va, align 4
; ABI-NEXT: call void @sink_valist(ptr %va)
@@ -96,14 +96,14 @@ define internal void @defn_internal_simple(...) {
}
; no declare for available_externally
-define available_externally void @available_externally_simple(...) {
-; OPT-LABEL: define {{[^@]+}}@available_externally_simple(...) {
+define available_externally void @available_externally_simple(...) !prof !0 {
+; OPT-LABEL: define {{[^@]+}}@available_externally_simple(...) !prof !0 {
; OPT-NEXT: %va = alloca ptr, align 4
; OPT-NEXT: call void @llvm.va_start.p0(ptr %va)
; OPT-NEXT: call void @sink_valist(ptr %va)
; OPT-NEXT: ret void
;
-; ABI-LABEL: define {{[^@]+}}@available_externally_simple(ptr %varargs) {
+; ABI-LABEL: define {{[^@]+}}@available_externally_simple(ptr %varargs) !prof !0 {
; ABI-NEXT: %va = alloca ptr, align 4
; ABI-NEXT: store ptr %varargs, ptr %va, align 4
; ABI-NEXT: call void @sink_valist(ptr %va)
@@ -117,14 +117,14 @@ define available_externally void @available_externally_simple(...) {
}
; no declare for linkonce
-define linkonce void @defn_linkonce_simple(...) {
-; OPT-LABEL: define {{[^@]+}}@defn_linkonce_simple(...) {
+define linkonce void @defn_linkonce_simple(...) !prof !0 {
+; OPT-LABEL: define {{[^@]+}}@defn_linkonce_simple(...) !prof !0 {
; OPT-NEXT: %va = alloca ptr, align 4
; OPT-NEXT: call void @llvm.va_start.p0(ptr %va)
; OPT-NEXT: call void @sink_valist(ptr %va)
; OPT-NEXT: ret void
;
-; ABI-LABEL: define {{[^@]+}}@defn_linkonce_simple(ptr %varargs) {
+; ABI-LABEL: define {{[^@]+}}@defn_linkonce_simple(ptr %varargs) !prof !0 {
; ABI-NEXT: %va = alloca ptr, align 4
; ABI-NEXT: store ptr %varargs, ptr %va, align 4
; ABI-NEXT: call void @sink_valist(ptr %va)
@@ -138,14 +138,14 @@ define linkonce void @defn_linkonce_simple(...) {
}
; no declare for weak
-define weak void @defn_weak_simple(...) {
-; OPT-LABEL: define {{[^@]+}}@defn_weak_simple(...) {
+define weak void @defn_weak_simple(...) !prof !0 {
+; OPT-LABEL: define {{[^@]+}}@defn_weak_simple(...) !prof !0 {
; OPT-NEXT: %va = alloca ptr, align 4
; OPT-NEXT: call void @llvm.va_start.p0(ptr %va)
; OPT-NEXT: call void @sink_valist(ptr %va)
; OPT-NEXT: ret void
;
-; ABI-LABEL: define {{[^@]+}}@defn_weak_simple(ptr %varargs) {
+; ABI-LABEL: define {{[^@]+}}@defn_weak_simple(ptr %varargs) !prof !0 {
; ABI-NEXT: %va = alloca ptr, align 4
; ABI-NEXT: store ptr %varargs, ptr %va, align 4
; ABI-NEXT: call void @sink_valist(ptr %va)
@@ -165,14 +165,14 @@ declare extern_weak void @decl_extern_weak_simple(...)
; no define for extern_weak
; no declare for linkonce_odr
-define linkonce_odr void @defn_linkonce_odr_simple(...) {
-; OPT-LABEL: define {{[^@]+}}@defn_linkonce_odr_simple(...) {
+define linkonce_odr void @defn_linkonce_odr_simple(...) !prof !0 {
+; OPT-LABEL: define {{[^@]+}}@defn_linkonce_odr_simple(...) !prof !0 {
; OPT-NEXT: %va = alloca ptr, align 4
; OPT-NEXT: call void @llvm.va_start.p0(ptr %va)
; OPT-NEXT: call void @sink_valist(ptr %va)
; OPT-NEXT: ret void
;
-; ABI-LABEL: define {{[^@]+}}@defn_linkonce_odr_simple(ptr %varargs) {
+; ABI-LABEL: define {{[^@]+}}@defn_linkonce_odr_simple(ptr %varargs) !prof !0 {
; ABI-NEXT: %va = alloca ptr, align 4
; ABI-NEXT: store ptr %varargs, ptr %va, align 4
; ABI-NEXT: call void @sink_valist(ptr %va)
@@ -186,14 +186,14 @@ define linkonce_odr void @defn_linkonce_odr_simple(...) {
}
; no declare for weak_odr
-define weak_odr void @defn_weak_odr_simple(...) {
-; OPT-LABEL: define {{[^@]+}}@defn_weak_odr_simple(...) {
+define weak_odr void @defn_weak_odr_simple(...) !prof !0 {
+; OPT-LABEL: define {{[^@]+}}@defn_weak_odr_simple(...) !prof !0 {
; OPT-NEXT: %va = alloca ptr, align 4
; OPT-NEXT: call void @llvm.va_start.p0(ptr %va)
; OPT-NEXT: call void @sink_valist(ptr %va)
; OPT-NEXT: ret void
;
-; ABI-LABEL: define {{[^@]+}}@defn_weak_odr_simple(ptr %varargs) {
+; ABI-LABEL: define {{[^@]+}}@defn_weak_odr_simple(ptr %varargs) !prof !0 {
; ABI-NEXT: %va = alloca ptr, align 4
; ABI-NEXT: store ptr %varargs, ptr %va, align 4
; ABI-NEXT: call void @sink_valist(ptr %va)
@@ -207,8 +207,8 @@ define weak_odr void @defn_weak_odr_simple(...) {
}
declare external void @decl_external_simple(...)
-define external void @defn_external_simple(...) {
-; OPT-LABEL: define {{[^@]+}}@defn_external_simple(...) {
+define external void @defn_external_simple(...) !prof !0 {
+; OPT-LABEL: define {{[^@]+}}@defn_external_simple(...) !prof !0 {
; OPT-NEXT: entry:
; OPT-NEXT: %va_start = alloca ptr, align 4
; OPT-NEXT: call void @llvm.lifetime.start.p0(ptr %va_start)
@@ -218,7 +218,7 @@ define external void @defn_external_simple(...) {
; OPT-NEXT: call void @llvm.lifetime.end.p0(ptr %va_start)
; OPT-NEXT: ret void
;
-; ABI-LABEL: define {{[^@]+}}@defn_external_simple(ptr %varargs) {
+; ABI-LABEL: define {{[^@]+}}@defn_external_simple(ptr %varargs) !prof !0 {
; ABI-NEXT: %va = alloca ptr, align 4
; ABI-NEXT: store ptr %varargs, ptr %va, align 4
; ABI-NEXT: call void @sink_valist(ptr %va)
@@ -230,3 +230,15 @@ define external void @defn_external_simple(...) {
call void @llvm.va_end(ptr %va)
ret void
}
+
+!0 = !{!"function_entry_count", i64 1000}
+;.
+; OPT: attributes #0 = { nocallback nofree nosync nounwind willreturn }
+; OPT: attributes #1 = { nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) }
+;.
+; ABI: attributes #0 = { nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) }
+;.
+; OPT: !0 = !{!"function_entry_count", i64 1000}
+;.
+; ABI: !0 = !{!"function_entry_count", i64 1000}
+;.
diff --git a/llvm/test/Transforms/ExpandVariadics/expand-va-intrinsic-split-simple.ll b/llvm/test/Transforms/ExpandVariadics/expand-va-intrinsic-split-simple.ll
index e21b72dbc4d2d..dbb14814f1c75 100644
--- a/llvm/test/Transforms/ExpandVariadics/expand-va-intrinsic-split-simple.ll
+++ b/llvm/test/Transforms/ExpandVariadics/expand-va-intrinsic-split-simple.ll
@@ -1,4 +1,4 @@
-; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: -p --function-signature
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: -p --function-signature --check-globals
; RUN: opt -mtriple=wasm32-unknown-unknown -S --passes=expand-variadics --expand-variadics-override=optimize < %s | FileCheck %s --check-prefixes=OPT
; RUN: opt -mtriple=wasm32-unknown-unknown -S --passes=expand-variadics --expand-variadics-override=lowering < %s | FileCheck %s --check-prefixes=ABI
; REQUIRES: webassembly-registered-target
@@ -6,8 +6,8 @@
; Examples are variadic functions that return the first or the second of an int and a double
; Split the functions into an internal equivalent that takes a va_list and a ABI preserving wrapper
-define i32 @variadic_int_double_get_firstz(...) {
-; OPT-LABEL: define {{[^@]+}}@variadic_int_double_get_firstz(...) {
+define i32 @variadic_int_double_get_firstz(...) !prof !0 {
+; OPT-LABEL: define {{[^@]+}}@variadic_int_double_get_firstz(...) !prof !0 {
; OPT-NEXT: entry:
; OPT-NEXT: %va_start = alloca ptr, align 4
; OPT-NEXT: call void @llvm.lifetime.start.p0(ptr %va_start)
@@ -17,7 +17,7 @@ define i32 @variadic_int_double_get_firstz(...) {
; OPT-NEXT: call void @llvm.lifetime.end.p0(ptr %va_start)
; OPT-NEXT: ret i32 %1
;
-; ABI-LABEL: define {{[^@]+}}@variadic_int_double_get_firstz(ptr %varargs) {
+; ABI-LABEL: define {{[^@]+}}@variadic_int_double_get_firstz(ptr %varargs) !prof !0 {
; ABI-NEXT: entry:
; ABI-NEXT: %va = alloca ptr, align 4
; ABI-NEXT: store ptr %varargs, ptr %va, align 4
@@ -212,3 +212,15 @@ declare void @variadic_without_callers(...)
declare void @llvm.va_start.p0(ptr)
declare void @llvm.va_end.p0(ptr)
+
+!0 = !{!"function_entry_count", i64 1000}
+;.
+; OPT: attributes #0 = { nocallback nofree nosync nounwind willreturn }
+; OPT: attributes #1 = { nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) }
+;.
+; ABI: attributes #0 = { nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) }
+;.
+; OPT: !0 = !{!"function_entry_count", i64 1000}
+;.
+; ABI: !0 = !{!"function_entry_count", i64 1000}
+;.
diff --git a/llvm/test/Transforms/ExpandVariadics/intrinsics.ll b/llvm/test/Transforms/ExpandVariadics/intrinsics.ll
index 52ce80eb4b7b6..429fe0abb2aaa 100644
--- a/llvm/test/Transforms/ExpandVariadics/intrinsics.ll
+++ b/llvm/test/Transforms/ExpandVariadics/intrinsics.ll
@@ -1,4 +1,4 @@
-; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-globals
; RUN: opt -mtriple=wasm32-unknown-unknown -S --passes=expand-variadics --expand-variadics-override=optimize < %s | FileCheck %s -check-prefixes=CHECK,OPT
; RUN: opt -mtriple=wasm32-unknown-unknown -S --passes=expand-variadics --expand-variadics-override=lowering < %s | FileCheck %s -check-prefixes=CHECK,ABI
; REQUIRES: webassembly-registered-target
@@ -16,7 +16,7 @@ declare void @llvm.va_start.p0(ptr)
declare void @llvm.va_end.p0(ptr)
-define void @start_once(...) {
+define void @start_once(...) !prof !0 {
; OPT-LABEL: @start_once(
; OPT-NEXT: entry:
; OPT-NEXT: [[VA_START:%.*]] = alloca ptr, align 4
@@ -118,3 +118,17 @@ entry:
call void @llvm.lifetime.end.p0(ptr nonnull %cp)
ret void
}
+
+!0 = !{!"function_entry_count", i64 1000}
+;.
+; OPT: attributes #[[ATTR0:[0-9]+]] = { nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) }
+; OPT: attributes #[[ATTR1:[0-9]+]] = { nocallback nofree nosync nounwind willreturn }
+; OPT: attributes #[[ATTR2:[0-9]+]] = { nocallback nofree nounwind willreturn memory(argmem: readwrite) }
+;.
+; ABI: attributes #[[ATTR0:[0-9]+]] = { nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) }
+; ABI: attributes #[[ATTR1:[0-9]+]] = { nocallback nofree nounwind willreturn memory(argmem: readwrite) }
+;.
+; OPT: [[META0:![0-9]+]] = !{!"function_entry_count", i64 1000}
+;.
+; ABI: [[META0:![0-9]+]] = !{!"function_entry_count", i64 1000}
+;.
|
|
✅ With the latest revision this PR passed the C/C++ code formatter. |
mtrofin
left a comment
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.
left a nit, and there's the clang-format to fix, but lgtm otherwise. Please wait a bit for others to chime in, too.
JonChesterfield
left a comment
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.
Wonderful, thank you!
Co-authored-by: Mircea Trofin <[email protected]>
This PR fixes the issue where profile metadata (
!prof) is dropped from theVariadicWrapperwhenExpandVariadicsruns in--expand-variadics-override=optimizemode.In optimize mode, the pass splits the original variadic function into two parts:
va_listsetup.During this process, the basic blocks and associated metadata are spliced into the
FixedArityReplacement. Consequently, theVariadicWrapper—which serves as the entry point for callers—is left without function entry count metadata.This change explicitly copies the
MD_profmetadata from theFixedArityReplacementback to theVariadicWrapperafter the split is defined.