diff options
| author | Erik Desjardins <erikdesjardins@users.noreply.github.com> | 2024-03-09 11:40:40 -0500 |
|---|---|---|
| committer | Erik Desjardins <erikdesjardins@users.noreply.github.com> | 2024-03-09 12:08:48 -0500 |
| commit | 38324a1f4fd131112ece8b9e1c995ad364b0ca17 (patch) | |
| tree | 31e71e3aec1bcae369976475a9d1ee8e27cbd0f3 | |
| parent | c56ffaa3af2647838c25c6e1afbfef9309710929 (diff) | |
| download | rust-38324a1f4fd131112ece8b9e1c995ad364b0ca17.tar.gz rust-38324a1f4fd131112ece8b9e1c995ad364b0ca17.zip | |
improve byval abi docs
| -rw-r--r-- | compiler/rustc_target/src/abi/call/mod.rs | 37 | ||||
| -rw-r--r-- | compiler/rustc_target/src/abi/call/x86_64.rs | 2 |
2 files changed, 34 insertions, 5 deletions
diff --git a/compiler/rustc_target/src/abi/call/mod.rs b/compiler/rustc_target/src/abi/call/mod.rs index 6e24dc4bc0b..d326cff85c5 100644 --- a/compiler/rustc_target/src/abi/call/mod.rs +++ b/compiler/rustc_target/src/abi/call/mod.rs @@ -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 } => { diff --git a/compiler/rustc_target/src/abi/call/x86_64.rs b/compiler/rustc_target/src/abi/call/x86_64.rs index 2eb50cc8dea..f3208fe5d03 100644 --- a/compiler/rustc_target/src/abi/call/x86_64.rs +++ b/compiler/rustc_target/src/abi/call/x86_64.rs @@ -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 |
