diff options
| author | gnzlbg <gonzalobg88@gmail.com> | 2018-03-15 16:36:02 +0100 |
|---|---|---|
| committer | gnzlbg <gonzalobg88@gmail.com> | 2018-03-15 16:36:02 +0100 |
| commit | 4fe6acf9721b520ddf3c5ee1bc7d300d13545649 (patch) | |
| tree | 9d9bb3712ac0a3fb9c34224b37bcb38f7e5f10ce | |
| parent | 8478fa2007a2d2a9de21d88ebed13f16b6330393 (diff) | |
| download | rust-4fe6acf9721b520ddf3c5ee1bc7d300d13545649.tar.gz rust-4fe6acf9721b520ddf3c5ee1bc7d300d13545649.zip | |
add compile fail tests
| -rw-r--r-- | src/librustc_llvm/ffi.rs | 2 | ||||
| -rw-r--r-- | src/librustc_trans/common.rs | 20 | ||||
| -rw-r--r-- | src/librustc_trans/intrinsic.rs | 28 | ||||
| -rw-r--r-- | src/test/compile-fail/simd-intrinsic-generic-reduction.rs | 76 |
4 files changed, 125 insertions, 1 deletions
diff --git a/src/librustc_llvm/ffi.rs b/src/librustc_llvm/ffi.rs index 00547017349..c0cdd212770 100644 --- a/src/librustc_llvm/ffi.rs +++ b/src/librustc_llvm/ffi.rs @@ -621,6 +621,7 @@ extern "C" { pub fn LLVMConstIntGetSExtValue(ConstantVal: ValueRef) -> c_longlong; pub fn LLVMRustConstInt128Get(ConstantVal: ValueRef, SExt: bool, high: *mut u64, low: *mut u64) -> bool; + pub fn LLVMConstRealGetDouble (ConstantVal: ValueRef, losesInfo: *mut Bool) -> f64; // Operations on composite constants @@ -1607,6 +1608,7 @@ extern "C" { pub fn LLVMRustWriteValueToString(value_ref: ValueRef, s: RustStringRef); pub fn LLVMIsAConstantInt(value_ref: ValueRef) -> ValueRef; + pub fn LLVMIsAConstantFP(value_ref: ValueRef) -> ValueRef; pub fn LLVMRustPassKind(Pass: PassRef) -> PassKind; pub fn LLVMRustFindAndCreatePass(Pass: *const c_char) -> PassRef; diff --git a/src/librustc_trans/common.rs b/src/librustc_trans/common.rs index 7c4e2340d5b..a2c2fad68f6 100644 --- a/src/librustc_trans/common.rs +++ b/src/librustc_trans/common.rs @@ -270,6 +270,19 @@ pub fn const_get_elt(v: ValueRef, idx: u64) -> ValueRef { } } +pub fn const_get_real(v: ValueRef) -> Option<(f64, bool)> { + unsafe { + if is_const_real(v) { + let mut loses_info: llvm::Bool = ::std::mem::uninitialized(); + let r = llvm::LLVMConstRealGetDouble(v, &mut loses_info as *mut llvm::Bool); + let loses_info = if loses_info == 1 { true } else { false }; + Some((r, loses_info)) + } else { + None + } + } +} + pub fn const_to_uint(v: ValueRef) -> u64 { unsafe { llvm::LLVMConstIntGetZExtValue(v) @@ -282,6 +295,13 @@ pub fn is_const_integral(v: ValueRef) -> bool { } } +pub fn is_const_real(v: ValueRef) -> bool { + unsafe { + !llvm::LLVMIsAConstantFP(v).is_null() + } +} + + #[inline] fn hi_lo_to_u128(lo: u64, hi: u64) -> u128 { ((hi as u128) << 64) | (lo as u128) diff --git a/src/librustc_trans/intrinsic.rs b/src/librustc_trans/intrinsic.rs index 72c619a3b0c..f1ecad2067b 100644 --- a/src/librustc_trans/intrinsic.rs +++ b/src/librustc_trans/intrinsic.rs @@ -1174,7 +1174,25 @@ fn generic_simd_intrinsic<'a, 'tcx>( ty::TyFloat(f) => { // ordered arithmetic reductions take an accumulator let acc = if $ordered { - args[1].immediate() + let acc = args[1].immediate(); + // FIXME: https://bugs.llvm.org/show_bug.cgi?id=36734 + // * if the accumulator of the fadd isn't 0, incorrect + // code is generated + // * if the accumulator of the fmul isn't 1, incorrect + // code is generated + match const_get_real(acc) { + None => return_error!("accumulator of {} is not a constant", $name), + Some((v, loses_info)) => { + if $name.contains("mul") && v != 1.0_f64 { + return_error!("accumulator of {} is not 1.0", $name); + } else if $name.contains("add") && v != 0.0_f64 { + return_error!("accumulator of {} is not 0.0", $name); + } else if loses_info { + return_error!("accumulator of {} loses information", $name); + } + } + } + acc } else { // unordered arithmetic reductions do not: match f.bit_width() { @@ -1248,6 +1266,14 @@ unsupported {} from `{}` with element `{}` of size `{}` to `{}`"#, in_elem, in_ty, ret_ty); args[0].immediate() } else { + match in_elem.sty { + ty::TyInt(_) | ty::TyUint(_) => {}, + _ => { + return_error!("unsupported {} from `{}` with element `{}` to `{}`", + $name, in_ty, in_elem, ret_ty) + } + } + // boolean reductions operate on vectors of i1s: let i1 = Type::i1(bx.cx); let i1xn = Type::vector(&i1, in_len as u64); diff --git a/src/test/compile-fail/simd-intrinsic-generic-reduction.rs b/src/test/compile-fail/simd-intrinsic-generic-reduction.rs new file mode 100644 index 00000000000..b4c069eb10f --- /dev/null +++ b/src/test/compile-fail/simd-intrinsic-generic-reduction.rs @@ -0,0 +1,76 @@ +// 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. + +#![feature(repr_simd, platform_intrinsics)] +#![allow(non_camel_case_types)] + +#[repr(simd)] +#[derive(Copy, Clone)] +pub struct f32x4(pub f32, pub f32, pub f32, pub f32); + +#[repr(simd)] +#[derive(Copy, Clone)] +pub struct u32x4(pub u32, pub u32, pub u32, pub u32); + + +extern "platform-intrinsic" { + fn simd_reduce_add_ordered<T, U>(x: T, y: U) -> U; + fn simd_reduce_mul_ordered<T, U>(x: T, y: U) -> U; + fn simd_reduce_and<T, U>(x: T) -> U; + fn simd_reduce_or<T, U>(x: T) -> U; + fn simd_reduce_xor<T, U>(x: T) -> U; + fn simd_reduce_all<T>(x: T) -> bool; + fn simd_reduce_any<T>(x: T) -> bool; +} + +fn main() { + let x = u32x4(0, 0, 0, 0); + let z = f32x4(0.0, 0.0, 0.0, 0.0); + + unsafe { + simd_reduce_add_ordered(z, 0_f32); + simd_reduce_mul_ordered(z, 1_f32); + + simd_reduce_add_ordered(z, 2_f32); + //~^ ERROR accumulator of simd_reduce_add_ordered is not 0.0 + simd_reduce_mul_ordered(z, 3_f32); + //~^ ERROR accumulator of simd_reduce_mul_ordered is not 1.0 + + let _: f32 = simd_reduce_and(x); + //~^ ERROR expected return type `u32` (element of input `u32x4`), found `f32` + let _: f32 = simd_reduce_or(x); + //~^ ERROR expected return type `u32` (element of input `u32x4`), found `f32` + let _: f32 = simd_reduce_xor(x); + //~^ ERROR expected return type `u32` (element of input `u32x4`), found `f32` + + let _: f32 = simd_reduce_and(z); + //~^ ERROR unsupported simd_reduce_and from `f32x4` with element `f32` to `f32` + let _: f32 = simd_reduce_or(z); + //~^ ERROR unsupported simd_reduce_or from `f32x4` with element `f32` to `f32` + let _: f32 = simd_reduce_xor(z); + //~^ ERROR unsupported simd_reduce_xor from `f32x4` with element `f32` to `f32` + + let _: bool = simd_reduce_all(z); + //~^ ERROR unsupported simd_reduce_all from `f32x4` with element `f32` to `bool` + let _: bool = simd_reduce_any(z); + //~^ ERROR unsupported simd_reduce_any from `f32x4` with element `f32` to `bool` + + foo(0_f32); + } +} + +#[inline(never)] +unsafe fn foo(x: f32) { + let z = f32x4(0.0, 0.0, 0.0, 0.0); + simd_reduce_add_ordered(z, x); + //~^ ERROR accumulator of simd_reduce_add_ordered is not a constant + simd_reduce_mul_ordered(z, x); + //~^ ERROR accumulator of simd_reduce_mul_ordered is not a constant +} |
