about summary refs log tree commit diff
path: root/src/librustc_codegen_llvm
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2019-02-24 04:16:12 +0000
committerbors <bors@rust-lang.org>2019-02-24 04:16:12 +0000
commit7cb3ee453b829a513749eb49e6cbe7fe4da527b1 (patch)
treee1cb90aab0ff7a37bce986740a0bf6fef4981f64 /src/librustc_codegen_llvm
parentf573049729ca7f4a4977e48467156d7fc8b13f62 (diff)
parentf0783d5cb1b46cd29c3271661342532f4925ba04 (diff)
downloadrust-7cb3ee453b829a513749eb49e6cbe7fe4da527b1.tar.gz
rust-7cb3ee453b829a513749eb49e6cbe7fe4da527b1.zip
Auto merge of #58304 - gnzlbg:simd_saturated, r=nagisa
Add generic simd saturated add/sub intrinsics

r? @eddyb
Diffstat (limited to 'src/librustc_codegen_llvm')
-rw-r--r--src/librustc_codegen_llvm/context.rs26
-rw-r--r--src/librustc_codegen_llvm/intrinsic.rs45
2 files changed, 63 insertions, 8 deletions
diff --git a/src/librustc_codegen_llvm/context.rs b/src/librustc_codegen_llvm/context.rs
index d9c4d22b411..edeef23bdca 100644
--- a/src/librustc_codegen_llvm/context.rs
+++ b/src/librustc_codegen_llvm/context.rs
@@ -515,14 +515,24 @@ impl CodegenCx<'b, 'tcx> {
         let t_f32 = self.type_f32();
         let t_f64 = self.type_f64();
 
-        let t_v2f32 = self.type_vector(t_f32, 2);
-        let t_v4f32 = self.type_vector(t_f32, 4);
-        let t_v8f32 = self.type_vector(t_f32, 8);
-        let t_v16f32 = self.type_vector(t_f32, 16);
-
-        let t_v2f64 = self.type_vector(t_f64, 2);
-        let t_v4f64 = self.type_vector(t_f64, 4);
-        let t_v8f64 = self.type_vector(t_f64, 8);
+        macro_rules! vector_types {
+            ($id_out:ident: $elem_ty:ident, $len:expr) => {
+                let $id_out = self.type_vector($elem_ty, $len);
+            };
+            ($($id_out:ident: $elem_ty:ident, $len:expr;)*) => {
+                $(vector_types!($id_out: $elem_ty, $len);)*
+            }
+        }
+        vector_types! {
+            t_v2f32: t_f32, 2;
+            t_v4f32: t_f32, 4;
+            t_v8f32: t_f32, 8;
+            t_v16f32: t_f32, 16;
+
+            t_v2f64: t_f64, 2;
+            t_v4f64: t_f64, 4;
+            t_v8f64: t_f64, 8;
+        }
 
         ifn!("llvm.memset.p0i8.i16", fn(i8p, t_i8, t_i16, t_i32, i1) -> void);
         ifn!("llvm.memset.p0i8.i32", fn(i8p, t_i8, t_i32, t_i32, i1) -> void);
diff --git a/src/librustc_codegen_llvm/intrinsic.rs b/src/librustc_codegen_llvm/intrinsic.rs
index 3785e19af97..d12ee7649bd 100644
--- a/src/librustc_codegen_llvm/intrinsic.rs
+++ b/src/librustc_codegen_llvm/intrinsic.rs
@@ -1848,7 +1848,52 @@ unsupported {} from `{}` with element `{}` of size `{}` to `{}`"#,
         simd_xor: Uint, Int => xor;
         simd_fmax: Float => maxnum;
         simd_fmin: Float => minnum;
+
+    }
+
+    if name == "simd_saturating_add" || name == "simd_saturating_sub" {
+        let lhs = args[0].immediate();
+        let rhs = args[1].immediate();
+        let is_add = name == "simd_saturating_add";
+        let ptr_bits = bx.tcx().data_layout.pointer_size.bits() as _;
+        let (signed, elem_width, elem_ty) = match in_elem.sty {
+            ty::Int(i) =>
+                (
+                    true,
+                    i.bit_width().unwrap_or(ptr_bits),
+                    bx.cx.type_int_from_ty(i)
+                ),
+            ty::Uint(i) =>
+                (
+                    false,
+                    i.bit_width().unwrap_or(ptr_bits),
+                    bx.cx.type_uint_from_ty(i)
+                ),
+            _ => {
+                return_error!(
+                    "expected element type `{}` of vector type `{}` \
+                     to be a signed or unsigned integer type",
+                    arg_tys[0].simd_type(tcx).sty, arg_tys[0]
+                );
+            }
+        };
+        let llvm_intrinsic = &format!(
+            "llvm.{}{}.sat.v{}i{}",
+            if signed { 's' } else { 'u' },
+            if is_add { "add" } else { "sub" },
+            in_len, elem_width
+        );
+        let vec_ty = bx.cx.type_vector(elem_ty, in_len as u64);
+
+        let f = bx.declare_cfn(
+            &llvm_intrinsic,
+            bx.type_func(&[vec_ty, vec_ty], vec_ty)
+        );
+        llvm::SetUnnamedAddr(f, false);
+        let v = bx.call(f, &[lhs, rhs], None);
+        return Ok(v);
     }
+
     span_bug!(span, "unknown SIMD intrinsic");
 }