https://github.com/chfast created https://github.com/llvm/llvm-project/pull/191198
After a musttail call, the function epilog emitted a redundant return in a dead block. This happened because EnsureInsertPoint() created a new block after the musttail's ClearInsertionPoint(), and EmitFunctionEpilog then added a return to it. Remove EnsureInsertPoint() after the musttail return so the insert point stays cleared. Guard EmitFunctionEpilog and the return value store in EmitReturnStmt with HaveInsertPoint() checks. This is a reworked version of #134282, addressing review feedback. Fixes #104770. From 0d2642da9ca2218ca0af2545dc34b41271ac6c09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= <[email protected]> Date: Thu, 9 Apr 2026 08:49:37 +0200 Subject: [PATCH] [Clang] Remove unnecessary return block after musttail call After a musttail call, the function epilog emitted a redundant return in a dead block. This happened because EnsureInsertPoint() created a new block after the musttail's ClearInsertionPoint(), and EmitFunctionEpilog then added a return to it. Remove EnsureInsertPoint() after the musttail return so the insert point stays cleared. Guard EmitFunctionEpilog and the return value store in EmitReturnStmt with HaveInsertPoint() checks. This is a reworked version of #134282, addressing review feedback. Fixes #104770. Co-authored-by: Kiran <[email protected]> --- clang/lib/CodeGen/CGCall.cpp | 5 +++- clang/lib/CodeGen/CGExprComplex.cpp | 4 ++- clang/lib/CodeGen/CGStmt.cpp | 3 ++ clang/test/CodeGenCXX/attr-musttail.cpp | 4 +-- clang/test/CodeGenCXX/fake-use-musttail.cpp | 6 +--- clang/test/CodeGenCXX/musttail-epilog.cpp | 32 +++++++++++++++++++++ 6 files changed, 45 insertions(+), 9 deletions(-) create mode 100644 clang/test/CodeGenCXX/musttail-epilog.cpp diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp index c0e2456891e9d..db6ce0ace8c86 100644 --- a/clang/lib/CodeGen/CGCall.cpp +++ b/clang/lib/CodeGen/CGCall.cpp @@ -4104,6 +4104,10 @@ llvm::Value *CodeGenFunction::EmitCMSEClearRecord(llvm::Value *Src, void CodeGenFunction::EmitFunctionEpilog( const CGFunctionInfo &FI, bool EmitRetDbgLoc, SourceLocation EndLoc, uint64_t RetKeyInstructionsSourceAtom) { + // Nothing to do if the function body already emitted a return. + if (!HaveInsertPoint()) + return; + if (FI.isNoReturn()) { // Noreturn functions don't return. EmitUnreachable(EndLoc); @@ -6271,7 +6275,6 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, else Builder.CreateRet(CI); Builder.ClearInsertionPoint(); - EnsureInsertPoint(); return GetUndefRValue(RetTy); } diff --git a/clang/lib/CodeGen/CGExprComplex.cpp b/clang/lib/CodeGen/CGExprComplex.cpp index 757663eb50f58..e70c75752d561 100644 --- a/clang/lib/CodeGen/CGExprComplex.cpp +++ b/clang/lib/CodeGen/CGExprComplex.cpp @@ -1491,7 +1491,9 @@ void CodeGenFunction::EmitComplexExprIntoLValue(const Expr *E, LValue dest, "Invalid complex expression to emit"); ComplexExprEmitter Emitter(*this); ComplexPairTy Val = Emitter.Visit(const_cast<Expr *>(E)); - Emitter.EmitStoreOfComplex(Val, dest, isInit); + // The call may have already emitted a return (e.g. musttail). + if (HaveInsertPoint()) + Emitter.EmitStoreOfComplex(Val, dest, isInit); } /// EmitStoreOfComplex - Store a complex number into the specified l-value. diff --git a/clang/lib/CodeGen/CGStmt.cpp b/clang/lib/CodeGen/CGStmt.cpp index a75d3dc64c6b4..a55d53cf0c0a5 100644 --- a/clang/lib/CodeGen/CGStmt.cpp +++ b/clang/lib/CodeGen/CGStmt.cpp @@ -1644,6 +1644,9 @@ void CodeGenFunction::EmitReturnStmt(const ReturnStmt &S) { switch (getEvaluationKind(RV->getType())) { case TEK_Scalar: { llvm::Value *Ret = EmitScalarExpr(RV); + // The call may have already emitted a return (e.g. musttail). + if (!HaveInsertPoint()) + break; if (CurFnInfo->getReturnInfo().getKind() == ABIArgInfo::Indirect) { EmitStoreOfScalar(Ret, MakeAddrLValue(ReturnValue, RV->getType()), /*isInit*/ true); diff --git a/clang/test/CodeGenCXX/attr-musttail.cpp b/clang/test/CodeGenCXX/attr-musttail.cpp index c0081ec232e4a..1d908e2c785f1 100644 --- a/clang/test/CodeGenCXX/attr-musttail.cpp +++ b/clang/test/CodeGenCXX/attr-musttail.cpp @@ -7,11 +7,11 @@ int Baz(int); int Func1(int x) { if (x) { - // CHECK: %call = musttail call noundef i32 @_Z3Bari(i32 noundef %1) + // CHECK: %call = musttail call noundef i32 @_Z3Bari(i32 noundef %{{.*}}) // CHECK-NEXT: ret i32 %call [[clang::musttail]] return Bar(x); } else { - [[clang::musttail]] return Baz(x); // CHECK: %call1 = musttail call noundef i32 @_Z3Bazi(i32 noundef %3) + [[clang::musttail]] return Baz(x); // CHECK: %call1 = musttail call noundef i32 @_Z3Bazi(i32 noundef %{{.*}}) } } diff --git a/clang/test/CodeGenCXX/fake-use-musttail.cpp b/clang/test/CodeGenCXX/fake-use-musttail.cpp index 9d341ab52f1c8..ac7f8a1f17c61 100644 --- a/clang/test/CodeGenCXX/fake-use-musttail.cpp +++ b/clang/test/CodeGenCXX/fake-use-musttail.cpp @@ -16,11 +16,7 @@ extern "C" char *bar(int *); // 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 +// CHECK-NOT: ret ptr // extern "C" const char *foo(int *e) { [[clang::musttail]] return bar(e); diff --git a/clang/test/CodeGenCXX/musttail-epilog.cpp b/clang/test/CodeGenCXX/musttail-epilog.cpp new file mode 100644 index 0000000000000..566dff65e8748 --- /dev/null +++ b/clang/test/CodeGenCXX/musttail-epilog.cpp @@ -0,0 +1,32 @@ +// RUN: %clang_cc1 -emit-llvm %s -triple x86_64-unknown-linux-gnu -o - | FileCheck %s + +// After a musttail call, the function epilog should not emit a redundant +// return statement in a dead block. + +int F1(short); +void V1(int); +double _Complex C1(short); + +// CHECK-LABEL: define {{.*}} @_Z5test1s( +// CHECK: musttail call +// CHECK-NEXT: ret i32 +// CHECK-NOT: ret i32 +int test1(short P0) { + [[clang::musttail]] return F1(P0); +} + +// CHECK-LABEL: define {{.*}} @_Z5test2i( +// CHECK: musttail call +// CHECK-NEXT: ret void +// CHECK-NOT: ret void +void test2(int x) { + [[clang::musttail]] return V1(x); +} + +// CHECK-LABEL: define {{.*}} @_Z5test3s( +// CHECK: musttail call +// CHECK-NEXT: ret { double, double } +// CHECK-NOT: ret { double, double } +double _Complex test3(short P0) { + [[clang::musttail]] return C1(P0); +} _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
