diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -1835,6 +1835,14 @@ let LangOpts = [COnly]; } +def BTFTag : InheritableAttr { + let Spellings = [Clang<"btf_tag">]; + let Args = [StringArgument<"BTFTag">]; + let Subjects = SubjectList<[Var, Function, Record, Field], ErrorDiag>; + let Documentation = [BTFTagDocs]; + let LangOpts = [COnly]; +} + def WebAssemblyExportName : InheritableAttr, TargetSpecificAttr { let Spellings = [Clang<"export_name">]; diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -2011,6 +2011,16 @@ struct or union, similar to clang ``__builtin_preserve_access_index()``. }]; } +def BTFTagDocs : Documentation { + let Category = DocCatFunction; + let Content = [{ +Clang supports the ``__attribute__((btf_tag("ARGUMENT")))`` attribute for all +targets. This attribute may be attached to a struct/union, struct/union field, +function, function parameter or variable declaration. If -g is specified, +the ``ARGUMENT`` info will be preserved in IR and be emitted to dwarf. +For BPF targets, the ``ARGUMENT`` info will be emitted to .BTF ELF section too. + }]; +} def MipsInterruptDocs : Documentation { let Category = DocCatFunction; diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -3363,6 +3363,7 @@ EnforceTCBAttr *mergeEnforceTCBAttr(Decl *D, const EnforceTCBAttr &AL); EnforceTCBLeafAttr *mergeEnforceTCBLeafAttr(Decl *D, const EnforceTCBLeafAttr &AL); + BTFTagAttr *mergeBTFTagAttr(Decl *D, const BTFTagAttr &AL); void mergeDeclAttributes(NamedDecl *New, Decl *Old, AvailabilityMergeKind AMK = AMK_Redeclaration); diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -2674,6 +2674,8 @@ NewAttr = S.mergeEnforceTCBAttr(D, *TCBA); else if (const auto *TCBLA = dyn_cast(Attr)) NewAttr = S.mergeEnforceTCBLeafAttr(D, *TCBLA); + else if (const auto *BTFA = dyn_cast(Attr)) + NewAttr = S.mergeBTFTagAttr(D, *BTFA); else if (Attr->shouldInheritEvenIfAlreadyPresent() || !DeclHasAttr(D, Attr)) NewAttr = cast(Attr->clone(S.Context)); diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -6842,6 +6842,30 @@ Rec->addAttr(::new (S.Context) BPFPreserveAccessIndexAttr(S.Context, AL)); } +static bool hasBTFTagAttr(Decl *D, StringRef Tag) { + for (const auto *I : D->specific_attrs()) { + if (I->getBTFTag() == Tag) + return true; + } + return false; +} + +static void handleBTFTagAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + StringRef Str; + if (!S.checkStringLiteralArgumentAttr(AL, 0, Str)) + return; + if (hasBTFTagAttr(D, Str)) + return; + + D->addAttr(::new (S.Context) BTFTagAttr(S.Context, AL, Str)); +} + +BTFTagAttr *Sema::mergeBTFTagAttr(Decl *D, const BTFTagAttr &AL) { + if (hasBTFTagAttr(D, AL.getBTFTag())) + return nullptr; + return ::new (Context) BTFTagAttr(Context, AL, AL.getBTFTag()); +} + static void handleWebAssemblyExportNameAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (!isFunctionOrMethod(D)) { S.Diag(D->getLocation(), diag::warn_attribute_wrong_decl_type) @@ -7879,6 +7903,9 @@ case ParsedAttr::AT_BPFPreserveAccessIndex: handleBPFPreserveAccessIndexAttr(S, D, AL); break; + case ParsedAttr::AT_BTFTag: + handleBTFTagAttr(S, D, AL); + break; case ParsedAttr::AT_WebAssemblyExportName: handleWebAssemblyExportNameAttr(S, D, AL); break; diff --git a/clang/test/Misc/pragma-attribute-supported-attributes-list.test b/clang/test/Misc/pragma-attribute-supported-attributes-list.test --- a/clang/test/Misc/pragma-attribute-supported-attributes-list.test +++ b/clang/test/Misc/pragma-attribute-supported-attributes-list.test @@ -22,6 +22,7 @@ // CHECK-NEXT: Assumption (SubjectMatchRule_function, SubjectMatchRule_objc_method) // CHECK-NEXT: Availability ((SubjectMatchRule_record, SubjectMatchRule_enum, SubjectMatchRule_enum_constant, SubjectMatchRule_field, SubjectMatchRule_function, SubjectMatchRule_namespace, SubjectMatchRule_objc_category, SubjectMatchRule_objc_implementation, SubjectMatchRule_objc_interface, SubjectMatchRule_objc_method, SubjectMatchRule_objc_property, SubjectMatchRule_objc_protocol, SubjectMatchRule_record, SubjectMatchRule_type_alias, SubjectMatchRule_variable)) // CHECK-NEXT: BPFPreserveAccessIndex (SubjectMatchRule_record) +// CHECK-NEXT: BTFTag (SubjectMatchRule_variable, SubjectMatchRule_function, SubjectMatchRule_record, SubjectMatchRule_field) // CHECK-NEXT: BuiltinAlias (SubjectMatchRule_function) // CHECK-NEXT: CFAuditedTransfer (SubjectMatchRule_function) // CHECK-NEXT: CFConsumed (SubjectMatchRule_variable_is_parameter) diff --git a/clang/test/Sema/attr-btf_tag.c b/clang/test/Sema/attr-btf_tag.c new file mode 100644 --- /dev/null +++ b/clang/test/Sema/attr-btf_tag.c @@ -0,0 +1,42 @@ +// RUN: %clang_cc1 -x c -triple x86_64-pc-linux-gnu -dwarf-version=4 -fsyntax-only -verify %s + +#define __tag1 __attribute__((btf_tag("tag1"))) +#define __tag2 __attribute__((btf_tag("tag2"))) +#define __tag3 __attribute__((btf_tag("tag3"))) + +#define __tag_no_arg __attribute__((btf_tag())) +#define __tag_2_arg __attribute__((btf_tag("tag1", "tag2"))) +#define __invalid __attribute__((btf_tag(1))) + +struct __tag1 __tag2 t1; +struct t1 { + int a __tag1; +} __tag3; + +struct __tag1 t2; +struct __tag2 __tag3 t2 { + int a __tag1; +}; + +int g1 __tag1; +int g2 __tag_no_arg; // expected-error {{'btf_tag' attribute takes one argument}} +int g3 __tag_2_arg; // expected-error {{'btf_tag' attribute takes one argument}} +int i1 __invalid; // expected-error {{'btf_tag' attribute requires a string}} + +enum e1 { + E1 +} __tag1; // expected-error {{'btf_tag' attribute only applies to variables, functions, structs, unions, classes, and non-static data members}} + +enum e2 { + E2 +} __tag_no_arg; // expected-error {{'btf_tag' attribute only applies to variables, functions, structs, unions, classes, and non-static data members}} + +enum e3 { + E3 +} __tag_2_arg; // expected-error {{'btf_tag' attribute only applies to variables, functions, structs, unions, classes, and non-static data members}} + +int __tag1 __tag2 foo(struct t1 *arg, struct t2 *arg2); +int __tag2 __tag3 foo(struct t1 *arg, struct t2 *arg2); +int __tag1 foo(struct t1 *arg __tag1, struct t2 *arg2) { + return arg->a + arg2->a; +}