about summary refs log tree commit diff
diff options
context:
space:
mode:
authorgnzlbg <gonzalobg88@gmail.com>2018-03-15 16:36:02 +0100
committergnzlbg <gonzalobg88@gmail.com>2018-03-15 16:36:02 +0100
commit4fe6acf9721b520ddf3c5ee1bc7d300d13545649 (patch)
tree9d9bb3712ac0a3fb9c34224b37bcb38f7e5f10ce
parent8478fa2007a2d2a9de21d88ebed13f16b6330393 (diff)
downloadrust-4fe6acf9721b520ddf3c5ee1bc7d300d13545649.tar.gz
rust-4fe6acf9721b520ddf3c5ee1bc7d300d13545649.zip
add compile fail tests
-rw-r--r--src/librustc_llvm/ffi.rs2
-rw-r--r--src/librustc_trans/common.rs20
-rw-r--r--src/librustc_trans/intrinsic.rs28
-rw-r--r--src/test/compile-fail/simd-intrinsic-generic-reduction.rs76
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
+}