[llvm-branch-commits] [clang] [CIR][CodeGen][NFC] Share the AArch64/AMDGPU target predicates (PR #223425)

Henrich Lauko via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Tue Sep 29 03:25:59 PDT 2026


https://github.com/xlauko updated https://github.com/llvm/llvm-project/pull/223425

>From 5213a374a2bc7ab126d5b33de2a2e9e961268476 Mon Sep 17 00:00:00 2001
From: Henrich Lauko <hlauko at nvidia.com>
Date: Tue, 29 Sep 2026 09:56:12 +0000
Subject: [PATCH 1/3] [CIR][CodeGen][NFC] Share the bit-field and vbase layout
 ABI predicates

isDiscreteBitFieldABI and isOverlappingVBaseABI were equivalent members of
CGRecordLowering and CIRRecordLowering. Both only consult the target's C++
ABI and, for the bit-field rule, the record's ms_struct attribute, so they
become free functions in RecordLayoutUtils.h taking the ASTContext and the
RecordDecl.

No functional change.
---
 .../clang/CodeGenUtils/RecordLayoutUtils.h    | 12 +++++++
 .../CIR/CodeGen/CIRGenRecordLayoutBuilder.cpp | 23 +++-----------
 clang/lib/CodeGen/CGRecordLayoutBuilder.cpp   | 31 +++++--------------
 clang/lib/CodeGenUtils/RecordLayoutUtils.cpp  |  9 ++++++
 4 files changed, 32 insertions(+), 43 deletions(-)

diff --git a/clang/include/clang/CodeGenUtils/RecordLayoutUtils.h b/clang/include/clang/CodeGenUtils/RecordLayoutUtils.h
index 77f14fee5a3b4..2c1ee3c271a3d 100644
--- a/clang/include/clang/CodeGenUtils/RecordLayoutUtils.h
+++ b/clang/include/clang/CodeGenUtils/RecordLayoutUtils.h
@@ -18,6 +18,12 @@
 
 namespace clang::CodeGenUtils {
 
+/// The Microsoft bitfield layout rule allocates discrete storage units of the
+/// field's formal type and only combines adjacent fields of the same formal
+/// type.  We want to emit a layout with these discrete storage units instead
+/// of combining them into a continuous run.
+bool isDiscreteBitFieldABI(const ASTContext &Ctx, const RecordDecl *RD);
+
 /// Return true iff the field is "empty", that is, either a zero-width
 /// bit-field or an \ref isEmptyRecordForLayout.
 bool isEmptyFieldForLayout(const ASTContext &Ctx, const FieldDecl *FD);
@@ -29,6 +35,12 @@ bool isEmptyFieldForLayout(const ASTContext &Ctx, const FieldDecl *FD);
 /// isEmptyRecord.
 bool isEmptyRecordForLayout(const ASTContext &Ctx, QualType T);
 
+/// The Itanium base layout rule allows virtual bases to overlap other bases,
+/// which complicates layout in specific ways.
+///
+/// Note specifically that the ms_struct attribute doesn't change this.
+bool isOverlappingVBaseABI(const ASTContext &Ctx);
+
 } // namespace clang::CodeGenUtils
 
 #endif // LLVM_CLANG_CODEGENUTILS_RECORDLAYOUTUTILS_H
diff --git a/clang/lib/CIR/CodeGen/CIRGenRecordLayoutBuilder.cpp b/clang/lib/CIR/CodeGen/CIRGenRecordLayoutBuilder.cpp
index c2075a245f05c..733cb208fd93e 100644
--- a/clang/lib/CIR/CodeGen/CIRGenRecordLayoutBuilder.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenRecordLayoutBuilder.cpp
@@ -23,6 +23,7 @@
 #include "clang/CIR/Dialect/IR/CIRDataLayout.h"
 #include "clang/CIR/MissingFeatures.h"
 #include "clang/CodeGenUtils/CodeGenUtils.h"
+#include "clang/CodeGenUtils/RecordLayoutUtils.h"
 #include "llvm/Support/Casting.h"
 
 #include <memory>
@@ -133,27 +134,10 @@ struct CIRRecordLowering final {
   /// Helper function to check if the target machine is BigEndian.
   bool isBigEndian() const { return astContext.getTargetInfo().isBigEndian(); }
 
-  // The Itanium base layout rule allows virtual bases to overlap
-  // other bases, which complicates layout in specific ways.
-  //
-  // Note specifically that the ms_struct attribute doesn't change this.
-  bool isOverlappingVBaseABI() {
-    return !astContext.getTargetInfo().getCXXABI().isMicrosoft();
-  }
   // Recursively searches all of the bases to find out if a vbase is
   // not the primary vbase of some base class.
   bool hasOwnStorage(const CXXRecordDecl *decl, const CXXRecordDecl *query);
 
-  /// The Microsoft bitfield layout rule allocates discrete storage
-  /// units of the field's formal type and only combines adjacent
-  /// fields of the same formal type.  We want to emit a layout with
-  /// these discrete storage units instead of combining them into a
-  /// continuous run.
-  bool isDiscreteBitFieldABI() {
-    return astContext.getTargetInfo().getCXXABI().isMicrosoft() ||
-           recordDecl->isMsStruct(astContext);
-  }
-
   CharUnits bitsToCharUnits(uint64_t bitOffset) {
     return astContext.toCharUnitsFromBits(bitOffset);
   }
@@ -445,7 +429,7 @@ void CIRRecordLowering::fillOutputFields() {
 RecordDecl::field_iterator
 CIRRecordLowering::accumulateBitFields(RecordDecl::field_iterator field,
                                        RecordDecl::field_iterator fieldEnd) {
-  if (isDiscreteBitFieldABI()) {
+  if (CodeGenUtils::isDiscreteBitFieldABI(astContext, recordDecl)) {
     // run stores the first element of the current run of bitfields. fieldEnd is
     // used as a special value to note that we don't have a current run. A
     // bitfield run is a contiguous collection of bitfields that can be stored
@@ -1292,7 +1276,8 @@ void CIRRecordLowering::accumulateVBases() {
     CharUnits offset = astRecordLayout.getVBaseClassOffset(baseDecl);
     // If the vbase is a primary virtual base of some base, then it doesn't
     // get its own storage location but instead lives inside of that base.
-    if (isOverlappingVBaseABI() && astContext.isNearlyEmpty(baseDecl) &&
+    if (CodeGenUtils::isOverlappingVBaseABI(astContext) &&
+        astContext.isNearlyEmpty(baseDecl) &&
         !hasOwnStorage(cxxRecordDecl, baseDecl)) {
       members.push_back(MemberInfo(offset, MemberInfo::InfoKind::VBase, nullptr,
                                    cir::RecordMemberKind::Data, baseDecl));
diff --git a/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp b/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp
index d98d7c0c96dc3..7b21b40ff26ed 100644
--- a/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp
+++ b/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp
@@ -22,6 +22,7 @@
 #include "clang/AST/RecordLayout.h"
 #include "clang/Basic/CodeGenOptions.h"
 #include "clang/CodeGenUtils/CodeGenUtils.h"
+#include "clang/CodeGenUtils/RecordLayoutUtils.h"
 #include "llvm/IR/DataLayout.h"
 #include "llvm/IR/DerivedTypes.h"
 #include "llvm/IR/Type.h"
@@ -100,27 +101,9 @@ struct CGRecordLowering {
     return MemberInfo(Offset, MemberInfo::Field, Data);
   }
 
-  /// The Microsoft bitfield layout rule allocates discrete storage
-  /// units of the field's formal type and only combines adjacent
-  /// fields of the same formal type.  We want to emit a layout with
-  /// these discrete storage units instead of combining them into a
-  /// continuous run.
-  bool isDiscreteBitFieldABI() const {
-    return Context.getTargetInfo().getCXXABI().isMicrosoft() ||
-           D->isMsStruct(Context);
-  }
-
   /// Helper function to check if the target machine is BigEndian.
   bool isBE() const { return Context.getTargetInfo().isBigEndian(); }
 
-  /// The Itanium base layout rule allows virtual bases to overlap
-  /// other bases, which complicates layout in specific ways.
-  ///
-  /// Note specifically that the ms_struct attribute doesn't change this.
-  bool isOverlappingVBaseABI() const {
-    return !Context.getTargetInfo().getCXXABI().isMicrosoft();
-  }
-
   /// Wraps llvm::Type::getIntNTy with some implicit arguments.
   llvm::Type *getIntNType(uint64_t NumBits) const {
     unsigned AlignedBits = llvm::alignTo(NumBits, Context.getCharWidth());
@@ -143,7 +126,8 @@ struct CGRecordLowering {
   llvm::Type *getStorageType(const FieldDecl *FD) const {
     llvm::Type *Type = Types.ConvertTypeForMem(FD->getType());
     if (!FD->isBitField()) return Type;
-    if (isDiscreteBitFieldABI()) return Type;
+    if (CodeGenUtils::isDiscreteBitFieldABI(Context, D))
+      return Type;
     return getIntNType(std::min(FD->getBitWidthValue(),
                                 (unsigned)Context.toBits(getSize(Type))));
   }
@@ -406,7 +390,7 @@ RecordDecl::field_iterator
 CGRecordLowering::accumulateBitFields(bool isNonVirtualBaseType,
                                       RecordDecl::field_iterator Field,
                                       RecordDecl::field_iterator FieldEnd) {
-  if (isDiscreteBitFieldABI()) {
+  if (CodeGenUtils::isDiscreteBitFieldABI(Context, D)) {
     // Run stores the first element of the current run of bitfields. FieldEnd is
     // used as a special value to note that we don't have a current run. A
     // bitfield run is a contiguous collection of bitfields that can be stored
@@ -874,7 +858,7 @@ CGRecordLowering::calculateTailClippingOffset(bool isNonVirtualBaseType) const {
   // smaller than the nvsize.  Here we check to see if such a base is placed
   // before the nvsize and set the scissor offset to that, instead of the
   // nvsize.
-  if (!isNonVirtualBaseType && isOverlappingVBaseABI())
+  if (!isNonVirtualBaseType && CodeGenUtils::isOverlappingVBaseABI(Context))
     for (const auto &Base : RD->vbases()) {
       const CXXRecordDecl *BaseDecl = Base.getType()->getAsCXXRecordDecl();
       if (isEmptyRecordForLayout(Context, Base.getType()))
@@ -898,9 +882,8 @@ void CGRecordLowering::accumulateVBases() {
     CharUnits Offset = Layout.getVBaseClassOffset(BaseDecl);
     // If the vbase is a primary virtual base of some base, then it doesn't
     // get its own storage location but instead lives inside of that base.
-    if (isOverlappingVBaseABI() &&
-        Context.isNearlyEmpty(BaseDecl) &&
-        !hasOwnStorage(RD, BaseDecl)) {
+    if (CodeGenUtils::isOverlappingVBaseABI(Context) &&
+        Context.isNearlyEmpty(BaseDecl) && !hasOwnStorage(RD, BaseDecl)) {
       Members.push_back(MemberInfo(Offset, MemberInfo::VBase, nullptr,
                                    BaseDecl));
       continue;
diff --git a/clang/lib/CodeGenUtils/RecordLayoutUtils.cpp b/clang/lib/CodeGenUtils/RecordLayoutUtils.cpp
index 3b8d433dc8759..b41fb61491377 100644
--- a/clang/lib/CodeGenUtils/RecordLayoutUtils.cpp
+++ b/clang/lib/CodeGenUtils/RecordLayoutUtils.cpp
@@ -7,9 +7,14 @@
 //===----------------------------------------------------------------------===//
 
 #include "clang/CodeGenUtils/RecordLayoutUtils.h"
+#include "clang/Basic/TargetInfo.h"
 
 namespace clang::CodeGenUtils {
 
+bool isDiscreteBitFieldABI(const ASTContext &Ctx, const RecordDecl *RD) {
+  return Ctx.getTargetInfo().getCXXABI().isMicrosoft() || RD->isMsStruct(Ctx);
+}
+
 bool isEmptyFieldForLayout(const ASTContext &Ctx, const FieldDecl *FD) {
   if (FD->isZeroLengthBitField())
     return true;
@@ -42,4 +47,8 @@ bool isEmptyRecordForLayout(const ASTContext &Ctx, QualType T) {
   return true;
 }
 
+bool isOverlappingVBaseABI(const ASTContext &Ctx) {
+  return !Ctx.getTargetInfo().getCXXABI().isMicrosoft();
+}
+
 } // namespace clang::CodeGenUtils

>From 034a98e85e9187ce677f0111724fa293c35c20ad Mon Sep 17 00:00:00 2001
From: Henrich Lauko <hlauko at nvidia.com>
Date: Tue, 29 Sep 2026 09:56:18 +0000
Subject: [PATCH 2/3] [CIR][CodeGen][NFC] Share hasOwnStorage

Both record lowerings carried the same recursive walk deciding whether a
virtual base is the primary virtual base of some other base and therefore
has no storage of its own. It touches only the ASTContext's record layouts,
so it becomes a free function in RecordLayoutUtils.h.

No functional change.
---
 .../clang/CodeGenUtils/RecordLayoutUtils.h    |  5 +++++
 .../CIR/CodeGen/CIRGenRecordLayoutBuilder.cpp | 17 +--------------
 clang/lib/CodeGen/CGRecordLayoutBuilder.cpp   | 21 ++++---------------
 clang/lib/CodeGenUtils/RecordLayoutUtils.cpp  | 12 +++++++++++
 4 files changed, 22 insertions(+), 33 deletions(-)

diff --git a/clang/include/clang/CodeGenUtils/RecordLayoutUtils.h b/clang/include/clang/CodeGenUtils/RecordLayoutUtils.h
index 2c1ee3c271a3d..594411e076277 100644
--- a/clang/include/clang/CodeGenUtils/RecordLayoutUtils.h
+++ b/clang/include/clang/CodeGenUtils/RecordLayoutUtils.h
@@ -18,6 +18,11 @@
 
 namespace clang::CodeGenUtils {
 
+/// Recursively searches all of the bases of \p Decl to find out whether
+/// \p Query is not the primary vbase of some base class.
+bool hasOwnStorage(const ASTContext &Ctx, const CXXRecordDecl *Decl,
+                   const CXXRecordDecl *Query);
+
 /// The Microsoft bitfield layout rule allocates discrete storage units of the
 /// field's formal type and only combines adjacent fields of the same formal
 /// type.  We want to emit a layout with these discrete storage units instead
diff --git a/clang/lib/CIR/CodeGen/CIRGenRecordLayoutBuilder.cpp b/clang/lib/CIR/CodeGen/CIRGenRecordLayoutBuilder.cpp
index 733cb208fd93e..63715e1f6e814 100644
--- a/clang/lib/CIR/CodeGen/CIRGenRecordLayoutBuilder.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenRecordLayoutBuilder.cpp
@@ -134,10 +134,6 @@ struct CIRRecordLowering final {
   /// Helper function to check if the target machine is BigEndian.
   bool isBigEndian() const { return astContext.getTargetInfo().isBigEndian(); }
 
-  // Recursively searches all of the bases to find out if a vbase is
-  // not the primary vbase of some base class.
-  bool hasOwnStorage(const CXXRecordDecl *decl, const CXXRecordDecl *query);
-
   CharUnits bitsToCharUnits(uint64_t bitOffset) {
     return astContext.toCharUnitsFromBits(bitOffset);
   }
@@ -1112,17 +1108,6 @@ void CIRRecordLowering::lowerUnion(bool nonVirtualBaseType) {
   packed = !layoutSize.isMultipleOf(getMemberAlignment(storageType));
 }
 
-bool CIRRecordLowering::hasOwnStorage(const CXXRecordDecl *decl,
-                                      const CXXRecordDecl *query) {
-  const ASTRecordLayout &declLayout = astContext.getASTRecordLayout(decl);
-  if (declLayout.isPrimaryBaseVirtual() && declLayout.getPrimaryBase() == query)
-    return false;
-  for (const auto &base : decl->bases())
-    if (!hasOwnStorage(base.getType()->getAsCXXRecordDecl(), query))
-      return false;
-  return true;
-}
-
 /// The AAPCS that defines that, when possible, bit-fields should
 /// be accessed using containers of the declared type width:
 /// When a volatile bit-field is read, and its container does not overlap with
@@ -1278,7 +1263,7 @@ void CIRRecordLowering::accumulateVBases() {
     // get its own storage location but instead lives inside of that base.
     if (CodeGenUtils::isOverlappingVBaseABI(astContext) &&
         astContext.isNearlyEmpty(baseDecl) &&
-        !hasOwnStorage(cxxRecordDecl, baseDecl)) {
+        !CodeGenUtils::hasOwnStorage(astContext, cxxRecordDecl, baseDecl)) {
       members.push_back(MemberInfo(offset, MemberInfo::InfoKind::VBase, nullptr,
                                    cir::RecordMemberKind::Data, baseDecl));
       continue;
diff --git a/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp b/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp
index 7b21b40ff26ed..905382f5ea939 100644
--- a/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp
+++ b/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp
@@ -172,10 +172,6 @@ struct CGRecordLowering {
   void accumulateBases();
   void accumulateVPtrs();
   void accumulateVBases();
-  /// Recursively searches all of the bases to find out if a vbase is
-  /// not the primary vbase of some base class.
-  bool hasOwnStorage(const CXXRecordDecl *Decl,
-                     const CXXRecordDecl *Query) const;
   void calculateZeroInit();
   CharUnits calculateTailClippingOffset(bool isNonVirtualBaseType) const;
   void checkBitfieldClipping(bool isNonVirtualBaseType) const;
@@ -865,7 +861,8 @@ CGRecordLowering::calculateTailClippingOffset(bool isNonVirtualBaseType) const {
         continue;
       // If the vbase is a primary virtual base of some base, then it doesn't
       // get its own storage location but instead lives inside of that base.
-      if (Context.isNearlyEmpty(BaseDecl) && !hasOwnStorage(RD, BaseDecl))
+      if (Context.isNearlyEmpty(BaseDecl) &&
+          !CodeGenUtils::hasOwnStorage(Context, RD, BaseDecl))
         continue;
       ScissorOffset = std::min(ScissorOffset,
                                Layout.getVBaseClassOffset(BaseDecl));
@@ -883,7 +880,8 @@ void CGRecordLowering::accumulateVBases() {
     // If the vbase is a primary virtual base of some base, then it doesn't
     // get its own storage location but instead lives inside of that base.
     if (CodeGenUtils::isOverlappingVBaseABI(Context) &&
-        Context.isNearlyEmpty(BaseDecl) && !hasOwnStorage(RD, BaseDecl)) {
+        Context.isNearlyEmpty(BaseDecl) &&
+        !CodeGenUtils::hasOwnStorage(Context, RD, BaseDecl)) {
       Members.push_back(MemberInfo(Offset, MemberInfo::VBase, nullptr,
                                    BaseDecl));
       continue;
@@ -897,17 +895,6 @@ void CGRecordLowering::accumulateVBases() {
   }
 }
 
-bool CGRecordLowering::hasOwnStorage(const CXXRecordDecl *Decl,
-                                     const CXXRecordDecl *Query) const {
-  const ASTRecordLayout &DeclLayout = Context.getASTRecordLayout(Decl);
-  if (DeclLayout.isPrimaryBaseVirtual() && DeclLayout.getPrimaryBase() == Query)
-    return false;
-  for (const auto &Base : Decl->bases())
-    if (!hasOwnStorage(Base.getType()->getAsCXXRecordDecl(), Query))
-      return false;
-  return true;
-}
-
 void CGRecordLowering::calculateZeroInit() {
   for (std::vector<MemberInfo>::const_iterator Member = Members.begin(),
                                                MemberEnd = Members.end();
diff --git a/clang/lib/CodeGenUtils/RecordLayoutUtils.cpp b/clang/lib/CodeGenUtils/RecordLayoutUtils.cpp
index b41fb61491377..31306470b6da6 100644
--- a/clang/lib/CodeGenUtils/RecordLayoutUtils.cpp
+++ b/clang/lib/CodeGenUtils/RecordLayoutUtils.cpp
@@ -7,10 +7,22 @@
 //===----------------------------------------------------------------------===//
 
 #include "clang/CodeGenUtils/RecordLayoutUtils.h"
+#include "clang/AST/RecordLayout.h"
 #include "clang/Basic/TargetInfo.h"
 
 namespace clang::CodeGenUtils {
 
+bool hasOwnStorage(const ASTContext &Ctx, const CXXRecordDecl *Decl,
+                   const CXXRecordDecl *Query) {
+  const ASTRecordLayout &DeclLayout = Ctx.getASTRecordLayout(Decl);
+  if (DeclLayout.isPrimaryBaseVirtual() && DeclLayout.getPrimaryBase() == Query)
+    return false;
+  for (const auto &Base : Decl->bases())
+    if (!hasOwnStorage(Ctx, Base.getType()->getAsCXXRecordDecl(), Query))
+      return false;
+  return true;
+}
+
 bool isDiscreteBitFieldABI(const ASTContext &Ctx, const RecordDecl *RD) {
   return Ctx.getTargetInfo().getCXXABI().isMicrosoft() || RD->isMsStruct(Ctx);
 }

>From 3a994911503c44e64a4d2f6b75e72065b00ef4cf Mon Sep 17 00:00:00 2001
From: Henrich Lauko <hlauko at nvidia.com>
Date: Tue, 29 Sep 2026 09:56:29 +0000
Subject: [PATCH 3/3] [CIR][CodeGen][NFC] Share the Arm SME inlinability check

Both CodeGens carry the same ArmSMEInlinability bit enum, the same
isStreamingCompatible helper and the same getArmSMEInlinability walk over
the caller's and callee's SME attributes. None of it touches llvm::Type,
llvm::Value or the CIR dialect, so it moves to a new TargetUtils.h. CIR's
copy was marked "TODO(cir): Find a way to share this with classic codegen".

No functional change.
---
 .../include/clang/CodeGenUtils/TargetUtils.h  | 51 ++++++++++++
 clang/lib/CIR/CodeGen/Targets/AArch64.cpp     | 55 +------------
 clang/lib/CodeGen/Targets/AArch64.cpp         | 78 +++++--------------
 clang/lib/CodeGenUtils/CMakeLists.txt         |  1 +
 clang/lib/CodeGenUtils/TargetUtils.cpp        | 50 ++++++++++++
 5 files changed, 123 insertions(+), 112 deletions(-)
 create mode 100644 clang/include/clang/CodeGenUtils/TargetUtils.h
 create mode 100644 clang/lib/CodeGenUtils/TargetUtils.cpp

diff --git a/clang/include/clang/CodeGenUtils/TargetUtils.h b/clang/include/clang/CodeGenUtils/TargetUtils.h
new file mode 100644
index 0000000000000..23d3a9e8dd6c2
--- /dev/null
+++ b/clang/include/clang/CodeGenUtils/TargetUtils.h
@@ -0,0 +1,51 @@
+//===--- TargetUtils.h - Shared target-specific AST queries -----*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file holds the target-specific AST queries that both classic CodeGen
+// and CIR CodeGen need.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_CODEGENUTILS_TARGETUTILS_H
+#define LLVM_CLANG_CODEGENUTILS_TARGETUTILS_H
+
+#include "llvm/ADT/BitmaskEnum.h"
+
+#include <cstdint>
+
+namespace clang {
+class FunctionDecl;
+} // namespace clang
+
+namespace clang::CodeGenUtils {
+
+/// The Arm SME ABI issues that can prevent inlining one function into another.
+enum class ArmSMEInlinability : uint8_t {
+  Ok = 0,
+  ErrorCalleeRequiresNewZA = 1 << 0,
+  ErrorCalleeRequiresNewZT0 = 1 << 1,
+  WarnIncompatibleStreamingModes = 1 << 2,
+  ErrorIncompatibleStreamingModes = 1 << 3,
+
+  IncompatibleStreamingModes = WarnIncompatibleStreamingModes |
+      ErrorIncompatibleStreamingModes,
+
+  LLVM_MARK_AS_BITMASK_ENUM(/*LargestValue=*/ErrorIncompatibleStreamingModes),
+};
+
+// Enable the bitwise operators on ArmSMEInlinability.
+LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE();
+
+/// Determines if there are any Arm SME ABI issues with inlining \p Callee into
+/// \p Caller. Returns the issue (if any) in the ArmSMEInlinability bit enum.
+ArmSMEInlinability getArmSMEInlinability(const FunctionDecl *Caller,
+                                         const FunctionDecl *Callee);
+
+} // namespace clang::CodeGenUtils
+
+#endif // LLVM_CLANG_CODEGENUTILS_TARGETUTILS_H
diff --git a/clang/lib/CIR/CodeGen/Targets/AArch64.cpp b/clang/lib/CIR/CodeGen/Targets/AArch64.cpp
index cf69ca681f3f7..48791b9fa931f 100644
--- a/clang/lib/CIR/CodeGen/Targets/AArch64.cpp
+++ b/clang/lib/CIR/CodeGen/Targets/AArch64.cpp
@@ -16,6 +16,7 @@
 #include "TargetInfo.h"
 #include "clang/AST/Decl.h"
 #include "clang/CIR/MissingFeatures.h"
+#include "clang/CodeGenUtils/TargetUtils.h"
 
 using namespace clang;
 using namespace clang::CIRGen;
@@ -56,61 +57,11 @@ class AArch64TargetCIRGenInfo : public TargetCIRGenInfo {
 
 } // namespace
 
-// TODO(cir): Find a way to share this with classic codegen.
-enum class ArmSMEInlinability : uint8_t {
-  Ok = 0,
-  ErrorCalleeRequiresNewZA = 1 << 0,
-  ErrorCalleeRequiresNewZT0 = 1 << 1,
-  WarnIncompatibleStreamingModes = 1 << 2,
-  ErrorIncompatibleStreamingModes = 1 << 3,
-
-  IncompatibleStreamingModes =
-      WarnIncompatibleStreamingModes | ErrorIncompatibleStreamingModes,
-
-  LLVM_MARK_AS_BITMASK_ENUM(/*LargestValue=*/ErrorIncompatibleStreamingModes),
-};
-
-static bool isStreamingCompatible(const FunctionDecl *fd) {
-  if (const auto *fpt = fd->getType()->getAs<FunctionProtoType>())
-    return fpt->getAArch64SMEAttributes() &
-           clang::FunctionType::SME_PStateSMCompatibleMask;
-  return false;
-}
-
-/// Determines if there are any Arm SME ABI issues with inlining \p Callee into
-/// \p Caller. Returns the issue (if any) in the ArmSMEInlinability bit enum.
-static ArmSMEInlinability getArmSMEInlinability(const FunctionDecl *caller,
-                                                const FunctionDecl *callee) {
-  bool callerIsStreaming =
-      clang::IsArmStreamingFunction(caller, /*IncludeLocallyStreaming=*/true);
-  bool calleeIsStreaming =
-      clang::IsArmStreamingFunction(callee, /*IncludeLocallyStreaming=*/true);
-  bool callerIsStreamingCompatible = isStreamingCompatible(caller);
-  bool calleeIsStreamingCompatible = isStreamingCompatible(callee);
-
-  ArmSMEInlinability inlinability = ArmSMEInlinability::Ok;
-
-  if (!calleeIsStreamingCompatible &&
-      (callerIsStreaming != calleeIsStreaming || callerIsStreamingCompatible)) {
-    if (calleeIsStreaming)
-      inlinability |= ArmSMEInlinability::ErrorIncompatibleStreamingModes;
-    else
-      inlinability |= ArmSMEInlinability::WarnIncompatibleStreamingModes;
-  }
-  if (auto *newAttr = callee->getAttr<ArmNewAttr>()) {
-    if (newAttr->isNewZA())
-      inlinability |= ArmSMEInlinability::ErrorCalleeRequiresNewZA;
-    if (newAttr->isNewZT0())
-      inlinability |= ArmSMEInlinability::ErrorCalleeRequiresNewZT0;
-  }
-
-  return inlinability;
-}
-
 bool AArch64TargetCIRGenInfo::wouldInliningViolateFunctionCallABI(
     const FunctionDecl *caller, const FunctionDecl *callee) const {
   return caller && callee &&
-         getArmSMEInlinability(caller, callee) != ArmSMEInlinability::Ok;
+         CodeGenUtils::getArmSMEInlinability(caller, callee) !=
+             CodeGenUtils::ArmSMEInlinability::Ok;
 }
 
 std::unique_ptr<TargetCIRGenInfo>
diff --git a/clang/lib/CodeGen/Targets/AArch64.cpp b/clang/lib/CodeGen/Targets/AArch64.cpp
index 23a4e5c0ce9ec..e76d7fa21b807 100644
--- a/clang/lib/CodeGen/Targets/AArch64.cpp
+++ b/clang/lib/CodeGen/Targets/AArch64.cpp
@@ -10,6 +10,7 @@
 #include "TargetInfo.h"
 #include "clang/AST/Decl.h"
 #include "clang/Basic/DiagnosticFrontend.h"
+#include "clang/CodeGenUtils/TargetUtils.h"
 #include "llvm/TargetParser/AArch64TargetParser.h"
 
 using namespace clang;
@@ -1191,13 +1192,6 @@ RValue AArch64ABIInfo::EmitMSVAArg(CodeGenFunction &CGF, Address VAListAddr,
                           CharUnits::fromQuantity(8), AllowHigherAlign, Slot);
 }
 
-static bool isStreamingCompatible(const FunctionDecl *F) {
-  if (const auto *T = F->getType()->getAs<FunctionProtoType>())
-    return T->getAArch64SMEAttributes() &
-           FunctionType::SME_PStateSMCompatibleMask;
-  return false;
-}
-
 // Report an error if an argument or return value of type Ty would need to be
 // passed in a floating-point register.
 static void diagnoseIfNeedsFPReg(DiagnosticsEngine &Diags,
@@ -1233,74 +1227,37 @@ void AArch64TargetCodeGenInfo::checkFunctionABI(
   }
 }
 
-enum class ArmSMEInlinability : uint8_t {
-  Ok = 0,
-  ErrorCalleeRequiresNewZA = 1 << 0,
-  ErrorCalleeRequiresNewZT0 = 1 << 1,
-  WarnIncompatibleStreamingModes = 1 << 2,
-  ErrorIncompatibleStreamingModes = 1 << 3,
-
-  IncompatibleStreamingModes =
-      WarnIncompatibleStreamingModes | ErrorIncompatibleStreamingModes,
-
-  LLVM_MARK_AS_BITMASK_ENUM(/*LargestValue=*/ErrorIncompatibleStreamingModes),
-};
-
-/// Determines if there are any Arm SME ABI issues with inlining \p Callee into
-/// \p Caller. Returns the issue (if any) in the ArmSMEInlinability bit enum.
-static ArmSMEInlinability GetArmSMEInlinability(const FunctionDecl *Caller,
-                                                const FunctionDecl *Callee) {
-  bool CallerIsStreaming =
-      IsArmStreamingFunction(Caller, /*IncludeLocallyStreaming=*/true);
-  bool CalleeIsStreaming =
-      IsArmStreamingFunction(Callee, /*IncludeLocallyStreaming=*/true);
-  bool CallerIsStreamingCompatible = isStreamingCompatible(Caller);
-  bool CalleeIsStreamingCompatible = isStreamingCompatible(Callee);
-
-  ArmSMEInlinability Inlinability = ArmSMEInlinability::Ok;
-
-  if (!CalleeIsStreamingCompatible &&
-      (CallerIsStreaming != CalleeIsStreaming || CallerIsStreamingCompatible)) {
-    if (CalleeIsStreaming)
-      Inlinability |= ArmSMEInlinability::ErrorIncompatibleStreamingModes;
-    else
-      Inlinability |= ArmSMEInlinability::WarnIncompatibleStreamingModes;
-  }
-  if (auto *NewAttr = Callee->getAttr<ArmNewAttr>()) {
-    if (NewAttr->isNewZA())
-      Inlinability |= ArmSMEInlinability::ErrorCalleeRequiresNewZA;
-    if (NewAttr->isNewZT0())
-      Inlinability |= ArmSMEInlinability::ErrorCalleeRequiresNewZT0;
-  }
-
-  return Inlinability;
-}
-
 void AArch64TargetCodeGenInfo::checkFunctionCallABIStreaming(
     CodeGenModule &CGM, SourceLocation CallLoc, const FunctionDecl *Caller,
     const FunctionDecl *Callee) const {
   if (!Caller || !Callee || !Callee->hasAttr<AlwaysInlineAttr>())
     return;
 
-  ArmSMEInlinability Inlinability = GetArmSMEInlinability(Caller, Callee);
+  CodeGenUtils::ArmSMEInlinability Inlinability =
+      CodeGenUtils::getArmSMEInlinability(Caller, Callee);
 
-  if ((Inlinability & ArmSMEInlinability::IncompatibleStreamingModes) !=
-      ArmSMEInlinability::Ok)
+  if ((Inlinability &
+       CodeGenUtils::ArmSMEInlinability::IncompatibleStreamingModes) !=
+      CodeGenUtils::ArmSMEInlinability::Ok)
     CGM.getDiags().Report(
         CallLoc,
-        (Inlinability & ArmSMEInlinability::ErrorIncompatibleStreamingModes) ==
-                ArmSMEInlinability::ErrorIncompatibleStreamingModes
+        (Inlinability &
+         CodeGenUtils::ArmSMEInlinability::ErrorIncompatibleStreamingModes) ==
+                CodeGenUtils::ArmSMEInlinability::
+                    ErrorIncompatibleStreamingModes
             ? diag::err_function_always_inline_attribute_mismatch
             : diag::warn_function_always_inline_attribute_mismatch)
         << Caller->getDeclName() << Callee->getDeclName() << "streaming";
 
-  if ((Inlinability & ArmSMEInlinability::ErrorCalleeRequiresNewZA) ==
-      ArmSMEInlinability::ErrorCalleeRequiresNewZA)
+  if ((Inlinability &
+       CodeGenUtils::ArmSMEInlinability::ErrorCalleeRequiresNewZA) ==
+      CodeGenUtils::ArmSMEInlinability::ErrorCalleeRequiresNewZA)
     CGM.getDiags().Report(CallLoc, diag::err_function_always_inline_new_za)
         << Callee->getDeclName();
 
-  if ((Inlinability & ArmSMEInlinability::ErrorCalleeRequiresNewZT0) ==
-      ArmSMEInlinability::ErrorCalleeRequiresNewZT0)
+  if ((Inlinability &
+       CodeGenUtils::ArmSMEInlinability::ErrorCalleeRequiresNewZT0) ==
+      CodeGenUtils::ArmSMEInlinability::ErrorCalleeRequiresNewZT0)
     CGM.getDiags().Report(CallLoc, diag::err_function_always_inline_new_zt0)
         << Callee->getDeclName();
 }
@@ -1339,7 +1296,8 @@ void AArch64TargetCodeGenInfo::checkFunctionCallABI(CodeGenModule &CGM,
 bool AArch64TargetCodeGenInfo::wouldInliningViolateFunctionCallABI(
     const FunctionDecl *Caller, const FunctionDecl *Callee) const {
   return Caller && Callee &&
-         GetArmSMEInlinability(Caller, Callee) != ArmSMEInlinability::Ok;
+         CodeGenUtils::getArmSMEInlinability(Caller, Callee) !=
+             CodeGenUtils::ArmSMEInlinability::Ok;
 }
 
 void AArch64ABIInfo::appendAttributeMangling(TargetClonesAttr *Attr,
diff --git a/clang/lib/CodeGenUtils/CMakeLists.txt b/clang/lib/CodeGenUtils/CMakeLists.txt
index f46ac572a0ce9..edd32da5b5f7c 100644
--- a/clang/lib/CodeGenUtils/CMakeLists.txt
+++ b/clang/lib/CodeGenUtils/CMakeLists.txt
@@ -12,6 +12,7 @@ add_clang_library(clangCodeGenUtils
   ItaniumCXXABIUtils.cpp
   ModuleUtils.cpp
   RecordLayoutUtils.cpp
+  TargetUtils.cpp
 
   LINK_LIBS
   clangAST
diff --git a/clang/lib/CodeGenUtils/TargetUtils.cpp b/clang/lib/CodeGenUtils/TargetUtils.cpp
new file mode 100644
index 0000000000000..2561d6760773b
--- /dev/null
+++ b/clang/lib/CodeGenUtils/TargetUtils.cpp
@@ -0,0 +1,50 @@
+//===--- TargetUtils.cpp - Shared target-specific AST queries ---*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/CodeGenUtils/TargetUtils.h"
+#include "clang/AST/Attr.h"
+#include "clang/AST/Decl.h"
+
+namespace clang::CodeGenUtils {
+
+static bool isStreamingCompatible(const FunctionDecl *F) {
+  if (const auto *T = F->getType()->getAs<FunctionProtoType>())
+    return T->getAArch64SMEAttributes() &
+           FunctionType::SME_PStateSMCompatibleMask;
+  return false;
+}
+
+ArmSMEInlinability getArmSMEInlinability(const FunctionDecl *Caller,
+                                         const FunctionDecl *Callee) {
+  bool CallerIsStreaming =
+      IsArmStreamingFunction(Caller, /*IncludeLocallyStreaming=*/true);
+  bool CalleeIsStreaming =
+      IsArmStreamingFunction(Callee, /*IncludeLocallyStreaming=*/true);
+  bool CallerIsStreamingCompatible = isStreamingCompatible(Caller);
+  bool CalleeIsStreamingCompatible = isStreamingCompatible(Callee);
+
+  ArmSMEInlinability Inlinability = ArmSMEInlinability::Ok;
+
+  if (!CalleeIsStreamingCompatible &&
+      (CallerIsStreaming != CalleeIsStreaming || CallerIsStreamingCompatible)) {
+    if (CalleeIsStreaming)
+      Inlinability |= ArmSMEInlinability::ErrorIncompatibleStreamingModes;
+    else
+      Inlinability |= ArmSMEInlinability::WarnIncompatibleStreamingModes;
+  }
+  if (auto *NewAttr = Callee->getAttr<ArmNewAttr>()) {
+    if (NewAttr->isNewZA())
+      Inlinability |= ArmSMEInlinability::ErrorCalleeRequiresNewZA;
+    if (NewAttr->isNewZT0())
+      Inlinability |= ArmSMEInlinability::ErrorCalleeRequiresNewZT0;
+  }
+
+  return Inlinability;
+}
+
+} // namespace clang::CodeGenUtils



More information about the llvm-branch-commits mailing list