[llvm] [BPF] Support for `DW_TAG_variant_part` in BTF generation (PR #155783)

Tamir Duberstein via llvm-commits llvm-commits at lists.llvm.org
Fri Oct 17 11:58:02 PDT 2025


================
@@ -0,0 +1,87 @@
+; RUN: llc -mtriple=bpfel -filetype=obj -o %t1 %s
+; RUN: llvm-objcopy --dump-section='.BTF'=%t2 %t1
+; RUN: %python %p/print_btf.py %t2 | FileCheck -check-prefixes=CHECK-BTF %s
+; RUN: llc -mtriple=bpfeb -filetype=obj -o %t1 %s
+; RUN: llvm-objcopy --dump-section='.BTF'=%t2 %t1
+; RUN: %python %p/print_btf.py %t2 | FileCheck -check-prefixes=CHECK-BTF %s
+;
+; Source:
+;   #![no_std]
+;   #![no_main]
+;
+;   pub enum MyEnum {
+;       First { a: u32, b: i32 },
+;       Second(u32),
+;   }
+;
+;   #[unsafe(no_mangle)]
+;   pub static X: MyEnum = MyEnum::First { a: 54, b: -23 };
+;
+;   #[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-bc
+;   llvm-extract --glob=X $(find target/ -name "*.bc" | head -n 1) -o variant-part.bc
+;   llvm-dis variant-part.bc -o variant-part.ll
+
+; ModuleID = 'variant-part.bc'
+source_filename = "c0znihgkvro8hs0n88fgrtg6x"
+target datalayout = "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128"
+target triple = "bpfel"
+
+ at X = constant [12 x i8] c"\00\00\00\006\00\00\00\E9\FF\FF\FF", align 4, !dbg !0
+
+!llvm.module.flags = !{!22, !23, !24, !25}
+!llvm.ident = !{!26}
+!llvm.dbg.cu = !{!27}
+
+; CHECK-BTF:      [1] STRUCT 'MyEnum' size=12 vlen=1
+; CHECK-BTF-NEXT:         '(anon)' type_id=3 bits_offset=0
----------------
tamird wrote:

This anon is the variant union **member** - Rust `enum`s are represented as
```c
struct MyEnum {
  union { // <--- both the member and the type are anonymous
    u32, // <-- anonymous discriminator
    Variant1,
    ...
    VariantN,
  }
}
```

In Rust you never access the discriminator nor the union directly. Instead you do something like:

```rust
fn use_myEnum(value: myEnum) {
  match value {
    MyEnum::First { a, b } => println!("first! a={a}, b={b}"),
    MyEnum::Second(value) => println!("second! value={value}")
  }
}
```

the compiler checks that your `match` is exhaustive - meaning it covers all variants of `MyEnum`; otherwise compilation fails.

> Also without 'name' for discriminator field, not sure how it will be used by BTF/kernel etc.

It's probably not usable without a name, but I think we shouldn't invent a name for it here. The discriminator's `(anon)` comes from `Discriminator.NameOff = BDebug.addString(DDTy->getName());` on line 318 (I think) -- so the "solution" would be to change rustc to give it a name, which will automatically show up here.

Having said that, I think the name would be mostly useful for relocations, and we're a long way off from being able to apply BTF relocations to BPF generated from Rust.

The point of this PR is to translate the Rust DI to BTF as faithfully as possible, and that's how we get these anons.

https://github.com/llvm/llvm-project/pull/155783


More information about the llvm-commits mailing list