about summary refs log tree commit diff
diff options
context:
space:
mode:
authorHuon Wilson <dbau.pp+github@gmail.com>2015-07-16 16:46:36 -0700
committerHuon Wilson <dbau.pp+github@gmail.com>2015-08-17 14:41:38 -0700
commit9af385bddb3076637ab299672c90702562644894 (patch)
treea5e6171ed28d2c0099ebf0a1f81878bb91b317bd
parent1bfbde6778ee4839ca62aad3d025477296cf323f (diff)
downloadrust-9af385bddb3076637ab299672c90702562644894.tar.gz
rust-9af385bddb3076637ab299672c90702562644894.zip
Add rustc_platform_intrinsics & some arm/x86 intrs.
These are enough to implement a cross-platform SIMD single-precision
mandelbrot renderer.
-rw-r--r--mk/crates.mk5
-rw-r--r--src/librustc_platform_intrinsics/aarch64.rs49
-rw-r--r--src/librustc_platform_intrinsics/arm.rs46
-rwxr-xr-xsrc/librustc_platform_intrinsics/lib.rs94
-rw-r--r--src/librustc_platform_intrinsics/x86.rs38
-rw-r--r--src/librustc_trans/lib.rs1
-rw-r--r--src/librustc_trans/trans/intrinsic.rs37
-rw-r--r--src/librustc_typeck/check/mod.rs6
8 files changed, 273 insertions, 3 deletions
diff --git a/mk/crates.mk b/mk/crates.mk
index af2a663b61d..611f0146285 100644
--- a/mk/crates.mk
+++ b/mk/crates.mk
@@ -56,7 +56,7 @@ TARGET_CRATES := libc std flate arena term \
 		 alloc_system
 RUSTC_CRATES := rustc rustc_typeck rustc_borrowck rustc_resolve rustc_driver \
                 rustc_trans rustc_back rustc_llvm rustc_privacy rustc_lint \
-                rustc_data_structures
+                rustc_data_structures rustc_platform_intrinsics
 HOST_CRATES := syntax $(RUSTC_CRATES) rustdoc fmt_macros
 TOOLS := compiletest rustdoc rustc rustbook error-index-generator
 
@@ -74,7 +74,7 @@ DEPS_rustc_driver := arena flate getopts graphviz libc rustc rustc_back rustc_bo
 		     rustc_trans rustc_privacy rustc_lint
 
 DEPS_rustc_trans := arena flate getopts graphviz libc rustc rustc_back \
-	                log syntax serialize rustc_llvm
+	                log syntax serialize rustc_llvm rustc_platform_intrinsics
 DEPS_rustc_typeck := rustc syntax
 DEPS_rustc_borrowck := rustc log graphviz syntax
 DEPS_rustc_resolve := rustc log syntax
@@ -83,6 +83,7 @@ DEPS_rustc_lint := rustc log syntax
 DEPS_rustc := syntax flate arena serialize getopts rbml \
               log graphviz rustc_llvm rustc_back rustc_data_structures
 DEPS_rustc_llvm := native:rustllvm libc std rustc_bitflags
+DEPS_rustc_platform_intrinsics := rustc rustc_llvm
 DEPS_rustc_back := std syntax rustc_llvm flate log libc
 DEPS_rustc_data_structures := std log serialize
 DEPS_rustdoc := rustc rustc_driver native:hoedown serialize getopts \
diff --git a/src/librustc_platform_intrinsics/aarch64.rs b/src/librustc_platform_intrinsics/aarch64.rs
new file mode 100644
index 00000000000..2bdb9ce4327
--- /dev/null
+++ b/src/librustc_platform_intrinsics/aarch64.rs
@@ -0,0 +1,49 @@
+// Copyright 2015 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.
+
+use {Intrinsic, i, f, v};
+use rustc::middle::ty;
+
+macro_rules! p {
+    ($name: expr, ($($inputs: tt),*) -> $output: tt) => {
+        plain!(concat!("llvm.aarch64.neon.", $name), ($($inputs),*) -> $output)
+    }
+}
+pub fn find<'tcx>(_tcx: &ty::ctxt<'tcx>, name: &str) -> Option<Intrinsic> {
+    Some(match name {
+        "vmaxvq_u8" => p!("umaxv.i8.v16i8", (i8x16) -> i8),
+        "vmaxvq_u16" => p!("umaxv.i16.v8i16", (i16x8) -> i16),
+        "vmaxvq_u32" => p!("umaxv.i32.v4i32", (i32x4) -> i32),
+
+        "vmaxvq_s8" => p!("smaxv.i8.v16i8", (i8x16) -> i8),
+        "vmaxvq_s16" => p!("smaxv.i16.v8i16", (i16x8) -> i16),
+        "vmaxvq_s32" => p!("smaxv.i32.v4i32", (i32x4) -> i32),
+
+        "vminvq_u8" => p!("uminv.i8.v16i8", (i8x16) -> i8),
+        "vminvq_u16" => p!("uminv.i16.v8i16", (i16x8) -> i16),
+        "vminvq_u32" => p!("uminv.i32.v4i32", (i32x4) -> i32),
+        "vminvq_s8" => p!("sminv.i8.v16i8", (i8x16) -> i8),
+        "vminvq_s16" => p!("sminv.i16.v8i16", (i16x8) -> i16),
+        "vminvq_s32" => p!("sminv.i32.v4i32", (i32x4) -> i32),
+
+        "vsqrtq_f32" => plain!("llvm.sqrt.v4f32", (f32x4) -> f32x4),
+        "vsqrtq_f64" => plain!("llvm.sqrt.v2f64", (f64x2) -> f64x2),
+
+        "vrsqrteq_f32" => p!("vrsqrte.v4f32", (f32x4) -> f32x4),
+        "vrsqrteq_f64" => p!("vrsqrte.v2f64", (f64x2) -> f64x2),
+
+        "vmaxq_f32" => p!("fmax.v4f32", (f32x4, f32x4) -> f32x4),
+        "vmaxq_f64" => p!("fmax.v2f64", (f64x2, f64x2) -> f64x2),
+
+        "vminq_f32" => p!("fmin.v4f32", (f32x4, f32x4) -> f32x4),
+        "vminq_f64" => p!("fmin.v2f64", (f64x2, f64x2) -> f64x2),
+        _ => return None,
+    })
+}
diff --git a/src/librustc_platform_intrinsics/arm.rs b/src/librustc_platform_intrinsics/arm.rs
new file mode 100644
index 00000000000..7fa7d45a600
--- /dev/null
+++ b/src/librustc_platform_intrinsics/arm.rs
@@ -0,0 +1,46 @@
+// Copyright 2015 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.
+
+use {Intrinsic, i, f, v};
+use rustc::middle::ty;
+
+macro_rules! p {
+    ($name: expr, ($($inputs: tt),*) -> $output: tt) => {
+        plain!(concat!("llvm.arm.neon.", $name), ($($inputs),*) -> $output)
+    }
+}
+pub fn find<'tcx>(_tcx: &ty::ctxt<'tcx>, name: &str) -> Option<Intrinsic> {
+    Some(match name {
+        "vpmax_u8" => p!("vpmaxu.v8i8", (i8x8, i8x8) -> i8x8),
+        "vpmax_s8" => p!("vpmaxs.v8i8", (i8x8, i8x8) -> i8x8),
+        "vpmax_u16" => p!("vpmaxu.v4i16", (i16x4, i16x4) -> i16x4),
+        "vpmax_s16" => p!("vpmaxs.v4i16", (i16x4, i16x4) -> i16x4),
+        "vpmax_u32" => p!("vpmaxu.v2i32", (i32x2, i32x2) -> i32x2),
+        "vpmax_s32" => p!("vpmaxs.v2i32", (i32x2, i32x2) -> i32x2),
+
+        "vpmin_u8" => p!("vpminu.v8i8", (i8x8, i8x8) -> i8x8),
+        "vpmin_s8" => p!("vpmins.v8i8", (i8x8, i8x8) -> i8x8),
+        "vpmin_u16" => p!("vpminu.v4i16", (i16x4, i16x4) -> i16x4),
+        "vpmin_s16" => p!("vpmins.v4i16", (i16x4, i16x4) -> i16x4),
+        "vpmin_u32" => p!("vpminu.v2i32", (i32x2, i32x2) -> i32x2),
+        "vpmin_s32" => p!("vpmins.v2i32", (i32x2, i32x2) -> i32x2),
+
+        "vsqrtq_f32" => plain!("llvm.sqrt.v4f32", (f32x4) -> f32x4),
+        "vsqrtq_f64" => plain!("llvm.sqrt.v2f64", (f64x2) -> f64x2),
+
+        "vrsqrteq_f32" => p!("vrsqrte.v4f32", (f32x4) -> f32x4),
+        "vrsqrteq_f64" => p!("vrsqrte.v2f64", (f64x2) -> f64x2),
+
+        "vmaxq_f32" => p!("vmaxs.v4f32", (f32x4, f32x4) -> f32x4),
+
+        "vminq_f32" => p!("vmins.v4f32", (f32x4, f32x4) -> f32x4),
+        _ => return None,
+    })
+}
diff --git a/src/librustc_platform_intrinsics/lib.rs b/src/librustc_platform_intrinsics/lib.rs
new file mode 100755
index 00000000000..17e98770e83
--- /dev/null
+++ b/src/librustc_platform_intrinsics/lib.rs
@@ -0,0 +1,94 @@
+// Copyright 2015 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.
+
+#![cfg_attr(stage0, feature(custom_attribute))]
+#![crate_name = "rustc_platform_intrinsics"]
+#![unstable(feature = "rustc_private", issue = "27812")]
+#![staged_api]
+#![crate_type = "dylib"]
+#![crate_type = "rlib"]
+#![feature(staged_api, rustc_private)]
+
+extern crate rustc_llvm as llvm;
+extern crate rustc;
+
+use rustc::middle::ty;
+
+pub struct Intrinsic {
+    pub inputs: Vec<Type>,
+    pub output: Type,
+
+    pub definition: IntrinsicDef,
+}
+
+#[derive(Clone)]
+pub enum Type {
+    Integer(u8),
+    Float(u8),
+    Pointer(Box<Type>),
+    Vector(Box<Type>, u8),
+}
+
+pub enum IntrinsicDef {
+    Named(&'static str),
+}
+
+fn i(width: u8) -> Type { Type::Integer(width) }
+fn f(width: u8) -> Type { Type::Float(width) }
+fn v(x: Type, length: u8) -> Type { Type::Vector(Box::new(x), length) }
+
+macro_rules! ty {
+    (f32x4) => (v(f(32), 4));
+    (f64x2) => (v(f(64), 2));
+
+    (i8x16) => (v(i(8), 16));
+    (i16x8) => (v(i(16), 8));
+    (i32x4) => (v(i(32), 4));
+    (i64x2) => (v(i(64), 2));
+
+    (f32x2) => (v(f(32), 2));
+    (i8x8) => (v(i(8), 8));
+    (i16x4) => (v(i(16), 4));
+    (i32x2) => (v(i(32), 2));
+
+    (i64) => (i(64));
+    (i32) => (i(32));
+    (i16) => (i(16));
+    (i8) => (i(8));
+    (f32) => (f(32));
+    (f64) => (f(64));
+}
+macro_rules! plain {
+    ($name: expr, ($($inputs: tt),*) -> $output: tt) => {
+        Intrinsic {
+            inputs: vec![$(ty!($inputs)),*],
+            output: ty!($output),
+            definition: ::IntrinsicDef::Named($name)
+        }
+    }
+}
+
+mod x86;
+mod arm;
+mod aarch64;
+
+impl Intrinsic {
+    pub fn find<'tcx>(tcx: &ty::ctxt<'tcx>, name: &str) -> Option<Intrinsic> {
+        if name.starts_with("x86_") {
+            x86::find(tcx, &name["x86_".len()..])
+        } else if name.starts_with("arm_") {
+            arm::find(tcx, &name["arm_".len()..])
+        } else if name.starts_with("aarch64_") {
+            aarch64::find(tcx, &name["aarch64_".len()..])
+        } else {
+            None
+        }
+    }
+}
diff --git a/src/librustc_platform_intrinsics/x86.rs b/src/librustc_platform_intrinsics/x86.rs
new file mode 100644
index 00000000000..93cadf8b694
--- /dev/null
+++ b/src/librustc_platform_intrinsics/x86.rs
@@ -0,0 +1,38 @@
+// Copyright 2015 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.
+
+use {Intrinsic, i, f, v};
+use rustc::middle::ty;
+
+macro_rules! p {
+    ($name: expr, ($($inputs: tt),*) -> $output: tt) => {
+        plain!(concat!("llvm.x86.", $name), ($($inputs),*) -> $output)
+    }
+}
+
+pub fn find<'tcx>(_tcx: &ty::ctxt<'tcx>, name: &str) -> Option<Intrinsic> {
+    Some(match name {
+        "mm_movemask_ps" => p!("sse.movmsk.ps", (f32x4) -> i32),
+        "mm_movemask_pd" => p!("sse2.movmsk.pd", (f64x2) -> i32),
+        "mm_movemask_epi8" => p!("sse2.pmovmskb.128", (i8x16) -> i32),
+
+        "mm_rsqrt_ps" => p!("sse.rsqrt.ps", (f32x4) -> f32x4),
+
+        "mm_sqrt_ps" => plain!("llvm.sqrt.v4f32", (f32x4) -> f32x4),
+        "mm_sqrt_pd" => plain!("llvm.sqrt.v2f64", (f64x2) -> f64x2),
+
+        "mm_max_ps" => p!("sse.max.ps", (f32x4, f32x4) -> f32x4),
+        "mm_max_pd" => p!("sse2.max.pd", (f64x2, f64x2) -> f64x2),
+
+        "mm_min_ps" => p!("sse.min.ps", (f32x4, f32x4) -> f32x4),
+        "mm_min_pd" => p!("sse2.min.pd", (f64x2, f64x2) -> f64x2),
+        _ => return None
+    })
+}
diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs
index 6d91ae6fed6..23f21f337f3 100644
--- a/src/librustc_trans/lib.rs
+++ b/src/librustc_trans/lib.rs
@@ -54,6 +54,7 @@ extern crate libc;
 extern crate rustc;
 extern crate rustc_back;
 extern crate rustc_llvm as llvm;
+extern crate rustc_platform_intrinsics as intrinsics;
 extern crate serialize;
 
 #[macro_use] extern crate log;
diff --git a/src/librustc_trans/trans/intrinsic.rs b/src/librustc_trans/trans/intrinsic.rs
index 489c54dc6e2..f79b62878c1 100644
--- a/src/librustc_trans/trans/intrinsic.rs
+++ b/src/librustc_trans/trans/intrinsic.rs
@@ -11,6 +11,7 @@
 #![allow(non_upper_case_globals)]
 
 use arena::TypedArena;
+use intrinsics::{self, Intrinsic};
 use llvm;
 use llvm::{SequentiallyConsistent, Acquire, Release, AtomicXchg, ValueRef, TypeKind};
 use middle::subst;
@@ -905,7 +906,41 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
 
         }
 
-        (_, _) => ccx.sess().span_bug(foreign_item.span, "unknown intrinsic")
+        (_, _) => {
+            match Intrinsic::find(tcx, &name) {
+                None => ccx.sess().span_bug(foreign_item.span, "unknown intrinsic"),
+                Some(intr) => {
+                    fn ty_to_type(ccx: &CrateContext, t: &intrinsics::Type) -> Type {
+                        use intrinsics::Type::*;
+                        match *t {
+                            Integer(x) => Type::ix(ccx, x as u64),
+                            Float(x) => {
+                                match x {
+                                    32 => Type::f32(ccx),
+                                    64 => Type::f64(ccx),
+                                    _ => unreachable!()
+                                }
+                            }
+                            Pointer(_) => unimplemented!(),
+                            Vector(ref t, length) => Type::vector(&ty_to_type(ccx, t),
+                                                                  length as u64)
+                        }
+                    }
+
+                    let inputs = intr.inputs.iter().map(|t| ty_to_type(ccx, t)).collect::<Vec<_>>();
+                    let outputs = ty_to_type(ccx, &intr.output);
+                    match intr.definition {
+                        intrinsics::IntrinsicDef::Named(name) => {
+                            let f = declare::declare_cfn(ccx,
+                                                         name,
+                                                         Type::func(&inputs, &outputs),
+                                                         tcx.mk_nil());
+                            Call(bcx, f, &llargs, None, call_debug_location)
+                        }
+                    }
+                }
+            }
+        }
     };
 
     if val_ty(llval) != Type::void(ccx) &&
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 749bc8ab294..56230ae06f9 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -5378,6 +5378,12 @@ pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &ast::ForeignItem) {
                 (0, vec![tcx.mk_fn(None, fn_ty), mut_u8], mut_u8)
             }
 
+            name if name.starts_with("x86_") ||
+                    name.starts_with("arm_") ||
+                    name.starts_with("aarch64_") => {
+                // FIXME: skip checking these for now
+                return
+            }
             ref other => {
                 span_err!(tcx.sess, it.span, E0093,
                     "unrecognized intrinsic function: `{}`", *other);