From a44c434b68e515ce9f2627367c83ff6b22328261 Mon Sep 17 00:00:00 2001 From: Fangrui Song Date: Sat, 4 Jan 2020 15:39:19 -0800 Subject: [PATCH] Support function attribute patchable_function_entry This feature is generic. Make it applicable for AArch64 and X86 because the backend has only implemented NOP insertion for AArch64 and X86. Reviewed By: nickdesaulniers, aaron.ballman Differential Revision: https://reviews.llvm.org/D72221 --- clang/include/clang/Basic/Attr.td | 9 +++++++++ clang/include/clang/Basic/AttrDocs.td | 12 +++++++++++ clang/lib/CodeGen/CodeGenFunction.cpp | 8 +++++++- clang/lib/Sema/SemaDeclAttr.cpp | 23 ++++++++++++++++++++++ clang/test/CodeGen/patchable-function-entry.c | 21 ++++++++++++++++++++ ...pragma-attribute-supported-attributes-list.test | 1 + clang/test/Sema/patchable-function-entry-attr.c | 17 ++++++++++++++++ clang/test/Sema/patchable-function-entry-attr.cpp | 9 +++++++++ 8 files changed, 99 insertions(+), 1 deletion(-) create mode 100644 clang/test/CodeGen/patchable-function-entry.c create mode 100644 clang/test/Sema/patchable-function-entry-attr.c create mode 100644 clang/test/Sema/patchable-function-entry-attr.cpp diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index d1c42e8..16556b5 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -683,6 +683,15 @@ def XRayLogArgs : InheritableAttr { let Documentation = [XRayDocs]; } +def PatchableFunctionEntry + : InheritableAttr, + TargetSpecificAttr> { + let Spellings = [GCC<"patchable_function_entry">]; + let Subjects = SubjectList<[Function, ObjCMethod]>; + let Args = [UnsignedArgument<"Count">, DefaultIntArgument<"Offset", 0>]; + let Documentation = [PatchableFunctionEntryDocs]; +} + def TLSModel : InheritableAttr { let Spellings = [GCC<"tls_model">]; let Subjects = SubjectList<[TLSVar], ErrorDiag>; diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td index 6692c38..03d36ae 100644 --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -3988,6 +3988,18 @@ If a function has neither of these attributes, they become subject to the XRay h }]; } +def PatchableFunctionEntryDocs : Documentation { + let Category = DocCatFunction; + let Content = [{ +``__attribute__((patchable_function_entry(N,M)))`` is used to generate M NOPs +before the function entry and N-M NOPs after the function entry. This attribute +takes precedence over the command line option ``-fpatchable-function-entry=N,M``. +``M`` defaults to 0 if omitted. + +Currently, only M=0 is supported. +}]; +} + def TransparentUnionDocs : Documentation { let Category = DocCatDecl; let Content = [{ diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp index a717f43..e59fe06 100644 --- a/clang/lib/CodeGen/CodeGenFunction.cpp +++ b/clang/lib/CodeGen/CodeGenFunction.cpp @@ -799,8 +799,8 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy, FD->getBody()->getStmtClass() == Stmt::CoroutineBodyStmtClass) SanOpts.Mask &= ~SanitizerKind::Null; - // Apply xray attributes to the function (as a string, for now) if (D) { + // Apply xray attributes to the function (as a string, for now) if (const auto *XRayAttr = D->getAttr()) { if (CGM.getCodeGenOpts().XRayInstrumentationBundle.has( XRayInstrKind::Function)) { @@ -819,6 +819,12 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy, "xray-instruction-threshold", llvm::itostr(CGM.getCodeGenOpts().XRayInstructionThreshold)); } + + if (const auto *Attr = D->getAttr()) { + // Attr->getStart is currently ignored. + Fn->addFnAttr("patchable-function-entry", + std::to_string(Attr->getCount())); + } } // Add no-jump-tables value. diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index 142c6f1..5c51b0f 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -4915,6 +4915,25 @@ static void handleXRayLogArgsAttr(Sema &S, Decl *D, const ParsedAttr &AL) { XRayLogArgsAttr(S.Context, AL, ArgCount.getSourceIndex())); } +static void handlePatchableFunctionEntryAttr(Sema &S, Decl *D, + const ParsedAttr &AL) { + uint32_t Count = 0, Offset = 0; + if (!checkUInt32Argument(S, AL, AL.getArgAsExpr(0), Count, 0, true)) + return; + if (AL.getNumArgs() == 2) { + Expr *Arg = AL.getArgAsExpr(1); + if (!checkUInt32Argument(S, AL, Arg, Offset, 1, true)) + return; + if (Offset) { + S.Diag(getAttrLoc(AL), diag::err_attribute_argument_out_of_range) + << &AL << 0 << 0 << Arg->getBeginLoc(); + return; + } + } + D->addAttr(::new (S.Context) + PatchableFunctionEntryAttr(S.Context, AL, Count, Offset)); +} + static bool ArmMveAliasValid(unsigned BuiltinID, StringRef AliasName) { if (AliasName.startswith("__arm_")) AliasName = AliasName.substr(6); @@ -7396,6 +7415,10 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, handleXRayLogArgsAttr(S, D, AL); break; + case ParsedAttr::AT_PatchableFunctionEntry: + handlePatchableFunctionEntryAttr(S, D, AL); + break; + // Move semantics attribute. case ParsedAttr::AT_Reinitializes: handleSimpleAttribute(S, D, AL); diff --git a/clang/test/CodeGen/patchable-function-entry.c b/clang/test/CodeGen/patchable-function-entry.c new file mode 100644 index 0000000..678d90f --- /dev/null +++ b/clang/test/CodeGen/patchable-function-entry.c @@ -0,0 +1,21 @@ +// RUN: %clang_cc1 -triple aarch64 -emit-llvm %s -o - | FileCheck %s + +// CHECK: define void @f0() #0 +__attribute__((patchable_function_entry(0))) void f0() {} + +// CHECK: define void @f00() #0 +__attribute__((patchable_function_entry(0, 0))) void f00() {} + +// CHECK: define void @f2() #1 +__attribute__((patchable_function_entry(2))) void f2() {} + +// CHECK: define void @f20() #1 +__attribute__((patchable_function_entry(2, 0))) void f20() {} + +// CHECK: define void @f20decl() #1 +__attribute__((patchable_function_entry(2, 0))) void f20decl(); +void f20decl() {} + +/// M in patchable_function_entry(N,M) is currently ignored. +// CHECK: attributes #0 = { {{.*}} "patchable-function-entry"="0" +// CHECK: attributes #1 = { {{.*}} "patchable-function-entry"="2" diff --git a/clang/test/Misc/pragma-attribute-supported-attributes-list.test b/clang/test/Misc/pragma-attribute-supported-attributes-list.test index ef518cd..76401ef 100644 --- a/clang/test/Misc/pragma-attribute-supported-attributes-list.test +++ b/clang/test/Misc/pragma-attribute-supported-attributes-list.test @@ -128,6 +128,7 @@ // CHECK-NEXT: Owner (SubjectMatchRule_record_not_is_union) // CHECK-NEXT: ParamTypestate (SubjectMatchRule_variable_is_parameter) // CHECK-NEXT: PassObjectSize (SubjectMatchRule_variable_is_parameter) +// CHECK-NEXT: PatchableFunctionEntry (SubjectMatchRule_function, SubjectMatchRule_objc_method) // CHECK-NEXT: Pointer (SubjectMatchRule_record_not_is_union) // CHECK-NEXT: ReleaseHandle (SubjectMatchRule_variable_is_parameter) // CHECK-NEXT: RenderScriptKernel (SubjectMatchRule_function) diff --git a/clang/test/Sema/patchable-function-entry-attr.c b/clang/test/Sema/patchable-function-entry-attr.c new file mode 100644 index 0000000..f807bd4 --- /dev/null +++ b/clang/test/Sema/patchable-function-entry-attr.c @@ -0,0 +1,17 @@ +// RUN: %clang_cc1 -triple aarch64 -fsyntax-only -verify %s + +// expected-error@+1 {{'patchable_function_entry' attribute takes at least 1 argument}} +__attribute__((patchable_function_entry)) void f(); + +// expected-error@+1 {{'patchable_function_entry' attribute takes no more than 2 arguments}} +__attribute__((patchable_function_entry(0, 0, 0))) void f(); + +// expected-error@+1 {{'patchable_function_entry' attribute requires a non-negative integral compile time constant expression}} +__attribute__((patchable_function_entry(-1))) void f(); + +int i; +// expected-error@+1 {{'patchable_function_entry' attribute requires parameter 0 to be an integer constant}} +__attribute__((patchable_function_entry(i))) void f(); + +// expected-error@+1 {{'patchable_function_entry' attribute requires integer constant between 0 and 0 inclusive}} +__attribute__((patchable_function_entry(1, 1))) void f(); diff --git a/clang/test/Sema/patchable-function-entry-attr.cpp b/clang/test/Sema/patchable-function-entry-attr.cpp new file mode 100644 index 0000000..c443b2d --- /dev/null +++ b/clang/test/Sema/patchable-function-entry-attr.cpp @@ -0,0 +1,9 @@ +// RUN: %clang_cc1 -triple aarch64 -fsyntax-only -verify=silence %s +// RUN: %clang_cc1 -triple i386 -fsyntax-only -verify=silence %s +// RUN: %clang_cc1 -triple x86_64 -fsyntax-only -verify=silence %s +// RUN: %clang_cc1 -triple ppc64le -fsyntax-only -verify %s + +// silence-no-diagnostics + +// expected-warning@+1 {{unknown attribute 'patchable_function_entry' ignored}} +[[gnu::patchable_function_entry(0)]] void f(); -- 2.7.4