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?= <tbae...@redhat.com> 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<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]; +} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits