Skip to content

Commit 00158ae

Browse files
alexguirreRKSimon
authored andcommitted
[clang] Enable constexpr on LZCNT/POPCNT MS extension intrinsics
As discussed on #46593 - this enables us to use __lzcnt / __popcnt intrinsics inside constexpr code. Differential Revision: https://reviews.llvm.org/D157420
1 parent dda2cd2 commit 00158ae

File tree

4 files changed

+86
-9
lines changed

4 files changed

+86
-9
lines changed

clang/docs/LanguageExtensions.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5225,12 +5225,18 @@ The following x86-specific intrinsics can be used in constant expressions:
52255225
* ``_castf64_u64``
52265226
* ``_castu32_f32``
52275227
* ``_castu64_f64``
5228+
* ``__lzcnt16``
5229+
* ``__lzcnt``
5230+
* ``__lzcnt64``
52285231
* ``_mm_popcnt_u32``
52295232
* ``_mm_popcnt_u64``
52305233
* ``_popcnt32``
52315234
* ``_popcnt64``
52325235
* ``__popcntd``
52335236
* ``__popcntq``
5237+
* ``__popcnt16``
5238+
* ``__popcnt``
5239+
* ``__popcnt64``
52345240
* ``__rolb``
52355241
* ``__rolw``
52365242
* ``__rold``

clang/include/clang/Basic/Builtins.def

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1017,12 +1017,12 @@ LANGBUILTIN(__iso_volatile_store16, "vsD*s", "n", ALL_MS_LANGUAGES)
10171017
LANGBUILTIN(__iso_volatile_store32, "viD*i", "n", ALL_MS_LANGUAGES)
10181018
LANGBUILTIN(__iso_volatile_store64, "vLLiD*LLi", "n", ALL_MS_LANGUAGES)
10191019
LANGBUILTIN(__noop, "i.", "n", ALL_MS_LANGUAGES)
1020-
LANGBUILTIN(__lzcnt16, "UsUs", "nc", ALL_MS_LANGUAGES)
1021-
LANGBUILTIN(__lzcnt, "UiUi", "nc", ALL_MS_LANGUAGES)
1022-
LANGBUILTIN(__lzcnt64, "UWiUWi", "nc", ALL_MS_LANGUAGES)
1023-
LANGBUILTIN(__popcnt16, "UsUs", "nc", ALL_MS_LANGUAGES)
1024-
LANGBUILTIN(__popcnt, "UiUi", "nc", ALL_MS_LANGUAGES)
1025-
LANGBUILTIN(__popcnt64, "UWiUWi", "nc", ALL_MS_LANGUAGES)
1020+
LANGBUILTIN(__lzcnt16, "UsUs", "ncE", ALL_MS_LANGUAGES)
1021+
LANGBUILTIN(__lzcnt, "UiUi", "ncE", ALL_MS_LANGUAGES)
1022+
LANGBUILTIN(__lzcnt64, "UWiUWi", "ncE", ALL_MS_LANGUAGES)
1023+
LANGBUILTIN(__popcnt16, "UsUs", "ncE", ALL_MS_LANGUAGES)
1024+
LANGBUILTIN(__popcnt, "UiUi", "ncE", ALL_MS_LANGUAGES)
1025+
LANGBUILTIN(__popcnt64, "UWiUWi", "ncE", ALL_MS_LANGUAGES)
10261026
LANGBUILTIN(_ReturnAddress, "v*", "n", ALL_MS_LANGUAGES)
10271027
LANGBUILTIN(_rotl8, "UcUcUc", "nE", ALL_MS_LANGUAGES)
10281028
LANGBUILTIN(_rotl16, "UsUsUc", "nE", ALL_MS_LANGUAGES)

clang/lib/AST/ExprConstant.cpp

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12124,11 +12124,21 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
1212412124
case Builtin::BI__builtin_clz:
1212512125
case Builtin::BI__builtin_clzl:
1212612126
case Builtin::BI__builtin_clzll:
12127-
case Builtin::BI__builtin_clzs: {
12127+
case Builtin::BI__builtin_clzs:
12128+
case Builtin::BI__lzcnt16: // Microsoft variants of count leading-zeroes
12129+
case Builtin::BI__lzcnt:
12130+
case Builtin::BI__lzcnt64: {
1212812131
APSInt Val;
1212912132
if (!EvaluateInteger(E->getArg(0), Val, Info))
1213012133
return false;
12131-
if (!Val)
12134+
12135+
// When the argument is 0, the result of GCC builtins is undefined, whereas
12136+
// for Microsoft intrinsics, the result is the bit-width of the argument.
12137+
bool ZeroIsUndefined = BuiltinOp != Builtin::BI__lzcnt16 &&
12138+
BuiltinOp != Builtin::BI__lzcnt &&
12139+
BuiltinOp != Builtin::BI__lzcnt64;
12140+
12141+
if (ZeroIsUndefined && !Val)
1213212142
return Error(E);
1213312143

1213412144
return Success(Val.countl_zero(), E);
@@ -12267,7 +12277,10 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
1226712277

1226812278
case Builtin::BI__builtin_popcount:
1226912279
case Builtin::BI__builtin_popcountl:
12270-
case Builtin::BI__builtin_popcountll: {
12280+
case Builtin::BI__builtin_popcountll:
12281+
case Builtin::BI__popcnt16: // Microsoft variants of popcount
12282+
case Builtin::BI__popcnt:
12283+
case Builtin::BI__popcnt64: {
1227112284
APSInt Val;
1227212285
if (!EvaluateInteger(E->getArg(0), Val, Info))
1227312286
return false;

clang/test/CodeGen/ms-intrinsics-other.c

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,38 @@
1414
// RUN: -triple armv7--darwin -Oz -emit-llvm %s -o - \
1515
// RUN: | FileCheck %s --check-prefix=CHECK-ARM
1616

17+
// RUN: %clang_cc1 -x c++ -std=c++11 \
18+
// RUN: -ffreestanding -fms-extensions -Wno-implicit-function-declaration \
19+
// RUN: -triple x86_64--darwin -Oz -emit-llvm %s -o - \
20+
// RUN: | FileCheck %s
21+
// RUN: %clang_cc1 -x c++ -std=c++11 \
22+
// RUN: -ffreestanding -fms-extensions -Wno-implicit-function-declaration \
23+
// RUN: -triple x86_64--linux -Oz -emit-llvm %s -o - \
24+
// RUN: | FileCheck %s
25+
// RUN: %clang_cc1 -x c++ -std=c++11 \
26+
// RUN: -ffreestanding -fms-extensions -Wno-implicit-function-declaration \
27+
// RUN: -triple aarch64--darwin -Oz -emit-llvm %s -o - \
28+
// RUN: | FileCheck %s --check-prefix=CHECK-ARM-ARM64
29+
// RUN: %clang_cc1 -x c++ -std=c++11 \
30+
// RUN: -ffreestanding -fms-extensions -Wno-implicit-function-declaration \
31+
// RUN: -triple aarch64--darwin -Oz -emit-llvm %s -o - \
32+
// RUN: | FileCheck %s --check-prefix=CHECK-ARM
33+
// RUN: %clang_cc1 -x c++ -std=c++11 \
34+
// RUN: -ffreestanding -fms-extensions -Wno-implicit-function-declaration \
35+
// RUN: -triple armv7--darwin -Oz -emit-llvm %s -o - \
36+
// RUN: | FileCheck %s --check-prefix=CHECK-ARM
37+
1738
// LP64 targets use 'long' as 'int' for MS intrinsics (-fms-extensions)
1839
#ifdef __LP64__
1940
#define LONG int
2041
#else
2142
#define LONG long
2243
#endif
2344

45+
#ifdef __cplusplus
46+
extern "C" {
47+
#endif
48+
2449
unsigned char test_BitScanForward(unsigned LONG *Index, unsigned LONG Mask) {
2550
return _BitScanForward(Index, Mask);
2651
}
@@ -416,3 +441,36 @@ LONG test_InterlockedDecrement_nf(LONG volatile *Addend) {
416441
// CHECK-ARM: ret i32 [[RESULT]]
417442
// CHECK-ARM: }
418443
#endif
444+
445+
#ifdef __cplusplus
446+
}
447+
#endif
448+
449+
450+
// Test constexpr handling.
451+
#if defined(__cplusplus) && (__cplusplus >= 201103L)
452+
453+
char popcnt16_0[__popcnt16(0x0000) == 0 ? 1 : -1];
454+
char popcnt16_1[__popcnt16(0x10F0) == 5 ? 1 : -1];
455+
456+
char popcnt_0[__popcnt(0x00000000) == 0 ? 1 : -1];
457+
char popcnt_1[__popcnt(0x100000F0) == 5 ? 1 : -1];
458+
459+
char popcnt64_0[__popcnt64(0x0000000000000000ULL) == 0 ? 1 : -1];
460+
char popcnt64_1[__popcnt64(0xF00000F000000001ULL) == 9 ? 1 : -1];
461+
462+
#define BITSIZE(x) (sizeof(x) * 8)
463+
char lzcnt16_0[__lzcnt16(1) == BITSIZE(short) - 1 ? 1 : -1];
464+
char lzcnt16_1[__lzcnt16(1 << (BITSIZE(short) - 1)) == 0 ? 1 : -1];
465+
char lzcnt16_2[__lzcnt16(0) == BITSIZE(short) ? 1 : -1];
466+
467+
char lzcnt_0[__lzcnt(1) == BITSIZE(int) - 1 ? 1 : -1];
468+
char lzcnt_1[__lzcnt(1 << (BITSIZE(int) - 1)) == 0 ? 1 : -1];
469+
char lzcnt_2[__lzcnt(0) == BITSIZE(int) ? 1 : -1];
470+
471+
char lzcnt64_0[__lzcnt64(1ULL) == BITSIZE(__int64) - 1 ? 1 : -1];
472+
char lzcnt64_1[__lzcnt64(1ULL << (BITSIZE(__int64) - 1)) == 0 ? 1 : -1];
473+
char lzcnt64_2[__lzcnt64(0ULL) == BITSIZE(__int64) ? 1 : -1];
474+
#undef BITSIZE
475+
476+
#endif

0 commit comments

Comments
 (0)