[clang] [clang][Interp] Implement __builtin_bitreverse (PR #71687)

2023-11-16 Thread Timm Baeder via cfe-commits

https://github.com/tbaederr closed 
https://github.com/llvm/llvm-project/pull/71687
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang][Interp] Implement __builtin_bitreverse (PR #71687)

2023-11-16 Thread Aaron Ballman via cfe-commits


@@ -59,13 +59,54 @@ static void pushInt(InterpState &S, int32_t Val) {
 llvm_unreachable("Int isn't 16 or 32 bit?");
 }
 
-static bool retInt(InterpState &S, CodePtr OpPC, APValue &Result) {
-  PrimType IntType = getIntPrimType(S);
-  if (IntType == PT_Sint32)
-return Ret(S, OpPC, Result);
-  else if (IntType == PT_Sint16)
-return Ret(S, OpPC, Result);
-  llvm_unreachable("Int isn't 16 or 32 bit?");
+static void pushAPSInt(InterpState &S, const APSInt &Val) {
+  bool Signed = Val.isSigned();
+
+  if (Signed) {
+switch (Val.getBitWidth()) {
+case 64:
+  S.Stk.push>(
+  Integral<64, true>::from(Val.getSExtValue()));
+  break;
+case 32:
+  S.Stk.push>(
+  Integral<32, true>::from(Val.getSExtValue()));
+  break;
+case 16:
+  S.Stk.push>(
+  Integral<16, true>::from(Val.getSExtValue()));
+  break;
+case 8:
+  S.Stk.push>(
+  Integral<8, true>::from(Val.getSExtValue()));
+  break;
+default:
+  llvm_unreachable("Invalid integer bitwidth");

AaronBallman wrote:

Yeah, that's the situation I'm worried about (not really specific to bitreverse 
as that only has hardcoded bit widths). However, now that I look at 
builtins.def more closely, most of the ones taking variadic arguments are doing 
so because they have custom type-checking that often disallows 
non-power-of-two-types. So I think we're fine for now, probably.

https://github.com/llvm/llvm-project/pull/71687
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang][Interp] Implement __builtin_bitreverse (PR #71687)

2023-11-16 Thread Aaron Ballman via cfe-commits

https://github.com/AaronBallman approved this pull request.

LGTM

https://github.com/llvm/llvm-project/pull/71687
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang][Interp] Implement __builtin_bitreverse (PR #71687)

2023-11-16 Thread Aaron Ballman via cfe-commits

https://github.com/AaronBallman edited 
https://github.com/llvm/llvm-project/pull/71687
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang][Interp] Implement __builtin_bitreverse (PR #71687)

2023-11-15 Thread Timm Baeder via cfe-commits

https://github.com/tbaederr updated 
https://github.com/llvm/llvm-project/pull/71687

>From f10454ffa4337726e6f3b324a38ffc1fd381b54b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Timm=20B=C3=A4der?= 
Date: Wed, 8 Nov 2023 15:51:44 +0100
Subject: [PATCH] [clang][Interp] Implement __builtin_bitreverse

Since the return value of this function is slightly more involved than
the void/bool/int/size_t return values we've seen so far, also refactor
this.
---
 clang/lib/AST/Interp/InterpBuiltin.cpp  | 207 +---
 clang/test/AST/Interp/builtin-functions.cpp |   7 +
 2 files changed, 147 insertions(+), 67 deletions(-)

diff --git a/clang/lib/AST/Interp/InterpBuiltin.cpp 
b/clang/lib/AST/Interp/InterpBuiltin.cpp
index 8c5efe2df909b34..bb3e13599b01d4e 100644
--- a/clang/lib/AST/Interp/InterpBuiltin.cpp
+++ b/clang/lib/AST/Interp/InterpBuiltin.cpp
@@ -59,13 +59,54 @@ static void pushInt(InterpState &S, int32_t Val) {
 llvm_unreachable("Int isn't 16 or 32 bit?");
 }
 
-static bool retInt(InterpState &S, CodePtr OpPC, APValue &Result) {
-  PrimType IntType = getIntPrimType(S);
-  if (IntType == PT_Sint32)
-return Ret(S, OpPC, Result);
-  else if (IntType == PT_Sint16)
-return Ret(S, OpPC, Result);
-  llvm_unreachable("Int isn't 16 or 32 bit?");
+static void pushAPSInt(InterpState &S, const APSInt &Val) {
+  bool Signed = Val.isSigned();
+
+  if (Signed) {
+switch (Val.getBitWidth()) {
+case 64:
+  S.Stk.push>(
+  Integral<64, true>::from(Val.getSExtValue()));
+  break;
+case 32:
+  S.Stk.push>(
+  Integral<32, true>::from(Val.getSExtValue()));
+  break;
+case 16:
+  S.Stk.push>(
+  Integral<16, true>::from(Val.getSExtValue()));
+  break;
+case 8:
+  S.Stk.push>(
+  Integral<8, true>::from(Val.getSExtValue()));
+  break;
+default:
+  llvm_unreachable("Invalid integer bitwidth");
+}
+return;
+  }
+
+  // Unsigned.
+  switch (Val.getBitWidth()) {
+  case 64:
+S.Stk.push>(
+Integral<64, false>::from(Val.getZExtValue()));
+break;
+  case 32:
+S.Stk.push>(
+Integral<32, false>::from(Val.getZExtValue()));
+break;
+  case 16:
+S.Stk.push>(
+Integral<16, false>::from(Val.getZExtValue()));
+break;
+  case 8:
+S.Stk.push>(
+Integral<8, false>::from(Val.getZExtValue()));
+break;
+  default:
+llvm_unreachable("Invalid integer bitwidth");
+  }
 }
 
 static void pushSizeT(InterpState &S, uint64_t Val) {
@@ -87,20 +128,29 @@ static void pushSizeT(InterpState &S, uint64_t Val) {
   }
 }
 
-static bool retSizeT(InterpState &S, CodePtr OpPC, APValue &Result) {
-  const TargetInfo &TI = S.getCtx().getTargetInfo();
-  unsigned SizeTWidth = TI.getTypeWidth(TI.getSizeType());
-
-  switch (SizeTWidth) {
-  case 64:
-return Ret(S, OpPC, Result);
-  case 32:
-return Ret(S, OpPC, Result);
-  case 16:
-return Ret(S, OpPC, Result);
+static bool retPrimValue(InterpState &S, CodePtr OpPC, APValue &Result,
+ std::optional &T) {
+  if (!T)
+return RetVoid(S, OpPC, Result);
+
+#define RET_CASE(X)
\
+  case X:  
\
+return Ret(S, OpPC, Result);
+  switch (*T) {
+RET_CASE(PT_Float);
+RET_CASE(PT_Bool);
+RET_CASE(PT_Sint8);
+RET_CASE(PT_Uint8);
+RET_CASE(PT_Sint16);
+RET_CASE(PT_Uint16);
+RET_CASE(PT_Sint32);
+RET_CASE(PT_Uint32);
+RET_CASE(PT_Sint64);
+RET_CASE(PT_Uint64);
+  default:
+llvm_unreachable("Unsupported return type for builtin function");
   }
-
-  llvm_unreachable("size_t isn't 64 or 32 bit?");
+#undef RET_CASE
 }
 
 static bool interp__builtin_strcmp(InterpState &S, CodePtr OpPC,
@@ -457,40 +507,55 @@ static bool interp__builtin_clrsb(InterpState &S, CodePtr 
OpPC,
   return true;
 }
 
+static bool interp__builtin_bitreverse(InterpState &S, CodePtr OpPC,
+   const InterpFrame *Frame,
+   const Function *Func,
+   const CallExpr *Call) {
+  PrimType ArgT = *S.getContext().classify(Call->getArg(0)->getType());
+  APSInt Val = peekToAPSInt(S.Stk, ArgT);
+  pushAPSInt(S, APSInt(Val.reverseBits(), /*IsUnsigned=*/true));
+  return true;
+}
+
 bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F,
   const CallExpr *Call) {
   InterpFrame *Frame = S.Current;
   APValue Dummy;
 
+  QualType ReturnType = Call->getCallReturnType(S.getCtx());
+  std::optional ReturnT = S.getContext().classify(ReturnType);
+  // If classify failed, we assume void.
+  assert(ReturnT || ReturnType->isVoidType());
+
   switch (F->getBuiltinID()) {
   case Builtin::BI__builtin_is_constant_evaluated:
 S.Stk.push(Boolean::from(S.inConstantContext()));
-return Ret(S, OpPC, Dummy);
+break;
   case Builtin::BI__builtin_assume:

[clang] [clang][Interp] Implement __builtin_bitreverse (PR #71687)

2023-11-15 Thread Timm Baeder via cfe-commits


@@ -59,13 +59,54 @@ static void pushInt(InterpState &S, int32_t Val) {
 llvm_unreachable("Int isn't 16 or 32 bit?");
 }
 
-static bool retInt(InterpState &S, CodePtr OpPC, APValue &Result) {
-  PrimType IntType = getIntPrimType(S);
-  if (IntType == PT_Sint32)
-return Ret(S, OpPC, Result);
-  else if (IntType == PT_Sint16)
-return Ret(S, OpPC, Result);
-  llvm_unreachable("Int isn't 16 or 32 bit?");
+static void pushAPSInt(InterpState &S, const APSInt &Val) {
+  bool Signed = Val.isSigned();
+
+  if (Signed) {
+switch (Val.getBitWidth()) {
+case 64:
+  S.Stk.push>(
+  Integral<64, true>::from(Val.getSExtValue()));
+  break;
+case 32:
+  S.Stk.push>(
+  Integral<32, true>::from(Val.getSExtValue()));
+  break;
+case 16:
+  S.Stk.push>(
+  Integral<16, true>::from(Val.getSExtValue()));
+  break;
+case 8:
+  S.Stk.push>(
+  Integral<8, true>::from(Val.getSExtValue()));
+  break;
+default:
+  llvm_unreachable("Invalid integer bitwidth");

tbaederr wrote:

I thought BitInt wasn't possible here since the builtins have `l`, `ll`, etc. 
variants... but I guess that's not true for the ones defined as variadic 
functions?

https://github.com/llvm/llvm-project/pull/71687
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang][Interp] Implement __builtin_bitreverse (PR #71687)

2023-11-15 Thread Aaron Ballman via cfe-commits


@@ -59,13 +59,54 @@ static void pushInt(InterpState &S, int32_t Val) {
 llvm_unreachable("Int isn't 16 or 32 bit?");
 }
 
-static bool retInt(InterpState &S, CodePtr OpPC, APValue &Result) {
-  PrimType IntType = getIntPrimType(S);
-  if (IntType == PT_Sint32)
-return Ret(S, OpPC, Result);
-  else if (IntType == PT_Sint16)
-return Ret(S, OpPC, Result);
-  llvm_unreachable("Int isn't 16 or 32 bit?");
+static void pushAPSInt(InterpState &S, const APSInt &Val) {
+  bool Signed = Val.isSigned();
+
+  if (Signed) {
+switch (Val.getBitWidth()) {
+case 64:
+  S.Stk.push>(
+  Integral<64, true>::from(Val.getSExtValue()));
+  break;
+case 32:
+  S.Stk.push>(
+  Integral<32, true>::from(Val.getSExtValue()));
+  break;
+case 16:
+  S.Stk.push>(
+  Integral<16, true>::from(Val.getSExtValue()));
+  break;
+case 8:
+  S.Stk.push>(
+  Integral<8, true>::from(Val.getSExtValue()));
+  break;
+default:
+  llvm_unreachable("Invalid integer bitwidth");

AaronBallman wrote:

`_BitInt`?

Not that you need to support it in this patch, but I do wonder if this design 
is painting us into a corner.

https://github.com/llvm/llvm-project/pull/71687
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang][Interp] Implement __builtin_bitreverse (PR #71687)

2023-11-15 Thread Aaron Ballman via cfe-commits

https://github.com/AaronBallman approved this pull request.

The changes seem reasonable to me but I think we should start putting some 
effort in to support _BitInt because I have a sneaking suspicion that will be 
hard to support with all the power-of-two literals being used, and the more 
integer handling code we add, the harder it will be to support in the future. 
WDYT?

https://github.com/llvm/llvm-project/pull/71687
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang][Interp] Implement __builtin_bitreverse (PR #71687)

2023-11-15 Thread Aaron Ballman via cfe-commits

https://github.com/AaronBallman edited 
https://github.com/llvm/llvm-project/pull/71687
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang][Interp] Implement __builtin_bitreverse (PR #71687)

2023-11-13 Thread Timm Baeder via cfe-commits

tbaederr wrote:

Ping

https://github.com/llvm/llvm-project/pull/71687
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang][Interp] Implement __builtin_bitreverse (PR #71687)

2023-11-08 Thread via cfe-commits

llvmbot wrote:




@llvm/pr-subscribers-clang

Author: Timm Baeder (tbaederr)


Changes

Since the return value of this function is slightly more involved than the 
void/bool/int/size_t return values we've seen so far, also refactor this.

---
Full diff: https://github.com/llvm/llvm-project/pull/71687.diff


2 Files Affected:

- (modified) clang/lib/AST/Interp/InterpBuiltin.cpp (+136-63) 
- (modified) clang/test/AST/Interp/builtin-functions.cpp (+7) 


``diff
diff --git a/clang/lib/AST/Interp/InterpBuiltin.cpp 
b/clang/lib/AST/Interp/InterpBuiltin.cpp
index f26d298f5b60045..b5a9af7e334624e 100644
--- a/clang/lib/AST/Interp/InterpBuiltin.cpp
+++ b/clang/lib/AST/Interp/InterpBuiltin.cpp
@@ -59,13 +59,54 @@ static void pushInt(InterpState &S, int32_t Val) {
 llvm_unreachable("Int isn't 16 or 32 bit?");
 }
 
-static bool retInt(InterpState &S, CodePtr OpPC, APValue &Result) {
-  PrimType IntType = getIntPrimType(S);
-  if (IntType == PT_Sint32)
-return Ret(S, OpPC, Result);
-  else if (IntType == PT_Sint16)
-return Ret(S, OpPC, Result);
-  llvm_unreachable("Int isn't 16 or 32 bit?");
+static void pushAPSInt(InterpState &S, const APSInt &Val) {
+  bool Signed = Val.isSigned();
+
+  if (Signed) {
+switch (Val.getBitWidth()) {
+case 64:
+  S.Stk.push>(
+  Integral<64, true>::from(Val.getSExtValue()));
+  break;
+case 32:
+  S.Stk.push>(
+  Integral<32, true>::from(Val.getSExtValue()));
+  break;
+case 16:
+  S.Stk.push>(
+  Integral<16, true>::from(Val.getSExtValue()));
+  break;
+case 8:
+  S.Stk.push>(
+  Integral<8, true>::from(Val.getSExtValue()));
+  break;
+default:
+  llvm_unreachable("Invalid integer bitwidth");
+}
+return;
+  }
+
+  // Unsigned.
+  switch (Val.getBitWidth()) {
+  case 64:
+S.Stk.push>(
+Integral<64, false>::from(Val.getZExtValue()));
+break;
+  case 32:
+S.Stk.push>(
+Integral<32, false>::from(Val.getZExtValue()));
+break;
+  case 16:
+S.Stk.push>(
+Integral<16, false>::from(Val.getZExtValue()));
+break;
+  case 8:
+S.Stk.push>(
+Integral<8, false>::from(Val.getZExtValue()));
+break;
+  default:
+llvm_unreachable("Invalid integer bitwidth");
+  }
 }
 
 static void pushSizeT(InterpState &S, uint64_t Val) {
@@ -87,20 +128,29 @@ static void pushSizeT(InterpState &S, uint64_t Val) {
   }
 }
 
-static bool retSizeT(InterpState &S, CodePtr OpPC, APValue &Result) {
-  const TargetInfo &TI = S.getCtx().getTargetInfo();
-  unsigned SizeTWidth = TI.getTypeWidth(TI.getSizeType());
-
-  switch (SizeTWidth) {
-  case 64:
-return Ret(S, OpPC, Result);
-  case 32:
-return Ret(S, OpPC, Result);
-  case 16:
-return Ret(S, OpPC, Result);
+static bool retPrimValue(InterpState &S, CodePtr OpPC, APValue &Result,
+ std::optional &T) {
+  if (!T)
+return RetVoid(S, OpPC, Result);
+
+#define RET_CASE(X)
\
+  case X:  
\
+return Ret(S, OpPC, Result);
+  switch (*T) {
+RET_CASE(PT_Float);
+RET_CASE(PT_Bool);
+RET_CASE(PT_Sint8);
+RET_CASE(PT_Uint8);
+RET_CASE(PT_Sint16);
+RET_CASE(PT_Uint16);
+RET_CASE(PT_Sint32);
+RET_CASE(PT_Uint32);
+RET_CASE(PT_Sint64);
+RET_CASE(PT_Uint64);
+  default:
+llvm_unreachable("Unsupported return type for builtin function");
   }
-
-  llvm_unreachable("size_t isn't 64 or 32 bit?");
+#undef RET_CASE
 }
 
 static bool interp__builtin_strcmp(InterpState &S, CodePtr OpPC,
@@ -439,40 +489,55 @@ static bool interp__builtin_popcount(InterpState &S, 
CodePtr OpPC,
   return true;
 }
 
+static bool interp__builtin_bitreverse(InterpState &S, CodePtr OpPC,
+   const InterpFrame *Frame,
+   const Function *Func,
+   const CallExpr *Call) {
+  PrimType ArgT = *S.getContext().classify(Call->getArg(0)->getType());
+  APSInt Val = peekToAPSInt(S.Stk, ArgT);
+  pushAPSInt(S, APSInt(Val.reverseBits(), /*IsUnsigend=*/true));
+  return true;
+}
+
 bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F,
   const CallExpr *Call) {
   InterpFrame *Frame = S.Current;
   APValue Dummy;
 
+  QualType ReturnType = Call->getCallReturnType(S.getCtx());
+  std::optional ReturnT = S.getContext().classify(ReturnType);
+  // If classify failed, we assume void.
+  assert(ReturnT || ReturnType->isVoidType());
+
   switch (F->getBuiltinID()) {
   case Builtin::BI__builtin_is_constant_evaluated:
 S.Stk.push(Boolean::from(S.inConstantContext()));
-return Ret(S, OpPC, Dummy);
+break;
   case Builtin::BI__builtin_assume:
-return RetVoid(S, OpPC, Dummy);
+break;
   case Builtin::BI__builtin_strcmp:
-if (interp__builtin_strcmp(S, OpPC, Frame))
-  return retI

[clang] [clang][Interp] Implement __builtin_bitreverse (PR #71687)

2023-11-08 Thread Timm Baeder via cfe-commits

https://github.com/tbaederr created 
https://github.com/llvm/llvm-project/pull/71687

Since the return value of this function is slightly more involved than the 
void/bool/int/size_t return values we've seen so far, also refactor this.

>From 140555c8af75fcf117d10d7877f4cd248b9f7480 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Timm=20B=C3=A4der?= 
Date: Wed, 8 Nov 2023 15:51:44 +0100
Subject: [PATCH] [clang][Interp] Implement __builtin_bitreverse

Since the return value of this function is slightly more involved than
the void/bool/int/size_t return values we've seen so far, also refactor
this.
---
 clang/lib/AST/Interp/InterpBuiltin.cpp  | 199 +---
 clang/test/AST/Interp/builtin-functions.cpp |   7 +
 2 files changed, 143 insertions(+), 63 deletions(-)

diff --git a/clang/lib/AST/Interp/InterpBuiltin.cpp 
b/clang/lib/AST/Interp/InterpBuiltin.cpp
index f26d298f5b60045..b5a9af7e334624e 100644
--- a/clang/lib/AST/Interp/InterpBuiltin.cpp
+++ b/clang/lib/AST/Interp/InterpBuiltin.cpp
@@ -59,13 +59,54 @@ static void pushInt(InterpState &S, int32_t Val) {
 llvm_unreachable("Int isn't 16 or 32 bit?");
 }
 
-static bool retInt(InterpState &S, CodePtr OpPC, APValue &Result) {
-  PrimType IntType = getIntPrimType(S);
-  if (IntType == PT_Sint32)
-return Ret(S, OpPC, Result);
-  else if (IntType == PT_Sint16)
-return Ret(S, OpPC, Result);
-  llvm_unreachable("Int isn't 16 or 32 bit?");
+static void pushAPSInt(InterpState &S, const APSInt &Val) {
+  bool Signed = Val.isSigned();
+
+  if (Signed) {
+switch (Val.getBitWidth()) {
+case 64:
+  S.Stk.push>(
+  Integral<64, true>::from(Val.getSExtValue()));
+  break;
+case 32:
+  S.Stk.push>(
+  Integral<32, true>::from(Val.getSExtValue()));
+  break;
+case 16:
+  S.Stk.push>(
+  Integral<16, true>::from(Val.getSExtValue()));
+  break;
+case 8:
+  S.Stk.push>(
+  Integral<8, true>::from(Val.getSExtValue()));
+  break;
+default:
+  llvm_unreachable("Invalid integer bitwidth");
+}
+return;
+  }
+
+  // Unsigned.
+  switch (Val.getBitWidth()) {
+  case 64:
+S.Stk.push>(
+Integral<64, false>::from(Val.getZExtValue()));
+break;
+  case 32:
+S.Stk.push>(
+Integral<32, false>::from(Val.getZExtValue()));
+break;
+  case 16:
+S.Stk.push>(
+Integral<16, false>::from(Val.getZExtValue()));
+break;
+  case 8:
+S.Stk.push>(
+Integral<8, false>::from(Val.getZExtValue()));
+break;
+  default:
+llvm_unreachable("Invalid integer bitwidth");
+  }
 }
 
 static void pushSizeT(InterpState &S, uint64_t Val) {
@@ -87,20 +128,29 @@ static void pushSizeT(InterpState &S, uint64_t Val) {
   }
 }
 
-static bool retSizeT(InterpState &S, CodePtr OpPC, APValue &Result) {
-  const TargetInfo &TI = S.getCtx().getTargetInfo();
-  unsigned SizeTWidth = TI.getTypeWidth(TI.getSizeType());
-
-  switch (SizeTWidth) {
-  case 64:
-return Ret(S, OpPC, Result);
-  case 32:
-return Ret(S, OpPC, Result);
-  case 16:
-return Ret(S, OpPC, Result);
+static bool retPrimValue(InterpState &S, CodePtr OpPC, APValue &Result,
+ std::optional &T) {
+  if (!T)
+return RetVoid(S, OpPC, Result);
+
+#define RET_CASE(X)
\
+  case X:  
\
+return Ret(S, OpPC, Result);
+  switch (*T) {
+RET_CASE(PT_Float);
+RET_CASE(PT_Bool);
+RET_CASE(PT_Sint8);
+RET_CASE(PT_Uint8);
+RET_CASE(PT_Sint16);
+RET_CASE(PT_Uint16);
+RET_CASE(PT_Sint32);
+RET_CASE(PT_Uint32);
+RET_CASE(PT_Sint64);
+RET_CASE(PT_Uint64);
+  default:
+llvm_unreachable("Unsupported return type for builtin function");
   }
-
-  llvm_unreachable("size_t isn't 64 or 32 bit?");
+#undef RET_CASE
 }
 
 static bool interp__builtin_strcmp(InterpState &S, CodePtr OpPC,
@@ -439,40 +489,55 @@ static bool interp__builtin_popcount(InterpState &S, 
CodePtr OpPC,
   return true;
 }
 
+static bool interp__builtin_bitreverse(InterpState &S, CodePtr OpPC,
+   const InterpFrame *Frame,
+   const Function *Func,
+   const CallExpr *Call) {
+  PrimType ArgT = *S.getContext().classify(Call->getArg(0)->getType());
+  APSInt Val = peekToAPSInt(S.Stk, ArgT);
+  pushAPSInt(S, APSInt(Val.reverseBits(), /*IsUnsigend=*/true));
+  return true;
+}
+
 bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F,
   const CallExpr *Call) {
   InterpFrame *Frame = S.Current;
   APValue Dummy;
 
+  QualType ReturnType = Call->getCallReturnType(S.getCtx());
+  std::optional ReturnT = S.getContext().classify(ReturnType);
+  // If classify failed, we assume void.
+  assert(ReturnT || ReturnType->isVoidType());
+
   switch (F->getBuiltinID()) {
   case Builtin::BI__builtin_is_co