llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-backend-powerpc Author: Luminyx (Luminyx1) <details> <summary>Changes</summary> Allows use of `__attribute__((no_caller_saved_registers))` on PowerPC targets for non-clobbering C/C++ functions. --- Full diff: https://github.com/llvm/llvm-project/pull/174320.diff 10 Files Affected: - (modified) clang/include/clang/Basic/Attr.td (+6-3) - (modified) clang/include/clang/Basic/AttrDocs.td (+5-2) - (modified) clang/include/clang/Basic/DiagnosticSemaKinds.td (+3) - (modified) clang/lib/CodeGen/CGCall.cpp (+1-1) - (modified) clang/lib/Sema/SemaDecl.cpp (+8-2) - (modified) clang/lib/Sema/SemaExpr.cpp (+2-2) - (modified) clang/lib/Sema/SemaType.cpp (+2-2) - (added) clang/test/Sema/attr-no-caller-saved-registers.c (+13) - (modified) llvm/lib/Target/PowerPC/PPCCallingConv.td (+29-5) - (modified) llvm/lib/Target/PowerPC/PPCRegisterInfo.cpp (+21) ``````````diff diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index b017906a8d690..351b681070f93 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -476,6 +476,7 @@ def TargetMips32 : TargetArch<["mips", "mipsel"]>; def TargetAnyMips : TargetArch<["mips", "mipsel", "mips64", "mips64el"]>; def TargetMSP430 : TargetArch<["msp430"]>; def TargetM68k : TargetArch<["m68k"]>; +def TargetPowerPC : TargetArch<["ppc", "ppcle", "ppc64", "ppc64le"]>; def TargetRISCV : TargetArch<["riscv32", "riscv64"]>; def TargetX86 : TargetArch<["x86"]>; def TargetX86_64 : TargetArch<["x86_64"]>; @@ -3897,10 +3898,12 @@ def AnyX86Interrupt : InheritableAttr, TargetSpecificAttr<TargetAnyX86> { let Documentation = [AnyX86InterruptDocs]; } -def AnyX86NoCallerSavedRegisters : InheritableAttr, - TargetSpecificAttr<TargetAnyX86> { +def NoCallerSavedRegisters + : InheritableAttr, + TargetSpecificAttr< + TargetArch<!listconcat(TargetX86.Arches, TargetPowerPC.Arches)>> { let Spellings = [GCC<"no_caller_saved_registers">]; - let Documentation = [AnyX86NoCallerSavedRegistersDocs]; + let Documentation = [NoCallerSavedRegistersDocs]; let SimpleHandler = 1; } diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td index 812b48058d189..d0fb5cd5d6f79 100644 --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -5993,7 +5993,7 @@ non-GPR registers. }]; } -def AnyX86NoCallerSavedRegistersDocs : Documentation { +def NoCallerSavedRegistersDocs : Documentation { let Category = DocCatFunction; let Content = [{ Use this attribute to indicate that the specified function has no @@ -6007,10 +6007,13 @@ The user can call functions specified with the 'no_caller_saved_registers' attribute from an interrupt handler without saving and restoring all call-clobbered registers. -Functions specified with the 'no_caller_saved_registers' attribute should only +On X86, functions specified with the 'no_caller_saved_registers' attribute should only call other functions with the 'no_caller_saved_registers' attribute, or should be compiled with the '-mgeneral-regs-only' flag to avoid saving unused non-GPR registers. +On PowerPC, functions specified with the 'no_caller_saved_registers' attribute may not +return a value as the return register will be restored and thus cannot hold a value. + Note that 'no_caller_saved_registers' attribute is not a calling convention. In fact, it only overrides the decision of which registers should be saved by the caller, but not how the parameters are passed from the caller to the callee. diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 6c6a26614ad0e..f918cb666bd2c 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -403,6 +403,9 @@ def warn_anyx86_excessive_regsave : Warning< " with attribute 'no_caller_saved_registers'" " or be compiled with '-mgeneral-regs-only'">, InGroup<DiagGroup<"excessive-regsave">>; +def err_anyppc_return_regsave : Error< + "cannot save regs if function returns value as " + "the return value gets clobbered during restore">; def warn_arm_interrupt_vfp_clobber : Warning< "interrupt service routine with vfp enabled may clobber the " "interruptee's vfp state; " diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp index 4a9025b6e0b0f..15b96c987c0a5 100644 --- a/clang/lib/CodeGen/CGCall.cpp +++ b/clang/lib/CodeGen/CGCall.cpp @@ -2514,7 +2514,7 @@ void CodeGenModule::ConstructAttributeList(StringRef Name, if (TargetDecl->hasAttr<ReturnsNonNullAttr>() && !CodeGenOpts.NullPointerIsValid) RetAttrs.addAttribute(llvm::Attribute::NonNull); - if (TargetDecl->hasAttr<AnyX86NoCallerSavedRegistersAttr>()) + if (TargetDecl->hasAttr<NoCallerSavedRegistersAttr>()) FuncAttrs.addAttribute("no_caller_saved_registers"); if (TargetDecl->hasAttr<AnyX86NoCfCheckAttr>()) FuncAttrs.addAttribute(llvm::Attribute::NoCfCheck); diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index b943ea2f85030..fae49505aa5b4 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -3938,8 +3938,8 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, NamedDecl *&OldD, Scope *S, if (OldTypeInfo.getNoCallerSavedRegs() != NewTypeInfo.getNoCallerSavedRegs()) { if (NewTypeInfo.getNoCallerSavedRegs()) { - AnyX86NoCallerSavedRegistersAttr *Attr = - New->getAttr<AnyX86NoCallerSavedRegistersAttr>(); + NoCallerSavedRegistersAttr *Attr = + New->getAttr<NoCallerSavedRegistersAttr>(); Diag(New->getLocation(), diag::err_function_attribute_mismatch) << Attr; Diag(OldLocation, diag::note_previous_declaration); return true; @@ -16929,6 +16929,12 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body, bool IsInstantiation, if (FD && !FD->isDeleted()) checkTypeSupport(FD->getType(), FD->getLocation(), FD); + if (getASTContext().getTargetInfo().getTriple().isPPC() && + FD && FD->hasAttr<NoCallerSavedRegistersAttr>() && + !FD->getReturnType()->isVoidType()) { + Diag(FD->getBeginLoc(), diag::err_anyppc_return_regsave); + } + return dcl; } diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index e12e4b204afad..6d19df6b7b9fe 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -6961,12 +6961,12 @@ ExprResult Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl, // save and restore the non-GPR state. if (auto *Caller = getCurFunctionDecl()) { if (Caller->hasAttr<AnyX86InterruptAttr>() || - Caller->hasAttr<AnyX86NoCallerSavedRegistersAttr>()) { + Caller->hasAttr<NoCallerSavedRegistersAttr>()) { const TargetInfo &TI = Context.getTargetInfo(); bool HasNonGPRRegisters = TI.hasFeature("sse") || TI.hasFeature("x87") || TI.hasFeature("mmx"); if (HasNonGPRRegisters && - (!FDecl || !FDecl->hasAttr<AnyX86NoCallerSavedRegistersAttr>())) { + (!FDecl || !FDecl->hasAttr<NoCallerSavedRegistersAttr>())) { Diag(Fn->getExprLoc(), diag::warn_anyx86_excessive_regsave) << (Caller->hasAttr<AnyX86InterruptAttr>() ? 0 : 1); if (FDecl) diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index 7ef83433326ed..801353b812b70 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -164,7 +164,7 @@ static void diagnoseBadTypeAttribute(Sema &S, const ParsedAttr &attr, case ParsedAttr::AT_ArmOut: \ case ParsedAttr::AT_ArmInOut: \ case ParsedAttr::AT_ArmAgnostic: \ - case ParsedAttr::AT_AnyX86NoCallerSavedRegisters: \ + case ParsedAttr::AT_NoCallerSavedRegisters: \ case ParsedAttr::AT_AnyX86NoCfCheck: \ CALLING_CONV_ATTRS_CASELIST @@ -7935,7 +7935,7 @@ static bool handleFunctionTypeAttr(TypeProcessingState &state, ParsedAttr &attr, return true; } - if (attr.getKind() == ParsedAttr::AT_AnyX86NoCallerSavedRegisters) { + if (attr.getKind() == ParsedAttr::AT_NoCallerSavedRegisters) { if (S.CheckAttrTarget(attr) || S.CheckAttrNoArgs(attr)) return true; diff --git a/clang/test/Sema/attr-no-caller-saved-registers.c b/clang/test/Sema/attr-no-caller-saved-registers.c new file mode 100644 index 0000000000000..36af95efd6284 --- /dev/null +++ b/clang/test/Sema/attr-no-caller-saved-registers.c @@ -0,0 +1,13 @@ +// RUN: %clang_cc1 %s -verify -fsyntax-only -triple powerpc-eabi + +__attribute__((no_caller_saved_registers)) void valid(void) { } + +#ifdef __powerpc__ +__attribute__((no_caller_saved_registers)) int invalid1(void) { // expected-error{{cannot save regs if function returns value as the return value gets clobbered during restore}} + return 0; +} + +__attribute__((no_caller_saved_registers)) void* invalid2(void) { // expected-error{{cannot save regs if function returns value as the return value gets clobbered during restore}} + return 0; +} +#endif diff --git a/llvm/lib/Target/PowerPC/PPCCallingConv.td b/llvm/lib/Target/PowerPC/PPCCallingConv.td index 5d4fe06ebdddd..04d2d4801f793 100644 --- a/llvm/lib/Target/PowerPC/PPCCallingConv.td +++ b/llvm/lib/Target/PowerPC/PPCCallingConv.td @@ -343,6 +343,35 @@ def CSR_PPC64_R2_Altivec : CalleeSavedRegs<(add CSR_PPC64_Altivec, X2)>; def CSR_NoRegs : CalleeSavedRegs<(add)>; +def CSR_ALL_VSRP : CalleeSavedRegs<(sequence "VSRp%u", 0, 31)>; + +def CSR_VSRP : + CalleeSavedRegs<(add VSRp26, VSRp27, VSRp28, VSRp29, VSRp30, VSRp31)>; + +// NoCallerSavedRegisters attribute marks ALL registers as non-volatile EXCEPT for r1. +def CSR_SVR32_SaveAll_Common : CalleeSavedRegs<(add R0, (sequence "R%u", 3, 31), + (sequence "CR%u", 0, 7))>; + +def CSR_SVR32_SaveAll : CalleeSavedRegs<(add CSR_SVR32_SaveAll_Common, + (sequence "F%u", 0, 31))>; + +def CSR_SVR32_SaveAll_Altivec : CalleeSavedRegs<(add CSR_SVR32_SaveAll, + (sequence "V%u", 0, 31))>; + +def CSR_SVR32_SaveAll_SPE : CalleeSavedRegs<(add CSR_SVR32_SaveAll_Common, + (sequence "S%u", 0, 31))>; + +def CSR_SVR32_SaveAll_VSRP : CalleeSavedRegs<(add CSR_SVR32_SaveAll, CSR_ALL_VSRP)>; + +def CSR_SVR64_SaveAll : CalleeSavedRegs<(add R0, (sequence "X%u", 3, 31), + (sequence "F%u", 0, 31), + (sequence "CR%u", 0, 7))>; + +def CSR_SVR64_SaveAll_VSRP : CalleeSavedRegs<(add CSR_SVR64_SaveAll, CSR_ALL_VSRP)>; + +def CSR_SVR64_SaveAll_Altivec : CalleeSavedRegs<(add CSR_SVR64_SaveAll, + (sequence "V%u", 0, 31))>; + // coldcc calling convection marks most registers as non-volatile. // Do not include r1 since the stack pointer is never considered a CSR. // Do not include r2, since it is the TOC register and is added depending @@ -397,11 +426,6 @@ def CSR_64_AllRegs_VSX : CalleeSavedRegs<(add CSR_64_AllRegs_Altivec, def CSR_64_AllRegs_AIX_Dflt_VSX : CalleeSavedRegs<(add CSR_64_AllRegs_Altivec, (sequence "VSL%u", 0, 19))>; -def CSR_ALL_VSRP : CalleeSavedRegs<(sequence "VSRp%u", 0, 31)>; - -def CSR_VSRP : - CalleeSavedRegs<(add VSRp26, VSRp27, VSRp28, VSRp29, VSRp30, VSRp31)>; - def CSR_SVR432_VSRP : CalleeSavedRegs<(add CSR_SVR432_Altivec, CSR_VSRP)>; def CSR_SVR464_VSRP : CalleeSavedRegs<(add CSR_PPC64_Altivec, CSR_VSRP)>; diff --git a/llvm/lib/Target/PowerPC/PPCRegisterInfo.cpp b/llvm/lib/Target/PowerPC/PPCRegisterInfo.cpp index b3a7c829958ec..aaa9654529b3d 100644 --- a/llvm/lib/Target/PowerPC/PPCRegisterInfo.cpp +++ b/llvm/lib/Target/PowerPC/PPCRegisterInfo.cpp @@ -199,6 +199,27 @@ PPCRegisterInfo::getCalleeSavedRegs(const MachineFunction *MF) const { return CSR_64_AllRegs_SaveList; } + // No caller saved registers. + if (MF->getFunction().hasFnAttribute("no_caller_saved_registers")) { + if (Subtarget.isAIXABI()) + report_fatal_error("NoCallerSavedRegisters unimplemented on AIX."); + if (TM.isPPC64()) { + if (Subtarget.pairedVectorMemops()) + return CSR_SVR64_SaveAll_VSRP_SaveList; + if (Subtarget.hasAltivec()) + return CSR_SVR64_SaveAll_Altivec_SaveList; + return CSR_SVR64_SaveAll_SaveList; + } + // 32-bit targets. + if (Subtarget.pairedVectorMemops()) + return CSR_SVR32_SaveAll_VSRP_SaveList; + if (Subtarget.hasAltivec()) + return CSR_SVR32_SaveAll_Altivec_SaveList; + if (Subtarget.hasSPE()) + return CSR_SVR32_SaveAll_SPE_SaveList; + return CSR_SVR32_SaveAll_SaveList; + } + // On PPC64, we might need to save r2 (but only if it is not reserved). // We do not need to treat R2 as callee-saved when using PC-Relative calls // because any direct uses of R2 will cause it to be reserved. If the function `````````` </details> https://github.com/llvm/llvm-project/pull/174320 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
