diff --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst --- a/clang/docs/LanguageExtensions.rst +++ b/clang/docs/LanguageExtensions.rst @@ -5225,12 +5225,18 @@ * ``_castf64_u64`` * ``_castu32_f32`` * ``_castu64_f64`` +* ``__lzcnt16`` +* ``__lzcnt`` +* ``__lzcnt64`` * ``_mm_popcnt_u32`` * ``_mm_popcnt_u64`` * ``_popcnt32`` * ``_popcnt64`` * ``__popcntd`` * ``__popcntq`` +* ``__popcnt16`` +* ``__popcnt`` +* ``__popcnt64`` * ``__rolb`` * ``__rolw`` * ``__rold`` diff --git a/clang/include/clang/Basic/Builtins.def b/clang/include/clang/Basic/Builtins.def --- a/clang/include/clang/Basic/Builtins.def +++ b/clang/include/clang/Basic/Builtins.def @@ -1017,12 +1017,12 @@ LANGBUILTIN(__iso_volatile_store32, "viD*i", "n", ALL_MS_LANGUAGES) LANGBUILTIN(__iso_volatile_store64, "vLLiD*LLi", "n", ALL_MS_LANGUAGES) LANGBUILTIN(__noop, "i.", "n", ALL_MS_LANGUAGES) -LANGBUILTIN(__lzcnt16, "UsUs", "nc", ALL_MS_LANGUAGES) -LANGBUILTIN(__lzcnt, "UiUi", "nc", ALL_MS_LANGUAGES) -LANGBUILTIN(__lzcnt64, "UWiUWi", "nc", ALL_MS_LANGUAGES) -LANGBUILTIN(__popcnt16, "UsUs", "nc", ALL_MS_LANGUAGES) -LANGBUILTIN(__popcnt, "UiUi", "nc", ALL_MS_LANGUAGES) -LANGBUILTIN(__popcnt64, "UWiUWi", "nc", ALL_MS_LANGUAGES) +LANGBUILTIN(__lzcnt16, "UsUs", "ncE", ALL_MS_LANGUAGES) +LANGBUILTIN(__lzcnt, "UiUi", "ncE", ALL_MS_LANGUAGES) +LANGBUILTIN(__lzcnt64, "UWiUWi", "ncE", ALL_MS_LANGUAGES) +LANGBUILTIN(__popcnt16, "UsUs", "ncE", ALL_MS_LANGUAGES) +LANGBUILTIN(__popcnt, "UiUi", "ncE", ALL_MS_LANGUAGES) +LANGBUILTIN(__popcnt64, "UWiUWi", "ncE", ALL_MS_LANGUAGES) LANGBUILTIN(_ReturnAddress, "v*", "n", ALL_MS_LANGUAGES) LANGBUILTIN(_rotl8, "UcUcUc", "nE", ALL_MS_LANGUAGES) LANGBUILTIN(_rotl16, "UsUsUc", "nE", ALL_MS_LANGUAGES) diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -12124,11 +12124,21 @@ case Builtin::BI__builtin_clz: case Builtin::BI__builtin_clzl: case Builtin::BI__builtin_clzll: - case Builtin::BI__builtin_clzs: { + case Builtin::BI__builtin_clzs: + case Builtin::BI__lzcnt16: // Microsoft variants of count leading-zeroes + case Builtin::BI__lzcnt: + case Builtin::BI__lzcnt64: { APSInt Val; if (!EvaluateInteger(E->getArg(0), Val, Info)) return false; - if (!Val) + + // When the argument is 0, the result of GCC builtins is undefined, whereas + // for Microsoft intrinsics, the result is the bit-width of the argument. + bool ZeroIsUndefined = BuiltinOp != Builtin::BI__lzcnt16 && + BuiltinOp != Builtin::BI__lzcnt && + BuiltinOp != Builtin::BI__lzcnt64; + + if (ZeroIsUndefined && !Val) return Error(E); return Success(Val.countl_zero(), E); @@ -12267,7 +12277,10 @@ case Builtin::BI__builtin_popcount: case Builtin::BI__builtin_popcountl: - case Builtin::BI__builtin_popcountll: { + case Builtin::BI__builtin_popcountll: + case Builtin::BI__popcnt16: // Microsoft variants of popcount + case Builtin::BI__popcnt: + case Builtin::BI__popcnt64: { APSInt Val; if (!EvaluateInteger(E->getArg(0), Val, Info)) return false; diff --git a/clang/test/CodeGen/ms-intrinsics-other.c b/clang/test/CodeGen/ms-intrinsics-other.c --- a/clang/test/CodeGen/ms-intrinsics-other.c +++ b/clang/test/CodeGen/ms-intrinsics-other.c @@ -14,6 +14,27 @@ // RUN: -triple armv7--darwin -Oz -emit-llvm %s -o - \ // RUN: | FileCheck %s --check-prefix=CHECK-ARM +// RUN: %clang_cc1 -x c++ -std=c++11 \ +// RUN: -ffreestanding -fms-extensions -Wno-implicit-function-declaration \ +// RUN: -triple x86_64--darwin -Oz -emit-llvm %s -o - \ +// RUN: | FileCheck %s +// RUN: %clang_cc1 -x c++ -std=c++11 \ +// RUN: -ffreestanding -fms-extensions -Wno-implicit-function-declaration \ +// RUN: -triple x86_64--linux -Oz -emit-llvm %s -o - \ +// RUN: | FileCheck %s +// RUN: %clang_cc1 -x c++ -std=c++11 \ +// RUN: -ffreestanding -fms-extensions -Wno-implicit-function-declaration \ +// RUN: -triple aarch64--darwin -Oz -emit-llvm %s -o - \ +// RUN: | FileCheck %s --check-prefix=CHECK-ARM-ARM64 +// RUN: %clang_cc1 -x c++ -std=c++11 \ +// RUN: -ffreestanding -fms-extensions -Wno-implicit-function-declaration \ +// RUN: -triple aarch64--darwin -Oz -emit-llvm %s -o - \ +// RUN: | FileCheck %s --check-prefix=CHECK-ARM +// RUN: %clang_cc1 -x c++ -std=c++11 \ +// RUN: -ffreestanding -fms-extensions -Wno-implicit-function-declaration \ +// RUN: -triple armv7--darwin -Oz -emit-llvm %s -o - \ +// RUN: | FileCheck %s --check-prefix=CHECK-ARM + // LP64 targets use 'long' as 'int' for MS intrinsics (-fms-extensions) #ifdef __LP64__ #define LONG int @@ -21,6 +42,10 @@ #define LONG long #endif +#ifdef __cplusplus +extern "C" { +#endif + unsigned char test_BitScanForward(unsigned LONG *Index, unsigned LONG Mask) { return _BitScanForward(Index, Mask); } @@ -416,3 +441,36 @@ // CHECK-ARM: ret i32 [[RESULT]] // CHECK-ARM: } #endif + +#ifdef __cplusplus +} +#endif + + +// Test constexpr handling. +#if defined(__cplusplus) && (__cplusplus >= 201103L) + +char popcnt16_0[__popcnt16(0x0000) == 0 ? 1 : -1]; +char popcnt16_1[__popcnt16(0x10F0) == 5 ? 1 : -1]; + +char popcnt_0[__popcnt(0x00000000) == 0 ? 1 : -1]; +char popcnt_1[__popcnt(0x100000F0) == 5 ? 1 : -1]; + +char popcnt64_0[__popcnt64(0x0000000000000000ULL) == 0 ? 1 : -1]; +char popcnt64_1[__popcnt64(0xF00000F000000001ULL) == 9 ? 1 : -1]; + +#define BITSIZE(x) (sizeof(x) * 8) +char lzcnt16_0[__lzcnt16(1) == BITSIZE(short) - 1 ? 1 : -1]; +char lzcnt16_1[__lzcnt16(1 << (BITSIZE(short) - 1)) == 0 ? 1 : -1]; +char lzcnt16_2[__lzcnt16(0) == BITSIZE(short) ? 1 : -1]; + +char lzcnt_0[__lzcnt(1) == BITSIZE(int) - 1 ? 1 : -1]; +char lzcnt_1[__lzcnt(1 << (BITSIZE(int) - 1)) == 0 ? 1 : -1]; +char lzcnt_2[__lzcnt(0) == BITSIZE(int) ? 1 : -1]; + +char lzcnt64_0[__lzcnt64(1ULL) == BITSIZE(__int64) - 1 ? 1 : -1]; +char lzcnt64_1[__lzcnt64(1ULL << (BITSIZE(__int64) - 1)) == 0 ? 1 : -1]; +char lzcnt64_2[__lzcnt64(0ULL) == BITSIZE(__int64) ? 1 : -1]; +#undef BITSIZE + +#endif