[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 08:42:53 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] [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);
More information about the cfe-commits
mailing list