Skip to content

Commit 249be7d

Browse files
committed
add SSE2 ABI for x86, and use it for float and SIMD passing
1 parent 5149572 commit 249be7d

25 files changed

+147
-23
lines changed

compiler/rustc_target/src/callconv/mod.rs

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use crate::abi::{
99
self, AddressSpace, Align, BackendRepr, HasDataLayout, Pointer, Size, TyAbiInterface,
1010
TyAndLayout,
1111
};
12-
use crate::spec::{HasTargetSpec, HasWasmCAbiOpt, HasX86AbiOpt, WasmCAbi};
12+
use crate::spec::{HasTargetSpec, HasWasmCAbiOpt, HasX86AbiOpt, RustcAbi, WasmCAbi};
1313

1414
mod aarch64;
1515
mod amdgpu;
@@ -748,6 +748,22 @@ impl<'a, Ty> FnAbi<'a, Ty> {
748748
_ => {}
749749
};
750750

751+
// Decides whether we can pass the given SIMD argument via `PassMode::Direct`.
752+
// May only return `true` if the target will always pass those arguments the same way,
753+
// no matter what the user does with `-Ctarget-feature`! In other words, whatever
754+
// target features are required to pass a SIMD value in registers must be listed in
755+
// the `abi_required_features` for the current target and ABI.
756+
let can_pass_simd_directly = |arg: &ArgAbi<'_, Ty>| match &*spec.arch {
757+
// On x86, if we have SSE2 (which we have by default for x86_64), we can always pass up
758+
// to 128-bit-sized vectors.
759+
"x86" if spec.rustc_abi == Some(RustcAbi::X86Sse2) => arg.layout.size.bits() <= 128,
760+
"x86_64" if spec.rustc_abi != Some(RustcAbi::X86Softfloat) => {
761+
arg.layout.size.bits() <= 128
762+
}
763+
// So far, we haven't implemented this logic for any other target.
764+
_ => false,
765+
};
766+
751767
for (arg_idx, arg) in self
752768
.args
753769
.iter_mut()
@@ -847,7 +863,10 @@ impl<'a, Ty> FnAbi<'a, Ty> {
847863
//
848864
// Note that the intrinsic ABI is exempt here as those are not
849865
// real functions anyway, and the backend expects very specific types.
850-
if abi != ExternAbi::RustIntrinsic && spec.simd_types_indirect {
866+
if abi != ExternAbi::RustIntrinsic
867+
&& spec.simd_types_indirect
868+
&& !can_pass_simd_directly(arg)
869+
{
851870
arg.make_indirect();
852871
}
853872
}

compiler/rustc_target/src/callconv/x86.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ use crate::abi::call::{ArgAttribute, FnAbi, PassMode, Reg, RegKind};
22
use crate::abi::{
33
AddressSpace, Align, BackendRepr, Float, HasDataLayout, Pointer, TyAbiInterface, TyAndLayout,
44
};
5-
use crate::spec::HasTargetSpec;
65
use crate::spec::abi::Abi as SpecAbi;
6+
use crate::spec::{HasTargetSpec, RustcAbi};
77

88
#[derive(PartialEq)]
99
pub(crate) enum Flavor {
@@ -234,7 +234,13 @@ where
234234
_ => false, // anyway not passed via registers on x86
235235
};
236236
if has_float {
237-
if fn_abi.ret.layout.size <= Pointer(AddressSpace::DATA).size(cx) {
237+
if cx.target_spec().rustc_abi == Some(RustcAbi::X86Sse2)
238+
&& fn_abi.ret.layout.backend_repr.is_scalar()
239+
&& fn_abi.ret.layout.size.bits() <= 128
240+
{
241+
// This is a single scalar that fits into an SSE register.
242+
fn_abi.ret.cast_to(Reg { kind: RegKind::Vector, size: fn_abi.ret.layout.size });
243+
} else if fn_abi.ret.layout.size <= Pointer(AddressSpace::DATA).size(cx) {
238244
// Same size or smaller than pointer, return in an integer register.
239245
fn_abi.ret.cast_to(Reg { kind: RegKind::Integer, size: fn_abi.ret.layout.size });
240246
} else {

compiler/rustc_target/src/spec/base/apple/mod.rs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ use std::borrow::Cow;
22
use std::env;
33

44
use crate::spec::{
5-
Cc, DebuginfoKind, FloatAbi, FramePointer, LinkerFlavor, Lld, SplitDebuginfo, StackProbeType,
6-
StaticCow, TargetOptions, cvs,
5+
Cc, DebuginfoKind, FloatAbi, FramePointer, LinkerFlavor, Lld, RustcAbi, SplitDebuginfo,
6+
StackProbeType, StaticCow, TargetOptions, cvs,
77
};
88

99
#[cfg(test)]
@@ -103,7 +103,7 @@ pub(crate) fn base(
103103
arch: Arch,
104104
abi: TargetAbi,
105105
) -> (TargetOptions, StaticCow<str>, StaticCow<str>) {
106-
let opts = TargetOptions {
106+
let mut opts = TargetOptions {
107107
abi: abi.target_abi().into(),
108108
llvm_floatabi: Some(FloatAbi::Hard),
109109
os: os.into(),
@@ -154,6 +154,10 @@ pub(crate) fn base(
154154

155155
..Default::default()
156156
};
157+
if matches!(arch, Arch::I386 | Arch::I686) {
158+
// All Apple x86-32 targets have SSE2.
159+
opts.rustc_abi = Some(RustcAbi::X86Sse2);
160+
}
157161
(opts, unversioned_llvm_target(os, arch, abi), arch.target_arch())
158162
}
159163

compiler/rustc_target/src/spec/mod.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1117,6 +1117,8 @@ impl ToJson for FloatAbi {
11171117
/// The Rustc-specific variant of the ABI used for this target.
11181118
#[derive(Clone, Copy, PartialEq, Hash, Debug)]
11191119
pub enum RustcAbi {
1120+
/// On x86-32 only: make use of SSE and SSE2 for ABI purposes.
1121+
X86Sse2,
11201122
/// On x86-32/64 only: do not use any FPU or SIMD registers for the ABI/
11211123
X86Softfloat,
11221124
}
@@ -1126,6 +1128,7 @@ impl FromStr for RustcAbi {
11261128

11271129
fn from_str(s: &str) -> Result<RustcAbi, ()> {
11281130
Ok(match s {
1131+
"x86-sse2" => RustcAbi::X86Sse2,
11291132
"x86-softfloat" => RustcAbi::X86Softfloat,
11301133
_ => return Err(()),
11311134
})
@@ -1135,6 +1138,7 @@ impl FromStr for RustcAbi {
11351138
impl ToJson for RustcAbi {
11361139
fn to_json(&self) -> Json {
11371140
match *self {
1141+
RustcAbi::X86Sse2 => "x86-sse2",
11381142
RustcAbi::X86Softfloat => "x86-softfloat",
11391143
}
11401144
.to_json()
@@ -3269,6 +3273,11 @@ impl Target {
32693273
// Check consistency of Rust ABI declaration.
32703274
if let Some(rust_abi) = self.rustc_abi {
32713275
match rust_abi {
3276+
RustcAbi::X86Sse2 => check_matches!(
3277+
&*self.arch,
3278+
"x86",
3279+
"`x86-sse2` ABI is only valid for x86-32 targets"
3280+
),
32723281
RustcAbi::X86Softfloat => check_matches!(
32733282
&*self.arch,
32743283
"x86" | "x86_64",

compiler/rustc_target/src/spec/targets/i586_pc_nto_qnx700.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use crate::spec::base::nto_qnx;
2-
use crate::spec::{StackProbeType, Target, TargetOptions, base};
2+
use crate::spec::{RustcAbi, StackProbeType, Target, TargetOptions, base};
33

44
pub(crate) fn target() -> Target {
55
let mut meta = nto_qnx::meta();
@@ -14,6 +14,7 @@ pub(crate) fn target() -> Target {
1414
.into(),
1515
arch: "x86".into(),
1616
options: TargetOptions {
17+
rustc_abi: Some(RustcAbi::X86Sse2),
1718
cpu: "pentium4".into(),
1819
max_atomic_width: Some(64),
1920
pre_link_args: nto_qnx::pre_link_args(

compiler/rustc_target/src/spec/targets/i686_linux_android.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::spec::{SanitizerSet, StackProbeType, Target, TargetOptions, base};
1+
use crate::spec::{RustcAbi, SanitizerSet, StackProbeType, Target, TargetOptions, base};
22

33
// See https://developer.android.com/ndk/guides/abis.html#x86
44
// for target ABI requirements.
@@ -8,6 +8,7 @@ pub(crate) fn target() -> Target {
88

99
base.max_atomic_width = Some(64);
1010

11+
base.rustc_abi = Some(RustcAbi::X86Sse2);
1112
// https://developer.android.com/ndk/guides/abis.html#x86
1213
base.cpu = "pentiumpro".into();
1314
base.features = "+mmx,+sse,+sse2,+sse3,+ssse3".into();

compiler/rustc_target/src/spec/targets/i686_pc_windows_gnu.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1-
use crate::spec::{Cc, FramePointer, LinkerFlavor, Lld, Target, base};
1+
use crate::spec::{Cc, FramePointer, LinkerFlavor, Lld, RustcAbi, Target, base};
22

33
pub(crate) fn target() -> Target {
44
let mut base = base::windows_gnu::opts();
5+
base.rustc_abi = Some(RustcAbi::X86Sse2);
56
base.cpu = "pentium4".into();
67
base.max_atomic_width = Some(64);
78
base.frame_pointer = FramePointer::Always; // Required for backtraces

compiler/rustc_target/src/spec/targets/i686_pc_windows_gnullvm.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1-
use crate::spec::{Cc, FramePointer, LinkerFlavor, Lld, Target, base};
1+
use crate::spec::{Cc, FramePointer, LinkerFlavor, Lld, RustcAbi, Target, base};
22

33
pub(crate) fn target() -> Target {
44
let mut base = base::windows_gnullvm::opts();
5+
base.rustc_abi = Some(RustcAbi::X86Sse2);
56
base.cpu = "pentium4".into();
67
base.max_atomic_width = Some(64);
78
base.frame_pointer = FramePointer::Always; // Required for backtraces

compiler/rustc_target/src/spec/targets/i686_pc_windows_msvc.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1-
use crate::spec::{LinkerFlavor, Lld, SanitizerSet, Target, base};
1+
use crate::spec::{LinkerFlavor, Lld, RustcAbi, SanitizerSet, Target, base};
22

33
pub(crate) fn target() -> Target {
44
let mut base = base::windows_msvc::opts();
5+
base.rustc_abi = Some(RustcAbi::X86Sse2);
56
base.cpu = "pentium4".into();
67
base.max_atomic_width = Some(64);
78
base.supported_sanitizers = SanitizerSet::ADDRESS;

compiler/rustc_target/src/spec/targets/i686_unknown_freebsd.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1-
use crate::spec::{Cc, LinkerFlavor, Lld, StackProbeType, Target, base};
1+
use crate::spec::{Cc, LinkerFlavor, Lld, RustcAbi, StackProbeType, Target, base};
22

33
pub(crate) fn target() -> Target {
44
let mut base = base::freebsd::opts();
5+
base.rustc_abi = Some(RustcAbi::X86Sse2);
56
base.cpu = "pentium4".into();
67
base.max_atomic_width = Some(64);
78
base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m32", "-Wl,-znotext"]);

0 commit comments

Comments
 (0)