Add rustc_platform_intrinsics & some arm/x86 intrs.
These are enough to implement a cross-platform SIMD single-precision mandelbrot renderer.
This commit is contained in:
parent
1bfbde6778
commit
9af385bddb
|
@ -56,7 +56,7 @@ TARGET_CRATES := libc std flate arena term \
|
||||||
alloc_system
|
alloc_system
|
||||||
RUSTC_CRATES := rustc rustc_typeck rustc_borrowck rustc_resolve rustc_driver \
|
RUSTC_CRATES := rustc rustc_typeck rustc_borrowck rustc_resolve rustc_driver \
|
||||||
rustc_trans rustc_back rustc_llvm rustc_privacy rustc_lint \
|
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
|
HOST_CRATES := syntax $(RUSTC_CRATES) rustdoc fmt_macros
|
||||||
TOOLS := compiletest rustdoc rustc rustbook error-index-generator
|
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
|
rustc_trans rustc_privacy rustc_lint
|
||||||
|
|
||||||
DEPS_rustc_trans := arena flate getopts graphviz libc rustc rustc_back \
|
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_typeck := rustc syntax
|
||||||
DEPS_rustc_borrowck := rustc log graphviz syntax
|
DEPS_rustc_borrowck := rustc log graphviz syntax
|
||||||
DEPS_rustc_resolve := rustc log 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 \
|
DEPS_rustc := syntax flate arena serialize getopts rbml \
|
||||||
log graphviz rustc_llvm rustc_back rustc_data_structures
|
log graphviz rustc_llvm rustc_back rustc_data_structures
|
||||||
DEPS_rustc_llvm := native:rustllvm libc std rustc_bitflags
|
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_back := std syntax rustc_llvm flate log libc
|
||||||
DEPS_rustc_data_structures := std log serialize
|
DEPS_rustc_data_structures := std log serialize
|
||||||
DEPS_rustdoc := rustc rustc_driver native:hoedown serialize getopts \
|
DEPS_rustdoc := rustc rustc_driver native:hoedown serialize getopts \
|
||||||
|
|
|
@ -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,
|
||||||
|
})
|
||||||
|
}
|
|
@ -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,
|
||||||
|
})
|
||||||
|
}
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
||||||
|
})
|
||||||
|
}
|
|
@ -54,6 +54,7 @@ extern crate libc;
|
||||||
extern crate rustc;
|
extern crate rustc;
|
||||||
extern crate rustc_back;
|
extern crate rustc_back;
|
||||||
extern crate rustc_llvm as llvm;
|
extern crate rustc_llvm as llvm;
|
||||||
|
extern crate rustc_platform_intrinsics as intrinsics;
|
||||||
extern crate serialize;
|
extern crate serialize;
|
||||||
|
|
||||||
#[macro_use] extern crate log;
|
#[macro_use] extern crate log;
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
#![allow(non_upper_case_globals)]
|
#![allow(non_upper_case_globals)]
|
||||||
|
|
||||||
use arena::TypedArena;
|
use arena::TypedArena;
|
||||||
|
use intrinsics::{self, Intrinsic};
|
||||||
use llvm;
|
use llvm;
|
||||||
use llvm::{SequentiallyConsistent, Acquire, Release, AtomicXchg, ValueRef, TypeKind};
|
use llvm::{SequentiallyConsistent, Acquire, Release, AtomicXchg, ValueRef, TypeKind};
|
||||||
use middle::subst;
|
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) &&
|
if val_ty(llval) != Type::void(ccx) &&
|
||||||
|
|
|
@ -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)
|
(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 => {
|
ref other => {
|
||||||
span_err!(tcx.sess, it.span, E0093,
|
span_err!(tcx.sess, it.span, E0093,
|
||||||
"unrecognized intrinsic function: `{}`", *other);
|
"unrecognized intrinsic function: `{}`", *other);
|
||||||
|
|
Loading…
Reference in New Issue