@@ -1211,7 +1211,9 @@ impl Evaluator<'_> {
1211
1211
}
1212
1212
lc = & lc[ ..self . ptr_size ( ) ] ;
1213
1213
rc = & rc[ ..self . ptr_size ( ) ] ;
1214
- ls
1214
+ lc = self . read_memory ( Address :: from_bytes ( lc) ?, ls) ?;
1215
+ rc = self . read_memory ( Address :: from_bytes ( rc) ?, ls) ?;
1216
+ break ' binary_op Owned ( vec ! [ u8 :: from( lc == rc) ] ) ;
1215
1217
} else {
1216
1218
self . size_of_sized ( & ty, locals, "operand of binary op" ) ?
1217
1219
} ;
@@ -1340,18 +1342,8 @@ impl Evaluator<'_> {
1340
1342
}
1341
1343
} else {
1342
1344
let is_signed = matches ! ( ty. as_builtin( ) , Some ( BuiltinType :: Int ( _) ) ) ;
1343
- let l128 = i128:: from_le_bytes ( pad16 ( lc, is_signed) ) ;
1344
- let r128 = i128:: from_le_bytes ( pad16 ( rc, is_signed) ) ;
1345
- let check_overflow = |r : i128 | {
1346
- // FIXME: this is not very correct, and only catches the basic cases.
1347
- let r = r. to_le_bytes ( ) ;
1348
- for & k in & r[ lc. len ( ) ..] {
1349
- if k != 0 && ( k != 255 || !is_signed) {
1350
- return Err ( MirEvalError :: Panic ( format ! ( "Overflow in {op:?}" ) ) ) ;
1351
- }
1352
- }
1353
- Ok ( Owned ( r[ 0 ..lc. len ( ) ] . into ( ) ) )
1354
- } ;
1345
+ let l128 = IntValue :: from_bytes ( lc, is_signed) ;
1346
+ let r128 = IntValue :: from_bytes ( rc, is_signed) ;
1355
1347
match op {
1356
1348
BinOp :: Ge | BinOp :: Gt | BinOp :: Le | BinOp :: Lt | BinOp :: Eq | BinOp :: Ne => {
1357
1349
let r = op. run_compare ( l128, r128) as u8 ;
@@ -1366,25 +1358,31 @@ impl Evaluator<'_> {
1366
1358
| BinOp :: Rem
1367
1359
| BinOp :: Sub => {
1368
1360
let r = match op {
1369
- BinOp :: Add => l128. overflowing_add ( r128) . 0 ,
1370
- BinOp :: Mul => l128. overflowing_mul ( r128) . 0 ,
1361
+ BinOp :: Add => l128. checked_add ( r128) . ok_or_else ( || {
1362
+ MirEvalError :: Panic ( format ! ( "Overflow in {op:?}" ) )
1363
+ } ) ?,
1364
+ BinOp :: Mul => l128. checked_mul ( r128) . ok_or_else ( || {
1365
+ MirEvalError :: Panic ( format ! ( "Overflow in {op:?}" ) )
1366
+ } ) ?,
1371
1367
BinOp :: Div => l128. checked_div ( r128) . ok_or_else ( || {
1372
1368
MirEvalError :: Panic ( format ! ( "Overflow in {op:?}" ) )
1373
1369
} ) ?,
1374
1370
BinOp :: Rem => l128. checked_rem ( r128) . ok_or_else ( || {
1375
1371
MirEvalError :: Panic ( format ! ( "Overflow in {op:?}" ) )
1376
1372
} ) ?,
1377
- BinOp :: Sub => l128. overflowing_sub ( r128) . 0 ,
1373
+ BinOp :: Sub => l128. checked_sub ( r128) . ok_or_else ( || {
1374
+ MirEvalError :: Panic ( format ! ( "Overflow in {op:?}" ) )
1375
+ } ) ?,
1378
1376
BinOp :: BitAnd => l128 & r128,
1379
1377
BinOp :: BitOr => l128 | r128,
1380
1378
BinOp :: BitXor => l128 ^ r128,
1381
1379
_ => unreachable ! ( ) ,
1382
1380
} ;
1383
- check_overflow ( r ) ?
1381
+ Owned ( r . to_bytes ( ) )
1384
1382
}
1385
1383
BinOp :: Shl | BinOp :: Shr => {
1386
1384
let r = ' b: {
1387
- if let Ok ( shift_amount) = u32 :: try_from ( r128) {
1385
+ if let Some ( shift_amount) = r128. as_u32 ( ) {
1388
1386
let r = match op {
1389
1387
BinOp :: Shl => l128. checked_shl ( shift_amount) ,
1390
1388
BinOp :: Shr => l128. checked_shr ( shift_amount) ,
@@ -1401,7 +1399,7 @@ impl Evaluator<'_> {
1401
1399
} ;
1402
1400
return Err ( MirEvalError :: Panic ( format ! ( "Overflow in {op:?}" ) ) ) ;
1403
1401
} ;
1404
- Owned ( r. to_le_bytes ( ) [ ..lc . len ( ) ] . to_vec ( ) )
1402
+ Owned ( r. to_bytes ( ) )
1405
1403
}
1406
1404
BinOp :: Offset => not_supported ! ( "offset binop" ) ,
1407
1405
}
@@ -2974,3 +2972,129 @@ pub fn pad16(it: &[u8], is_signed: bool) -> [u8; 16] {
2974
2972
res[ ..it. len ( ) ] . copy_from_slice ( it) ;
2975
2973
res
2976
2974
}
2975
+
2976
+ macro_rules! for_each_int_type {
2977
+ ( $call_macro: path, $args: tt) => {
2978
+ $call_macro! {
2979
+ $args
2980
+ I8
2981
+ U8
2982
+ I16
2983
+ U16
2984
+ I32
2985
+ U32
2986
+ I64
2987
+ U64
2988
+ I128
2989
+ U128
2990
+ }
2991
+ } ;
2992
+ }
2993
+
2994
+ #[ derive( Debug , Clone , Copy , PartialEq , Eq , PartialOrd , Ord ) ]
2995
+ enum IntValue {
2996
+ I8 ( i8 ) ,
2997
+ U8 ( u8 ) ,
2998
+ I16 ( i16 ) ,
2999
+ U16 ( u16 ) ,
3000
+ I32 ( i32 ) ,
3001
+ U32 ( u32 ) ,
3002
+ I64 ( i64 ) ,
3003
+ U64 ( u64 ) ,
3004
+ I128 ( i128 ) ,
3005
+ U128 ( u128 ) ,
3006
+ }
3007
+
3008
+ macro_rules! checked_int_op {
3009
+ ( [ $op: ident ] $( $int_ty: ident ) + ) => {
3010
+ fn $op( self , other: Self ) -> Option <Self > {
3011
+ match ( self , other) {
3012
+ $( ( Self :: $int_ty( a) , Self :: $int_ty( b) ) => a. $op( b) . map( Self :: $int_ty) , ) +
3013
+ _ => panic!( "incompatible integer types" ) ,
3014
+ }
3015
+ }
3016
+ } ;
3017
+ }
3018
+
3019
+ macro_rules! int_bit_shifts {
3020
+ ( [ $op: ident ] $( $int_ty: ident ) + ) => {
3021
+ fn $op( self , amount: u32 ) -> Option <Self > {
3022
+ match self {
3023
+ $( Self :: $int_ty( this) => this. $op( amount) . map( Self :: $int_ty) , ) +
3024
+ }
3025
+ }
3026
+ } ;
3027
+ }
3028
+
3029
+ macro_rules! unchecked_int_op {
3030
+ ( [ $name: ident, $op: tt ] $( $int_ty: ident ) + ) => {
3031
+ fn $name( self , other: Self ) -> Self {
3032
+ match ( self , other) {
3033
+ $( ( Self :: $int_ty( a) , Self :: $int_ty( b) ) => Self :: $int_ty( a $op b) , ) +
3034
+ _ => panic!( "incompatible integer types" ) ,
3035
+ }
3036
+ }
3037
+ } ;
3038
+ }
3039
+
3040
+ impl IntValue {
3041
+ fn from_bytes ( bytes : & [ u8 ] , is_signed : bool ) -> Self {
3042
+ match ( bytes. len ( ) , is_signed) {
3043
+ ( 1 , false ) => Self :: U8 ( u8:: from_le_bytes ( bytes. try_into ( ) . unwrap ( ) ) ) ,
3044
+ ( 1 , true ) => Self :: I8 ( i8:: from_le_bytes ( bytes. try_into ( ) . unwrap ( ) ) ) ,
3045
+ ( 2 , false ) => Self :: U16 ( u16:: from_le_bytes ( bytes. try_into ( ) . unwrap ( ) ) ) ,
3046
+ ( 2 , true ) => Self :: I16 ( i16:: from_le_bytes ( bytes. try_into ( ) . unwrap ( ) ) ) ,
3047
+ ( 4 , false ) => Self :: U32 ( u32:: from_le_bytes ( bytes. try_into ( ) . unwrap ( ) ) ) ,
3048
+ ( 4 , true ) => Self :: I32 ( i32:: from_le_bytes ( bytes. try_into ( ) . unwrap ( ) ) ) ,
3049
+ ( 8 , false ) => Self :: U64 ( u64:: from_le_bytes ( bytes. try_into ( ) . unwrap ( ) ) ) ,
3050
+ ( 8 , true ) => Self :: I64 ( i64:: from_le_bytes ( bytes. try_into ( ) . unwrap ( ) ) ) ,
3051
+ ( 16 , false ) => Self :: U128 ( u128:: from_le_bytes ( bytes. try_into ( ) . unwrap ( ) ) ) ,
3052
+ ( 16 , true ) => Self :: I128 ( i128:: from_le_bytes ( bytes. try_into ( ) . unwrap ( ) ) ) ,
3053
+ _ => panic ! ( "invalid integer size" ) ,
3054
+ }
3055
+ }
3056
+
3057
+ fn to_bytes ( self ) -> Vec < u8 > {
3058
+ macro_rules! m {
3059
+ ( [ ] $( $int_ty: ident ) + ) => {
3060
+ match self {
3061
+ $( Self :: $int_ty( v) => v. to_le_bytes( ) . to_vec( ) ) ,+
3062
+ }
3063
+ } ;
3064
+ }
3065
+ for_each_int_type ! { m, [ ] }
3066
+ }
3067
+
3068
+ fn as_u32 ( self ) -> Option < u32 > {
3069
+ macro_rules! m {
3070
+ ( [ ] $( $int_ty: ident ) + ) => {
3071
+ match self {
3072
+ $( Self :: $int_ty( v) => v. try_into( ) . ok( ) ) ,+
3073
+ }
3074
+ } ;
3075
+ }
3076
+ for_each_int_type ! { m, [ ] }
3077
+ }
3078
+
3079
+ for_each_int_type ! ( checked_int_op, [ checked_add] ) ;
3080
+ for_each_int_type ! ( checked_int_op, [ checked_sub] ) ;
3081
+ for_each_int_type ! ( checked_int_op, [ checked_div] ) ;
3082
+ for_each_int_type ! ( checked_int_op, [ checked_rem] ) ;
3083
+ for_each_int_type ! ( checked_int_op, [ checked_mul] ) ;
3084
+
3085
+ for_each_int_type ! ( int_bit_shifts, [ checked_shl] ) ;
3086
+ for_each_int_type ! ( int_bit_shifts, [ checked_shr] ) ;
3087
+ }
3088
+
3089
+ impl std:: ops:: BitAnd for IntValue {
3090
+ type Output = Self ;
3091
+ for_each_int_type ! ( unchecked_int_op, [ bitand, & ] ) ;
3092
+ }
3093
+ impl std:: ops:: BitOr for IntValue {
3094
+ type Output = Self ;
3095
+ for_each_int_type ! ( unchecked_int_op, [ bitor, |] ) ;
3096
+ }
3097
+ impl std:: ops:: BitXor for IntValue {
3098
+ type Output = Self ;
3099
+ for_each_int_type ! ( unchecked_int_op, [ bitxor, ^] ) ;
3100
+ }
0 commit comments