about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorAlex Crichton <alex@alexcrichton.com>2018-01-26 06:51:43 -0800
committerAlex Crichton <alex@alexcrichton.com>2018-01-26 06:51:43 -0800
commita9101095e8dfe3558f822f7f16e8fb5fe8d8a63e (patch)
tree6cabe961ed619938991e4c98882902b813dde40d /src
parenta7f41567c52bf4ce851963809ca3c08cfeffab79 (diff)
parent502de01ff40d37d3e6b419c3931a23284ce1a4e4 (diff)
downloadrust-a9101095e8dfe3558f822f7f16e8fb5fe8d8a63e.tar.gz
rust-a9101095e8dfe3558f822f7f16e8fb5fe8d8a63e.zip
Merge branch 'simd-always-mem' of https://github.com/alexcrichton/rust into rollup
Diffstat (limited to 'src')
-rw-r--r--src/librustc_trans/abi.rs25
-rw-r--r--src/test/codegen/x86_mmx.rs4
-rw-r--r--src/test/run-pass/simd-target-feature-mixup.rs181
3 files changed, 207 insertions, 3 deletions
diff --git a/src/librustc_trans/abi.rs b/src/librustc_trans/abi.rs
index 5079ce77523..9cabd9356e9 100644
--- a/src/librustc_trans/abi.rs
+++ b/src/librustc_trans/abi.rs
@@ -871,6 +871,31 @@ impl<'a, 'tcx> FnType<'tcx> {
 
                 match arg.layout.abi {
                     layout::Abi::Aggregate { .. } => {}
+
+                    // This is a fun case! The gist of what this is doing is
+                    // that we want callers and callees to always agree on the
+                    // ABI of how they pass SIMD arguments. If we were to *not*
+                    // make these arguments indirect then they'd be immediates
+                    // in LLVM, which means that they'd used whatever the
+                    // appropriate ABI is for the callee and the caller. That
+                    // means, for example, if the caller doesn't have AVX
+                    // enabled but the callee does, then passing an AVX argument
+                    // across this boundary would cause corrupt data to show up.
+                    //
+                    // This problem is fixed by unconditionally passing SIMD
+                    // arguments through memory between callers and callees
+                    // which should get them all to agree on ABI regardless of
+                    // target feature sets. Some more information about this
+                    // issue can be found in #44367.
+                    //
+                    // Note that the platform intrinsic ABI is exempt here as
+                    // that's how we connect up to LLVM and it's unstable
+                    // anyway, we control all calls to it in libstd.
+                    layout::Abi::Vector { .. } if abi != Abi::PlatformIntrinsic => {
+                        arg.make_indirect();
+                        return
+                    }
+
                     _ => return
                 }
 
diff --git a/src/test/codegen/x86_mmx.rs b/src/test/codegen/x86_mmx.rs
index bedda63bbff..dc9f63c35db 100644
--- a/src/test/codegen/x86_mmx.rs
+++ b/src/test/codegen/x86_mmx.rs
@@ -22,9 +22,7 @@ pub struct i8x8(u64);
 
 #[no_mangle]
 pub fn a(a: &mut i8x8, b: i8x8) -> i8x8 {
-    // CHECK-LABEL: define x86_mmx @a(x86_mmx*{{.*}}, x86_mmx{{.*}})
-    // CHECK: store x86_mmx %b, x86_mmx* %a
-    // CHECK: ret x86_mmx %b
+    // CHECK-LABEL: define void @a(x86_mmx*{{.*}}, x86_mmx*{{.*}}, x86_mmx*{{.*}})
     *a = b;
     return b
 }
diff --git a/src/test/run-pass/simd-target-feature-mixup.rs b/src/test/run-pass/simd-target-feature-mixup.rs
new file mode 100644
index 00000000000..b60aec2b5c9
--- /dev/null
+++ b/src/test/run-pass/simd-target-feature-mixup.rs
@@ -0,0 +1,181 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(repr_simd, target_feature, cfg_target_feature)]
+
+use std::process::{Command, ExitStatus};
+use std::env;
+
+fn main() {
+    if let Some(level) = env::args().nth(1) {
+        return test::main(&level)
+    }
+
+    let me = env::current_exe().unwrap();
+    for level in ["sse", "avx", "avx512"].iter() {
+        let status = Command::new(&me).arg(level).status().unwrap();
+        if status.success() {
+            println!("success with {}", level);
+            continue
+        }
+
+        // We don't actually know if our computer has the requisite target features
+        // for the test below. Testing for that will get added to libstd later so
+        // for now just asume sigill means this is a machine that can't run this test.
+        if is_sigill(status) {
+            println!("sigill with {}, assuming spurious", level);
+            continue
+        }
+        panic!("invalid status at {}: {}", level, status);
+    }
+}
+
+#[cfg(unix)]
+fn is_sigill(status: ExitStatus) -> bool {
+    use std::os::unix::prelude::*;
+    status.signal() == Some(4)
+}
+
+#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+#[allow(bad_style)]
+mod test {
+    // An SSE type
+    #[repr(simd)]
+    #[derive(PartialEq, Debug, Clone, Copy)]
+    struct __m128i(u64, u64);
+
+    // An AVX type
+    #[repr(simd)]
+    #[derive(PartialEq, Debug, Clone, Copy)]
+    struct __m256i(u64, u64, u64, u64);
+
+    // An AVX-512 type
+    #[repr(simd)]
+    #[derive(PartialEq, Debug, Clone, Copy)]
+    struct __m512i(u64, u64, u64, u64, u64, u64, u64, u64);
+
+    pub fn main(level: &str) {
+        unsafe {
+            main_normal(level);
+            main_sse(level);
+            if level == "sse" {
+                return
+            }
+            main_avx(level);
+            if level == "avx" {
+                return
+            }
+            main_avx512(level);
+        }
+    }
+
+    macro_rules! mains {
+        ($(
+            $(#[$attr:meta])*
+            unsafe fn $main:ident(level: &str) {
+                ...
+            }
+        )*) => ($(
+            $(#[$attr])*
+            unsafe fn $main(level: &str) {
+                let m128 = __m128i(1, 2);
+                let m256 = __m256i(3, 4, 5, 6);
+                let m512 = __m512i(7, 8, 9, 10, 11, 12, 13, 14);
+                assert_eq!(id_sse_128(m128), m128);
+                assert_eq!(id_sse_256(m256), m256);
+                assert_eq!(id_sse_512(m512), m512);
+
+                if level == "sse" {
+                    return
+                }
+                assert_eq!(id_avx_128(m128), m128);
+                assert_eq!(id_avx_256(m256), m256);
+                assert_eq!(id_avx_512(m512), m512);
+
+                if level == "avx" {
+                    return
+                }
+                assert_eq!(id_avx512_128(m128), m128);
+                assert_eq!(id_avx512_256(m256), m256);
+                assert_eq!(id_avx512_512(m512), m512);
+            }
+        )*)
+    }
+
+    mains! {
+        unsafe fn main_normal(level: &str) { ... }
+        #[target_feature(enable = "sse2")]
+        unsafe fn main_sse(level: &str) { ... }
+        #[target_feature(enable = "avx")]
+        unsafe fn main_avx(level: &str) { ... }
+        #[target_feature(enable = "avx512bw")]
+        unsafe fn main_avx512(level: &str) { ... }
+    }
+
+
+    #[target_feature(enable = "sse2")]
+    unsafe fn id_sse_128(a: __m128i) -> __m128i {
+        assert_eq!(a, __m128i(1, 2));
+        a.clone()
+    }
+
+    #[target_feature(enable = "sse2")]
+    unsafe fn id_sse_256(a: __m256i) -> __m256i {
+        assert_eq!(a, __m256i(3, 4, 5, 6));
+        a.clone()
+    }
+
+    #[target_feature(enable = "sse2")]
+    unsafe fn id_sse_512(a: __m512i) -> __m512i {
+        assert_eq!(a, __m512i(7, 8, 9, 10, 11, 12, 13, 14));
+        a.clone()
+    }
+
+    #[target_feature(enable = "avx")]
+    unsafe fn id_avx_128(a: __m128i) -> __m128i {
+        assert_eq!(a, __m128i(1, 2));
+        a.clone()
+    }
+
+    #[target_feature(enable = "avx")]
+    unsafe fn id_avx_256(a: __m256i) -> __m256i {
+        assert_eq!(a, __m256i(3, 4, 5, 6));
+        a.clone()
+    }
+
+    #[target_feature(enable = "avx")]
+    unsafe fn id_avx_512(a: __m512i) -> __m512i {
+        assert_eq!(a, __m512i(7, 8, 9, 10, 11, 12, 13, 14));
+        a.clone()
+    }
+
+    #[target_feature(enable = "avx512bw")]
+    unsafe fn id_avx512_128(a: __m128i) -> __m128i {
+        assert_eq!(a, __m128i(1, 2));
+        a.clone()
+    }
+
+    #[target_feature(enable = "avx512bw")]
+    unsafe fn id_avx512_256(a: __m256i) -> __m256i {
+        assert_eq!(a, __m256i(3, 4, 5, 6));
+        a.clone()
+    }
+
+    #[target_feature(enable = "avx512bw")]
+    unsafe fn id_avx512_512(a: __m512i) -> __m512i {
+        assert_eq!(a, __m512i(7, 8, 9, 10, 11, 12, 13, 14));
+        a.clone()
+    }
+}
+
+#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
+mod test {
+    pub fn main(level: &str) {}
+}