Merge branch 'simd-always-mem' of https://github.com/alexcrichton/rust into rollup
This commit is contained in:
commit
a9101095e8
@ -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
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
181
src/test/run-pass/simd-target-feature-mixup.rs
Normal file
181
src/test/run-pass/simd-target-feature-mixup.rs
Normal file
@ -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) {}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user