@@ -55,8 +55,8 @@ static APSInt peekToAPSInt(InterpStack &Stk, PrimType T, size_t Offset = 0) {
55
55
APSInt R;
56
56
INT_TYPE_SWITCH (T, {
57
57
T Val = Stk.peek <T>(Offset);
58
- R = APSInt (
59
- APInt (Val. bitWidth (), static_cast < uint64_t >(Val), T::isSigned () ));
58
+ R = APSInt (APInt (Val. bitWidth (), static_cast < uint64_t >(Val), T::isSigned ()),
59
+ ! T::isSigned ());
60
60
});
61
61
62
62
return R;
@@ -155,6 +155,11 @@ static void pushSizeT(InterpState &S, uint64_t Val) {
155
155
}
156
156
}
157
157
158
+ static void assignInteger (Pointer &Dest, PrimType ValueT, const APSInt &Value) {
159
+ INT_TYPE_SWITCH_NO_BOOL (
160
+ ValueT, { Dest.deref <T>() = T::from (static_cast <T>(Value)); });
161
+ }
162
+
158
163
static bool retPrimValue (InterpState &S, CodePtr OpPC, APValue &Result,
159
164
std::optional<PrimType> &T) {
160
165
if (!T)
@@ -667,6 +672,175 @@ static bool interp__builtin_launder(InterpState &S, CodePtr OpPC,
667
672
return true ;
668
673
}
669
674
675
+ // Two integral values followed by a pointer (lhs, rhs, resultOut)
676
+ static bool interp__builtin_overflowop (InterpState &S, CodePtr OpPC,
677
+ const InterpFrame *Frame,
678
+ const Function *Func,
679
+ const CallExpr *Call) {
680
+ Pointer &ResultPtr = S.Stk .peek <Pointer>();
681
+ if (ResultPtr.isDummy ())
682
+ return false ;
683
+
684
+ unsigned BuiltinOp = Func->getBuiltinID ();
685
+ PrimType RHST = *S.getContext ().classify (Call->getArg (1 )->getType ());
686
+ PrimType LHST = *S.getContext ().classify (Call->getArg (0 )->getType ());
687
+ APSInt RHS = peekToAPSInt (S.Stk , RHST,
688
+ align (primSize (PT_Ptr)) + align (primSize (RHST)));
689
+ APSInt LHS = peekToAPSInt (S.Stk , LHST,
690
+ align (primSize (PT_Ptr)) + align (primSize (RHST)) +
691
+ align (primSize (LHST)));
692
+ QualType ResultType = Call->getArg (2 )->getType ()->getPointeeType ();
693
+ PrimType ResultT = *S.getContext ().classify (ResultType);
694
+ bool Overflow;
695
+
696
+ APSInt Result;
697
+ if (BuiltinOp == Builtin::BI__builtin_add_overflow ||
698
+ BuiltinOp == Builtin::BI__builtin_sub_overflow ||
699
+ BuiltinOp == Builtin::BI__builtin_mul_overflow) {
700
+ bool IsSigned = LHS.isSigned () || RHS.isSigned () ||
701
+ ResultType->isSignedIntegerOrEnumerationType ();
702
+ bool AllSigned = LHS.isSigned () && RHS.isSigned () &&
703
+ ResultType->isSignedIntegerOrEnumerationType ();
704
+ uint64_t LHSSize = LHS.getBitWidth ();
705
+ uint64_t RHSSize = RHS.getBitWidth ();
706
+ uint64_t ResultSize = S.getCtx ().getTypeSize (ResultType);
707
+ uint64_t MaxBits = std::max (std::max (LHSSize, RHSSize), ResultSize);
708
+
709
+ // Add an additional bit if the signedness isn't uniformly agreed to. We
710
+ // could do this ONLY if there is a signed and an unsigned that both have
711
+ // MaxBits, but the code to check that is pretty nasty. The issue will be
712
+ // caught in the shrink-to-result later anyway.
713
+ if (IsSigned && !AllSigned)
714
+ ++MaxBits;
715
+
716
+ LHS = APSInt (LHS.extOrTrunc (MaxBits), !IsSigned);
717
+ RHS = APSInt (RHS.extOrTrunc (MaxBits), !IsSigned);
718
+ Result = APSInt (MaxBits, !IsSigned);
719
+ }
720
+
721
+ // Find largest int.
722
+ switch (BuiltinOp) {
723
+ default :
724
+ llvm_unreachable (" Invalid value for BuiltinOp" );
725
+ case Builtin::BI__builtin_add_overflow:
726
+ case Builtin::BI__builtin_sadd_overflow:
727
+ case Builtin::BI__builtin_saddl_overflow:
728
+ case Builtin::BI__builtin_saddll_overflow:
729
+ case Builtin::BI__builtin_uadd_overflow:
730
+ case Builtin::BI__builtin_uaddl_overflow:
731
+ case Builtin::BI__builtin_uaddll_overflow:
732
+ Result = LHS.isSigned () ? LHS.sadd_ov (RHS, Overflow)
733
+ : LHS.uadd_ov (RHS, Overflow);
734
+ break ;
735
+ case Builtin::BI__builtin_sub_overflow:
736
+ case Builtin::BI__builtin_ssub_overflow:
737
+ case Builtin::BI__builtin_ssubl_overflow:
738
+ case Builtin::BI__builtin_ssubll_overflow:
739
+ case Builtin::BI__builtin_usub_overflow:
740
+ case Builtin::BI__builtin_usubl_overflow:
741
+ case Builtin::BI__builtin_usubll_overflow:
742
+ Result = LHS.isSigned () ? LHS.ssub_ov (RHS, Overflow)
743
+ : LHS.usub_ov (RHS, Overflow);
744
+ break ;
745
+ case Builtin::BI__builtin_mul_overflow:
746
+ case Builtin::BI__builtin_smul_overflow:
747
+ case Builtin::BI__builtin_smull_overflow:
748
+ case Builtin::BI__builtin_smulll_overflow:
749
+ case Builtin::BI__builtin_umul_overflow:
750
+ case Builtin::BI__builtin_umull_overflow:
751
+ case Builtin::BI__builtin_umulll_overflow:
752
+ Result = LHS.isSigned () ? LHS.smul_ov (RHS, Overflow)
753
+ : LHS.umul_ov (RHS, Overflow);
754
+ break ;
755
+ }
756
+
757
+ // In the case where multiple sizes are allowed, truncate and see if
758
+ // the values are the same.
759
+ if (BuiltinOp == Builtin::BI__builtin_add_overflow ||
760
+ BuiltinOp == Builtin::BI__builtin_sub_overflow ||
761
+ BuiltinOp == Builtin::BI__builtin_mul_overflow) {
762
+ // APSInt doesn't have a TruncOrSelf, so we use extOrTrunc instead,
763
+ // since it will give us the behavior of a TruncOrSelf in the case where
764
+ // its parameter <= its size. We previously set Result to be at least the
765
+ // type-size of the result, so getTypeSize(ResultType) <= Resu
766
+ APSInt Temp = Result.extOrTrunc (S.getCtx ().getTypeSize (ResultType));
767
+ Temp.setIsSigned (ResultType->isSignedIntegerOrEnumerationType ());
768
+
769
+ if (!APSInt::isSameValue (Temp, Result))
770
+ Overflow = true ;
771
+ Result = Temp;
772
+ }
773
+
774
+ // Write Result to ResultPtr and put Overflow on the stacl.
775
+ assignInteger (ResultPtr, ResultT, Result);
776
+ ResultPtr.initialize ();
777
+ assert (Func->getDecl ()->getReturnType ()->isBooleanType ());
778
+ S.Stk .push <Boolean>(Overflow);
779
+ return true ;
780
+ }
781
+
782
+ // / Three integral values followed by a pointer (lhs, rhs, carry, carryOut).
783
+ static bool interp__builtin_carryop (InterpState &S, CodePtr OpPC,
784
+ const InterpFrame *Frame,
785
+ const Function *Func,
786
+ const CallExpr *Call) {
787
+ unsigned BuiltinOp = Func->getBuiltinID ();
788
+ PrimType LHST = *S.getContext ().classify (Call->getArg (0 )->getType ());
789
+ PrimType RHST = *S.getContext ().classify (Call->getArg (1 )->getType ());
790
+ PrimType CarryT = *S.getContext ().classify (Call->getArg (2 )->getType ());
791
+ APSInt RHS = peekToAPSInt (S.Stk , RHST,
792
+ align (primSize (PT_Ptr)) + align (primSize (CarryT)) +
793
+ align (primSize (RHST)));
794
+ APSInt LHS =
795
+ peekToAPSInt (S.Stk , LHST,
796
+ align (primSize (PT_Ptr)) + align (primSize (RHST)) +
797
+ align (primSize (CarryT)) + align (primSize (LHST)));
798
+ APSInt CarryIn = peekToAPSInt (
799
+ S.Stk , LHST, align (primSize (PT_Ptr)) + align (primSize (CarryT)));
800
+ APSInt CarryOut;
801
+
802
+ APSInt Result;
803
+ // Copy the number of bits and sign.
804
+ Result = LHS;
805
+ CarryOut = LHS;
806
+
807
+ bool FirstOverflowed = false ;
808
+ bool SecondOverflowed = false ;
809
+ switch (BuiltinOp) {
810
+ default :
811
+ llvm_unreachable (" Invalid value for BuiltinOp" );
812
+ case Builtin::BI__builtin_addcb:
813
+ case Builtin::BI__builtin_addcs:
814
+ case Builtin::BI__builtin_addc:
815
+ case Builtin::BI__builtin_addcl:
816
+ case Builtin::BI__builtin_addcll:
817
+ Result =
818
+ LHS.uadd_ov (RHS, FirstOverflowed).uadd_ov (CarryIn, SecondOverflowed);
819
+ break ;
820
+ case Builtin::BI__builtin_subcb:
821
+ case Builtin::BI__builtin_subcs:
822
+ case Builtin::BI__builtin_subc:
823
+ case Builtin::BI__builtin_subcl:
824
+ case Builtin::BI__builtin_subcll:
825
+ Result =
826
+ LHS.usub_ov (RHS, FirstOverflowed).usub_ov (CarryIn, SecondOverflowed);
827
+ break ;
828
+ }
829
+ // It is possible for both overflows to happen but CGBuiltin uses an OR so
830
+ // this is consistent.
831
+ CarryOut = (uint64_t )(FirstOverflowed | SecondOverflowed);
832
+
833
+ Pointer &CarryOutPtr = S.Stk .peek <Pointer>();
834
+ QualType CarryOutType = Call->getArg (3 )->getType ()->getPointeeType ();
835
+ PrimType CarryOutT = *S.getContext ().classify (CarryOutType);
836
+ assignInteger (CarryOutPtr, CarryOutT, CarryOut);
837
+ CarryOutPtr.initialize ();
838
+
839
+ assert (Call->getType () == Call->getArg (0 )->getType ());
840
+ pushAPSInt (S, Result);
841
+ return true ;
842
+ }
843
+
670
844
bool InterpretBuiltin (InterpState &S, CodePtr OpPC, const Function *F,
671
845
const CallExpr *Call) {
672
846
InterpFrame *Frame = S.Current ;
@@ -901,6 +1075,45 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F,
901
1075
return false ;
902
1076
break ;
903
1077
1078
+ case Builtin::BI__builtin_add_overflow:
1079
+ case Builtin::BI__builtin_sub_overflow:
1080
+ case Builtin::BI__builtin_mul_overflow:
1081
+ case Builtin::BI__builtin_sadd_overflow:
1082
+ case Builtin::BI__builtin_uadd_overflow:
1083
+ case Builtin::BI__builtin_uaddl_overflow:
1084
+ case Builtin::BI__builtin_uaddll_overflow:
1085
+ case Builtin::BI__builtin_usub_overflow:
1086
+ case Builtin::BI__builtin_usubl_overflow:
1087
+ case Builtin::BI__builtin_usubll_overflow:
1088
+ case Builtin::BI__builtin_umul_overflow:
1089
+ case Builtin::BI__builtin_umull_overflow:
1090
+ case Builtin::BI__builtin_umulll_overflow:
1091
+ case Builtin::BI__builtin_saddl_overflow:
1092
+ case Builtin::BI__builtin_saddll_overflow:
1093
+ case Builtin::BI__builtin_ssub_overflow:
1094
+ case Builtin::BI__builtin_ssubl_overflow:
1095
+ case Builtin::BI__builtin_ssubll_overflow:
1096
+ case Builtin::BI__builtin_smul_overflow:
1097
+ case Builtin::BI__builtin_smull_overflow:
1098
+ case Builtin::BI__builtin_smulll_overflow:
1099
+ if (!interp__builtin_overflowop (S, OpPC, Frame, F, Call))
1100
+ return false ;
1101
+ break ;
1102
+
1103
+ case Builtin::BI__builtin_addcb:
1104
+ case Builtin::BI__builtin_addcs:
1105
+ case Builtin::BI__builtin_addc:
1106
+ case Builtin::BI__builtin_addcl:
1107
+ case Builtin::BI__builtin_addcll:
1108
+ case Builtin::BI__builtin_subcb:
1109
+ case Builtin::BI__builtin_subcs:
1110
+ case Builtin::BI__builtin_subc:
1111
+ case Builtin::BI__builtin_subcl:
1112
+ case Builtin::BI__builtin_subcll:
1113
+ if (!interp__builtin_carryop (S, OpPC, Frame, F, Call))
1114
+ return false ;
1115
+ break ;
1116
+
904
1117
default :
905
1118
return false ;
906
1119
}
0 commit comments