[llvm] [BPF] Support wrapping BPF map structs into nested, single field structs (PR #144097)
Tamir Duberstein via llvm-commits
llvm-commits at lists.llvm.org
Fri Jun 13 09:28:45 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
----------------
tamird wrote:
various strings with paths from your machine have snuck in here. i'm not sure what the convention is for these tests, but in case it is to sanitize these, please do so.
https://github.com/llvm/llvm-project/pull/144097
More information about the llvm-commits
mailing list