Skip to content

Commit

Permalink
[clang][Interp] Implement builtin_expect (#69713)
Browse files Browse the repository at this point in the history
  • Loading branch information
tbaederr committed Dec 8, 2023
1 parent 61f1825 commit d5e2cbd
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 0 deletions.
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) {
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

0 comments on commit d5e2cbd

Please sign in to comment.