1
Fork 0

improve byval abi docs

This commit is contained in:
Erik Desjardins 2024-03-09 11:40:40 -05:00
parent c56ffaa3af
commit 38324a1f4f
2 changed files with 34 additions and 5 deletions

View file

@ -46,17 +46,23 @@ pub enum PassMode {
///
/// The argument has a layout abi of `ScalarPair`.
Pair(ArgAttributes, ArgAttributes),
/// Pass the argument after casting it. See the `CastTarget` docs for details. The bool
/// indicates if a `Reg::i32()` dummy argument is emitted before the real argument.
/// Pass the argument after casting it. See the `CastTarget` docs for details.
///
/// `pad_i32` indicates if a `Reg::i32()` dummy argument is emitted before the real argument.
Cast { pad_i32: bool, cast: Box<CastTarget> },
/// Pass the argument indirectly via a hidden pointer.
///
/// The `meta_attrs` value, if any, is for the metadata (vtable or length) of an unsized
/// argument. (This is the only mode that supports unsized arguments.)
///
/// `on_stack` defines that the value should be passed at a fixed stack offset in accordance to
/// the ABI rather than passed using a pointer. This corresponds to the `byval` LLVM argument
/// attribute (using a byte array type with the same size as the Rust type [which ensures that
/// padding is preserved and that we do not rely on LLVM's struct layout], and with alignment
/// determined in a complex, target-specific manner [see callers of `make_indirect_byval`]).
/// attribute. The `byval` argument will use a byte array with the same size as the Rust type
/// (which ensures that padding is preserved and that we do not rely on LLVM's struct layout),
/// and will use the alignment specified in `attrs.pointee_align` (if `Some`) or the type's
/// alignment, depending on the target's ABI. This means that the alignment will not always
/// match the Rust type's alignment; see documentation of `make_indirect_byval` for more info.
///
/// `on_stack` cannot be true for unsized arguments, i.e., when `meta_attrs` is `Some`.
Indirect { attrs: ArgAttributes, meta_attrs: Option<ArgAttributes>, on_stack: bool },
}
@ -598,6 +604,8 @@ impl<'a, Ty> ArgAbi<'a, Ty> {
}
}
/// Pass this argument indirectly, by passing a (thin or fat) pointer to the argument instead.
/// This is valid for both sized and unsized arguments.
pub fn make_indirect(&mut self) {
match self.mode {
PassMode::Direct(_) | PassMode::Pair(_, _) => {
@ -611,7 +619,26 @@ impl<'a, Ty> ArgAbi<'a, Ty> {
}
}
/// Pass this argument indirectly, by placing it at a fixed stack offset.
/// This corresponds to the `byval` LLVM argument attribute.
/// This is only valid for sized arguments.
///
/// `byval_align` specifies the alignment of the `byval` stack slot, which does not need to
/// correspond to the type's alignment. This will be `Some` if the target's ABI specifies that
/// stack slots used for arguments passed by-value have specific alignment requirements which
/// differ from the alignment used in other situations.
///
/// If `None`, the type's alignment is used.
///
/// If the resulting alignment differs from the type's alignment,
/// the argument will be copied to an alloca with sufficient alignment,
/// either in the caller (if the type's alignment is lower than the byval alignment)
/// or in the callee† (if the type's alignment is higher than the byval alignment),
/// to ensure that Rust code never sees an underaligned pointer.
///
/// † This is currently broken, see <https://github.com/rust-lang/rust/pull/122212>.
pub fn make_indirect_byval(&mut self, byval_align: Option<Align>) {
assert!(!self.layout.is_unsized(), "used byval ABI for unsized layout");
self.make_indirect();
match self.mode {
PassMode::Indirect { ref mut attrs, meta_attrs: _, ref mut on_stack } => {

View file

@ -217,6 +217,8 @@ where
match cls_or_mem {
Err(Memory) => {
if is_arg {
// The x86_64 ABI doesn't have any special requirements for `byval` alignment,
// the type's alignment is always used.
arg.make_indirect_byval(None);
} else {
// `sret` parameter thus one less integer register available