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 or the MIT license +// , 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 { + 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 or the MIT license +// , 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 { + 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 or the MIT license +// , 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, + pub output: Type, + + pub definition: IntrinsicDef, +} + +#[derive(Clone)] +pub enum Type { + Integer(u8), + Float(u8), + Pointer(Box), + Vector(Box, 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 { + 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 or the MIT license +// , 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 { + 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::>(); + 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);