diff options
| author | Erik Desjardins <erikdesjardins@users.noreply.github.com> | 2024-03-17 00:22:35 -0400 |
|---|---|---|
| committer | Erik Desjardins <erikdesjardins@users.noreply.github.com> | 2024-03-17 00:39:21 -0400 |
| commit | 8841315d3e9aa02cb54d757cb5cd8131c263a893 (patch) | |
| tree | f6bcf48ffe30c5fb2be4b5f9355e6c5f2003f89b /compiler/rustc_codegen_ssa/src/mir | |
| parent | 74ef47e90ca1466ea7f3dd8c3ec3738f05345809 (diff) | |
| download | rust-8841315d3e9aa02cb54d757cb5cd8131c263a893.tar.gz rust-8841315d3e9aa02cb54d757cb5cd8131c263a893.zip | |
make PassMode::Cast consistently copy between Rust/ABI representation
Previously, we did this slightly incorrectly for return values, and didn't do it at all for arguments.
Diffstat (limited to 'compiler/rustc_codegen_ssa/src/mir')
| -rw-r--r-- | compiler/rustc_codegen_ssa/src/mir/block.rs | 32 |
1 files changed, 29 insertions, 3 deletions
diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index 9bb2a528265..333c03ce823 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -1471,9 +1471,35 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { if by_ref && !arg.is_indirect() { // Have to load the argument, maybe while casting it. - if let PassMode::Cast { cast: ty, .. } = &arg.mode { - let llty = bx.cast_backend_type(ty); - llval = bx.load(llty, llval, align.min(arg.layout.align.abi)); + if let PassMode::Cast { cast, pad_i32: _ } = &arg.mode { + // The ABI mandates that the value is passed as a different struct representation. + // Spill and reload it from the stack to convert from the Rust representation to + // the ABI representation. + let scratch_size = cast.size(bx); + let scratch_align = cast.align(bx); + // Note that the ABI type may be either larger or smaller than the Rust type, + // due to the presence or absence of trailing padding. For example: + // - On some ABIs, the Rust layout { f64, f32, <f32 padding> } may omit padding + // when passed by value, making it smaller. + // - On some ABIs, the Rust layout { u16, u16, u16 } may be padded up to 8 bytes + // when passed by value, making it larger. + let copy_bytes = cmp::min(scratch_size.bytes(), arg.layout.size.bytes()); + // Allocate some scratch space... + let llscratch = bx.alloca(bx.cast_backend_type(cast), scratch_align); + bx.lifetime_start(llscratch, scratch_size); + // ...memcpy the value... + bx.memcpy( + llscratch, + scratch_align, + llval, + align, + bx.const_usize(copy_bytes), + MemFlags::empty(), + ); + // ...and then load it with the ABI type. + let cast_ty = bx.cast_backend_type(cast); + llval = bx.load(cast_ty, llscratch, scratch_align); + bx.lifetime_end(llscratch, scratch_size); } else { // We can't use `PlaceRef::load` here because the argument // may have a type we don't treat as immediate, but the ABI |
