@@ -967,34 +967,55 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
967
967
}
968
968
969
969
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 ( ) ;
972
971
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" ) ;
986
974
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
+ } ;
988
1008
989
1009
let then_block = func. new_block ( "then" ) ;
1010
+ let after_block = func. new_block ( "after" ) ;
990
1011
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) ) ;
998
1019
then_block. end_with_jump ( None , after_block) ;
999
1020
1000
1021
self . llbb ( ) . end_with_conditional ( None , overflow, then_block, after_block) ;
@@ -1007,19 +1028,18 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
1007
1028
}
1008
1029
else {
1009
1030
// 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)
1015
1035
}
1016
1036
}
1017
1037
1018
1038
// Algorithm from: https://locklessinc.com/articles/sat_arithmetic/
1019
1039
fn saturating_sub ( & mut self , lhs : RValue < ' gcc > , rhs : RValue < ' gcc > , signed : bool , width : u64 ) -> RValue < ' gcc > {
1040
+ let result_type = lhs. get_type ( ) ;
1020
1041
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
1023
1043
let func = self . current_func . borrow ( ) . expect ( "func" ) ;
1024
1044
let res = func. new_local ( None , result_type, "saturating_diff" ) ;
1025
1045
let supports_native_type = self . is_native_int_type ( result_type) ;
@@ -1059,6 +1079,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
1059
1079
let then_block = func. new_block ( "then" ) ;
1060
1080
let after_block = func. new_block ( "after" ) ;
1061
1081
1082
+ // Return `result_type`'s maximum or minimum value on overflow
1062
1083
// NOTE: convert the type to unsigned to have an unsigned shift.
1063
1084
let unsigned_type = result_type. to_unsigned ( & self . cx ) ;
1064
1085
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> {
1076
1097
res. to_rvalue ( )
1077
1098
}
1078
1099
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)
1084
1104
}
1085
1105
}
1086
1106
}
0 commit comments