@@ -274,40 +274,6 @@ impl<'tcx> GotocCtx<'tcx> {
274
274
} } ;
275
275
}
276
276
277
- // Intrinsics which encode a SIMD arithmetic operation with overflow check.
278
- // We expand the overflow check because CBMC overflow operations don't accept array as
279
- // argument.
280
- macro_rules! _codegen_simd_with_overflow_check {
281
- ( $op: ident, $overflow: ident) => { {
282
- let a = fargs. remove( 0 ) ;
283
- let b = fargs. remove( 0 ) ;
284
- let mut check = Expr :: bool_false( ) ;
285
- if let Type :: Vector { size, .. } = a. typ( ) {
286
- let a_size = size;
287
- if let Type :: Vector { size, .. } = b. typ( ) {
288
- let b_size = size;
289
- assert_eq!( a_size, b_size, "Expected same length vectors" , ) ;
290
- for i in 0 ..* a_size {
291
- // create expression
292
- let index = Expr :: int_constant( i, Type :: ssize_t( ) ) ;
293
- let v_a = a. clone( ) . index_array( index. clone( ) ) ;
294
- let v_b = b. clone( ) . index_array( index) ;
295
- check = check. or( v_a. $overflow( v_b) ) ;
296
- }
297
- }
298
- }
299
- let check_stmt = self . codegen_assert(
300
- check. not( ) ,
301
- PropertyClass :: ArithmeticOverflow ,
302
- format!( "attempt to compute {} which would overflow" , intrinsic) . as_str( ) ,
303
- loc,
304
- ) ;
305
- let res = a. $op( b) ;
306
- let expr_place = self . codegen_expr_to_place( p, res) ;
307
- Stmt :: block( vec![ expr_place, check_stmt] , loc)
308
- } } ;
309
- }
310
-
311
277
// Intrinsics which encode a simple wrapping arithmetic operation
312
278
macro_rules! codegen_wrapping_op {
313
279
( $f: ident) => { { codegen_intrinsic_binop!( $f) } } ;
@@ -606,9 +572,14 @@ impl<'tcx> GotocCtx<'tcx> {
606
572
"saturating_sub" => codegen_intrinsic_binop_with_mm ! ( saturating_sub) ,
607
573
"sinf32" => codegen_simple_intrinsic ! ( Sinf ) ,
608
574
"sinf64" => codegen_simple_intrinsic ! ( Sin ) ,
609
- "simd_add" => {
610
- unstable_codegen ! ( codegen_simd_with_overflow_check!( plus, add_overflow_p) )
611
- }
575
+ "simd_add" => self . codegen_simd_op_with_overflow (
576
+ Expr :: plus,
577
+ Expr :: add_overflow_p,
578
+ fargs,
579
+ intrinsic,
580
+ p,
581
+ loc,
582
+ ) ,
612
583
"simd_and" => codegen_intrinsic_binop ! ( bitand) ,
613
584
"simd_div" => unstable_codegen ! ( codegen_intrinsic_binop!( div) ) ,
614
585
"simd_eq" => self . codegen_simd_cmp ( Expr :: vector_eq, fargs, p, span, farg_types, ret_ty) ,
@@ -624,7 +595,14 @@ impl<'tcx> GotocCtx<'tcx> {
624
595
}
625
596
"simd_le" => self . codegen_simd_cmp ( Expr :: vector_le, fargs, p, span, farg_types, ret_ty) ,
626
597
"simd_lt" => self . codegen_simd_cmp ( Expr :: vector_lt, fargs, p, span, farg_types, ret_ty) ,
627
- "simd_mul" => unstable_codegen ! ( codegen_simd_with_overflow_check!( mul, mul_overflow_p) ) ,
598
+ "simd_mul" => self . codegen_simd_op_with_overflow (
599
+ Expr :: mul,
600
+ Expr :: mul_overflow_p,
601
+ fargs,
602
+ intrinsic,
603
+ p,
604
+ loc,
605
+ ) ,
628
606
"simd_ne" => {
629
607
self . codegen_simd_cmp ( Expr :: vector_neq, fargs, p, span, farg_types, ret_ty)
630
608
}
@@ -642,7 +620,14 @@ impl<'tcx> GotocCtx<'tcx> {
642
620
}
643
621
}
644
622
// "simd_shuffle#" => handled in an `if` preceding this match
645
- "simd_sub" => unstable_codegen ! ( codegen_simd_with_overflow_check!( sub, sub_overflow_p) ) ,
623
+ "simd_sub" => self . codegen_simd_op_with_overflow (
624
+ Expr :: sub,
625
+ Expr :: sub_overflow_p,
626
+ fargs,
627
+ intrinsic,
628
+ p,
629
+ loc,
630
+ ) ,
646
631
"simd_xor" => codegen_intrinsic_binop ! ( bitxor) ,
647
632
"size_of" => codegen_intrinsic_const ! ( ) ,
648
633
"size_of_val" => codegen_size_align ! ( size) ,
@@ -1432,6 +1417,44 @@ impl<'tcx> GotocCtx<'tcx> {
1432
1417
self . codegen_expr_to_place ( p, e)
1433
1418
}
1434
1419
1420
+ /// Intrinsics which encode a SIMD arithmetic operation with overflow check.
1421
+ /// We expand the overflow check because CBMC overflow operations don't accept array as
1422
+ /// argument.
1423
+ fn codegen_simd_op_with_overflow < F : FnOnce ( Expr , Expr ) -> Expr , G : Fn ( Expr , Expr ) -> Expr > (
1424
+ & mut self ,
1425
+ op_fun : F ,
1426
+ overflow_fun : G ,
1427
+ mut fargs : Vec < Expr > ,
1428
+ intrinsic : & str ,
1429
+ p : & Place < ' tcx > ,
1430
+ loc : Location ,
1431
+ ) -> Stmt {
1432
+ let a = fargs. remove ( 0 ) ;
1433
+ let b = fargs. remove ( 0 ) ;
1434
+
1435
+ let a_size = a. typ ( ) . len ( ) . unwrap ( ) ;
1436
+ let b_size = b. typ ( ) . len ( ) . unwrap ( ) ;
1437
+ assert_eq ! ( a_size, b_size, "expected same length vectors" ) ;
1438
+
1439
+ let mut check = Expr :: bool_false ( ) ;
1440
+ for i in 0 ..a_size {
1441
+ // create expression
1442
+ let index = Expr :: int_constant ( i, Type :: ssize_t ( ) ) ;
1443
+ let v_a = a. clone ( ) . index_array ( index. clone ( ) ) ;
1444
+ let v_b = b. clone ( ) . index_array ( index) ;
1445
+ check = check. or ( overflow_fun ( v_a, v_b) ) ;
1446
+ }
1447
+ let check_stmt = self . codegen_assert_assume (
1448
+ check. not ( ) ,
1449
+ PropertyClass :: ArithmeticOverflow ,
1450
+ format ! ( "attempt to compute {} which would overflow" , intrinsic) . as_str ( ) ,
1451
+ loc,
1452
+ ) ;
1453
+ let res = op_fun ( a, b) ;
1454
+ let expr_place = self . codegen_expr_to_place ( p, res) ;
1455
+ Stmt :: block ( vec ! [ expr_place, check_stmt] , loc)
1456
+ }
1457
+
1435
1458
/// simd_shuffle constructs a new vector from the elements of two input vectors,
1436
1459
/// choosing values according to an input array of indexes.
1437
1460
///
0 commit comments