[clang] [Clang][AArch64] Include SME attributes in the name mangling of function types (PR #114209)

Kerry McLaughlin via cfe-commits cfe-commits at lists.llvm.org
Mon Nov 25 08:51:30 PST 2024


https://github.com/kmclaughlin-arm updated https://github.com/llvm/llvm-project/pull/114209

>From ff5b6defc0df704f63fffabc731bcd38a1e24d3b Mon Sep 17 00:00:00 2001
From: Kerry McLaughlin <kerry.mclaughlin at arm.com>
Date: Tue, 15 Oct 2024 15:22:56 +0000
Subject: [PATCH 1/3] [Clang][AArch64] Include SME attributes in the name
 mangling of function types.

Similar to arm_sve_vector_bits, the mangling of function types is implemented as
a pseudo template if there are any SME attributes present, i.e.

  __SME_ATTRS<normal_function_type, streaming_mode, za_state, zt0_state>

For example, the following function:

  void f(svint8_t (*fn)() __arm_streaming) { fn(); }

is mangled as:

  fP9__SME_ATTRSIFu10__SVInt8_tELj1ELj0ELj0EE

See https://github.com/ARM-software/abi-aa/pull/290
---
 clang/lib/AST/ItaniumMangle.cpp               | 41 ++++++++++++
 .../CodeGenCXX/aarch64-mangle-sme-atts.cpp    | 65 +++++++++++++++++++
 2 files changed, 106 insertions(+)
 create mode 100644 clang/test/CodeGenCXX/aarch64-mangle-sme-atts.cpp

diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp
index b3e46508cf596d..2a015b4c45297e 100644
--- a/clang/lib/AST/ItaniumMangle.cpp
+++ b/clang/lib/AST/ItaniumMangle.cpp
@@ -575,6 +575,7 @@ class CXXNameMangler {
   static StringRef getCallingConvQualifierName(CallingConv CC);
   void mangleExtParameterInfo(FunctionProtoType::ExtParameterInfo info);
   void mangleExtFunctionInfo(const FunctionType *T);
+  void mangleSMEAttrs(unsigned SMEAttrs);
   void mangleBareFunctionType(const FunctionProtoType *T, bool MangleReturnType,
                               const FunctionDecl *FD = nullptr);
   void mangleNeonVectorType(const VectorType *T);
@@ -3535,6 +3536,39 @@ void CXXNameMangler::mangleExtFunctionInfo(const FunctionType *T) {
   // FIXME: noreturn
 }
 
+bool hasSharedState(unsigned SMEAttrs) {
+  switch (SMEAttrs) {
+  case FunctionType::ARM_In:
+  case FunctionType::ARM_Out:
+  case FunctionType::ARM_InOut:
+  case FunctionType::ARM_Preserves:
+    return true;
+  default:
+    return false;
+  }
+}
+
+void CXXNameMangler::mangleSMEAttrs(unsigned SMEAttrs) {
+  if (!SMEAttrs)
+    return;
+
+  // Streaming Mode
+  if (SMEAttrs & FunctionType::SME_PStateSMEnabledMask)
+    Out << "Lj1E";
+  else if (SMEAttrs & FunctionType::SME_PStateSMCompatibleMask)
+    Out << "Lj2E";
+  else
+    Out << "Lj0E";
+
+  // ZA & ZT0 State
+  Out << (hasSharedState(FunctionType::getArmZAState(SMEAttrs)) ? "Lj1E"
+                                                                : "Lj0E");
+  Out << (hasSharedState(FunctionType::getArmZT0State(SMEAttrs)) ? "Lj1E"
+                                                                 : "Lj0E");
+
+  return;
+}
+
 void
 CXXNameMangler::mangleExtParameterInfo(FunctionProtoType::ExtParameterInfo PI) {
   // Vendor-specific qualifiers are emitted in reverse alphabetical order.
@@ -3572,6 +3606,11 @@ CXXNameMangler::mangleExtParameterInfo(FunctionProtoType::ExtParameterInfo PI) {
 // <function-type> ::= [<CV-qualifiers>] F [Y]
 //                      <bare-function-type> [<ref-qualifier>] E
 void CXXNameMangler::mangleType(const FunctionProtoType *T) {
+  unsigned SMEAttrs = T->getAArch64SMEAttributes();
+
+  if (SMEAttrs)
+    Out << "11__SME_ATTRSI";
+
   mangleExtFunctionInfo(T);
 
   // Mangle CV-qualifiers, if present.  These are 'this' qualifiers,
@@ -3605,6 +3644,8 @@ void CXXNameMangler::mangleType(const FunctionProtoType *T) {
   // Mangle the ref-qualifier, if present.
   mangleRefQualifier(T->getRefQualifier());
 
+  mangleSMEAttrs(SMEAttrs);
+
   Out << 'E';
 }
 
diff --git a/clang/test/CodeGenCXX/aarch64-mangle-sme-atts.cpp b/clang/test/CodeGenCXX/aarch64-mangle-sme-atts.cpp
new file mode 100644
index 00000000000000..16d4111cdfaaa1
--- /dev/null
+++ b/clang/test/CodeGenCXX/aarch64-mangle-sme-atts.cpp
@@ -0,0 +1,65 @@
+// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sve -target-feature +sme -target-feature +sme2 %s -emit-llvm -o - | FileCheck %s
+
+typedef __attribute__((neon_vector_type(2))) int int32x2_t;
+
+//
+// Streaming-Mode Attributes
+//
+
+// CHECK: define dso_local void @_Z12fn_streamingP11__SME_ATTRSIFvvLj1ELj0ELj0EE( 
+void fn_streaming(void (*foo)() __arm_streaming) { foo(); }
+
+// CHECK: define dso_local void @_Z12fn_streamingP11__SME_ATTRSIFivLj2ELj0ELj0EE(
+void fn_streaming(int (*foo)() __arm_streaming_compatible) { foo(); }
+
+//
+// ZA Attributes
+//
+
+// CHECK: define dso_local void @_Z15fn_za_preservedP11__SME_ATTRSIF11__Int32x2_tvLj0ELj1ELj0EE(
+__arm_new("za") void fn_za_preserved(int32x2_t (*foo)() __arm_preserves("za")) { foo(); }
+
+// CHECK: define dso_local void @_Z8fn_za_inP11__SME_ATTRSIFvu13__SVFloat64_tLj0ELj1ELj0EES_(
+__arm_new("za") void fn_za_in(void (*foo)(__SVFloat64_t) __arm_in("za"), __SVFloat64_t x) { foo(x); }
+
+// CHECK: define dso_local noundef i32 @_Z9fn_za_outP11__SME_ATTRSIFivLj0ELj1ELj0EE(
+__arm_new("za") int fn_za_out(int (*foo)() __arm_out("za")) { return foo(); }
+
+// CHECK: define dso_local void @_Z11fn_za_inoutP11__SME_ATTRSIFvvLj0ELj1ELj0EE(
+__arm_new("za") void fn_za_inout(void (*foo)() __arm_inout("za")) { foo(); }
+
+
+//
+// ZT0 Attributes
+//
+
+// CHECK: define dso_local void @_Z16fn_zt0_preservedP11__SME_ATTRSIFivLj0ELj0ELj1EE(
+__arm_new("zt0") void fn_zt0_preserved(int (*foo)() __arm_preserves("zt0")) { foo(); }
+
+// CHECK: define dso_local void @_Z9fn_zt0_inP11__SME_ATTRSIFivLj0ELj0ELj1EE(
+__arm_new("zt0") void fn_zt0_in(int (*foo)() __arm_in("zt0")) { foo(); }
+
+// CHECK: define dso_local void @_Z10fn_zt0_outP11__SME_ATTRSIFivLj0ELj0ELj1EE(
+__arm_new("zt0") void fn_zt0_out(int (*foo)() __arm_out("zt0")) { foo(); }
+
+// CHECK: define dso_local void @_Z12fn_zt0_inoutP11__SME_ATTRSIFivLj0ELj0ELj1EE(
+__arm_new("zt0") void fn_zt0_inout(int (*foo)() __arm_inout("zt0")) { foo(); }
+
+//
+// No SME Attributes
+//
+
+// CHECK: define dso_local void @_Z12no_sme_attrsPFvvE(
+void no_sme_attrs(void (*foo)()) { foo(); }
+
+// CHECK: define dso_local void @_Z24locally_streaming_callerPFvvE(
+__arm_locally_streaming void locally_streaming_caller(void (*foo)()) { foo(); }
+
+// CHECK: define dso_local void @_Z16streaming_callerv(
+void streaming_caller() __arm_streaming {}
+
+// CHECK: define dso_local void @_Z16za_shared_callerv(
+void za_shared_caller() __arm_in("za") {}
+
+// CHECK: define dso_local void @_Z17zt0_shared_callerv(
+void zt0_shared_caller() __arm_out("zt0") {}

>From 6317fc557364d524e1edc1b18e80da2a4058a5f9 Mon Sep 17 00:00:00 2001
From: Kerry McLaughlin <kerry.mclaughlin at arm.com>
Date: Mon, 4 Nov 2024 13:23:07 +0000
Subject: [PATCH 2/3] - Attributes are now encoded as one bitmask, with each of
 the attributes   represented separately. - Removed hasSharedState.

---
 clang/lib/AST/ItaniumMangle.cpp               | 57 ++++++++++++++-----
 .../CodeGenCXX/aarch64-mangle-sme-atts.cpp    | 31 ++++++----
 2 files changed, 63 insertions(+), 25 deletions(-)

diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp
index 2a015b4c45297e..23c8f255c7c16e 100644
--- a/clang/lib/AST/ItaniumMangle.cpp
+++ b/clang/lib/AST/ItaniumMangle.cpp
@@ -3536,35 +3536,64 @@ void CXXNameMangler::mangleExtFunctionInfo(const FunctionType *T) {
   // FIXME: noreturn
 }
 
-bool hasSharedState(unsigned SMEAttrs) {
+unsigned getZAState(unsigned SMEAttrs) {
   switch (SMEAttrs) {
   case FunctionType::ARM_In:
+    return 1;
   case FunctionType::ARM_Out:
+    return 2;
   case FunctionType::ARM_InOut:
+    return 3;
   case FunctionType::ARM_Preserves:
-    return true;
+    return 4;
   default:
-    return false;
+    return 0;
   }
 }
 
+// The mangling scheme for function types which have SME attributes is implemented as
+// a "pseudo" template:
+//
+//   '__SME_ATTRS<<normal_function_type>, <sme_state>>'
+//
+// Combining the function type with a bitmask representing the streaming and ZA properties
+// of the function's interface. The bits of sme_state are defined as follows:
+//    0:  Streaming Mode
+//    1:  Streaming Compatible
+//    2:  ZA Agnostic
+//  3-5:  ZA State
+//  6-8:  ZT0 State
+//  9-63: 0, reserved for future type attributes.
+//
+// For example:
+//  void f(svint8_t (*fn)() __arm_streaming_compatible __arm_inout("za")) { fn(); }
+//
+// The function fn is described as '__SME_ATTRS<Fu10__SVInt8_tvE, 26u>' and mangled as:
+//
+//  "11__SME_ATTRSI" + function type mangling + "Lj" + bitmask + "EE"
+//
+//  i.e. "11__SME_ATTRSIFu10__SVInt8_tvELj26EE"
+//
 void CXXNameMangler::mangleSMEAttrs(unsigned SMEAttrs) {
   if (!SMEAttrs)
     return;
 
   // Streaming Mode
+  unsigned Bitmask = 0;
   if (SMEAttrs & FunctionType::SME_PStateSMEnabledMask)
-    Out << "Lj1E";
+    Bitmask |= 1;
   else if (SMEAttrs & FunctionType::SME_PStateSMCompatibleMask)
-    Out << "Lj2E";
-  else
-    Out << "Lj0E";
+    Bitmask |= 1 << 1;
+
+  // TODO: Must represent __arm_agnostic("sme_za_state")
+
+  // ZA-State
+  Bitmask |= getZAState(FunctionType::getArmZAState(SMEAttrs)) << 3;
+
+  // ZT0 State
+  Bitmask |= getZAState(FunctionType::getArmZT0State(SMEAttrs)) << 6;
 
-  // ZA & ZT0 State
-  Out << (hasSharedState(FunctionType::getArmZAState(SMEAttrs)) ? "Lj1E"
-                                                                : "Lj0E");
-  Out << (hasSharedState(FunctionType::getArmZT0State(SMEAttrs)) ? "Lj1E"
-                                                                 : "Lj0E");
+  Out << "Lj" << Bitmask << "EE";
 
   return;
 }
@@ -3644,9 +3673,9 @@ void CXXNameMangler::mangleType(const FunctionProtoType *T) {
   // Mangle the ref-qualifier, if present.
   mangleRefQualifier(T->getRefQualifier());
 
-  mangleSMEAttrs(SMEAttrs);
-
   Out << 'E';
+
+  mangleSMEAttrs(SMEAttrs);
 }
 
 void CXXNameMangler::mangleType(const FunctionNoProtoType *T) {
diff --git a/clang/test/CodeGenCXX/aarch64-mangle-sme-atts.cpp b/clang/test/CodeGenCXX/aarch64-mangle-sme-atts.cpp
index 16d4111cdfaaa1..09db59ac621a22 100644
--- a/clang/test/CodeGenCXX/aarch64-mangle-sme-atts.cpp
+++ b/clang/test/CodeGenCXX/aarch64-mangle-sme-atts.cpp
@@ -6,26 +6,26 @@ typedef __attribute__((neon_vector_type(2))) int int32x2_t;
 // Streaming-Mode Attributes
 //
 
-// CHECK: define dso_local void @_Z12fn_streamingP11__SME_ATTRSIFvvLj1ELj0ELj0EE( 
+// CHECK: define dso_local void @_Z12fn_streamingP11__SME_ATTRSIFvvELj1EE
 void fn_streaming(void (*foo)() __arm_streaming) { foo(); }
 
-// CHECK: define dso_local void @_Z12fn_streamingP11__SME_ATTRSIFivLj2ELj0ELj0EE(
-void fn_streaming(int (*foo)() __arm_streaming_compatible) { foo(); }
+// CHECK: define dso_local void @_Z23fn_streaming_compatibleP11__SME_ATTRSIFivELj2EE(
+void fn_streaming_compatible(int (*foo)() __arm_streaming_compatible) { foo(); }
 
 //
 // ZA Attributes
 //
 
-// CHECK: define dso_local void @_Z15fn_za_preservedP11__SME_ATTRSIF11__Int32x2_tvLj0ELj1ELj0EE(
+// CHECK: define dso_local void @_Z15fn_za_preservedP11__SME_ATTRSIF11__Int32x2_tvELj32EE(
 __arm_new("za") void fn_za_preserved(int32x2_t (*foo)() __arm_preserves("za")) { foo(); }
 
-// CHECK: define dso_local void @_Z8fn_za_inP11__SME_ATTRSIFvu13__SVFloat64_tLj0ELj1ELj0EES_(
+// CHECK: define dso_local void @_Z8fn_za_inP11__SME_ATTRSIFvu13__SVFloat64_tELj8EES_(
 __arm_new("za") void fn_za_in(void (*foo)(__SVFloat64_t) __arm_in("za"), __SVFloat64_t x) { foo(x); }
 
-// CHECK: define dso_local noundef i32 @_Z9fn_za_outP11__SME_ATTRSIFivLj0ELj1ELj0EE(
+// CHECK: define dso_local noundef i32 @_Z9fn_za_outP11__SME_ATTRSIFivELj16EE(
 __arm_new("za") int fn_za_out(int (*foo)() __arm_out("za")) { return foo(); }
 
-// CHECK: define dso_local void @_Z11fn_za_inoutP11__SME_ATTRSIFvvLj0ELj1ELj0EE(
+// CHECK: define dso_local void @_Z11fn_za_inoutP11__SME_ATTRSIFvvELj24EE(
 __arm_new("za") void fn_za_inout(void (*foo)() __arm_inout("za")) { foo(); }
 
 
@@ -33,18 +33,27 @@ __arm_new("za") void fn_za_inout(void (*foo)() __arm_inout("za")) { foo(); }
 // ZT0 Attributes
 //
 
-// CHECK: define dso_local void @_Z16fn_zt0_preservedP11__SME_ATTRSIFivLj0ELj0ELj1EE(
+// CHECK: define dso_local void @_Z16fn_zt0_preservedP11__SME_ATTRSIFivELj256EE(
 __arm_new("zt0") void fn_zt0_preserved(int (*foo)() __arm_preserves("zt0")) { foo(); }
 
-// CHECK: define dso_local void @_Z9fn_zt0_inP11__SME_ATTRSIFivLj0ELj0ELj1EE(
+// CHECK: define dso_local void @_Z9fn_zt0_inP11__SME_ATTRSIFivELj64EE(
 __arm_new("zt0") void fn_zt0_in(int (*foo)() __arm_in("zt0")) { foo(); }
 
-// CHECK: define dso_local void @_Z10fn_zt0_outP11__SME_ATTRSIFivLj0ELj0ELj1EE(
+// CHECK: define dso_local void @_Z10fn_zt0_outP11__SME_ATTRSIFivELj128EE(
 __arm_new("zt0") void fn_zt0_out(int (*foo)() __arm_out("zt0")) { foo(); }
 
-// CHECK: define dso_local void @_Z12fn_zt0_inoutP11__SME_ATTRSIFivLj0ELj0ELj1EE(
+// CHECK: define dso_local void @_Z12fn_zt0_inoutP11__SME_ATTRSIFivELj192EE(
 __arm_new("zt0") void fn_zt0_inout(int (*foo)() __arm_inout("zt0")) { foo(); }
 
+//
+// Streaming-mode, ZA & ZT0 Attributes
+//
+
+// CHECK: define dso_local void @_Z17fn_all_attr_typesP11__SME_ATTRSIFivELj282EE(
+__arm_new("za") __arm_new("zt0")
+void fn_all_attr_types(int (*foo)() __arm_streaming_compatible __arm_inout("za") __arm_preserves("zt0"))
+{ foo(); }
+
 //
 // No SME Attributes
 //

>From ff9b38ff6ab50611ed3835438834cb1ec6662238 Mon Sep 17 00:00:00 2001
From: Kerry McLaughlin <kerry.mclaughlin at arm.com>
Date: Mon, 25 Nov 2024 16:27:16 +0000
Subject: [PATCH 3/3] - Added SMEState enum - Renamed getZAState ->
 encodeZAState - Added llvm_unreachable to encodeZAState - Added a link to the
 AAPCS in the comment above mangleSMEAttrs

---
 clang/lib/AST/ItaniumMangle.cpp | 66 ++++++++++++++++++---------------
 1 file changed, 36 insertions(+), 30 deletions(-)

diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp
index 23c8f255c7c16e..e3bedb7770f80a 100644
--- a/clang/lib/AST/ItaniumMangle.cpp
+++ b/clang/lib/AST/ItaniumMangle.cpp
@@ -3536,62 +3536,68 @@ void CXXNameMangler::mangleExtFunctionInfo(const FunctionType *T) {
   // FIXME: noreturn
 }
 
-unsigned getZAState(unsigned SMEAttrs) {
+enum SMEState {
+  Normal = 0,
+  SM_Enabled = 1 << 0,
+  SM_Compatible = 1 << 1,
+  ZA_Agnostic = 1 << 2,
+  ZA_Shift = 3,
+  ZT0_Shift = 6,
+  None = 0b000,
+  In = 0b001,
+  Out = 0b010,
+  InOut = 0b011,
+  Preserves = 0b100
+};
+
+unsigned encodeZAState(unsigned SMEAttrs) {
   switch (SMEAttrs) {
+  case FunctionType::ARM_None:
+    return SMEState::None;
   case FunctionType::ARM_In:
-    return 1;
+    return SMEState::In;
   case FunctionType::ARM_Out:
-    return 2;
+    return SMEState::Out;
   case FunctionType::ARM_InOut:
-    return 3;
+    return SMEState::InOut;
   case FunctionType::ARM_Preserves:
-    return 4;
-  default:
-    return 0;
+    return SMEState::Preserves;
   }
+  llvm_unreachable("Unrecognised SME attribute");
 }
 
-// The mangling scheme for function types which have SME attributes is implemented as
-// a "pseudo" template:
+// As described in the AArch64 ACLE, the mangling scheme for function types
+// which have SME attributes is implemented as a "pseudo" template:
 //
 //   '__SME_ATTRS<<normal_function_type>, <sme_state>>'
 //
-// Combining the function type with a bitmask representing the streaming and ZA properties
-// of the function's interface. The bits of sme_state are defined as follows:
-//    0:  Streaming Mode
-//    1:  Streaming Compatible
-//    2:  ZA Agnostic
-//  3-5:  ZA State
-//  6-8:  ZT0 State
-//  9-63: 0, reserved for future type attributes.
-//
-// For example:
-//  void f(svint8_t (*fn)() __arm_streaming_compatible __arm_inout("za")) { fn(); }
-//
-// The function fn is described as '__SME_ATTRS<Fu10__SVInt8_tvE, 26u>' and mangled as:
+// Combining the function type with a bitmask representing the streaming and ZA
+// properties of the function's interface.
 //
-//  "11__SME_ATTRSI" + function type mangling + "Lj" + bitmask + "EE"
-//
-//  i.e. "11__SME_ATTRSIFu10__SVInt8_tvELj26EE"
+// The mangling scheme is otherwise defined in the appendices to the Procedure
+// Call Standard for the Arm Architecture, see
+// https://github.com/ARM-software/abi-aa/blob/main/aapcs64/aapcs64.rst#appendix-c-mangling
 //
 void CXXNameMangler::mangleSMEAttrs(unsigned SMEAttrs) {
   if (!SMEAttrs)
     return;
 
   // Streaming Mode
-  unsigned Bitmask = 0;
+  unsigned Bitmask = SMEState::Normal;
   if (SMEAttrs & FunctionType::SME_PStateSMEnabledMask)
-    Bitmask |= 1;
+    Bitmask |= SMEState::SM_Enabled;
   else if (SMEAttrs & FunctionType::SME_PStateSMCompatibleMask)
-    Bitmask |= 1 << 1;
+    Bitmask |= SMEState::SM_Compatible;
 
   // TODO: Must represent __arm_agnostic("sme_za_state")
 
   // ZA-State
-  Bitmask |= getZAState(FunctionType::getArmZAState(SMEAttrs)) << 3;
+  Bitmask |= encodeZAState(FunctionType::getArmZAState(SMEAttrs))
+             << SMEState::ZA_Shift;
 
   // ZT0 State
-  Bitmask |= getZAState(FunctionType::getArmZT0State(SMEAttrs)) << 6;
+  Bitmask |= encodeZAState(FunctionType::getArmZT0State(SMEAttrs))
+             << SMEState::ZT0_Shift;
 
   Out << "Lj" << Bitmask << "EE";
 



More information about the cfe-commits mailing list