[clang] ec40097 - [clang][Interp] Implement __builtin_{ctz,clz}g

Timm Bäder via cfe-commits cfe-commits at lists.llvm.org
Wed Apr 10 03:27:50 PDT 2024


Author: Timm Bäder
Date: 2024-04-10T12:27:33+02:00
New Revision: ec40097db28374c1226f0f7e45f18491a596778b

URL: https://github.com/llvm/llvm-project/commit/ec40097db28374c1226f0f7e45f18491a596778b
DIFF: https://github.com/llvm/llvm-project/commit/ec40097db28374c1226f0f7e45f18491a596778b.diff

LOG: [clang][Interp] Implement __builtin_{ctz,clz}g

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 1bf5d55314f1f2..984ba4f7f2689c 100644
--- a/clang/lib/AST/Interp/InterpBuiltin.cpp
+++ b/clang/lib/AST/Interp/InterpBuiltin.cpp
@@ -16,6 +16,16 @@
 namespace clang {
 namespace interp {
 
+static unsigned callArgSize(const InterpState &S, const CallExpr *C) {
+  unsigned O = 0;
+
+  for (const Expr *E : C->arguments()) {
+    O += align(primSize(*S.getContext().classify(E)));
+  }
+
+  return O;
+}
+
 template <typename T>
 static T getParam(const InterpFrame *Frame, unsigned Index) {
   assert(Frame->getFunction()->getNumParams() > Index);
@@ -816,9 +826,10 @@ static bool interp__builtin_carryop(InterpState &S, CodePtr OpPC,
 static bool interp__builtin_clz(InterpState &S, CodePtr OpPC,
                                 const InterpFrame *Frame, const Function *Func,
                                 const CallExpr *Call) {
+  unsigned CallSize = callArgSize(S, Call);
   unsigned BuiltinOp = Func->getBuiltinID();
   PrimType ValT = *S.getContext().classify(Call->getArg(0));
-  const APSInt &Val = peekToAPSInt(S.Stk, ValT);
+  const APSInt &Val = peekToAPSInt(S.Stk, ValT, CallSize);
 
   // 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.
@@ -826,8 +837,19 @@ static bool interp__builtin_clz(InterpState &S, CodePtr OpPC,
                          BuiltinOp != Builtin::BI__lzcnt &&
                          BuiltinOp != Builtin::BI__lzcnt64;
 
-  if (ZeroIsUndefined && Val == 0)
-    return false;
+  if (Val == 0) {
+    if (Func->getBuiltinID() == Builtin::BI__builtin_clzg &&
+        Call->getNumArgs() == 2) {
+      // We have a fallback parameter.
+      PrimType FallbackT = *S.getContext().classify(Call->getArg(1));
+      const APSInt &Fallback = peekToAPSInt(S.Stk, FallbackT);
+      pushInteger(S, Fallback, Call->getType());
+      return true;
+    }
+
+    if (ZeroIsUndefined)
+      return false;
+  }
 
   pushInteger(S, Val.countl_zero(), Call->getType());
   return true;
@@ -836,11 +858,21 @@ static bool interp__builtin_clz(InterpState &S, CodePtr OpPC,
 static bool interp__builtin_ctz(InterpState &S, CodePtr OpPC,
                                 const InterpFrame *Frame, const Function *Func,
                                 const CallExpr *Call) {
+  unsigned CallSize = callArgSize(S, Call);
   PrimType ValT = *S.getContext().classify(Call->getArg(0));
-  const APSInt &Val = peekToAPSInt(S.Stk, ValT);
-
-  if (Val == 0)
+  const APSInt &Val = peekToAPSInt(S.Stk, ValT, CallSize);
+
+  if (Val == 0) {
+    if (Func->getBuiltinID() == Builtin::BI__builtin_ctzg &&
+        Call->getNumArgs() == 2) {
+      // We have a fallback parameter.
+      PrimType FallbackT = *S.getContext().classify(Call->getArg(1));
+      const APSInt &Fallback = peekToAPSInt(S.Stk, FallbackT);
+      pushInteger(S, Fallback, Call->getType());
+      return true;
+    }
     return false;
+  }
 
   pushInteger(S, Val.countr_zero(), Call->getType());
   return true;
@@ -1223,6 +1255,7 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F,
   case Builtin::BI__builtin_clzl:
   case Builtin::BI__builtin_clzll:
   case Builtin::BI__builtin_clzs:
+  case Builtin::BI__builtin_clzg:
   case Builtin::BI__lzcnt16: // Microsoft variants of count leading-zeroes
   case Builtin::BI__lzcnt:
   case Builtin::BI__lzcnt64:
@@ -1234,6 +1267,7 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F,
   case Builtin::BI__builtin_ctzl:
   case Builtin::BI__builtin_ctzll:
   case Builtin::BI__builtin_ctzs:
+  case Builtin::BI__builtin_ctzg:
     if (!interp__builtin_ctz(S, OpPC, Frame, F, Call))
       return false;
     break;

diff  --git a/clang/test/AST/Interp/builtin-functions.cpp b/clang/test/AST/Interp/builtin-functions.cpp
index 2e9d1a831dcf6e..a7adc92d3714fa 100644
--- a/clang/test/AST/Interp/builtin-functions.cpp
+++ b/clang/test/AST/Interp/builtin-functions.cpp
@@ -482,6 +482,9 @@ void test_noexcept(int *i) {
 #undef TEST_TYPE
 } // end namespace test_launder
 
+
+/// FIXME: The commented out tests here use a IntAP value and fail.
+/// This currently means we will leak the IntAP value since nothing cleans it up.
 namespace clz {
   char clz1[__builtin_clz(1) == BITSIZE(int) - 1 ? 1 : -1];
   char clz2[__builtin_clz(7) == BITSIZE(int) - 3 ? 1 : -1];
@@ -492,6 +495,63 @@ namespace clz {
   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];
+
+  int clz10 = __builtin_clzg((unsigned char)0);
+  char clz11[__builtin_clzg((unsigned char)0, 42) == 42 ? 1 : -1];
+  char clz12[__builtin_clzg((unsigned char)0x1) == BITSIZE(char) - 1 ? 1 : -1];
+  char clz13[__builtin_clzg((unsigned char)0x1, 42) == BITSIZE(char) - 1 ? 1 : -1];
+  char clz14[__builtin_clzg((unsigned char)0xf) == BITSIZE(char) - 4 ? 1 : -1];
+  char clz15[__builtin_clzg((unsigned char)0xf, 42) == BITSIZE(char) - 4 ? 1 : -1];
+  char clz16[__builtin_clzg((unsigned char)(1 << (BITSIZE(char) - 1))) == 0 ? 1 : -1];
+  char clz17[__builtin_clzg((unsigned char)(1 << (BITSIZE(char) - 1)), 42) == 0 ? 1 : -1];
+  int clz18 = __builtin_clzg((unsigned short)0);
+  char clz19[__builtin_clzg((unsigned short)0, 42) == 42 ? 1 : -1];
+  char clz20[__builtin_clzg((unsigned short)0x1) == BITSIZE(short) - 1 ? 1 : -1];
+  char clz21[__builtin_clzg((unsigned short)0x1, 42) == BITSIZE(short) - 1 ? 1 : -1];
+  char clz22[__builtin_clzg((unsigned short)0xf) == BITSIZE(short) - 4 ? 1 : -1];
+  char clz23[__builtin_clzg((unsigned short)0xf, 42) == BITSIZE(short) - 4 ? 1 : -1];
+  char clz24[__builtin_clzg((unsigned short)(1 << (BITSIZE(short) - 1))) == 0 ? 1 : -1];
+  char clz25[__builtin_clzg((unsigned short)(1 << (BITSIZE(short) - 1)), 42) == 0 ? 1 : -1];
+  int clz26 = __builtin_clzg(0U);
+  char clz27[__builtin_clzg(0U, 42) == 42 ? 1 : -1];
+  char clz28[__builtin_clzg(0x1U) == BITSIZE(int) - 1 ? 1 : -1];
+  char clz29[__builtin_clzg(0x1U, 42) == BITSIZE(int) - 1 ? 1 : -1];
+  char clz30[__builtin_clzg(0xfU) == BITSIZE(int) - 4 ? 1 : -1];
+  char clz31[__builtin_clzg(0xfU, 42) == BITSIZE(int) - 4 ? 1 : -1];
+  char clz32[__builtin_clzg(1U << (BITSIZE(int) - 1)) == 0 ? 1 : -1];
+  char clz33[__builtin_clzg(1U << (BITSIZE(int) - 1), 42) == 0 ? 1 : -1];
+  int clz34 = __builtin_clzg(0UL);
+  char clz35[__builtin_clzg(0UL, 42) == 42 ? 1 : -1];
+  char clz36[__builtin_clzg(0x1UL) == BITSIZE(long) - 1 ? 1 : -1];
+  char clz37[__builtin_clzg(0x1UL, 42) == BITSIZE(long) - 1 ? 1 : -1];
+  char clz38[__builtin_clzg(0xfUL) == BITSIZE(long) - 4 ? 1 : -1];
+  char clz39[__builtin_clzg(0xfUL, 42) == BITSIZE(long) - 4 ? 1 : -1];
+  char clz40[__builtin_clzg(1UL << (BITSIZE(long) - 1)) == 0 ? 1 : -1];
+  char clz41[__builtin_clzg(1UL << (BITSIZE(long) - 1), 42) == 0 ? 1 : -1];
+  int clz42 = __builtin_clzg(0ULL);
+  char clz43[__builtin_clzg(0ULL, 42) == 42 ? 1 : -1];
+  char clz44[__builtin_clzg(0x1ULL) == BITSIZE(long long) - 1 ? 1 : -1];
+  char clz45[__builtin_clzg(0x1ULL, 42) == BITSIZE(long long) - 1 ? 1 : -1];
+  char clz46[__builtin_clzg(0xfULL) == BITSIZE(long long) - 4 ? 1 : -1];
+  char clz47[__builtin_clzg(0xfULL, 42) == BITSIZE(long long) - 4 ? 1 : -1];
+  char clz48[__builtin_clzg(1ULL << (BITSIZE(long long) - 1)) == 0 ? 1 : -1];
+  char clz49[__builtin_clzg(1ULL << (BITSIZE(long long) - 1), 42) == 0 ? 1 : -1];
+#ifdef __SIZEOF_INT128__
+  // int clz50 = __builtin_clzg((unsigned __int128)0);
+  char clz51[__builtin_clzg((unsigned __int128)0, 42) == 42 ? 1 : -1];
+  char clz52[__builtin_clzg((unsigned __int128)0x1) == BITSIZE(__int128) - 1 ? 1 : -1];
+  char clz53[__builtin_clzg((unsigned __int128)0x1, 42) == BITSIZE(__int128) - 1 ? 1 : -1];
+  char clz54[__builtin_clzg((unsigned __int128)0xf) == BITSIZE(__int128) - 4 ? 1 : -1];
+  char clz55[__builtin_clzg((unsigned __int128)0xf, 42) == BITSIZE(__int128) - 4 ? 1 : -1];
+#endif
+#ifndef __AVR__
+  // int clz58 = __builtin_clzg((unsigned _BitInt(128))0);
+  char clz59[__builtin_clzg((unsigned _BitInt(128))0, 42) == 42 ? 1 : -1];
+  char clz60[__builtin_clzg((unsigned _BitInt(128))0x1) == BITSIZE(_BitInt(128)) - 1 ? 1 : -1];
+  char clz61[__builtin_clzg((unsigned _BitInt(128))0x1, 42) == BITSIZE(_BitInt(128)) - 1 ? 1 : -1];
+  char clz62[__builtin_clzg((unsigned _BitInt(128))0xf) == BITSIZE(_BitInt(128)) - 4 ? 1 : -1];
+  char clz63[__builtin_clzg((unsigned _BitInt(128))0xf, 42) == BITSIZE(_BitInt(128)) - 4 ? 1 : -1];
+#endif
 }
 
 namespace ctz {
@@ -502,6 +562,66 @@ namespace ctz {
   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];
+  int ctz8 = __builtin_ctzg((unsigned char)0);
+  char ctz9[__builtin_ctzg((unsigned char)0, 42) == 42 ? 1 : -1];
+  char ctz10[__builtin_ctzg((unsigned char)0x1) == 0 ? 1 : -1];
+  char ctz11[__builtin_ctzg((unsigned char)0x1, 42) == 0 ? 1 : -1];
+  char ctz12[__builtin_ctzg((unsigned char)0x10) == 4 ? 1 : -1];
+  char ctz13[__builtin_ctzg((unsigned char)0x10, 42) == 4 ? 1 : -1];
+  char ctz14[__builtin_ctzg((unsigned char)(1 << (BITSIZE(char) - 1))) == BITSIZE(char) - 1 ? 1 : -1];
+  char ctz15[__builtin_ctzg((unsigned char)(1 << (BITSIZE(char) - 1)), 42) == BITSIZE(char) - 1 ? 1 : -1];
+  int ctz16 = __builtin_ctzg((unsigned short)0);
+  char ctz17[__builtin_ctzg((unsigned short)0, 42) == 42 ? 1 : -1];
+  char ctz18[__builtin_ctzg((unsigned short)0x1) == 0 ? 1 : -1];
+  char ctz19[__builtin_ctzg((unsigned short)0x1, 42) == 0 ? 1 : -1];
+  char ctz20[__builtin_ctzg((unsigned short)0x10) == 4 ? 1 : -1];
+  char ctz21[__builtin_ctzg((unsigned short)0x10, 42) == 4 ? 1 : -1];
+  char ctz22[__builtin_ctzg((unsigned short)(1 << (BITSIZE(short) - 1))) == BITSIZE(short) - 1 ? 1 : -1];
+  char ctz23[__builtin_ctzg((unsigned short)(1 << (BITSIZE(short) - 1)), 42) == BITSIZE(short) - 1 ? 1 : -1];
+  int ctz24 = __builtin_ctzg(0U);
+  char ctz25[__builtin_ctzg(0U, 42) == 42 ? 1 : -1];
+  char ctz26[__builtin_ctzg(0x1U) == 0 ? 1 : -1];
+  char ctz27[__builtin_ctzg(0x1U, 42) == 0 ? 1 : -1];
+  char ctz28[__builtin_ctzg(0x10U) == 4 ? 1 : -1];
+  char ctz29[__builtin_ctzg(0x10U, 42) == 4 ? 1 : -1];
+  char ctz30[__builtin_ctzg(1U << (BITSIZE(int) - 1)) == BITSIZE(int) - 1 ? 1 : -1];
+  char ctz31[__builtin_ctzg(1U << (BITSIZE(int) - 1), 42) == BITSIZE(int) - 1 ? 1 : -1];
+  int ctz32 = __builtin_ctzg(0UL);
+  char ctz33[__builtin_ctzg(0UL, 42) == 42 ? 1 : -1];
+  char ctz34[__builtin_ctzg(0x1UL) == 0 ? 1 : -1];
+  char ctz35[__builtin_ctzg(0x1UL, 42) == 0 ? 1 : -1];
+  char ctz36[__builtin_ctzg(0x10UL) == 4 ? 1 : -1];
+  char ctz37[__builtin_ctzg(0x10UL, 42) == 4 ? 1 : -1];
+  char ctz38[__builtin_ctzg(1UL << (BITSIZE(long) - 1)) == BITSIZE(long) - 1 ? 1 : -1];
+  char ctz39[__builtin_ctzg(1UL << (BITSIZE(long) - 1), 42) == BITSIZE(long) - 1 ? 1 : -1];
+  int ctz40 = __builtin_ctzg(0ULL);
+  char ctz41[__builtin_ctzg(0ULL, 42) == 42 ? 1 : -1];
+  char ctz42[__builtin_ctzg(0x1ULL) == 0 ? 1 : -1];
+  char ctz43[__builtin_ctzg(0x1ULL, 42) == 0 ? 1 : -1];
+  char ctz44[__builtin_ctzg(0x10ULL) == 4 ? 1 : -1];
+  char ctz45[__builtin_ctzg(0x10ULL, 42) == 4 ? 1 : -1];
+  char ctz46[__builtin_ctzg(1ULL << (BITSIZE(long long) - 1)) == BITSIZE(long long) - 1 ? 1 : -1];
+  char ctz47[__builtin_ctzg(1ULL << (BITSIZE(long long) - 1), 42) == BITSIZE(long long) - 1 ? 1 : -1];
+#ifdef __SIZEOF_INT128__
+  // int ctz48 = __builtin_ctzg((unsigned __int128)0);
+  char ctz49[__builtin_ctzg((unsigned __int128)0, 42) == 42 ? 1 : -1];
+  char ctz50[__builtin_ctzg((unsigned __int128)0x1) == 0 ? 1 : -1];
+  char ctz51[__builtin_ctzg((unsigned __int128)0x1, 42) == 0 ? 1 : -1];
+  char ctz52[__builtin_ctzg((unsigned __int128)0x10) == 4 ? 1 : -1];
+  char ctz53[__builtin_ctzg((unsigned __int128)0x10, 42) == 4 ? 1 : -1];
+  char ctz54[__builtin_ctzg((unsigned __int128)1 << (BITSIZE(__int128) - 1)) == BITSIZE(__int128) - 1 ? 1 : -1];
+  char ctz55[__builtin_ctzg((unsigned __int128)1 << (BITSIZE(__int128) - 1), 42) == BITSIZE(__int128) - 1 ? 1 : -1];
+#endif
+#ifndef __AVR__
+  // int ctz56 = __builtin_ctzg((unsigned _BitInt(128))0);
+  char ctz57[__builtin_ctzg((unsigned _BitInt(128))0, 42) == 42 ? 1 : -1];
+  char ctz58[__builtin_ctzg((unsigned _BitInt(128))0x1) == 0 ? 1 : -1];
+  char ctz59[__builtin_ctzg((unsigned _BitInt(128))0x1, 42) == 0 ? 1 : -1];
+  char ctz60[__builtin_ctzg((unsigned _BitInt(128))0x10) == 4 ? 1 : -1];
+  char ctz61[__builtin_ctzg((unsigned _BitInt(128))0x10, 42) == 4 ? 1 : -1];
+  char ctz62[__builtin_ctzg((unsigned _BitInt(128))1 << (BITSIZE(_BitInt(128)) - 1)) == BITSIZE(_BitInt(128)) - 1 ? 1 : -1];
+  char ctz63[__builtin_ctzg((unsigned _BitInt(128))1 << (BITSIZE(_BitInt(128)) - 1), 42) == BITSIZE(_BitInt(128)) - 1 ? 1 : -1];
+#endif
 }
 
 namespace bswap {


        


More information about the cfe-commits mailing list