diff options
Diffstat (limited to 'compiler/rustc_target/src/abi/call/x86.rs')
| -rw-r--r-- | compiler/rustc_target/src/abi/call/x86.rs | 82 |
1 files changed, 51 insertions, 31 deletions
diff --git a/compiler/rustc_target/src/abi/call/x86.rs b/compiler/rustc_target/src/abi/call/x86.rs index 58c0717b7d1..d2c604fafa6 100644 --- a/compiler/rustc_target/src/abi/call/x86.rs +++ b/compiler/rustc_target/src/abi/call/x86.rs @@ -1,5 +1,5 @@ use crate::abi::call::{ArgAttribute, FnAbi, PassMode, Reg, RegKind}; -use crate::abi::{Align, HasDataLayout, TyAbiInterface}; +use crate::abi::{Abi, Align, HasDataLayout, TyAbiInterface, TyAndLayout}; use crate::spec::HasTargetSpec; #[derive(PartialEq)] @@ -53,38 +53,58 @@ where if arg.is_ignore() { continue; } - if !arg.layout.is_aggregate() { - arg.extend_integer_width_to(32); - continue; - } - // We need to compute the alignment of the `byval` argument. The rules can be found in - // `X86_32ABIInfo::getTypeStackAlignInBytes` in Clang's `TargetInfo.cpp`. Summarized here, - // they are: - // - // 1. If the natural alignment of the type is less than or equal to 4, the alignment is 4. - // - // 2. Otherwise, on Linux, the alignment of any vector type is the natural alignment. - // (This doesn't matter here because we ensure we have an aggregate with the check above.) - // - // 3. Otherwise, on Apple platforms, the alignment of anything that contains a vector type - // is 16. - // - // 4. If none of these conditions are true, the alignment is 4. - let t = cx.target_spec(); - let align_4 = Align::from_bytes(4).unwrap(); - let align_16 = Align::from_bytes(16).unwrap(); - let byval_align = if arg.layout.align.abi < align_4 { - align_4 - } else if t.is_like_osx && arg.layout.align.abi >= align_16 { - // FIXME(pcwalton): This is dubious--we should actually be looking inside the type to - // determine if it contains SIMD vector values--but I think it's fine? - align_16 - } else { - align_4 - }; + if arg.layout.is_aggregate() { + // We need to compute the alignment of the `byval` argument. The rules can be found in + // `X86_32ABIInfo::getTypeStackAlignInBytes` in Clang's `TargetInfo.cpp`. Summarized + // here, they are: + // + // 1. If the natural alignment of the type is <= 4, the alignment is 4. + // + // 2. Otherwise, on Linux, the alignment of any vector type is the natural alignment. + // This doesn't matter here because we only pass aggregates via `byval`, not vectors. + // + // 3. Otherwise, on Apple platforms, the alignment of anything that contains a vector + // type is 16. + // + // 4. If none of these conditions are true, the alignment is 4. + + fn contains_vector<'a, Ty, C>(cx: &C, layout: TyAndLayout<'a, Ty>) -> bool + where + Ty: TyAbiInterface<'a, C> + Copy, + { + match layout.abi { + Abi::Uninhabited | Abi::Scalar(_) | Abi::ScalarPair(..) => false, + Abi::Vector { .. } => true, + Abi::Aggregate { .. } => { + for i in 0..layout.fields.count() { + if contains_vector(cx, layout.field(cx, i)) { + return true; + } + } + false + } + } + } - arg.make_indirect_byval(Some(byval_align)); + let t = cx.target_spec(); + let align_4 = Align::from_bytes(4).unwrap(); + let align_16 = Align::from_bytes(16).unwrap(); + let byval_align = if arg.layout.align.abi < align_4 { + // (1.) + align_4 + } else if t.is_like_osx && contains_vector(cx, arg.layout) { + // (3.) + align_16 + } else { + // (4.) + align_4 + }; + + arg.make_indirect_byval(Some(byval_align)); + } else { + arg.extend_integer_width_to(32); + } } if flavor == Flavor::FastcallOrVectorcall { |
