@@ -178,6 +178,34 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
178178 ) ?;
179179 self . write_scalar ( val, dest) ?;
180180 }
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+ }
181209 sym:: discriminant_value => {
182210 let place = self . deref_pointer ( & args[ 0 ] ) ?;
183211 let variant = self . read_discriminant ( & place) ?;
@@ -573,6 +601,106 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
573601 } )
574602 }
575603
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+
576704 /// Offsets a pointer by some multiple of its type, returning an error if the pointer leaves its
577705 /// allocation.
578706 pub fn ptr_offset_inbounds (
0 commit comments