@@ -14,7 +14,7 @@ use type_::Type;
1414use type_of:: LayoutLlvmExt ;
1515use rustc:: ty:: { self , Ty } ;
1616use rustc:: ty:: layout:: { self , LayoutOf , HasTyCtxt , Primitive } ;
17- use rustc_codegen_ssa:: common:: TypeKind ;
17+ use rustc_codegen_ssa:: common:: { IntPredicate , TypeKind } ;
1818use rustc:: hir;
1919use syntax:: ast:: { self , FloatTy } ;
2020use syntax:: symbol:: Symbol ;
@@ -28,7 +28,7 @@ use rustc::session::Session;
2828use syntax_pos:: Span ;
2929
3030use std:: cmp:: Ordering ;
31- use std:: iter;
31+ use std:: { iter, i128 , u128 } ;
3232
3333fn get_simple_intrinsic ( cx : & CodegenCx < ' ll , ' _ > , name : & str ) -> Option < & ' ll Value > {
3434 let llvm_name = match name {
@@ -342,7 +342,7 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> {
342342 "bitreverse" | "add_with_overflow" | "sub_with_overflow" |
343343 "mul_with_overflow" | "overflowing_add" | "overflowing_sub" | "overflowing_mul" |
344344 "unchecked_div" | "unchecked_rem" | "unchecked_shl" | "unchecked_shr" | "exact_div" |
345- "rotate_left" | "rotate_right" => {
345+ "rotate_left" | "rotate_right" | "saturating_add" | "saturating_sub" => {
346346 let ty = arg_tys[ 0 ] ;
347347 match int_type_width_signed ( ty, self ) {
348348 Some ( ( width, signed) ) =>
@@ -468,6 +468,44 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> {
468468 self . or ( shift1, shift2)
469469 }
470470 } ,
471+ "saturating_add" | "saturating_sub" => {
472+ let is_add = name == "saturating_add" ;
473+ let lhs = args[ 0 ] . immediate ( ) ;
474+ let rhs = args[ 1 ] . immediate ( ) ;
475+ if llvm_util:: get_major_version ( ) >= 8 {
476+ let llvm_name = & format ! ( "llvm.{}{}.sat.i{}" ,
477+ if signed { 's' } else { 'u' } ,
478+ if is_add { "add" } else { "sub" } ,
479+ width) ;
480+ let llfn = self . get_intrinsic ( llvm_name) ;
481+ self . call ( llfn, & [ lhs, rhs] , None )
482+ } else {
483+ let llvm_name = & format ! ( "llvm.{}{}.with.overflow.i{}" ,
484+ if signed { 's' } else { 'u' } ,
485+ if is_add { "add" } else { "sub" } ,
486+ width) ;
487+ let llfn = self . get_intrinsic ( llvm_name) ;
488+ let pair = self . call ( llfn, & [ lhs, rhs] , None ) ;
489+ let val = self . extract_value ( pair, 0 ) ;
490+ let overflow = self . extract_value ( pair, 1 ) ;
491+ let llty = self . type_ix ( width) ;
492+
493+ let limit = if signed {
494+ let limit_lo = self . const_uint_big (
495+ llty, ( i128:: MIN >> ( 128 - width) ) as u128 ) ;
496+ let limit_hi = self . const_uint_big (
497+ llty, ( i128:: MAX >> ( 128 - width) ) as u128 ) ;
498+ let neg = self . icmp (
499+ IntPredicate :: IntSLT , val, self . const_uint ( llty, 0 ) ) ;
500+ self . select ( neg, limit_hi, limit_lo)
501+ } else if is_add {
502+ self . const_uint_big ( llty, u128:: MAX >> ( 128 - width) )
503+ } else {
504+ self . const_uint ( llty, 0 )
505+ } ;
506+ self . select ( overflow, limit, val)
507+ }
508+ } ,
471509 _ => bug ! ( ) ,
472510 } ,
473511 None => {
0 commit comments