diff options
Diffstat (limited to 'src/librustc_codegen_llvm')
| -rw-r--r-- | src/librustc_codegen_llvm/context.rs | 26 | ||||
| -rw-r--r-- | src/librustc_codegen_llvm/intrinsic.rs | 45 |
2 files changed, 63 insertions, 8 deletions
diff --git a/src/librustc_codegen_llvm/context.rs b/src/librustc_codegen_llvm/context.rs index f6795588441..2ed338f491a 100644 --- a/src/librustc_codegen_llvm/context.rs +++ b/src/librustc_codegen_llvm/context.rs @@ -510,14 +510,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 58b466dbe6f..161cd7170c5 100644 --- a/src/librustc_codegen_llvm/intrinsic.rs +++ b/src/librustc_codegen_llvm/intrinsic.rs @@ -1850,7 +1850,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"); } |
