From 4a5aa1a7bf8b1714b817ede8e09cd28c0784228a Mon Sep 17 00:00:00 2001 From: Yonghong Song Date: Fri, 1 Nov 2019 22:16:59 -0700 Subject: [BPF] Add preserve_access_index attribute for record definition This patch introduced a new bpf specific attribute which can be added to struct or union definition. For example, struct s { ... } __attribute__((preserve_access_index)); union u { ... } __attribute__((preserve_access_index)); The goal is to simplify user codes for cases where preserve access index happens for certain struct/union, so user does not need to use clang __builtin_preserve_access_index for every members. The attribute has no effect if -g is not specified. When the attribute is specified and -g is specified, any member access defined by that structure or union, including array subscript access and inner records, will be preserved through __builtin_preserve_{array,struct,union}_access_index() IR intrinsics, which will enable relocation generation in bpf backend. The following is an example to illustrate the usage: -bash-4.4$ cat t.c #define __reloc__ __attribute__((preserve_access_index)) struct s1 { int c; } __reloc__; struct s2 { union { struct s1 b[3]; }; } __reloc__; struct s3 { struct s2 a; } __reloc__; int test(struct s3 *arg) { return arg->a.b[2].c; } -bash-4.4$ clang -target bpf -g -S -O2 t.c A relocation with access string "0:0:0:0:2:0" will be generated representing access offset of arg->a.b[2].c. forward declaration with attribute is also handled properly such that the attribute is copied and populated in real record definition. Differential Revision: https://reviews.llvm.org/D69759 --- clang/lib/Sema/SemaDeclAttr.cpp | 66 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 65 insertions(+), 1 deletion(-) (limited to 'clang/lib/Sema/SemaDeclAttr.cpp') diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index 7f68d201491..526e61cdf9e 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -5700,6 +5700,59 @@ static void handleAVRSignalAttr(Sema &S, Decl *D, const ParsedAttr &AL) { handleSimpleAttribute(S, D, AL); } +static void handleBPFPreserveAIRecord(Sema &S, RecordDecl *RD, + const BPFPreserveAccessIndexAttr &AL) { + // Add preserve_access_index attribute to all fields and inner records. + for (DeclContext::decl_iterator D = RD->decls_begin(), DEnd = RD->decls_end(); + D != DEnd; ++D) { + // Any member or inner struct having attribute means done. + if (D->hasAttr()) + return; + + RecordDecl *Rec = dyn_cast(*D); + if (Rec) { + Rec->addAttr(::new (S.Context) BPFPreserveAccessIndexAttr(S.Context, AL)); + handleBPFPreserveAIRecord(S, Rec, AL); + } else { + D->addAttr(::new (S.Context) BPFPreserveAccessIndexAttr(S.Context, AL)); + } + } +} + +static void handleBPFPreserveAIRecord(Sema &S, RecordDecl *RD, + const ParsedAttr &AL) { + // Add preserve_access_index attribute to all fields and inner records. + for (DeclContext::decl_iterator D = RD->decls_begin(), DEnd = RD->decls_end(); + D != DEnd; ++D) { + RecordDecl *Rec = dyn_cast(*D); + if (Rec) { + // Inner record may have been processed. + if (!Rec->hasAttr()) { + Rec->addAttr(::new (S.Context) BPFPreserveAccessIndexAttr(S.Context, AL)); + handleBPFPreserveAIRecord(S, Rec, AL); + } + } else { + D->addAttr(::new (S.Context) BPFPreserveAccessIndexAttr(S.Context, AL)); + } + } +} + +static void handleBPFPreserveAccessIndexAttr(Sema &S, Decl *D, + const ParsedAttr &AL) { + RecordDecl *Rec = dyn_cast(D); + if (!Rec) { + S.Diag(D->getLocation(), diag::err_preserve_access_index_wrong_type) + << "preserve_addess_index" << "struct or union type"; + return; + } + + if (!checkAttributeNumArgs(S, AL, 0)) + return; + + handleBPFPreserveAIRecord(S, Rec, AL); + Rec->addAttr(::new (S.Context) BPFPreserveAccessIndexAttr(S.Context, AL)); +} + static void handleWebAssemblyImportModuleAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (!isFunctionOrMethod(D)) { S.Diag(D->getLocation(), diag::warn_attribute_wrong_decl_type) @@ -6576,6 +6629,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, case ParsedAttr::AT_AVRSignal: handleAVRSignalAttr(S, D, AL); break; + case ParsedAttr::AT_BPFPreserveAccessIndex: + handleBPFPreserveAccessIndexAttr(S, D, AL); + break; case ParsedAttr::AT_WebAssemblyImportModule: handleWebAssemblyImportModuleAttr(S, D, AL); break; @@ -7325,7 +7381,8 @@ void Sema::ProcessDeclAttributeList(Scope *S, Decl *D, } } -// Helper for delayed processing TransparentUnion attribute. +// Helper for delayed processing TransparentUnion or BPFPreserveAccessIndexAttr +// attribute. void Sema::ProcessDeclAttributeDelayed(Decl *D, const ParsedAttributesView &AttrList) { for (const ParsedAttr &AL : AttrList) @@ -7333,6 +7390,13 @@ void Sema::ProcessDeclAttributeDelayed(Decl *D, handleTransparentUnionAttr(*this, D, AL); break; } + + // For BPFPreserveAccessIndexAttr, we want to populate the attributes + // to fields and inner records as well. + if (D->hasAttr()) { + handleBPFPreserveAIRecord(*this, cast(D), + *D->getAttr()); + } } // Annotation attributes are the only attributes allowed after an access -- cgit v1.2.3