[clang] [clang][Interp] Implement builtin_expect (PR #69713)
Timm Baeder via cfe-commits
cfe-commits at lists.llvm.org
Sat Oct 21 10:11:06 PDT 2023
https://github.com/tbaederr updated https://github.com/llvm/llvm-project/pull/69713
>From 1d60343ec3acb89764ab56a7035e1d7355e741ed Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Timm=20B=C3=A4der?= <tbaeder at redhat.com>
Date: Fri, 20 Oct 2023 14:16:22 +0200
Subject: [PATCH] [clang][Interp] Implement builtin_expect
---
clang/lib/AST/Interp/InterpBuiltin.cpp | 64 +++++++++++++++++++
clang/test/AST/Interp/builtin-functions.cpp | 8 +++
.../Sema/builtin-expect-with-probability.cpp | 1 +
3 files changed, 73 insertions(+)
diff --git a/clang/lib/AST/Interp/InterpBuiltin.cpp b/clang/lib/AST/Interp/InterpBuiltin.cpp
index 7552c1b88cff60c..48678b468e82ed5 100644
--- a/clang/lib/AST/Interp/InterpBuiltin.cpp
+++ b/clang/lib/AST/Interp/InterpBuiltin.cpp
@@ -33,6 +33,19 @@ PrimType getIntPrimType(const InterpState &S) {
llvm_unreachable("Int isn't 16 or 32 bit?");
}
+PrimType getLongPrimType(const InterpState &S) {
+ const TargetInfo &TI = S.getCtx().getTargetInfo();
+ unsigned LongWidth = TI.getLongWidth();
+
+ if (LongWidth == 64)
+ return PT_Sint64;
+ else if (LongWidth == 32)
+ return PT_Sint32;
+ else if (LongWidth == 16)
+ return PT_Sint16;
+ llvm_unreachable("long isn't 16, 32 or 64 bit?");
+}
+
/// Peek an integer value from the stack into an APSInt.
static APSInt peekToAPSInt(InterpStack &Stk, PrimType T, size_t Offset = 0) {
if (Offset == 0)
@@ -59,6 +72,19 @@ static void pushInt(InterpState &S, int32_t Val) {
llvm_unreachable("Int isn't 16 or 32 bit?");
}
+/// Pushes \p Val to the stack, as a target-dependent 'long'.
+static void pushLong(InterpState &S, int64_t Val) {
+ PrimType LongType = getLongPrimType(S);
+ if (LongType == PT_Sint64)
+ S.Stk.push<Integral<64, true>>(Integral<64, true>::from(Val));
+ else if (LongType == PT_Sint32)
+ S.Stk.push<Integral<32, true>>(Integral<32, true>::from(Val));
+ else if (LongType == PT_Sint16)
+ S.Stk.push<Integral<16, true>>(Integral<16, true>::from(Val));
+ else
+ llvm_unreachable("Long isn't 16, 32 or 64 bit?");
+}
+
static bool retInt(InterpState &S, CodePtr OpPC, APValue &Result) {
PrimType IntType = getIntPrimType(S);
if (IntType == PT_Sint32)
@@ -68,6 +94,17 @@ static bool retInt(InterpState &S, CodePtr OpPC, APValue &Result) {
llvm_unreachable("Int isn't 16 or 32 bit?");
}
+static bool retLong(InterpState &S, CodePtr OpPC, APValue &Result) {
+ PrimType LongType = getLongPrimType(S);
+ if (LongType == PT_Sint64)
+ return Ret<PT_Sint64>(S, OpPC, Result);
+ else if (LongType == PT_Sint32)
+ return Ret<PT_Sint32>(S, OpPC, Result);
+ else if (LongType == PT_Sint16)
+ return Ret<PT_Sint16>(S, OpPC, Result);
+ llvm_unreachable("Int isn't 16 or 32 bit?");
+}
+
static void pushSizeT(InterpState &S, uint64_t Val) {
const TargetInfo &TI = S.getCtx().getTargetInfo();
unsigned SizeTWidth = TI.getTypeWidth(TI.getSizeType());
@@ -409,6 +446,27 @@ static bool interp__builtin_popcount(InterpState &S, CodePtr OpPC,
return true;
}
+// __builtin_expect(long, long) or
+// __builtin_expect_with_probability(long, long, double)
+static bool interp__builtin_expect(InterpState &S, CodePtr OpPC,
+ const InterpFrame *Frame,
+ const Function *Func, const CallExpr *Call) {
+ // The return value is simply the value of the first parameter.
+ // We ignore the probability.
+ unsigned NumArgs = Call->getNumArgs();
+ PrimType ArgT = *S.getContext().classify(Call->getArg(0)->getType());
+
+ assert(NumArgs == 2 || NumArgs == 3);
+
+ unsigned Offset = align(primSize(getLongPrimType(S))) * 2;
+ if (NumArgs == 3)
+ Offset += align(primSize(PT_Float));
+
+ APSInt Val = peekToAPSInt(S.Stk, ArgT, Offset);
+ pushLong(S, Val.getSExtValue());
+ return true;
+}
+
bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F,
const CallExpr *Call) {
InterpFrame *Frame = S.Current;
@@ -534,6 +592,12 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F,
return retInt(S, OpPC, Dummy);
break;
+ case Builtin::BI__builtin_expect:
+ case Builtin::BI__builtin_expect_with_probability:
+ if (interp__builtin_expect(S, OpPC, Frame, F, Call))
+ return retLong(S, OpPC, Dummy);
+ break;
+
default:
return false;
}
diff --git a/clang/test/AST/Interp/builtin-functions.cpp b/clang/test/AST/Interp/builtin-functions.cpp
index 65361d67d68d578..d928b494a5204a6 100644
--- a/clang/test/AST/Interp/builtin-functions.cpp
+++ b/clang/test/AST/Interp/builtin-functions.cpp
@@ -282,3 +282,11 @@ namespace popcount {
char popcount9[__builtin_popcountll(0xF0F0LL) == 8 ? 1 : -1];
char popcount10[__builtin_popcountll(~0LL) == BITSIZE(long long) ? 1 : -1];
}
+
+namespace expect {
+ constexpr int a() {
+ return 12;
+ }
+ static_assert(__builtin_expect(a(),1) == 12, "");
+ static_assert(__builtin_expect_with_probability(a(), 1, 1.0) == 12, "");
+}
diff --git a/clang/test/Sema/builtin-expect-with-probability.cpp b/clang/test/Sema/builtin-expect-with-probability.cpp
index 2b72c7b27ae93e8..c55cde84b254834 100644
--- a/clang/test/Sema/builtin-expect-with-probability.cpp
+++ b/clang/test/Sema/builtin-expect-with-probability.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -fexperimental-new-constant-interpreter %s
__attribute__((noreturn)) extern void bar();
More information about the cfe-commits
mailing list