llvmorg-github-actions[bot] wrote:

<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-backend-x86

Author: AZero13 (AZero13)

<details>
<summary>Changes</summary>

The `preserve_none` calling convention is primarily optimized for JIT 
compilation, hot paths, and avoiding caller-saved registers on non-variadic 
prototypes. On x86-64, it delegates the 12th integer parameter to the `RAX` 
register.

For variadic functions on the x86-64 System V ABI, the caller is required to 
set `%al` to the number of vector (XMM) registers being used to pass arguments. 
Because `preserve_none` delegates unassigned parameters to the standard C 
calling convention, `LowerCall` will emit an assignment of the XMM register 
count to `%al`, clobbering the 12th argument passed in `%eax` (the lower 32 
bits of `RAX`).

Since `preserve_none` fundamentally lacks the register space to pass a 12th 
argument in `RAX` while simultaneously passing the vector register count in 
`AL`, this patch explicitly rejects `preserve_none` on variadic functions in 
both Clang Sema and LLVM's X86 DAG lowering.

---
Full diff: https://github.com/llvm/llvm-project/pull/220301.diff


4 Files Affected:

- (modified) clang/include/clang/Basic/Specifiers.h (+1) 
- (modified) clang/test/Sema/preserve-none-call-conv.c (+2) 
- (modified) llvm/lib/Target/X86/X86ISelLoweringCall.cpp (+10-2) 
- (added) llvm/test/CodeGen/X86/preserve_none_vararg.ll (+10) 


``````````diff
diff --git a/clang/include/clang/Basic/Specifiers.h 
b/clang/include/clang/Basic/Specifiers.h
index c1b7198565f07..fdb13f62f1aa1 100644
--- a/clang/include/clang/Basic/Specifiers.h
+++ b/clang/include/clang/Basic/Specifiers.h
@@ -328,6 +328,7 @@ namespace clang {
     case CC_Swift:
     case CC_SwiftAsync:
     case CC_M68kRTD:
+    case CC_PreserveNone:
       return false;
     default:
       return true;
diff --git a/clang/test/Sema/preserve-none-call-conv.c 
b/clang/test/Sema/preserve-none-call-conv.c
index fc9463726e3f5..6c2f6245cdd57 100644
--- a/clang/test/Sema/preserve-none-call-conv.c
+++ b/clang/test/Sema/preserve-none-call-conv.c
@@ -18,3 +18,5 @@ typedef_fun_t typedef_fun_boo; // expected-note {{previous 
declaration is here}}
 void __attribute__((preserve_none)) typedef_fun_boo(int x) { } // 
expected-error {{function declared 'preserve_none' here was previously declared 
without calling convention}}
 
 struct type_test_boo {} __attribute__((preserve_none));  // expected-warning 
{{'preserve_none' attribute only applies to functions and function pointers}}
+
+void __attribute__((preserve_none)) variadic_boo(int x, ...) { } // 
expected-error {{variadic function cannot use 'preserve_none' calling 
convention}}
diff --git a/llvm/lib/Target/X86/X86ISelLoweringCall.cpp 
b/llvm/lib/Target/X86/X86ISelLoweringCall.cpp
index 9a03da14ee10e..7a92badb00e59 100644
--- a/llvm/lib/Target/X86/X86ISelLoweringCall.cpp
+++ b/llvm/lib/Target/X86/X86ISelLoweringCall.cpp
@@ -1960,7 +1960,10 @@ SDValue X86TargetLowering::LowerFormalArguments(
       MRI.disableCalleeSavedRegister(Pair.first);
   }
 
-  if (CallingConv::PreserveNone == CallConv)
+  if (CallingConv::PreserveNone == CallConv) {
+    if (isVarArg)
+      errorUnsupported(DAG, dl,
+                       "preserve_none calling convention does not support 
variadic functions");
     for (const ISD::InputArg &In : Ins) {
       if (In.Flags.isSwiftSelf() || In.Flags.isSwiftAsync() ||
           In.Flags.isSwiftError()) {
@@ -1969,6 +1972,7 @@ SDValue X86TargetLowering::LowerFormalArguments(
         break;
       }
     }
+  }
 
   return Chain;
 }
@@ -2777,7 +2781,10 @@ 
X86TargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
     InGlue = Chain.getValue(1);
   }
 
-  if (CallingConv::PreserveNone == CallConv)
+  if (CallingConv::PreserveNone == CallConv) {
+    if (isVarArg)
+      errorUnsupported(DAG, dl,
+                       "preserve_none calling convention does not support 
variadic functions");
     for (const ISD::OutputArg &Out : Outs) {
       if (Out.Flags.isSwiftSelf() || Out.Flags.isSwiftAsync() ||
           Out.Flags.isSwiftError()) {
@@ -2786,6 +2793,7 @@ 
X86TargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
         break;
       }
     }
+  }
 
   // Handle result values, copying them out of physregs into vregs that we
   // return.
diff --git a/llvm/test/CodeGen/X86/preserve_none_vararg.ll 
b/llvm/test/CodeGen/X86/preserve_none_vararg.ll
new file mode 100644
index 0000000000000..508b65ef52946
--- /dev/null
+++ b/llvm/test/CodeGen/X86/preserve_none_vararg.ll
@@ -0,0 +1,10 @@
+; RUN: not llc -mtriple=x86_64-unknown-unknown < %s 2>&1 | FileCheck %s
+
+; CHECK: LLVM ERROR: preserve_none calling convention does not support 
variadic functions
+
+declare preserve_none void @vararg_func(i32, ...)
+
+define void @test() {
+  call preserve_none void (i32, ...) @vararg_func(i32 0)
+  ret void
+}

``````````

</details>


https://github.com/llvm/llvm-project/pull/220301
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to