From 01cc5b3e195bb01088fdd59638f0d8c6d0a78142 Mon Sep 17 00:00:00 2001 From: gnzlbg Date: Tue, 13 Mar 2018 16:46:55 +0100 Subject: add intrinsics for portable packed simd vector reductions --- src/rustllvm/RustWrapper.cpp | 46 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) (limited to 'src/rustllvm/RustWrapper.cpp') diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp index 27d5496f576..e749549201e 100644 --- a/src/rustllvm/RustWrapper.cpp +++ b/src/rustllvm/RustWrapper.cpp @@ -1395,3 +1395,49 @@ LLVMRustModuleCost(LLVMModuleRef M) { auto f = unwrap(M)->functions(); return std::distance(std::begin(f), std::end(f)); } + +// Vector reductions: +extern "C" LLVMValueRef +LLVMRustBuildVectorReduceFAdd(LLVMBuilderRef B, LLVMValueRef Acc, LLVMValueRef Src) { + return wrap(unwrap(B)->CreateFAddReduce(unwrap(Acc),unwrap(Src))); +} +extern "C" LLVMValueRef +LLVMRustBuildVectorReduceFMul(LLVMBuilderRef B, LLVMValueRef Acc, LLVMValueRef Src) { + return wrap(unwrap(B)->CreateFMulReduce(unwrap(Acc),unwrap(Src))); +} +extern "C" LLVMValueRef +LLVMRustBuildVectorReduceAdd(LLVMBuilderRef B, LLVMValueRef Src) { + return wrap(unwrap(B)->CreateAddReduce(unwrap(Src))); +} +extern "C" LLVMValueRef +LLVMRustBuildVectorReduceMul(LLVMBuilderRef B, LLVMValueRef Src) { + return wrap(unwrap(B)->CreateMulReduce(unwrap(Src))); +} +extern "C" LLVMValueRef +LLVMRustBuildVectorReduceAnd(LLVMBuilderRef B, LLVMValueRef Src) { + return wrap(unwrap(B)->CreateAndReduce(unwrap(Src))); +} +extern "C" LLVMValueRef +LLVMRustBuildVectorReduceOr(LLVMBuilderRef B, LLVMValueRef Src) { + return wrap(unwrap(B)->CreateOrReduce(unwrap(Src))); +} +extern "C" LLVMValueRef +LLVMRustBuildVectorReduceXor(LLVMBuilderRef B, LLVMValueRef Src) { + return wrap(unwrap(B)->CreateXorReduce(unwrap(Src))); +} +extern "C" LLVMValueRef +LLVMRustBuildVectorReduceMin(LLVMBuilderRef B, LLVMValueRef Src, bool IsSigned) { + return wrap(unwrap(B)->CreateIntMinReduce(unwrap(Src), IsSigned)); +} +extern "C" LLVMValueRef +LLVMRustBuildVectorReduceMax(LLVMBuilderRef B, LLVMValueRef Src, bool IsSigned) { + return wrap(unwrap(B)->CreateIntMaxReduce(unwrap(Src), IsSigned)); +} +extern "C" LLVMValueRef +LLVMRustBuildVectorReduceFMin(LLVMBuilderRef B, LLVMValueRef Src, bool NoNaN) { + return wrap(unwrap(B)->CreateFPMinReduce(unwrap(Src), NoNaN)); +} +extern "C" LLVMValueRef +LLVMRustBuildVectorReduceFMax(LLVMBuilderRef B, LLVMValueRef Src, bool NoNaN) { + return wrap(unwrap(B)->CreateFPMaxReduce(unwrap(Src), NoNaN)); +} -- cgit 1.4.1-3-g733a5 From 07ce659dd03523b526cb4804b9ef882f31e9ecf3 Mon Sep 17 00:00:00 2001 From: gnzlbg Date: Wed, 14 Mar 2018 17:22:40 +0100 Subject: expose ordered/unordered/nanless intirnsics --- src/librustc_trans/builder.rs | 18 ++ src/librustc_trans/intrinsic.rs | 300 ++++++++------------- src/librustc_typeck/check/intrinsic.rs | 7 +- src/rustllvm/RustWrapper.cpp | 2 + .../run-pass/simd-intrinsic-generic-reduction.rs | 104 ++++--- 5 files changed, 202 insertions(+), 229 deletions(-) (limited to 'src/rustllvm/RustWrapper.cpp') diff --git a/src/librustc_trans/builder.rs b/src/librustc_trans/builder.rs index 2c38197d68e..371f53013b9 100644 --- a/src/librustc_trans/builder.rs +++ b/src/librustc_trans/builder.rs @@ -958,6 +958,9 @@ 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 { + // FIXME: add a non-fast math version once + // https://bugs.llvm.org/show_bug.cgi?id=36732 + // is fixed. let instr = llvm::LLVMRustBuildVectorReduceFAdd(self.llbuilder, acc, src); llvm::LLVMRustSetHasUnsafeAlgebra(instr); instr @@ -966,6 +969,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { pub fn vector_reduce_fmul_fast(&self, acc: ValueRef, src: ValueRef) -> ValueRef { self.count_insn("vector.reduce.fmul_fast"); unsafe { + // FIXME: add a non-fast math version once + // https://bugs.llvm.org/show_bug.cgi?id=36732 + // is fixed. let instr = llvm::LLVMRustBuildVectorReduceFMul(self.llbuilder, acc, src); llvm::LLVMRustSetHasUnsafeAlgebra(instr); instr @@ -1001,6 +1007,18 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { llvm::LLVMRustBuildVectorReduceXor(self.llbuilder, src) } } + pub fn vector_reduce_fmin(&self, src: ValueRef) -> ValueRef { + self.count_insn("vector.reduce.fmin"); + unsafe { + llvm::LLVMRustBuildVectorReduceFMin(self.llbuilder, src, true) + } + } + pub fn vector_reduce_fmax(&self, src: ValueRef) -> ValueRef { + self.count_insn("vector.reduce.fmax"); + unsafe { + llvm::LLVMRustBuildVectorReduceFMax(self.llbuilder, src, true) + } + } pub fn vector_reduce_fmin_fast(&self, src: ValueRef) -> ValueRef { self.count_insn("vector.reduce.fmin_fast"); unsafe { diff --git a/src/librustc_trans/intrinsic.rs b/src/librustc_trans/intrinsic.rs index 011273f02e1..8b62a1be80c 100644 --- a/src/librustc_trans/intrinsic.rs +++ b/src/librustc_trans/intrinsic.rs @@ -1150,210 +1150,134 @@ 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) + macro_rules! arith_red { + ($name:tt : $integer_reduce:ident, $float_reduce:ident, $ordered:expr) => { + if name == $name { + 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(_) | ty::TyUint(_) => { + let r = bx.$integer_reduce(args[0].immediate()); + if $ordered { + // if overflow occurs, the result is the + // mathematical result modulo 2^n: + if name.contains("mul") { + Ok(bx.mul(args[1].immediate(), r)) + } else { + Ok(bx.add(args[1].immediate(), r)) + } + } else { + Ok(bx.$integer_reduce(args[0].immediate())) + } + }, + ty::TyFloat(f) => { + // ordered arithmetic reductions take an accumulator + let acc = if $ordered { + args[1].immediate() + } else { + // unordered arithmetic reductions do not: + 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 `{}`", + $name, in_ty, in_elem, v, ret_ty + ) + } + } + + }; + Ok(bx.$float_reduce(acc, args[0].immediate())) } - }; - Ok(bx.vector_reduce_fadd_fast(acc, args[0].immediate())) + _ => { + return_error!( + "unsupported {} from `{}` with element `{}` to `{}`", + $name, in_ty, in_elem, ret_ty + ) + }, + } } - _ => { - 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) + arith_red!("simd_reduce_add_ordered": vector_reduce_add, vector_reduce_fadd_fast, true); + arith_red!("simd_reduce_mul_ordered": vector_reduce_mul, vector_reduce_fmul_fast, true); + arith_red!("simd_reduce_add_unordered": vector_reduce_add, vector_reduce_fadd_fast, false); + arith_red!("simd_reduce_mul_unordered": vector_reduce_mul, vector_reduce_fmul_fast, false); + + macro_rules! minmax_red { + ($name:tt: $int_red:ident, $float_red:ident) => { + if name == $name { + 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.$int_red(args[0].immediate(), true)) + }, + ty::TyUint(_u) => { + Ok(bx.$int_red(args[0].immediate(), false)) + }, + ty::TyFloat(_f) => { + Ok(bx.$float_red(args[0].immediate())) } - }; - Ok(bx.vector_reduce_fmul_fast(acc, args[0].immediate())) + _ => { + return_error!("unsupported {} from `{}` with element `{}` to `{}`", + $name, in_ty, in_elem, ret_ty) + }, + } } - _ => { - 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) - }, - } - } + minmax_red!("simd_reduce_min": vector_reduce_min, vector_reduce_fmin); + minmax_red!("simd_reduce_max": vector_reduce_max, vector_reduce_fmax); - 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) - }, - } - } + minmax_red!("simd_reduce_min_nanless": vector_reduce_min, vector_reduce_fmin_fast); + minmax_red!("simd_reduce_max_nanless": vector_reduce_max, vector_reduce_fmax_fast); - 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) - }, + macro_rules! bitwise_red { + ($name:tt : $red:ident, $boolean:expr) => { + if name == $name { + let input = if !$boolean { + require!(ret_ty == in_elem, + "expected return type `{}` (element of input `{}`), found `{}`", + in_elem, in_ty, ret_ty); + args[0].immediate() + } else { + // boolean reductions operate on vectors of i1s: + let i1 = Type::i1(bx.cx); + let i1xn = Type::vector(&i1, in_len as u64); + bx.trunc(args[0].immediate(), i1xn) + }; + return match in_elem.sty { + ty::TyInt(_) | ty::TyUint(_) => { + let r = bx.$red(input); + Ok( + if !$boolean { + r + } else { + bx.zext(r, Type::bool(bx.cx)) + } + ) + }, + _ => { + return_error!("unsupported {} from `{}` with element `{}` to `{}`", + $name, 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))); - } - + bitwise_red!("simd_reduce_and": vector_reduce_and, false); + bitwise_red!("simd_reduce_or": vector_reduce_or, false); + bitwise_red!("simd_reduce_xor": vector_reduce_xor, false); + bitwise_red!("simd_reduce_all": vector_reduce_and, true); + bitwise_red!("simd_reduce_any": vector_reduce_or, true); if name == "simd_cast" { require_simd!(ret_ty, "return"); diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs index f2d01c57f29..b87b8aa0bdb 100644 --- a/src/librustc_typeck/check/intrinsic.rs +++ b/src/librustc_typeck/check/intrinsic.rs @@ -362,9 +362,12 @@ pub fn check_platform_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, "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_add_ordered" | "simd_reduce_mul_ordered" + => (2, vec![param(0), param(1)], param(1)), + "simd_reduce_add_unordered" | "simd_reduce_mul_unordered" | "simd_reduce_and" | "simd_reduce_or" | "simd_reduce_xor" | - "simd_reduce_min" | "simd_reduce_max" + "simd_reduce_min" | "simd_reduce_max" | + "simd_reduce_min_nanless" | "simd_reduce_max_nanless" => (2, vec![param(0)], param(1)), name if name.starts_with("simd_shuffle") => { match name["simd_shuffle".len()..].parse() { diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp index e749549201e..9d5f9042f18 100644 --- a/src/rustllvm/RustWrapper.cpp +++ b/src/rustllvm/RustWrapper.cpp @@ -1397,6 +1397,7 @@ LLVMRustModuleCost(LLVMModuleRef M) { } // Vector reductions: +#if LLVM_VERSION_GE(6, 0) extern "C" LLVMValueRef LLVMRustBuildVectorReduceFAdd(LLVMBuilderRef B, LLVMValueRef Acc, LLVMValueRef Src) { return wrap(unwrap(B)->CreateFAddReduce(unwrap(Acc),unwrap(Src))); @@ -1441,3 +1442,4 @@ extern "C" LLVMValueRef LLVMRustBuildVectorReduceFMax(LLVMBuilderRef B, LLVMValueRef Src, bool NoNaN) { return wrap(unwrap(B)->CreateFPMaxReduce(unwrap(Src), NoNaN)); } +#endif diff --git a/src/test/run-pass/simd-intrinsic-generic-reduction.rs b/src/test/run-pass/simd-intrinsic-generic-reduction.rs index 15b291ae179..6755c92961b 100644 --- a/src/test/run-pass/simd-intrinsic-generic-reduction.rs +++ b/src/test/run-pass/simd-intrinsic-generic-reduction.rs @@ -39,10 +39,14 @@ struct b8x16( ); extern "platform-intrinsic" { - fn simd_reduce_add(x: T) -> U; - fn simd_reduce_mul(x: T) -> U; + fn simd_reduce_add_unordered(x: T) -> U; + fn simd_reduce_mul_unordered(x: T) -> U; + fn simd_reduce_add_ordered(x: T, acc: U) -> U; + fn simd_reduce_mul_ordered(x: T, acc: U) -> U; fn simd_reduce_min(x: T) -> U; fn simd_reduce_max(x: T) -> U; + fn simd_reduce_min_nanless(x: T) -> U; + fn simd_reduce_max_nanless(x: T) -> U; fn simd_reduce_and(x: T) -> U; fn simd_reduce_or(x: T) -> U; fn simd_reduce_xor(x: T) -> U; @@ -53,91 +57,113 @@ extern "platform-intrinsic" { fn main() { unsafe { let x = i32x4(1, -2, 3, 4); - let r: i32 = simd_reduce_add(x); - assert!(r == 6_i32); - let r: i32 = simd_reduce_mul(x); - assert!(r == -24_i32); + let r: i32 = simd_reduce_add_unordered(x); + assert_eq!(r, 6_i32); + let r: i32 = simd_reduce_mul_unordered(x); + assert_eq!(r, -24_i32); + let r: i32 = simd_reduce_add_ordered(x, -1); + assert_eq!(r, 5_i32); + let r: i32 = simd_reduce_mul_ordered(x, -1); + assert_eq!(r, 24_i32); + let r: i32 = simd_reduce_min(x); - assert!(r == -21_i32); + assert_eq!(r, -2_i32); let r: i32 = simd_reduce_max(x); - assert!(r == 4_i32); + assert_eq!(r, 4_i32); let x = i32x4(-1, -1, -1, -1); let r: i32 = simd_reduce_and(x); - assert!(r == -1_i32); + assert_eq!(r, -1_i32); let r: i32 = simd_reduce_or(x); - assert!(r == -1_i32); + assert_eq!(r, -1_i32); let r: i32 = simd_reduce_xor(x); - assert!(r == 0_i32); + assert_eq!(r, 0_i32); let x = i32x4(-1, -1, 0, -1); let r: i32 = simd_reduce_and(x); - assert!(r == 0_i32); + assert_eq!(r, 0_i32); let r: i32 = simd_reduce_or(x); - assert!(r == -1_i32); + assert_eq!(r, -1_i32); let r: i32 = simd_reduce_xor(x); - assert!(r == -1_i32); + assert_eq!(r, -1_i32); } unsafe { let x = u32x4(1, 2, 3, 4); - let r: u32 = simd_reduce_add(x); - assert!(r == 10_u32); - let r: u32 = simd_reduce_mul(x); - assert!(r == 24_u32); + let r: u32 = simd_reduce_add_unordered(x); + assert_eq!(r, 10_u32); + let r: u32 = simd_reduce_mul_unordered(x); + assert_eq!(r, 24_u32); + let r: u32 = simd_reduce_add_ordered(x, 1); + assert_eq!(r, 11_u32); + let r: u32 = simd_reduce_mul_ordered(x, 2); + assert_eq!(r, 48_u32); + let r: u32 = simd_reduce_min(x); - assert!(r == 1_u32); + assert_eq!(r, 1_u32); let r: u32 = simd_reduce_max(x); - assert!(r == 4_u32); + assert_eq!(r, 4_u32); let t = u32::max_value(); let x = u32x4(t, t, t, t); let r: u32 = simd_reduce_and(x); - assert!(r == t); + assert_eq!(r, t); let r: u32 = simd_reduce_or(x); - assert!(r == t); + assert_eq!(r, t); let r: u32 = simd_reduce_xor(x); - assert!(r == 0_u32); + assert_eq!(r, 0_u32); let x = u32x4(t, t, 0, t); let r: u32 = simd_reduce_and(x); - assert!(r == 0_u32); + assert_eq!(r, 0_u32); let r: u32 = simd_reduce_or(x); - assert!(r == t); + assert_eq!(r, t); let r: u32 = simd_reduce_xor(x); - assert!(r == t); + assert_eq!(r, t); } unsafe { let x = f32x4(1., -2., 3., 4.); - let r: f32 = simd_reduce_add(x); - assert!(r == 6_f32); - let r: f32 = simd_reduce_mul(x); - assert!(r == -24_f32); + let r: f32 = simd_reduce_add_unordered(x); + assert_eq!(r, 6_f32); + let r: f32 = simd_reduce_mul_unordered(x); + assert_eq!(r, -24_f32); + // FIXME: only works correctly for accumulator, 0: + // https://bugs.llvm.org/show_bug.cgi?id=36734 + let r: f32 = simd_reduce_add_ordered(x, 0.); + assert_eq!(r, 6_f32); + // FIXME: only works correctly for accumulator, 1: + // https://bugs.llvm.org/show_bug.cgi?id=36734 + let r: f32 = simd_reduce_mul_ordered(x, 1.); + assert_eq!(r, -24_f32); + let r: f32 = simd_reduce_min(x); - assert!(r == -2_f32); + assert_eq!(r, -2_f32); let r: f32 = simd_reduce_max(x); - assert!(r == 4_f32); + assert_eq!(r, 4_f32); + let r: f32 = simd_reduce_min_nanless(x); + assert_eq!(r, -2_f32); + let r: f32 = simd_reduce_max_nanless(x); + assert_eq!(r, 4_f32); } unsafe { let x = b8x4(!0, !0, !0, !0); let r: bool = simd_reduce_all(x); - //let r: bool = foobar(x); - assert!(r); + assert_eq!(r, true); let r: bool = simd_reduce_any(x); - assert!(r); + assert_eq!(r, true); let x = b8x4(!0, !0, 0, !0); let r: bool = simd_reduce_all(x); - assert!(!r); + assert_eq!(r, false); let r: bool = simd_reduce_any(x); - assert!(r); + assert_eq!(r, true); let x = b8x4(0, 0, 0, 0); let r: bool = simd_reduce_all(x); - assert!(!r); + assert_eq!(r, false); let r: bool = simd_reduce_any(x); - assert!(!r); + assert_eq!(r, false); } } -- cgit 1.4.1-3-g733a5 From c990fa0d880586d85e191b0691a415f9180f4e61 Mon Sep 17 00:00:00 2001 From: gnzlbg Date: Wed, 14 Mar 2018 22:12:38 +0100 Subject: add dummy symbols for LLVM<6 --- src/rustllvm/RustWrapper.cpp | 47 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) (limited to 'src/rustllvm/RustWrapper.cpp') diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp index 9d5f9042f18..c647218c1ac 100644 --- a/src/rustllvm/RustWrapper.cpp +++ b/src/rustllvm/RustWrapper.cpp @@ -1442,4 +1442,51 @@ extern "C" LLVMValueRef LLVMRustBuildVectorReduceFMax(LLVMBuilderRef B, LLVMValueRef Src, bool NoNaN) { return wrap(unwrap(B)->CreateFPMaxReduce(unwrap(Src), NoNaN)); } + +#else + +extern "C" LLVMValueRef +LLVMRustBuildVectorReduceFAdd(LLVMBuilderRef, LLVMValueRef, LLVMValueRef Src) { + return Src; +} +extern "C" LLVMValueRef +LLVMRustBuildVectorReduceFMul(LLVMBuilderRef, LLVMValueRef, LLVMValueRef Src) { + return Src; +} +extern "C" LLVMValueRef +LLVMRustBuildVectorReduceAdd(LLVMBuilderRef, LLVMValueRef Src) { + return Src; +} +extern "C" LLVMValueRef +LLVMRustBuildVectorReduceMul(LLVMBuilderRef, LLVMValueRef Src) { + return Src; +} +extern "C" LLVMValueRef +LLVMRustBuildVectorReduceAnd(LLVMBuilderRef, LLVMValueRef Src) { + return Src; +} +extern "C" LLVMValueRef +LLVMRustBuildVectorReduceOr(LLVMBuilderRef, LLVMValueRef Src) { + return Src; +} +extern "C" LLVMValueRef +LLVMRustBuildVectorReduceXor(LLVMBuilderRef, LLVMValueRef Src) { + return Src; +} +extern "C" LLVMValueRef +LLVMRustBuildVectorReduceMin(LLVMBuilderRef, LLVMValueRef Src, bool) { + return Src; +} +extern "C" LLVMValueRef +LLVMRustBuildVectorReduceMax(LLVMBuilderRef, LLVMValueRef Src, bool) { + return Src; +} +extern "C" LLVMValueRef +LLVMRustBuildVectorReduceFMin(LLVMBuilderRef, LLVMValueRef Src, bool) { + return Src; +} +extern "C" LLVMValueRef +LLVMRustBuildVectorReduceFMax(LLVMBuilderRef, LLVMValueRef Src, bool) { + return Src; +} #endif -- cgit 1.4.1-3-g733a5 From 3125a307596db12d8b014da330373446dda5d7ca Mon Sep 17 00:00:00 2001 From: gnzlbg Date: Thu, 15 Mar 2018 10:08:22 +0100 Subject: error on vector reduction usage if LLVM version is < 5.0 --- src/rustllvm/RustWrapper.cpp | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) (limited to 'src/rustllvm/RustWrapper.cpp') diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp index c647218c1ac..cd3ae1e743b 100644 --- a/src/rustllvm/RustWrapper.cpp +++ b/src/rustllvm/RustWrapper.cpp @@ -21,6 +21,8 @@ #if LLVM_VERSION_GE(5, 0) #include "llvm/ADT/Optional.h" +#else +#include #endif //===----------------------------------------------------------------------=== @@ -1397,7 +1399,7 @@ LLVMRustModuleCost(LLVMModuleRef M) { } // Vector reductions: -#if LLVM_VERSION_GE(6, 0) +#if LLVM_VERSION_GE(5, 0) extern "C" LLVMValueRef LLVMRustBuildVectorReduceFAdd(LLVMBuilderRef B, LLVMValueRef Acc, LLVMValueRef Src) { return wrap(unwrap(B)->CreateFAddReduce(unwrap(Acc),unwrap(Src))); @@ -1445,48 +1447,65 @@ LLVMRustBuildVectorReduceFMax(LLVMBuilderRef B, LLVMValueRef Src, bool NoNaN) { #else +void error_and_exit(const char* msg) { + raw_fd_ostream OS(2, false); + OS << ::std::string(msg); + std::exit(EXIT_FAILURE); +} + extern "C" LLVMValueRef LLVMRustBuildVectorReduceFAdd(LLVMBuilderRef, LLVMValueRef, LLVMValueRef Src) { + error_and_exit("LLVMRustBuildVectorReduceFAdd requires LLVM >= 5.0"); return Src; } extern "C" LLVMValueRef LLVMRustBuildVectorReduceFMul(LLVMBuilderRef, LLVMValueRef, LLVMValueRef Src) { + error_and_exit("LLVMRustBuildVectorReduceFMul requires LLVM >= 5.0"); return Src; } extern "C" LLVMValueRef LLVMRustBuildVectorReduceAdd(LLVMBuilderRef, LLVMValueRef Src) { + error_and_exit("LLVMRustBuildVectorReduceAdd requires LLVM >= 5.0"); return Src; } extern "C" LLVMValueRef LLVMRustBuildVectorReduceMul(LLVMBuilderRef, LLVMValueRef Src) { + error_and_exit("LLVMRustBuildVectorReduceMul requires LLVM >= 5.0"); return Src; } extern "C" LLVMValueRef LLVMRustBuildVectorReduceAnd(LLVMBuilderRef, LLVMValueRef Src) { + error_and_exit("LLVMRustBuildVectorReduceAnd requires LLVM >= 5.0"); return Src; } extern "C" LLVMValueRef LLVMRustBuildVectorReduceOr(LLVMBuilderRef, LLVMValueRef Src) { + error_and_exit("LLVMRustBuildVectorReduceOr requires LLVM >= 5.0"); return Src; } extern "C" LLVMValueRef LLVMRustBuildVectorReduceXor(LLVMBuilderRef, LLVMValueRef Src) { + error_and_exit("LLVMRustBuildVectorReduceXor requires LLVM >= 5.0"); return Src; } extern "C" LLVMValueRef LLVMRustBuildVectorReduceMin(LLVMBuilderRef, LLVMValueRef Src, bool) { + error_and_exit("LLVMRustBuildVectorReduceMin requires LLVM >= 5.0"); return Src; } extern "C" LLVMValueRef LLVMRustBuildVectorReduceMax(LLVMBuilderRef, LLVMValueRef Src, bool) { + error_and_exit("LLVMRustBuildVectorReduceMax requires LLVM >= 5.0"); return Src; } extern "C" LLVMValueRef LLVMRustBuildVectorReduceFMin(LLVMBuilderRef, LLVMValueRef Src, bool) { + error_and_exit("LLVMRustBuildVectorReduceFMin requires LLVM >= 5.0"); return Src; } extern "C" LLVMValueRef LLVMRustBuildVectorReduceFMax(LLVMBuilderRef, LLVMValueRef Src, bool) { + error_and_exit("LLVMRustBuildVectorReduceFMax requires LLVM >= 5.0"); return Src; } #endif -- cgit 1.4.1-3-g733a5 From 19b81f61142fe69edb48d08e9bbfa96d389e8ffd Mon Sep 17 00:00:00 2001 From: gnzlbg Date: Thu, 15 Mar 2018 16:51:58 +0100 Subject: error via bug! instead of stderr+terminate --- src/librustc_trans/builder.rs | 66 +++++++++++++++++++++++++++++++++++++------ src/rustllvm/RustWrapper.cpp | 61 +++++++++++++++------------------------ 2 files changed, 79 insertions(+), 48 deletions(-) (limited to 'src/rustllvm/RustWrapper.cpp') diff --git a/src/librustc_trans/builder.rs b/src/librustc_trans/builder.rs index 371f53013b9..3f5a9a54ff1 100644 --- a/src/librustc_trans/builder.rs +++ b/src/librustc_trans/builder.rs @@ -962,6 +962,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // https://bugs.llvm.org/show_bug.cgi?id=36732 // is fixed. let instr = llvm::LLVMRustBuildVectorReduceFAdd(self.llbuilder, acc, src); + if instr.is_null() { + bug!("LLVMRustBuildVectorReduceFAdd is not available in LLVM version < 5.0"); + } llvm::LLVMRustSetHasUnsafeAlgebra(instr); instr } @@ -973,6 +976,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // https://bugs.llvm.org/show_bug.cgi?id=36732 // is fixed. let instr = llvm::LLVMRustBuildVectorReduceFMul(self.llbuilder, acc, src); + if instr.is_null() { + bug!("LLVMRustBuildVectorReduceFMul is not available in LLVM version < 5.0"); + } llvm::LLVMRustSetHasUnsafeAlgebra(instr); instr } @@ -980,49 +986,80 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { pub fn vector_reduce_add(&self, src: ValueRef) -> ValueRef { self.count_insn("vector.reduce.add"); unsafe { - llvm::LLVMRustBuildVectorReduceAdd(self.llbuilder, src) + let instr = llvm::LLVMRustBuildVectorReduceAdd(self.llbuilder, src); + if instr.is_null() { + bug!("LLVMRustBuildVectorReduceAdd is not available in LLVM version < 5.0"); + } + instr } } pub fn vector_reduce_mul(&self, src: ValueRef) -> ValueRef { self.count_insn("vector.reduce.mul"); unsafe { - llvm::LLVMRustBuildVectorReduceMul(self.llbuilder, src) + let instr = llvm::LLVMRustBuildVectorReduceMul(self.llbuilder, src); + if instr.is_null() { + bug!("LLVMRustBuildVectorReduceMul is not available in LLVM version < 5.0"); + } + instr } } pub fn vector_reduce_and(&self, src: ValueRef) -> ValueRef { self.count_insn("vector.reduce.and"); unsafe { - llvm::LLVMRustBuildVectorReduceAnd(self.llbuilder, src) + let instr = llvm::LLVMRustBuildVectorReduceAnd(self.llbuilder, src); + if instr.is_null() { + bug!("LLVMRustBuildVectorReduceAnd is not available in LLVM version < 5.0"); + } + instr } } pub fn vector_reduce_or(&self, src: ValueRef) -> ValueRef { self.count_insn("vector.reduce.or"); unsafe { - llvm::LLVMRustBuildVectorReduceOr(self.llbuilder, src) + let instr = llvm::LLVMRustBuildVectorReduceOr(self.llbuilder, src); + if instr.is_null() { + bug!("LLVMRustBuildVectorReduceOr is not available in LLVM version < 5.0"); + } + instr } } pub fn vector_reduce_xor(&self, src: ValueRef) -> ValueRef { self.count_insn("vector.reduce.xor"); unsafe { - llvm::LLVMRustBuildVectorReduceXor(self.llbuilder, src) + let instr = llvm::LLVMRustBuildVectorReduceXor(self.llbuilder, src); + if instr.is_null() { + bug!("LLVMRustBuildVectorReduceXor is not available in LLVM version < 5.0"); + } + instr } } pub fn vector_reduce_fmin(&self, src: ValueRef) -> ValueRef { self.count_insn("vector.reduce.fmin"); unsafe { - llvm::LLVMRustBuildVectorReduceFMin(self.llbuilder, src, true) + let instr = llvm::LLVMRustBuildVectorReduceFMin(self.llbuilder, src, true); + if instr.is_null() { + bug!("LLVMRustBuildVectorReduceFMin is not available in LLVM version < 5.0"); + } + instr } } pub fn vector_reduce_fmax(&self, src: ValueRef) -> ValueRef { self.count_insn("vector.reduce.fmax"); unsafe { - llvm::LLVMRustBuildVectorReduceFMax(self.llbuilder, src, true) + let instr = llvm::LLVMRustBuildVectorReduceFMax(self.llbuilder, src, true); + if instr.is_null() { + bug!("LLVMRustBuildVectorReduceFMax is not available in LLVM version < 5.0"); + } + instr } } 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); + if instr.is_null() { + bug!("LLVMRustBuildVectorReduceFMin is not available in LLVM version < 5.0"); + } llvm::LLVMRustSetHasUnsafeAlgebra(instr); instr } @@ -1031,6 +1068,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { self.count_insn("vector.reduce.fmax_fast"); unsafe { let instr = llvm::LLVMRustBuildVectorReduceFMax(self.llbuilder, src, false); + if instr.is_null() { + bug!("LLVMRustBuildVectorReduceFMax is not available in LLVM version < 5.0"); + } llvm::LLVMRustSetHasUnsafeAlgebra(instr); instr } @@ -1038,13 +1078,21 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { 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) + let instr = llvm::LLVMRustBuildVectorReduceMin(self.llbuilder, src, is_signed); + if instr.is_null() { + bug!("LLVMRustBuildVectorReduceMin is not available in LLVM version < 5.0"); + } + instr } } 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) + let instr = llvm::LLVMRustBuildVectorReduceMax(self.llbuilder, src, is_signed); + if instr.is_null() { + bug!("LLVMRustBuildVectorReduceMax is not available in LLVM version < 5.0"); + } + instr } } diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp index cd3ae1e743b..a5644d6f9e2 100644 --- a/src/rustllvm/RustWrapper.cpp +++ b/src/rustllvm/RustWrapper.cpp @@ -1447,65 +1447,48 @@ LLVMRustBuildVectorReduceFMax(LLVMBuilderRef B, LLVMValueRef Src, bool NoNaN) { #else -void error_and_exit(const char* msg) { - raw_fd_ostream OS(2, false); - OS << ::std::string(msg); - std::exit(EXIT_FAILURE); -} - extern "C" LLVMValueRef -LLVMRustBuildVectorReduceFAdd(LLVMBuilderRef, LLVMValueRef, LLVMValueRef Src) { - error_and_exit("LLVMRustBuildVectorReduceFAdd requires LLVM >= 5.0"); - return Src; +LLVMRustBuildVectorReduceFAdd(LLVMBuilderRef, LLVMValueRef, LLVMValueRef) { + return nullptr; } extern "C" LLVMValueRef -LLVMRustBuildVectorReduceFMul(LLVMBuilderRef, LLVMValueRef, LLVMValueRef Src) { - error_and_exit("LLVMRustBuildVectorReduceFMul requires LLVM >= 5.0"); - return Src; +LLVMRustBuildVectorReduceFMul(LLVMBuilderRef, LLVMValueRef, LLVMValueRef) { + return nullptr; } extern "C" LLVMValueRef -LLVMRustBuildVectorReduceAdd(LLVMBuilderRef, LLVMValueRef Src) { - error_and_exit("LLVMRustBuildVectorReduceAdd requires LLVM >= 5.0"); - return Src; +LLVMRustBuildVectorReduceAdd(LLVMBuilderRef, LLVMValueRef) { + return nullptr; } extern "C" LLVMValueRef -LLVMRustBuildVectorReduceMul(LLVMBuilderRef, LLVMValueRef Src) { - error_and_exit("LLVMRustBuildVectorReduceMul requires LLVM >= 5.0"); - return Src; +LLVMRustBuildVectorReduceMul(LLVMBuilderRef, LLVMValueRef) { + return nullptr; } extern "C" LLVMValueRef -LLVMRustBuildVectorReduceAnd(LLVMBuilderRef, LLVMValueRef Src) { - error_and_exit("LLVMRustBuildVectorReduceAnd requires LLVM >= 5.0"); - return Src; +LLVMRustBuildVectorReduceAnd(LLVMBuilderRef, LLVMValueRef) { + return nullptr; } extern "C" LLVMValueRef -LLVMRustBuildVectorReduceOr(LLVMBuilderRef, LLVMValueRef Src) { - error_and_exit("LLVMRustBuildVectorReduceOr requires LLVM >= 5.0"); - return Src; +LLVMRustBuildVectorReduceOr(LLVMBuilderRef, LLVMValueRef) { + return nullptr; } extern "C" LLVMValueRef -LLVMRustBuildVectorReduceXor(LLVMBuilderRef, LLVMValueRef Src) { - error_and_exit("LLVMRustBuildVectorReduceXor requires LLVM >= 5.0"); - return Src; +LLVMRustBuildVectorReduceXor(LLVMBuilderRef, LLVMValueRef) { + return nullptr; } extern "C" LLVMValueRef -LLVMRustBuildVectorReduceMin(LLVMBuilderRef, LLVMValueRef Src, bool) { - error_and_exit("LLVMRustBuildVectorReduceMin requires LLVM >= 5.0"); - return Src; +LLVMRustBuildVectorReduceMin(LLVMBuilderRef, LLVMValueRef, bool) { + return nullptr; } extern "C" LLVMValueRef -LLVMRustBuildVectorReduceMax(LLVMBuilderRef, LLVMValueRef Src, bool) { - error_and_exit("LLVMRustBuildVectorReduceMax requires LLVM >= 5.0"); - return Src; +LLVMRustBuildVectorReduceMax(LLVMBuilderRef, LLVMValueRef, bool) { + return nullptr; } extern "C" LLVMValueRef -LLVMRustBuildVectorReduceFMin(LLVMBuilderRef, LLVMValueRef Src, bool) { - error_and_exit("LLVMRustBuildVectorReduceFMin requires LLVM >= 5.0"); - return Src; +LLVMRustBuildVectorReduceFMin(LLVMBuilderRef, LLVMValueRef, bool) { + return nullptr; } extern "C" LLVMValueRef -LLVMRustBuildVectorReduceFMax(LLVMBuilderRef, LLVMValueRef Src, bool) { - error_and_exit("LLVMRustBuildVectorReduceFMax requires LLVM >= 5.0"); - return Src; +LLVMRustBuildVectorReduceFMax(LLVMBuilderRef, LLVMValueRef, bool) { + return nullptr; } #endif -- cgit 1.4.1-3-g733a5