@@ -14,7 +14,7 @@ use type_::Type;
14
14
use type_of:: LayoutLlvmExt ;
15
15
use rustc:: ty:: { self , Ty } ;
16
16
use rustc:: ty:: layout:: { self , LayoutOf , HasTyCtxt , Primitive } ;
17
- use rustc_codegen_ssa:: common:: TypeKind ;
17
+ use rustc_codegen_ssa:: common:: { IntPredicate , TypeKind } ;
18
18
use rustc:: hir;
19
19
use syntax:: ast:: { self , FloatTy } ;
20
20
use syntax:: symbol:: Symbol ;
@@ -28,7 +28,7 @@ use rustc::session::Session;
28
28
use syntax_pos:: Span ;
29
29
30
30
use std:: cmp:: Ordering ;
31
- use std:: iter;
31
+ use std:: { iter, i128 , u128 } ;
32
32
33
33
fn get_simple_intrinsic ( cx : & CodegenCx < ' ll , ' _ > , name : & str ) -> Option < & ' ll Value > {
34
34
let llvm_name = match name {
@@ -342,7 +342,7 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> {
342
342
"bitreverse" | "add_with_overflow" | "sub_with_overflow" |
343
343
"mul_with_overflow" | "overflowing_add" | "overflowing_sub" | "overflowing_mul" |
344
344
"unchecked_div" | "unchecked_rem" | "unchecked_shl" | "unchecked_shr" | "exact_div" |
345
- "rotate_left" | "rotate_right" => {
345
+ "rotate_left" | "rotate_right" | "saturating_add" | "saturating_sub" => {
346
346
let ty = arg_tys[ 0 ] ;
347
347
match int_type_width_signed ( ty, self ) {
348
348
Some ( ( width, signed) ) =>
@@ -468,6 +468,44 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> {
468
468
self . or ( shift1, shift2)
469
469
}
470
470
} ,
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
+ } ,
471
509
_ => bug ! ( ) ,
472
510
} ,
473
511
None => {
0 commit comments