From 4a5aa1a7bf8b1714b817ede8e09cd28c0784228a Mon Sep 17 00:00:00 2001 From: Yonghong Song Date: Fri, 1 Nov 2019 22:16:59 -0700 Subject: [PATCH] [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/include/clang/Basic/Attr.td | 7 ++ clang/include/clang/Basic/AttrDocs.td | 11 ++++ clang/include/clang/Basic/DiagnosticSemaKinds.td | 1 + clang/lib/CodeGen/CGExpr.cpp | 75 ++++++++++++++++++++-- clang/lib/Sema/SemaDeclAttr.cpp | 66 ++++++++++++++++++- .../CodeGen/bpf-attr-preserve-access-index-1.c | 23 +++++++ .../CodeGen/bpf-attr-preserve-access-index-2.c | 24 +++++++ .../CodeGen/bpf-attr-preserve-access-index-3.c | 32 +++++++++ .../CodeGen/bpf-attr-preserve-access-index-4.c | 33 ++++++++++ .../CodeGen/bpf-attr-preserve-access-index-5.c | 32 +++++++++ .../CodeGen/bpf-attr-preserve-access-index-6.c | 32 +++++++++ .../CodeGen/bpf-attr-preserve-access-index-7.c | 36 +++++++++++ .../CodeGen/bpf-attr-preserve-access-index-8.c | 36 +++++++++++ clang/test/Sema/bpf-attr-preserve-access-index.c | 48 ++++++++++++++ 14 files changed, 448 insertions(+), 8 deletions(-) create mode 100644 clang/test/CodeGen/bpf-attr-preserve-access-index-1.c create mode 100644 clang/test/CodeGen/bpf-attr-preserve-access-index-2.c create mode 100644 clang/test/CodeGen/bpf-attr-preserve-access-index-3.c create mode 100644 clang/test/CodeGen/bpf-attr-preserve-access-index-4.c create mode 100644 clang/test/CodeGen/bpf-attr-preserve-access-index-5.c create mode 100644 clang/test/CodeGen/bpf-attr-preserve-access-index-6.c create mode 100644 clang/test/CodeGen/bpf-attr-preserve-access-index-7.c create mode 100644 clang/test/CodeGen/bpf-attr-preserve-access-index-8.c create mode 100644 clang/test/Sema/bpf-attr-preserve-access-index.c diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index 0d25e77..aef02b5 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -332,6 +332,7 @@ class TargetArch arches> : TargetSpec { } def TargetARM : TargetArch<["arm", "thumb", "armeb", "thumbeb"]>; def TargetAVR : TargetArch<["avr"]>; +def TargetBPF : TargetArch<["bpfel", "bpfeb"]>; def TargetMips32 : TargetArch<["mips", "mipsel"]>; def TargetAnyMips : TargetArch<["mips", "mipsel", "mips64", "mips64el"]>; def TargetMSP430 : TargetArch<["msp430"]>; @@ -1578,6 +1579,12 @@ def AMDGPUNumVGPR : InheritableAttr { let Subjects = SubjectList<[Function], ErrorDiag, "kernel functions">; } +def BPFPreserveAccessIndex : InheritableAttr, + TargetSpecificAttr { + let Spellings = [Clang<"preserve_access_index">]; + let Documentation = [BPFPreserveAccessIndexDocs]; +} + def WebAssemblyImportModule : InheritableAttr, TargetSpecificAttr { let Spellings = [Clang<"import_module">]; diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td index 3a90931..50e76bf 100644 --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -1634,6 +1634,17 @@ The semantics are as follows: }]; } +def BPFPreserveAccessIndexDocs : Documentation { + let Category = DocCatFunction; + let Content = [{ +Clang supports the ``__attribute__((preserve_access_index))`` +attribute for the BPF target. This attribute may be attached to a +struct or union declaration, where if -g is specified, it enables +preserving struct or union member access debuginfo indicies of this +struct or union, similar to clang ``__builtin_preserve_acceess_index()``. + }]; +} + def MipsInterruptDocs : Documentation { let Category = DocCatFunction; let Heading = "interrupt (MIPS)"; diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 88d73dc..33a0f97 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -10065,6 +10065,7 @@ def err_preserve_field_info_not_field : Error< "__builtin_preserve_field_info argument %0 not a field access">; def err_preserve_field_info_not_const: Error< "__builtin_preserve_field_info argument %0 not a constant">; +def err_preserve_access_index_wrong_type: Error<"%0 attribute only applies to %1">; def err_bit_cast_non_trivially_copyable : Error< "__builtin_bit_cast %select{source|destination}0 type must be trivially copyable">; diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index 9940671..e32db8c 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -3402,11 +3402,67 @@ static QualType getFixedSizeElementType(const ASTContext &ctx, return eltType; } +/// Given an array base, check whether its member access belongs to a record +/// with preserve_access_index attribute or not. +static bool IsPreserveAIArrayBase(CodeGenFunction &CGF, const Expr *ArrayBase) { + if (!ArrayBase || !CGF.getDebugInfo()) + return false; + + const auto *ImplicitCast = dyn_cast(ArrayBase); + if (!ImplicitCast) + return false; + + // Only support base as either a MemberExpr or DeclRefExpr. + // DeclRefExpr to cover cases like: + // struct s { int a; int b[10]; }; + // struct s *p; + // p[1].a + // p[1] will generate a DeclRefExpr and p[1].a is a MemberExpr. + // p->b[5] is a MemberExpr example. + const Expr *E = ImplicitCast->getSubExpr(); + const auto *MemberCast = dyn_cast(E); + if (MemberCast) + return MemberCast->getMemberDecl()->hasAttr(); + + const auto *DeclRefCast = dyn_cast(E); + if (DeclRefCast) { + const VarDecl *VarDef = dyn_cast(DeclRefCast->getDecl()); + if (!VarDef) + return false; + + const auto *PtrT = dyn_cast(VarDef->getType().getTypePtr()); + if (!PtrT) + return false; + const auto *PointeeT = PtrT->getPointeeType().getTypePtr(); + + // Peel off typedef's + const auto *TypedefT = dyn_cast(PointeeT); + while (TypedefT) { + PointeeT = TypedefT->desugar().getTypePtr(); + TypedefT = dyn_cast(PointeeT); + } + + // Not a typedef any more, it should be an elaborated type. + const auto ElaborateT = dyn_cast(PointeeT); + if (!ElaborateT) + return false; + + const auto *RecT = dyn_cast(ElaborateT->desugar().getTypePtr()); + if (!RecT) + return false; + + return RecT->getDecl()->hasAttr(); + } + + return false; +} + static Address emitArraySubscriptGEP(CodeGenFunction &CGF, Address addr, ArrayRef indices, QualType eltType, bool inbounds, bool signedIndices, SourceLocation loc, QualType *arrayType = nullptr, + const Expr *Base = nullptr, const llvm::Twine &name = "arrayidx") { // All the indices except that last must be zero. #ifndef NDEBUG @@ -3428,7 +3484,8 @@ static Address emitArraySubscriptGEP(CodeGenFunction &CGF, Address addr, llvm::Value *eltPtr; auto LastIndex = dyn_cast(indices.back()); - if (!CGF.IsInPreservedAIRegion || !LastIndex) { + if (!LastIndex || + (!CGF.IsInPreservedAIRegion && !IsPreserveAIArrayBase(CGF, Base))) { eltPtr = emitArraySubscriptGEP( CGF, addr.getPointer(), indices, inbounds, signedIndices, loc, name); @@ -3582,7 +3639,7 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E, Addr = emitArraySubscriptGEP( *this, ArrayLV.getAddress(), {CGM.getSize(CharUnits::Zero()), Idx}, E->getType(), !getLangOpts().isSignedOverflowDefined(), SignedIndices, - E->getExprLoc(), &arrayType); + E->getExprLoc(), &arrayType, E->getBase()); EltBaseInfo = ArrayLV.getBaseInfo(); EltTBAAInfo = CGM.getTBAAInfoForSubobject(ArrayLV, E->getType()); } else { @@ -3592,7 +3649,8 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E, QualType ptrType = E->getBase()->getType(); Addr = emitArraySubscriptGEP(*this, Addr, Idx, E->getType(), !getLangOpts().isSignedOverflowDefined(), - SignedIndices, E->getExprLoc(), &ptrType); + SignedIndices, E->getExprLoc(), &ptrType, + E->getBase()); } LValue LV = MakeAddrLValue(Addr, E->getType(), EltBaseInfo, EltTBAAInfo); @@ -3993,12 +4051,13 @@ LValue CodeGenFunction::EmitLValueForField(LValue base, const CGBitFieldInfo &Info = RL.getBitFieldInfo(field); Address Addr = base.getAddress(); unsigned Idx = RL.getLLVMFieldNo(field); - if (!IsInPreservedAIRegion) { + const RecordDecl *rec = field->getParent(); + if (!IsInPreservedAIRegion && + (!getDebugInfo() || !rec->hasAttr())) { if (Idx != 0) // For structs, we GEP to the field that the record layout suggests. Addr = Builder.CreateStructGEP(Addr, Idx, field->getName()); } else { - const RecordDecl *rec = field->getParent(); llvm::DIType *DbgInfo = getDebugInfo()->getOrCreateRecordType( getContext().getRecordType(rec), rec->getLocation()); Addr = Builder.CreatePreserveStructAccessIndex(Addr, Idx, @@ -4081,7 +4140,8 @@ LValue CodeGenFunction::EmitLValueForField(LValue base, addr = Address(Builder.CreateLaunderInvariantGroup(addr.getPointer()), addr.getAlignment()); - if (IsInPreservedAIRegion) { + if (IsInPreservedAIRegion || + (getDebugInfo() && rec->hasAttr())) { // Remember the original union field index llvm::DIType *DbgInfo = getDebugInfo()->getOrCreateRecordType( getContext().getRecordType(rec), rec->getLocation()); @@ -4095,7 +4155,8 @@ LValue CodeGenFunction::EmitLValueForField(LValue base, addr = Builder.CreateElementBitCast( addr, CGM.getTypes().ConvertTypeForMem(FieldType), field->getName()); } else { - if (!IsInPreservedAIRegion) + if (!IsInPreservedAIRegion && + (!getDebugInfo() || !rec->hasAttr())) // For structs, we GEP to the field that the record layout suggests. addr = emitAddrOfFieldStorage(*this, addr, field); else diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index 7f68d20..526e61c 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 diff --git a/clang/test/CodeGen/bpf-attr-preserve-access-index-1.c b/clang/test/CodeGen/bpf-attr-preserve-access-index-1.c new file mode 100644 index 0000000..accf6ab --- /dev/null +++ b/clang/test/CodeGen/bpf-attr-preserve-access-index-1.c @@ -0,0 +1,23 @@ +// REQUIRES: bpf-registered-target +// RUN: %clang -target bpf -emit-llvm -S -g %s -o - | FileCheck %s + +#define __reloc__ __attribute__((preserve_access_index)) + +// test simple member access and initial struct with non-zero stride access +struct s1 { + int a; + union { + int b; + int c; + }; +} __reloc__; +typedef struct s1 __s1; + +int test(__s1 *arg) { + return arg->a + arg[1].b; +} + +// CHECK: call i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.s1s(%struct.s1* %{{[0-9a-z]+}}, i32 0, i32 0) +// CHECK: call %struct.s1* @llvm.preserve.array.access.index.p0s_struct.s1s.p0s_struct.s1s(%struct.s1* %{{[0-9a-z]+}}, i32 0, i32 1) +// CHECK: call %union.anon* @llvm.preserve.struct.access.index.p0s_union.anons.p0s_struct.s1s(%struct.s1* %{{[0-9a-z]+}}, i32 1, i32 1) +// CHECK: call %union.anon* @llvm.preserve.union.access.index.p0s_union.anons.p0s_union.anons(%union.anon* %{{[0-9a-z]+}}, i32 0) diff --git a/clang/test/CodeGen/bpf-attr-preserve-access-index-2.c b/clang/test/CodeGen/bpf-attr-preserve-access-index-2.c new file mode 100644 index 0000000..a136eee --- /dev/null +++ b/clang/test/CodeGen/bpf-attr-preserve-access-index-2.c @@ -0,0 +1,24 @@ +// REQUIRES: bpf-registered-target +// RUN: %clang -target bpf -emit-llvm -S -g %s -o - | FileCheck %s + +#define __reloc__ __attribute__((preserve_access_index)) + +// test array access +struct s1 { + int a[3]; + union { + int b; + int c[4]; + }; +} __reloc__; +typedef struct s1 __s1; + +int test(__s1 *arg) { + return arg->a[2] + arg->c[2]; +} + +// CHECK: call [3 x i32]* @llvm.preserve.struct.access.index.p0a3i32.p0s_struct.s1s(%struct.s1* %{{[0-9a-z]+}}, i32 0, i32 0) +// CHECK: call i32* @llvm.preserve.array.access.index.p0i32.p0a3i32([3 x i32]* %{{[0-9a-z]+}}, i32 1, i32 2) +// CHECK: call %union.anon* @llvm.preserve.struct.access.index.p0s_union.anons.p0s_struct.s1s(%struct.s1* %{{[0-9a-z]+}}, i32 1, i32 1) +// CHECK: call %union.anon* @llvm.preserve.union.access.index.p0s_union.anons.p0s_union.anons(%union.anon* %{{[0-9a-z]+}}, i32 1) +// CHECK: call i32* @llvm.preserve.array.access.index.p0i32.p0a4i32([4 x i32]* %{{[0-9a-z]+}}, i32 1, i32 2) diff --git a/clang/test/CodeGen/bpf-attr-preserve-access-index-3.c b/clang/test/CodeGen/bpf-attr-preserve-access-index-3.c new file mode 100644 index 0000000..917b508 --- /dev/null +++ b/clang/test/CodeGen/bpf-attr-preserve-access-index-3.c @@ -0,0 +1,32 @@ +// REQUIRES: bpf-registered-target +// RUN: %clang -target bpf -emit-llvm -S -g %s -o - | FileCheck %s + +#define __reloc__ __attribute__((preserve_access_index)) + +// chain of records, all with attributes +struct s1 { + int c; +} __reloc__; +typedef struct s1 __s1; + +struct s2 { + union { + __s1 b[3]; + }; +} __reloc__; +typedef struct s2 __s2; + +struct s3 { + __s2 a; +} __reloc__; +typedef struct s3 __s3; + +int test(__s3 *arg) { + return arg->a.b[2].c; +} + +// CHECK: call %struct.s2* @llvm.preserve.struct.access.index.p0s_struct.s2s.p0s_struct.s3s(%struct.s3* %{{[0-9a-z]+}}, i32 0, i32 0) +// CHECK: call %union.anon* @llvm.preserve.struct.access.index.p0s_union.anons.p0s_struct.s2s(%struct.s2* %{{[0-9a-z]+}}, i32 0, i32 0) +// CHECK: call %union.anon* @llvm.preserve.union.access.index.p0s_union.anons.p0s_union.anons(%union.anon* %{{[0-9a-z]+}}, i32 0) +// CHECK: call %struct.s1* @llvm.preserve.array.access.index.p0s_struct.s1s.p0a3s_struct.s1s([3 x %struct.s1]* %{{[0-9a-z]+}}, i32 1, i32 2) +// CHECK: call i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.s1s(%struct.s1* %{{[0-9a-z]+}}, i32 0, i32 0) diff --git a/clang/test/CodeGen/bpf-attr-preserve-access-index-4.c b/clang/test/CodeGen/bpf-attr-preserve-access-index-4.c new file mode 100644 index 0000000..5ec56d96 --- /dev/null +++ b/clang/test/CodeGen/bpf-attr-preserve-access-index-4.c @@ -0,0 +1,33 @@ +// REQUIRES: bpf-registered-target +// RUN: %clang -target bpf -emit-llvm -S -g %s -o - | FileCheck %s + +#define __reloc__ __attribute__((preserve_access_index)) + +// chain of records, some do not have attributes. +struct s1 { + int c; +}; +typedef struct s1 __s1; + +struct s2 { + union { + __s1 b[3]; + }; +} __reloc__; +typedef struct s2 __s2; + +struct s3 { + __s2 a; +}; +typedef struct s3 __s3; + +int test(__s3 *arg) { + return arg->a.b[2].c; +} + +// CHECK: define dso_local i32 @test +// CHECK-NOT: call %struct.s2* @llvm.preserve.struct.access.index.p0s_struct.s2s.p0s_struct.s3s +// CHECK: call %union.anon* @llvm.preserve.struct.access.index.p0s_union.anons.p0s_struct.s2s(%struct.s2* %a, i32 0, i32 0) +// CHECK: call %union.anon* @llvm.preserve.union.access.index.p0s_union.anons.p0s_union.anons(%union.anon* %1, i32 0) +// CHECK: call %struct.s1* @llvm.preserve.array.access.index.p0s_struct.s1s.p0a3s_struct.s1s([3 x %struct.s1]* %b, i32 1, i32 2) +// CHECK-NOT: call i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.s1s diff --git a/clang/test/CodeGen/bpf-attr-preserve-access-index-5.c b/clang/test/CodeGen/bpf-attr-preserve-access-index-5.c new file mode 100644 index 0000000..281bcdd --- /dev/null +++ b/clang/test/CodeGen/bpf-attr-preserve-access-index-5.c @@ -0,0 +1,32 @@ +// REQUIRES: bpf-registered-target +// RUN: %clang -target bpf -emit-llvm -S -g %s -o - | FileCheck %s + +#define __reloc__ __attribute__((preserve_access_index)) + +// chain of records, attribute may be in inner record. +struct s1 { + int c; +} __reloc__; +typedef struct s1 __s1; + +struct s2 { + union { + __s1 b[3]; + } __reloc__; +}; +typedef struct s2 __s2; + +struct s3 { + __s2 a; +} __reloc__; +typedef struct s3 __s3; + +int test(__s3 *arg) { + return arg->a.b[2].c; +} + +// CHECK: call %struct.s2* @llvm.preserve.struct.access.index.p0s_struct.s2s.p0s_struct.s3s(%struct.s3* %{{[0-9a-z]+}}, i32 0, i32 0) +// CHECK-NOT: call %union.anon* @llvm.preserve.struct.access.index.p0s_union.anons.p0s_struct.s2s +// CHECK: call %union.anon* @llvm.preserve.union.access.index.p0s_union.anons.p0s_union.anons(%union.anon* %{{[0-9a-z]+}}, i32 0) +// CHECK: call %struct.s1* @llvm.preserve.array.access.index.p0s_struct.s1s.p0a3s_struct.s1s([3 x %struct.s1]* %{{[0-9a-z]+}}, i32 1, i32 2) +// CHECK: call i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.s1s(%struct.s1* %{{[0-9a-z]+}}, i32 0, i32 0) diff --git a/clang/test/CodeGen/bpf-attr-preserve-access-index-6.c b/clang/test/CodeGen/bpf-attr-preserve-access-index-6.c new file mode 100644 index 0000000..a763f28 --- /dev/null +++ b/clang/test/CodeGen/bpf-attr-preserve-access-index-6.c @@ -0,0 +1,32 @@ +// REQUIRES: bpf-registered-target +// RUN: %clang -target bpf -emit-llvm -S -g %s -o - | FileCheck %s + +#define __reloc__ __attribute__((preserve_access_index)) + +// chain of records, both inner and outer record have attributes. +struct s1 { + int c; +} __reloc__; +typedef struct s1 __s1; + +struct s2 { + union { + __s1 b[3]; + } __reloc__; +} __reloc__; +typedef struct s2 __s2; + +struct s3 { + __s2 a; +} __reloc__; +typedef struct s3 __s3; + +int test(__s3 *arg) { + return arg->a.b[2].c; +} + +// CHECK: call %struct.s2* @llvm.preserve.struct.access.index.p0s_struct.s2s.p0s_struct.s3s(%struct.s3* %{{[0-9a-z]+}}, i32 0, i32 0) +// CHECK: call %union.anon* @llvm.preserve.struct.access.index.p0s_union.anons.p0s_struct.s2s(%struct.s2* %{{[0-9a-z]+}}, i32 0, i32 0) +// CHECK: call %union.anon* @llvm.preserve.union.access.index.p0s_union.anons.p0s_union.anons(%union.anon* %{{[0-9a-z]+}}, i32 0) +// CHECK: call %struct.s1* @llvm.preserve.array.access.index.p0s_struct.s1s.p0a3s_struct.s1s([3 x %struct.s1]* %{{[0-9a-z]+}}, i32 1, i32 2) +// CHECK: call i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.s1s(%struct.s1* %{{[0-9a-z]+}}, i32 0, i32 0) diff --git a/clang/test/CodeGen/bpf-attr-preserve-access-index-7.c b/clang/test/CodeGen/bpf-attr-preserve-access-index-7.c new file mode 100644 index 0000000..49f4a4d --- /dev/null +++ b/clang/test/CodeGen/bpf-attr-preserve-access-index-7.c @@ -0,0 +1,36 @@ +// REQUIRES: bpf-registered-target +// RUN: %clang -target bpf -emit-llvm -S -g %s -o - | FileCheck %s + +#define __reloc__ __attribute__((preserve_access_index)) + +// chain of records, all with attributes +struct __reloc__ s1; +struct __reloc__ s2; +struct __reloc__ s3; + +struct s1 { + int c; +}; +typedef struct s1 __s1; + +struct s2 { + union { + __s1 b[3]; + }; +}; +typedef struct s2 __s2; + +struct s3 { + __s2 a; +}; +typedef struct s3 __s3; + +int test(__s3 *arg) { + return arg->a.b[2].c; +} + +// CHECK: call %struct.s2* @llvm.preserve.struct.access.index.p0s_struct.s2s.p0s_struct.s3s(%struct.s3* %{{[0-9a-z]+}}, i32 0, i32 0) +// CHECK: call %union.anon* @llvm.preserve.struct.access.index.p0s_union.anons.p0s_struct.s2s(%struct.s2* %{{[0-9a-z]+}}, i32 0, i32 0) +// CHECK: call %union.anon* @llvm.preserve.union.access.index.p0s_union.anons.p0s_union.anons(%union.anon* %{{[0-9a-z]+}}, i32 0) +// CHECK: call %struct.s1* @llvm.preserve.array.access.index.p0s_struct.s1s.p0a3s_struct.s1s([3 x %struct.s1]* %{{[0-9a-z]+}}, i32 1, i32 2) +// CHECK: call i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.s1s(%struct.s1* %{{[0-9a-z]+}}, i32 0, i32 0) diff --git a/clang/test/CodeGen/bpf-attr-preserve-access-index-8.c b/clang/test/CodeGen/bpf-attr-preserve-access-index-8.c new file mode 100644 index 0000000..7febf7c --- /dev/null +++ b/clang/test/CodeGen/bpf-attr-preserve-access-index-8.c @@ -0,0 +1,36 @@ +// REQUIRES: bpf-registered-target +// RUN: %clang -target bpf -emit-llvm -S -g %s -o - | FileCheck %s + +#define __reloc__ __attribute__((preserve_access_index)) + +// chain of records, all with attributes +struct s1; +struct s2; +struct s3; + +struct s1 { + int c; +} __reloc__; +typedef struct s1 __s1; + +struct s2 { + union { + __s1 b[3]; + }; +} __reloc__; +typedef struct s2 __s2; + +struct s3 { + __s2 a; +} __reloc__; +typedef struct s3 __s3; + +int test(__s3 *arg) { + return arg->a.b[2].c; +} + +// CHECK: call %struct.s2* @llvm.preserve.struct.access.index.p0s_struct.s2s.p0s_struct.s3s(%struct.s3* %{{[0-9a-z]+}}, i32 0, i32 0) +// CHECK: call %union.anon* @llvm.preserve.struct.access.index.p0s_union.anons.p0s_struct.s2s(%struct.s2* %{{[0-9a-z]+}}, i32 0, i32 0) +// CHECK: call %union.anon* @llvm.preserve.union.access.index.p0s_union.anons.p0s_union.anons(%union.anon* %{{[0-9a-z]+}}, i32 0) +// CHECK: call %struct.s1* @llvm.preserve.array.access.index.p0s_struct.s1s.p0a3s_struct.s1s([3 x %struct.s1]* %{{[0-9a-z]+}}, i32 1, i32 2) +// CHECK: call i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.s1s(%struct.s1* %{{[0-9a-z]+}}, i32 0, i32 0) diff --git a/clang/test/Sema/bpf-attr-preserve-access-index.c b/clang/test/Sema/bpf-attr-preserve-access-index.c new file mode 100644 index 0000000..472f778 --- /dev/null +++ b/clang/test/Sema/bpf-attr-preserve-access-index.c @@ -0,0 +1,48 @@ +// RUN: %clang_cc1 -x c -triple bpf-pc-linux-gnu -dwarf-version=4 -fsyntax-only -verify %s + +#define __reloc__ __attribute__((preserve_access_index)) +#define __err_reloc__ __attribute__((preserve_access_index(0))) + +struct t1 { + int a; + int b[4]; + int c:1; +} __reloc__; + +union t2 { + int a; + int b[4]; + int c:1; +} __reloc__; + +struct t3 { + int a; +} __err_reloc__; // expected-error {{'preserve_access_index' attribute takes no arguments}} + +struct t4 { + union { + int a; + char b[5]; + }; + struct { + int c:1; + } __reloc__; + int d; +} __reloc__; + +struct __reloc__ p; +struct __reloc__ q; +struct p { + int a; +}; + +int a __reloc__; // expected-error {{preserve_addess_index attribute only applies to struct or union type}} +struct s *p __reloc__; // expected-error {{preserve_addess_index attribute only applies to struct or union type}} + +void invalid1(const int __reloc__ *arg) {} // expected-error {{preserve_addess_index attribute only applies to struct or union type}} +void invalid2() { const int __reloc__ *arg; } // expected-error {{preserve_addess_index attribute only applies to struct or union type}} +int valid3(struct t4 *arg) { return arg->a + arg->b[3] + arg->c + arg->d; } +int valid4(void *arg) { + struct local_t { int a; int b; } __reloc__; + return ((struct local_t *)arg)->b; +} -- 2.7.4