let Documentation = [XRayDocs];
}
+def PatchableFunctionEntry
+ : InheritableAttr,
+ TargetSpecificAttr<TargetArch<["aarch64", "x86", "x86_64"]>> {
+ 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>;
}];
}
+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 = [{
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<XRayInstrumentAttr>()) {
if (CGM.getCodeGenOpts().XRayInstrumentationBundle.has(
XRayInstrKind::Function)) {
"xray-instruction-threshold",
llvm::itostr(CGM.getCodeGenOpts().XRayInstructionThreshold));
}
+
+ if (const auto *Attr = D->getAttr<PatchableFunctionEntryAttr>()) {
+ // Attr->getStart is currently ignored.
+ Fn->addFnAttr("patchable-function-entry",
+ std::to_string(Attr->getCount()));
+ }
}
// Add no-jump-tables value.
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);
handleXRayLogArgsAttr(S, D, AL);
break;
+ case ParsedAttr::AT_PatchableFunctionEntry:
+ handlePatchableFunctionEntryAttr(S, D, AL);
+ break;
+
// Move semantics attribute.
case ParsedAttr::AT_Reinitializes:
handleSimpleAttribute<ReinitializesAttr>(S, D, AL);
--- /dev/null
+// 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"
// 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)
--- /dev/null
+// 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();
--- /dev/null
+// 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();