Right. I'm not saying that accesses to structures nested by value are uncommon. What I'm saying is that we could roll out experimental nightly-only support for BTF relocations, behind a feature gate, without waiting for const Sized / sized hierarchy to be fully implemented.
That said, I agree that sized hierarchy and support for accesses nested by value would definitely be needed to expose the feature without a gate and on stable Rust.
The more I think about it, the more I'm leaning towards neutral naming not tied to BTF, which could also suit Swift ABI or any other kind of field access relocation. My current implementation touches the field projection logic (compiler/rustc_codegen_ssa/src/mir/place.rs) in MIR in the following way:
Choosing a target-specific name (bpf_*/btf_*) would mean poisoning this logic with target-specific concepts. It would also require add an another boolean if an another relocation mechanism (e.g. Swift ABI) is added.
Keeping the name neutral keeps MIR target-agnostic and adds only one boolean. Therefore, I would rather call it "relocatable".
Great suggestion. We could add the following Rust intrinsics, which would lower to the following LLVM intrinsics.
With neutral naming, this could eventually be implemented for other relocation mechanisms (e.g. Swift ABI):
Does it have to be a feature of structs and arrays?
Could it instead be expressed as a macro or intrinsic function that gives an offset to use with ptr::read? (which could be sufficient to make getters and setters for something struct-like that isn't an actual struct)
Or maybe it could be implemented as getters and setters on extern opaque types?
It wouldn't be as neat as 1st class structs that work with literals and pattern matching, but might be sufficient to interact with kernel structs treating them as an API.
I think the current implementation in LLVM makes it quite hard to implement with anything else than real structs:
Using @llvm.preserve.*.access.index intrinsics instead of getelementptr in LLVM has two effects:
It ensures the offset stays literally in the code and is not transformed by optimization passes,
and it allows debuginfo metadata with type information to be attached to the access.
The BPF codegen backend then writes the used type names and field names into a symbol table and generates BTF relocations that connect each such offset in the code with the symbolic names of the accessed type and field and type layout information.
With a macro or intrinsic function, the compiler would still need to generate type debug metadata, so that the BPF codegen backend can find the names and check the types for compatibility. It's probably way easier to reuse the infrastructure that already generates debuginfo metadata for Rust types than to reimplement part of it just for BPF.
re: "relocatable". I would definitely not call it "bpf_relocatable" (target specific), but between "relocatable" and "btf_relocatable", BTF is the means through which relocation information is captured (BTF types/fields) and expressed (.BTF.ext section), so btf_ prefix seems appropriate. For this Swift use case you were talking about, would relocation information be expressed differently somehow?
In the end it doesn't matter all that much, but too-generic "relocatable" has a potential to be, well, too generic and thus confusing. But just my 2 cents.
re: instrinsics, make sense and seems like a good idea. will the "does it exist" primitive be expressed as an extra argument to "preserve_xxx_info" or it would require its own set of intrinsics?