[clang] 3defe8f - [clang][Interp] Implement __builtin_bitreverse (#71687)
via cfe-commits
cfe-commits at lists.llvm.org
Thu Nov 16 23:29:17 PST 2023
Author: Timm Baeder
Date: 2023-11-17T08:29:13+01:00
New Revision: 3defe8facc55431c040f964802588473e2d4452b
URL: https://github.com/llvm/llvm-project/commit/3defe8facc55431c040f964802588473e2d4452b
DIFF: https://github.com/llvm/llvm-project/commit/3defe8facc55431c040f964802588473e2d4452b.diff
LOG: [clang][Interp] Implement __builtin_bitreverse (#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.
Added:
Modified:
clang/lib/AST/Interp/InterpBuiltin.cpp
clang/test/AST/Interp/builtin-functions.cpp
Removed:
################################################################################
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<PT_Sint32>(S, OpPC, Result);
- else if (IntType == PT_Sint16)
- return Ret<PT_Sint16>(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>>(
+ Integral<64, true>::from(Val.getSExtValue()));
+ break;
+ case 32:
+ S.Stk.push<Integral<32, true>>(
+ Integral<32, true>::from(Val.getSExtValue()));
+ break;
+ case 16:
+ S.Stk.push<Integral<16, true>>(
+ Integral<16, true>::from(Val.getSExtValue()));
+ break;
+ case 8:
+ S.Stk.push<Integral<8, true>>(
+ 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>>(
+ Integral<64, false>::from(Val.getZExtValue()));
+ break;
+ case 32:
+ S.Stk.push<Integral<32, false>>(
+ Integral<32, false>::from(Val.getZExtValue()));
+ break;
+ case 16:
+ S.Stk.push<Integral<16, false>>(
+ Integral<16, false>::from(Val.getZExtValue()));
+ break;
+ case 8:
+ S.Stk.push<Integral<8, false>>(
+ 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<PT_Uint64>(S, OpPC, Result);
- case 32:
- return Ret<PT_Uint32>(S, OpPC, Result);
- case 16:
- return Ret<PT_Uint16>(S, OpPC, Result);
+static bool retPrimValue(InterpState &S, CodePtr OpPC, APValue &Result,
+ std::optional<PrimType> &T) {
+ if (!T)
+ return RetVoid(S, OpPC, Result);
+
+#define RET_CASE(X) \
+ case X: \
+ return Ret<X>(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<PrimType> 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>(Boolean::from(S.inConstantContext()));
- return Ret<PT_Bool>(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 retInt(S, OpPC, Dummy);
+ if (!interp__builtin_strcmp(S, OpPC, Frame))
+ return false;
break;
case Builtin::BI__builtin_strlen:
- if (interp__builtin_strlen(S, OpPC, Frame))
- return retSizeT(S, OpPC, Dummy);
+ if (!interp__builtin_strlen(S, OpPC, Frame))
+ return false;
break;
case Builtin::BI__builtin_nan:
case Builtin::BI__builtin_nanf:
case Builtin::BI__builtin_nanl:
case Builtin::BI__builtin_nanf16:
case Builtin::BI__builtin_nanf128:
- if (interp__builtin_nan(S, OpPC, Frame, F, /*Signaling=*/false))
- return Ret<PT_Float>(S, OpPC, Dummy);
+ if (!interp__builtin_nan(S, OpPC, Frame, F, /*Signaling=*/false))
+ return false;
break;
case Builtin::BI__builtin_nans:
case Builtin::BI__builtin_nansf:
case Builtin::BI__builtin_nansl:
case Builtin::BI__builtin_nansf16:
case Builtin::BI__builtin_nansf128:
- if (interp__builtin_nan(S, OpPC, Frame, F, /*Signaling=*/true))
- return Ret<PT_Float>(S, OpPC, Dummy);
+ if (!interp__builtin_nan(S, OpPC, Frame, F, /*Signaling=*/true))
+ return false;
break;
case Builtin::BI__builtin_huge_val:
@@ -503,15 +568,15 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F,
case Builtin::BI__builtin_infl:
case Builtin::BI__builtin_inff16:
case Builtin::BI__builtin_inff128:
- if (interp__builtin_inf(S, OpPC, Frame, F))
- return Ret<PT_Float>(S, OpPC, Dummy);
+ if (!interp__builtin_inf(S, OpPC, Frame, F))
+ return false;
break;
case Builtin::BI__builtin_copysign:
case Builtin::BI__builtin_copysignf:
case Builtin::BI__builtin_copysignl:
case Builtin::BI__builtin_copysignf128:
- if (interp__builtin_copysign(S, OpPC, Frame, F))
- return Ret<PT_Float>(S, OpPC, Dummy);
+ if (!interp__builtin_copysign(S, OpPC, Frame, F))
+ return false;
break;
case Builtin::BI__builtin_fmin:
@@ -519,8 +584,8 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F,
case Builtin::BI__builtin_fminl:
case Builtin::BI__builtin_fminf16:
case Builtin::BI__builtin_fminf128:
- if (interp__builtin_fmin(S, OpPC, Frame, F))
- return Ret<PT_Float>(S, OpPC, Dummy);
+ if (!interp__builtin_fmin(S, OpPC, Frame, F))
+ return false;
break;
case Builtin::BI__builtin_fmax:
@@ -528,60 +593,60 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F,
case Builtin::BI__builtin_fmaxl:
case Builtin::BI__builtin_fmaxf16:
case Builtin::BI__builtin_fmaxf128:
- if (interp__builtin_fmax(S, OpPC, Frame, F))
- return Ret<PT_Float>(S, OpPC, Dummy);
+ if (!interp__builtin_fmax(S, OpPC, Frame, F))
+ return false;
break;
case Builtin::BI__builtin_isnan:
- if (interp__builtin_isnan(S, OpPC, Frame, F))
- return retInt(S, OpPC, Dummy);
+ if (!interp__builtin_isnan(S, OpPC, Frame, F))
+ return false;
break;
case Builtin::BI__builtin_issignaling:
- if (interp__builtin_issignaling(S, OpPC, Frame, F))
- return retInt(S, OpPC, Dummy);
+ if (!interp__builtin_issignaling(S, OpPC, Frame, F))
+ return false;
break;
case Builtin::BI__builtin_isinf:
- if (interp__builtin_isinf(S, OpPC, Frame, F, /*Sign=*/false))
- return retInt(S, OpPC, Dummy);
+ if (!interp__builtin_isinf(S, OpPC, Frame, F, /*Sign=*/false))
+ return false;
break;
case Builtin::BI__builtin_isinf_sign:
- if (interp__builtin_isinf(S, OpPC, Frame, F, /*Sign=*/true))
- return retInt(S, OpPC, Dummy);
+ if (!interp__builtin_isinf(S, OpPC, Frame, F, /*Sign=*/true))
+ return false;
break;
case Builtin::BI__builtin_isfinite:
- if (interp__builtin_isfinite(S, OpPC, Frame, F))
- return retInt(S, OpPC, Dummy);
+ if (!interp__builtin_isfinite(S, OpPC, Frame, F))
+ return false;
break;
case Builtin::BI__builtin_isnormal:
- if (interp__builtin_isnormal(S, OpPC, Frame, F))
- return retInt(S, OpPC, Dummy);
+ if (!interp__builtin_isnormal(S, OpPC, Frame, F))
+ return false;
break;
case Builtin::BI__builtin_issubnormal:
- if (interp__builtin_issubnormal(S, OpPC, Frame, F))
- return retInt(S, OpPC, Dummy);
+ if (!interp__builtin_issubnormal(S, OpPC, Frame, F))
+ return false;
break;
case Builtin::BI__builtin_iszero:
- if (interp__builtin_iszero(S, OpPC, Frame, F))
- return retInt(S, OpPC, Dummy);
+ if (!interp__builtin_iszero(S, OpPC, Frame, F))
+ return false;
break;
case Builtin::BI__builtin_isfpclass:
- if (interp__builtin_isfpclass(S, OpPC, Frame, F, Call))
- return retInt(S, OpPC, Dummy);
+ if (!interp__builtin_isfpclass(S, OpPC, Frame, F, Call))
+ return false;
break;
case Builtin::BI__builtin_fpclassify:
- if (interp__builtin_fpclassify(S, OpPC, Frame, F))
- return retInt(S, OpPC, Dummy);
+ if (!interp__builtin_fpclassify(S, OpPC, Frame, F))
+ return false;
break;
case Builtin::BI__builtin_fabs:
case Builtin::BI__builtin_fabsf:
case Builtin::BI__builtin_fabsl:
case Builtin::BI__builtin_fabsf128:
- if (interp__builtin_fabs(S, OpPC, Frame, F))
- return Ret<PT_Float>(S, OpPC, Dummy);
+ if (!interp__builtin_fabs(S, OpPC, Frame, F))
+ return false;
break;
case Builtin::BI__builtin_popcount:
@@ -590,29 +655,37 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F,
case Builtin::BI__popcnt16: // Microsoft variants of popcount
case Builtin::BI__popcnt:
case Builtin::BI__popcnt64:
- if (interp__builtin_popcount(S, OpPC, Frame, F, Call))
- return retInt(S, OpPC, Dummy);
+ if (!interp__builtin_popcount(S, OpPC, Frame, F, Call))
+ return false;
break;
case Builtin::BI__builtin_parity:
case Builtin::BI__builtin_parityl:
case Builtin::BI__builtin_parityll:
- if (interp__builtin_parity(S, OpPC, Frame, F, Call))
- return retInt(S, OpPC, Dummy);
+ if (!interp__builtin_parity(S, OpPC, Frame, F, Call))
+ return false;
break;
case Builtin::BI__builtin_clrsb:
case Builtin::BI__builtin_clrsbl:
case Builtin::BI__builtin_clrsbll:
- if (interp__builtin_clrsb(S, OpPC, Frame, F, Call))
- return retInt(S, OpPC, Dummy);
+ if (!interp__builtin_clrsb(S, OpPC, Frame, F, Call))
+ return false;
+ break;
+
+ case Builtin::BI__builtin_bitreverse8:
+ case Builtin::BI__builtin_bitreverse16:
+ case Builtin::BI__builtin_bitreverse32:
+ case Builtin::BI__builtin_bitreverse64:
+ if (!interp__builtin_bitreverse(S, OpPC, Frame, F, Call))
+ return false;
break;
default:
return false;
}
- return false;
+ return retPrimValue(S, OpPC, Dummy, ReturnT);
}
bool InterpretOffsetOf(InterpState &S, CodePtr OpPC, const OffsetOfExpr *E,
diff --git a/clang/test/AST/Interp/builtin-functions.cpp b/clang/test/AST/Interp/builtin-functions.cpp
index acc2dc315a2755a..0726dab37cb4eb0 100644
--- a/clang/test/AST/Interp/builtin-functions.cpp
+++ b/clang/test/AST/Interp/builtin-functions.cpp
@@ -324,3 +324,10 @@ namespace clrsb {
char clrsb11[__builtin_clrsb(0xf) == BITSIZE(int) - 5 ? 1 : -1];
char clrsb12[__builtin_clrsb(~0x1f) == BITSIZE(int) - 6 ? 1 : -1];
}
+
+namespace bitreverse {
+ char bitreverse1[__builtin_bitreverse8(0x01) == 0x80 ? 1 : -1];
+ char bitreverse2[__builtin_bitreverse16(0x3C48) == 0x123C ? 1 : -1];
+ char bitreverse3[__builtin_bitreverse32(0x12345678) == 0x1E6A2C48 ? 1 : -1];
+ char bitreverse4[__builtin_bitreverse64(0x0123456789ABCDEFULL) == 0xF7B3D591E6A2C480 ? 1 : -1];
+}
More information about the cfe-commits
mailing list