[clang] [Clang][CodeGen] Emit fake uses before musttail calls (PR #136867)
https://github.com/SLTozer closed https://github.com/llvm/llvm-project/pull/136867 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang][CodeGen] Emit fake uses before musttail calls (PR #136867)
https://github.com/SLTozer updated
https://github.com/llvm/llvm-project/pull/136867
>From 90c09c8326077a1ba6797519bbefd014f32b5beb Mon Sep 17 00:00:00 2001
From: Stephen Tozer
Date: Wed, 23 Apr 2025 14:24:50 +0100
Subject: [PATCH 1/5] [Clang] Emit Fake Uses before musttail calls
Fixes the issue reported following the merge of #118026.
When a valid `musttail` call is made, the function it is made from must
return immediately after the call; if there are any cleanups left in the
function, then an error is triggered. This is not necessary for fake uses
however - it is perfectly valid to simply emit the fake use "cleanup" code
before the tail call, and indeed LLVM will automatically move any fake uses
following a tail call to come before the tail call.
Therefore, this patch specifically choose to handle fake use cleanups when
a musttail call is present by simply emitting them immediately before the
call.
---
clang/lib/CodeGen/CGCall.cpp| 12 +++-
clang/test/CodeGenCXX/fake-use-musttail.cpp | 72 +
2 files changed, 83 insertions(+), 1 deletion(-)
create mode 100644 clang/test/CodeGenCXX/fake-use-musttail.cpp
diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp
index 8cb27420dd911..c8cddfc06fce7 100644
--- a/clang/lib/CodeGen/CGCall.cpp
+++ b/clang/lib/CodeGen/CGCall.cpp
@@ -6001,8 +6001,18 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo
&CallInfo,
for (auto it = EHStack.find(CurrentCleanupScopeDepth); it != EHStack.end();
++it) {
EHCleanupScope *Cleanup = dyn_cast(&*it);
- if (!(Cleanup && Cleanup->getCleanup()->isRedundantBeforeReturn()))
+ // Fake uses can be safely emitted immediately prior to the tail call; we
+ // choose to emit the fake use before the call rather than after, to
avoid
+ // forcing variable values from every call on the "stack" to be preserved
+ // simultaneously.
+ if (Cleanup && Cleanup->isFakeUse()) {
+CGBuilderTy::InsertPointGuard IPG(Builder);
+Builder.SetInsertPoint(CI);
+Cleanup->getCleanup()->Emit(*this, EHScopeStack::Cleanup::Flags());
+ } else if (!(Cleanup &&
+ Cleanup->getCleanup()->isRedundantBeforeReturn())) {
CGM.ErrorUnsupported(MustTailCall, "tail call skipping over cleanups");
+ }
}
if (CI->getType()->isVoidTy())
Builder.CreateRetVoid();
diff --git a/clang/test/CodeGenCXX/fake-use-musttail.cpp
b/clang/test/CodeGenCXX/fake-use-musttail.cpp
new file mode 100644
index 0..7d1420ce5fdb6
--- /dev/null
+++ b/clang/test/CodeGenCXX/fake-use-musttail.cpp
@@ -0,0 +1,72 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py
UTC_ARGS: --version 5
+// RUN: %clang_cc1 -emit-llvm -fextend-variable-liveness -o - %s | FileCheck %s
+
+/// Tests that when we have fake uses in a function ending in a musttail call,
+/// we emit the fake uses and their corresponding loads immediately prior to
the
+/// tail call.
+
+struct Class1 {
+ Class1(int);
+};
+
+class Class2 {
+ static const char *foo(int *, const char *, int *, Class1, const int *,
+ unsigned long);
+ template
+ static char *bar(int *, const char *, int *, Class1, const int *, unsigned
long);
+};
+
+// CHECK-LABEL: define dso_local noundef ptr
@_ZN6Class23fooEPiPKcS0_6Class1PKim(
+// CHECK-SAME: ptr noundef [[E:%.*]], ptr noundef [[F:%.*]], ptr noundef
[[G:%.*]], ptr noundef [[H:%.*]], i64 noundef [[I:%.*]]) #[[ATTR0:[0-9]+]]
align 2 {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT:[[TMP0:%.*]] = alloca [[STRUCT_CLASS1:%.*]], align 1
+// CHECK-NEXT:[[E_ADDR:%.*]] = alloca ptr, align 8
+// CHECK-NEXT:[[F_ADDR:%.*]] = alloca ptr, align 8
+// CHECK-NEXT:[[G_ADDR:%.*]] = alloca ptr, align 8
+// CHECK-NEXT:[[H_ADDR:%.*]] = alloca ptr, align 8
+// CHECK-NEXT:[[I_ADDR:%.*]] = alloca i64, align 8
+// CHECK-NEXT:[[AGG_TMP:%.*]] = alloca [[STRUCT_CLASS1]], align 1
+// CHECK-NEXT:store ptr [[E]], ptr [[E_ADDR]], align 8
+// CHECK-NEXT:store ptr [[F]], ptr [[F_ADDR]], align 8
+// CHECK-NEXT:store ptr [[G]], ptr [[G_ADDR]], align 8
+// CHECK-NEXT:store ptr [[H]], ptr [[H_ADDR]], align 8
+// CHECK-NEXT:store i64 [[I]], ptr [[I_ADDR]], align 8
+// CHECK-NEXT:[[TMP1:%.*]] = load ptr, ptr [[E_ADDR]], align 8
+// CHECK-NEXT:[[TMP2:%.*]] = load ptr, ptr [[F_ADDR]], align 8
+// CHECK-NEXT:[[TMP3:%.*]] = load ptr, ptr [[G_ADDR]], align 8
+// CHECK-NEXT:call void @_ZN6Class1C1Ei(ptr noundef nonnull align 1
dereferenceable(1) [[AGG_TMP]], i32 noundef 0)
+// CHECK-NEXT:[[TMP4:%.*]] = load ptr, ptr [[H_ADDR]], align 8
+// CHECK-NEXT:[[TMP5:%.*]] = load i64, ptr [[I_ADDR]], align 8
+// CHECK-NEXT:[[FAKE_USE:%.*]] = load i64, ptr [[I_ADDR]], align 8
+// CHECK-NEXT:notail call void (...) @llvm.fake.use(i64 [[FAKE_USE]])
#[[ATTR3:[0-9]+]]
+// CHECK-NEXT:[[FAKE_USE1:%.*]] = load ptr, ptr [[H_ADDR]], align
[clang] [Clang][CodeGen] Emit fake uses before musttail calls (PR #136867)
https://github.com/SLTozer updated
https://github.com/llvm/llvm-project/pull/136867
>From 90c09c8326077a1ba6797519bbefd014f32b5beb Mon Sep 17 00:00:00 2001
From: Stephen Tozer
Date: Wed, 23 Apr 2025 14:24:50 +0100
Subject: [PATCH 1/4] [Clang] Emit Fake Uses before musttail calls
Fixes the issue reported following the merge of #118026.
When a valid `musttail` call is made, the function it is made from must
return immediately after the call; if there are any cleanups left in the
function, then an error is triggered. This is not necessary for fake uses
however - it is perfectly valid to simply emit the fake use "cleanup" code
before the tail call, and indeed LLVM will automatically move any fake uses
following a tail call to come before the tail call.
Therefore, this patch specifically choose to handle fake use cleanups when
a musttail call is present by simply emitting them immediately before the
call.
---
clang/lib/CodeGen/CGCall.cpp| 12 +++-
clang/test/CodeGenCXX/fake-use-musttail.cpp | 72 +
2 files changed, 83 insertions(+), 1 deletion(-)
create mode 100644 clang/test/CodeGenCXX/fake-use-musttail.cpp
diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp
index 8cb27420dd911..c8cddfc06fce7 100644
--- a/clang/lib/CodeGen/CGCall.cpp
+++ b/clang/lib/CodeGen/CGCall.cpp
@@ -6001,8 +6001,18 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo
&CallInfo,
for (auto it = EHStack.find(CurrentCleanupScopeDepth); it != EHStack.end();
++it) {
EHCleanupScope *Cleanup = dyn_cast(&*it);
- if (!(Cleanup && Cleanup->getCleanup()->isRedundantBeforeReturn()))
+ // Fake uses can be safely emitted immediately prior to the tail call; we
+ // choose to emit the fake use before the call rather than after, to
avoid
+ // forcing variable values from every call on the "stack" to be preserved
+ // simultaneously.
+ if (Cleanup && Cleanup->isFakeUse()) {
+CGBuilderTy::InsertPointGuard IPG(Builder);
+Builder.SetInsertPoint(CI);
+Cleanup->getCleanup()->Emit(*this, EHScopeStack::Cleanup::Flags());
+ } else if (!(Cleanup &&
+ Cleanup->getCleanup()->isRedundantBeforeReturn())) {
CGM.ErrorUnsupported(MustTailCall, "tail call skipping over cleanups");
+ }
}
if (CI->getType()->isVoidTy())
Builder.CreateRetVoid();
diff --git a/clang/test/CodeGenCXX/fake-use-musttail.cpp
b/clang/test/CodeGenCXX/fake-use-musttail.cpp
new file mode 100644
index 0..7d1420ce5fdb6
--- /dev/null
+++ b/clang/test/CodeGenCXX/fake-use-musttail.cpp
@@ -0,0 +1,72 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py
UTC_ARGS: --version 5
+// RUN: %clang_cc1 -emit-llvm -fextend-variable-liveness -o - %s | FileCheck %s
+
+/// Tests that when we have fake uses in a function ending in a musttail call,
+/// we emit the fake uses and their corresponding loads immediately prior to
the
+/// tail call.
+
+struct Class1 {
+ Class1(int);
+};
+
+class Class2 {
+ static const char *foo(int *, const char *, int *, Class1, const int *,
+ unsigned long);
+ template
+ static char *bar(int *, const char *, int *, Class1, const int *, unsigned
long);
+};
+
+// CHECK-LABEL: define dso_local noundef ptr
@_ZN6Class23fooEPiPKcS0_6Class1PKim(
+// CHECK-SAME: ptr noundef [[E:%.*]], ptr noundef [[F:%.*]], ptr noundef
[[G:%.*]], ptr noundef [[H:%.*]], i64 noundef [[I:%.*]]) #[[ATTR0:[0-9]+]]
align 2 {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT:[[TMP0:%.*]] = alloca [[STRUCT_CLASS1:%.*]], align 1
+// CHECK-NEXT:[[E_ADDR:%.*]] = alloca ptr, align 8
+// CHECK-NEXT:[[F_ADDR:%.*]] = alloca ptr, align 8
+// CHECK-NEXT:[[G_ADDR:%.*]] = alloca ptr, align 8
+// CHECK-NEXT:[[H_ADDR:%.*]] = alloca ptr, align 8
+// CHECK-NEXT:[[I_ADDR:%.*]] = alloca i64, align 8
+// CHECK-NEXT:[[AGG_TMP:%.*]] = alloca [[STRUCT_CLASS1]], align 1
+// CHECK-NEXT:store ptr [[E]], ptr [[E_ADDR]], align 8
+// CHECK-NEXT:store ptr [[F]], ptr [[F_ADDR]], align 8
+// CHECK-NEXT:store ptr [[G]], ptr [[G_ADDR]], align 8
+// CHECK-NEXT:store ptr [[H]], ptr [[H_ADDR]], align 8
+// CHECK-NEXT:store i64 [[I]], ptr [[I_ADDR]], align 8
+// CHECK-NEXT:[[TMP1:%.*]] = load ptr, ptr [[E_ADDR]], align 8
+// CHECK-NEXT:[[TMP2:%.*]] = load ptr, ptr [[F_ADDR]], align 8
+// CHECK-NEXT:[[TMP3:%.*]] = load ptr, ptr [[G_ADDR]], align 8
+// CHECK-NEXT:call void @_ZN6Class1C1Ei(ptr noundef nonnull align 1
dereferenceable(1) [[AGG_TMP]], i32 noundef 0)
+// CHECK-NEXT:[[TMP4:%.*]] = load ptr, ptr [[H_ADDR]], align 8
+// CHECK-NEXT:[[TMP5:%.*]] = load i64, ptr [[I_ADDR]], align 8
+// CHECK-NEXT:[[FAKE_USE:%.*]] = load i64, ptr [[I_ADDR]], align 8
+// CHECK-NEXT:notail call void (...) @llvm.fake.use(i64 [[FAKE_USE]])
#[[ATTR3:[0-9]+]]
+// CHECK-NEXT:[[FAKE_USE1:%.*]] = load ptr, ptr [[H_ADDR]], align
[clang] [Clang][CodeGen] Emit fake uses before musttail calls (PR #136867)
https://github.com/rjmccall edited https://github.com/llvm/llvm-project/pull/136867 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang][CodeGen] Emit fake uses before musttail calls (PR #136867)
@@ -6001,8 +6001,18 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo
&CallInfo,
for (auto it = EHStack.find(CurrentCleanupScopeDepth); it != EHStack.end();
++it) {
EHCleanupScope *Cleanup = dyn_cast(&*it);
- if (!(Cleanup && Cleanup->getCleanup()->isRedundantBeforeReturn()))
+ // Fake uses can be safely emitted immediately prior to the tail call; we
+ // choose to emit the fake use before the call rather than after, to
avoid
+ // forcing variable values from every call on the "stack" to be preserved
+ // simultaneously.
rjmccall wrote:
The second half of this comment is odd. There isn't really a choice about this;
the fake uses must be emitted prior to the tail call because there cannot be
anything after it.
https://github.com/llvm/llvm-project/pull/136867
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang][CodeGen] Emit fake uses before musttail calls (PR #136867)
https://github.com/rjmccall commented: Functionality seems fine. A couple minor requests, then LGTM. https://github.com/llvm/llvm-project/pull/136867 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang][CodeGen] Emit fake uses before musttail calls (PR #136867)
@@ -0,0 +1,56 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py
UTC_ARGS: --version 5
+// RUN: %clang_cc1 -emit-llvm -fextend-variable-liveness -o - %s | FileCheck %s
+
+/// Tests that when we have fake uses in a function ending in a musttail call,
+/// we emit the fake uses and their corresponding loads immediately prior to
the
+/// tail call.
+
+extern "C" char *bar(int *, const char *, int *, const int *, unsigned long);
+
+// CHECK-LABEL: define dso_local ptr @foo(
+// CHECK-SAME: ptr noundef [[E:%.*]], ptr noundef [[F:%.*]], ptr noundef
[[G:%.*]], ptr noundef [[H:%.*]], i64 noundef [[I:%.*]]) #[[ATTR0:[0-9]+]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT:[[E_ADDR:%.*]] = alloca ptr, align 8
+// CHECK-NEXT:[[F_ADDR:%.*]] = alloca ptr, align 8
+// CHECK-NEXT:[[G_ADDR:%.*]] = alloca ptr, align 8
+// CHECK-NEXT:[[H_ADDR:%.*]] = alloca ptr, align 8
+// CHECK-NEXT:[[I_ADDR:%.*]] = alloca i64, align 8
+// CHECK-NEXT:store ptr [[E]], ptr [[E_ADDR]], align 8
+// CHECK-NEXT:store ptr [[F]], ptr [[F_ADDR]], align 8
+// CHECK-NEXT:store ptr [[G]], ptr [[G_ADDR]], align 8
+// CHECK-NEXT:store ptr [[H]], ptr [[H_ADDR]], align 8
+// CHECK-NEXT:store i64 [[I]], ptr [[I_ADDR]], align 8
+// CHECK-NEXT:[[TMP0:%.*]] = load ptr, ptr [[E_ADDR]], align 8
+// CHECK-NEXT:[[TMP1:%.*]] = load ptr, ptr [[F_ADDR]], align 8
+// CHECK-NEXT:[[TMP2:%.*]] = load ptr, ptr [[G_ADDR]], align 8
+// CHECK-NEXT:[[TMP3:%.*]] = load ptr, ptr [[H_ADDR]], align 8
+// CHECK-NEXT:[[TMP4:%.*]] = load i64, ptr [[I_ADDR]], align 8
+// CHECK-NEXT:[[FAKE_USE:%.*]] = load i64, ptr [[I_ADDR]], align 8
+// CHECK-NEXT:notail call void (...) @llvm.fake.use(i64 [[FAKE_USE]])
#[[ATTR3:[0-9]+]]
rjmccall wrote:
If you're not testing the attributes, you can just leave this off; matches
don't have to match the entire line.
https://github.com/llvm/llvm-project/pull/136867
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang][CodeGen] Emit fake uses before musttail calls (PR #136867)
gulfemsavrun wrote: Is there anything that is blocking this PR to be merged? If it needs more time to review, could you please revert the original change and reland with this fix? This is blocking us to roll Clang in our project. https://github.com/llvm/llvm-project/pull/136867 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang][CodeGen] Emit fake uses before musttail calls (PR #136867)
https://github.com/SLTozer updated
https://github.com/llvm/llvm-project/pull/136867
>From 90c09c8326077a1ba6797519bbefd014f32b5beb Mon Sep 17 00:00:00 2001
From: Stephen Tozer
Date: Wed, 23 Apr 2025 14:24:50 +0100
Subject: [PATCH 1/3] [Clang] Emit Fake Uses before musttail calls
Fixes the issue reported following the merge of #118026.
When a valid `musttail` call is made, the function it is made from must
return immediately after the call; if there are any cleanups left in the
function, then an error is triggered. This is not necessary for fake uses
however - it is perfectly valid to simply emit the fake use "cleanup" code
before the tail call, and indeed LLVM will automatically move any fake uses
following a tail call to come before the tail call.
Therefore, this patch specifically choose to handle fake use cleanups when
a musttail call is present by simply emitting them immediately before the
call.
---
clang/lib/CodeGen/CGCall.cpp| 12 +++-
clang/test/CodeGenCXX/fake-use-musttail.cpp | 72 +
2 files changed, 83 insertions(+), 1 deletion(-)
create mode 100644 clang/test/CodeGenCXX/fake-use-musttail.cpp
diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp
index 8cb27420dd911..c8cddfc06fce7 100644
--- a/clang/lib/CodeGen/CGCall.cpp
+++ b/clang/lib/CodeGen/CGCall.cpp
@@ -6001,8 +6001,18 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo
&CallInfo,
for (auto it = EHStack.find(CurrentCleanupScopeDepth); it != EHStack.end();
++it) {
EHCleanupScope *Cleanup = dyn_cast(&*it);
- if (!(Cleanup && Cleanup->getCleanup()->isRedundantBeforeReturn()))
+ // Fake uses can be safely emitted immediately prior to the tail call; we
+ // choose to emit the fake use before the call rather than after, to
avoid
+ // forcing variable values from every call on the "stack" to be preserved
+ // simultaneously.
+ if (Cleanup && Cleanup->isFakeUse()) {
+CGBuilderTy::InsertPointGuard IPG(Builder);
+Builder.SetInsertPoint(CI);
+Cleanup->getCleanup()->Emit(*this, EHScopeStack::Cleanup::Flags());
+ } else if (!(Cleanup &&
+ Cleanup->getCleanup()->isRedundantBeforeReturn())) {
CGM.ErrorUnsupported(MustTailCall, "tail call skipping over cleanups");
+ }
}
if (CI->getType()->isVoidTy())
Builder.CreateRetVoid();
diff --git a/clang/test/CodeGenCXX/fake-use-musttail.cpp
b/clang/test/CodeGenCXX/fake-use-musttail.cpp
new file mode 100644
index 0..7d1420ce5fdb6
--- /dev/null
+++ b/clang/test/CodeGenCXX/fake-use-musttail.cpp
@@ -0,0 +1,72 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py
UTC_ARGS: --version 5
+// RUN: %clang_cc1 -emit-llvm -fextend-variable-liveness -o - %s | FileCheck %s
+
+/// Tests that when we have fake uses in a function ending in a musttail call,
+/// we emit the fake uses and their corresponding loads immediately prior to
the
+/// tail call.
+
+struct Class1 {
+ Class1(int);
+};
+
+class Class2 {
+ static const char *foo(int *, const char *, int *, Class1, const int *,
+ unsigned long);
+ template
+ static char *bar(int *, const char *, int *, Class1, const int *, unsigned
long);
+};
+
+// CHECK-LABEL: define dso_local noundef ptr
@_ZN6Class23fooEPiPKcS0_6Class1PKim(
+// CHECK-SAME: ptr noundef [[E:%.*]], ptr noundef [[F:%.*]], ptr noundef
[[G:%.*]], ptr noundef [[H:%.*]], i64 noundef [[I:%.*]]) #[[ATTR0:[0-9]+]]
align 2 {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT:[[TMP0:%.*]] = alloca [[STRUCT_CLASS1:%.*]], align 1
+// CHECK-NEXT:[[E_ADDR:%.*]] = alloca ptr, align 8
+// CHECK-NEXT:[[F_ADDR:%.*]] = alloca ptr, align 8
+// CHECK-NEXT:[[G_ADDR:%.*]] = alloca ptr, align 8
+// CHECK-NEXT:[[H_ADDR:%.*]] = alloca ptr, align 8
+// CHECK-NEXT:[[I_ADDR:%.*]] = alloca i64, align 8
+// CHECK-NEXT:[[AGG_TMP:%.*]] = alloca [[STRUCT_CLASS1]], align 1
+// CHECK-NEXT:store ptr [[E]], ptr [[E_ADDR]], align 8
+// CHECK-NEXT:store ptr [[F]], ptr [[F_ADDR]], align 8
+// CHECK-NEXT:store ptr [[G]], ptr [[G_ADDR]], align 8
+// CHECK-NEXT:store ptr [[H]], ptr [[H_ADDR]], align 8
+// CHECK-NEXT:store i64 [[I]], ptr [[I_ADDR]], align 8
+// CHECK-NEXT:[[TMP1:%.*]] = load ptr, ptr [[E_ADDR]], align 8
+// CHECK-NEXT:[[TMP2:%.*]] = load ptr, ptr [[F_ADDR]], align 8
+// CHECK-NEXT:[[TMP3:%.*]] = load ptr, ptr [[G_ADDR]], align 8
+// CHECK-NEXT:call void @_ZN6Class1C1Ei(ptr noundef nonnull align 1
dereferenceable(1) [[AGG_TMP]], i32 noundef 0)
+// CHECK-NEXT:[[TMP4:%.*]] = load ptr, ptr [[H_ADDR]], align 8
+// CHECK-NEXT:[[TMP5:%.*]] = load i64, ptr [[I_ADDR]], align 8
+// CHECK-NEXT:[[FAKE_USE:%.*]] = load i64, ptr [[I_ADDR]], align 8
+// CHECK-NEXT:notail call void (...) @llvm.fake.use(i64 [[FAKE_USE]])
#[[ATTR3:[0-9]+]]
+// CHECK-NEXT:[[FAKE_USE1:%.*]] = load ptr, ptr [[H_ADDR]], align
[clang] [Clang][CodeGen] Emit fake uses before musttail calls (PR #136867)
https://github.com/SLTozer updated
https://github.com/llvm/llvm-project/pull/136867
>From 90c09c8326077a1ba6797519bbefd014f32b5beb Mon Sep 17 00:00:00 2001
From: Stephen Tozer
Date: Wed, 23 Apr 2025 14:24:50 +0100
Subject: [PATCH 1/2] [Clang] Emit Fake Uses before musttail calls
Fixes the issue reported following the merge of #118026.
When a valid `musttail` call is made, the function it is made from must
return immediately after the call; if there are any cleanups left in the
function, then an error is triggered. This is not necessary for fake uses
however - it is perfectly valid to simply emit the fake use "cleanup" code
before the tail call, and indeed LLVM will automatically move any fake uses
following a tail call to come before the tail call.
Therefore, this patch specifically choose to handle fake use cleanups when
a musttail call is present by simply emitting them immediately before the
call.
---
clang/lib/CodeGen/CGCall.cpp| 12 +++-
clang/test/CodeGenCXX/fake-use-musttail.cpp | 72 +
2 files changed, 83 insertions(+), 1 deletion(-)
create mode 100644 clang/test/CodeGenCXX/fake-use-musttail.cpp
diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp
index 8cb27420dd911..c8cddfc06fce7 100644
--- a/clang/lib/CodeGen/CGCall.cpp
+++ b/clang/lib/CodeGen/CGCall.cpp
@@ -6001,8 +6001,18 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo
&CallInfo,
for (auto it = EHStack.find(CurrentCleanupScopeDepth); it != EHStack.end();
++it) {
EHCleanupScope *Cleanup = dyn_cast(&*it);
- if (!(Cleanup && Cleanup->getCleanup()->isRedundantBeforeReturn()))
+ // Fake uses can be safely emitted immediately prior to the tail call; we
+ // choose to emit the fake use before the call rather than after, to
avoid
+ // forcing variable values from every call on the "stack" to be preserved
+ // simultaneously.
+ if (Cleanup && Cleanup->isFakeUse()) {
+CGBuilderTy::InsertPointGuard IPG(Builder);
+Builder.SetInsertPoint(CI);
+Cleanup->getCleanup()->Emit(*this, EHScopeStack::Cleanup::Flags());
+ } else if (!(Cleanup &&
+ Cleanup->getCleanup()->isRedundantBeforeReturn())) {
CGM.ErrorUnsupported(MustTailCall, "tail call skipping over cleanups");
+ }
}
if (CI->getType()->isVoidTy())
Builder.CreateRetVoid();
diff --git a/clang/test/CodeGenCXX/fake-use-musttail.cpp
b/clang/test/CodeGenCXX/fake-use-musttail.cpp
new file mode 100644
index 0..7d1420ce5fdb6
--- /dev/null
+++ b/clang/test/CodeGenCXX/fake-use-musttail.cpp
@@ -0,0 +1,72 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py
UTC_ARGS: --version 5
+// RUN: %clang_cc1 -emit-llvm -fextend-variable-liveness -o - %s | FileCheck %s
+
+/// Tests that when we have fake uses in a function ending in a musttail call,
+/// we emit the fake uses and their corresponding loads immediately prior to
the
+/// tail call.
+
+struct Class1 {
+ Class1(int);
+};
+
+class Class2 {
+ static const char *foo(int *, const char *, int *, Class1, const int *,
+ unsigned long);
+ template
+ static char *bar(int *, const char *, int *, Class1, const int *, unsigned
long);
+};
+
+// CHECK-LABEL: define dso_local noundef ptr
@_ZN6Class23fooEPiPKcS0_6Class1PKim(
+// CHECK-SAME: ptr noundef [[E:%.*]], ptr noundef [[F:%.*]], ptr noundef
[[G:%.*]], ptr noundef [[H:%.*]], i64 noundef [[I:%.*]]) #[[ATTR0:[0-9]+]]
align 2 {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT:[[TMP0:%.*]] = alloca [[STRUCT_CLASS1:%.*]], align 1
+// CHECK-NEXT:[[E_ADDR:%.*]] = alloca ptr, align 8
+// CHECK-NEXT:[[F_ADDR:%.*]] = alloca ptr, align 8
+// CHECK-NEXT:[[G_ADDR:%.*]] = alloca ptr, align 8
+// CHECK-NEXT:[[H_ADDR:%.*]] = alloca ptr, align 8
+// CHECK-NEXT:[[I_ADDR:%.*]] = alloca i64, align 8
+// CHECK-NEXT:[[AGG_TMP:%.*]] = alloca [[STRUCT_CLASS1]], align 1
+// CHECK-NEXT:store ptr [[E]], ptr [[E_ADDR]], align 8
+// CHECK-NEXT:store ptr [[F]], ptr [[F_ADDR]], align 8
+// CHECK-NEXT:store ptr [[G]], ptr [[G_ADDR]], align 8
+// CHECK-NEXT:store ptr [[H]], ptr [[H_ADDR]], align 8
+// CHECK-NEXT:store i64 [[I]], ptr [[I_ADDR]], align 8
+// CHECK-NEXT:[[TMP1:%.*]] = load ptr, ptr [[E_ADDR]], align 8
+// CHECK-NEXT:[[TMP2:%.*]] = load ptr, ptr [[F_ADDR]], align 8
+// CHECK-NEXT:[[TMP3:%.*]] = load ptr, ptr [[G_ADDR]], align 8
+// CHECK-NEXT:call void @_ZN6Class1C1Ei(ptr noundef nonnull align 1
dereferenceable(1) [[AGG_TMP]], i32 noundef 0)
+// CHECK-NEXT:[[TMP4:%.*]] = load ptr, ptr [[H_ADDR]], align 8
+// CHECK-NEXT:[[TMP5:%.*]] = load i64, ptr [[I_ADDR]], align 8
+// CHECK-NEXT:[[FAKE_USE:%.*]] = load i64, ptr [[I_ADDR]], align 8
+// CHECK-NEXT:notail call void (...) @llvm.fake.use(i64 [[FAKE_USE]])
#[[ATTR3:[0-9]+]]
+// CHECK-NEXT:[[FAKE_USE1:%.*]] = load ptr, ptr [[H_ADDR]], align
[clang] [Clang][CodeGen] Emit fake uses before musttail calls (PR #136867)
wolfy1961 wrote: LGTM https://github.com/llvm/llvm-project/pull/136867 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang][CodeGen] Emit fake uses before musttail calls (PR #136867)
gulfemsavrun wrote: Thanks for the fix, and I verified that it resolves the issue that I reported in https://github.com/llvm/llvm-project/pull/118026#issuecomment-2822881489. https://github.com/llvm/llvm-project/pull/136867 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
