[clang] [Clang][CodeGen] Emit fake uses before musttail calls (PR #136867)
Stephen Tozer via cfe-commits
cfe-commits at lists.llvm.org
Fri Apr 25 02:50:51 PDT 2025
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 <stephen.tozer at sony.com>
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<EHCleanupScope>(&*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 0000000000000..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 <class>
+ 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 8
+// CHECK-NEXT: notail call void (...) @llvm.fake.use(ptr [[FAKE_USE1]]) #[[ATTR3]]
+// CHECK-NEXT: [[FAKE_USE2:%.*]] = load [[STRUCT_CLASS1]], ptr [[TMP0]], align 1
+// CHECK-NEXT: notail call void (...) @llvm.fake.use([[STRUCT_CLASS1]] [[FAKE_USE2]]) #[[ATTR3]]
+// CHECK-NEXT: [[FAKE_USE3:%.*]] = load ptr, ptr [[G_ADDR]], align 8
+// CHECK-NEXT: notail call void (...) @llvm.fake.use(ptr [[FAKE_USE3]]) #[[ATTR3]]
+// CHECK-NEXT: [[FAKE_USE4:%.*]] = load ptr, ptr [[F_ADDR]], align 8
+// CHECK-NEXT: notail call void (...) @llvm.fake.use(ptr [[FAKE_USE4]]) #[[ATTR3]]
+// CHECK-NEXT: [[FAKE_USE5:%.*]] = load ptr, ptr [[E_ADDR]], align 8
+// CHECK-NEXT: notail call void (...) @llvm.fake.use(ptr [[FAKE_USE5]]) #[[ATTR3]]
+// CHECK-NEXT: [[CALL:%.*]] = musttail call noundef ptr @_ZN6Class23barIiEEPcPiPKcS2_6Class1PKim(ptr noundef [[TMP1]], ptr noundef [[TMP2]], ptr noundef [[TMP3]], ptr noundef [[TMP4]], i64 noundef [[TMP5]])
+// CHECK-NEXT: ret ptr [[CALL]]
+// CHECK: [[BB6:.*:]]
+// CHECK-NEXT: [[FAKE_USE6:%.*]] = load i64, ptr [[I_ADDR]], align 8
+// CHECK-NEXT: notail call void (...) @llvm.fake.use(i64 [[FAKE_USE6]]) #[[ATTR3]]
+// CHECK-NEXT: [[FAKE_USE7:%.*]] = load ptr, ptr [[H_ADDR]], align 8
+// CHECK-NEXT: notail call void (...) @llvm.fake.use(ptr [[FAKE_USE7]]) #[[ATTR3]]
+// CHECK-NEXT: [[FAKE_USE8:%.*]] = load [[STRUCT_CLASS1]], ptr [[TMP0]], align 1
+// CHECK-NEXT: notail call void (...) @llvm.fake.use([[STRUCT_CLASS1]] [[FAKE_USE8]]) #[[ATTR3]]
+// CHECK-NEXT: [[FAKE_USE9:%.*]] = load ptr, ptr [[G_ADDR]], align 8
+// CHECK-NEXT: notail call void (...) @llvm.fake.use(ptr [[FAKE_USE9]]) #[[ATTR3]]
+// CHECK-NEXT: [[FAKE_USE10:%.*]] = load ptr, ptr [[F_ADDR]], align 8
+// CHECK-NEXT: notail call void (...) @llvm.fake.use(ptr [[FAKE_USE10]]) #[[ATTR3]]
+// CHECK-NEXT: [[FAKE_USE11:%.*]] = load ptr, ptr [[E_ADDR]], align 8
+// CHECK-NEXT: notail call void (...) @llvm.fake.use(ptr [[FAKE_USE11]]) #[[ATTR3]]
+// CHECK-NEXT: ret ptr undef
+//
+const char *Class2::foo(int *e, const char *f, int *g, Class1, const int *h,
+ unsigned long i) {
+ [[clang::musttail]] return bar<int>(e, f, g, int(), h, i);
+}
>From 2765fb7d11c1ac294301baba20ef5f44d641be17 Mon Sep 17 00:00:00 2001
From: Stephen Tozer <stephen.tozer at sony.com>
Date: Thu, 24 Apr 2025 11:27:03 +0100
Subject: [PATCH 2/5] Simplify test
---
clang/test/CodeGenCXX/fake-use-musttail.cpp | 65 ++++++++-------------
1 file changed, 25 insertions(+), 40 deletions(-)
diff --git a/clang/test/CodeGenCXX/fake-use-musttail.cpp b/clang/test/CodeGenCXX/fake-use-musttail.cpp
index 7d1420ce5fdb6..c0dacca8eab18 100644
--- a/clang/test/CodeGenCXX/fake-use-musttail.cpp
+++ b/clang/test/CodeGenCXX/fake-use-musttail.cpp
@@ -5,68 +5,53 @@
/// we emit the fake uses and their corresponding loads immediately prior to the
/// tail call.
-struct Class1 {
- Class1(int);
-};
+template <class>
+char *bar(int *, const char *, int *, const int *, unsigned long);
-class Class2 {
- static const char *foo(int *, const char *, int *, Class1, const int *,
- unsigned long);
- template <class>
- 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-LABEL: define dso_local noundef ptr @_Z3fooPiPKcS_PKim(
+// 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: [[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: [[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]+]]
// CHECK-NEXT: [[FAKE_USE1:%.*]] = load ptr, ptr [[H_ADDR]], align 8
// CHECK-NEXT: notail call void (...) @llvm.fake.use(ptr [[FAKE_USE1]]) #[[ATTR3]]
-// CHECK-NEXT: [[FAKE_USE2:%.*]] = load [[STRUCT_CLASS1]], ptr [[TMP0]], align 1
-// CHECK-NEXT: notail call void (...) @llvm.fake.use([[STRUCT_CLASS1]] [[FAKE_USE2]]) #[[ATTR3]]
-// CHECK-NEXT: [[FAKE_USE3:%.*]] = load ptr, ptr [[G_ADDR]], align 8
+// CHECK-NEXT: [[FAKE_USE2:%.*]] = load ptr, ptr [[G_ADDR]], align 8
+// CHECK-NEXT: notail call void (...) @llvm.fake.use(ptr [[FAKE_USE2]]) #[[ATTR3]]
+// CHECK-NEXT: [[FAKE_USE3:%.*]] = load ptr, ptr [[F_ADDR]], align 8
// CHECK-NEXT: notail call void (...) @llvm.fake.use(ptr [[FAKE_USE3]]) #[[ATTR3]]
-// CHECK-NEXT: [[FAKE_USE4:%.*]] = load ptr, ptr [[F_ADDR]], align 8
+// CHECK-NEXT: [[FAKE_USE4:%.*]] = load ptr, ptr [[E_ADDR]], align 8
// CHECK-NEXT: notail call void (...) @llvm.fake.use(ptr [[FAKE_USE4]]) #[[ATTR3]]
-// CHECK-NEXT: [[FAKE_USE5:%.*]] = load ptr, ptr [[E_ADDR]], align 8
-// CHECK-NEXT: notail call void (...) @llvm.fake.use(ptr [[FAKE_USE5]]) #[[ATTR3]]
-// CHECK-NEXT: [[CALL:%.*]] = musttail call noundef ptr @_ZN6Class23barIiEEPcPiPKcS2_6Class1PKim(ptr noundef [[TMP1]], ptr noundef [[TMP2]], ptr noundef [[TMP3]], ptr noundef [[TMP4]], i64 noundef [[TMP5]])
+// CHECK-NEXT: [[CALL:%.*]] = musttail call noundef ptr @_Z3barIiEPcPiPKcS1_PKim(ptr noundef [[TMP0]], ptr noundef [[TMP1]], ptr noundef [[TMP2]], ptr noundef [[TMP3]], i64 noundef [[TMP4]])
// CHECK-NEXT: ret ptr [[CALL]]
-// CHECK: [[BB6:.*:]]
-// CHECK-NEXT: [[FAKE_USE6:%.*]] = load i64, ptr [[I_ADDR]], align 8
-// CHECK-NEXT: notail call void (...) @llvm.fake.use(i64 [[FAKE_USE6]]) #[[ATTR3]]
-// CHECK-NEXT: [[FAKE_USE7:%.*]] = load ptr, ptr [[H_ADDR]], align 8
+// CHECK: [[BB5:.*:]]
+// CHECK-NEXT: [[FAKE_USE5:%.*]] = load i64, ptr [[I_ADDR]], align 8
+// CHECK-NEXT: notail call void (...) @llvm.fake.use(i64 [[FAKE_USE5]]) #[[ATTR3]]
+// CHECK-NEXT: [[FAKE_USE6:%.*]] = load ptr, ptr [[H_ADDR]], align 8
+// CHECK-NEXT: notail call void (...) @llvm.fake.use(ptr [[FAKE_USE6]]) #[[ATTR3]]
+// CHECK-NEXT: [[FAKE_USE7:%.*]] = load ptr, ptr [[G_ADDR]], align 8
// CHECK-NEXT: notail call void (...) @llvm.fake.use(ptr [[FAKE_USE7]]) #[[ATTR3]]
-// CHECK-NEXT: [[FAKE_USE8:%.*]] = load [[STRUCT_CLASS1]], ptr [[TMP0]], align 1
-// CHECK-NEXT: notail call void (...) @llvm.fake.use([[STRUCT_CLASS1]] [[FAKE_USE8]]) #[[ATTR3]]
-// CHECK-NEXT: [[FAKE_USE9:%.*]] = load ptr, ptr [[G_ADDR]], align 8
+// CHECK-NEXT: [[FAKE_USE8:%.*]] = load ptr, ptr [[F_ADDR]], align 8
+// CHECK-NEXT: notail call void (...) @llvm.fake.use(ptr [[FAKE_USE8]]) #[[ATTR3]]
+// CHECK-NEXT: [[FAKE_USE9:%.*]] = load ptr, ptr [[E_ADDR]], align 8
// CHECK-NEXT: notail call void (...) @llvm.fake.use(ptr [[FAKE_USE9]]) #[[ATTR3]]
-// CHECK-NEXT: [[FAKE_USE10:%.*]] = load ptr, ptr [[F_ADDR]], align 8
-// CHECK-NEXT: notail call void (...) @llvm.fake.use(ptr [[FAKE_USE10]]) #[[ATTR3]]
-// CHECK-NEXT: [[FAKE_USE11:%.*]] = load ptr, ptr [[E_ADDR]], align 8
-// CHECK-NEXT: notail call void (...) @llvm.fake.use(ptr [[FAKE_USE11]]) #[[ATTR3]]
// CHECK-NEXT: ret ptr undef
//
-const char *Class2::foo(int *e, const char *f, int *g, Class1, const int *h,
+const char *foo(int *e, const char *f, int *g, const int *h,
unsigned long i) {
- [[clang::musttail]] return bar<int>(e, f, g, int(), h, i);
+ [[clang::musttail]] return bar<int>(e, f, g, h, i);
}
>From d0e4e68a2f4f16a721fa0b265f023e030b441bd5 Mon Sep 17 00:00:00 2001
From: Stephen Tozer <stephen.tozer at sony.com>
Date: Thu, 24 Apr 2025 12:55:09 +0100
Subject: [PATCH 3/5] Use extern C to prevent name mangling
---
clang/test/CodeGenCXX/fake-use-musttail.cpp | 11 +++++------
1 file changed, 5 insertions(+), 6 deletions(-)
diff --git a/clang/test/CodeGenCXX/fake-use-musttail.cpp b/clang/test/CodeGenCXX/fake-use-musttail.cpp
index c0dacca8eab18..d0ac8ca5bea90 100644
--- a/clang/test/CodeGenCXX/fake-use-musttail.cpp
+++ b/clang/test/CodeGenCXX/fake-use-musttail.cpp
@@ -5,10 +5,9 @@
/// we emit the fake uses and their corresponding loads immediately prior to the
/// tail call.
-template <class>
-char *bar(int *, const char *, int *, const int *, unsigned long);
+extern "C" char *bar(int *, const char *, int *, const int *, unsigned long);
-// CHECK-LABEL: define dso_local noundef ptr @_Z3fooPiPKcS_PKim(
+// 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
@@ -36,7 +35,7 @@ char *bar(int *, const char *, int *, const int *, unsigned long);
// CHECK-NEXT: notail call void (...) @llvm.fake.use(ptr [[FAKE_USE3]]) #[[ATTR3]]
// CHECK-NEXT: [[FAKE_USE4:%.*]] = load ptr, ptr [[E_ADDR]], align 8
// CHECK-NEXT: notail call void (...) @llvm.fake.use(ptr [[FAKE_USE4]]) #[[ATTR3]]
-// CHECK-NEXT: [[CALL:%.*]] = musttail call noundef ptr @_Z3barIiEPcPiPKcS1_PKim(ptr noundef [[TMP0]], ptr noundef [[TMP1]], ptr noundef [[TMP2]], ptr noundef [[TMP3]], i64 noundef [[TMP4]])
+// CHECK-NEXT: [[CALL:%.*]] = musttail call ptr @bar(ptr noundef [[TMP0]], ptr noundef [[TMP1]], ptr noundef [[TMP2]], ptr noundef [[TMP3]], i64 noundef [[TMP4]])
// CHECK-NEXT: ret ptr [[CALL]]
// CHECK: [[BB5:.*:]]
// CHECK-NEXT: [[FAKE_USE5:%.*]] = load i64, ptr [[I_ADDR]], align 8
@@ -51,7 +50,7 @@ char *bar(int *, const char *, int *, const int *, unsigned long);
// CHECK-NEXT: notail call void (...) @llvm.fake.use(ptr [[FAKE_USE9]]) #[[ATTR3]]
// CHECK-NEXT: ret ptr undef
//
-const char *foo(int *e, const char *f, int *g, const int *h,
+extern "C" const char *foo(int *e, const char *f, int *g, const int *h,
unsigned long i) {
- [[clang::musttail]] return bar<int>(e, f, g, h, i);
+ [[clang::musttail]] return bar(e, f, g, h, i);
}
>From c8c371f048a59d1f4eeda69cd628456b0db294e6 Mon Sep 17 00:00:00 2001
From: Stephen Tozer <stephen.tozer at sony.com>
Date: Fri, 25 Apr 2025 09:51:53 +0100
Subject: [PATCH 4/5] Reduce comment, further simplify test
---
clang/lib/CodeGen/CGCall.cpp | 6 +--
clang/test/CodeGenCXX/fake-use-musttail.cpp | 51 +++++----------------
2 files changed, 13 insertions(+), 44 deletions(-)
diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp
index c8cddfc06fce7..4dbc5c2f00971 100644
--- a/clang/lib/CodeGen/CGCall.cpp
+++ b/clang/lib/CodeGen/CGCall.cpp
@@ -6001,10 +6001,8 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
for (auto it = EHStack.find(CurrentCleanupScopeDepth); it != EHStack.end();
++it) {
EHCleanupScope *Cleanup = dyn_cast<EHCleanupScope>(&*it);
- // 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.
+ // Fake uses can be safely emitted immediately prior to the tail call, so
+ // we choose to emit them just before the call here.
if (Cleanup && Cleanup->isFakeUse()) {
CGBuilderTy::InsertPointGuard IPG(Builder);
Builder.SetInsertPoint(CI);
diff --git a/clang/test/CodeGenCXX/fake-use-musttail.cpp b/clang/test/CodeGenCXX/fake-use-musttail.cpp
index d0ac8ca5bea90..f73e45d8a92a4 100644
--- a/clang/test/CodeGenCXX/fake-use-musttail.cpp
+++ b/clang/test/CodeGenCXX/fake-use-musttail.cpp
@@ -1,56 +1,27 @@
-// 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);
+extern "C" char *bar(int *);
// 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-SAME: ptr noundef [[E:%.*]])
// 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]+]]
-// CHECK-NEXT: [[FAKE_USE1:%.*]] = load ptr, ptr [[H_ADDR]], align 8
-// CHECK-NEXT: notail call void (...) @llvm.fake.use(ptr [[FAKE_USE1]]) #[[ATTR3]]
-// CHECK-NEXT: [[FAKE_USE2:%.*]] = load ptr, ptr [[G_ADDR]], align 8
-// CHECK-NEXT: notail call void (...) @llvm.fake.use(ptr [[FAKE_USE2]]) #[[ATTR3]]
-// CHECK-NEXT: [[FAKE_USE3:%.*]] = load ptr, ptr [[F_ADDR]], align 8
-// CHECK-NEXT: notail call void (...) @llvm.fake.use(ptr [[FAKE_USE3]]) #[[ATTR3]]
-// CHECK-NEXT: [[FAKE_USE4:%.*]] = load ptr, ptr [[E_ADDR]], align 8
-// CHECK-NEXT: notail call void (...) @llvm.fake.use(ptr [[FAKE_USE4]]) #[[ATTR3]]
-// CHECK-NEXT: [[CALL:%.*]] = musttail call ptr @bar(ptr noundef [[TMP0]], ptr noundef [[TMP1]], ptr noundef [[TMP2]], ptr noundef [[TMP3]], i64 noundef [[TMP4]])
+// CHECK-NEXT: [[FAKE_USE:%.*]] = load ptr, ptr [[E_ADDR]]
+// CHECK-NEXT: notail call void (...) @llvm.fake.use(ptr [[FAKE_USE]])
+// CHECK-NEXT: [[CALL:%.*]] = musttail call ptr @bar(ptr noundef [[TMP0]])
// CHECK-NEXT: ret ptr [[CALL]]
-// CHECK: [[BB5:.*:]]
-// CHECK-NEXT: [[FAKE_USE5:%.*]] = load i64, ptr [[I_ADDR]], align 8
-// CHECK-NEXT: notail call void (...) @llvm.fake.use(i64 [[FAKE_USE5]]) #[[ATTR3]]
-// CHECK-NEXT: [[FAKE_USE6:%.*]] = load ptr, ptr [[H_ADDR]], align 8
-// CHECK-NEXT: notail call void (...) @llvm.fake.use(ptr [[FAKE_USE6]]) #[[ATTR3]]
-// CHECK-NEXT: [[FAKE_USE7:%.*]] = load ptr, ptr [[G_ADDR]], align 8
-// CHECK-NEXT: notail call void (...) @llvm.fake.use(ptr [[FAKE_USE7]]) #[[ATTR3]]
-// CHECK-NEXT: [[FAKE_USE8:%.*]] = load ptr, ptr [[F_ADDR]], align 8
-// CHECK-NEXT: notail call void (...) @llvm.fake.use(ptr [[FAKE_USE8]]) #[[ATTR3]]
-// CHECK-NEXT: [[FAKE_USE9:%.*]] = load ptr, ptr [[E_ADDR]], align 8
-// CHECK-NEXT: notail call void (...) @llvm.fake.use(ptr [[FAKE_USE9]]) #[[ATTR3]]
+
+// CHECK: [[BB1:.*:]]
+// CHECK-NEXT: [[FAKE_USE1:%.*]] = load ptr, ptr [[E_ADDR]]
+// CHECK-NEXT: notail call void (...) @llvm.fake.use(ptr [[FAKE_USE1]])
// CHECK-NEXT: ret ptr undef
//
-extern "C" const char *foo(int *e, const char *f, int *g, const int *h,
- unsigned long i) {
- [[clang::musttail]] return bar(e, f, g, h, i);
+extern "C" const char *foo(int *e) {
+ [[clang::musttail]] return bar(e);
}
>From bc98cd0a440e43bb6f7ca1bd93aafcd0044d1d1d Mon Sep 17 00:00:00 2001
From: Stephen Tozer <stephen.tozer at sony.com>
Date: Fri, 25 Apr 2025 10:50:34 +0100
Subject: [PATCH 5/5] Set explicit triple
---
clang/test/CodeGenCXX/fake-use-musttail.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang/test/CodeGenCXX/fake-use-musttail.cpp b/clang/test/CodeGenCXX/fake-use-musttail.cpp
index f73e45d8a92a4..9d341ab52f1c8 100644
--- a/clang/test/CodeGenCXX/fake-use-musttail.cpp
+++ b/clang/test/CodeGenCXX/fake-use-musttail.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -emit-llvm -fextend-variable-liveness -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -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
More information about the cfe-commits
mailing list