https://github.com/andykaylor created 
https://github.com/llvm/llvm-project/pull/215424

This adds an AArch64-specific implementation of TargetCIRGenInfo and adds 
handlers for the functions that require AArch64-specific handling. I've 
implemented the wouldInliningViolateFunctionCallABI function (because that 
seemed easier than deciding when to report NYI), generated an NYI error for 
isScalarizableAsmOperand in the one case where it needs to do something other 
than forward the call to the based class, and added MissingFeatures asserts for 
setTargetAttributes (because CIR doesn't support the features it wants to add 
attributes for yet).

Assisted-by: Cursor / various models

>From 1c05a8c3de6afe8d7cac011ecf39a22149b135e6 Mon Sep 17 00:00:00 2001
From: Andy Kaylor <[email protected]>
Date: Mon, 10 Aug 2026 15:28:44 -0700
Subject: [PATCH] [CIR] Add AArch64TargetCIRGenInfo

This adds an AArch64-specific implementation of TargetCIRGenInfo and
adds handlers for the functions that require AArch64-specific handling.
I've implemented the wouldInliningViolateFunctionCallABI function (because
that seemed easier than deciding when to report NYI), generated an NYI error
for isScalarizableAsmOperand in the one case where it needs to do something
other than forward the call to the based class, and added MissingFeatures
asserts for setTargetAttributes (because CIR doesn't support the features
it wants to add attributes for yet).

Assisted-by: Cursor / various models
---
 clang/include/clang/CIR/MissingFeatures.h     |   1 +
 clang/lib/CIR/CodeGen/CIRGenModule.cpp        |   6 +
 clang/lib/CIR/CodeGen/CMakeLists.txt          |   1 +
 clang/lib/CIR/CodeGen/TargetInfo.cpp          |   1 +
 clang/lib/CIR/CodeGen/TargetInfo.h            |   3 +
 clang/lib/CIR/CodeGen/Targets/AArch64.cpp     | 119 ++++++++++++++++++
 .../CIR/CodeGen/aarch64-ls64-inline-asm-nyi.c |  16 +++
 .../aarch64-sme-callsite-inline-attrs.c       |  91 ++++++++++++++
 8 files changed, 238 insertions(+)
 create mode 100644 clang/lib/CIR/CodeGen/Targets/AArch64.cpp
 create mode 100644 clang/test/CIR/CodeGen/aarch64-ls64-inline-asm-nyi.c
 create mode 100644 clang/test/CIR/CodeGen/aarch64-sme-callsite-inline-attrs.c

diff --git a/clang/include/clang/CIR/MissingFeatures.h 
b/clang/include/clang/CIR/MissingFeatures.h
index 02475b70c5dcd..3961df31e9dde 100644
--- a/clang/include/clang/CIR/MissingFeatures.h
+++ b/clang/include/clang/CIR/MissingFeatures.h
@@ -194,6 +194,7 @@ struct MissingFeatures {
   static bool assignMemcpyizer() { return false; }
   static bool astVarDeclInterface() { return false; }
   static bool attributeNoBuiltin() { return false; }
+  static bool branchProtection() { return false; }
   static bool builtinCall() { return false; }
   static bool builtinCallF128() { return false; }
   static bool builtinBitCountExpr() { return false; }
diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.cpp 
b/clang/lib/CIR/CodeGen/CIRGenModule.cpp
index ae9cad0b7c30f..b2f3fe195ac33 100644
--- a/clang/lib/CIR/CodeGen/CIRGenModule.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenModule.cpp
@@ -308,6 +308,12 @@ const TargetCIRGenInfo 
&CIRGenModule::getTargetCIRGenInfo() {
       return *theTargetCIRGenInfo;
     }
   }
+  case llvm::Triple::aarch64:
+  case llvm::Triple::aarch64_32:
+  case llvm::Triple::aarch64_be: {
+    theTargetCIRGenInfo = createAArch64TargetCIRGenInfo(genTypes);
+    return *theTargetCIRGenInfo;
+  }
   case llvm::Triple::nvptx:
   case llvm::Triple::nvptx64:
     theTargetCIRGenInfo = createNVPTXTargetCIRGenInfo(genTypes);
diff --git a/clang/lib/CIR/CodeGen/CMakeLists.txt 
b/clang/lib/CIR/CodeGen/CMakeLists.txt
index 1fe9b25dd786c..3ea96a8ea05e9 100644
--- a/clang/lib/CIR/CodeGen/CMakeLists.txt
+++ b/clang/lib/CIR/CodeGen/CMakeLists.txt
@@ -56,6 +56,7 @@ add_clang_library(clangCIR
   CIRGenTypes.cpp
   CIRGenVTables.cpp
   TargetInfo.cpp
+  Targets/AArch64.cpp
   Targets/AMDGPU.cpp
   Targets/NVPTX.cpp
   Targets/SPIRV.cpp
diff --git a/clang/lib/CIR/CodeGen/TargetInfo.cpp 
b/clang/lib/CIR/CodeGen/TargetInfo.cpp
index ba7eeb29dd252..584140a20f838 100644
--- a/clang/lib/CIR/CodeGen/TargetInfo.cpp
+++ b/clang/lib/CIR/CodeGen/TargetInfo.cpp
@@ -120,6 +120,7 @@ class X8664TargetCIRGenInfo : public TargetCIRGenInfo {
   X8664TargetCIRGenInfo(CIRGenTypes &cgt)
       : TargetCIRGenInfo(std::make_unique<X8664ABIInfo>(cgt)) {}
 };
+
 } // namespace
 
 std::unique_ptr<TargetCIRGenInfo>
diff --git a/clang/lib/CIR/CodeGen/TargetInfo.h 
b/clang/lib/CIR/CodeGen/TargetInfo.h
index e720a4ad2ec5c..eb9e431034bc9 100644
--- a/clang/lib/CIR/CodeGen/TargetInfo.h
+++ b/clang/lib/CIR/CodeGen/TargetInfo.h
@@ -171,6 +171,9 @@ void setAMDGPUTargetFunctionAttributes(const clang::Decl 
*decl,
 
 std::unique_ptr<TargetCIRGenInfo> createX8664TargetCIRGenInfo(CIRGenTypes 
&cgt);
 
+std::unique_ptr<TargetCIRGenInfo>
+createAArch64TargetCIRGenInfo(CIRGenTypes &cgt);
+
 std::unique_ptr<TargetCIRGenInfo> createNVPTXTargetCIRGenInfo(CIRGenTypes 
&cgt);
 
 std::unique_ptr<TargetCIRGenInfo> createSPIRVTargetCIRGenInfo(CIRGenTypes 
&cgt);
diff --git a/clang/lib/CIR/CodeGen/Targets/AArch64.cpp 
b/clang/lib/CIR/CodeGen/Targets/AArch64.cpp
new file mode 100644
index 0000000000000..5407beae5c696
--- /dev/null
+++ b/clang/lib/CIR/CodeGen/Targets/AArch64.cpp
@@ -0,0 +1,119 @@
+//===---- AArch64.cpp - AArch64-specific CIR CodeGen 
----------------------===//
+//
+// 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 provides AArch64-specific CIR CodeGen logic.
+//
+//===----------------------------------------------------------------------===//
+
+#include "../ABIInfo.h"
+#include "../CIRGenFunction.h"
+#include "../CIRGenModule.h"
+#include "../TargetInfo.h"
+#include "clang/AST/Decl.h"
+#include "clang/CIR/MissingFeatures.h"
+
+using namespace clang;
+using namespace clang::CIRGen;
+
+namespace {
+
+class AArch64ABIInfo : public ABIInfo {
+public:
+  AArch64ABIInfo(CIRGenTypes &cgt) : ABIInfo(cgt) {}
+};
+
+class AArch64TargetCIRGenInfo : public TargetCIRGenInfo {
+public:
+  AArch64TargetCIRGenInfo(CIRGenTypes &cgt)
+      : TargetCIRGenInfo(std::make_unique<AArch64ABIInfo>(cgt)) {}
+
+  void setTargetAttributes(const Decl *d, mlir::Operation *gv,
+                           CIRGenModule &cgm) const override {
+    auto fn = mlir::dyn_cast<cir::FuncOp>(gv);
+    if (!fn)
+      return;
+    assert(!cir::MissingFeatures::branchProtection());
+    assert(!cir::MissingFeatures::pointerAuthentication());
+  }
+
+  bool isScalarizableAsmOperand(CIRGenFunction &cgf,
+                                mlir::Type ty) const override {
+    if (cgf.getTarget().hasFeature("ls64")) {
+      cgf.cgm.errorNYI("AArch64 LS64 scalarizable asm operand");
+      return true;
+    }
+    return TargetCIRGenInfo::isScalarizableAsmOperand(cgf, ty);
+  }
+
+  bool wouldInliningViolateFunctionCallABI(
+      const FunctionDecl *caller, const FunctionDecl *callee) const override;
+};
+
+} // 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;
+}
+
+std::unique_ptr<TargetCIRGenInfo>
+clang::CIRGen::createAArch64TargetCIRGenInfo(CIRGenTypes &cgt) {
+  return std::make_unique<AArch64TargetCIRGenInfo>(cgt);
+}
diff --git a/clang/test/CIR/CodeGen/aarch64-ls64-inline-asm-nyi.c 
b/clang/test/CIR/CodeGen/aarch64-ls64-inline-asm-nyi.c
new file mode 100644
index 0000000000000..60486cf9c0c5f
--- /dev/null
+++ b/clang/test/CIR/CodeGen/aarch64-ls64-inline-asm-nyi.c
@@ -0,0 +1,16 @@
+// RUN: not %clang_cc1 -triple aarch64 -target-feature +ls64 -fclangir \
+// RUN:   -emit-cir %s -o /dev/null 2>&1 | FileCheck %s
+
+struct data512 {
+  unsigned long long data[8];
+};
+
+void store(const struct data512 *input, void *addr) {
+  __asm__ volatile("st64b %0, [%1]"
+                   :
+                   : "r"(*input), "r"(addr)
+                   : "memory");
+}
+
+// CHECK: error: ClangIR code gen Not Yet Implemented: AArch64 LS64
+// CHECK-SAME: scalarizable asm operand
diff --git a/clang/test/CIR/CodeGen/aarch64-sme-callsite-inline-attrs.c 
b/clang/test/CIR/CodeGen/aarch64-sme-callsite-inline-attrs.c
new file mode 100644
index 0000000000000..5f2c98bd7abca
--- /dev/null
+++ b/clang/test/CIR/CodeGen/aarch64-sme-callsite-inline-attrs.c
@@ -0,0 +1,91 @@
+// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sme \
+// RUN:   -target-feature +sme2 -fclangir -emit-cir %s -o %t.cir
+// RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s
+// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sme \
+// RUN:   -target-feature +sme2 -fclangir -emit-llvm %s -o %t-cir.ll
+// RUN: FileCheck --check-prefix=LLVM --input-file=%t-cir.ll %s
+// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sme \
+// RUN:   -target-feature +sme2 -emit-llvm %s -o %t.ll
+// RUN: FileCheck --check-prefix=LLVM --input-file=%t.ll %s
+
+volatile int value;
+
+__attribute__((noinline)) static void was_inlined(void) { ++value; }
+
+void normal(void) { was_inlined(); }
+void compatible(void) __arm_streaming_compatible { was_inlined(); }
+void streaming(void) __arm_streaming { was_inlined(); }
+__arm_new("za") void new_za(void) { was_inlined(); }
+__arm_new("zt0") void new_zt0(void) { was_inlined(); }
+
+// CIR-LABEL: cir.func{{.*}} @normal_caller()
+// LLVM-LABEL: define{{.*}} void @normal_caller()
+void normal_caller(void) {
+  [[clang::always_inline]] normal();
+  // CIR: cir.call @normal() {inline_kind = #cir.inline_kind<always_inline>}
+  // LLVM-NOT: call void @normal()
+  // LLVM: call void @was_inlined()
+
+  [[clang::always_inline]] compatible();
+  // CIR: cir.call @compatible() {inline_kind = 
#cir.inline_kind<always_inline>}
+  // LLVM-NOT: call void @compatible()
+  // LLVM: call void @was_inlined()
+
+  [[clang::always_inline]] streaming();
+  // CIR: cir.call @streaming()
+  // CIR-NOT: inline_kind
+  // LLVM: call void @streaming()
+
+  [[clang::always_inline]] new_za();
+  // CIR: cir.call @new_za()
+  // CIR-NOT: inline_kind
+  // LLVM: call void @new_za()
+
+  [[clang::always_inline]] new_zt0();
+  // CIR: cir.call @new_zt0()
+  // CIR-NOT: inline_kind
+  // CIR: cir.return
+  // LLVM: call void @new_zt0()
+  // LLVM: ret void
+}
+
+// CIR-LABEL: cir.func{{.*}} @compatible_caller()
+// LLVM-LABEL: define{{.*}} void @compatible_caller()
+void compatible_caller(void) __arm_streaming_compatible {
+  [[clang::always_inline]] normal();
+  // CIR: cir.call @normal()
+  // CIR-NOT: inline_kind
+  // LLVM: call void @normal()
+
+  [[clang::always_inline]] compatible();
+  // CIR: cir.call @compatible() {inline_kind = 
#cir.inline_kind<always_inline>}
+  // LLVM-NOT: call void @compatible()
+  // LLVM: call void @was_inlined()
+
+  [[clang::always_inline]] streaming();
+  // CIR: cir.call @streaming()
+  // CIR-NOT: inline_kind
+  // CIR: cir.return
+  // LLVM: call void @streaming()
+  // LLVM: ret void
+}
+
+// CIR-LABEL: cir.func{{.*}} @streaming_caller()
+// LLVM-LABEL: define{{.*}} void @streaming_caller()
+void streaming_caller(void) __arm_streaming {
+  [[clang::always_inline]] normal();
+  // CIR: cir.call @normal()
+  // CIR-NOT: inline_kind
+  // LLVM: call void @normal()
+
+  [[clang::always_inline]] compatible();
+  // CIR: cir.call @compatible() {inline_kind = 
#cir.inline_kind<always_inline>}
+  // LLVM-NOT: call void @compatible()
+  // LLVM: call void @was_inlined()
+
+  [[clang::always_inline]] streaming();
+  // CIR: cir.call @streaming() {inline_kind = #cir.inline_kind<always_inline>}
+  // LLVM-NOT: call void @streaming()
+  // LLVM: call void @was_inlined()
+  // LLVM: ret void
+}

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

Reply via email to