https://github.com/chfast updated https://github.com/llvm/llvm-project/pull/191198
From f2b4489c8b70c608961674008e421e75a5561a34 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 1/2] [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 09f6d63a36bd6..2b6df337f35a5 100644 --- a/clang/lib/CodeGen/CGCall.cpp +++ b/clang/lib/CodeGen/CGCall.cpp @@ -4174,6 +4174,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); @@ -6374,7 +6378,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 4d98ee9957418..4cea9e821881b 100644 --- a/clang/lib/CodeGen/CGExprComplex.cpp +++ b/clang/lib/CodeGen/CGExprComplex.cpp @@ -1488,7 +1488,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 30756180ebafa..fd7ff1d8f8a82 100644 --- a/clang/lib/CodeGen/CGStmt.cpp +++ b/clang/lib/CodeGen/CGStmt.cpp @@ -1647,6 +1647,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); +} From b4642ed7d3ae186179e31e02344551280517430a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= <[email protected]> Date: Mon, 15 Jun 2026 09:16:00 +0200 Subject: [PATCH 2/2] [Clang] Fix broken module for musttail thunk returning aggregate The virtual function pointer thunk emitted its own return after EmitCall, which now already emits the return and clears the insertion point for a musttail call, leaving the thunk's CreateRet orphaned. Guard it with HaveInsertPoint() and drop the now unnecessary dead block. --- clang/lib/CodeGen/ItaniumCXXABI.cpp | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/clang/lib/CodeGen/ItaniumCXXABI.cpp b/clang/lib/CodeGen/ItaniumCXXABI.cpp index b4b3284f752ae..73e2a40e1a213 100644 --- a/clang/lib/CodeGen/ItaniumCXXABI.cpp +++ b/clang/lib/CodeGen/ItaniumCXXABI.cpp @@ -3528,14 +3528,16 @@ ItaniumCXXABI::getOrCreateVirtualFunctionPointerThunk(const CXXMethodDecl *MD) { /*IsMustTail=*/true, SourceLocation(), true); auto *Call = cast<llvm::CallInst>(CallOrInvoke); Call->setTailCallKind(llvm::CallInst::TCK_MustTail); - if (Call->getType()->isVoidTy()) - CGF.Builder.CreateRetVoid(); - else - CGF.Builder.CreateRet(Call); + // EmitCall already emits the return and clears the insertion point for the + // musttail call; only emit one here if it left a valid insertion point. + if (CGF.HaveInsertPoint()) { + if (Call->getType()->isVoidTy()) + CGF.Builder.CreateRetVoid(); + else + CGF.Builder.CreateRet(Call); + CGF.Builder.ClearInsertionPoint(); + } - // Finish the function to maintain CodeGenFunction invariants. - // FIXME: Don't emit unreachable code. - CGF.EmitBlock(CGF.createBasicBlock()); CGF.FinishFunction(); return ThunkFn; } _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
