Skip to content

[clang][Interp] Implement builtin_expect #69713

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Dec 8, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 52 additions & 0 deletions clang/lib/AST/Interp/InterpBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,19 @@ PrimType getIntPrimType(const InterpState &S) {
llvm_unreachable("Int isn't 16 or 32 bit?");
}

PrimType getLongPrimType(const InterpState &S) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't suppose we can merge with getIntPrimType ?

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)
Expand Down Expand Up @@ -110,6 +123,19 @@ static void pushAPSInt(InterpState &S, const APSInt &Val) {
}
}

/// 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 void pushSizeT(InterpState &S, uint64_t Val) {
const TargetInfo &TI = S.getCtx().getTargetInfo();
unsigned SizeTWidth = TI.getTypeWidth(TI.getSizeType());
Expand Down Expand Up @@ -533,6 +559,26 @@ static bool interp__builtin_classify_type(InterpState &S, CodePtr OpPC,
return true;
}

// __builtin_expect(long, long)
// __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();
assert(NumArgs == 2 || NumArgs == 3);

PrimType ArgT = *S.getContext().classify(Call->getArg(0)->getType());
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;
Expand Down Expand Up @@ -702,6 +748,12 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F,
return false;
break;

case Builtin::BI__builtin_expect:
case Builtin::BI__builtin_expect_with_probability:
if (!interp__builtin_expect(S, OpPC, Frame, F, Call))
return false;
break;

default:
return false;
}
Expand Down
8 changes: 8 additions & 0 deletions clang/test/AST/Interp/builtin-functions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -331,3 +331,11 @@ namespace bitreverse {
char bitreverse3[__builtin_bitreverse32(0x12345678) == 0x1E6A2C48 ? 1 : -1];
char bitreverse4[__builtin_bitreverse64(0x0123456789ABCDEFULL) == 0xF7B3D591E6A2C480 ? 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, "");
}
1 change: 1 addition & 0 deletions clang/test/Sema/builtin-expect-with-probability.cpp
Original file line number Diff line number Diff line change
@@ -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();

Expand Down