Author: Andy Kaylor Date: 2026-08-12T08:56:53-07:00 New Revision: 30e26d3da53252ee9a658f78b3cd3b957de65331
URL: https://github.com/llvm/llvm-project/commit/30e26d3da53252ee9a658f78b3cd3b957de65331 DIFF: https://github.com/llvm/llvm-project/commit/30e26d3da53252ee9a658f78b3cd3b957de65331.diff LOG: [CIR] Add AArch64TargetCIRGenInfo (#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 Added: clang/lib/CIR/CodeGen/Targets/AArch64.cpp clang/test/CIR/CodeGen/aarch64-ls64-inline-asm-nyi.c Modified: clang/include/clang/CIR/MissingFeatures.h clang/lib/CIR/CodeGen/CIRGenModule.cpp clang/lib/CIR/CodeGen/CMakeLists.txt clang/lib/CIR/CodeGen/TargetInfo.h clang/test/CodeGen/AArch64/sme-inline-callees-streaming-attrs.c Removed: ################################################################################ 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 b55dc71969c74..9ddd65e80f800 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.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..cf69ca681f3f7 --- /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/CodeGen/AArch64/sme-inline-callees-streaming-attrs.c b/clang/test/CodeGen/AArch64/sme-inline-callees-streaming-attrs.c index 2071e66e0d652..b7872dfad6551 100644 --- a/clang/test/CodeGen/AArch64/sme-inline-callees-streaming-attrs.c +++ b/clang/test/CodeGen/AArch64/sme-inline-callees-streaming-attrs.c @@ -1,6 +1,11 @@ // RUN: %clang_cc1 -triple aarch64-none-linux-gnu -emit-llvm -target-feature +sme -target-feature +sme2 %s -DUSE_FLATTEN -o - | FileCheck %s // RUN: %clang_cc1 -triple aarch64-none-linux-gnu -emit-llvm -target-feature +sme -target-feature +sme2 %s -DUSE_ALWAYS_INLINE_STMT -o - | FileCheck %s +// RUN: %if cir-enabled %{%clang_cc1 -triple aarch64-none-linux-gnu -fclangir -emit-llvm -target-feature +sme -target-feature +sme2 %s -DUSE_ALWAYS_INLINE_STMT -o - | FileCheck %s %} +// RUN: %if cir-enabled %{%clang_cc1 -triple aarch64-none-linux-gnu -fclangir -emit-cir -target-feature +sme -target-feature +sme2 %s -DUSE_ALWAYS_INLINE_STMT -o - | FileCheck --check-prefixes=CIR %s %} + +// TODO(cir): Add USE_FLATTEN run lines when CIR supports the `flatten` attribue. + // REQUIRES: aarch64-registered-target extern void was_inlined(void); @@ -32,14 +37,25 @@ void caller(void) { STMT_ATTR fn_streaming_new_zt0(); } // CHECK-LABEL: void @caller() -// CHECK-NEXT: entry: -// CHECK-NEXT: call void @was_inlined +// CHECK: call void @was_inlined // CHECK-NEXT: call void @was_inlined // CHECK-NEXT: call void @fn_streaming // CHECK-NEXT: call void @fn_locally_streaming // CHECK-NEXT: call void @fn_streaming_new_za // CHECK-NEXT: call void @fn_streaming_new_zt0 +// CIR-LABEL: @caller() +// CIR: cir.call @fn() {inline_kind = #cir.inline_kind<always_inline>} +// CIR: cir.call @fn_streaming_compatible() {inline_kind = #cir.inline_kind<always_inline>} +// CIR: cir.call @fn_streaming() +// CIR-NOT: inline_kind +// CIR: cir.call @fn_locally_streaming() +// CIR-NOT: inline_kind +// CIR: cir.call @fn_streaming_new_za() +// CIR-NOT: inline_kind +// CIR: cir.call @fn_streaming_new_zt0() +// CIR-NOT: inline_kind + FN_ATTR void caller_streaming_compatible(void) __arm_streaming_compatible { STMT_ATTR fn(); STMT_ATTR fn_streaming_compatible(); @@ -49,14 +65,26 @@ FN_ATTR void caller_streaming_compatible(void) __arm_streaming_compatible { STMT_ATTR fn_streaming_new_zt0(); } // CHECK-LABEL: void @caller_streaming_compatible() -// CHECK-NEXT: entry: -// CHECK-NEXT: call void @fn +// CHECK: call void @fn // CHECK-NEXT: call void @was_inlined // CHECK-NEXT: call void @fn_streaming // CHECK-NEXT: call void @fn_locally_streaming // CHECK-NEXT: call void @fn_streaming_new_za // CHECK-NEXT: call void @fn_streaming_new_zt0 +// CIR-LABEL: @caller_streaming_compatible() +// CIR: cir.call @fn() +// CIR-NOT: inline_kind +// CIR: cir.call @fn_streaming_compatible() {inline_kind = #cir.inline_kind<always_inline>} +// CIR: cir.call @fn_streaming() +// CIR-NOT: inline_kind +// CIR: cir.call @fn_locally_streaming() +// CIR-NOT: inline_kind +// CIR: cir.call @fn_streaming_new_za() +// CIR-NOT: inline_kind +// CIR: cir.call @fn_streaming_new_zt0() +// CIR-NOT: inline_kind + FN_ATTR void caller_streaming(void) __arm_streaming { STMT_ATTR fn(); STMT_ATTR fn_streaming_compatible(); @@ -66,14 +94,24 @@ FN_ATTR void caller_streaming(void) __arm_streaming { STMT_ATTR fn_streaming_new_zt0(); } // CHECK-LABEL: void @caller_streaming() -// CHECK-NEXT: entry: -// CHECK-NEXT: call void @fn +// CHECK: call void @fn // CHECK-NEXT: call void @was_inlined // CHECK-NEXT: call void @was_inlined // CHECK-NEXT: call void @was_inlined // CHECK-NEXT: call void @fn_streaming_new_za // CHECK-NEXT: call void @fn_streaming_new_zt0 +// CIR-LABEL: @caller_streaming() +// CIR: cir.call @fn() +// CIR-NOT: inline_kind +// CIR: cir.call @fn_streaming_compatible() {inline_kind = #cir.inline_kind<always_inline>} +// CIR: cir.call @fn_streaming() {inline_kind = #cir.inline_kind<always_inline>} +// CIR: cir.call @fn_locally_streaming() {inline_kind = #cir.inline_kind<always_inline>} +// CIR: cir.call @fn_streaming_new_za() +// CIR-NOT: inline_kind +// CIR: cir.call @fn_streaming_new_zt0() +// CIR-NOT: inline_kind + FN_ATTR __arm_locally_streaming void caller_locally_streaming(void) { STMT_ATTR fn(); @@ -84,10 +122,20 @@ void caller_locally_streaming(void) { STMT_ATTR fn_streaming_new_zt0(); } // CHECK-LABEL: void @caller_locally_streaming() -// CHECK-NEXT: entry: -// CHECK-NEXT: call void @fn +// CHECK: call void @fn // CHECK-NEXT: call void @was_inlined // CHECK-NEXT: call void @was_inlined // CHECK-NEXT: call void @was_inlined // CHECK-NEXT: call void @fn_streaming_new_za // CHECK-NEXT: call void @fn_streaming_new_zt0 + +// CIR-LABEL: @caller_locally_streaming() +// CIR: cir.call @fn() +// CIR-NOT: inline_kind +// CIR: cir.call @fn_streaming_compatible() {inline_kind = #cir.inline_kind<always_inline>} +// CIR: cir.call @fn_streaming() {inline_kind = #cir.inline_kind<always_inline>} +// CIR: cir.call @fn_locally_streaming() {inline_kind = #cir.inline_kind<always_inline>} +// CIR: cir.call @fn_streaming_new_za() +// CIR-NOT: inline_kind +// CIR: cir.call @fn_streaming_new_zt0() +// CIR-NOT: inline_kind _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
