[clang] [clang] Allow __builtin_unpredictable in constant expressions (PR #228256)
Paweł Bylica via cfe-commits
cfe-commits at lists.llvm.org
Thu Oct 22 03:07:56 PDT 2026
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?= <pawel at hepcolgum.band>
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 {
More information about the cfe-commits
mailing list