[clang] [clang][x86][bytecode] Refactor BMI intrinsic wrappers to use interp__builtin_elementwise_int_binop (PR #160362)

via cfe-commits cfe-commits at lists.llvm.org
Wed Sep 24 10:59:36 PDT 2025


https://github.com/jiang1997 updated https://github.com/llvm/llvm-project/pull/160362

>From 56d89a0b7fda8ed43b41a0674f742e5ee0e72cc6 Mon Sep 17 00:00:00 2001
From: jiang1997 <jieke at live.cn>
Date: Wed, 24 Sep 2025 02:15:57 +0800
Subject: [PATCH 1/3] [clang][x86][bytecode] Refactor BMI intrinsic wrappers to
 use elementwise_int_binop

---
 clang/lib/AST/ByteCode/InterpBuiltin.cpp     | 147 +++++++------------
 clang/test/AST/ByteCode/x86-bmi-builtins.cpp |  67 +++++++++
 2 files changed, 119 insertions(+), 95 deletions(-)
 create mode 100644 clang/test/AST/ByteCode/x86-bmi-builtins.cpp

diff --git a/clang/lib/AST/ByteCode/InterpBuiltin.cpp b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
index 5423d3ca73c81..d34704419b59e 100644
--- a/clang/lib/AST/ByteCode/InterpBuiltin.cpp
+++ b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
@@ -1319,97 +1319,6 @@ static bool interp__builtin_assume_aligned(InterpState &S, CodePtr OpPC,
   return true;
 }
 
-static bool interp__builtin_ia32_bextr(InterpState &S, CodePtr OpPC,
-                                       const InterpFrame *Frame,
-                                       const CallExpr *Call) {
-  if (Call->getNumArgs() != 2 || !Call->getArg(0)->getType()->isIntegerType() ||
-      !Call->getArg(1)->getType()->isIntegerType())
-    return false;
-
-  PrimType ValT = *S.Ctx.classify(Call->getArg(0));
-  PrimType IndexT = *S.Ctx.classify(Call->getArg(1));
-  APSInt Index = popToAPSInt(S.Stk, IndexT);
-  APSInt Val = popToAPSInt(S.Stk, ValT);
-
-  unsigned BitWidth = Val.getBitWidth();
-  uint64_t Shift = Index.extractBitsAsZExtValue(8, 0);
-  uint64_t Length = Index.extractBitsAsZExtValue(8, 8);
-  Length = Length > BitWidth ? BitWidth : Length;
-
-  // Handle out of bounds cases.
-  if (Length == 0 || Shift >= BitWidth) {
-    pushInteger(S, 0, Call->getType());
-    return true;
-  }
-
-  uint64_t Result = Val.getZExtValue() >> Shift;
-  Result &= llvm::maskTrailingOnes<uint64_t>(Length);
-  pushInteger(S, Result, Call->getType());
-  return true;
-}
-
-static bool interp__builtin_ia32_bzhi(InterpState &S, CodePtr OpPC,
-                                      const InterpFrame *Frame,
-                                      const CallExpr *Call) {
-  QualType CallType = Call->getType();
-  if (Call->getNumArgs() != 2 || !Call->getArg(0)->getType()->isIntegerType() ||
-      !Call->getArg(1)->getType()->isIntegerType() ||
-      !CallType->isIntegerType())
-    return false;
-
-  APSInt Idx = popToAPSInt(S, Call->getArg(1));
-  APSInt Val = popToAPSInt(S, Call->getArg(0));
-
-  unsigned BitWidth = Val.getBitWidth();
-  uint64_t Index = Idx.extractBitsAsZExtValue(8, 0);
-
-  if (Index < BitWidth)
-    Val.clearHighBits(BitWidth - Index);
-
-  pushInteger(S, Val, CallType);
-  return true;
-}
-
-static bool interp__builtin_ia32_pdep(InterpState &S, CodePtr OpPC,
-                                      const InterpFrame *Frame,
-                                      const CallExpr *Call) {
-  if (Call->getNumArgs() != 2 || !Call->getArg(0)->getType()->isIntegerType() ||
-      !Call->getArg(1)->getType()->isIntegerType())
-    return false;
-
-  APSInt Mask = popToAPSInt(S, Call->getArg(1));
-  APSInt Val = popToAPSInt(S, Call->getArg(0));
-
-  unsigned BitWidth = Val.getBitWidth();
-  APInt Result = APInt::getZero(BitWidth);
-  for (unsigned I = 0, P = 0; I != BitWidth; ++I) {
-    if (Mask[I])
-      Result.setBitVal(I, Val[P++]);
-  }
-  pushInteger(S, std::move(Result), Call->getType());
-  return true;
-}
-
-static bool interp__builtin_ia32_pext(InterpState &S, CodePtr OpPC,
-                                      const InterpFrame *Frame,
-                                      const CallExpr *Call) {
-  if (Call->getNumArgs() != 2 || !Call->getArg(0)->getType()->isIntegerType() ||
-      !Call->getArg(1)->getType()->isIntegerType())
-    return false;
-
-  APSInt Mask = popToAPSInt(S, Call->getArg(1));
-  APSInt Val = popToAPSInt(S, Call->getArg(0));
-
-  unsigned BitWidth = Val.getBitWidth();
-  APInt Result = APInt::getZero(BitWidth);
-  for (unsigned I = 0, P = 0; I != BitWidth; ++I) {
-    if (Mask[I])
-      Result.setBitVal(P++, Val[I]);
-  }
-  pushInteger(S, std::move(Result), Call->getType());
-  return true;
-}
-
 /// (CarryIn, LHS, RHS, Result)
 static bool interp__builtin_ia32_addcarry_subborrow(InterpState &S,
                                                     CodePtr OpPC,
@@ -3256,11 +3165,37 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const CallExpr *Call,
   case clang::X86::BI__builtin_ia32_bextr_u64:
   case clang::X86::BI__builtin_ia32_bextri_u32:
   case clang::X86::BI__builtin_ia32_bextri_u64:
-    return interp__builtin_ia32_bextr(S, OpPC, Frame, Call);
+    return interp__builtin_elementwise_int_binop(
+        S, OpPC, Call, [](const APSInt &Val, const APSInt &Idx) {
+          unsigned BitWidth = Val.getBitWidth();
+          uint64_t Shift = Idx.extractBitsAsZExtValue(8, 0);
+          uint64_t Length = Idx.extractBitsAsZExtValue(8, 8);
+          if (Length > BitWidth) {
+            Length = BitWidth;
+          }
+
+          // Handle out of bounds cases.
+          if (Length == 0 || Shift >= BitWidth)
+            return APInt(BitWidth, 0);
+
+          uint64_t Result = Val.getZExtValue() >> Shift;
+          Result &= llvm::maskTrailingOnes<uint64_t>(Length);
+          return APInt(BitWidth, Result);
+        });
 
   case clang::X86::BI__builtin_ia32_bzhi_si:
   case clang::X86::BI__builtin_ia32_bzhi_di:
-    return interp__builtin_ia32_bzhi(S, OpPC, Frame, Call);
+    return interp__builtin_elementwise_int_binop(
+        S, OpPC, Call, [](const APSInt &Val, const APSInt &Idx) {
+          unsigned BitWidth = Val.getBitWidth();
+          uint64_t Index = Idx.extractBitsAsZExtValue(8, 0);
+          APSInt Result = Val;
+
+          if (Index < BitWidth)
+            Result.clearHighBits(BitWidth - Index);
+
+          return Result;
+        });
 
   case clang::X86::BI__builtin_ia32_lzcnt_u16:
   case clang::X86::BI__builtin_ia32_lzcnt_u32:
@@ -3280,11 +3215,33 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const CallExpr *Call,
 
   case clang::X86::BI__builtin_ia32_pdep_si:
   case clang::X86::BI__builtin_ia32_pdep_di:
-    return interp__builtin_ia32_pdep(S, OpPC, Frame, Call);
+    return interp__builtin_elementwise_int_binop(
+        S, OpPC, Call, [](const APSInt &Val, const APSInt &Mask) {
+          unsigned BitWidth = Val.getBitWidth();
+          APInt Result = APInt::getZero(BitWidth);
+
+          for (unsigned I = 0, P = 0; I != BitWidth; ++I) {
+            if (Mask[I])
+              Result.setBitVal(I, Val[P++]);
+          }
+
+          return Result;
+        });
 
   case clang::X86::BI__builtin_ia32_pext_si:
   case clang::X86::BI__builtin_ia32_pext_di:
-    return interp__builtin_ia32_pext(S, OpPC, Frame, Call);
+    return interp__builtin_elementwise_int_binop(
+        S, OpPC, Call, [](const APSInt &Val, const APSInt &Mask) {
+          unsigned BitWidth = Val.getBitWidth();
+          APInt Result = APInt::getZero(BitWidth);
+
+          for (unsigned I = 0, P = 0; I != BitWidth; ++I) {
+            if (Mask[I])
+              Result.setBitVal(P++, Val[I]);
+          }
+
+          return Result;
+        });
 
   case clang::X86::BI__builtin_ia32_addcarryx_u32:
   case clang::X86::BI__builtin_ia32_addcarryx_u64:
diff --git a/clang/test/AST/ByteCode/x86-bmi-builtins.cpp b/clang/test/AST/ByteCode/x86-bmi-builtins.cpp
new file mode 100644
index 0000000000000..28fb53b10b6f2
--- /dev/null
+++ b/clang/test/AST/ByteCode/x86-bmi-builtins.cpp
@@ -0,0 +1,67 @@
+// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -target-feature +bmi -target-feature +bmi2 -fexperimental-new-constant-interpreter -fsyntax-only %s
+// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -target-feature +bmi -target-feature +bmi2 -fsyntax-only %s
+
+// expected-no-diagnostics
+
+static_assert(__builtin_ia32_pdep_si(0x89ABCDEFu, 0x00000000u) == 0x00000000u);
+static_assert(__builtin_ia32_pdep_si(0x89ABCDEFu, 0x000000F0u) == 0x000000F0u);
+static_assert(__builtin_ia32_pdep_si(0x89ABCDEFu, 0x000000C0u) == 0x000000C0u);
+static_assert(__builtin_ia32_pdep_si(0x89ABCDEFu, 0xF00000F0u) == 0xE00000F0u);
+static_assert(__builtin_ia32_pdep_si(0x89ABCDEFu, 0xFFFFFFFFu) == 0x89ABCDEFu);
+
+static_assert(__builtin_ia32_pdep_di(0x0123456789ABCDEFULL, 0x0000000000000000ULL) ==
+              0x0000000000000000ULL);
+static_assert(__builtin_ia32_pdep_di(0x0123456789ABCDEFULL, 0x00000000000000F0ULL) ==
+              0x00000000000000F0ULL);
+static_assert(__builtin_ia32_pdep_di(0x0123456789ABCDEFULL, 0xF00000F0F00000F0ULL) ==
+              0xC00000D0E00000F0ULL);
+static_assert(__builtin_ia32_pdep_di(0x0123456789ABCDEFULL, 0xFFFFFFFFFFFFFFFFULL) ==
+              0x0123456789ABCDEFULL);
+
+static_assert(__builtin_ia32_pext_si(0x89ABCDEFu, 0x00000000u) == 0x00000000u);
+static_assert(__builtin_ia32_pext_si(0x89ABCDEFu, 0x000000F0u) == 0x0000000Eu);
+static_assert(__builtin_ia32_pext_si(0x89ABCDEFu, 0x000000C0u) == 0x00000003u);
+static_assert(__builtin_ia32_pext_si(0x89ABCDEFu, 0xF00000F0u) == 0x0000008Eu);
+static_assert(__builtin_ia32_pext_si(0x89ABCDEFu, 0xFFFFFFFFu) == 0x89ABCDEFu);
+
+static_assert(__builtin_ia32_pext_di(0x0123456789ABCDEFULL, 0x0000000000000000ULL) ==
+              0x0000000000000000ULL);
+static_assert(__builtin_ia32_pext_di(0x0123456789ABCDEFULL, 0x00000000000000F0ULL) ==
+              0x000000000000000EULL);
+static_assert(__builtin_ia32_pext_di(0x0123456789ABCDEFULL, 0xF00000F0F00000F0ULL) ==
+              0x000000000000068EULL);
+static_assert(__builtin_ia32_pext_di(0x0123456789ABCDEFULL, 0xFFFFFFFFFFFFFFFFULL) ==
+              0x0123456789ABCDEFULL);
+
+static_assert(__builtin_ia32_bzhi_si(0x89ABCDEFu, 0u) == 0x00000000u);
+static_assert(__builtin_ia32_bzhi_si(0x89ABCDEFu, 16u) == 0x0000CDEFu);
+static_assert(__builtin_ia32_bzhi_si(0x89ABCDEFu, 31u) == 0x09ABCDEFu);
+static_assert(__builtin_ia32_bzhi_si(0x89ABCDEFu, 32u) == 0x89ABCDEFu);
+static_assert(__builtin_ia32_bzhi_si(0x89ABCDEFu, 99u) == 0x89ABCDEFu);
+static_assert(__builtin_ia32_bzhi_si(0x89ABCDEFu, 260u) == 0x0000000Fu);
+
+static_assert(__builtin_ia32_bzhi_di(0x0123456789ABCDEFULL, 0ULL) == 0x0000000000000000ULL);
+static_assert(__builtin_ia32_bzhi_di(0x0123456789ABCDEFULL, 32ULL) == 0x0000000089ABCDEFULL);
+static_assert(__builtin_ia32_bzhi_di(0x0123456789ABCDEFULL, 99ULL) == 0x0123456789ABCDEFULL);
+static_assert(__builtin_ia32_bzhi_di(0x0123456789ABCDEFULL, 520ULL) == 0x00000000000000EFULL);
+
+static_assert(__builtin_ia32_bextr_u32(0x89ABCDEFu, 0x0000u) == 0x00000000u);
+static_assert(__builtin_ia32_bextr_u32(0x89ABCDEFu, 0x0800u) == 0x000000EFu);
+static_assert(__builtin_ia32_bextr_u32(0x89ABCDEFu, 0x0804u) == 0x000000DEu);
+static_assert(__builtin_ia32_bextr_u32(0x89ABCDEFu, 0x0414u) == 0x0000000Au);
+static_assert(__builtin_ia32_bextr_u32(0x89ABCDEFu, 0x081Cu) == 0x00000008u);
+static_assert(__builtin_ia32_bextr_u32(0x89ABCDEFu, 0x0428u) == 0x00000000u);
+
+static_assert(__builtin_ia32_bextri_u32(0x89ABCDEFu, 0x0800u) == 0x000000EFu);
+static_assert(__builtin_ia32_bextri_u32(0x89ABCDEFu, 0x0804u) == 0x000000DEu);
+static_assert(__builtin_ia32_bextri_u32(0x89ABCDEFu, 0x0414u) == 0x0000000Au);
+
+static_assert(__builtin_ia32_bextr_u64(0x0123456789ABCDEFULL, 0x0000ULL) == 0x0000000000000000ULL);
+static_assert(__builtin_ia32_bextr_u64(0x0123456789ABCDEFULL, 0x1008ULL) == 0x000000000000ABCDULL);
+static_assert(__builtin_ia32_bextr_u64(0x0123456789ABCDEFULL, 0x0804ULL) == 0x00000000000000DEULL);
+static_assert(__builtin_ia32_bextr_u64(0x0123456789ABCDEFULL, 0xC800ULL) == 0x0123456789ABCDEFULL);
+static_assert(__builtin_ia32_bextr_u64(0x0123456789ABCDEFULL, 0x1028ULL) == 0x0000000000002345ULL);
+static_assert(__builtin_ia32_bextr_u64(0x0123456789ABCDEFULL, 0x0850ULL) == 0x0000000000000000ULL);
+
+static_assert(__builtin_ia32_bextri_u64(0x0123456789ABCDEFULL, 0x1008ULL) == 0x000000000000ABCDULL);
+static_assert(__builtin_ia32_bextri_u64(0x0123456789ABCDEFULL, 0x0804ULL) == 0x00000000000000DEULL);

>From 2625c644c65acddde852601eed4658fe4bab5220 Mon Sep 17 00:00:00 2001
From: jiang1997 <jieke at live.cn>
Date: Thu, 25 Sep 2025 01:56:56 +0800
Subject: [PATCH 2/3] Use APInt instead of APSInt

---
 clang/lib/AST/ByteCode/InterpBuiltin.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang/lib/AST/ByteCode/InterpBuiltin.cpp b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
index d34704419b59e..6119970ec7467 100644
--- a/clang/lib/AST/ByteCode/InterpBuiltin.cpp
+++ b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
@@ -3189,7 +3189,7 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const CallExpr *Call,
         S, OpPC, Call, [](const APSInt &Val, const APSInt &Idx) {
           unsigned BitWidth = Val.getBitWidth();
           uint64_t Index = Idx.extractBitsAsZExtValue(8, 0);
-          APSInt Result = Val;
+          APInt Result = Val;
 
           if (Index < BitWidth)
             Result.clearHighBits(BitWidth - Index);

>From 59dd8b6901b7df6d2ca7718af6d48445db9b199f Mon Sep 17 00:00:00 2001
From: jiang1997 <jieke at live.cn>
Date: Thu, 25 Sep 2025 01:57:31 +0800
Subject: [PATCH 3/3] Remove unnecessary braces for code style consistency

---
 clang/lib/AST/ByteCode/InterpBuiltin.cpp | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/clang/lib/AST/ByteCode/InterpBuiltin.cpp b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
index 6119970ec7467..82067be828c64 100644
--- a/clang/lib/AST/ByteCode/InterpBuiltin.cpp
+++ b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
@@ -3170,9 +3170,8 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const CallExpr *Call,
           unsigned BitWidth = Val.getBitWidth();
           uint64_t Shift = Idx.extractBitsAsZExtValue(8, 0);
           uint64_t Length = Idx.extractBitsAsZExtValue(8, 8);
-          if (Length > BitWidth) {
+          if (Length > BitWidth)
             Length = BitWidth;
-          }
 
           // Handle out of bounds cases.
           if (Length == 0 || Shift >= BitWidth)



More information about the cfe-commits mailing list