From ea98dc8b8f508b8393651992830e5e51d3876728 Mon Sep 17 00:00:00 2001 From: Jacek Caban Date: Sat, 27 Jul 2024 14:29:05 +0200 Subject: [PATCH] [clang][ARM64EC] Add support for hybrid_patchable attribute. (#99478) --- clang/docs/ReleaseNotes.rst | 3 ++ clang/include/clang/Basic/Attr.td | 9 +++++ clang/include/clang/Basic/AttrDocs.td | 10 ++++++ .../clang/Basic/DiagnosticSemaKinds.td | 3 ++ clang/lib/CodeGen/CodeGenFunction.cpp | 3 ++ clang/lib/Sema/SemaDecl.cpp | 5 +++ clang/lib/Sema/SemaDeclAttr.cpp | 3 ++ clang/test/CodeGen/arm64ec-hybrid-patchable.c | 34 +++++++++++++++++++ ...a-attribute-supported-attributes-list.test | 1 + 9 files changed, 71 insertions(+) create mode 100644 clang/test/CodeGen/arm64ec-hybrid-patchable.c diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 4f1a916aad9d2b..ddad083571eb19 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -116,6 +116,9 @@ Attribute Changes in Clang - Introduced a new format attribute ``__attribute__((format(syslog, 1, 2)))`` from OpenBSD. +- The ``hybrid_patchable`` attribute is now supported on ARM64EC targets. It can be used to specify + that a function requires an additional x86-64 thunk, which may be patched at runtime. + Improvements to Clang's diagnostics ----------------------------------- diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index 4825979a974d22..46d0a66d59c375 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -477,6 +477,9 @@ def TargetELF : TargetSpec { def TargetELFOrMachO : TargetSpec { let ObjectFormats = ["ELF", "MachO"]; } +def TargetWindowsArm64EC : TargetSpec { + let CustomCode = [{ Target.getTriple().isWindowsArm64EC() }]; +} def TargetSupportsInitPriority : TargetSpec { let CustomCode = [{ !Target.getTriple().isOSzOS() }]; @@ -4027,6 +4030,12 @@ def SelectAny : InheritableAttr { let SimpleHandler = 1; } +def HybridPatchable : InheritableAttr, TargetSpecificAttr { + let Spellings = [Declspec<"hybrid_patchable">, Clang<"hybrid_patchable">]; + let Subjects = SubjectList<[Function]>; + let Documentation = [HybridPatchableDocs]; +} + def Thread : Attr { let Spellings = [Declspec<"thread">]; let LangOpts = [MicrosoftExt]; diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td index 99738812c81579..b5d468eb5ec952 100644 --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -5985,6 +5985,16 @@ For more information see or `msvc documentation `_. }]; } +def HybridPatchableDocs : Documentation { + let Category = DocCatFunction; + let Content = [{ +The ``hybrid_patchable`` attribute declares an ARM64EC function with an additional +x86-64 thunk, which may be patched at runtime. + +For more information see +`ARM64EC ABI documentation `_. +}]; } + def WebAssemblyExportNameDocs : Documentation { let Category = DocCatFunction; let Content = [{ diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index e768151ce23c14..9e6d85c469d641 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -3681,6 +3681,9 @@ def err_attribute_weak_static : Error< "weak declaration cannot have internal linkage">; def err_attribute_selectany_non_extern_data : Error< "'selectany' can only be applied to data items with external linkage">; +def warn_attribute_hybrid_patchable_non_extern : Warning< + "'hybrid_patchable' is ignored on functions without external linkage">, + InGroup; def err_declspec_thread_on_thread_variable : Error< "'__declspec(thread)' applied to variable that already has a " "thread-local storage specifier">; diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp index d6078696a7d91f..af201554898f31 100644 --- a/clang/lib/CodeGen/CodeGenFunction.cpp +++ b/clang/lib/CodeGen/CodeGenFunction.cpp @@ -991,6 +991,9 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy, if (D && D->hasAttr()) Fn->addFnAttr(llvm::Attribute::NoProfile); + if (D && D->hasAttr()) + Fn->addFnAttr(llvm::Attribute::HybridPatchable); + if (D) { // Function attributes take precedence over command line flags. if (auto *A = D->getAttr()) { diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 7bdecb2546f30a..694a754646f274 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -6890,6 +6890,11 @@ static void checkAttributesAfterMerging(Sema &S, NamedDecl &ND) { } } + if (HybridPatchableAttr *Attr = ND.getAttr()) { + if (!ND.isExternallyVisible()) + S.Diag(Attr->getLocation(), + diag::warn_attribute_hybrid_patchable_non_extern); + } if (const InheritableAttr *Attr = getDLLAttr(&ND)) { auto *VD = dyn_cast(&ND); bool IsAnonymousNS = false; diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index 8b0a6bf4caf48a..003d7a24f01507 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -6871,6 +6871,9 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL, case ParsedAttr::AT_MSConstexpr: handleMSConstexprAttr(S, D, AL); break; + case ParsedAttr::AT_HybridPatchable: + handleSimpleAttribute(S, D, AL); + break; // HLSL attributes: case ParsedAttr::AT_HLSLNumThreads: diff --git a/clang/test/CodeGen/arm64ec-hybrid-patchable.c b/clang/test/CodeGen/arm64ec-hybrid-patchable.c new file mode 100644 index 00000000000000..4d1fa12afd2aae --- /dev/null +++ b/clang/test/CodeGen/arm64ec-hybrid-patchable.c @@ -0,0 +1,34 @@ +// REQUIRES: aarch64-registered-target +// RUN: %clang_cc1 -triple arm64ec-pc-windows -fms-extensions -emit-llvm -o - %s -verify | FileCheck %s + +// CHECK: ; Function Attrs: hybrid_patchable noinline nounwind optnone +// CHECK-NEXT: define dso_local i32 @func() #0 { +int __attribute__((hybrid_patchable)) func(void) { return 1; } + +// CHECK: ; Function Attrs: hybrid_patchable noinline nounwind optnone +// CHECK-NEXT: define dso_local i32 @func2() #0 { +int __declspec(hybrid_patchable) func2(void) { return 2; } + +// CHECK: ; Function Attrs: hybrid_patchable noinline nounwind optnone +// CHECK-NEXT: define dso_local i32 @func3() #0 { +int __declspec(hybrid_patchable) func3(void); +int func3(void) { return 3; } + +// CHECK: ; Function Attrs: hybrid_patchable noinline nounwind optnone +// CHECK-NEXT: define dso_local i32 @func4() #0 { +[[clang::hybrid_patchable]] int func4(void); +int func4(void) { return 3; } + +// CHECK: ; Function Attrs: hybrid_patchable noinline nounwind optnone +// CHECK-NEXT: define internal void @static_func() #0 { +// expected-warning@+1 {{'hybrid_patchable' is ignored on functions without external linkage}} +static void __declspec(hybrid_patchable) static_func(void) {} + +// CHECK: ; Function Attrs: hybrid_patchable noinline nounwind optnone +// CHECK-NEXT: define linkonce_odr dso_local i32 @func5() #0 comdat { +int inline __declspec(hybrid_patchable) func5(void) { return 4; } + +void caller(void) { + static_func(); + func5(); +} diff --git a/clang/test/Misc/pragma-attribute-supported-attributes-list.test b/clang/test/Misc/pragma-attribute-supported-attributes-list.test index 33f9c2f51363c6..e082db698ef0ce 100644 --- a/clang/test/Misc/pragma-attribute-supported-attributes-list.test +++ b/clang/test/Misc/pragma-attribute-supported-attributes-list.test @@ -83,6 +83,7 @@ // CHECK-NEXT: HIPManaged (SubjectMatchRule_variable) // CHECK-NEXT: HLSLResourceClass (SubjectMatchRule_record_not_is_union) // CHECK-NEXT: Hot (SubjectMatchRule_function) +// CHECK-NEXT: HybridPatchable (SubjectMatchRule_function) // CHECK-NEXT: IBAction (SubjectMatchRule_objc_method_is_instance) // CHECK-NEXT: IFunc (SubjectMatchRule_function) // CHECK-NEXT: InitPriority (SubjectMatchRule_variable)