[PATCH] D48040: Implement constexpr __builtin_*_overflow

2018-06-13 Thread Erich Keane via Phabricator via cfe-commits
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

2018-06-13 Thread Eli Friedman via Phabricator via cfe-commits
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

2018-06-13 Thread Erich Keane via Phabricator via cfe-commits
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

2018-06-13 Thread Eli Friedman via Phabricator via cfe-commits
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

2018-06-13 Thread Erich Keane via Phabricator via cfe-commits
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

2018-06-11 Thread John McCall via Phabricator via cfe-commits
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

2018-06-11 Thread Erich Keane via Phabricator via cfe-commits
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

2018-06-11 Thread Erich Keane via Phabricator via cfe-commits
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

2018-06-11 Thread Eli Friedman via Phabricator via cfe-commits
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

2018-06-11 Thread Erich Keane via Phabricator via cfe-commits
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

2018-06-11 Thread Eli Friedman via Phabricator via cfe-commits
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

2018-06-11 Thread Erich Keane via Phabricator via cfe-commits
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

2018-06-11 Thread John McCall via Phabricator via cfe-commits
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

2018-06-11 Thread Erich Keane via Phabricator via cfe-commits
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