[llvm] [BPF] Support wrapping BPF map structs into nested, single field structs (PR #144097)
Michal Rostecki via llvm-commits
llvm-commits at lists.llvm.org
Sat Jun 14 08:32:27 PDT 2025
================
@@ -0,0 +1,609 @@
+; RUN: llc -mtriple=bpfel -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK-SHORT %s
+; RUN: llc -mtriple=bpfel -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
+
+; Source code:
+; #![no_std]
+; #![no_main]
+; #![allow(dead_code)]
+;
+; pub const BPF_MAP_TYPE_HASH: usize = 1;
+;
+; // The real map definition.
+; pub struct HashMapDef<K, V, const M: usize, const F: usize> {
+; r#type: *const [i32; BPF_MAP_TYPE_HASH],
+; key: *const K,
+; value: *const V,
+; max_entries: *const [i32; M],
+; map_flags: *const [i32; F],
+; }
+; impl<K, V, const M: usize, const F: usize> HashMapDef<K, V, M, F> {
+; pub const fn new() -> Self {
+; Self {
+; r#type: &[0i32; BPF_MAP_TYPE_HASH],
+; key: ::core::ptr::null(),
+; value: ::core::ptr::null(),
+; max_entries: &[0i32; M],
+; map_flags: &[0i32; F],
+; }
+; }
+; }
+; // Use `UnsafeCell` to allow mutability by multiple threads.
+; pub struct HashMap<K, V, const M: usize, const F: usize = 0>(
+; core::cell::UnsafeCell<HashMapDef<K, V, M, F>>,
+; );
+; impl<K, V, const M: usize, const F: usize> HashMap<K, V, M, F> {
+; pub const fn new() -> Self {
+; Self(core::cell::UnsafeCell::new(HashMapDef::new()))
+; }
+; }
+; // Mark `HashMap` as thread-safe.
+; unsafe impl<K: Sync, V: Sync, const M: usize, const F: usize> Sync for HashMap<K, V, M, F> {}
+;
+; // Define custom structs for key and values.
+; pub struct MyKey(u32);
+; pub struct MyValue(u32);
+;
+; #[link_section = ".maps"]
+; #[export_name = "HASH_MAP"]
+; pub static HASH_MAP: HashMap<MyKey, MyValue, 10> = HashMap::new();
+;
+; #[cfg(not(test))]
+; #[panic_handler]
+; fn panic(_info: &core::panic::PanicInfo) -> ! {
+; loop {}
+; }
+; Compilation flag:
+; cargo +nightly rustc -Zbuild-std=core --target bpfel-unknown-none -- --emit=llvm-ir
+
+; ModuleID = 'map_def.b515d5aaa59f5dac-cgu.0'
+source_filename = "map_def.b515d5aaa59f5dac-cgu.0"
+target datalayout = "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128"
+target triple = "bpfel"
+
+ at alloc_83ea17bf0c4f4a5a5a13d3ae7955acd0 = private unnamed_addr constant [4 x i8] zeroinitializer, align 4
+ at alloc_e225df0b9c7f20aa5692610f2f2527d2 = private unnamed_addr constant [40 x i8] zeroinitializer, align 4
+ at HASH_MAP = local_unnamed_addr global <{ ptr, [16 x i8], ptr, ptr }> <{ ptr @alloc_83ea17bf0c4f4a5a5a13d3ae7955acd0, [16 x i8] zeroinitializer, ptr @alloc_e225df0b9c7f20aa5692610f2f2527d2, ptr inttoptr (i64 4 to ptr) }>, section ".maps", align 8, !dbg !0
+
+; __rustc::rust_begin_unwind
+; Function Attrs: nofree norecurse noreturn nosync nounwind memory(none)
+define hidden void @_RNvCsksSW6QfmhpE_7___rustc17rust_begin_unwind(ptr noalias nocapture noundef readonly align 8 dereferenceable(24) %_info) unnamed_addr #0 !dbg !56 {
+start:
+ #dbg_value(ptr %_info, !220, !DIExpression(), !221)
+ br label %bb1, !dbg !222
+
+bb1: ; preds = %bb1, %start
+ br label %bb1, !dbg !222
+}
+
+attributes #0 = { nofree norecurse noreturn nosync nounwind memory(none) "target-cpu"="generic" }
+
+; The resulting BTF should look like:
+; #0: <VOID>
+; #1: <PTR> --> [3]
+; #2: <INT> 'i32' bits:32 off:0 enc:signed
+; #3: <ARRAY> n:1 idx-->[4] val-->[2]
+; #4: <INT> '__ARRAY_SIZE_TYPE__' bits:32 off:0
+; #5: <PTR> --> [6]
+; #6: <STRUCT> 'MyKey' sz:4 n:1
+; #00 '__0' off:0 --> [7]
+; #7: <INT> 'u32' bits:32 off:0
+; #8: <PTR> --> [9]
+; #9: <STRUCT> 'MyValue' sz:4 n:1
+; #00 '__0' off:0 --> [7]
+; #10: <PTR> --> [11]
+; #11: <ARRAY> n:10 idx-->[4] val-->[2]
+; #12: <PTR> --> [13]
+; #13: <ARRAY> n:0 idx-->[4] val-->[2]
+; #14: <STRUCT> 'HashMapDef<map_def::MyKey, map_def::MyValue, 10, 0>' sz:40 n:5
+; #00 'type' off:0 --> [1]
+; #01 'key' off:64 --> [5]
+; #02 'value' off:128 --> [8]
+; #03 'max_entries' off:192 --> [10]
+; #04 'map_flags' off:256 --> [12]
+; #15: <STRUCT> 'UnsafeCell<map_def::HashMapDef<map_def::MyKey, map_def::MyValue, 10, 0>>' sz:40 n:1
+; #00 'value' off:0 --> [14]
+; #16: <STRUCT> 'HashMap<map_def::MyKey, map_def::MyValue, 10, 0>' sz:40 n:1
+; #00 '__0' off:0 --> [15]
+; #17: <VAR> 'HASH_MAP' kind:global-alloc --> [16]
+; #18: <PTR> --> [19]
+; #19: <STRUCT> 'PanicInfo' sz:24 n:4
+; #00 'message' off:0 --> [20]
+; #01 'location' off:64 --> [21]
+; #02 'can_unwind' off:128 --> [22]
+; #03 'force_no_backtrace' off:136 --> [22]
+; #20: <PTR> --> [27]
+; #21: <PTR> --> [28]
+; #22: <INT> 'bool' bits:8 off:0 enc:bool
+; #23: <FUNC_PROTO> r-->[0] n:1
+; #00 '_info' --> [18]
+; #24: <FUNC> 'panic' --> static [23]
+; #25: <DATASEC> '.maps' sz:0 n:1
+; #00 off:0 sz:40 --> [17]
+; #26: <DATASEC> '.rodata' sz:0 n:0
+; #27: <FWD> 'Arguments' kind:struct
+; #28: <FWD> 'Location' kind:struct
+;
+; Before bug https://github.com/llvm/llvm-project/issues/143361 was fixed, the
+; BTF kind of MyKey (#6) and MyValue (#9) would be <FWD> instead of <STRUCT>.
+; The main goal of this test is making sure that the full <STRUCT> BTF is
+; generated for these types.
+
+; We expect exactly 6 structs:
+; * MyKey
+; * MyValue
+; * HashMapDef<map_def::MyKey, map_def::MyValue, 10, 0>
+; * UnsafeCell<map_def::HashMapDef<map_def::MyKey, map_def::MyValue, 10, 0>>
+; * HashMap<map_def::MyKey, map_def::MyValue, 10, 0>
+; * PanicInfo (comes from the Rust core library)
+;
+; CHECK-SHORT-COUNT-6: BTF_KIND_STRUCT
+; CHECK-SHORT-NOT: BTF_KIND_STRUCT
+
+; We expect exactly 2 forward declarations:
+; * Arguments
+; * Location
+; Both of them come from Rust core library. These types are not used in fields
+; of any structs actually used by the program, so skipping them is absolutely
+; fine.
+;
+; CHECK-SHORT-COUNT-2: BTF_KIND_FWD
+; CHECK-SHORT-NOT: BTF_KIND_FWD
+
+; Assert the whole BTF section.
+;
+; CHECK: .section .BTF,"", at progbits
+; CHECK-NEXT: .short 60319 # 0xeb9f
+; CHECK-NEXT: .byte 1
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .long 24
+; CHECK-NEXT: .long 0
+; CHECK-NEXT: .long 568
+; CHECK-NEXT: .long 568
+; CHECK-NEXT: .long 639
+; CHECK-NEXT: .long 1 # BTF_KIND_PTR(id = 1)
+; CHECK-NEXT: .long 33554432 # 0x2000000
+; CHECK-NEXT: .long 3
+; CHECK-NEXT: .long 17 # BTF_KIND_INT(id = 2)
+; CHECK-NEXT: .long 16777216 # 0x1000000
+; CHECK-NEXT: .long 4
+; CHECK-NEXT: .long 16777248 # 0x1000020
+; CHECK-NEXT: .long 0 # BTF_KIND_ARRAY(id = 3)
+; CHECK-NEXT: .long 50331648 # 0x3000000
+; CHECK-NEXT: .long 0
+; CHECK-NEXT: .long 2
+; CHECK-NEXT: .long 4
+; CHECK-NEXT: .long 1
+; CHECK-NEXT: .long 21 # BTF_KIND_INT(id = 4)
+; CHECK-NEXT: .long 16777216 # 0x1000000
+; CHECK-NEXT: .long 4
+; CHECK-NEXT: .long 32 # 0x20
+; CHECK-NEXT: .long 41 # BTF_KIND_PTR(id = 5)
+; CHECK-NEXT: .long 33554432 # 0x2000000
+; CHECK-NEXT: .long 6
+; CHECK-NEXT: .long 63 # BTF_KIND_STRUCT(id = 6)
+; CHECK-NEXT: .long 67108865 # 0x4000001
+; CHECK-NEXT: .long 4
+; CHECK-NEXT: .long 69
+; CHECK-NEXT: .long 7
+; CHECK-NEXT: .long 0 # 0x0
+; CHECK-NEXT: .long 73 # BTF_KIND_INT(id = 7)
+; CHECK-NEXT: .long 16777216 # 0x1000000
+; CHECK-NEXT: .long 4
+; CHECK-NEXT: .long 32 # 0x20
+; CHECK-NEXT: .long 77 # BTF_KIND_PTR(id = 8)
+; CHECK-NEXT: .long 33554432 # 0x2000000
+; CHECK-NEXT: .long 9
+; CHECK-NEXT: .long 101 # BTF_KIND_STRUCT(id = 9)
+; CHECK-NEXT: .long 67108865 # 0x4000001
+; CHECK-NEXT: .long 4
+; CHECK-NEXT: .long 69
+; CHECK-NEXT: .long 7
+; CHECK-NEXT: .long 0 # 0x0
+; CHECK-NEXT: .long 109 # BTF_KIND_PTR(id = 10)
+; CHECK-NEXT: .long 33554432 # 0x2000000
+; CHECK-NEXT: .long 11
+; CHECK-NEXT: .long 0 # BTF_KIND_ARRAY(id = 11)
+; CHECK-NEXT: .long 50331648 # 0x3000000
+; CHECK-NEXT: .long 0
+; CHECK-NEXT: .long 2
+; CHECK-NEXT: .long 4
+; CHECK-NEXT: .long 10
+; CHECK-NEXT: .long 126 # BTF_KIND_PTR(id = 12)
+; CHECK-NEXT: .long 33554432 # 0x2000000
+; CHECK-NEXT: .long 13
+; CHECK-NEXT: .long 0 # BTF_KIND_ARRAY(id = 13)
+; CHECK-NEXT: .long 50331648 # 0x3000000
+; CHECK-NEXT: .long 0
+; CHECK-NEXT: .long 2
+; CHECK-NEXT: .long 4
+; CHECK-NEXT: .long 0
+; CHECK-NEXT: .long 142 # BTF_KIND_STRUCT(id = 14)
+; CHECK-NEXT: .long 67108869 # 0x4000005
+; CHECK-NEXT: .long 40
+; CHECK-NEXT: .long 194
+; CHECK-NEXT: .long 1
+; CHECK-NEXT: .long 0 # 0x0
+; CHECK-NEXT: .long 199
+; CHECK-NEXT: .long 5
+; CHECK-NEXT: .long 64 # 0x40
+; CHECK-NEXT: .long 203
+; CHECK-NEXT: .long 8
+; CHECK-NEXT: .long 128 # 0x80
+; CHECK-NEXT: .long 209
+; CHECK-NEXT: .long 10
+; CHECK-NEXT: .long 192 # 0xc0
+; CHECK-NEXT: .long 221
+; CHECK-NEXT: .long 12
+; CHECK-NEXT: .long 256 # 0x100
+; CHECK-NEXT: .long 231 # BTF_KIND_STRUCT(id = 15)
+; CHECK-NEXT: .long 67108865 # 0x4000001
+; CHECK-NEXT: .long 40
+; CHECK-NEXT: .long 203
+; CHECK-NEXT: .long 14
+; CHECK-NEXT: .long 0 # 0x0
+; CHECK-NEXT: .long 304 # BTF_KIND_STRUCT(id = 16)
+; CHECK-NEXT: .long 67108865 # 0x4000001
+; CHECK-NEXT: .long 40
+; CHECK-NEXT: .long 69
+; CHECK-NEXT: .long 15
+; CHECK-NEXT: .long 0 # 0x0
+; CHECK-NEXT: .long 353 # BTF_KIND_VAR(id = 17)
+; CHECK-NEXT: .long 234881024 # 0xe000000
+; CHECK-NEXT: .long 16
+; CHECK-NEXT: .long 1
+; CHECK-NEXT: .long 362 # BTF_KIND_PTR(id = 18)
+; CHECK-NEXT: .long 33554432 # 0x2000000
+; CHECK-NEXT: .long 19
+; CHECK-NEXT: .long 398 # BTF_KIND_STRUCT(id = 19)
+; CHECK-NEXT: .long 67108868 # 0x4000004
+; CHECK-NEXT: .long 24
+; CHECK-NEXT: .long 408
+; CHECK-NEXT: .long 20
+; CHECK-NEXT: .long 0 # 0x0
+; CHECK-NEXT: .long 416
+; CHECK-NEXT: .long 21
+; CHECK-NEXT: .long 64 # 0x40
+; CHECK-NEXT: .long 425
+; CHECK-NEXT: .long 22
+; CHECK-NEXT: .long 128 # 0x80
+; CHECK-NEXT: .long 436
+; CHECK-NEXT: .long 22
+; CHECK-NEXT: .long 136 # 0x88
+; CHECK-NEXT: .long 455 # BTF_KIND_PTR(id = 20)
+; CHECK-NEXT: .long 33554432 # 0x2000000
+; CHECK-NEXT: .long 27
+; CHECK-NEXT: .long 477 # BTF_KIND_PTR(id = 21)
+; CHECK-NEXT: .long 33554432 # 0x2000000
+; CHECK-NEXT: .long 28
+; CHECK-NEXT: .long 510 # BTF_KIND_INT(id = 22)
+; CHECK-NEXT: .long 16777216 # 0x1000000
+; CHECK-NEXT: .long 1
+; CHECK-NEXT: .long 67108872 # 0x4000008
+; CHECK-NEXT: .long 0 # BTF_KIND_FUNC_PROTO(id = 23)
+; CHECK-NEXT: .long 218103809 # 0xd000001
+; CHECK-NEXT: .long 0
+; CHECK-NEXT: .long 515
+; CHECK-NEXT: .long 18
+; CHECK-NEXT: .long 521 # BTF_KIND_FUNC(id = 24)
+; CHECK-NEXT: .long 201326592 # 0xc000000
+; CHECK-NEXT: .long 23
+; CHECK-NEXT: .long 606 # BTF_KIND_DATASEC(id = 25)
+; CHECK-NEXT: .long 251658241 # 0xf000001
+; CHECK-NEXT: .long 0
+; CHECK-NEXT: .long 17
+; CHECK-NEXT: .long HASH_MAP
+; CHECK-NEXT: .long 40
+; CHECK-NEXT: .long 612 # BTF_KIND_DATASEC(id = 26)
+; CHECK-NEXT: .long 251658240 # 0xf000000
+; CHECK-NEXT: .long 0
+; CHECK-NEXT: .long 620 # BTF_KIND_FWD(id = 27)
+; CHECK-NEXT: .long 117440512 # 0x7000000
+; CHECK-NEXT: .long 0
+; CHECK-NEXT: .long 630 # BTF_KIND_FWD(id = 28)
+; CHECK-NEXT: .long 117440512 # 0x7000000
+; CHECK-NEXT: .long 0
+; CHECK-NEXT: .byte 0 # string offset=0
+; CHECK-NEXT: .ascii "*const [i32; 1]" # string offset=1
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .ascii "i32" # string offset=17
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .ascii "__ARRAY_SIZE_TYPE__" # string offset=21
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .ascii "*const map_def::MyKey" # string offset=41
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .ascii "MyKey" # string offset=63
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .ascii "__0" # string offset=69
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .ascii "u32" # string offset=73
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .ascii "*const map_def::MyValue" # string offset=77
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .ascii "MyValue" # string offset=101
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .ascii "*const [i32; 10]" # string offset=109
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .ascii "*const [i32; 0]" # string offset=126
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .ascii "HashMapDef<map_def::MyKey, map_def::MyValue, 10, 0>" # string offset=142
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .ascii "type" # string offset=194
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .ascii "key" # string offset=199
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .ascii "value" # string offset=203
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .ascii "max_entries" # string offset=209
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .ascii "map_flags" # string offset=221
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .ascii "UnsafeCell<map_def::HashMapDef<map_def::MyKey, map_def::MyValue, 10, 0>>" # string offset=231
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .ascii "HashMap<map_def::MyKey, map_def::MyValue, 10, 0>" # string offset=304
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .ascii "HASH_MAP" # string offset=353
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .ascii "&core::panic::panic_info::PanicInfo" # string offset=362
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .ascii "PanicInfo" # string offset=398
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .ascii "message" # string offset=408
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .ascii "location" # string offset=416
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .ascii "can_unwind" # string offset=425
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .ascii "force_no_backtrace" # string offset=436
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .ascii "&core::fmt::Arguments" # string offset=455
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .ascii "&core::panic::location::Location" # string offset=477
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .ascii "bool" # string offset=510
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .ascii "_info" # string offset=515
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .ascii "panic" # string offset=521
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .ascii ".text" # string offset=527
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .ascii "/home/vadorovsky/playground/map-def/map-def-ebpf/src/main.rs" # string offset=533
----------------
vadorovsky wrote:
Good point. In the most of `.ll` test files I see that `/tmp` is used as directory. I sanitized it to `/tmp/map-def/src`.
https://github.com/llvm/llvm-project/pull/144097
More information about the llvm-commits
mailing list