[clang] [clang][bytecode] Support __builtin_reduce_add (PR #117672)

Timm Baeder via cfe-commits cfe-commits at lists.llvm.org
Sun Dec 1 01:02:54 PST 2024


https://github.com/tbaederr updated https://github.com/llvm/llvm-project/pull/117672

>From 1bb49850c392cdc535849f43ad14b02cbbb9dcc0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Timm=20B=C3=A4der?= <tbaeder at redhat.com>
Date: Tue, 26 Nov 2024 06:33:12 +0100
Subject: [PATCH] [clang][bytecode] Support __builtin_reduce_add

---
 clang/lib/AST/ByteCode/InterpBuiltin.cpp      | 48 ++++++++++++++++++-
 clang/test/AST/ByteCode/builtin-functions.cpp | 45 +++++++++++++++++
 2 files changed, 91 insertions(+), 2 deletions(-)

diff --git a/clang/lib/AST/ByteCode/InterpBuiltin.cpp b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
index b450d8263c30bf..dc7d23f81d3f4e 100644
--- a/clang/lib/AST/ByteCode/InterpBuiltin.cpp
+++ b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
@@ -89,13 +89,14 @@ static void pushInteger(InterpState &S, const APSInt &Val, QualType QT) {
   std::optional<PrimType> T = S.getContext().classify(QT);
   assert(T);
 
+  unsigned BitWidth = S.getASTContext().getTypeSize(QT);
   if (QT->isSignedIntegerOrEnumerationType()) {
     int64_t V = Val.getSExtValue();
-    INT_TYPE_SWITCH(*T, { S.Stk.push<T>(T::from(V)); });
+    INT_TYPE_SWITCH(*T, { S.Stk.push<T>(T::from(V, BitWidth)); });
   } else {
     assert(QT->isUnsignedIntegerOrEnumerationType());
     uint64_t V = Val.getZExtValue();
-    INT_TYPE_SWITCH(*T, { S.Stk.push<T>(T::from(V)); });
+    INT_TYPE_SWITCH(*T, { S.Stk.push<T>(T::from(V, BitWidth)); });
   }
 }
 
@@ -137,6 +138,8 @@ static bool retPrimValue(InterpState &S, CodePtr OpPC, APValue &Result,
     RET_CASE(PT_Uint32);
     RET_CASE(PT_Sint64);
     RET_CASE(PT_Uint64);
+    RET_CASE(PT_IntAP);
+    RET_CASE(PT_IntAPS);
   default:
     llvm_unreachable("Unsupported return type for builtin function");
   }
@@ -1684,6 +1687,42 @@ static bool interp__builtin_arithmetic_fence(InterpState &S, CodePtr OpPC,
   return true;
 }
 
+static bool interp__builtin_vector_reduce(InterpState &S, CodePtr OpPC,
+                                          const InterpFrame *Frame,
+                                          const Function *Func,
+                                          const CallExpr *Call) {
+  const Pointer &Arg = S.Stk.peek<Pointer>();
+  assert(Arg.getFieldDesc()->isPrimitiveArray());
+
+  unsigned ID = Func->getBuiltinID();
+  if (ID == Builtin::BI__builtin_reduce_add) {
+    QualType ElemType = Arg.getFieldDesc()->getElemQualType();
+    assert(Call->getType() == ElemType);
+    PrimType ElemT = *S.getContext().classify(ElemType);
+    unsigned NumElems = Arg.getNumElems();
+
+    INT_TYPE_SWITCH(ElemT, {
+      T Sum = Arg.atIndex(0).deref<T>();
+      unsigned BitWidth = Sum.bitWidth();
+      for (unsigned I = 1; I != NumElems; ++I) {
+        T Elem = Arg.atIndex(I).deref<T>();
+        if (T::add(Sum, Elem, BitWidth, &Sum)) {
+          unsigned OverflowBits = BitWidth + 1;
+          (void)handleOverflow(
+              S, OpPC,
+              (Sum.toAPSInt(OverflowBits) + Elem.toAPSInt(OverflowBits)));
+          return false;
+        }
+      }
+      pushInteger(S, Sum, Call->getType());
+    });
+
+    return true;
+  }
+
+  llvm_unreachable("Unsupported vector reduce builtin");
+}
+
 bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F,
                       const CallExpr *Call, uint32_t BuiltinID) {
   const InterpFrame *Frame = S.Current;
@@ -2130,6 +2169,11 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F,
       return false;
     break;
 
+  case Builtin::BI__builtin_reduce_add:
+    if (!interp__builtin_vector_reduce(S, OpPC, Frame, F, Call))
+      return false;
+    break;
+
   default:
     S.FFDiag(S.Current->getLocation(OpPC),
              diag::note_invalid_subexpr_in_const_expr)
diff --git a/clang/test/AST/ByteCode/builtin-functions.cpp b/clang/test/AST/ByteCode/builtin-functions.cpp
index b5d334178f8213..972d39ca509615 100644
--- a/clang/test/AST/ByteCode/builtin-functions.cpp
+++ b/clang/test/AST/ByteCode/builtin-functions.cpp
@@ -990,3 +990,48 @@ namespace BuiltinInImplicitCtor {
   } Foo;
   static_assert(Foo.a == 0, "");
 }
+
+
+typedef double vector4double __attribute__((__vector_size__(32)));
+typedef float vector4float __attribute__((__vector_size__(16)));
+typedef long long vector4long __attribute__((__vector_size__(32)));
+typedef int vector4int __attribute__((__vector_size__(16)));
+typedef unsigned long long vector4ulong __attribute__((__vector_size__(32)));
+typedef unsigned int vector4uint __attribute__((__vector_size__(16)));
+typedef short vector4short __attribute__((__vector_size__(8)));
+typedef char vector4char __attribute__((__vector_size__(4)));
+typedef double vector8double __attribute__((__vector_size__(64)));
+typedef float vector8float __attribute__((__vector_size__(32)));
+typedef long long vector8long __attribute__((__vector_size__(64)));
+typedef int vector8int __attribute__((__vector_size__(32)));
+typedef short vector8short __attribute__((__vector_size__(16)));
+typedef char vector8char __attribute__((__vector_size__(8)));
+
+namespace RecuceAdd {
+  static_assert(__builtin_reduce_add((vector4char){}) == 0);
+  static_assert(__builtin_reduce_add((vector4char){1, 2, 3, 4}) == 10);
+  static_assert(__builtin_reduce_add((vector4short){10, 20, 30, 40}) == 100);
+  static_assert(__builtin_reduce_add((vector4int){100, 200, 300, 400}) == 1000);
+  static_assert(__builtin_reduce_add((vector4long){1000, 2000, 3000, 4000}) == 10000);
+  constexpr int reduceAddInt1 = __builtin_reduce_add((vector4int){~(1 << (sizeof(int) * 8 - 1)), 0, 0, 1});
+  // both-error at -1 {{must be initialized by a constant expression}} \
+  // both-note at -1 {{outside the range of representable values of type 'int'}}
+  constexpr long long reduceAddLong1 = __builtin_reduce_add((vector4long){~(1LL << (sizeof(long long) * 8 - 1)), 0, 0, 1});
+  // both-error at -1 {{must be initialized by a constant expression}} \
+  // both-note at -1 {{outside the range of representable values of type 'long long'}}
+  constexpr int reduceAddInt2 = __builtin_reduce_add((vector4int){(1 << (sizeof(int) * 8 - 1)), 0, 0, -1});
+  // both-error at -1 {{must be initialized by a constant expression}} \
+  // both-note at -1 {{outside the range of representable values of type 'int'}}
+  constexpr long long reduceAddLong2 = __builtin_reduce_add((vector4long){(1LL << (sizeof(long long) * 8 - 1)), 0, 0, -1});
+  // both-error at -1 {{must be initialized by a constant expression}} \
+  // both-note at -1 {{outside the range of representable values of type 'long long'}}
+  static_assert(__builtin_reduce_add((vector4uint){~0U, 0, 0, 1}) == 0);
+  static_assert(__builtin_reduce_add((vector4ulong){~0ULL, 0, 0, 1}) == 0);
+
+
+#ifdef __SIZEOF_INT128__
+  typedef __int128 v4i128 __attribute__((__vector_size__(128 * 2)));
+  constexpr __int128 reduceAddInt3 = __builtin_reduce_add((v4i128){});
+  static_assert(reduceAddInt3 == 0);
+#endif
+}



More information about the cfe-commits mailing list