Skip to content

Commit 1c2ed36

Browse files
authored
[clang][x86] Add constexpr support for BMI/TBM BEXTR intrinsics (#109577)
This is an initial patch for constexpr handling of the BEXTR intrinsics - the plan is to support all x86 bit manipulation intrinsics eventually (and then SSE/AVX intrinsics), but I wanted to treat this as an initial test patch. Hopefully this will unstick #94161 as well.
1 parent 795c24c commit 1c2ed36

File tree

6 files changed

+94
-23
lines changed

6 files changed

+94
-23
lines changed

clang/include/clang/Basic/BuiltinsX86.def

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -555,7 +555,7 @@ TARGET_BUILTIN(__builtin_ia32_lzcnt_u16, "UsUs", "nc", "lzcnt")
555555
TARGET_BUILTIN(__builtin_ia32_lzcnt_u32, "UiUi", "nc", "lzcnt")
556556

557557
// BMI
558-
TARGET_BUILTIN(__builtin_ia32_bextr_u32, "UiUiUi", "nc", "bmi")
558+
TARGET_BUILTIN(__builtin_ia32_bextr_u32, "UiUiUi", "ncE", "bmi")
559559
TARGET_BUILTIN(__builtin_ia32_tzcnt_u16, "UsUs", "nc", "")
560560
TARGET_BUILTIN(__builtin_ia32_tzcnt_u32, "UiUi", "nc", "")
561561

@@ -565,7 +565,7 @@ TARGET_BUILTIN(__builtin_ia32_pdep_si, "UiUiUi", "nc", "bmi2")
565565
TARGET_BUILTIN(__builtin_ia32_pext_si, "UiUiUi", "nc", "bmi2")
566566

567567
// TBM
568-
TARGET_BUILTIN(__builtin_ia32_bextri_u32, "UiUiIUi", "nc", "tbm")
568+
TARGET_BUILTIN(__builtin_ia32_bextri_u32, "UiUiIUi", "ncE", "tbm")
569569

570570
// LWP
571571
TARGET_BUILTIN(__builtin_ia32_llwpcb, "vv*", "n", "lwp")

clang/include/clang/Basic/BuiltinsX86_64.def

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,12 +71,12 @@ TARGET_BUILTIN(__builtin_ia32_subborrow_u64, "UcUcUOiUOiUOi*", "n", "")
7171
TARGET_BUILTIN(__builtin_ia32_rdrand64_step, "UiUOi*", "n", "rdrnd")
7272
TARGET_BUILTIN(__builtin_ia32_rdseed64_step, "UiUOi*", "n", "rdseed")
7373
TARGET_BUILTIN(__builtin_ia32_lzcnt_u64, "UOiUOi", "nc", "lzcnt")
74-
TARGET_BUILTIN(__builtin_ia32_bextr_u64, "UOiUOiUOi", "nc", "bmi")
74+
TARGET_BUILTIN(__builtin_ia32_bextr_u64, "UOiUOiUOi", "ncE", "bmi")
7575
TARGET_BUILTIN(__builtin_ia32_tzcnt_u64, "UOiUOi", "nc", "")
7676
TARGET_BUILTIN(__builtin_ia32_bzhi_di, "UOiUOiUOi", "nc", "bmi2")
7777
TARGET_BUILTIN(__builtin_ia32_pdep_di, "UOiUOiUOi", "nc", "bmi2")
7878
TARGET_BUILTIN(__builtin_ia32_pext_di, "UOiUOiUOi", "nc", "bmi2")
79-
TARGET_BUILTIN(__builtin_ia32_bextri_u64, "UOiUOiIUOi", "nc", "tbm")
79+
TARGET_BUILTIN(__builtin_ia32_bextri_u64, "UOiUOiIUOi", "ncE", "tbm")
8080
TARGET_BUILTIN(__builtin_ia32_lwpins64, "UcUOiUiIUi", "n", "lwp")
8181
TARGET_BUILTIN(__builtin_ia32_lwpval64, "vUOiUiIUi", "n", "lwp")
8282
TARGET_BUILTIN(__builtin_ia32_vcvtsd2si64, "OiV2dIi", "ncV:128:", "avx512f")

clang/lib/AST/ExprConstant.cpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
#include "clang/AST/TypeLoc.h"
5353
#include "clang/Basic/Builtins.h"
5454
#include "clang/Basic/DiagnosticSema.h"
55+
#include "clang/Basic/TargetBuiltins.h"
5556
#include "clang/Basic/TargetInfo.h"
5657
#include "llvm/ADT/APFixedPoint.h"
5758
#include "llvm/ADT/Sequence.h"
@@ -13462,6 +13463,29 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
1346213463
return false;
1346313464
return Success(DidOverflow, E);
1346413465
}
13466+
13467+
case clang::X86::BI__builtin_ia32_bextr_u32:
13468+
case clang::X86::BI__builtin_ia32_bextr_u64:
13469+
case clang::X86::BI__builtin_ia32_bextri_u32:
13470+
case clang::X86::BI__builtin_ia32_bextri_u64: {
13471+
APSInt Val, Idx;
13472+
if (!EvaluateInteger(E->getArg(0), Val, Info) ||
13473+
!EvaluateInteger(E->getArg(1), Idx, Info))
13474+
return false;
13475+
13476+
unsigned BitWidth = Val.getBitWidth();
13477+
uint64_t Shift = Idx.extractBitsAsZExtValue(8, 0);
13478+
uint64_t Length = Idx.extractBitsAsZExtValue(8, 8);
13479+
Length = Length > BitWidth ? BitWidth : Length;
13480+
13481+
// Handle out of bounds cases.
13482+
if (Length == 0 || Shift >= BitWidth)
13483+
return Success(0, E);
13484+
13485+
uint64_t Result = Val.getZExtValue() >> Shift;
13486+
Result &= llvm::maskTrailingOnes<uint64_t>(Length);
13487+
return Success(Result, E);
13488+
}
1346513489
}
1346613490
}
1346713491

clang/lib/Headers/bmiintrin.h

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,12 @@ _mm_tzcnt_64(unsigned long long __X)
166166
/* Define the default attributes for the functions in this file. */
167167
#define __DEFAULT_FN_ATTRS __attribute__((__always_inline__, __nodebug__, __target__("bmi")))
168168

169+
#if defined(__cplusplus) && (__cplusplus >= 201103L)
170+
#define __DEFAULT_FN_ATTRS_CONSTEXPR __DEFAULT_FN_ATTRS constexpr
171+
#else
172+
#define __DEFAULT_FN_ATTRS_CONSTEXPR __DEFAULT_FN_ATTRS
173+
#endif
174+
169175
/// Performs a bitwise AND of the second operand with the one's
170176
/// complement of the first operand.
171177
///
@@ -223,9 +229,8 @@ __andn_u32(unsigned int __X, unsigned int __Y)
223229
/// \returns An unsigned integer whose least significant bits contain the
224230
/// extracted bits.
225231
/// \see _bextr_u32
226-
static __inline__ unsigned int __DEFAULT_FN_ATTRS
227-
__bextr_u32(unsigned int __X, unsigned int __Y)
228-
{
232+
static __inline__ unsigned int __DEFAULT_FN_ATTRS_CONSTEXPR
233+
__bextr_u32(unsigned int __X, unsigned int __Y) {
229234
return __builtin_ia32_bextr_u32(__X, __Y);
230235
}
231236

@@ -248,10 +253,9 @@ __bextr_u32(unsigned int __X, unsigned int __Y)
248253
/// \returns An unsigned integer whose least significant bits contain the
249254
/// extracted bits.
250255
/// \see __bextr_u32
251-
static __inline__ unsigned int __DEFAULT_FN_ATTRS
252-
_bextr_u32(unsigned int __X, unsigned int __Y, unsigned int __Z)
253-
{
254-
return __builtin_ia32_bextr_u32 (__X, ((__Y & 0xff) | ((__Z & 0xff) << 8)));
256+
static __inline__ unsigned int __DEFAULT_FN_ATTRS_CONSTEXPR
257+
_bextr_u32(unsigned int __X, unsigned int __Y, unsigned int __Z) {
258+
return __builtin_ia32_bextr_u32(__X, ((__Y & 0xff) | ((__Z & 0xff) << 8)));
255259
}
256260

257261
/* Intel-specified, single-leading-underscore version of BEXTR2 */
@@ -271,7 +275,7 @@ _bextr_u32(unsigned int __X, unsigned int __Y, unsigned int __Z)
271275
/// \returns An unsigned integer whose least significant bits contain the
272276
/// extracted bits.
273277
/// \see __bextr_u32
274-
static __inline__ unsigned int __DEFAULT_FN_ATTRS
278+
static __inline__ unsigned int __DEFAULT_FN_ATTRS_CONSTEXPR
275279
_bextr2_u32(unsigned int __X, unsigned int __Y) {
276280
return __builtin_ia32_bextr_u32(__X, __Y);
277281
}
@@ -444,9 +448,8 @@ __andn_u64 (unsigned long long __X, unsigned long long __Y)
444448
/// \returns An unsigned 64-bit integer whose least significant bits contain the
445449
/// extracted bits.
446450
/// \see _bextr_u64
447-
static __inline__ unsigned long long __DEFAULT_FN_ATTRS
448-
__bextr_u64(unsigned long long __X, unsigned long long __Y)
449-
{
451+
static __inline__ unsigned long long __DEFAULT_FN_ATTRS_CONSTEXPR
452+
__bextr_u64(unsigned long long __X, unsigned long long __Y) {
450453
return __builtin_ia32_bextr_u64(__X, __Y);
451454
}
452455

@@ -469,10 +472,9 @@ __bextr_u64(unsigned long long __X, unsigned long long __Y)
469472
/// \returns An unsigned 64-bit integer whose least significant bits contain the
470473
/// extracted bits.
471474
/// \see __bextr_u64
472-
static __inline__ unsigned long long __DEFAULT_FN_ATTRS
473-
_bextr_u64(unsigned long long __X, unsigned int __Y, unsigned int __Z)
474-
{
475-
return __builtin_ia32_bextr_u64 (__X, ((__Y & 0xff) | ((__Z & 0xff) << 8)));
475+
static __inline__ unsigned long long __DEFAULT_FN_ATTRS_CONSTEXPR
476+
_bextr_u64(unsigned long long __X, unsigned int __Y, unsigned int __Z) {
477+
return __builtin_ia32_bextr_u64(__X, ((__Y & 0xff) | ((__Z & 0xff) << 8)));
476478
}
477479

478480
/* Intel-specified, single-leading-underscore version of BEXTR2 */
@@ -492,7 +494,7 @@ _bextr_u64(unsigned long long __X, unsigned int __Y, unsigned int __Z)
492494
/// \returns An unsigned 64-bit integer whose least significant bits contain the
493495
/// extracted bits.
494496
/// \see __bextr_u64
495-
static __inline__ unsigned long long __DEFAULT_FN_ATTRS
497+
static __inline__ unsigned long long __DEFAULT_FN_ATTRS_CONSTEXPR
496498
_bextr2_u64(unsigned long long __X, unsigned long long __Y) {
497499
return __builtin_ia32_bextr_u64(__X, __Y);
498500
}

clang/test/CodeGen/X86/bmi-builtins.c

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1-
// RUN: %clang_cc1 -ffreestanding %s -triple=x86_64-apple-darwin -target-feature +bmi -emit-llvm -o - -Wall -Werror | FileCheck %s --check-prefixes=CHECK,TZCNT
2-
// RUN: %clang_cc1 -fms-extensions -fms-compatibility -fms-compatibility-version=17.00 -ffreestanding %s -triple=x86_64-windows-msvc -emit-llvm -o - -Wall -Werror -DTEST_TZCNT | FileCheck %s --check-prefix=TZCNT
1+
// RUN: %clang_cc1 -x c -ffreestanding %s -triple=x86_64-apple-darwin -target-feature +bmi -emit-llvm -o - -Wall -Werror | FileCheck %s --check-prefixes=CHECK,TZCNT
2+
// RUN: %clang_cc1 -x c -fms-extensions -fms-compatibility -fms-compatibility-version=17.00 -ffreestanding %s -triple=x86_64-windows-msvc -emit-llvm -o - -Wall -Werror -DTEST_TZCNT | FileCheck %s --check-prefix=TZCNT
3+
// RUN: %clang_cc1 -x c++ -std=c++11 -ffreestanding %s -triple=x86_64-apple-darwin -target-feature +bmi -emit-llvm -o - -Wall -Werror | FileCheck %s --check-prefixes=CHECK,TZCNT
4+
// RUN: %clang_cc1 -x c++ -std=c++11 -fms-extensions -fms-compatibility -fms-compatibility-version=17.00 -ffreestanding %s -triple=x86_64-windows-msvc -emit-llvm -o - -Wall -Werror -DTEST_TZCNT | FileCheck %s --check-prefix=TZCNT
35

46

57
#include <immintrin.h>
@@ -232,3 +234,32 @@ unsigned long long test_blsr_u64(unsigned long long __X) {
232234
#endif
233235

234236
#endif // !defined(TEST_TZCNT)
237+
238+
// Test constexpr handling.
239+
#if defined(__cplusplus) && (__cplusplus >= 201103L)
240+
char bextr32_0[__bextr_u32(0x00000000, 0x00000000) == 0x00000000 ? 1 : -1];
241+
char bextr32_1[__bextr_u32(0x000003F0, 0xFFFF1004) == 0x0000003F ? 1 : -1];
242+
char bextr32_2[__bextr_u32(0x000003F0, 0xFFFF3008) == 0x00000003 ? 1 : -1];
243+
244+
char bextr32_3[_bextr2_u32(0x00000000, 0x00000000) == 0x00000000 ? 1 : -1];
245+
char bextr32_4[_bextr2_u32(0x000003F0, 0xFFFF1004) == 0x0000003F ? 1 : -1];
246+
char bextr32_5[_bextr2_u32(0x000003F0, 0xFFFF3008) == 0x00000003 ? 1 : -1];
247+
248+
char bextr32_6[_bextr_u32(0x00000000, 0x00000000, 0x00000000) == 0x00000000 ? 1 : -1];
249+
char bextr32_7[_bextr_u32(0x000003F0, 0xFFFFFF04, 0xFFFFFF10) == 0x0000003F ? 1 : -1];
250+
char bextr32_8[_bextr_u32(0x000003F0, 0xFFFFFF08, 0xFFFFFF30) == 0x00000003 ? 1 : -1];
251+
252+
#ifdef __x86_64__
253+
char bextr64_0[__bextr_u64(0x0000000000000000ULL, 0x0000000000000000ULL) == 0x0000000000000000ULL ? 1 : -1];
254+
char bextr64_1[__bextr_u64(0xF000000000000001ULL, 0x0000000000004001ULL) == 0x7800000000000000ULL ? 1 : -1];
255+
char bextr64_2[__bextr_u64(0xF000000000000001ULL, 0xFFFFFFFFFFFF1001ULL) == 0x0000000000000000ULL ? 1 : -1];
256+
257+
char bextr64_3[_bextr2_u64(0x0000000000000000ULL, 0x0000000000000000ULL) == 0x0000000000000000ULL ? 1 : -1];
258+
char bextr64_4[_bextr2_u64(0xF000000000000001ULL, 0x0000000000004001ULL) == 0x7800000000000000ULL ? 1 : -1];
259+
char bextr64_5[_bextr2_u64(0xF000000000000001ULL, 0xFFFFFFFFFFFF1001ULL) == 0x0000000000000000ULL ? 1 : -1];
260+
261+
char bextr64_6[_bextr_u64(0x0000000000000000ULL, 0x0000000000000000ULL, 0x0000000000000000ULL) == 0x0000000000000000ULL ? 1 : -1];
262+
char bextr64_7[_bextr_u64(0xF000000000000001ULL, 0x0000000000000001ULL, 0x0000000000000040ULL) == 0x7800000000000000ULL ? 1 : -1];
263+
char bextr64_8[_bextr_u64(0xF000000000000001ULL, 0xFFFFFFFFFFFFFF01ULL, 0xFFFFFFFFFFFFFF10ULL) == 0x0000000000000000ULL ? 1 : -1];
264+
#endif
265+
#endif

clang/test/CodeGen/X86/tbm-builtins.c

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
// RUN: %clang_cc1 -ffreestanding %s -triple=x86_64-unknown-unknown -target-feature +tbm -emit-llvm -o - | FileCheck %s
1+
// RUN: %clang_cc1 -x c -ffreestanding %s -triple=x86_64-unknown-unknown -target-feature +tbm -emit-llvm -o - | FileCheck %s
2+
// RUN: %clang_cc1 -x c++ -std=c++11 -ffreestanding %s -triple=x86_64-unknown-unknown -target-feature +tbm -emit-llvm -o - | FileCheck %s
23

34
#include <x86intrin.h>
45

@@ -177,3 +178,16 @@ unsigned long long test__tzmsk_u64(unsigned long long a) {
177178
return __tzmsk_u64(a);
178179
}
179180
#endif
181+
182+
// Test constexpr handling.
183+
#if defined(__cplusplus) && (__cplusplus >= 201103L)
184+
char bextri32_0[__bextri_u32(0x00000000, 0x00000000) == 0x00000000 ? 1 : -1];
185+
char bextri32_1[__bextri_u32(0x000003F0, 0xFFFF1004) == 0x0000003F ? 1 : -1];
186+
char bextri32_2[__bextri_u32(0x000003F0, 0xFFFF3008) == 0x00000003 ? 1 : -1];
187+
188+
#ifdef __x86_64__
189+
char bextri64_0[__bextri_u64(0x0000000000000000ULL, 0x0000000000000000ULL) == 0x0000000000000000ULL ? 1 : -1];
190+
char bextri64_1[__bextri_u64(0xF000000000000001ULL, 0x0000000000004001ULL) == 0x7800000000000000ULL ? 1 : -1];
191+
char bextri64_2[__bextri_u64(0xF000000000000001ULL, 0xFFFFFFFFFFFF1001ULL) == 0x0000000000000000ULL ? 1 : -1];
192+
#endif
193+
#endif

0 commit comments

Comments
 (0)