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 @@ -1016,12 +1016,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 @@ -12123,11 +12123,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); @@ -12266,7 +12276,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