Author: Timm Baeder
Date: 2025-08-26T13:51:30+02:00
New Revision: 773e6c3a3563421e1ae8c0093d03a5de8a3139c2

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

LOG: [clang][bytecode] Support remaining add_sat like X86 builtins (#155358)

Added: 
    

Modified: 
    clang/lib/AST/ByteCode/Integral.h
    clang/lib/AST/ByteCode/InterpBuiltin.cpp
    clang/test/CodeGen/X86/avx2-builtins.c

Removed: 
    


################################################################################
diff  --git a/clang/lib/AST/ByteCode/Integral.h 
b/clang/lib/AST/ByteCode/Integral.h
index af5cd2d13ecca..131802439f0c5 100644
--- a/clang/lib/AST/ByteCode/Integral.h
+++ b/clang/lib/AST/ByteCode/Integral.h
@@ -318,6 +318,11 @@ template <unsigned Bits, bool Signed> class Integral final 
{
   template <typename T> static bool CheckMulUB(T A, T B, T &R) {
     if constexpr (std::is_signed_v<T>) {
       return llvm::MulOverflow<T>(A, B, R);
+    } else if constexpr (sizeof(T) < sizeof(int)) {
+      // Silly integer promotion rules will convert both A and B to int,
+      // even it T is unsigned. Prevent that by manually casting to uint first.
+      R = static_cast<T>(static_cast<unsigned>(A) * static_cast<unsigned>(B));
+      return false;
     } else {
       R = A * B;
       return false;

diff  --git a/clang/lib/AST/ByteCode/InterpBuiltin.cpp 
b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
index cec3c9b33d453..b41c9ef544578 100644
--- a/clang/lib/AST/ByteCode/InterpBuiltin.cpp
+++ b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
@@ -2514,9 +2514,9 @@ static bool 
interp__builtin_is_within_lifetime(InterpState &S, CodePtr OpPC,
   return true;
 }
 
-static bool interp__builtin_elementwise_sat(InterpState &S, CodePtr OpPC,
-                                            const CallExpr *Call,
-                                            unsigned BuiltinID) {
+static bool interp__builtin_elementwise_int_binop(InterpState &S, CodePtr OpPC,
+                                                  const CallExpr *Call,
+                                                  unsigned BuiltinID) {
   assert(Call->getNumArgs() == 2);
 
   // Single integer case.
@@ -2553,6 +2553,8 @@ static bool interp__builtin_elementwise_sat(InterpState 
&S, CodePtr OpPC,
   const Pointer &LHS = S.Stk.pop<Pointer>();
   const Pointer &Dst = S.Stk.peek<Pointer>();
   PrimType ElemT = *S.getContext().classify(VT->getElementType());
+  bool DestUnsigned =
+      VT->getElementType()->isUnsignedIntegerOrEnumerationType();
   unsigned NumElems = VT->getNumElements();
   for (unsigned I = 0; I != NumElems; ++I) {
     APSInt Elem1;
@@ -2586,6 +2588,34 @@ static bool interp__builtin_elementwise_sat(InterpState 
&S, CodePtr OpPC,
       Result = APSInt(llvm::APIntOps::mulhs(Elem1, Elem2),
                       /*isUnsigned=*/false);
       break;
+    case clang::X86::BI__builtin_ia32_psllv2di:
+    case clang::X86::BI__builtin_ia32_psllv4di:
+    case clang::X86::BI__builtin_ia32_psllv4si:
+    case clang::X86::BI__builtin_ia32_psllv8si:
+      if (Elem2.uge(Elem2.getBitWidth())) {
+        Result = APSInt(APInt::getZero(Elem2.getBitWidth()), DestUnsigned);
+        break;
+      }
+      Result = APSInt(Elem1.shl(Elem2.getZExtValue()), DestUnsigned);
+      break;
+    case clang::X86::BI__builtin_ia32_psrav4si:
+    case clang::X86::BI__builtin_ia32_psrav8si:
+      if (Elem2.uge(Elem2.getBitWidth())) {
+        Result = APSInt(Elem1.ashr(Elem2.getBitWidth() - 1), DestUnsigned);
+        break;
+      }
+      Result = APSInt(Elem1.ashr(Elem2.getZExtValue()), DestUnsigned);
+      break;
+    case clang::X86::BI__builtin_ia32_psrlv2di:
+    case clang::X86::BI__builtin_ia32_psrlv4di:
+    case clang::X86::BI__builtin_ia32_psrlv4si:
+    case clang::X86::BI__builtin_ia32_psrlv8si:
+      if (Elem2.uge(Elem2.getBitWidth())) {
+        Result = APSInt(APInt::getZero(Elem2.getBitWidth()), DestUnsigned);
+        break;
+      }
+      Result = APSInt(Elem1.lshr(Elem2.getZExtValue()), DestUnsigned);
+      break;
     default:
       llvm_unreachable("Wrong builtin ID");
     }
@@ -3232,7 +3262,17 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, 
const CallExpr *Call,
   case clang::X86::BI__builtin_ia32_pmulhw128:
   case clang::X86::BI__builtin_ia32_pmulhw256:
   case clang::X86::BI__builtin_ia32_pmulhw512:
-    return interp__builtin_elementwise_sat(S, OpPC, Call, BuiltinID);
+  case clang::X86::BI__builtin_ia32_psllv2di:
+  case clang::X86::BI__builtin_ia32_psllv4di:
+  case clang::X86::BI__builtin_ia32_psllv4si:
+  case clang::X86::BI__builtin_ia32_psllv8si:
+  case clang::X86::BI__builtin_ia32_psrav4si:
+  case clang::X86::BI__builtin_ia32_psrav8si:
+  case clang::X86::BI__builtin_ia32_psrlv2di:
+  case clang::X86::BI__builtin_ia32_psrlv4di:
+  case clang::X86::BI__builtin_ia32_psrlv4si:
+  case clang::X86::BI__builtin_ia32_psrlv8si:
+    return interp__builtin_elementwise_int_binop(S, OpPC, Call, BuiltinID);
 
   case Builtin::BI__builtin_elementwise_max:
   case Builtin::BI__builtin_elementwise_min:

diff  --git a/clang/test/CodeGen/X86/avx2-builtins.c 
b/clang/test/CodeGen/X86/avx2-builtins.c
index 29cb3e8860be9..49e35230ba225 100644
--- a/clang/test/CodeGen/X86/avx2-builtins.c
+++ b/clang/test/CodeGen/X86/avx2-builtins.c
@@ -7,6 +7,14 @@
 // RUN: %clang_cc1 -x c++ -flax-vector-conversions=none -ffreestanding %s 
-triple=i386-apple-darwin -target-feature +avx2 -emit-llvm -o - -Wall -Werror | 
FileCheck %s --check-prefixes=CHECK,X86
 // RUN: %clang_cc1 -x c++ -flax-vector-conversions=none -ffreestanding %s 
-triple=i386-apple-darwin -target-feature +avx2 -fno-signed-char -emit-llvm -o 
- -Wall -Werror | FileCheck %s --check-prefixes=CHECK,X86
 
+// RUN: %clang_cc1 -x c -flax-vector-conversions=none -ffreestanding %s 
-triple=x86_64-apple-darwin -target-feature +avx2 -emit-llvm -o - -Wall -Werror 
-fexperimental-new-constant-interpreter | FileCheck %s 
--check-prefixes=CHECK,X64
+// RUN: %clang_cc1 -x c -flax-vector-conversions=none -ffreestanding %s 
-triple=x86_64-apple-darwin -target-feature +avx2 -fno-signed-char -emit-llvm 
-o - -Wall -Werror -fexperimental-new-constant-interpreter | FileCheck %s 
--check-prefixes=CHECK,X64
+// RUN: %clang_cc1 -x c -flax-vector-conversions=none -ffreestanding %s 
-triple=i386-apple-darwin -target-feature +avx2 -emit-llvm -o - -Wall -Werror 
-fexperimental-new-constant-interpreter | FileCheck %s 
--check-prefixes=CHECK,X86
+// RUN: %clang_cc1 -x c -flax-vector-conversions=none -ffreestanding %s 
-triple=i386-apple-darwin -target-feature +avx2 -fno-signed-char -emit-llvm -o 
- -Wall -Werror -fexperimental-new-constant-interpreter | FileCheck %s 
--check-prefixes=CHECK,X86
+// RUN: %clang_cc1 -x c++ -flax-vector-conversions=none -ffreestanding %s 
-triple=x86_64-apple-darwin -target-feature +avx2 -emit-llvm -o - -Wall -Werror 
-fexperimental-new-constant-interpreter | FileCheck %s 
--check-prefixes=CHECK,X64
+// RUN: %clang_cc1 -x c++ -flax-vector-conversions=none -ffreestanding %s 
-triple=x86_64-apple-darwin -target-feature +avx2 -fno-signed-char -emit-llvm 
-o - -Wall -Werror -fexperimental-new-constant-interpreter | FileCheck %s 
--check-prefixes=CHECK,X64
+// RUN: %clang_cc1 -x c++ -flax-vector-conversions=none -ffreestanding %s 
-triple=i386-apple-darwin -target-feature +avx2 -emit-llvm -o - -Wall -Werror 
-fexperimental-new-constant-interpreter | FileCheck %s 
--check-prefixes=CHECK,X86
+// RUN: %clang_cc1 -x c++ -flax-vector-conversions=none -ffreestanding %s 
-triple=i386-apple-darwin -target-feature +avx2 -fno-signed-char -emit-llvm -o 
- -Wall -Werror -fexperimental-new-constant-interpreter | FileCheck %s 
--check-prefixes=CHECK,X86
 
 #include <immintrin.h>
 #include "builtin_test_helpers.h"


        
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to