@@ -178,6 +178,34 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
178
178
) ?;
179
179
self . write_scalar ( val, dest) ?;
180
180
}
181
+ sym:: add_with_carry | sym:: sub_with_carry => {
182
+ let l = self . read_immediate ( & args[ 0 ] ) ?;
183
+ let r = self . read_immediate ( & args[ 1 ] ) ?;
184
+ let c = self . read_immediate ( & args[ 2 ] ) ?;
185
+ let ( val, overflowed) = self . carrying_arith (
186
+ if intrinsic_name == sym:: add_with_carry { BinOp :: Add } else { BinOp :: Sub } ,
187
+ & l,
188
+ & r,
189
+ & c,
190
+ ) ?;
191
+ self . write_scalar_pair ( val, overflowed, dest) ?;
192
+ }
193
+ sym:: mul_double | sym:: mul_double_add | sym:: mul_double_add2 => {
194
+ let l = self . read_immediate ( & args[ 0 ] ) ?;
195
+ let r = self . read_immediate ( & args[ 1 ] ) ?;
196
+ let c1 = if intrinsic_name != sym:: mul_double {
197
+ Some ( self . read_immediate ( & args[ 2 ] ) ?)
198
+ } else {
199
+ None
200
+ } ;
201
+ let c2 = if intrinsic_name == sym:: mul_double_add2 {
202
+ Some ( self . read_immediate ( & args[ 3 ] ) ?)
203
+ } else {
204
+ None
205
+ } ;
206
+ let ( lo, hi) = self . mul_double_add2 ( & l, & r, c1. as_ref ( ) , c2. as_ref ( ) ) ?;
207
+ self . write_scalar_pair ( lo, hi, dest) ?;
208
+ }
181
209
sym:: discriminant_value => {
182
210
let place = self . deref_pointer ( & args[ 0 ] ) ?;
183
211
let variant = self . read_discriminant ( & place) ?;
@@ -573,6 +601,106 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
573
601
} )
574
602
}
575
603
604
+ pub fn carrying_arith (
605
+ & self ,
606
+ mir_op : BinOp ,
607
+ l : & ImmTy < ' tcx , M :: Provenance > ,
608
+ r : & ImmTy < ' tcx , M :: Provenance > ,
609
+ c : & ImmTy < ' tcx , M :: Provenance > ,
610
+ ) -> InterpResult < ' tcx , ( Scalar < M :: Provenance > , Scalar < M :: Provenance > ) > {
611
+ assert_eq ! ( l. layout. ty, r. layout. ty) ;
612
+ assert_matches ! ( l. layout. ty. kind( ) , ty:: Int ( ..) | ty:: Uint ( ..) ) ;
613
+ assert_matches ! ( c. layout. ty. kind( ) , ty:: Bool ) ;
614
+ assert_matches ! ( mir_op, BinOp :: Add | BinOp :: Sub ) ;
615
+
616
+ let mir_op = mir_op. wrapping_to_overflowing ( ) . unwrap ( ) ;
617
+
618
+ let ( val, overflowed1) = self . binary_op ( mir_op, l, r) ?. to_scalar_pair ( ) ;
619
+
620
+ let val = ImmTy :: from_scalar ( val, l. layout ) ;
621
+ let c = ImmTy :: from_scalar ( c. to_scalar ( ) , l. layout ) ;
622
+
623
+ let ( val, overflowed2) = self . binary_op ( mir_op, & val, & c) ?. to_scalar_pair ( ) ;
624
+
625
+ let overflowed1 = overflowed1. to_bool ( ) ?;
626
+ let overflowed2 = overflowed2. to_bool ( ) ?;
627
+
628
+ let overflowed = Scalar :: from_bool ( if l. layout . abi . is_signed ( ) {
629
+ overflowed1 != overflowed2
630
+ } else {
631
+ overflowed1 | overflowed2
632
+ } ) ;
633
+
634
+ interp_ok ( ( val, overflowed) )
635
+ }
636
+
637
+ pub fn mul_double_add2 (
638
+ & self ,
639
+ l : & ImmTy < ' tcx , M :: Provenance > ,
640
+ r : & ImmTy < ' tcx , M :: Provenance > ,
641
+ c1 : Option < & ImmTy < ' tcx , M :: Provenance > > ,
642
+ c2 : Option < & ImmTy < ' tcx , M :: Provenance > > ,
643
+ ) -> InterpResult < ' tcx , ( Scalar < M :: Provenance > , Scalar < M :: Provenance > ) > {
644
+ assert_eq ! ( l. layout. ty, r. layout. ty) ;
645
+ assert_matches ! ( l. layout. ty. kind( ) , ty:: Int ( ..) | ty:: Uint ( ..) ) ;
646
+
647
+ let is_signed = l. layout . abi . is_signed ( ) ;
648
+ let size = l. layout . size ;
649
+ let bits = size. bits ( ) ;
650
+ let l = l. to_scalar_int ( ) ?;
651
+ let r = r. to_scalar_int ( ) ?;
652
+
653
+ interp_ok ( if is_signed {
654
+ let l = l. to_int ( size) ;
655
+ let r = r. to_int ( size) ;
656
+ let c1 = c1. map_or ( interp_ok ( 0 ) , |c1| interp_ok ( c1. to_scalar_int ( ) ?. to_int ( size) ) ) ?;
657
+ let c2 = c2. map_or ( interp_ok ( 0 ) , |c2| interp_ok ( c2. to_scalar_int ( ) ?. to_int ( size) ) ) ?;
658
+ if bits == 128 {
659
+ #[ cfg( bootstrap) ]
660
+ {
661
+ let _ = ( l, r, c1, c2) ;
662
+ unimplemented ! ( )
663
+ }
664
+ #[ cfg( not( bootstrap) ) ]
665
+ {
666
+ let ( lo, hi) = l. carrying2_mul ( r, c1, c2) ;
667
+ let lo = Scalar :: from_uint ( lo, size) ;
668
+ let hi = Scalar :: from_int ( hi, size) ;
669
+ ( lo, hi)
670
+ }
671
+ } else {
672
+ let prod = l * r + c1 + c2;
673
+ let lo = Scalar :: from_int ( prod, size) ;
674
+ let hi = Scalar :: from_int ( prod >> size. bits ( ) , size) ;
675
+ ( lo, hi)
676
+ }
677
+ } else {
678
+ let l = l. to_uint ( size) ;
679
+ let r = r. to_uint ( size) ;
680
+ let c1 = c1. map_or ( interp_ok ( 0 ) , |c1| interp_ok ( c1. to_scalar_int ( ) ?. to_uint ( size) ) ) ?;
681
+ let c2 = c2. map_or ( interp_ok ( 0 ) , |c2| interp_ok ( c2. to_scalar_int ( ) ?. to_uint ( size) ) ) ?;
682
+ if bits == 128 {
683
+ #[ cfg( bootstrap) ]
684
+ {
685
+ let _ = ( l, r, c1, c2) ;
686
+ unimplemented ! ( )
687
+ }
688
+ #[ cfg( not( bootstrap) ) ]
689
+ {
690
+ let ( lo, hi) = l. carrying2_mul ( r, c1, c2) ;
691
+ let lo = Scalar :: from_uint ( lo, size) ;
692
+ let hi = Scalar :: from_uint ( hi, size) ;
693
+ ( lo, hi)
694
+ }
695
+ } else {
696
+ let prod = l * r + c1 + c2;
697
+ let lo = Scalar :: from_uint ( prod, size) ;
698
+ let hi = Scalar :: from_uint ( prod >> size. bits ( ) , size) ;
699
+ ( lo, hi)
700
+ }
701
+ } )
702
+ }
703
+
576
704
/// Offsets a pointer by some multiple of its type, returning an error if the pointer leaves its
577
705
/// allocation.
578
706
pub fn ptr_offset_inbounds (
0 commit comments