[PATCH] D48040: Implement constexpr __builtin_*_overflow
This revision was automatically updated to reflect the committed changes. Closed by commit rL334650: Implement constexpr __builtin_*_overflow (authored by erichkeane, committed by ). Herald added a subscriber: llvm-commits. Changed prior to commit: https://reviews.llvm.org/D48040?vs=151151=151241#toc Repository: rL LLVM https://reviews.llvm.org/D48040 Files: cfe/trunk/lib/AST/ExprConstant.cpp cfe/trunk/test/SemaCXX/builtins-overflow.cpp Index: cfe/trunk/lib/AST/ExprConstant.cpp === --- cfe/trunk/lib/AST/ExprConstant.cpp +++ cfe/trunk/lib/AST/ExprConstant.cpp @@ -8155,6 +8155,124 @@ case Builtin::BIomp_is_initial_device: // We can decide statically which value the runtime would return if called. return Success(Info.getLangOpts().OpenMPIsDevice ? 0 : 1, E); + case Builtin::BI__builtin_add_overflow: + case Builtin::BI__builtin_sub_overflow: + case Builtin::BI__builtin_mul_overflow: + case Builtin::BI__builtin_sadd_overflow: + case Builtin::BI__builtin_uadd_overflow: + case Builtin::BI__builtin_uaddl_overflow: + case Builtin::BI__builtin_uaddll_overflow: + case Builtin::BI__builtin_usub_overflow: + case Builtin::BI__builtin_usubl_overflow: + case Builtin::BI__builtin_usubll_overflow: + case Builtin::BI__builtin_umul_overflow: + case Builtin::BI__builtin_umull_overflow: + case Builtin::BI__builtin_umulll_overflow: + case Builtin::BI__builtin_saddl_overflow: + case Builtin::BI__builtin_saddll_overflow: + case Builtin::BI__builtin_ssub_overflow: + case Builtin::BI__builtin_ssubl_overflow: + case Builtin::BI__builtin_ssubll_overflow: + case Builtin::BI__builtin_smul_overflow: + case Builtin::BI__builtin_smull_overflow: + case Builtin::BI__builtin_smulll_overflow: { +LValue ResultLValue; +APSInt LHS, RHS; + +QualType ResultType = E->getArg(2)->getType()->getPointeeType(); +if (!EvaluateInteger(E->getArg(0), LHS, Info) || +!EvaluateInteger(E->getArg(1), RHS, Info) || +!EvaluatePointer(E->getArg(2), ResultLValue, Info)) + return false; + +APSInt Result; +bool DidOverflow = false; + +// If the types don't have to match, enlarge all 3 to the largest of them. +if (BuiltinOp == Builtin::BI__builtin_add_overflow || +BuiltinOp == Builtin::BI__builtin_sub_overflow || +BuiltinOp == Builtin::BI__builtin_mul_overflow) { + bool IsSigned = LHS.isSigned() || RHS.isSigned() || + ResultType->isSignedIntegerOrEnumerationType(); + bool AllSigned = LHS.isSigned() && RHS.isSigned() && + ResultType->isSignedIntegerOrEnumerationType(); + uint64_t LHSSize = LHS.getBitWidth(); + uint64_t RHSSize = RHS.getBitWidth(); + uint64_t ResultSize = Info.Ctx.getTypeSize(ResultType); + uint64_t MaxBits = std::max(std::max(LHSSize, RHSSize), ResultSize); + + // Add an additional bit if the signedness isn't uniformly agreed to. We + // could do this ONLY if there is a signed and an unsigned that both have + // MaxBits, but the code to check that is pretty nasty. The issue will be + // caught in the shrink-to-result later anyway. + if (IsSigned && !AllSigned) +++MaxBits; + + LHS = APSInt(IsSigned ? LHS.sextOrSelf(MaxBits) : LHS.zextOrSelf(MaxBits), + !IsSigned); + RHS = APSInt(IsSigned ? RHS.sextOrSelf(MaxBits) : RHS.zextOrSelf(MaxBits), + !IsSigned); + Result = APSInt(MaxBits, !IsSigned); +} + +// Find largest int. +switch (BuiltinOp) { +default: + llvm_unreachable("Invalid value for BuiltinOp"); +case Builtin::BI__builtin_add_overflow: +case Builtin::BI__builtin_sadd_overflow: +case Builtin::BI__builtin_saddl_overflow: +case Builtin::BI__builtin_saddll_overflow: +case Builtin::BI__builtin_uadd_overflow: +case Builtin::BI__builtin_uaddl_overflow: +case Builtin::BI__builtin_uaddll_overflow: + Result = LHS.isSigned() ? LHS.sadd_ov(RHS, DidOverflow) + : LHS.uadd_ov(RHS, DidOverflow); + break; +case Builtin::BI__builtin_sub_overflow: +case Builtin::BI__builtin_ssub_overflow: +case Builtin::BI__builtin_ssubl_overflow: +case Builtin::BI__builtin_ssubll_overflow: +case Builtin::BI__builtin_usub_overflow: +case Builtin::BI__builtin_usubl_overflow: +case Builtin::BI__builtin_usubll_overflow: + Result = LHS.isSigned() ? LHS.ssub_ov(RHS, DidOverflow) + : LHS.usub_ov(RHS, DidOverflow); + break; +case Builtin::BI__builtin_mul_overflow: +case Builtin::BI__builtin_smul_overflow: +case Builtin::BI__builtin_smull_overflow: +case Builtin::BI__builtin_smulll_overflow: +case Builtin::BI__builtin_umul_overflow: +case Builtin::BI__builtin_umull_overflow: +case Builtin::BI__builtin_umulll_overflow: + Result = LHS.isSigned() ? LHS.smul_ov(RHS, DidOverflow) +
[PATCH] D48040: Implement constexpr __builtin_*_overflow
efriedma added a comment. Oh, sorry, I mixed up the two values. I meant that you should add a couple testcases to ensure the stored value is correct on overflow. https://reviews.llvm.org/D48040 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D48040: Implement constexpr __builtin_*_overflow
erichkeane added a comment. I believe my tests DO validate the return value correctly, don't they? It uses a sentinel, but the ternary should check that return value, right? Or is there an obvious thing I'm missing? https://reviews.llvm.org/D48040 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D48040: Implement constexpr __builtin_*_overflow
efriedma accepted this revision. efriedma added a comment. This revision is now accepted and ready to land. I'd like to see a couple of testcases ensuring the return value is correct on overflow (we had a problem with that for __builtin_mul_overflow in the past). Otherwise LGTM. https://reviews.llvm.org/D48040 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D48040: Implement constexpr __builtin_*_overflow
erichkeane updated this revision to Diff 151151. erichkeane added a comment. Separated out the other patch as Eli suggested (which has now been committed), and rebased this patch on top of it. https://reviews.llvm.org/D48040 Files: lib/AST/ExprConstant.cpp test/SemaCXX/builtins-overflow.cpp Index: lib/AST/ExprConstant.cpp === --- lib/AST/ExprConstant.cpp +++ lib/AST/ExprConstant.cpp @@ -8155,6 +8155,124 @@ case Builtin::BIomp_is_initial_device: // We can decide statically which value the runtime would return if called. return Success(Info.getLangOpts().OpenMPIsDevice ? 0 : 1, E); + case Builtin::BI__builtin_add_overflow: + case Builtin::BI__builtin_sub_overflow: + case Builtin::BI__builtin_mul_overflow: + case Builtin::BI__builtin_sadd_overflow: + case Builtin::BI__builtin_uadd_overflow: + case Builtin::BI__builtin_uaddl_overflow: + case Builtin::BI__builtin_uaddll_overflow: + case Builtin::BI__builtin_usub_overflow: + case Builtin::BI__builtin_usubl_overflow: + case Builtin::BI__builtin_usubll_overflow: + case Builtin::BI__builtin_umul_overflow: + case Builtin::BI__builtin_umull_overflow: + case Builtin::BI__builtin_umulll_overflow: + case Builtin::BI__builtin_saddl_overflow: + case Builtin::BI__builtin_saddll_overflow: + case Builtin::BI__builtin_ssub_overflow: + case Builtin::BI__builtin_ssubl_overflow: + case Builtin::BI__builtin_ssubll_overflow: + case Builtin::BI__builtin_smul_overflow: + case Builtin::BI__builtin_smull_overflow: + case Builtin::BI__builtin_smulll_overflow: { +LValue ResultLValue; +APSInt LHS, RHS; + +QualType ResultType = E->getArg(2)->getType()->getPointeeType(); +if (!EvaluateInteger(E->getArg(0), LHS, Info) || +!EvaluateInteger(E->getArg(1), RHS, Info) || +!EvaluatePointer(E->getArg(2), ResultLValue, Info)) + return false; + +APSInt Result; +bool DidOverflow = false; + +// If the types don't have to match, enlarge all 3 to the largest of them. +if (BuiltinOp == Builtin::BI__builtin_add_overflow || +BuiltinOp == Builtin::BI__builtin_sub_overflow || +BuiltinOp == Builtin::BI__builtin_mul_overflow) { + bool IsSigned = LHS.isSigned() || RHS.isSigned() || + ResultType->isSignedIntegerOrEnumerationType(); + bool AllSigned = LHS.isSigned() && RHS.isSigned() && + ResultType->isSignedIntegerOrEnumerationType(); + uint64_t LHSSize = LHS.getBitWidth(); + uint64_t RHSSize = RHS.getBitWidth(); + uint64_t ResultSize = Info.Ctx.getTypeSize(ResultType); + uint64_t MaxBits = std::max(std::max(LHSSize, RHSSize), ResultSize); + + // Add an additional bit if the signedness isn't uniformly agreed to. We + // could do this ONLY if there is a signed and an unsigned that both have + // MaxBits, but the code to check that is pretty nasty. The issue will be + // caught in the shrink-to-result later anyway. + if (IsSigned && !AllSigned) +++MaxBits; + + LHS = APSInt(IsSigned ? LHS.sextOrSelf(MaxBits) : LHS.zextOrSelf(MaxBits), + !IsSigned); + RHS = APSInt(IsSigned ? RHS.sextOrSelf(MaxBits) : RHS.zextOrSelf(MaxBits), + !IsSigned); + Result = APSInt(MaxBits, !IsSigned); +} + +// Find largest int. +switch (BuiltinOp) { +default: + llvm_unreachable("Invalid value for BuiltinOp"); +case Builtin::BI__builtin_add_overflow: +case Builtin::BI__builtin_sadd_overflow: +case Builtin::BI__builtin_saddl_overflow: +case Builtin::BI__builtin_saddll_overflow: +case Builtin::BI__builtin_uadd_overflow: +case Builtin::BI__builtin_uaddl_overflow: +case Builtin::BI__builtin_uaddll_overflow: + Result = LHS.isSigned() ? LHS.sadd_ov(RHS, DidOverflow) + : LHS.uadd_ov(RHS, DidOverflow); + break; +case Builtin::BI__builtin_sub_overflow: +case Builtin::BI__builtin_ssub_overflow: +case Builtin::BI__builtin_ssubl_overflow: +case Builtin::BI__builtin_ssubll_overflow: +case Builtin::BI__builtin_usub_overflow: +case Builtin::BI__builtin_usubl_overflow: +case Builtin::BI__builtin_usubll_overflow: + Result = LHS.isSigned() ? LHS.ssub_ov(RHS, DidOverflow) + : LHS.usub_ov(RHS, DidOverflow); + break; +case Builtin::BI__builtin_mul_overflow: +case Builtin::BI__builtin_smul_overflow: +case Builtin::BI__builtin_smull_overflow: +case Builtin::BI__builtin_smulll_overflow: +case Builtin::BI__builtin_umul_overflow: +case Builtin::BI__builtin_umull_overflow: +case Builtin::BI__builtin_umulll_overflow: + Result = LHS.isSigned() ? LHS.smul_ov(RHS, DidOverflow) + : LHS.umul_ov(RHS, DidOverflow); + break; +} + +// In the case where multiple sizes are allowed, truncate and see if +// the values are
[PATCH] D48040: Implement constexpr __builtin_*_overflow
rjmccall added a comment. Thanks, comment change looks good. LGTM. https://reviews.llvm.org/D48040 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D48040: Implement constexpr __builtin_*_overflow
erichkeane added a comment. Alright, done here: https://reviews.llvm.org/D48053 This one'll require some rebasing on that change, but I'm not sure how to do it in SVN. Therefore, I'll just rebase this one when it comes to commit it. -Erich https://reviews.llvm.org/D48040 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D48040: Implement constexpr __builtin_*_overflow
erichkeane added inline comments. Comment at: lib/Sema/SemaChecking.cpp:210 +Arg = S.PerformCopyInitialization(Entity, SourceLocation(), Arg); +TheCall->setArg(I, Arg.get()); } efriedma wrote: > erichkeane wrote: > > efriedma wrote: > > > Can you split this change into a separate patch? Testcase: > > > > > > ``` > > > int a() { > > > const int x = 3; > > > static int z; > > > constexpr int * y = > > > return []() { return __builtin_sub_overflow(x,x,y); }(); > > > }``` > > Can you clarify what you mean? That above testcase (with added captures) > > seems to work currently. What difference in behavior should I be expecting? > The testcase should type-check as-is, without adding any captures. Reading > the value of a constexpr variable, or a const variable of integer type, isn't > an odr-use. This doesn't work correctly at the moment because the > lvalue-to-rvalue conversions are missing from the AST. Compare to the > following: > > ``` > int a() { > const int x = 3; > static int z; > constexpr int * y = > return []() { return __builtin_sub_overflow((int)x,(int)x,(int*)y); }(); > } > ``` Ah, got it! I 'll split that off into a separate patch with those test cases now. Look for the review soon! https://reviews.llvm.org/D48040 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D48040: Implement constexpr __builtin_*_overflow
efriedma added inline comments. Comment at: lib/Sema/SemaChecking.cpp:210 +Arg = S.PerformCopyInitialization(Entity, SourceLocation(), Arg); +TheCall->setArg(I, Arg.get()); } erichkeane wrote: > efriedma wrote: > > Can you split this change into a separate patch? Testcase: > > > > ``` > > int a() { > > const int x = 3; > > static int z; > > constexpr int * y = > > return []() { return __builtin_sub_overflow(x,x,y); }(); > > }``` > Can you clarify what you mean? That above testcase (with added captures) > seems to work currently. What difference in behavior should I be expecting? The testcase should type-check as-is, without adding any captures. Reading the value of a constexpr variable, or a const variable of integer type, isn't an odr-use. This doesn't work correctly at the moment because the lvalue-to-rvalue conversions are missing from the AST. Compare to the following: ``` int a() { const int x = 3; static int z; constexpr int * y = return []() { return __builtin_sub_overflow((int)x,(int)x,(int*)y); }(); } ``` https://reviews.llvm.org/D48040 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D48040: Implement constexpr __builtin_*_overflow
erichkeane added inline comments. Comment at: lib/Sema/SemaChecking.cpp:210 +Arg = S.PerformCopyInitialization(Entity, SourceLocation(), Arg); +TheCall->setArg(I, Arg.get()); } efriedma wrote: > Can you split this change into a separate patch? Testcase: > > ``` > int a() { > const int x = 3; > static int z; > constexpr int * y = > return []() { return __builtin_sub_overflow(x,x,y); }(); > }``` Can you clarify what you mean? That above testcase (with added captures) seems to work currently. What difference in behavior should I be expecting? https://reviews.llvm.org/D48040 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D48040: Implement constexpr __builtin_*_overflow
efriedma added inline comments. Comment at: lib/Sema/SemaChecking.cpp:210 +Arg = S.PerformCopyInitialization(Entity, SourceLocation(), Arg); +TheCall->setArg(I, Arg.get()); } Can you split this change into a separate patch? Testcase: ``` int a() { const int x = 3; static int z; constexpr int * y = return []() { return __builtin_sub_overflow(x,x,y); }(); }``` https://reviews.llvm.org/D48040 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D48040: Implement constexpr __builtin_*_overflow
erichkeane updated this revision to Diff 150808. erichkeane marked an inline comment as done. https://reviews.llvm.org/D48040 Files: lib/AST/ExprConstant.cpp lib/Sema/SemaChecking.cpp test/SemaCXX/builtins-overflow.cpp Index: lib/AST/ExprConstant.cpp === --- lib/AST/ExprConstant.cpp +++ lib/AST/ExprConstant.cpp @@ -8155,6 +8155,124 @@ case Builtin::BIomp_is_initial_device: // We can decide statically which value the runtime would return if called. return Success(Info.getLangOpts().OpenMPIsDevice ? 0 : 1, E); + case Builtin::BI__builtin_add_overflow: + case Builtin::BI__builtin_sub_overflow: + case Builtin::BI__builtin_mul_overflow: + case Builtin::BI__builtin_sadd_overflow: + case Builtin::BI__builtin_uadd_overflow: + case Builtin::BI__builtin_uaddl_overflow: + case Builtin::BI__builtin_uaddll_overflow: + case Builtin::BI__builtin_usub_overflow: + case Builtin::BI__builtin_usubl_overflow: + case Builtin::BI__builtin_usubll_overflow: + case Builtin::BI__builtin_umul_overflow: + case Builtin::BI__builtin_umull_overflow: + case Builtin::BI__builtin_umulll_overflow: + case Builtin::BI__builtin_saddl_overflow: + case Builtin::BI__builtin_saddll_overflow: + case Builtin::BI__builtin_ssub_overflow: + case Builtin::BI__builtin_ssubl_overflow: + case Builtin::BI__builtin_ssubll_overflow: + case Builtin::BI__builtin_smul_overflow: + case Builtin::BI__builtin_smull_overflow: + case Builtin::BI__builtin_smulll_overflow: { +LValue ResultLValue; +APSInt LHS, RHS; + +QualType ResultType = E->getArg(2)->getType()->getPointeeType(); +if (!EvaluateInteger(E->getArg(0), LHS, Info) || +!EvaluateInteger(E->getArg(1), RHS, Info) || +!EvaluatePointer(E->getArg(2), ResultLValue, Info)) + return false; + +APSInt Result; +bool DidOverflow = false; + +// If the types don't have to match, enlarge all 3 to the largest of them. +if (BuiltinOp == Builtin::BI__builtin_add_overflow || +BuiltinOp == Builtin::BI__builtin_sub_overflow || +BuiltinOp == Builtin::BI__builtin_mul_overflow) { + bool IsSigned = LHS.isSigned() || RHS.isSigned() || + ResultType->isSignedIntegerOrEnumerationType(); + bool AllSigned = LHS.isSigned() && RHS.isSigned() && + ResultType->isSignedIntegerOrEnumerationType(); + uint64_t LHSSize = LHS.getBitWidth(); + uint64_t RHSSize = RHS.getBitWidth(); + uint64_t ResultSize = Info.Ctx.getTypeSize(ResultType); + uint64_t MaxBits = std::max(std::max(LHSSize, RHSSize), ResultSize); + + // Add an additional bit if the signedness isn't uniformly agreed to. We + // could do this ONLY if there is a signed and an unsigned that both have + // MaxBits, but the code to check that is pretty nasty. The issue will be + // caught in the shrink-to-result later anyway. + if (IsSigned && !AllSigned) +++MaxBits; + + LHS = APSInt(IsSigned ? LHS.sextOrSelf(MaxBits) : LHS.zextOrSelf(MaxBits), + !IsSigned); + RHS = APSInt(IsSigned ? RHS.sextOrSelf(MaxBits) : RHS.zextOrSelf(MaxBits), + !IsSigned); + Result = APSInt(MaxBits, !IsSigned); +} + +// Find largest int. +switch (BuiltinOp) { +default: + llvm_unreachable("Invalid value for BuiltinOp"); +case Builtin::BI__builtin_add_overflow: +case Builtin::BI__builtin_sadd_overflow: +case Builtin::BI__builtin_saddl_overflow: +case Builtin::BI__builtin_saddll_overflow: +case Builtin::BI__builtin_uadd_overflow: +case Builtin::BI__builtin_uaddl_overflow: +case Builtin::BI__builtin_uaddll_overflow: + Result = LHS.isSigned() ? LHS.sadd_ov(RHS, DidOverflow) + : LHS.uadd_ov(RHS, DidOverflow); + break; +case Builtin::BI__builtin_sub_overflow: +case Builtin::BI__builtin_ssub_overflow: +case Builtin::BI__builtin_ssubl_overflow: +case Builtin::BI__builtin_ssubll_overflow: +case Builtin::BI__builtin_usub_overflow: +case Builtin::BI__builtin_usubl_overflow: +case Builtin::BI__builtin_usubll_overflow: + Result = LHS.isSigned() ? LHS.ssub_ov(RHS, DidOverflow) + : LHS.usub_ov(RHS, DidOverflow); + break; +case Builtin::BI__builtin_mul_overflow: +case Builtin::BI__builtin_smul_overflow: +case Builtin::BI__builtin_smull_overflow: +case Builtin::BI__builtin_smulll_overflow: +case Builtin::BI__builtin_umul_overflow: +case Builtin::BI__builtin_umull_overflow: +case Builtin::BI__builtin_umulll_overflow: + Result = LHS.isSigned() ? LHS.smul_ov(RHS, DidOverflow) + : LHS.umul_ov(RHS, DidOverflow); + break; +} + +// In the case where multiple sizes are allowed, truncate and see if +// the values are the same. +if (BuiltinOp == Builtin::BI__builtin_add_overflow || +
[PATCH] D48040: Implement constexpr __builtin_*_overflow
rjmccall added inline comments. Comment at: lib/AST/ExprConstant.cpp:8260 + // It won't GROW, since that isn't possible, so use this to allow + // TruncOrSelf. + APSInt Temp = Result.extOrTrunc(Info.Ctx.getTypeSize(ResultType)); The comment should explain *why* growth isn't possible (it's because we extended to the max-width type earlier). I don't think a casual reader is going to understand what you're saying about TruncOrSelf (that APSInt doesn't have such an operation, but that we can safely simulate it with `extOrTrunc` because we'll never do an extension). Repository: rC Clang https://reviews.llvm.org/D48040 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D48040: Implement constexpr __builtin_*_overflow
erichkeane created this revision. erichkeane added reviewers: eli.friedman, rjmccall. As requested here:https://bugs.llvm.org/show_bug.cgi?id=37633 permit the __builtin_*_overflow builtins in constexpr functions. Repository: rC Clang https://reviews.llvm.org/D48040 Files: lib/AST/ExprConstant.cpp lib/Sema/SemaChecking.cpp test/SemaCXX/builtins-overflow.cpp Index: lib/AST/ExprConstant.cpp === --- lib/AST/ExprConstant.cpp +++ lib/AST/ExprConstant.cpp @@ -8155,6 +8155,121 @@ case Builtin::BIomp_is_initial_device: // We can decide statically which value the runtime would return if called. return Success(Info.getLangOpts().OpenMPIsDevice ? 0 : 1, E); + case Builtin::BI__builtin_add_overflow: + case Builtin::BI__builtin_sub_overflow: + case Builtin::BI__builtin_mul_overflow: + case Builtin::BI__builtin_sadd_overflow: + case Builtin::BI__builtin_uadd_overflow: + case Builtin::BI__builtin_uaddl_overflow: + case Builtin::BI__builtin_uaddll_overflow: + case Builtin::BI__builtin_usub_overflow: + case Builtin::BI__builtin_usubl_overflow: + case Builtin::BI__builtin_usubll_overflow: + case Builtin::BI__builtin_umul_overflow: + case Builtin::BI__builtin_umull_overflow: + case Builtin::BI__builtin_umulll_overflow: + case Builtin::BI__builtin_saddl_overflow: + case Builtin::BI__builtin_saddll_overflow: + case Builtin::BI__builtin_ssub_overflow: + case Builtin::BI__builtin_ssubl_overflow: + case Builtin::BI__builtin_ssubll_overflow: + case Builtin::BI__builtin_smul_overflow: + case Builtin::BI__builtin_smull_overflow: + case Builtin::BI__builtin_smulll_overflow: { +LValue ResultLValue; +APSInt LHS, RHS; + +QualType ResultType = E->getArg(2)->getType()->getPointeeType(); +if (!EvaluateInteger(E->getArg(0), LHS, Info) || +!EvaluateInteger(E->getArg(1), RHS, Info) || +!EvaluatePointer(E->getArg(2), ResultLValue, Info)) + return false; + +APSInt Result; +bool DidOverflow = false; + +// If the types don't have to match, enlarge all 3 to the largest of them. +if (BuiltinOp == Builtin::BI__builtin_add_overflow || +BuiltinOp == Builtin::BI__builtin_sub_overflow || +BuiltinOp == Builtin::BI__builtin_mul_overflow) { + bool IsSigned = LHS.isSigned() || RHS.isSigned() || + ResultType->isSignedIntegerOrEnumerationType(); + bool AllSigned = LHS.isSigned() && RHS.isSigned() && + ResultType->isSignedIntegerOrEnumerationType(); + uint64_t LHSSize = LHS.getBitWidth(); + uint64_t RHSSize = RHS.getBitWidth(); + uint64_t ResultSize = Info.Ctx.getTypeSize(ResultType); + uint64_t MaxBits = std::max(std::max(LHSSize, RHSSize), ResultSize); + + // Add an additional bit if the signedness isn't uniformly agreed to. We + // could do this ONLY if there is a signed and an unsigned that both have + // MaxBits, but the code to check that is pretty nasty. The issue will be + // caught in the shrink-to-result later anyway. + if (IsSigned && !AllSigned) +++MaxBits; + + LHS = APSInt(IsSigned ? LHS.sextOrSelf(MaxBits) : LHS.zextOrSelf(MaxBits), + !IsSigned); + RHS = APSInt(IsSigned ? RHS.sextOrSelf(MaxBits) : RHS.zextOrSelf(MaxBits), + !IsSigned); + Result = APSInt(MaxBits, !IsSigned); +} + +// Find largest int. +switch (BuiltinOp) { +default: + llvm_unreachable("Invalid value for BuiltinOp"); +case Builtin::BI__builtin_add_overflow: +case Builtin::BI__builtin_sadd_overflow: +case Builtin::BI__builtin_saddl_overflow: +case Builtin::BI__builtin_saddll_overflow: +case Builtin::BI__builtin_uadd_overflow: +case Builtin::BI__builtin_uaddl_overflow: +case Builtin::BI__builtin_uaddll_overflow: + Result = LHS.isSigned() ? LHS.sadd_ov(RHS, DidOverflow) + : LHS.uadd_ov(RHS, DidOverflow); + break; +case Builtin::BI__builtin_sub_overflow: +case Builtin::BI__builtin_ssub_overflow: +case Builtin::BI__builtin_ssubl_overflow: +case Builtin::BI__builtin_ssubll_overflow: +case Builtin::BI__builtin_usub_overflow: +case Builtin::BI__builtin_usubl_overflow: +case Builtin::BI__builtin_usubll_overflow: + Result = LHS.isSigned() ? LHS.ssub_ov(RHS, DidOverflow) + : LHS.usub_ov(RHS, DidOverflow); + break; +case Builtin::BI__builtin_mul_overflow: +case Builtin::BI__builtin_smul_overflow: +case Builtin::BI__builtin_smull_overflow: +case Builtin::BI__builtin_smulll_overflow: +case Builtin::BI__builtin_umul_overflow: +case Builtin::BI__builtin_umull_overflow: +case Builtin::BI__builtin_umulll_overflow: + Result = LHS.isSigned() ? LHS.smul_ov(RHS, DidOverflow) + : LHS.umul_ov(RHS, DidOverflow); + break; +} + +// In the case where