提交 fe53a810 编写于 作者: A Alex Crichton

rustc: Add support for some more x86 SIMD ops

This commit adds compiler support for two basic operations needed for binding
SIMD on x86 platforms:

* First, a `nontemporal_store` intrinsic was added for the `_mm_stream_ps`, seen
  in rust-lang-nursery/stdsimd#114. This was relatively straightforward and is
  quite similar to the volatile store intrinsic.

* Next, and much more intrusively, a new type to the backend was added. The
  `x86_mmx` type is used in LLVM for a 64-bit vector register and is used in
  various intrinsics like `_mm_abs_pi8` as seen in rust-lang-nursery/stdsimd#74.
  This new type was added as a new layout option as well as having support added
  to the trans backend. The type is enabled with the `#[repr(x86_mmx)]`
  attribute which is intended to just be an implementation detail of SIMD in
  Rust.

I'm not 100% certain about how the `x86_mmx` type was added, so any extra eyes
or thoughts on that would be greatly appreciated!
上级 cc6b88cc
......@@ -1387,4 +1387,9 @@ pub fn volatile_copy_nonoverlapping_memory<T>(dst: *mut T, src: *const T,
/// # } }
/// ```
pub fn align_offset(ptr: *const (), align: usize) -> usize;
/// Emits a `!nontemporal` store according to LLVM (see their docs).
/// Probably will never become stable.
#[cfg(not(stage0))]
pub fn nontemporal_store<T>(ptr: *mut T, val: T);
}
......@@ -587,6 +587,7 @@ pub fn LLVMStructTypeInContext(C: ContextRef,
// Operations on other types
pub fn LLVMVoidTypeInContext(C: ContextRef) -> TypeRef;
pub fn LLVMX86MMXTypeInContext(C: ContextRef) -> TypeRef;
pub fn LLVMRustMetadataTypeInContext(C: ContextRef) -> TypeRef;
// Operations on all values
......
......@@ -612,6 +612,29 @@ pub fn atomic_store(&self, val: ValueRef, ptr: ValueRef,
}
}
pub fn nontemporal_store(&self, val: ValueRef, ptr: ValueRef) -> ValueRef {
debug!("Store {:?} -> {:?}", Value(val), Value(ptr));
assert!(!self.llbuilder.is_null());
self.count_insn("store.nontemporal");
let ptr = self.check_store(val, ptr);
unsafe {
let insn = llvm::LLVMBuildStore(self.llbuilder, val, ptr);
// According to LLVM [1] building a nontemporal store must *always*
// point to a metadata value of the integer 1. Who knew?
//
// [1]: http://llvm.org/docs/LangRef.html#store-instruction
let one = C_i32(self.ccx, 1);
let node = llvm::LLVMMDNodeInContext(self.ccx.llcx(),
&one,
1);
llvm::LLVMSetMetadata(insn,
llvm::MD_nontemporal as c_uint,
node);
insn
}
}
pub fn gep(&self, ptr: ValueRef, indices: &[ValueRef]) -> ValueRef {
self.count_insn("gep");
unsafe {
......
......@@ -37,13 +37,13 @@ fn main() {
#[repr(simd)]
#[derive(Copy, Clone)]
struct i32x1(i32);
struct i32x2(i32, i32);
extern "platform-intrinsic" {
fn simd_add<T>(a: T, b: T) -> T;
}
unsafe { simd_add(i32x1(0), i32x1(1)); } // ok!
unsafe { simd_add(i32x2(0, 0), i32x2(1, 2)); } // ok!
```
"##,
......
......@@ -540,6 +540,22 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bcx: &Builder<'a, 'tcx>,
}
}
"nontemporal_store" => {
let tp_ty = substs.type_at(0);
let dst = args[0].deref(bcx.ccx);
let val = if let OperandValue::Ref(ptr, align) = args[1].val {
bcx.load(ptr, align.non_abi())
} else {
from_immediate(bcx, args[1].immediate())
};
let ptr = bcx.pointercast(dst.llval, val_ty(val).ptr_to());
let store = bcx.nontemporal_store(val, ptr);
unsafe {
llvm::LLVMSetAlignment(store, ccx.align_of(tp_ty).abi() as u32);
}
return
}
_ => {
let intr = match Intrinsic::find(&name) {
Some(intr) => intr,
......
......@@ -286,4 +286,8 @@ pub fn pointee_for_abi_align(ccx: &CrateContext, align: Align) -> Type {
Type::i8(ccx)
}
}
pub fn x86_mmx(ccx: &CrateContext) -> Type {
ty!(llvm::LLVMX86MMXTypeInContext(ccx.llcx()))
}
}
......@@ -26,8 +26,23 @@ fn uncached_llvm_type<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
match layout.abi {
layout::Abi::Scalar(_) => bug!("handled elsewhere"),
layout::Abi::Vector => {
return Type::vector(&layout.field(ccx, 0).llvm_type(ccx),
layout.fields.count() as u64);
// LLVM has a separate type for 64-bit SIMD vectors on X86 called
// `x86_mmx` which is needed for some SIMD operations. As a bit of a
// hack (all SIMD definitions are super unstable anyway) we
// recognize any one-element SIMD vector as "this should be an
// x86_mmx" type. In general there shouldn't be a need for other
// one-element SIMD vectors, so it's assumed this won't clash with
// much else.
let use_x86_mmx = layout.fields.count() == 1 &&
layout.size.bits() == 64 &&
(ccx.sess().target.target.arch == "x86" ||
ccx.sess().target.target.arch == "x86_64");
if use_x86_mmx {
return Type::x86_mmx(ccx)
} else {
return Type::vector(&layout.field(ccx, 0).llvm_type(ccx),
layout.fields.count() as u64);
}
}
layout::Abi::ScalarPair(..) => {
return Type::struct_(ccx, &[
......
......@@ -318,6 +318,10 @@ pub fn check_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
(0, vec![ptr_ty, tcx.types.usize], tcx.types.usize)
},
"nontemporal_store" => {
(1, vec![ tcx.mk_mut_ptr(param(0)), param(0) ], tcx.mk_nil())
}
ref other => {
struct_span_err!(tcx.sess, it.span, E0093,
"unrecognized intrinsic function: `{}`",
......
// Copyright 2017 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.
// compile-flags: -O
#![feature(core_intrinsics)]
#![crate_type = "lib"]
#[no_mangle]
pub fn a(a: &mut u32, b: u32) {
// CHECK-LABEL: define void @a
// CHECK: store i32 %b, i32* %a, align 4, !nontemporal
unsafe {
std::intrinsics::nontemporal_store(a, b);
}
}
// Copyright 2017 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.
// ignore-arm
// ignore-aarch64
// ignore-emscripten
// compile-flags: -O
#![feature(repr_simd)]
#![crate_type="lib"]
#[repr(simd)]
#[derive(Clone, Copy)]
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
*a = b;
return b
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册