Index: include/clang/Basic/BuiltinsARM.def =================================================================== --- include/clang/Basic/BuiltinsARM.def +++ include/clang/Basic/BuiltinsARM.def @@ -18,6 +18,10 @@ # define LANGBUILTIN(ID, TYPE, ATTRS, BUILTIN_LANG) BUILTIN(ID, TYPE, ATTRS) #endif +#if defined(BUILTIN) && !defined(TARGET_HEADER_BUILTIN) +# define TARGET_HEADER_BUILTIN(ID, TYPE, ATTRS, HEADER, LANG, FEATURE) BUILTIN(ID, TYPE, ATTRS) +#endif + // In libgcc BUILTIN(__clear_cache, "vv*v*", "i") @@ -129,5 +133,11 @@ LANGBUILTIN(_MoveToCoprocessor, "vUiIUiIUiIUiIUiIUi", "", ALL_MS_LANGUAGES) LANGBUILTIN(_MoveToCoprocessor2, "vUiIUiIUiIUiIUiIUi", "", ALL_MS_LANGUAGES) +TARGET_HEADER_BUILTIN(_BitScanForward, "UcULi*ULi", "n", "intrin.h", ALL_MS_LANGUAGES, "") +TARGET_HEADER_BUILTIN(_BitScanReverse, "UcULi*ULi", "n", "intrin.h", ALL_MS_LANGUAGES, "") +TARGET_HEADER_BUILTIN(_BitScanForward64, "UcULi*ULLi", "n", "intrin.h", ALL_MS_LANGUAGES, "") +TARGET_HEADER_BUILTIN(_BitScanReverse64, "UcULi*ULLi", "n", "intrin.h", ALL_MS_LANGUAGES, "") + #undef BUILTIN #undef LANGBUILTIN +#undef TARGET_HEADER_BUILTIN Index: include/clang/Basic/BuiltinsX86.def =================================================================== --- include/clang/Basic/BuiltinsX86.def +++ include/clang/Basic/BuiltinsX86.def @@ -2069,6 +2069,10 @@ TARGET_BUILTIN(__builtin_ia32_monitorx, "vv*UiUi", "", "mwaitx") TARGET_BUILTIN(__builtin_ia32_mwaitx, "vUiUiUi", "", "mwaitx") +// MSVC +TARGET_HEADER_BUILTIN(_BitScanForward, "UcULi*ULi", "n", "intrin.h", ALL_MS_LANGUAGES, "") +TARGET_HEADER_BUILTIN(_BitScanReverse, "UcULi*ULi", "n", "intrin.h", ALL_MS_LANGUAGES, "") + #undef BUILTIN #undef TARGET_BUILTIN #undef TARGET_HEADER_BUILTIN Index: include/clang/Basic/BuiltinsX86_64.def =================================================================== --- include/clang/Basic/BuiltinsX86_64.def +++ include/clang/Basic/BuiltinsX86_64.def @@ -21,5 +21,8 @@ TARGET_HEADER_BUILTIN(__mulh, "LLiLLiLLi", "nch", "intrin.h", ALL_MS_LANGUAGES, "") TARGET_HEADER_BUILTIN(__umulh, "ULLiULLiULLi", "nch", "intrin.h", ALL_MS_LANGUAGES, "") +TARGET_HEADER_BUILTIN(_BitScanForward64, "UcULi*ULLi", "n", "intrin.h", ALL_MS_LANGUAGES, "") +TARGET_HEADER_BUILTIN(_BitScanReverse64, "UcULi*ULLi", "n", "intrin.h", ALL_MS_LANGUAGES, "") + #undef BUILTIN #undef TARGET_HEADER_BUILTIN Index: lib/Basic/Targets.cpp =================================================================== --- lib/Basic/Targets.cpp +++ lib/Basic/Targets.cpp @@ -5561,6 +5561,8 @@ { #ID, TYPE, ATTRS, nullptr, LANG, nullptr }, #define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) \ { #ID, TYPE, ATTRS, HEADER, ALL_LANGUAGES, nullptr }, +#define TARGET_HEADER_BUILTIN(ID, TYPE, ATTRS, HEADER, LANGS, FEATURE) \ + { #ID, TYPE, ATTRS, HEADER, LANGS, FEATURE }, #include "clang/Basic/BuiltinsARM.def" }; Index: lib/CodeGen/CGBuiltin.cpp =================================================================== --- lib/CodeGen/CGBuiltin.cpp +++ lib/CodeGen/CGBuiltin.cpp @@ -2637,6 +2637,57 @@ } } +// Many of MSVC builtins are on both x64 and ARM; to avoid repeating code, we +// handle them here. +namespace MSVC { + enum { + _BitScanForward, + _BitScanReverse + }; +} + +Value *CodeGenFunction::EmitMSVCBuiltinExpr(unsigned BuiltinID, + const CallExpr *E) { + switch (BuiltinID) { + case MSVC::_BitScanForward: + case MSVC::_BitScanReverse: { + Value *ArgValue = EmitScalarExpr(E->getArg(1)); + + llvm::Type *ArgType = ArgValue->getType(); + llvm::Type *IndexType = + EmitScalarExpr(E->getArg(0))->getType()->getPointerElementType(); + llvm::Type *ResultType = ConvertType(E->getType()); + + Value *ArgZero = llvm::Constant::getNullValue(ArgType); + Value *ResZero = llvm::Constant::getNullValue(ResultType); + Value *ResOne = llvm::ConstantInt::get(ResultType, 1); + + Value *IsZero = Builder.CreateICmpEQ(ArgValue, ArgZero); + Value *Result = Builder.CreateSelect(IsZero, ResZero, ResOne); + + Address IndexAddress = EmitPointerWithAlignment(E->getArg(0)); + + if (BuiltinID == MSVC::_BitScanForward) { + Value *F = CGM.getIntrinsic(Intrinsic::cttz, ArgType); + Value *ZeroCount = Builder.CreateCall(F, {ArgValue, Builder.getTrue()}); + ZeroCount = Builder.CreateIntCast(ZeroCount, IndexType, false); + Builder.CreateStore(ZeroCount, IndexAddress, false); + } else { + unsigned ArgWidth = cast(ArgType)->getBitWidth(); + Value *ArgTypeLastIndex = llvm::ConstantInt::get(IndexType, ArgWidth - 1); + + Value *F = CGM.getIntrinsic(Intrinsic::ctlz, ArgType); + Value *ZeroCount = Builder.CreateCall(F, {ArgValue, Builder.getTrue()}); + ZeroCount = Builder.CreateIntCast(ZeroCount, IndexType, false); + Value *Index = Builder.CreateNSWSub(ArgTypeLastIndex, ZeroCount); + Builder.CreateStore(Index, IndexAddress, false); + } + + return Result; + } + } +} + Value *CodeGenFunction::EmitTargetBuiltinExpr(unsigned BuiltinID, const CallExpr *E) { if (getContext().BuiltinInfo.isAuxBuiltinID(BuiltinID)) { @@ -4561,6 +4612,12 @@ return Builder.CreateCall(F, {Ops[1], Ops[2], Ops[0], Ops[3], Ops[4], Ops[5]}); } + case ARM::BI_BitScanForward: + case ARM::BI_BitScanForward64: + return EmitMSVCBuiltinExpr(MSVC::_BitScanForward, E); + case ARM::BI_BitScanReverse: + case ARM::BI_BitScanReverse64: + return EmitMSVCBuiltinExpr(MSVC::_BitScanReverse, E); } // Get the last argument, which specifies the vector type. @@ -7599,6 +7656,13 @@ HigherBits = Builder.CreateIntCast(HigherBits, ResType, IsSigned); return HigherBits; } + + case X86::BI_BitScanForward: + case X86::BI_BitScanForward64: + return EmitMSVCBuiltinExpr(MSVC::_BitScanForward, E); + case X86::BI_BitScanReverse: + case X86::BI_BitScanReverse64: + return EmitMSVCBuiltinExpr(MSVC::_BitScanReverse, E); } } Index: lib/CodeGen/CodeGenFunction.h =================================================================== --- lib/CodeGen/CodeGenFunction.h +++ lib/CodeGen/CodeGenFunction.h @@ -2959,6 +2959,7 @@ llvm::Value *EmitNVPTXBuiltinExpr(unsigned BuiltinID, const CallExpr *E); llvm::Value *EmitWebAssemblyBuiltinExpr(unsigned BuiltinID, const CallExpr *E); + llvm::Value *EmitMSVCBuiltinExpr(unsigned BuiltinID, const CallExpr *E); llvm::Value *EmitObjCProtocolExpr(const ObjCProtocolExpr *E); llvm::Value *EmitObjCStringLiteral(const ObjCStringLiteral *E); Index: lib/Headers/intrin.h =================================================================== --- lib/Headers/intrin.h +++ lib/Headers/intrin.h @@ -447,20 +447,6 @@ |* Bit Counting and Testing \*----------------------------------------------------------------------------*/ static __inline__ unsigned char __DEFAULT_FN_ATTRS -_BitScanForward(unsigned long *_Index, unsigned long _Mask) { - if (!_Mask) - return 0; - *_Index = __builtin_ctzl(_Mask); - return 1; -} -static __inline__ unsigned char __DEFAULT_FN_ATTRS -_BitScanReverse(unsigned long *_Index, unsigned long _Mask) { - if (!_Mask) - return 0; - *_Index = 31 - __builtin_clzl(_Mask); - return 1; -} -static __inline__ unsigned char __DEFAULT_FN_ATTRS _bittest(long const *_BitBase, long _BitPos) { return (*_BitBase >> _BitPos) & 1; } @@ -506,20 +492,6 @@ #endif #ifdef __x86_64__ static __inline__ unsigned char __DEFAULT_FN_ATTRS -_BitScanForward64(unsigned long *_Index, unsigned __int64 _Mask) { - if (!_Mask) - return 0; - *_Index = __builtin_ctzll(_Mask); - return 1; -} -static __inline__ unsigned char __DEFAULT_FN_ATTRS -_BitScanReverse64(unsigned long *_Index, unsigned __int64 _Mask) { - if (!_Mask) - return 0; - *_Index = 63 - __builtin_clzll(_Mask); - return 1; -} -static __inline__ unsigned char __DEFAULT_FN_ATTRS _bittest64(__int64 const *_BitBase, __int64 _BitPos) { return (*_BitBase >> _BitPos) & 1; } Index: test/CodeGen/ms-intrinsics.c =================================================================== --- test/CodeGen/ms-intrinsics.c +++ test/CodeGen/ms-intrinsics.c @@ -1,12 +1,12 @@ // RUN: %clang_cc1 -ffreestanding -fms-extensions -fms-compatibility -fms-compatibility-version=17.00 \ // RUN: -triple i686--windows -Oz -emit-llvm %s -o - \ -// RUN: | FileCheck %s -check-prefix CHECK -check-prefix CHECK-I386 +// RUN: | FileCheck %s -check-prefix=CHECK -check-prefix=CHECK-I386 // RUN: %clang_cc1 -ffreestanding -fms-extensions -fms-compatibility -fms-compatibility-version=17.00 \ // RUN: -triple thumbv7--windows -Oz -emit-llvm %s -o - \ -// RUN: | FileCheck %s +// RUN: | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-ARM-X64 // RUN: %clang_cc1 -ffreestanding -fms-extensions -fms-compatibility -fms-compatibility-version=17.00 \ // RUN: -triple x86_64--windows -Oz -emit-llvm %s -o - \ -// RUN: | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-X64 +// RUN: | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-X64 --check-prefix=CHECK-ARM-X64 // intrin.h needs size_t, but -ffreestanding prevents us from getting it from // stddef.h. Work around it with this typedef. @@ -14,6 +14,56 @@ #include +unsigned char test_BitScanForward(unsigned long *Index, unsigned long Mask) { + return _BitScanForward(Index, Mask); +} +// CHECK: define{{.*}}i8 @test_BitScanForward(i32* {{[a-z_ ]*}}%Index, i32 {{[a-z_ ]*}}%Mask){{.*}}{ +// CHECK: [[ISNOTZERO:%[a-z0-9.]+]] = icmp ne i32 %Mask, 0 +// CHECK: [[RESULT:%[0-9]+]] = zext i1 [[ISNOTZERO]] to i8 +// CHECK: [[INDEX:%[0-9]+]] = tail call i32 @llvm.cttz.i32(i32 %Mask, i1 true) +// CHECK: store i32 [[INDEX]], i32* %Index, align 4 +// CHECK: ret i8 [[RESULT]] +// CHECK: } + +unsigned char test_BitScanReverse(unsigned long *Index, unsigned long Mask) { + return _BitScanReverse(Index, Mask); +} +// CHECK: define{{.*}}i8 @test_BitScanReverse(i32* {{[a-z_ ]*}}%Index, i32 {{[a-z_ ]*}}%Mask){{.*}}{ +// CHECK: [[ISNOTZERO:%[a-z0-9.]+]] = icmp ne i32 %Mask, 0 +// CHECK: [[RESULT:%[0-9]+]] = zext i1 [[ISNOTZERO]] to i8 +// CHECK: [[REVINDEX:%[0-9]+]] = tail call i32 @llvm.ctlz.i32(i32 %Mask, i1 true) +// CHECK: [[INDEX:%[0-9]+]] = xor i32 [[REVINDEX]], 31 +// CHECK: store i32 [[INDEX]], i32* %Index, align 4 +// CHECK: ret i8 [[RESULT]] +// CHECK: } + +#if defined(__x86_64__) || defined(__arm__) +unsigned char test_BitScanForward64(unsigned long *Index, unsigned __int64 Mask) { + return _BitScanForward64(Index, Mask); +} +// CHECK-ARM-X64: define{{.*}}i8 @test_BitScanForward64(i32* {{[a-z_ ]*}}%Index, i64 {{[a-z_ ]*}}%Mask){{.*}}{ +// CHECK-ARM-X64: [[ISNOTZERO:%[a-z0-9.]+]] = icmp ne i64 %Mask, 0 +// CHECK-ARM-X64: [[RESULT:%[0-9]+]] = zext i1 [[ISNOTZERO]] to i8 +// CHECK-ARM-X64: [[INDEX:%[0-9]+]] = tail call i64 @llvm.cttz.i64(i64 %Mask, i1 true) +// CHECK-ARM-X64: [[ALIGNED_INDEX:%[0-9]+]] = trunc i64 [[INDEX]] to i32 +// CHECK-ARM-X64: store i32 [[ALIGNED_INDEX]], i32* %Index, align 4 +// CHECK-ARM-X64: ret i8 [[RESULT]] +// CHECK-ARM-X64: } + +unsigned char test_BitScanReverse64(unsigned long *Index, unsigned __int64 Mask) { + return _BitScanReverse64(Index, Mask); +} +// CHECK-ARM-X64: define{{.*}}i8 @test_BitScanReverse64(i32* {{[a-z_ ]*}}%Index, i64 {{[a-z_ ]*}}%Mask){{.*}}{ +// CHECK-ARM-X64: [[ISNOTZERO:%[a-z0-9.]+]] = icmp ne i64 %Mask, 0 +// CHECK-ARM-X64: [[RESULT:%[0-9]+]] = zext i1 [[ISNOTZERO]] to i8 +// CHECK-ARM-X64: [[REVINDEX:%[0-9]+]] = tail call i64 @llvm.ctlz.i64(i64 %Mask, i1 true) +// CHECK-ARM-X64: [[ALIGNED_REVINDEX:%[0-9]+]] = trunc i64 [[REVINDEX]] to i32 +// CHECK-ARM-X64: [[INDEX:%[0-9]+]] = xor i32 [[ALIGNED_REVINDEX]], 63 +// CHECK-ARM-X64: store i32 [[INDEX]], i32* %Index, align 4 +// CHECK-ARM-X64: ret i8 [[RESULT]] +// CHECK-ARM-X64: } +#endif + void *test_InterlockedExchangePointer(void * volatile *Target, void *Value) { return _InterlockedExchangePointer(Target, Value); }