[clang] [Clang][CodeGen] Emit fake uses before musttail calls (PR #136867)

2025-04-25 Thread Stephen Tozer via cfe-commits

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)

2025-04-25 Thread Stephen Tozer via cfe-commits

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)

2025-04-25 Thread Stephen Tozer via cfe-commits

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)

2025-04-25 Thread John McCall via cfe-commits

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)

2025-04-25 Thread John McCall via cfe-commits


@@ -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)

2025-04-25 Thread John McCall via cfe-commits

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)

2025-04-25 Thread John McCall via cfe-commits


@@ -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)

2025-04-24 Thread via cfe-commits

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)

2025-04-24 Thread Stephen Tozer via cfe-commits

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)

2025-04-24 Thread Stephen Tozer via cfe-commits

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)

2025-04-23 Thread Wolfgang Pieb via cfe-commits

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)

2025-04-23 Thread via cfe-commits

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