From f9c22f861739e52e77960ae8083490dfdf62d19e Mon Sep 17 00:00:00 2001 From: Jasmine Tang Date: Wed, 15 Oct 2025 12:13:58 -0700 Subject: [PATCH 1/2] Precommit --- clang/test/CodeGen/WebAssembly/musttail.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 clang/test/CodeGen/WebAssembly/musttail.c diff --git a/clang/test/CodeGen/WebAssembly/musttail.c b/clang/test/CodeGen/WebAssembly/musttail.c new file mode 100644 index 0000000000000..da100484e94f2 --- /dev/null +++ b/clang/test/CodeGen/WebAssembly/musttail.c @@ -0,0 +1,20 @@ +// RUN: %clang_cc1 %s -triple wasm32-unknown-unknown -target-feature +tail-call -o /dev/null -emit-llvm -verify=good +// RUN: %clang_cc1 %s -triple wasm64-unknown-unknown -target-feature +tail-call -o /dev/null -emit-llvm -verify=good +// RUN: %clang_cc1 %s -triple wasm32-unknown-unknown -o /dev/null -emit-llvm -verify=notail + +int foo(int x) { + return x; +} + +#if __has_attribute(musttail) +// good-warning@+2 {{HAS IT}} +// notail-warning@+1 {{HAS IT}} +#warning HAS IT +#else +#warning DOES NOT HAVE +#endif + +int bar(int x) +{ + [[clang::musttail]] return foo(1); +} From 26b9025acc1eaecd473196691ed5e23cfbabf88e Mon Sep 17 00:00:00 2001 From: Jasmine Tang Date: Wed, 15 Oct 2025 12:14:04 -0700 Subject: [PATCH 2/2] Add must tail support --- clang/include/clang/Basic/Attr.td | 7 ++++++- clang/include/clang/Basic/DiagnosticCommonKinds.td | 2 ++ clang/include/clang/Basic/TargetInfo.h | 3 +++ clang/lib/Basic/TargetInfo.cpp | 1 + clang/lib/Basic/Targets/WebAssembly.cpp | 3 +++ clang/lib/Sema/SemaStmt.cpp | 1 - clang/lib/Sema/SemaStmtAttr.cpp | 6 ++++++ clang/test/CodeGen/WebAssembly/musttail.c | 8 ++++---- 8 files changed, 25 insertions(+), 6 deletions(-) diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index 3cde249e286fa..fab4e1dca024b 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -483,6 +483,7 @@ def TargetAnyX86 : TargetArch<["x86", "x86_64"]>; def TargetSPIRV : TargetArch<["spirv", "spirv32", "spirv64"]>; def TargetWebAssembly : TargetArch<["wasm32", "wasm64"]>; def TargetNVPTX : TargetArch<["nvptx", "nvptx64"]>; +def TargetPowerPC : TargetArch<["ppc", "ppcle", "ppc64", "ppc64le"]>; def TargetWindows : TargetSpec { let OSes = ["Win32"]; } @@ -508,6 +509,10 @@ def TargetMicrosoftRecordLayout : TargetArch<["x86", "x86_64", "arm", "thumb", let CustomCode = [{ Target.hasMicrosoftRecordLayout() }]; } +def TargetMustTailAvaiable: TargetArch { + let CustomCode = [{ Target.hasMustTail() }]; +} + def TargetELF : TargetSpec { let ObjectFormats = ["ELF"]; } @@ -1896,7 +1901,7 @@ def NoMerge : DeclOrStmtAttr { "functions, statements and variables">; } -def MustTail : StmtAttr { +def MustTail : StmtAttr, TargetSpecificAttr { let Spellings = [Clang<"musttail">]; let Documentation = [MustTailDocs]; let Subjects = SubjectList<[ReturnStmt], ErrorDiag, "return statements">; diff --git a/clang/include/clang/Basic/DiagnosticCommonKinds.td b/clang/include/clang/Basic/DiagnosticCommonKinds.td index 6e50e225a8cc1..b0a928018cccd 100644 --- a/clang/include/clang/Basic/DiagnosticCommonKinds.td +++ b/clang/include/clang/Basic/DiagnosticCommonKinds.td @@ -374,6 +374,8 @@ def err_ppc_impossible_musttail: Error< >; def err_aix_musttail_unsupported: Error< "'musttail' attribute is not supported on AIX">; +def err_wasm_musttail_unsupported: Error< + "'musttail' attribute is not supported on this target without tail-call feature">; // Source manager def err_cannot_open_file : Error<"cannot open file '%0': %1">, DefaultFatal; diff --git a/clang/include/clang/Basic/TargetInfo.h b/clang/include/clang/Basic/TargetInfo.h index ceb16174e13e7..e2768bea1902e 100644 --- a/clang/include/clang/Basic/TargetInfo.h +++ b/clang/include/clang/Basic/TargetInfo.h @@ -229,6 +229,7 @@ class TargetInfo : public TransferrableTargetInfo, protected: // Target values set by the ctor of the actual target implementation. Default // values are specified by the TargetInfo constructor. + bool HasMustTail; bool BigEndian; bool TLSSupported; bool VLASupported; @@ -669,6 +670,8 @@ class TargetInfo : public TransferrableTargetInfo, : getLongFractScale() + 1; } + virtual bool hasMustTail() const { return HasMustTail; } + /// Determine whether the __int128 type is supported on this target. virtual bool hasInt128Type() const { return (getPointerWidth(LangAS::Default) >= 64) || diff --git a/clang/lib/Basic/TargetInfo.cpp b/clang/lib/Basic/TargetInfo.cpp index f4d7c1288cc04..9a5db6e164f66 100644 --- a/clang/lib/Basic/TargetInfo.cpp +++ b/clang/lib/Basic/TargetInfo.cpp @@ -59,6 +59,7 @@ static const LangASMap FakeAddrSpaceMap = { TargetInfo::TargetInfo(const llvm::Triple &T) : Triple(T) { // Set defaults. Defaults are set for a 32-bit RISC platform, like PPC or // SPARC. These should be overridden by concrete targets as needed. + HasMustTail = true; BigEndian = !T.isLittleEndian(); TLSSupported = true; VLASupported = true; diff --git a/clang/lib/Basic/Targets/WebAssembly.cpp b/clang/lib/Basic/Targets/WebAssembly.cpp index 55ffe1df0ba08..5bbb7af4c2ca1 100644 --- a/clang/lib/Basic/Targets/WebAssembly.cpp +++ b/clang/lib/Basic/Targets/WebAssembly.cpp @@ -213,6 +213,7 @@ bool WebAssemblyTargetInfo::initFeatureMap( bool WebAssemblyTargetInfo::handleTargetFeatures( std::vector &Features, DiagnosticsEngine &Diags) { + HasMustTail = false; for (const auto &Feature : Features) { if (Feature == "+atomics") { HasAtomics = true; @@ -345,10 +346,12 @@ bool WebAssemblyTargetInfo::handleTargetFeatures( } if (Feature == "+tail-call") { HasTailCall = true; + HasMustTail = true; continue; } if (Feature == "-tail-call") { HasTailCall = false; + HasMustTail = false; continue; } if (Feature == "+wide-arithmetic") { diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp index ae0bb616beb82..afd6fa617058b 100644 --- a/clang/lib/Sema/SemaStmt.cpp +++ b/clang/lib/Sema/SemaStmt.cpp @@ -695,7 +695,6 @@ bool Sema::checkMustTailAttr(const Stmt *St, const Attr &MTA) { const Expr *E = cast(St)->getRetValue(); const auto *CE = dyn_cast_or_null(IgnoreParenImplicitAsWritten(E)); - if (!CE) { Diag(St->getBeginLoc(), diag::err_musttail_needs_call) << &MTA; return false; diff --git a/clang/lib/Sema/SemaStmtAttr.cpp b/clang/lib/Sema/SemaStmtAttr.cpp index 50acc83f1841c..6ba8832d2e76a 100644 --- a/clang/lib/Sema/SemaStmtAttr.cpp +++ b/clang/lib/Sema/SemaStmtAttr.cpp @@ -672,6 +672,12 @@ static Attr *ProcessStmtAttribute(Sema &S, Stmt *St, const ParsedAttr &A, !(A.existsInTarget(S.Context.getTargetInfo()) || (S.Context.getLangOpts().SYCLIsDevice && Aux && A.existsInTarget(*Aux)))) { + // Special case: musttail on WebAssembly without tail-call feature + if (A.getKind() == ParsedAttr::AT_MustTail && + !S.Context.getTargetInfo().hasMustTail()) { + S.Diag(A.getLoc(), diag::err_wasm_musttail_unsupported); + return nullptr; + } if (A.isRegularKeywordAttribute()) { S.Diag(A.getLoc(), diag::err_keyword_not_supported_on_target) << A << A.getRange(); diff --git a/clang/test/CodeGen/WebAssembly/musttail.c b/clang/test/CodeGen/WebAssembly/musttail.c index da100484e94f2..75ed7657a8087 100644 --- a/clang/test/CodeGen/WebAssembly/musttail.c +++ b/clang/test/CodeGen/WebAssembly/musttail.c @@ -1,5 +1,4 @@ -// RUN: %clang_cc1 %s -triple wasm32-unknown-unknown -target-feature +tail-call -o /dev/null -emit-llvm -verify=good -// RUN: %clang_cc1 %s -triple wasm64-unknown-unknown -target-feature +tail-call -o /dev/null -emit-llvm -verify=good +// RUN: %clang_cc1 %s -triple wasm32-unknown-unknown -target-feature +tail-call -o /dev/null -emit-llvm -verify=tail // RUN: %clang_cc1 %s -triple wasm32-unknown-unknown -o /dev/null -emit-llvm -verify=notail int foo(int x) { @@ -7,14 +6,15 @@ int foo(int x) { } #if __has_attribute(musttail) -// good-warning@+2 {{HAS IT}} -// notail-warning@+1 {{HAS IT}} +// tail-warning@+1 {{HAS IT}} #warning HAS IT #else +// notail-warning@+1 {{DOES NOT HAVE}} #warning DOES NOT HAVE #endif int bar(int x) { + // notail-error@+1 {{'musttail' attribute is not supported on this target without tail-call feature}} [[clang::musttail]] return foo(1); }