[clang] b3e4686 - [clang][Interp] Implement __builtin_{ctz, clz, bswap}

Timm Bäder via cfe-commits cfe-commits at lists.llvm.org
Tue Feb 20 03:07:24 PST 2024


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();
+}


        


More information about the cfe-commits mailing list