[clang] [clang] Allow builtin addc/subc to be constant evaluated (PR #81656)
via cfe-commits
cfe-commits at lists.llvm.org
Tue Feb 13 11:56:27 PST 2024
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang
Author: Bryce Wilson (Bryce-MW)
<details>
<summary>Changes</summary>
There is some overlap with `*_overflow` which have the same result as these functions with a carry in of zero, but the type inference and way of returning results is different so it didn't seem worth handling them on the same branch.
These builtins are a little weird in that the carry in and out are the same types as the arguments and allow more than just a 1 or 0 input, so it is possible to carry twice. The way this is implemented in IR ORs the two carries so I copied that.
---
Full diff: https://github.com/llvm/llvm-project/pull/81656.diff
3 Files Affected:
- (modified) clang/docs/LanguageExtensions.rst (+10)
- (modified) clang/include/clang/Basic/Builtins.td (+2-2)
- (modified) clang/lib/AST/ExprConstant.cpp (+48)
``````````diff
diff --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst
index e91156837290f7..e8557a22662c07 100644
--- a/clang/docs/LanguageExtensions.rst
+++ b/clang/docs/LanguageExtensions.rst
@@ -5241,6 +5241,11 @@ Intrinsics Support within Constant Expressions
The following builtin intrinsics can be used in constant expressions:
+* ``__builtin_addcb``
+* ``__builtin_addcs``
+* ``__builtin_addc``
+* ``__builtin_addcl``
+* ``__builtin_addcll``
* ``__builtin_bitreverse8``
* ``__builtin_bitreverse16``
* ``__builtin_bitreverse32``
@@ -5287,6 +5292,11 @@ The following builtin intrinsics can be used in constant expressions:
* ``__builtin_rotateright16``
* ``__builtin_rotateright32``
* ``__builtin_rotateright64``
+* ``__builtin_subcb``
+* ``__builtin_subcs``
+* ``__builtin_subc``
+* ``__builtin_subcl``
+* ``__builtin_subcll``
The following x86-specific intrinsics can be used in constant expressions:
diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td
index 31a2bdeb2d3e5e..59dc0e20393b5f 100644
--- a/clang/include/clang/Basic/Builtins.td
+++ b/clang/include/clang/Basic/Builtins.td
@@ -4061,14 +4061,14 @@ class MPATemplate : Template<
def Addc : Builtin, MPATemplate {
let Spellings = ["__builtin_addc"];
- let Attributes = [NoThrow];
+ let Attributes = [NoThrow, Constexpr];
// FIXME: Why are these argumentes marked const?
let Prototype = "T(T const, T const, T const, T*)";
}
def Subc : Builtin, MPATemplate {
let Spellings = ["__builtin_subc"];
- let Attributes = [NoThrow];
+ let Attributes = [NoThrow, Constexpr];
// FIXME: Why are these argumentes marked const?
let Prototype = "T(T const, T const, T const, T*)";
}
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 089bc2094567f7..b518baec072759 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -12691,6 +12691,54 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
return BuiltinOp == Builtin::BI__atomic_always_lock_free ?
Success(0, E) : Error(E);
}
+ case Builtin::BI__builtin_addcb:
+ case Builtin::BI__builtin_addcs:
+ case Builtin::BI__builtin_addc:
+ case Builtin::BI__builtin_addcl:
+ case Builtin::BI__builtin_addcll:
+ case Builtin::BI__builtin_subcb:
+ case Builtin::BI__builtin_subcs:
+ case Builtin::BI__builtin_subc:
+ case Builtin::BI__builtin_subcl:
+ case Builtin::BI__builtin_subcll: {
+ LValue CarryOutLValue;
+ APSInt LHS, RHS, CarryIn, Result;
+ QualType ResultType = E->getArg(0)->getType();
+ if (!EvaluateInteger(E->getArg(0), LHS, Info) ||
+ !EvaluateInteger(E->getArg(1), RHS, Info) ||
+ !EvaluateInteger(E->getArg(2), CarryIn, Info) ||
+ !EvaluatePointer(E->getArg(3), CarryOutLValue, Info))
+ return false;
+
+ bool FirstOverflowed = false;
+ bool SecondOverflowed = false;
+ switch (BuiltinOp) {
+ default:
+ llvm_unreachable("Invalid value for BuiltinOp");
+ case Builtin::BI__builtin_addcb:
+ case Builtin::BI__builtin_addcs:
+ case Builtin::BI__builtin_addc:
+ case Builtin::BI__builtin_addcl:
+ case Builtin::BI__builtin_addcll:
+ Result = LHS.uadd_ov(RHS, FirstOverflowed).uadd_ov(CarryIn, SecondOverflowed);
+ break;
+ case Builtin::BI__builtin_subcb:
+ case Builtin::BI__builtin_subcs:
+ case Builtin::BI__builtin_subc:
+ case Builtin::BI__builtin_subcl:
+ case Builtin::BI__builtin_subcll:
+ Result = LHS.usub_ov(RHS, FirstOverflowed).usub_ov(CarryIn, SecondOverflowed);
+ break;
+ }
+
+ // It is possible for both overflows to happen but CGBuiltin uses an OR so this is consistent
+ APSInt API{FirstOverflowed | SecondOverflowed};
+ APValue APV{API};
+ if (!handleAssignment(Info, E, CarryOutLValue, ResultType, APV))
+ return false;
+ return Success(Result, E);
+
+ }
case Builtin::BI__builtin_add_overflow:
case Builtin::BI__builtin_sub_overflow:
case Builtin::BI__builtin_mul_overflow:
``````````
</details>
https://github.com/llvm/llvm-project/pull/81656
More information about the cfe-commits
mailing list