diff options
author | Yonghong Song <yhs@fb.com> | 2019-11-01 22:16:59 -0700 |
---|---|---|
committer | Yonghong Song <yhs@fb.com> | 2019-11-09 08:17:12 -0800 |
commit | 4a5aa1a7bf8b1714b817ede8e09cd28c0784228a (patch) | |
tree | 1bc0e5f6d33732583fce0799e0ec36ac96f93621 /clang/lib/Sema/SemaDeclAttr.cpp | |
parent | 27c4eaac8c066eb1f7c5ad26c6fbc3e78eded778 (diff) | |
download | bcm5719-llvm-4a5aa1a7bf8b1714b817ede8e09cd28c0784228a.tar.gz bcm5719-llvm-4a5aa1a7bf8b1714b817ede8e09cd28c0784228a.zip |
[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
Diffstat (limited to 'clang/lib/Sema/SemaDeclAttr.cpp')
-rw-r--r-- | clang/lib/Sema/SemaDeclAttr.cpp | 66 |
1 files changed, 65 insertions, 1 deletions
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<AVRSignalAttr>(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<BPFPreserveAccessIndexAttr>()) + return; + + RecordDecl *Rec = dyn_cast<RecordDecl>(*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<RecordDecl>(*D); + if (Rec) { + // Inner record may have been processed. + if (!Rec->hasAttr<BPFPreserveAccessIndexAttr>()) { + 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<RecordDecl>(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<BPFPreserveAccessIndexAttr>()) { + handleBPFPreserveAIRecord(*this, cast<RecordDecl>(D), + *D->getAttr<BPFPreserveAccessIndexAttr>()); + } } // Annotation attributes are the only attributes allowed after an access |