llvmbot wrote:

<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang-codegen

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

Reply via email to