Skip to content

Commit 030b8cb

Browse files
committed
[BPF] Attribute preserve_static_offset for structs
This commit adds a new BPF specific structure attribte `__attribute__((preserve_static_offset))` and a pass to deal with it. This attribute may be attached to a struct or union declaration, where it notifies the compiler that this structure is a "context" structure. The following limitations apply to context structures: - runtime environment might patch access to the fields of this type by updating the field offset; BPF verifier limits access patterns allowed for certain data types. E.g. `struct __sk_buff` and `struct bpf_sock_ops`. For these types only `LD/ST <reg> <static-offset>` memory loads and stores are allowed. This is so because offsets of the fields of these structures do not match real offsets in the running kernel. During BPF program load/verification loads and stores to the fields of these types are rewritten so that offsets match real offsets. For this rewrite to happen static offsets have to be encoded in the instructions. See `kernel/bpf/verifier.c:convert_ctx_access` function in the Linux kernel source tree for details. - runtime environment might disallow access to the field of the type through modified pointers. During BPF program verification a tag `PTR_TO_CTX` is tracked for register values. In case if register with such tag is modified BPF programs are not allowed to read or write memory using register. See kernel/bpf/verifier.c:check_mem_access function in the Linux kernel source tree for details. Access to the structure fields is translated to IR as a sequence: - `(load (getelementptr %ptr %offset))` or - `(store (getelementptr %ptr %offset))` During instruction selection phase such sequences are translated as a single load instruction with embedded offset, e.g. `LDW %ptr, %offset`, which matches access pattern necessary for the restricted set of types described above (when `%offset` is static). Multiple optimizer passes might separate these instructions, this includes: - SimplifyCFGPass (sinking) - InstCombine (sinking) - GVN (hoisting) The `preserve_static_offset` attribute marks structures for which the following transformations happen: - at the early IR processing stage: - `(load (getelementptr ...))` replaced by call to intrinsic `llvm.bpf.getelementptr.and.load`; - `(store (getelementptr ...))` replaced by call to intrinsic `llvm.bpf.getelementptr.and.store`; - at the late IR processing stage this modification is undone. Such handling prevents various optimizer passes from generating sequences of instructions that would be rejected by BPF verifier. The __attribute__((preserve_static_offset)) has a priority over __attribute__((preserve_access_index)). When preserve_access_index attribute is present preserve access index transformations are not applied. This addresses the issue reported by the following thread: https://lore.kernel.org/bpf/CAA-VZPmxh8o8EBcJ=m-DH4ytcxDFmo0JKsm1p1gf40kS0CE3NQ@mail.gmail.com/T/#m4b9ce2ce73b34f34172328f975235fc6f19841b6 This is a second attempt to commit this change, previous reverted commit is: cb13e92. The following items had been fixed: - test case bpf-preserve-static-offset-bitfield.c now uses `-triple bpfel` to avoid different codegen for little/big endian targets. - BPFPreserveStaticOffset.cpp:removePAICalls() modified to avoid use after free for `WorkList` elements `V`. Differential Revision: https://reviews.llvm.org/D133361
1 parent 31aebdd commit 030b8cb

File tree

65 files changed

+4343
-35
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

65 files changed

+4343
-35
lines changed

clang/include/clang/Basic/Attr.td

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2024,6 +2024,14 @@ def BPFPreserveAccessIndex : InheritableAttr,
20242024
let LangOpts = [COnly];
20252025
}
20262026

2027+
def BPFPreserveStaticOffset : InheritableAttr,
2028+
TargetSpecificAttr<TargetBPF> {
2029+
let Spellings = [Clang<"preserve_static_offset">];
2030+
let Subjects = SubjectList<[Record], ErrorDiag>;
2031+
let Documentation = [BPFPreserveStaticOffsetDocs];
2032+
let LangOpts = [COnly];
2033+
}
2034+
20272035
def BTFDeclTag : InheritableAttr {
20282036
let Spellings = [Clang<"btf_decl_tag">];
20292037
let Args = [StringArgument<"BTFDeclTag">];

clang/include/clang/Basic/AttrDocs.td

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2199,6 +2199,43 @@ preserving struct or union member access debuginfo indices of this
21992199
struct or union, similar to clang ``__builtin_preserve_access_index()``.
22002200
}];
22012201
}
2202+
2203+
def BPFPreserveStaticOffsetDocs : Documentation {
2204+
let Category = DocCatFunction;
2205+
let Content = [{
2206+
Clang supports the ``__attribute__((preserve_static_offset))``
2207+
attribute for the BPF target. This attribute may be attached to a
2208+
struct or union declaration. Reading or writing fields of types having
2209+
such annotation is guaranteed to generate LDX/ST/STX instruction with
2210+
offset corresponding to the field.
2211+
2212+
For example:
2213+
2214+
.. code-block:: c
2215+
2216+
struct foo {
2217+
int a;
2218+
int b;
2219+
};
2220+
2221+
struct bar {
2222+
int a;
2223+
struct foo b;
2224+
} __attribute__((preserve_static_offset));
2225+
2226+
void buz(struct bar *g) {
2227+
g->b.a = 42;
2228+
}
2229+
2230+
The assignment to ``g``'s field would produce an ST instruction with
2231+
offset 8: ``*(u32)(r1 + 8) = 42;``.
2232+
2233+
Without this attribute generated instructions might be different,
2234+
depending on optimizations behavior. E.g. the example above could be
2235+
rewritten as ``r1 += 8; *(u32)(r1 + 0) = 42;``.
2236+
}];
2237+
}
2238+
22022239
def BTFDeclTagDocs : Documentation {
22032240
let Category = DocCatFunction;
22042241
let Content = [{

clang/lib/CodeGen/CGExpr.cpp

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3833,6 +3833,33 @@ static QualType getFixedSizeElementType(const ASTContext &ctx,
38333833
return eltType;
38343834
}
38353835

3836+
static bool hasBPFPreserveStaticOffset(const RecordDecl *D) {
3837+
return D && D->hasAttr<BPFPreserveStaticOffsetAttr>();
3838+
}
3839+
3840+
static bool hasBPFPreserveStaticOffset(const Expr *E) {
3841+
if (!E)
3842+
return false;
3843+
QualType PointeeType = E->getType()->getPointeeType();
3844+
if (PointeeType.isNull())
3845+
return false;
3846+
if (const auto *BaseDecl = PointeeType->getAsRecordDecl())
3847+
return hasBPFPreserveStaticOffset(BaseDecl);
3848+
return false;
3849+
}
3850+
3851+
// Wraps Addr with a call to llvm.preserve.static.offset intrinsic.
3852+
static Address wrapWithBPFPreserveStaticOffset(CodeGenFunction &CGF,
3853+
Address &Addr) {
3854+
if (!CGF.getTarget().getTriple().isBPF())
3855+
return Addr;
3856+
3857+
llvm::Function *Fn =
3858+
CGF.CGM.getIntrinsic(llvm::Intrinsic::preserve_static_offset);
3859+
llvm::CallInst *Call = CGF.Builder.CreateCall(Fn, {Addr.getPointer()});
3860+
return Address(Call, Addr.getElementType(), Addr.getAlignment());
3861+
}
3862+
38363863
/// Given an array base, check whether its member access belongs to a record
38373864
/// with preserve_access_index attribute or not.
38383865
static bool IsPreserveAIArrayBase(CodeGenFunction &CGF, const Expr *ArrayBase) {
@@ -3894,6 +3921,9 @@ static Address emitArraySubscriptGEP(CodeGenFunction &CGF, Address addr,
38943921
CharUnits eltAlign =
38953922
getArrayElementAlign(addr.getAlignment(), indices.back(), eltSize);
38963923

3924+
if (hasBPFPreserveStaticOffset(Base))
3925+
addr = wrapWithBPFPreserveStaticOffset(CGF, addr);
3926+
38973927
llvm::Value *eltPtr;
38983928
auto LastIndex = dyn_cast<llvm::ConstantInt>(indices.back());
38993929
if (!LastIndex ||
@@ -4522,6 +4552,8 @@ LValue CodeGenFunction::EmitLValueForField(LValue base,
45224552
Address Addr = base.getAddress(*this);
45234553
unsigned Idx = RL.getLLVMFieldNo(field);
45244554
const RecordDecl *rec = field->getParent();
4555+
if (hasBPFPreserveStaticOffset(rec))
4556+
Addr = wrapWithBPFPreserveStaticOffset(*this, Addr);
45254557
if (!UseVolatile) {
45264558
if (!IsInPreservedAIRegion &&
45274559
(!getDebugInfo() || !rec->hasAttr<BPFPreserveAccessIndexAttr>())) {
@@ -4594,6 +4626,8 @@ LValue CodeGenFunction::EmitLValueForField(LValue base,
45944626
}
45954627

45964628
Address addr = base.getAddress(*this);
4629+
if (hasBPFPreserveStaticOffset(rec))
4630+
addr = wrapWithBPFPreserveStaticOffset(*this, addr);
45974631
if (auto *ClassDef = dyn_cast<CXXRecordDecl>(rec)) {
45984632
if (CGM.getCodeGenOpts().StrictVTablePointers &&
45994633
ClassDef->isDynamicClass()) {

clang/lib/Sema/SemaDeclAttr.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9036,6 +9036,9 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL,
90369036
case ParsedAttr::AT_BPFPreserveAccessIndex:
90379037
handleBPFPreserveAccessIndexAttr(S, D, AL);
90389038
break;
9039+
case ParsedAttr::AT_BPFPreserveStaticOffset:
9040+
handleSimpleAttribute<BPFPreserveStaticOffsetAttr>(S, D, AL);
9041+
break;
90399042
case ParsedAttr::AT_BTFDeclTag:
90409043
handleBTFDeclTagAttr(S, D, AL);
90419044
break;
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 2
2+
// REQUIRES: bpf-registered-target
3+
// RUN: %clang -cc1 -triple bpf -disable-llvm-passes -S -emit-llvm -o - %s \
4+
// RUN: | FileCheck %s
5+
6+
// Check that call to preserve.static.offset is generated when array
7+
// member of a struct marked with __attribute__((preserve_static_offset))
8+
// is accessed.
9+
10+
#define __ctx __attribute__((preserve_static_offset))
11+
12+
struct foo {
13+
struct {
14+
int a;
15+
} b[7];
16+
} __ctx;
17+
18+
// CHECK-LABEL: define dso_local i32 @arr_access
19+
// CHECK-SAME: (ptr noundef [[P:%.*]]) #[[ATTR0:[0-9]+]] {
20+
// CHECK-NEXT: entry:
21+
// CHECK-NEXT: [[P_ADDR:%.*]] = alloca ptr, align 8
22+
// CHECK-NEXT: store ptr [[P]], ptr [[P_ADDR]], align 8
23+
// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[P_ADDR]], align 8
24+
// CHECK-NEXT: [[TMP1:%.*]] = call ptr @llvm.preserve.static.offset(ptr [[TMP0]])
25+
// CHECK-NEXT: [[B:%.*]] = getelementptr inbounds [[STRUCT_FOO:%.*]], ptr [[TMP1]], i32 0, i32 0
26+
// CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [7 x %struct.anon], ptr [[B]], i64 0, i64 2
27+
// CHECK-NEXT: [[A:%.*]] = getelementptr inbounds [[STRUCT_ANON:%.*]], ptr [[ARRAYIDX]], i32 0, i32 0
28+
// CHECK-NEXT: [[TMP2:%.*]] = load i32, ptr [[A]], align 4
29+
// CHECK-NEXT: ret i32 [[TMP2]]
30+
//
31+
int arr_access(struct foo *p) {
32+
return p->b[2].a;
33+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 2
2+
// REQUIRES: bpf-registered-target
3+
// RUN: %clang -cc1 -triple bpfel -disable-llvm-passes -S -emit-llvm -o - %s \
4+
// RUN: | FileCheck %s
5+
6+
// Check that call to preserve.static.offset is generated when bitfield
7+
// from a struct marked with __attribute__((preserve_static_offset)) is
8+
// accessed.
9+
10+
#define __ctx __attribute__((preserve_static_offset))
11+
12+
struct foo {
13+
unsigned a:1;
14+
} __ctx;
15+
16+
// CHECK-LABEL: define dso_local void @lvalue_bitfield
17+
// CHECK-SAME: (ptr noundef [[P:%.*]]) #[[ATTR0:[0-9]+]] {
18+
// CHECK-NEXT: entry:
19+
// CHECK-NEXT: [[P_ADDR:%.*]] = alloca ptr, align 8
20+
// CHECK-NEXT: store ptr [[P]], ptr [[P_ADDR]], align 8
21+
// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[P_ADDR]], align 8
22+
// CHECK-NEXT: [[TMP1:%.*]] = call ptr @llvm.preserve.static.offset(ptr [[TMP0]])
23+
// CHECK-NEXT: [[BF_LOAD:%.*]] = load i8, ptr [[TMP1]], align 4
24+
// CHECK-NEXT: [[BF_CLEAR:%.*]] = and i8 [[BF_LOAD]], -2
25+
// CHECK-NEXT: [[BF_SET:%.*]] = or i8 [[BF_CLEAR]], 1
26+
// CHECK-NEXT: store i8 [[BF_SET]], ptr [[TMP1]], align 4
27+
// CHECK-NEXT: ret void
28+
//
29+
void lvalue_bitfield(struct foo *p) {
30+
p->a = 1;
31+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 2
2+
// REQUIRES: bpf-registered-target
3+
// RUN: %clang -cc1 -triple bpf -disable-llvm-passes -S -emit-llvm -o - %s \
4+
// RUN: | FileCheck %s
5+
6+
// Check that call to preserve.static.offset is generated when field of
7+
// a struct marked with __attribute__((preserve_static_offset)) is accessed.
8+
9+
#define __ctx __attribute__((preserve_static_offset))
10+
11+
struct foo {
12+
int a;
13+
} __ctx;
14+
15+
// CHECK-LABEL: define dso_local void @lvalue
16+
// CHECK-SAME: (ptr noundef [[P:%.*]]) #[[ATTR0:[0-9]+]] {
17+
// CHECK-NEXT: entry:
18+
// CHECK-NEXT: [[P_ADDR:%.*]] = alloca ptr, align 8
19+
// CHECK-NEXT: store ptr [[P]], ptr [[P_ADDR]], align 8
20+
// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[P_ADDR]], align 8
21+
// CHECK-NEXT: [[TMP1:%.*]] = call ptr @llvm.preserve.static.offset(ptr [[TMP0]])
22+
// CHECK-NEXT: [[A:%.*]] = getelementptr inbounds [[STRUCT_FOO:%.*]], ptr [[TMP1]], i32 0, i32 0
23+
// CHECK-NEXT: store i32 42, ptr [[A]], align 4
24+
// CHECK-NEXT: ret void
25+
//
26+
void lvalue(struct foo *p) {
27+
p->a = 42;
28+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// REQUIRES: x86-registered-target
2+
// RUN: %clang -cc1 -triple x86_64 -disable-llvm-passes -S -emit-llvm -o - %s \
3+
// RUN: | FileCheck %s
4+
5+
// Verify that __attribute__((preserve_static_offset))
6+
// has no effect for non-BPF target.
7+
8+
#define __ctx __attribute__((preserve_static_offset))
9+
10+
struct foo {
11+
int a;
12+
} __ctx;
13+
14+
// CHECK-NOT: @llvm_preserve_static_offset
15+
16+
int bar(struct foo *p) {
17+
return p->a;
18+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 2
2+
// REQUIRES: bpf-registered-target
3+
// RUN: %clang -cc1 -triple bpf -disable-llvm-passes -S -emit-llvm -o - %s \
4+
// RUN: | FileCheck %s
5+
6+
// Verify that preserve_static_offset does not interfere with
7+
// preserve_access_index at IR generation stage.
8+
9+
#define __ctx __attribute__((preserve_static_offset))
10+
#define __pai __attribute__((preserve_access_index))
11+
12+
struct foo {
13+
int a;
14+
} __ctx __pai;
15+
16+
// CHECK-LABEL: define dso_local i32 @bar
17+
// CHECK-SAME: (ptr noundef [[P:%.*]]) #[[ATTR0:[0-9]+]] {
18+
// CHECK-NEXT: entry:
19+
// CHECK-NEXT: [[P_ADDR:%.*]] = alloca ptr, align 8
20+
// CHECK-NEXT: store ptr [[P]], ptr [[P_ADDR]], align 8
21+
// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[P_ADDR]], align 8
22+
// CHECK-NEXT: [[TMP1:%.*]] = call ptr @llvm.preserve.static.offset(ptr [[TMP0]])
23+
// CHECK-NEXT: [[A:%.*]] = getelementptr inbounds [[STRUCT_FOO:%.*]], ptr [[TMP1]], i32 0, i32 0
24+
// CHECK-NEXT: [[TMP2:%.*]] = load i32, ptr [[A]], align 4
25+
// CHECK-NEXT: ret i32 [[TMP2]]
26+
//
27+
int bar(struct foo *p) {
28+
return p->a;
29+
}

clang/test/Misc/pragma-attribute-supported-attributes-list.test

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
// 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))
2424
// CHECK-NEXT: AvailableOnlyInDefaultEvalMethod (SubjectMatchRule_type_alias)
2525
// CHECK-NEXT: BPFPreserveAccessIndex (SubjectMatchRule_record)
26+
// CHECK-NEXT: BPFPreserveStaticOffset (SubjectMatchRule_record)
2627
// CHECK-NEXT: BTFDeclTag (SubjectMatchRule_variable, SubjectMatchRule_function, SubjectMatchRule_record, SubjectMatchRule_field, SubjectMatchRule_type_alias)
2728
// CHECK-NEXT: BuiltinAlias (SubjectMatchRule_function)
2829
// CHECK-NEXT: CFAuditedTransfer (SubjectMatchRule_function)
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
// RUN: %clang_cc1 -fsyntax-only -verify %s
2+
3+
#define __pso __attribute__((preserve_static_offset))
4+
5+
struct foo { int a; } __pso; // expected-warning{{unknown attribute}}
6+
union quux { int a; } __pso; // expected-warning{{unknown attribute}}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// RUN: %clang_cc1 -fsyntax-only -verify -triple bpf-pc-linux-gnu %s
2+
3+
#define __pso __attribute__((preserve_static_offset))
4+
5+
// These are correct usages.
6+
struct foo { int a; } __pso;
7+
union quux { int a; } __pso;
8+
struct doug { int a; } __pso __attribute__((packed));
9+
10+
// Rest are incorrect usages.
11+
typedef int bar __pso; // expected-error{{attribute only applies to}}
12+
struct goo {
13+
int a __pso; // expected-error{{attribute only applies to}}
14+
};
15+
int g __pso; // expected-error{{attribute only applies to}}
16+
__pso void ffunc1(void); // expected-error{{attribute only applies to}}
17+
void ffunc2(int a __pso); // expected-error{{attribute only applies to}}
18+
void ffunc3(void) {
19+
int a __pso; // expected-error{{attribute only applies to}}
20+
}
21+
22+
struct buz { int a; } __attribute__((preserve_static_offset("hello"))); // \
23+
expected-error{{attribute takes no arguments}}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// RUN: %clang_cc1 -fsyntax-only -ast-dump -triple bpf-pc-linux-gnu %s | FileCheck %s
2+
3+
// The 'preserve_static_offset' attribute should be propagated to
4+
// inline declarations (foo's 'b', 'bb', 'c' but not 'd').
5+
//
6+
// CHECK: RecordDecl {{.*}} struct foo definition
7+
// CHECK-NEXT: BPFPreserveStaticOffsetAttr
8+
// CHECK-NEXT: FieldDecl {{.*}} a
9+
// CHECK-NEXT: RecordDecl {{.*}} struct definition
10+
// CHECK-NEXT: FieldDecl {{.*}} aa
11+
// CHECK-NEXT: FieldDecl {{.*}} b
12+
// CHECK-NEXT: RecordDecl {{.*}} union bar definition
13+
// CHECK-NEXT: BPFPreserveStaticOffsetAttr
14+
// CHECK-NEXT: FieldDecl {{.*}} a
15+
// CHECK-NEXT: FieldDecl {{.*}} b
16+
17+
struct foo {
18+
int a;
19+
struct {
20+
int aa;
21+
} b;
22+
} __attribute__((preserve_static_offset));
23+
24+
union bar {
25+
int a;
26+
long b;
27+
} __attribute__((preserve_static_offset));

llvm/include/llvm/IR/Intrinsics.td

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2469,6 +2469,10 @@ def int_preserve_struct_access_index : DefaultAttrsIntrinsic<[llvm_anyptr_ty],
24692469
[IntrNoMem,
24702470
ImmArg<ArgIndex<1>>,
24712471
ImmArg<ArgIndex<2>>]>;
2472+
def int_preserve_static_offset : DefaultAttrsIntrinsic<[llvm_ptr_ty],
2473+
[llvm_ptr_ty],
2474+
[IntrNoMem, IntrSpeculatable,
2475+
ReadNone <ArgIndex<0>>]>;
24722476

24732477
//===------------ Intrinsics to perform common vector shuffles ------------===//
24742478

llvm/include/llvm/IR/IntrinsicsBPF.td

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,4 +37,43 @@ let TargetPrefix = "bpf" in { // All intrinsics start with "llvm.bpf."
3737
def int_bpf_compare : ClangBuiltin<"__builtin_bpf_compare">,
3838
Intrinsic<[llvm_i1_ty], [llvm_i32_ty, llvm_anyint_ty, llvm_anyint_ty],
3939
[IntrNoMem]>;
40+
def int_bpf_getelementptr_and_load : ClangBuiltin<"__builtin_bpf_getelementptr_and_load">,
41+
Intrinsic<[llvm_any_ty],
42+
[llvm_ptr_ty, // base ptr for getelementptr
43+
llvm_i1_ty, // volatile
44+
llvm_i8_ty, // atomic order
45+
llvm_i8_ty, // synscope id
46+
llvm_i8_ty, // alignment
47+
llvm_i1_ty, // inbounds
48+
llvm_vararg_ty], // indices for getelementptr insn
49+
[IntrNoCallback,
50+
IntrNoFree,
51+
IntrWillReturn,
52+
NoCapture <ArgIndex<0>>,
53+
ImmArg <ArgIndex<1>>, // volatile
54+
ImmArg <ArgIndex<2>>, // atomic order
55+
ImmArg <ArgIndex<3>>, // synscope id
56+
ImmArg <ArgIndex<4>>, // alignment
57+
ImmArg <ArgIndex<5>>, // inbounds
58+
]>;
59+
def int_bpf_getelementptr_and_store : ClangBuiltin<"__builtin_bpf_getelementptr_and_store">,
60+
Intrinsic<[],
61+
[llvm_any_ty, // value to store
62+
llvm_ptr_ty, // base ptr for getelementptr
63+
llvm_i1_ty, // volatile
64+
llvm_i8_ty, // atomic order
65+
llvm_i8_ty, // syncscope id
66+
llvm_i8_ty, // alignment
67+
llvm_i1_ty, // inbounds
68+
llvm_vararg_ty], // indexes for getelementptr insn
69+
[IntrNoCallback,
70+
IntrNoFree,
71+
IntrWillReturn,
72+
NoCapture <ArgIndex<1>>,
73+
ImmArg <ArgIndex<2>>, // volatile
74+
ImmArg <ArgIndex<3>>, // atomic order
75+
ImmArg <ArgIndex<4>>, // syncscope id
76+
ImmArg <ArgIndex<5>>, // alignment
77+
ImmArg <ArgIndex<6>>, // inbounds
78+
]>;
4079
}

0 commit comments

Comments
 (0)