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 @@ -2028,6 +2028,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, "") + TARGET_HEADER_BUILTIN(_ReadWriteBarrier, "v", "nh", "intrin.h", ALL_MS_LANGUAGES, "") TARGET_HEADER_BUILTIN(_ReadBarrier, "v", "nh", "intrin.h", ALL_MS_LANGUAGES, "") TARGET_HEADER_BUILTIN(_WriteBarrier, "v", "nh", "intrin.h", ALL_MS_LANGUAGES, "") Index: include/clang/Basic/BuiltinsX86_64.def =================================================================== --- include/clang/Basic/BuiltinsX86_64.def +++ include/clang/Basic/BuiltinsX86_64.def @@ -22,6 +22,9 @@ # define TARGET_HEADER_BUILTIN(ID, TYPE, ATTRS, HEADER, LANG, FEATURE) BUILTIN(ID, TYPE, ATTRS) #endif +TARGET_HEADER_BUILTIN(_BitScanForward64, "UcULi*ULLi", "n", "intrin.h", ALL_MS_LANGUAGES, "") +TARGET_HEADER_BUILTIN(_BitScanReverse64, "UcULi*ULLi", "n", "intrin.h", ALL_MS_LANGUAGES, "") + 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(_mul128, "LLiLLiLLiLLi*", "nh", "intrin.h", ALL_MS_LANGUAGES, "") Index: lib/Basic/Targets.cpp =================================================================== --- lib/Basic/Targets.cpp +++ lib/Basic/Targets.cpp @@ -5588,6 +5588,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,68 @@ } } +// Many of MSVC builtins are on both x64 and ARM; to avoid repeating code, we +// handle them here. +enum class CodeGenFunction::MSVCIntrin { + _BitScanForward, + _BitScanReverse +}; + +Value *CodeGenFunction::EmitMSVCBuiltinExpr(MSVCIntrin BuiltinID, + const CallExpr *E) { + switch (BuiltinID) { + case MSVCIntrin::_BitScanForward: + case MSVCIntrin::_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); + + BasicBlock *Begin = Builder.GetInsertBlock(); + BasicBlock *End = createBasicBlock("bitscan_end", this->CurFn); + Builder.SetInsertPoint(End); + PHINode *Result = Builder.CreatePHI(ResultType, 2, "bitscan_result"); + + Builder.SetInsertPoint(Begin); + Value *IsZero = Builder.CreateICmpEQ(ArgValue, ArgZero); + BasicBlock *NotZero = createBasicBlock("bitscan_not_zero", this->CurFn); + Builder.CreateCondBr(IsZero, End, NotZero); + Result->addIncoming(ResZero, Begin); + + Builder.SetInsertPoint(NotZero); + Address IndexAddress = EmitPointerWithAlignment(E->getArg(0)); + + if (BuiltinID == MSVCIntrin::_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); + } + Builder.CreateBr(End); + Result->addIncoming(ResOne, NotZero); + + Builder.SetInsertPoint(End); + return Result; + } + } + llvm_unreachable("Incorrect MSVC intrinsic!"); +} + Value *CodeGenFunction::EmitTargetBuiltinExpr(unsigned BuiltinID, const CallExpr *E) { if (getContext().BuiltinInfo.isAuxBuiltinID(BuiltinID)) { @@ -4561,6 +4623,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(MSVCIntrin::_BitScanForward, E); + case ARM::BI_BitScanReverse: + case ARM::BI_BitScanReverse64: + return EmitMSVCBuiltinExpr(MSVCIntrin::_BitScanReverse, E); } // Get the last argument, which specifies the vector type. @@ -7623,6 +7691,12 @@ return Builder.CreateFence(llvm::AtomicOrdering::SequentiallyConsistent, llvm::SingleThread); } + case X86::BI_BitScanForward: + case X86::BI_BitScanForward64: + return EmitMSVCBuiltinExpr(MSVCIntrin::_BitScanForward, E); + case X86::BI_BitScanReverse: + case X86::BI_BitScanReverse64: + return EmitMSVCBuiltinExpr(MSVCIntrin::_BitScanReverse, E); } } Index: lib/CodeGen/CodeGenFunction.h =================================================================== --- lib/CodeGen/CodeGenFunction.h +++ lib/CodeGen/CodeGenFunction.h @@ -2961,6 +2961,12 @@ llvm::Value *EmitWebAssemblyBuiltinExpr(unsigned BuiltinID, const CallExpr *E); +private: + enum class MSVCIntrin; + +public: + llvm::Value *EmitMSVCBuiltinExpr(MSVCIntrin BuiltinID, const CallExpr *E); + llvm::Value *EmitObjCProtocolExpr(const ObjCProtocolExpr *E); llvm::Value *EmitObjCStringLiteral(const ObjCStringLiteral *E); llvm::Value *EmitObjCBoxedExpr(const ObjCBoxedExpr *E); Index: lib/Headers/intrin.h =================================================================== --- lib/Headers/intrin.h +++ lib/Headers/intrin.h @@ -432,20 +432,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; } @@ -491,20 +477,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,68 @@ #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 eq i32 %Mask, 0 +// CHECK: br i1 [[ISNOTZERO]], label %[[END_LABEL:[a-z0-9.]+]], label %[[ISNOTZERO_LABEL:[0-9]+]] +// CHECK: ;