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 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits