[clang] added regcall struct by reg support (PR #95257)

via cfe-commits cfe-commits at lists.llvm.org
Wed Jun 12 07:45:35 PDT 2024


https://github.com/mahesh-attarde created https://github.com/llvm/llvm-project/pull/95257

In Context of __regcall,
Whenever  struct can fit in a register we must use single register to pass whole struct object.
Without this patch, it uses separate registers for each field. With Patch, if Struct size is <= 64
we can use GPR.

 

>From 6d6619f8f7a37906ac45791487a4d63b51a48ad1 Mon Sep 17 00:00:00 2001
From: mahesh-attarde <mahesh.attarde at intel.com>
Date: Wed, 12 Jun 2024 06:15:51 -0700
Subject: [PATCH] added regcall strct by reg support

---
 clang/lib/CodeGen/Targets/X86.cpp | 20 ++++++++++++
 clang/test/CodeGen/regcall3.c     | 53 +++++++++++++++++++++++++++++++
 2 files changed, 73 insertions(+)
 create mode 100644 clang/test/CodeGen/regcall3.c

diff --git a/clang/lib/CodeGen/Targets/X86.cpp b/clang/lib/CodeGen/Targets/X86.cpp
index 43dadf5e724ac..506d106ad65b0 100644
--- a/clang/lib/CodeGen/Targets/X86.cpp
+++ b/clang/lib/CodeGen/Targets/X86.cpp
@@ -148,6 +148,7 @@ class X86_32ABIInfo : public ABIInfo {
 
   Class classify(QualType Ty) const;
   ABIArgInfo classifyReturnType(QualType RetTy, CCState &State) const;
+
   ABIArgInfo classifyArgumentType(QualType RetTy, CCState &State,
                                   unsigned ArgIndex) const;
 
@@ -1306,6 +1307,8 @@ class X86_64ABIInfo : public ABIInfo {
                                            unsigned &NeededSSE,
                                            unsigned &MaxVectorWidth) const;
 
+  bool DoesRegcallStructFitInReg(QualType Ty) const;
+
   bool IsIllegalVectorType(QualType Ty) const;
 
   /// The 0.98 ABI revision clarified a lot of ambiguities,
@@ -2830,6 +2833,20 @@ X86_64ABIInfo::classifyArgumentType(QualType Ty, unsigned freeIntRegs,
   return ABIArgInfo::getDirect(ResType);
 }
 
+bool X86_64ABIInfo::DoesRegcallStructFitInReg(QualType Ty) const {
+  auto RT = Ty->castAs<RecordType>();
+  // For Integer class, Max GPR Size is 64
+  if (getContext().getTypeSize(Ty) > 64)
+    return false;
+  // Struct At hand must not have other non Builtin types
+  for (const auto *FD : RT->getDecl()->fields()) {
+    QualType MTy = FD->getType();
+    if (!MTy->isBuiltinType())
+      return false;
+  }
+  return true;
+}
+
 ABIArgInfo
 X86_64ABIInfo::classifyRegCallStructTypeImpl(QualType Ty, unsigned &NeededInt,
                                              unsigned &NeededSSE,
@@ -2837,6 +2854,9 @@ X86_64ABIInfo::classifyRegCallStructTypeImpl(QualType Ty, unsigned &NeededInt,
   auto RT = Ty->getAs<RecordType>();
   assert(RT && "classifyRegCallStructType only valid with struct types");
 
+  if (DoesRegcallStructFitInReg(Ty))
+    return classifyArgumentType(Ty, UINT_MAX, NeededInt, NeededSSE, true, true);
+
   if (RT->getDecl()->hasFlexibleArrayMember())
     return getIndirectReturnResult(Ty);
 
diff --git a/clang/test/CodeGen/regcall3.c b/clang/test/CodeGen/regcall3.c
new file mode 100644
index 0000000000000..1c83407220861
--- /dev/null
+++ b/clang/test/CodeGen/regcall3.c
@@ -0,0 +1,53 @@
+// RUN: %clang_cc1 -S %s -o - -ffreestanding -triple=x86_64-unknown-linux-gnu | FileCheck %s --check-prefixes=LINUX64
+
+#include <xmmintrin.h>
+struct struct1 { int x; int y; };
+void __regcall v6(int a, float b, struct struct1 c) {}
+
+void v6_caller(){
+    struct struct1 c0;
+    c0.x = 0xa0a0; c0.y = 0xb0b0;
+    int x= 0xf0f0, y = 0x0f0f;
+    v6(x,y,c0);
+}
+
+// LINUX64-LABEL: __regcall3__v6
+// LINUX64: movq	%rcx, -8(%rsp)
+// LINUX64: movl	%eax, -12(%rsp)
+// LINUX64: movss	%xmm0, -16(%rsp)
+
+// LINUX64-LABEL: v6_caller
+// LINUX64: movl	$41120, 16(%rsp)                # imm = 0xA0A0
+// LINUX64: movl	$45232, 20(%rsp)                # imm = 0xB0B0
+// LINUX64: movl	$61680, 12(%rsp)                # imm = 0xF0F0
+// LINUX64: movl	$3855, 8(%rsp)                  # imm = 0xF0F
+// LINUX64: movl	12(%rsp), %eax
+// LINUX64: cvtsi2ssl	8(%rsp), %xmm0
+// LINUX64: movq	16(%rsp), %rcx
+// LINUX64: callq	.L__regcall3__v6$local
+
+
+struct struct2 { int x; float y; };
+void __regcall v31(int a, float b, struct struct2 c) {}
+
+void v31_caller(){
+    struct struct2 c0;
+    c0.x = 0xa0a0; c0.y = 0xb0b0;
+    int x= 0xf0f0, y = 0x0f0f;
+    v31(x,y,c0);
+}
+
+// LINUX64: __regcall3__v31:                        # @__regcall3__v31
+// LINUX64: 	movq	%rcx, -8(%rsp)
+// LINUX64: 	movl	%eax, -12(%rsp)
+// LINUX64: 	movss	%xmm0, -16(%rsp)
+// LINUX64: v31_caller:                             # @v31_caller
+// LINUX64: 	movl	$41120, 16(%rsp)                # imm = 0xA0A0
+// LINUX64: 	movss	.LCPI3_0(%rip), %xmm0           # xmm0 = [4.5232E+4,0.0E+0,0.0E+0,0.0E+0]
+// LINUX64: 	movss	%xmm0, 20(%rsp)
+// LINUX64: 	movl	$61680, 12(%rsp)                # imm = 0xF0F0
+// LINUX64: 	movl	$3855, 8(%rsp)                  # imm = 0xF0F
+// LINUX64: 	movl	12(%rsp), %eax
+// LINUX64: 	cvtsi2ssl	8(%rsp), %xmm0
+// LINUX64: 	movq	16(%rsp), %rcx
+// LINUX64: 	callq	.L__regcall3__v31$local



More information about the cfe-commits mailing list