[clang] [clang][Interp] Implement __builtin_bitreverse (PR #71687)
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)
@@ -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)
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)
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)
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)
@@ -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)
@@ -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)
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)
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)
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)
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)
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