https://github.com/chfast updated https://github.com/llvm/llvm-project/pull/228256
From 994960fc1d8ecc5da1a6fb5dd83fe4b329bcd2ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= <[email protected]> Date: Thu, 1 Oct 2026 14:51:38 +0200 Subject: [PATCH] [clang] Allow __builtin_unpredictable in constant expressions __builtin_unpredictable returns its argument, but unlike __builtin_expect and __builtin_expect_with_probability it was not marked Constexpr. Using it in a constexpr function made the function never produce a constant expression: constexpr int f(int x) { if (__builtin_unpredictable(x > 0)) return 1; return 2; } static_assert(f(1) == 1); Evaluate it to its argument in both constant evaluators, like __builtin_expect. Assisted-by: Claude Code --- clang/docs/LanguageExtensions.md | 3 ++- clang/docs/ReleaseNotes.md | 3 +++ clang/include/clang/Basic/Builtins.td | 2 +- clang/lib/AST/ByteCode/InterpBuiltin.cpp | 9 ++++++--- clang/lib/AST/ExprConstant.cpp | 1 + clang/test/AST/ByteCode/builtin-functions.cpp | 9 +++++++++ 6 files changed, 22 insertions(+), 5 deletions(-) diff --git a/clang/docs/LanguageExtensions.md b/clang/docs/LanguageExtensions.md index 3db8d083c40756..a1c6e48b5f26dc 100644 --- a/clang/docs/LanguageExtensions.md +++ b/clang/docs/LanguageExtensions.md @@ -3921,7 +3921,8 @@ if (__builtin_unpredictable(x > 0)) { **Description**: The `__builtin_unpredictable()` builtin is expected to be used with control -flow conditions such as in `if` and `switch` statements. +flow conditions such as in `if` and `switch` statements. It returns its +argument and can be used in constant expressions. Query for this feature with `__has_builtin(__builtin_unpredictable)`. diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md index 7fe9977a979c0d..1fbd6b07688ebb 100644 --- a/clang/docs/ReleaseNotes.md +++ b/clang/docs/ReleaseNotes.md @@ -339,6 +339,9 @@ documentation](CIR/index.md) for more information regarding ClangIR's status and be detected by watching the directories or by comparing their modification times. +- `__builtin_unpredictable` can now be used in constant expressions, like + `__builtin_expect`. + ### New Compiler Flags - New option `-fmodules-validate-directory-dependencies` makes an implicitly diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td index 905c5d29d86e1f..ae0fd5a075c6e2 100644 --- a/clang/include/clang/Basic/Builtins.td +++ b/clang/include/clang/Basic/Builtins.td @@ -1444,7 +1444,7 @@ def VPrintfChk : Builtin { def Unpredictable : Builtin { let Spellings = ["__builtin_unpredictable"]; - let Attributes = [NoThrow, Const]; + let Attributes = [NoThrow, Const, Constexpr]; let Prototype = "long int(long int)"; } diff --git a/clang/lib/AST/ByteCode/InterpBuiltin.cpp b/clang/lib/AST/ByteCode/InterpBuiltin.cpp index 96d8cf9b175943..5131ff728ebc39 100644 --- a/clang/lib/AST/ByteCode/InterpBuiltin.cpp +++ b/clang/lib/AST/ByteCode/InterpBuiltin.cpp @@ -857,18 +857,20 @@ static bool interp__builtin_classify_type(InterpState &S, CodePtr OpPC, // __builtin_expect(long, long) // __builtin_expect_with_probability(long, long, double) +// __builtin_unpredictable(long) static bool interp__builtin_expect(InterpState &S, CodePtr OpPC, const InterpFrame *Frame, const CallExpr *Call) { // The return value is simply the value of the first parameter. - // We ignore the probability. + // We ignore the expected value and the probability. unsigned NumArgs = Call->getNumArgs(); - assert(NumArgs == 2 || NumArgs == 3); + assert(NumArgs >= 1 && NumArgs <= 3); PrimType ArgT = *S.getContext().classify(Call->getArg(0)->getType()); if (NumArgs == 3) S.Stk.discard<Floating>(); - discard(S.Stk, ArgT); + if (NumArgs >= 2) + discard(S.Stk, ArgT); // Top of the stack is now the first paramter. Leave it there as the return // value. @@ -4967,6 +4969,7 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const CallExpr *Call, case Builtin::BI__builtin_expect: case Builtin::BI__builtin_expect_with_probability: + case Builtin::BI__builtin_unpredictable: return interp__builtin_expect(S, OpPC, Frame, Call); case Builtin::BI__builtin_rotateleft8: diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index f7e892c6364e5e..a0b2e06b02a1bb 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -17640,6 +17640,7 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E, case Builtin::BI__builtin_expect: case Builtin::BI__builtin_expect_with_probability: + case Builtin::BI__builtin_unpredictable: return Visit(E->getArg(0)); case Builtin::BI__builtin_ptrauth_string_discriminator: { diff --git a/clang/test/AST/ByteCode/builtin-functions.cpp b/clang/test/AST/ByteCode/builtin-functions.cpp index 9077a14324b7f5..3295e881956fb3 100644 --- a/clang/test/AST/ByteCode/builtin-functions.cpp +++ b/clang/test/AST/ByteCode/builtin-functions.cpp @@ -625,6 +625,15 @@ namespace expect { } static_assert(__builtin_expect(a(),1) == 12, ""); static_assert(__builtin_expect_with_probability(a(), 1, 1.0) == 12, ""); + static_assert(__builtin_unpredictable(a()) == 12, ""); + + constexpr int b(int x) { + if (__builtin_unpredictable(x > 0)) + return 1; + return 2; + } + static_assert(b(1) == 1, ""); + static_assert(b(-1) == 2, ""); } namespace rotateleft { _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
