Author: Stephen Tozer Date: 2025-04-25T11:47:38+01:00 New Revision: 2d00c73003a6c5e9fd468afcf271b505d4f80f27
URL: https://github.com/llvm/llvm-project/commit/2d00c73003a6c5e9fd468afcf271b505d4f80f27 DIFF: https://github.com/llvm/llvm-project/commit/2d00c73003a6c5e9fd468afcf271b505d4f80f27.diff LOG: [Clang][CodeGen] Emit fake uses before musttail calls (#136867) 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. Added: clang/test/CodeGenCXX/fake-use-musttail.cpp Modified: clang/lib/CodeGen/CGCall.cpp Removed: ################################################################################ diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp index 836f34e5b347d..c7fbbbc6fd40d 100644 --- a/clang/lib/CodeGen/CGCall.cpp +++ b/clang/lib/CodeGen/CGCall.cpp @@ -6001,8 +6001,16 @@ 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, so + // we choose to emit them just before the call here. + 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..9d341ab52f1c8 --- /dev/null +++ b/clang/test/CodeGenCXX/fake-use-musttail.cpp @@ -0,0 +1,27 @@ +// 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 +/// tail call. + +extern "C" char *bar(int *); + +// CHECK-LABEL: define dso_local ptr @foo( +// CHECK-SAME: ptr noundef [[E:%.*]]) +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[E_ADDR:%.*]] = alloca ptr, align 8 +// CHECK-NEXT: store ptr [[E]], ptr [[E_ADDR]], align 8 +// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[E_ADDR]], align 8 +// 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: [[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) { + [[clang::musttail]] return bar(e); +} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits