Author: Timm Bäder Date: 2024-02-20T11:55:20+01:00 New Revision: b3e4686af37c7879790f48f244afcb2da21d3af8
URL: https://github.com/llvm/llvm-project/commit/b3e4686af37c7879790f48f244afcb2da21d3af8 DIFF: https://github.com/llvm/llvm-project/commit/b3e4686af37c7879790f48f244afcb2da21d3af8.diff LOG: [clang][Interp] Implement __builtin_{ctz,clz,bswap} 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 f1040d15a1d2ad..401af580e1aaf6 100644 --- a/clang/lib/AST/Interp/InterpBuiltin.cpp +++ b/clang/lib/AST/Interp/InterpBuiltin.cpp @@ -841,6 +841,52 @@ static bool interp__builtin_carryop(InterpState &S, CodePtr OpPC, return true; } +static bool interp__builtin_clz(InterpState &S, CodePtr OpPC, + const InterpFrame *Frame, const Function *Func, + const CallExpr *Call) { + unsigned BuiltinOp = Func->getBuiltinID(); + PrimType ValT = *S.getContext().classify(Call->getArg(0)); + const APSInt &Val = peekToAPSInt(S.Stk, ValT); + + // When the argument is 0, the result of GCC builtins is undefined, whereas + // for Microsoft intrinsics, the result is the bit-width of the argument. + bool ZeroIsUndefined = BuiltinOp != Builtin::BI__lzcnt16 && + BuiltinOp != Builtin::BI__lzcnt && + BuiltinOp != Builtin::BI__lzcnt64; + + if (ZeroIsUndefined && Val == 0) + return false; + + pushInt(S, Val.countl_zero()); + return true; +} + +static bool interp__builtin_ctz(InterpState &S, CodePtr OpPC, + const InterpFrame *Frame, const Function *Func, + const CallExpr *Call) { + PrimType ValT = *S.getContext().classify(Call->getArg(0)); + const APSInt &Val = peekToAPSInt(S.Stk, ValT); + + if (Val == 0) + return false; + + pushInt(S, Val.countr_zero()); + return true; +} + +static bool interp__builtin_bswap(InterpState &S, CodePtr OpPC, + const InterpFrame *Frame, + const Function *Func, const CallExpr *Call) { + PrimType ReturnT = *S.getContext().classify(Call->getType()); + PrimType ValT = *S.getContext().classify(Call->getArg(0)); + const APSInt &Val = peekToAPSInt(S.Stk, ValT); + assert(Val.getActiveBits() <= 64); + + INT_TYPE_SWITCH(ReturnT, + { S.Stk.push<T>(T::from(Val.byteSwap().getZExtValue())); }); + return true; +} + bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F, const CallExpr *Call) { InterpFrame *Frame = S.Current; @@ -1114,6 +1160,32 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F, return false; break; + case Builtin::BI__builtin_clz: + case Builtin::BI__builtin_clzl: + case Builtin::BI__builtin_clzll: + case Builtin::BI__builtin_clzs: + case Builtin::BI__lzcnt16: // Microsoft variants of count leading-zeroes + case Builtin::BI__lzcnt: + case Builtin::BI__lzcnt64: + if (!interp__builtin_clz(S, OpPC, Frame, F, Call)) + return false; + break; + + case Builtin::BI__builtin_ctz: + case Builtin::BI__builtin_ctzl: + case Builtin::BI__builtin_ctzll: + case Builtin::BI__builtin_ctzs: + if (!interp__builtin_ctz(S, OpPC, Frame, F, Call)) + return false; + break; + + case Builtin::BI__builtin_bswap16: + case Builtin::BI__builtin_bswap32: + case Builtin::BI__builtin_bswap64: + if (!interp__builtin_bswap(S, OpPC, Frame, F, Call)) + return false; + break; + default: return false; } diff --git a/clang/test/AST/Interp/builtin-functions.cpp b/clang/test/AST/Interp/builtin-functions.cpp index cbcfe7d5374d1a..3701106e02f05b 100644 --- a/clang/test/AST/Interp/builtin-functions.cpp +++ b/clang/test/AST/Interp/builtin-functions.cpp @@ -444,3 +444,32 @@ void test_noexcept(int *i) { } #undef TEST_TYPE } // end namespace test_launder + +namespace clz { + char clz1[__builtin_clz(1) == BITSIZE(int) - 1 ? 1 : -1]; + char clz2[__builtin_clz(7) == BITSIZE(int) - 3 ? 1 : -1]; + char clz3[__builtin_clz(1 << (BITSIZE(int) - 1)) == 0 ? 1 : -1]; + int clz4 = __builtin_clz(0); + char clz5[__builtin_clzl(0xFL) == BITSIZE(long) - 4 ? 1 : -1]; + char clz6[__builtin_clzll(0xFFLL) == BITSIZE(long long) - 8 ? 1 : -1]; + char clz7[__builtin_clzs(0x1) == BITSIZE(short) - 1 ? 1 : -1]; + char clz8[__builtin_clzs(0xf) == BITSIZE(short) - 4 ? 1 : -1]; + char clz9[__builtin_clzs(0xfff) == BITSIZE(short) - 12 ? 1 : -1]; +} + +namespace ctz { + char ctz1[__builtin_ctz(1) == 0 ? 1 : -1]; + char ctz2[__builtin_ctz(8) == 3 ? 1 : -1]; + char ctz3[__builtin_ctz(1 << (BITSIZE(int) - 1)) == BITSIZE(int) - 1 ? 1 : -1]; + int ctz4 = __builtin_ctz(0); + char ctz5[__builtin_ctzl(0x10L) == 4 ? 1 : -1]; + char ctz6[__builtin_ctzll(0x100LL) == 8 ? 1 : -1]; + char ctz7[__builtin_ctzs(1 << (BITSIZE(short) - 1)) == BITSIZE(short) - 1 ? 1 : -1]; +} + +namespace bswap { + extern int f(void); + int h3 = __builtin_bswap16(0x1234) == 0x3412 ? 1 : f(); + int h4 = __builtin_bswap32(0x1234) == 0x34120000 ? 1 : f(); + int h5 = __builtin_bswap64(0x1234) == 0x3412000000000000 ? 1 : f(); +} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits