Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions src/librustc_llvm/ffi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1201,6 +1201,46 @@ extern "C" {
Name: *const c_char)
-> ValueRef;

pub fn LLVMRustBuildVectorReduceFAdd(B: BuilderRef,
Acc: ValueRef,
Src: ValueRef)
-> ValueRef;
pub fn LLVMRustBuildVectorReduceFMul(B: BuilderRef,
Acc: ValueRef,
Src: ValueRef)
-> ValueRef;
pub fn LLVMRustBuildVectorReduceAdd(B: BuilderRef,
Src: ValueRef)
-> ValueRef;
pub fn LLVMRustBuildVectorReduceMul(B: BuilderRef,
Src: ValueRef)
-> ValueRef;
pub fn LLVMRustBuildVectorReduceAnd(B: BuilderRef,
Src: ValueRef)
-> ValueRef;
pub fn LLVMRustBuildVectorReduceOr(B: BuilderRef,
Src: ValueRef)
-> ValueRef;
pub fn LLVMRustBuildVectorReduceXor(B: BuilderRef,
Src: ValueRef)
-> ValueRef;
pub fn LLVMRustBuildVectorReduceMin(B: BuilderRef,
Src: ValueRef,
IsSigned: bool)
-> ValueRef;
pub fn LLVMRustBuildVectorReduceMax(B: BuilderRef,
Src: ValueRef,
IsSigned: bool)
-> ValueRef;
pub fn LLVMRustBuildVectorReduceFMin(B: BuilderRef,
Src: ValueRef,
IsNaN: bool)
-> ValueRef;
pub fn LLVMRustBuildVectorReduceFMax(B: BuilderRef,
Src: ValueRef,
IsNaN: bool)
-> ValueRef;

pub fn LLVMBuildIsNull(B: BuilderRef, Val: ValueRef, Name: *const c_char) -> ValueRef;
pub fn LLVMBuildIsNotNull(B: BuilderRef, Val: ValueRef, Name: *const c_char) -> ValueRef;
pub fn LLVMBuildPtrDiff(B: BuilderRef,
Expand Down
75 changes: 75 additions & 0 deletions src/librustc_trans/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -955,6 +955,81 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
}
}

pub fn vector_reduce_fadd_fast(&self, acc: ValueRef, src: ValueRef) -> ValueRef {
self.count_insn("vector.reduce.fadd_fast");
unsafe {
let instr = llvm::LLVMRustBuildVectorReduceFAdd(self.llbuilder, acc, src);
llvm::LLVMRustSetHasUnsafeAlgebra(instr);
instr
}
}
pub fn vector_reduce_fmul_fast(&self, acc: ValueRef, src: ValueRef) -> ValueRef {
self.count_insn("vector.reduce.fmul_fast");
unsafe {
let instr = llvm::LLVMRustBuildVectorReduceFMul(self.llbuilder, acc, src);
llvm::LLVMRustSetHasUnsafeAlgebra(instr);
instr
}
}
pub fn vector_reduce_add(&self, src: ValueRef) -> ValueRef {
self.count_insn("vector.reduce.add");
unsafe {
llvm::LLVMRustBuildVectorReduceAdd(self.llbuilder, src)
}
}
pub fn vector_reduce_mul(&self, src: ValueRef) -> ValueRef {
self.count_insn("vector.reduce.mul");
unsafe {
llvm::LLVMRustBuildVectorReduceMul(self.llbuilder, src)
}
}
pub fn vector_reduce_and(&self, src: ValueRef) -> ValueRef {
self.count_insn("vector.reduce.and");
unsafe {
llvm::LLVMRustBuildVectorReduceAnd(self.llbuilder, src)
}
}
pub fn vector_reduce_or(&self, src: ValueRef) -> ValueRef {
self.count_insn("vector.reduce.or");
unsafe {
llvm::LLVMRustBuildVectorReduceOr(self.llbuilder, src)
}
}
pub fn vector_reduce_xor(&self, src: ValueRef) -> ValueRef {
self.count_insn("vector.reduce.xor");
unsafe {
llvm::LLVMRustBuildVectorReduceXor(self.llbuilder, src)
}
}
pub fn vector_reduce_fmin_fast(&self, src: ValueRef) -> ValueRef {
self.count_insn("vector.reduce.fmin_fast");
unsafe {
let instr = llvm::LLVMRustBuildVectorReduceFMin(self.llbuilder, src, false);
llvm::LLVMRustSetHasUnsafeAlgebra(instr);
instr
}
}
pub fn vector_reduce_fmax_fast(&self, src: ValueRef) -> ValueRef {
self.count_insn("vector.reduce.fmax_fast");
unsafe {
let instr = llvm::LLVMRustBuildVectorReduceFMax(self.llbuilder, src, false);
llvm::LLVMRustSetHasUnsafeAlgebra(instr);
instr
}
}
pub fn vector_reduce_min(&self, src: ValueRef, is_signed: bool) -> ValueRef {
self.count_insn("vector.reduce.min");
unsafe {
llvm::LLVMRustBuildVectorReduceMin(self.llbuilder, src, is_signed)
}
}
pub fn vector_reduce_max(&self, src: ValueRef, is_signed: bool) -> ValueRef {
self.count_insn("vector.reduce.max");
unsafe {
llvm::LLVMRustBuildVectorReduceMax(self.llbuilder, src, is_signed)
}
}

pub fn extract_value(&self, agg_val: ValueRef, idx: u64) -> ValueRef {
self.count_insn("extractvalue");
assert_eq!(idx as c_uint as u64, idx);
Expand Down
219 changes: 216 additions & 3 deletions src/librustc_trans/intrinsic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1018,14 +1018,22 @@ fn generic_simd_intrinsic<'a, 'tcx>(
name, $($fmt)*));
}
}
macro_rules! require {
($cond: expr, $($fmt: tt)*) => {
if !$cond {
macro_rules! return_error {
($($fmt: tt)*) => {
{
emit_error!($($fmt)*);
return Err(());
}
}
}

macro_rules! require {
($cond: expr, $($fmt: tt)*) => {
if !$cond {
return_error!($($fmt)*);
}
};
}
macro_rules! require_simd {
($ty: expr, $position: expr) => {
require!($ty.is_simd(), "expected SIMD {} type, found non-SIMD `{}`", $position, $ty)
Expand Down Expand Up @@ -1142,6 +1150,211 @@ fn generic_simd_intrinsic<'a, 'tcx>(
return Ok(bx.extract_element(args[0].immediate(), args[1].immediate()))
}

if name == "simd_reduce_add" {
require!(ret_ty == in_elem,
"expected return type `{}` (element of input `{}`), found `{}`",
in_elem, in_ty, ret_ty);
return match in_elem.sty {
ty::TyInt(_i) => {
Ok(bx.vector_reduce_add(args[0].immediate()))
},
ty::TyUint(_u) => {
Ok(bx.vector_reduce_add(args[0].immediate()))
},
ty::TyFloat(f) => {
// undef as accumulator makes the reduction unordered:
let acc = match f.bit_width() {
32 => C_undef(Type::f32(bx.cx)),
64 => C_undef(Type::f64(bx.cx)),
v => {
return_error!(
"unsupported {} from `{}` with element `{}` of size `{}` to `{}`",
"simd_reduce_add", in_ty, in_elem, v, ret_ty)
}
};
Ok(bx.vector_reduce_fadd_fast(acc, args[0].immediate()))
}
_ => {
return_error!("unsupported {} from `{}` with element `{}` to `{}`",
"simd_reduce_add", in_ty, in_elem, ret_ty)
},
}
}

if name == "simd_reduce_mul" {
require!(ret_ty == in_elem,
"expected return type `{}` (element of input `{}`), found `{}`",
in_elem, in_ty, ret_ty);
return match in_elem.sty {
ty::TyInt(_i) => {
Ok(bx.vector_reduce_mul(args[0].immediate()))
},
ty::TyUint(_u) => {
Ok(bx.vector_reduce_mul(args[0].immediate()))
},
ty::TyFloat(f) => {
// undef as accumulator makes the reduction unordered:
let acc = match f.bit_width() {
32 => C_undef(Type::f32(bx.cx)),
64 => C_undef(Type::f64(bx.cx)),
v => {
return_error!(
"unsupported {} from `{}` with element `{}` of size `{}` to `{}`",
"simd_reduce_mul", in_ty, in_elem, v, ret_ty)
}
};
Ok(bx.vector_reduce_fmul_fast(acc, args[0].immediate()))
}
_ => {
return_error!("unsupported {} from `{}` with element `{}` to `{}`",
"simd_reduce_mul", in_ty, in_elem, ret_ty)
},
}
}

if name == "simd_reduce_min" {
require!(ret_ty == in_elem,
"expected return type `{}` (element of input `{}`), found `{}`",
in_elem, in_ty, ret_ty);
return match in_elem.sty {
ty::TyInt(_i) => {
Ok(bx.vector_reduce_min(args[0].immediate(), true))
},
ty::TyUint(_u) => {
Ok(bx.vector_reduce_min(args[0].immediate(), false))
},
ty::TyFloat(_f) => {
Ok(bx.vector_reduce_fmin_fast(args[0].immediate()))
}
_ => {
return_error!("unsupported {} from `{}` with element `{}` to `{}`",
"simd_reduce_min", in_ty, in_elem, ret_ty)
},
}
}

if name == "simd_reduce_max" {
require!(ret_ty == in_elem,
"expected return type `{}` (element of input `{}`), found `{}`",
in_elem, in_ty, ret_ty);
return match in_elem.sty {
ty::TyInt(_i) => {
Ok(bx.vector_reduce_max(args[0].immediate(), true))
},
ty::TyUint(_u) => {
Ok(bx.vector_reduce_max(args[0].immediate(), false))
},
ty::TyFloat(_f) => {
Ok(bx.vector_reduce_fmax_fast(args[0].immediate()))
}
_ => {
return_error!("unsupported {} from `{}` with element `{}` to `{}`",
"simd_reduce_max", in_ty, in_elem, ret_ty)
},
}
}

if name == "simd_reduce_and" {
require!(ret_ty == in_elem,
"expected return type `{}` (element of input `{}`), found `{}`",
in_elem, in_ty, ret_ty);
return match in_elem.sty {
ty::TyInt(_i) => {
Ok(bx.vector_reduce_and(args[0].immediate()))
},
ty::TyUint(_u) => {
Ok(bx.vector_reduce_and(args[0].immediate()))
},
_ => {
return_error!("unsupported {} from `{}` with element `{}` to `{}`",
"simd_reduce_and", in_ty, in_elem, ret_ty)
},
}
}

if name == "simd_reduce_or" {
require!(ret_ty == in_elem,
"expected return type `{}` (element of input `{}`), found `{}`",
in_elem, in_ty, ret_ty);
return match in_elem.sty {
ty::TyInt(_i) => {
Ok(bx.vector_reduce_or(args[0].immediate()))
},
ty::TyUint(_u) => {
Ok(bx.vector_reduce_or(args[0].immediate()))
},
_ => {
return_error!("unsupported {} from `{}` with element `{}` to `{}`",
"simd_reduce_or", in_ty, in_elem, ret_ty)
},
}
}

if name == "simd_reduce_xor" {
require!(ret_ty == in_elem,
"expected return type `{}` (element of input `{}`), found `{}`",
in_elem, in_ty, ret_ty);
return match in_elem.sty {
ty::TyInt(_i) => {
Ok(bx.vector_reduce_xor(args[0].immediate()))
},
ty::TyUint(_u) => {
Ok(bx.vector_reduce_xor(args[0].immediate()))
},
_ => {
return_error!("unsupported {} from `{}` with element `{}` to `{}`",
"simd_reduce_xor", in_ty, in_elem, ret_ty)
},
}
}

if name == "simd_reduce_all" {
//require!(ret_ty == in_elem,
// "expected return type `{}` (element of input `{}`), found `{}`",
// in_elem, in_ty, ret_ty);
let i1 = Type::i1(bx.cx);
let i1xn = Type::vector(&i1, in_len as u64);
let v = bx.trunc(args[0].immediate(), i1xn);

let red = match in_elem.sty {
ty::TyInt(_i) => {
bx.vector_reduce_and(v)
},
ty::TyUint(_u) => {
bx.vector_reduce_and(v)
},
_ => {
return_error!("unsupported {} from `{}` with element `{}` to `{}`",
"simd_reduce_and", in_ty, in_elem, ret_ty)
},
};
return Ok(bx.zext(red, Type::bool(bx.cx)));
}

if name == "simd_reduce_any" {
//require!(ret_ty == in_elem,
// "expected return type `{}` (element of input `{}`), found `{}`",
// in_elem, in_ty, ret_ty);
let i1 = Type::i1(bx.cx);
let i1xn = Type::vector(&i1, in_len as u64);
let v = bx.trunc(args[0].immediate(), i1xn);

let red = match in_elem.sty {
ty::TyInt(_i) => {
bx.vector_reduce_or(v)
},
ty::TyUint(_u) => {
bx.vector_reduce_or(v)
},
_ => {
return_error!("unsupported {} from `{}` with element `{}` to `{}`",
"simd_reduce_and", in_ty, in_elem, ret_ty)
},
};
return Ok(bx.zext(red, Type::bool(bx.cx)));
}


if name == "simd_cast" {
require_simd!(ret_ty, "return");
let out_len = ret_ty.simd_size(tcx);
Expand Down
5 changes: 5 additions & 0 deletions src/librustc_typeck/check/intrinsic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -361,6 +361,11 @@ pub fn check_platform_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
"simd_insert" => (2, vec![param(0), tcx.types.u32, param(1)], param(0)),
"simd_extract" => (2, vec![param(0), tcx.types.u32], param(1)),
"simd_cast" => (2, vec![param(0)], param(1)),
"simd_reduce_all" | "simd_reduce_any" => (1, vec![param(0)], tcx.types.bool),
"simd_reduce_add" | "simd_reduce_mul" |
"simd_reduce_and" | "simd_reduce_or" | "simd_reduce_xor" |
"simd_reduce_min" | "simd_reduce_max"
=> (2, vec![param(0)], param(1)),
name if name.starts_with("simd_shuffle") => {
match name["simd_shuffle".len()..].parse() {
Ok(n) => {
Expand Down
Loading