@@ -967,34 +967,55 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
967967 }
968968
969969 fn saturating_add ( & mut self , lhs : RValue < ' gcc > , rhs : RValue < ' gcc > , signed : bool , width : u64 ) -> RValue < ' gcc > {
970- let func = self . current_func . borrow ( ) . expect ( "func" ) ;
971-
970+ let result_type = lhs. get_type ( ) ;
972971 if signed {
973- // Algorithm from: https://stackoverflow.com/a/56531252/389119
974- let after_block = func. new_block ( "after" ) ;
975- let func_name =
976- match width {
977- 8 => "__builtin_add_overflow" ,
978- 16 => "__builtin_add_overflow" ,
979- 32 => "__builtin_sadd_overflow" ,
980- 64 => "__builtin_saddll_overflow" ,
981- 128 => "__builtin_add_overflow" ,
982- _ => unreachable ! ( ) ,
983- } ;
984- let overflow_func = self . context . get_builtin_function ( func_name) ;
985- let result_type = lhs. get_type ( ) ;
972+ // Based on algorithm from: https://stackoverflow.com/a/56531252/389119
973+ let func = self . current_func . borrow ( ) . expect ( "func" ) ;
986974 let res = func. new_local ( None , result_type, "saturating_sum" ) ;
987- let overflow = self . overflow_call ( overflow_func, & [ lhs, rhs, res. get_address ( None ) ] , None ) ;
975+ let supports_native_type = self . is_native_int_type ( result_type) ;
976+ let overflow =
977+ if supports_native_type {
978+ let func_name =
979+ match width {
980+ 8 => "__builtin_add_overflow" ,
981+ 16 => "__builtin_add_overflow" ,
982+ 32 => "__builtin_sadd_overflow" ,
983+ 64 => "__builtin_saddll_overflow" ,
984+ 128 => "__builtin_add_overflow" ,
985+ _ => unreachable ! ( ) ,
986+ } ;
987+ let overflow_func = self . context . get_builtin_function ( func_name) ;
988+ self . overflow_call ( overflow_func, & [ lhs, rhs, res. get_address ( None ) ] , None )
989+ }
990+ else {
991+ let func_name =
992+ match width {
993+ 128 => "__rust_i128_addo" ,
994+ _ => unreachable ! ( ) ,
995+ } ;
996+ let param_a = self . context . new_parameter ( None , result_type, "a" ) ;
997+ let param_b = self . context . new_parameter ( None , result_type, "b" ) ;
998+ let result_field = self . context . new_field ( None , result_type, "result" ) ;
999+ let overflow_field = self . context . new_field ( None , self . bool_type , "overflow" ) ;
1000+ let return_type = self . context . new_struct_type ( None , "result_overflow" , & [ result_field, overflow_field] ) ;
1001+ let func = self . context . new_function ( None , FunctionType :: Extern , return_type. as_type ( ) , & [ param_a, param_b] , func_name, false ) ;
1002+ let result = self . context . new_call ( None , func, & [ lhs, rhs] ) ;
1003+ let overflow = result. access_field ( None , overflow_field) ;
1004+ let int_result = result. access_field ( None , result_field) ;
1005+ self . llbb ( ) . add_assignment ( None , res, int_result) ;
1006+ overflow
1007+ } ;
9881008
9891009 let then_block = func. new_block ( "then" ) ;
1010+ let after_block = func. new_block ( "after" ) ;
9901011
991- let unsigned_type = self . context . new_int_type ( width as i32 / 8 , false ) ;
992- let shifted = self . context . new_cast ( None , lhs , unsigned_type ) >> self . context . new_rvalue_from_int ( unsigned_type , width as i32 - 1 ) ;
993- let uint_max = self . context . new_unary_op ( None , UnaryOp :: BitwiseNegate , unsigned_type ,
994- self . context . new_rvalue_from_int ( unsigned_type, 0 )
995- ) ;
996- let int_max = uint_max >> self . context . new_rvalue_one ( unsigned_type) ;
997- then_block. add_assignment ( None , res, self . context . new_cast ( None , shifted + int_max, result_type) ) ;
1012+ // Return `result_type`'s maximum or minimum value on overflow
1013+ // NOTE: convert the type to unsigned to have an unsigned shift.
1014+ let unsigned_type = result_type . to_unsigned ( & self . cx ) ;
1015+ let shifted = self . gcc_lshr ( self . gcc_int_cast ( lhs , unsigned_type) , self . gcc_int ( unsigned_type , width as i64 - 1 ) ) ;
1016+ let uint_max = self . gcc_not ( self . gcc_int ( unsigned_type , 0 ) ) ;
1017+ let int_max = self . gcc_lshr ( uint_max, self . gcc_int ( unsigned_type, 1 ) ) ;
1018+ then_block. add_assignment ( None , res, self . gcc_int_cast ( self . gcc_add ( shifted , int_max) , result_type) ) ;
9981019 then_block. end_with_jump ( None , after_block) ;
9991020
10001021 self . llbb ( ) . end_with_conditional ( None , overflow, then_block, after_block) ;
@@ -1007,19 +1028,18 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
10071028 }
10081029 else {
10091030 // Algorithm from: http://locklessinc.com/articles/sat_arithmetic/
1010- let res = lhs + rhs;
1011- let res_type = res. get_type ( ) ;
1012- let cond = self . context . new_comparison ( None , ComparisonOp :: LessThan , res, lhs) ;
1013- let value = self . context . new_unary_op ( None , UnaryOp :: Minus , res_type, self . context . new_cast ( None , cond, res_type) ) ;
1014- res | value
1031+ let res = self . gcc_add ( lhs, rhs) ;
1032+ let cond = self . gcc_icmp ( IntPredicate :: IntULT , res, lhs) ;
1033+ let value = self . gcc_neg ( self . gcc_int_cast ( cond, result_type) ) ;
1034+ self . gcc_or ( res, value)
10151035 }
10161036 }
10171037
10181038 // Algorithm from: https://locklessinc.com/articles/sat_arithmetic/
10191039 fn saturating_sub ( & mut self , lhs : RValue < ' gcc > , rhs : RValue < ' gcc > , signed : bool , width : u64 ) -> RValue < ' gcc > {
1040+ let result_type = lhs. get_type ( ) ;
10201041 if signed {
1021- // Also based on algorithm from: https://stackoverflow.com/a/56531252/389119
1022- let result_type = lhs. get_type ( ) ;
1042+ // Based on algorithm from: https://stackoverflow.com/a/56531252/389119
10231043 let func = self . current_func . borrow ( ) . expect ( "func" ) ;
10241044 let res = func. new_local ( None , result_type, "saturating_diff" ) ;
10251045 let supports_native_type = self . is_native_int_type ( result_type) ;
@@ -1059,6 +1079,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
10591079 let then_block = func. new_block ( "then" ) ;
10601080 let after_block = func. new_block ( "after" ) ;
10611081
1082+ // Return `result_type`'s maximum or minimum value on overflow
10621083 // NOTE: convert the type to unsigned to have an unsigned shift.
10631084 let unsigned_type = result_type. to_unsigned ( & self . cx ) ;
10641085 let shifted = self . gcc_lshr ( self . gcc_int_cast ( lhs, unsigned_type) , self . gcc_int ( unsigned_type, width as i64 - 1 ) ) ;
@@ -1076,11 +1097,10 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
10761097 res. to_rvalue ( )
10771098 }
10781099 else {
1079- let res = lhs - rhs;
1080- let comparison = self . context . new_comparison ( None , ComparisonOp :: LessThanEquals , res, lhs) ;
1081- let comparison = self . context . new_cast ( None , comparison, lhs. get_type ( ) ) ;
1082- let unary_op = self . context . new_unary_op ( None , UnaryOp :: Minus , comparison. get_type ( ) , comparison) ;
1083- self . and ( res, unary_op)
1100+ let res = self . gcc_sub ( lhs, rhs) ;
1101+ let comparison = self . gcc_icmp ( IntPredicate :: IntULE , res, lhs) ;
1102+ let value = self . gcc_neg ( self . gcc_int_cast ( comparison, result_type) ) ;
1103+ self . gcc_and ( res, value)
10841104 }
10851105 }
10861106}
0 commit comments