Skip to content

Commit d5e2cbd

Browse files
authored
[clang][Interp] Implement builtin_expect (#69713)
1 parent 61f1825 commit d5e2cbd

File tree

3 files changed

+61
-0
lines changed

3 files changed

+61
-0
lines changed

clang/lib/AST/Interp/InterpBuiltin.cpp

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,19 @@ PrimType getIntPrimType(const InterpState &S) {
3434
llvm_unreachable("Int isn't 16 or 32 bit?");
3535
}
3636

37+
PrimType getLongPrimType(const InterpState &S) {
38+
const TargetInfo &TI = S.getCtx().getTargetInfo();
39+
unsigned LongWidth = TI.getLongWidth();
40+
41+
if (LongWidth == 64)
42+
return PT_Sint64;
43+
else if (LongWidth == 32)
44+
return PT_Sint32;
45+
else if (LongWidth == 16)
46+
return PT_Sint16;
47+
llvm_unreachable("long isn't 16, 32 or 64 bit?");
48+
}
49+
3750
/// Peek an integer value from the stack into an APSInt.
3851
static APSInt peekToAPSInt(InterpStack &Stk, PrimType T, size_t Offset = 0) {
3952
if (Offset == 0)
@@ -110,6 +123,19 @@ static void pushAPSInt(InterpState &S, const APSInt &Val) {
110123
}
111124
}
112125

126+
/// Pushes \p Val to the stack, as a target-dependent 'long'.
127+
static void pushLong(InterpState &S, int64_t Val) {
128+
PrimType LongType = getLongPrimType(S);
129+
if (LongType == PT_Sint64)
130+
S.Stk.push<Integral<64, true>>(Integral<64, true>::from(Val));
131+
else if (LongType == PT_Sint32)
132+
S.Stk.push<Integral<32, true>>(Integral<32, true>::from(Val));
133+
else if (LongType == PT_Sint16)
134+
S.Stk.push<Integral<16, true>>(Integral<16, true>::from(Val));
135+
else
136+
llvm_unreachable("Long isn't 16, 32 or 64 bit?");
137+
}
138+
113139
static void pushSizeT(InterpState &S, uint64_t Val) {
114140
const TargetInfo &TI = S.getCtx().getTargetInfo();
115141
unsigned SizeTWidth = TI.getTypeWidth(TI.getSizeType());
@@ -533,6 +559,26 @@ static bool interp__builtin_classify_type(InterpState &S, CodePtr OpPC,
533559
return true;
534560
}
535561

562+
// __builtin_expect(long, long)
563+
// __builtin_expect_with_probability(long, long, double)
564+
static bool interp__builtin_expect(InterpState &S, CodePtr OpPC,
565+
const InterpFrame *Frame,
566+
const Function *Func, const CallExpr *Call) {
567+
// The return value is simply the value of the first parameter.
568+
// We ignore the probability.
569+
unsigned NumArgs = Call->getNumArgs();
570+
assert(NumArgs == 2 || NumArgs == 3);
571+
572+
PrimType ArgT = *S.getContext().classify(Call->getArg(0)->getType());
573+
unsigned Offset = align(primSize(getLongPrimType(S))) * 2;
574+
if (NumArgs == 3)
575+
Offset += align(primSize(PT_Float));
576+
577+
APSInt Val = peekToAPSInt(S.Stk, ArgT, Offset);
578+
pushLong(S, Val.getSExtValue());
579+
return true;
580+
}
581+
536582
bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F,
537583
const CallExpr *Call) {
538584
InterpFrame *Frame = S.Current;
@@ -702,6 +748,12 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F,
702748
return false;
703749
break;
704750

751+
case Builtin::BI__builtin_expect:
752+
case Builtin::BI__builtin_expect_with_probability:
753+
if (!interp__builtin_expect(S, OpPC, Frame, F, Call))
754+
return false;
755+
break;
756+
705757
default:
706758
return false;
707759
}

clang/test/AST/Interp/builtin-functions.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -331,3 +331,11 @@ namespace bitreverse {
331331
char bitreverse3[__builtin_bitreverse32(0x12345678) == 0x1E6A2C48 ? 1 : -1];
332332
char bitreverse4[__builtin_bitreverse64(0x0123456789ABCDEFULL) == 0xF7B3D591E6A2C480 ? 1 : -1];
333333
}
334+
335+
namespace expect {
336+
constexpr int a() {
337+
return 12;
338+
}
339+
static_assert(__builtin_expect(a(),1) == 12, "");
340+
static_assert(__builtin_expect_with_probability(a(), 1, 1.0) == 12, "");
341+
}

clang/test/Sema/builtin-expect-with-probability.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
// RUN: %clang_cc1 -fsyntax-only -verify %s
2+
// RUN: %clang_cc1 -fsyntax-only -verify -fexperimental-new-constant-interpreter %s
23

34
__attribute__((noreturn)) extern void bar();
45

0 commit comments

Comments
 (0)