Index: clang/include/clang-c/Index.h =================================================================== --- clang/include/clang-c/Index.h +++ clang/include/clang-c/Index.h @@ -2972,6 +2972,7 @@ CXCallingConv_AArch64VectorCall = 16, CXCallingConv_SwiftAsync = 17, CXCallingConv_AArch64SVEPCS = 18, + CXCallingConv_M68kRTD = 19, CXCallingConv_Invalid = 100, CXCallingConv_Unexposed = 200 Index: clang/include/clang/Basic/Attr.td =================================================================== --- clang/include/clang/Basic/Attr.td +++ clang/include/clang/Basic/Attr.td @@ -2724,6 +2724,11 @@ let Documentation = [PreserveAllDocs]; } +def M68kRTD: DeclOrTypeAttr { + let Spellings = [Clang<"m68k_rtd">]; + let Documentation = [M68kRTDDocs]; +} + def Target : InheritableAttr { let Spellings = [GCC<"target">]; let Args = [StringArgument<"featuresStr">]; Index: clang/include/clang/Basic/AttrDocs.td =================================================================== --- clang/include/clang/Basic/AttrDocs.td +++ clang/include/clang/Basic/AttrDocs.td @@ -2791,6 +2791,18 @@ }]; } +def M68kRTDDocs : Documentation { + let Category = DocCatCallingConvs; + let Content = [{ +On M68k targets, this attribute changes the calling convention of a function +to clear parameters off the stack on return. In other words, callee is +responsible for cleaning out the stack space allocated for incoming paramters. +This convention does not support variadic calls or unprototyped functions in C. +When targeting M68010 or newer CPUs, this calling convention is implemented +using the `rtd` instruction. + }]; +} + def DocCatConsumed : DocumentationCategory<"Consumed Annotation Checking"> { let Content = [{ Clang supports additional attributes for checking basic resource management Index: clang/include/clang/Basic/Specifiers.h =================================================================== --- clang/include/clang/Basic/Specifiers.h +++ clang/include/clang/Basic/Specifiers.h @@ -285,6 +285,7 @@ CC_AArch64VectorCall, // __attribute__((aarch64_vector_pcs)) CC_AArch64SVEPCS, // __attribute__((aarch64_sve_pcs)) CC_AMDGPUKernelCall, // __attribute__((amdgpu_kernel)) + CC_M68kRTD, // __attribute__((m68k_rtd)) }; /// Checks whether the given calling convention supports variadic @@ -301,6 +302,7 @@ case CC_OpenCLKernel: case CC_Swift: case CC_SwiftAsync: + case CC_M68kRTD: return false; default: return true; Index: clang/lib/AST/ASTContext.cpp =================================================================== --- clang/lib/AST/ASTContext.cpp +++ clang/lib/AST/ASTContext.cpp @@ -11991,8 +11991,13 @@ return CC_X86FastCall; break; case LangOptions::DCC_StdCall: - if (!IsVariadic) - return CC_X86StdCall; + if (!IsVariadic) { + const llvm::Triple &T = getTargetInfo().getTriple(); + if (T.isX86()) + return CC_X86StdCall; + else if (T.getArch() == llvm::Triple::m68k) + return CC_M68kRTD; + } break; case LangOptions::DCC_VectorCall: // __vectorcall cannot be applied to variadic functions. Index: clang/lib/AST/ItaniumMangle.cpp =================================================================== --- clang/lib/AST/ItaniumMangle.cpp +++ clang/lib/AST/ItaniumMangle.cpp @@ -3266,6 +3266,7 @@ case CC_OpenCLKernel: case CC_PreserveMost: case CC_PreserveAll: + case CC_M68kRTD: // FIXME: we should be mangling all of the above. return ""; Index: clang/lib/AST/Type.cpp =================================================================== --- clang/lib/AST/Type.cpp +++ clang/lib/AST/Type.cpp @@ -3307,6 +3307,7 @@ case CC_SwiftAsync: return "swiftasynccall"; case CC_PreserveMost: return "preserve_most"; case CC_PreserveAll: return "preserve_all"; + case CC_M68kRTD: return "m68k_rtd"; } llvm_unreachable("Invalid calling convention."); @@ -3772,6 +3773,7 @@ case attr::IntelOclBicc: case attr::PreserveMost: case attr::PreserveAll: + case attr::M68kRTD: return true; } llvm_unreachable("invalid attr kind"); Index: clang/lib/AST/TypePrinter.cpp =================================================================== --- clang/lib/AST/TypePrinter.cpp +++ clang/lib/AST/TypePrinter.cpp @@ -1035,6 +1035,9 @@ case CC_PreserveAll: OS << " __attribute__((preserve_all))"; break; + case CC_M68kRTD: + OS << " __attribute__((m68k_rtd))"; + break; } } @@ -1829,6 +1832,7 @@ case attr::PreserveAll: OS << "preserve_all"; break; + case attr::M68kRTD: OS << "m68k_rtd"; break; case attr::NoDeref: OS << "noderef"; break; Index: clang/lib/Basic/Targets/M68k.h =================================================================== --- clang/lib/Basic/Targets/M68k.h +++ clang/lib/Basic/Targets/M68k.h @@ -54,6 +54,7 @@ std::string_view getClobbers() const override; BuiltinVaListKind getBuiltinVaListKind() const override; bool setCPU(const std::string &Name) override; + CallingConvCheckResult checkCallingConvention(CallingConv CC) const override; }; } // namespace targets Index: clang/lib/Basic/Targets/M68k.cpp =================================================================== --- clang/lib/Basic/Targets/M68k.cpp +++ clang/lib/Basic/Targets/M68k.cpp @@ -250,5 +250,15 @@ return TargetInfo::VoidPtrBuiltinVaList; } +TargetInfo::CallingConvCheckResult +M68kTargetInfo::checkCallingConvention(CallingConv CC) const { + switch (CC) { + case CC_C: + case CC_M68kRTD: + return CCCR_OK; + default: + return TargetInfo::checkCallingConvention(CC); + } +} } // namespace targets } // namespace clang Index: clang/lib/CodeGen/CGCall.cpp =================================================================== --- clang/lib/CodeGen/CGCall.cpp +++ clang/lib/CodeGen/CGCall.cpp @@ -70,6 +70,7 @@ case CC_PreserveAll: return llvm::CallingConv::PreserveAll; case CC_Swift: return llvm::CallingConv::Swift; case CC_SwiftAsync: return llvm::CallingConv::SwiftTail; + case CC_M68kRTD: return llvm::CallingConv::M68k_RTD; } } @@ -251,6 +252,9 @@ if (D->hasAttr()) return CC_PreserveAll; + if (D->hasAttr()) + return CC_M68kRTD; + return CC_C; } Index: clang/lib/CodeGen/CGDebugInfo.cpp =================================================================== --- clang/lib/CodeGen/CGDebugInfo.cpp +++ clang/lib/CodeGen/CGDebugInfo.cpp @@ -1438,6 +1438,8 @@ return llvm::dwarf::DW_CC_LLVM_PreserveAll; case CC_X86RegCall: return llvm::dwarf::DW_CC_LLVM_X86RegCall; + case CC_M68kRTD: + return llvm::dwarf::DW_CC_LLVM_M68kRTD; } return 0; } Index: clang/lib/Frontend/CompilerInvocation.cpp =================================================================== --- clang/lib/Frontend/CompilerInvocation.cpp +++ clang/lib/Frontend/CompilerInvocation.cpp @@ -553,9 +553,10 @@ if (Arg *A = Args.getLastArg(OPT_fdefault_calling_conv_EQ)) { auto DefaultCC = LangOpts.getDefaultCallingConv(); - bool emitError = (DefaultCC == LangOptions::DCC_FastCall || - DefaultCC == LangOptions::DCC_StdCall) && - Arch != llvm::Triple::x86; + bool emitError = + DefaultCC == LangOptions::DCC_FastCall && Arch != llvm::Triple::x86; + emitError |= DefaultCC == LangOptions::DCC_StdCall && + Arch != llvm::Triple::m68k && Arch != llvm::Triple::x86; emitError |= (DefaultCC == LangOptions::DCC_VectorCall || DefaultCC == LangOptions::DCC_RegCall) && !T.isX86(); @@ -3747,7 +3748,7 @@ Diags.Report(diag::err_drv_argument_not_allowed_with) << A->getSpelling() << "-fdefault-calling-conv"; else { - if (T.getArch() != llvm::Triple::x86) + if (T.getArch() != llvm::Triple::x86 && T.getArch() != llvm::Triple::m68k) Diags.Report(diag::err_drv_argument_not_allowed_with) << A->getSpelling() << T.getTriple(); else Index: clang/lib/Sema/SemaDeclAttr.cpp =================================================================== --- clang/lib/Sema/SemaDeclAttr.cpp +++ clang/lib/Sema/SemaDeclAttr.cpp @@ -5107,6 +5107,9 @@ case ParsedAttr::AT_PreserveAll: D->addAttr(::new (S.Context) PreserveAllAttr(S.Context, AL)); return; + case ParsedAttr::AT_M68kRTD: + D->addAttr(::new (S.Context) M68kRTDAttr(S.Context, AL)); + return; default: llvm_unreachable("unexpected attribute kind"); } @@ -5299,6 +5302,9 @@ case ParsedAttr::AT_PreserveAll: CC = CC_PreserveAll; break; + case ParsedAttr::AT_M68kRTD: + CC = CC_M68kRTD; + break; default: llvm_unreachable("unexpected attribute kind"); } @@ -9100,6 +9106,7 @@ case ParsedAttr::AT_AArch64VectorPcs: case ParsedAttr::AT_AArch64SVEPcs: case ParsedAttr::AT_AMDGPUKernelCall: + case ParsedAttr::AT_M68kRTD: handleCallConvAttr(S, D, AL); break; case ParsedAttr::AT_Suppress: Index: clang/lib/Sema/SemaType.cpp =================================================================== --- clang/lib/Sema/SemaType.cpp +++ clang/lib/Sema/SemaType.cpp @@ -132,7 +132,8 @@ case ParsedAttr::AT_Pcs: \ case ParsedAttr::AT_IntelOclBicc: \ case ParsedAttr::AT_PreserveMost: \ - case ParsedAttr::AT_PreserveAll + case ParsedAttr::AT_PreserveAll: \ + case ParsedAttr::AT_M68kRTD // Function type attributes. #define FUNCTION_TYPE_ATTRS_CASELIST \ @@ -7736,6 +7737,8 @@ return createSimpleAttr(Ctx, Attr); case ParsedAttr::AT_PreserveAll: return createSimpleAttr(Ctx, Attr); + case ParsedAttr::AT_M68kRTD: + return createSimpleAttr(Ctx, Attr); } llvm_unreachable("unexpected attribute kind!"); } @@ -7954,9 +7957,9 @@ if (!supportsVariadicCall(CC)) { const FunctionProtoType *FnP = dyn_cast(fn); if (FnP && FnP->isVariadic()) { - // stdcall and fastcall are ignored with a warning for GCC and MS - // compatibility. - if (CC == CC_X86StdCall || CC == CC_X86FastCall) + // stdcall, fastcall, and m68k's RTD are ignored with a warning for GCC + // and MS compatibility. + if (CC == CC_X86StdCall || CC == CC_X86FastCall || CC == CC_M68kRTD) return S.Diag(attr.getLoc(), diag::warn_cconv_unsupported) << FunctionType::getNameForCallConv(CC) << (int)Sema::CallingConventionIgnoredReason::VariadicFunction; Index: clang/test/CodeGen/mrtd.c =================================================================== --- clang/test/CodeGen/mrtd.c +++ clang/test/CodeGen/mrtd.c @@ -1,20 +1,26 @@ -// RUN: %clang_cc1 -mrtd -triple i386-unknown-unknown -std=c89 -emit-llvm -o - %s 2>&1 | FileCheck %s +// RUN: %clang_cc1 -mrtd -triple i386-unknown-unknown -std=c89 -emit-llvm -o - %s 2>&1 | FileCheck --check-prefixes=CHECK,X86 %s +// RUN: %clang_cc1 -mrtd -triple m68k-unknown-unknown -std=c89 -emit-llvm -o - %s 2>&1 | FileCheck --check-prefixes=CHECK,M68k %s -// CHECK: mrtd.c:10:3: warning: function with no prototype cannot use the stdcall calling convention +// X86: mrtd.c:13:3: warning: function with no prototype cannot use the stdcall calling convention void baz(int arg); -// CHECK: define{{.*}} x86_stdcallcc void @foo(i32 noundef %arg) [[NUW:#[0-9]+]] +// X86: define{{.*}} x86_stdcallcc void @foo(i32 noundef %arg) [[NUW:#[0-9]+]] +// M68k: define{{.*}} m68k_rtdcc void @foo(i32 noundef %arg) void foo(int arg) { -// CHECK: call x86_stdcallcc i32 @bar( +// X86: call x86_stdcallcc i32 @bar( +#ifndef mc68000 bar(arg); -// CHECK: call x86_stdcallcc void @baz(i32 +#endif +// X86: call x86_stdcallcc void @baz(i32 +// M68k: call m68k_rtdcc void @baz(i32 baz(arg); } -// CHECK: declare x86_stdcallcc i32 @bar(...) +// X86: declare x86_stdcallcc i32 @bar(...) -// CHECK: declare x86_stdcallcc void @baz(i32 noundef) +// X86: declare x86_stdcallcc void @baz(i32 noundef) +// M68k: declare m68k_rtdcc void @baz(i32 noundef) void qux(int arg, ...) { } // CHECK: define{{.*}} void @qux(i32 noundef %arg, ...) @@ -22,7 +28,8 @@ void quux(int a1, int a2, int a3) { qux(a1, a2, a3); } -// CHECK-LABEL: define{{.*}} x86_stdcallcc void @quux +// X86-LABEL: define{{.*}} x86_stdcallcc void @quux +// M68k-LABEL: define{{.*}} m68k_rtdcc void @quux // CHECK: call void (i32, ...) @qux -// CHECK: attributes [[NUW]] = { noinline nounwind{{.*}} } +// X86: attributes [[NUW]] = { noinline nounwind{{.*}} } Index: clang/test/Sema/m68k-mrtd.c =================================================================== --- /dev/null +++ clang/test/Sema/m68k-mrtd.c @@ -0,0 +1,45 @@ +// RUN: %clang_cc1 -DMRTD -mrtd -triple m68k-unknown-unknown -std=c89 -verify %s +// RUN: %clang_cc1 -triple m68k-unknown-unknown -std=c89 -verify %s + +#ifdef MRTD +// expected-error@+3 {{function with no prototype cannot use the m68k_rtd calling convention}} +#endif +void foo(int arg) { + bar(arg); +} + +#ifndef MRTD +// expected-note@+5 {{previous declaration is here}} +// expected-error@+5 {{function declared 'm68k_rtd' here was previously declared without calling convention}} +// expected-note@+5 {{previous declaration is here}} +// expected-error@+5 {{function declared 'm68k_rtd' here was previously declared without calling convention}} +#endif +void nonvariadic1(int a, int b, int c); +void __attribute__((m68k_rtd)) nonvariadic1(int a, int b, int c); +void nonvariadic2(int a, int b, int c); +void __attribute__((m68k_rtd)) nonvariadic2(int a, int b, int c) { } + +// expected-warning@+2 {{m68k_rtd calling convention is not supported on variadic function}} +void variadic(int a, ...); +void __attribute__((m68k_rtd)) variadic(int a, ...); + +#ifdef MRTD +// expected-note@+3 {{previous declaration is here}} +// expected-error@+3 {{redeclaration of 'a' with a different type: 'void ((*))(int, int) __attribute__((cdecl))' vs 'void (*)(int, int) __attribute__((m68k_rtd))'}} +#endif +extern void (*a)(int, int); +__attribute__((cdecl)) extern void (*a)(int, int); + +extern void (*b)(int, ...); +__attribute__((cdecl)) extern void (*b)(int, ...); + +#ifndef MRTD +// expected-note@+3 {{previous declaration is here}} +// expected-error@+3 {{redeclaration of 'c' with a different type: 'void ((*))(int, int) __attribute__((m68k_rtd))' vs 'void (*)(int, int)'}} +#endif +extern void (*c)(int, int); +__attribute__((m68k_rtd)) extern void (*c)(int, int); + +// expected-warning@+2 {{m68k_rtd calling convention is not supported on variadic function}} +extern void (*d)(int, ...); +__attribute__((m68k_rtd)) extern void (*d)(int, ...); Index: clang/tools/libclang/CXType.cpp =================================================================== --- clang/tools/libclang/CXType.cpp +++ clang/tools/libclang/CXType.cpp @@ -678,6 +678,7 @@ TCALLINGCONV(SwiftAsync); TCALLINGCONV(PreserveMost); TCALLINGCONV(PreserveAll); + TCALLINGCONV(M68kRTD); case CC_SpirFunction: return CXCallingConv_Unexposed; case CC_AMDGPUKernelCall: return CXCallingConv_Unexposed; case CC_OpenCLKernel: return CXCallingConv_Unexposed;