llvm.org GIT mirror llvm / 35c568c
[BPF] add new intrinsics preserve_{array,union,struct}_access_index For background of BPF CO-RE project, please refer to http://vger.kernel.org/bpfconf2019.html In summary, BPF CO-RE intends to compile bpf programs adjustable on struct/union layout change so the same program can run on multiple kernels with adjustment before loading based on native kernel structures. In order to do this, we need keep track of GEP(getelementptr) instruction base and result debuginfo types, so we can adjust on the host based on kernel BTF info. Capturing such information as an IR optimization is hard as various optimization may have tweaked GEP and also union is replaced by structure it is impossible to track fieldindex for union member accesses. Three intrinsic functions, preserve_{array,union,struct}_access_index, are introducted. addr = preserve_array_access_index(base, index, dimension) addr = preserve_union_access_index(base, di_index) addr = preserve_struct_access_index(base, gep_index, di_index) here, base: the base pointer for the array/union/struct access. index: the last access index for array, the same for IR/DebugInfo layout. dimension: the array dimension. gep_index: the access index based on IR layout. di_index: the access index based on user/debuginfo types. For example, for the following example, $ cat test.c struct sk_buff { int i; int b1:1; int b2:2; union { struct { int o1; int o2; } o; struct { char flags; char dev_id; } dev; int netid; } u[10]; }; static int (*bpf_probe_read)(void *dst, int size, const void *unsafe_ptr) = (void *) 4; #define _(x) (__builtin_preserve_access_index(x)) int bpf_prog(struct sk_buff *ctx) { char dev_id; bpf_probe_read(&dev_id, sizeof(char), _(&ctx->u[5].dev.dev_id)); return dev_id; } $ clang -target bpf -O2 -g -emit-llvm -S -mllvm -print-before-all \ test.c >& log The generated IR looks like below: ... define dso_local i32 @bpf_prog(%struct.sk_buff*) #0 !dbg !15 { %2 = alloca %struct.sk_buff*, align 8 %3 = alloca i8, align 1 store %struct.sk_buff* %0, %struct.sk_buff** %2, align 8, !tbaa !45 call void @llvm.dbg.declare(metadata %struct.sk_buff** %2, metadata !43, metadata !DIExpression()), !dbg !49 call void @llvm.lifetime.start.p0i8(i64 1, i8* %3) #4, !dbg !50 call void @llvm.dbg.declare(metadata i8* %3, metadata !44, metadata !DIExpression()), !dbg !51 %4 = load i32 (i8*, i32, i8*)*, i32 (i8*, i32, i8*)** @bpf_probe_read, align 8, !dbg !52, !tbaa !45 %5 = load %struct.sk_buff*, %struct.sk_buff** %2, align 8, !dbg !53, !tbaa !45 %6 = call [10 x %union.anon]* @llvm.preserve.struct.access.index.p0a10s_union.anons.p0s_struct.sk_buffs( %struct.sk_buff* %5, i32 2, i32 3), !dbg !53, !llvm.preserve.access.index !19 %7 = call %union.anon* @llvm.preserve.array.access.index.p0s_union.anons.p0a10s_union.anons( [10 x %union.anon]* %6, i32 1, i32 5), !dbg !53 %8 = call %union.anon* @llvm.preserve.union.access.index.p0s_union.anons.p0s_union.anons( %union.anon* %7, i32 1), !dbg !53, !llvm.preserve.access.index !26 %9 = bitcast %union.anon* %8 to %struct.anon.0*, !dbg !53 %10 = call i8* @llvm.preserve.struct.access.index.p0i8.p0s_struct.anon.0s( %struct.anon.0* %9, i32 1, i32 1), !dbg !53, !llvm.preserve.access.index !34 %11 = call i32 %4(i8* %3, i32 1, i8* %10), !dbg !52 %12 = load i8, i8* %3, align 1, !dbg !54, !tbaa !55 %13 = sext i8 %12 to i32, !dbg !54 call void @llvm.lifetime.end.p0i8(i64 1, i8* %3) #4, !dbg !56 ret i32 %13, !dbg !57 } !19 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "sk_buff", file: !3, line: 1, size: 704, elements: !20) !26 = distinct !DICompositeType(tag: DW_TAG_union_type, scope: !19, file: !3, line: 5, size: 64, elements: !27) !34 = distinct !DICompositeType(tag: DW_TAG_structure_type, scope: !26, file: !3, line: 10, size: 16, elements: !35) Note that @llvm.preserve.{struct,union}.access.index calls have metadata llvm.preserve.access.index attached to instructions to provide struct/union debuginfo type information. For &ctx->u[5].dev.dev_id, . The "%6 = ..." represents struct member "u" with index 2 for IR layout and index 3 for DI layout. . The "%7 = ..." represents array subscript "5". . The "%8 = ..." represents union member "dev" with index 1 for DI layout. . The "%10 = ..." represents struct member "dev_id" with index 1 for both IR and DI layout. Basically, traversing the use-def chain recursively for the 3rd argument of bpf_probe_read() and examining all preserve_*_access_index calls, the debuginfo struct/union/array access index can be achieved. The intrinsics also contain enough information to regenerate codes for IR layout. For array and structure intrinsics, the proper GEP can be constructed. For union intrinsics, replacing all uses of "addr" with "base" should be enough. Signed-off-by: Yonghong Song <yhs@fb.com> Differential Revision: https://reviews.llvm.org/D61810 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@365352 91177308-0d34-0410-b5e6-96231b3b80d8 Yonghong Song a month ago
5 changed file(s) with 189 addition(s) and 1 deletion(s). Raw diff Collapse all Expand all
1730317303 """""""""
1730417304
1730517305 Lowers to a call to `objc_storeWeak `_.
17306
17307 Preserving Debug Information Intrinsics
17308 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
17309
17310 These intrinsics are used to carry certain debuginfo together with
17311 IR-level operations. For example, it may be desirable to
17312 know the structure/union name and the original user-level field
17313 indices. Such information got lost in IR GetElementPtr instruction
17314 since the IR types are different from debugInfo types and unions
17315 are converted to structs in IR.
17316
17317 '``llvm.preserve.array.access.index``' Intrinsic
17318 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
17319
17320 Syntax:
17321 """""""
17322 ::
17323
17324 declare
17325 @llvm.preserve.array.access.index.p0s_union.anons.p0a10s_union.anons( base,
17326 i32 dim,
17327 i32 index)
17328
17329 Overview:
17330 """""""""
17331
17332 The '``llvm.preserve.array.access.index``' intrinsic returns the getelementptr address
17333 based on array base ``base``, array dimension ``dim`` and the last access index ``index``
17334 into the array.
17335
17336 Arguments:
17337 """"""""""
17338
17339 The ``base`` is the array base address. The ``dim`` is the array dimension.
17340 The ``base`` is a pointer if ``dim`` equals 0.
17341 The ``index`` is the last access index into the array or pointer.
17342
17343 Semantics:
17344 """"""""""
17345
17346 The '``llvm.preserve.array.access.index``' intrinsic produces the same result
17347 as a getelementptr with base ``base`` and access operands ``{dim's 0's, index}``.
17348
17349 '``llvm.preserve.union.access.index``' Intrinsic
17350 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
17351
17352 Syntax:
17353 """""""
17354 ::
17355
17356 declare
17357 @llvm.preserve.union.access.index.p0s_union.anons.p0s_union.anons( base,
17358 i32 di_index)
17359
17360 Overview:
17361 """""""""
17362
17363 The '``llvm.preserve.union.access.index``' intrinsic carries the debuginfo field index
17364 ``di_index`` and returns the ``base`` address.
17365 The ``llvm.preserve.access.index`` type of metadata is attached to this call instruction
17366 to provide union debuginfo type.
17367
17368 Arguments:
17369 """"""""""
17370
17371 The ``base`` is the union base address. The ``di_index`` is the field index in debuginfo.
17372
17373 Semantics:
17374 """"""""""
17375
17376 The '``llvm.preserve.union.access.index``' intrinsic returns the ``base`` address.
17377
17378 '``llvm.preserve.struct.access.index``' Intrinsic
17379 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
17380
17381 Syntax:
17382 """""""
17383 ::
17384
17385 declare
17386 @llvm.preserve.struct.access.index.p0i8.p0s_struct.anon.0s( base,
17387 i32 gep_index,
17388 i32 di_index)
17389
17390 Overview:
17391 """""""""
17392
17393 The '``llvm.preserve.struct.access.index``' intrinsic returns the getelementptr address
17394 based on struct base ``base`` and IR struct member index ``gep_index``.
17395 The ``llvm.preserve.access.index`` type of metadata is attached to this call instruction
17396 to provide struct debuginfo type.
17397
17398 Arguments:
17399 """"""""""
17400
17401 The ``base`` is the structure base address. The ``gep_index`` is the struct member index
17402 based on IR structures. The ``di_index`` is the struct member index based on debuginfo.
17403
17404 Semantics:
17405 """"""""""
17406
17407 The '``llvm.preserve.struct.access.index``' intrinsic produces the same result
17408 as a getelementptr with base ``base`` and access operands ``{0, gep_index}``.
24522452 return V;
24532453 }
24542454
2455 Value *CreatePreserveArrayAccessIndex(Value *Base, unsigned Dimension,
2456 unsigned LastIndex) {
2457 assert(isa(Base->getType()) &&
2458 "Invalid Base ptr type for preserve.array.access.index.");
2459 auto *BaseType = Base->getType();
2460
2461 Value *LastIndexV = getInt32(LastIndex);
2462 Constant *Zero = ConstantInt::get(Type::getInt32Ty(Context), 0);
2463 SmallVector IdxList;
2464 for (unsigned I = 0; I < Dimension; ++I)
2465 IdxList.push_back(Zero);
2466 IdxList.push_back(LastIndexV);
2467
2468 Type *ResultType =
2469 GetElementPtrInst::getGEPReturnType(Base, IdxList);
2470
2471 Module *M = BB->getParent()->getParent();
2472 Function *FnPreserveArrayAccessIndex = Intrinsic::getDeclaration(
2473 M, Intrinsic::preserve_array_access_index, {ResultType, BaseType});
2474
2475 Value *DimV = getInt32(Dimension);
2476 CallInst *Fn =
2477 CreateCall(FnPreserveArrayAccessIndex, {Base, DimV, LastIndexV});
2478
2479 return Fn;
2480 }
2481
2482 Value *CreatePreserveUnionAccessIndex(Value *Base, unsigned FieldIndex,
2483 MDNode *DbgInfo) {
2484 assert(isa(Base->getType()) &&
2485 "Invalid Base ptr type for preserve.union.access.index.");
2486 auto *BaseType = Base->getType();
2487
2488 Module *M = BB->getParent()->getParent();
2489 Function *FnPreserveUnionAccessIndex = Intrinsic::getDeclaration(
2490 M, Intrinsic::preserve_union_access_index, {BaseType, BaseType});
2491
2492 Value *DIIndex = getInt32(FieldIndex);
2493 CallInst *Fn =
2494 CreateCall(FnPreserveUnionAccessIndex, {Base, DIIndex});
2495 Fn->setMetadata(LLVMContext::MD_preserve_access_index, DbgInfo);
2496
2497 return Fn;
2498 }
2499
2500 Value *CreatePreserveStructAccessIndex(Value *Base, unsigned Index,
2501 unsigned FieldIndex, MDNode *DbgInfo) {
2502 assert(isa(Base->getType()) &&
2503 "Invalid Base ptr type for preserve.struct.access.index.");
2504 auto *BaseType = Base->getType();
2505
2506 Value *GEPIndex = getInt32(Index);
2507 Constant *Zero = ConstantInt::get(Type::getInt32Ty(Context), 0);
2508 Type *ResultType =
2509 GetElementPtrInst::getGEPReturnType(Base, {Zero, GEPIndex});
2510
2511 Module *M = BB->getParent()->getParent();
2512 Function *FnPreserveStructAccessIndex = Intrinsic::getDeclaration(
2513 M, Intrinsic::preserve_struct_access_index, {ResultType, BaseType});
2514
2515 Value *DIIndex = getInt32(FieldIndex);
2516 CallInst *Fn = CreateCall(FnPreserveStructAccessIndex,
2517 {Base, GEPIndex, DIIndex});
2518 Fn->setMetadata(LLVMContext::MD_preserve_access_index, DbgInfo);
2519
2520 return Fn;
2521 }
2522
24552523 private:
24562524 /// Helper function that creates an assume intrinsic call that
24572525 /// represents an alignment assumption on the provided Ptr, Mask, Type
10391039 // Intrinsic to detect whether its argument is a constant.
10401040 def int_is_constant : Intrinsic<[llvm_i1_ty], [llvm_any_ty], [IntrNoMem], "llvm.is.constant">;
10411041
1042
10431042 //===-------------------------- Masked Intrinsics -------------------------===//
10441043 //
10451044 def int_masked_store : Intrinsic<[], [llvm_anyvector_ty,
12131212
12141213 def int_ssa_copy : Intrinsic<[llvm_any_ty], [LLVMMatchType<0>],
12151214 [IntrNoMem, Returned<0>]>;
1215
1216 //===------- Intrinsics that are used to preserve debug information -------===//
1217
1218 def int_preserve_array_access_index : Intrinsic<[llvm_anyptr_ty],
1219 [llvm_anyptr_ty, llvm_i32_ty,
1220 llvm_i32_ty],
1221 [IntrNoMem, ImmArg<1>, ImmArg<2>]>;
1222 def int_preserve_union_access_index : Intrinsic<[llvm_anyptr_ty],
1223 [llvm_anyptr_ty, llvm_i32_ty],
1224 [IntrNoMem, ImmArg<1>]>;
1225 def int_preserve_struct_access_index : Intrinsic<[llvm_anyptr_ty],
1226 [llvm_anyptr_ty, llvm_i32_ty,
1227 llvm_i32_ty],
1228 [IntrNoMem, ImmArg<1>,
1229 ImmArg<2>]>;
1230
12161231 //===----------------------------------------------------------------------===//
12171232 // Target-specific intrinsics
12181233 //===----------------------------------------------------------------------===//
9898 MD_irr_loop = 24, // "irr_loop"
9999 MD_access_group = 25, // "llvm.access.group"
100100 MD_callback = 26, // "callback"
101 MD_preserve_access_index = 27, // "llvm.preserve.*.access.index"
101102 };
102103
103104 /// Known operand bundle tag IDs, which always have the same value. All
6262 {MD_irr_loop, "irr_loop"},
6363 {MD_access_group, "llvm.access.group"},
6464 {MD_callback, "callback"},
65 {MD_preserve_access_index, "llvm.preserve.access.index"},
6566 };
6667
6768 for (auto &MDKind : MDKinds) {