Implement MS _BitScan intrinsics
Summary: _BitScan intrinsics (and some others, for example _Interlocked and _bittest) are supposed to work on both ARM and x86. This is an attempt to isolate them, avoiding repeating their code or writing separate function for each builtin. Reviewers: hans, thakis, rnk, majnemer Subscribers: RKSimon, cfe-commits, aemerson Differential Revision: https://reviews.llvm.org/D25264 llvm-svn: 284060
This commit is contained in:
parent
a8c44c3d0c
commit
2a0621e58a
|
@ -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(_MoveFromCoprocessor2, "UiIUiIUiIUiIUiIUi", "", ALL_MS_LANGUAGES)
|
|||
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
|
||||
|
|
|
@ -2028,6 +2028,10 @@ TARGET_BUILTIN(__builtin_ia32_selectpd_512, "V8dUcV8dV8d", "", "")
|
|||
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, "")
|
||||
|
|
|
@ -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, "")
|
||||
|
|
|
@ -5588,6 +5588,8 @@ const Builtin::Info ARMTargetInfo::BuiltinInfo[] = {
|
|||
{ #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"
|
||||
};
|
||||
|
||||
|
|
|
@ -2637,6 +2637,68 @@ static Value *EmitTargetArchBuiltinExpr(CodeGenFunction *CGF,
|
|||
}
|
||||
}
|
||||
|
||||
// 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<llvm::IntegerType>(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 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
|
|||
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 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
|
|||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2961,6 +2961,12 @@ public:
|
|||
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);
|
||||
|
|
|
@ -432,20 +432,6 @@ unsigned __int64 _umul128(unsigned __int64,
|
|||
|* 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 @@ _interlockedbittestandset_rel(long volatile *_BitBase, long _BitPos) {
|
|||
#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;
|
||||
}
|
||||
|
|
|
@ -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 @@ typedef __SIZE_TYPE__ size_t;
|
|||
|
||||
#include <intrin.h>
|
||||
|
||||
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: ; <label>:[[END_LABEL]]:
|
||||
// CHECK: [[RESULT:%[a-z0-9._]+]] = phi i8 [ 0, %[[ISZERO_LABEL:[0-9]+]] ], [ 1, %[[ISNOTZERO_LABEL]] ]
|
||||
// CHECK: ret i8 [[RESULT]]
|
||||
// CHECK: ; <label>:[[ISNOTZERO_LABEL]]:
|
||||
// CHECK: [[INDEX:%[0-9]+]] = tail call i32 @llvm.cttz.i32(i32 %Mask, i1 true)
|
||||
// CHECK: store i32 [[INDEX]], i32* %Index, align 4
|
||||
// CHECK: br label %[[END_LABEL]]
|
||||
|
||||
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:%[0-9]+]] = icmp eq i32 %Mask, 0
|
||||
// CHECK: br i1 [[ISNOTZERO]], label %[[END_LABEL:[a-z0-9.]+]], label %[[ISNOTZERO_LABEL:[0-9]+]]
|
||||
// CHECK: ; <label>:[[END_LABEL]]:
|
||||
// CHECK: [[RESULT:%[a-z0-9._]+]] = phi i8 [ 0, %[[ISZERO_LABEL:[0-9]+]] ], [ 1, %[[ISNOTZERO_LABEL]] ]
|
||||
// CHECK: ret i8 [[RESULT]]
|
||||
// CHECK: ; <label>:[[ISNOTZERO_LABEL]]:
|
||||
// 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: br label %[[END_LABEL]]
|
||||
|
||||
#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 eq i64 %Mask, 0
|
||||
// CHECK-ARM-X64: br i1 [[ISNOTZERO]], label %[[END_LABEL:[a-z0-9.]+]], label %[[ISNOTZERO_LABEL:[0-9]+]]
|
||||
// CHECK-ARM-X64: ; <label>:[[END_LABEL]]:
|
||||
// CHECK-ARM-X64: [[RESULT:%[a-z0-9._]+]] = phi i8 [ 0, %[[ISZERO_LABEL:[0-9]+]] ], [ 1, %[[ISNOTZERO_LABEL]] ]
|
||||
// CHECK-ARM-X64: ret i8 [[RESULT]]
|
||||
// CHECK-ARM-X64: ; <label>:[[ISNOTZERO_LABEL]]:
|
||||
// CHECK-ARM-X64: [[INDEX:%[0-9]+]] = tail call i64 @llvm.cttz.i64(i64 %Mask, i1 true)
|
||||
// CHECK-ARM-X64: [[TRUNC_INDEX:%[0-9]+]] = trunc i64 [[INDEX]] to i32
|
||||
// CHECK-ARM-X64: store i32 [[TRUNC_INDEX]], i32* %Index, align 4
|
||||
// CHECK-ARM-X64: br label %[[END_LABEL]]
|
||||
|
||||
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:%[0-9]+]] = icmp eq i64 %Mask, 0
|
||||
// CHECK-ARM-X64: br i1 [[ISNOTZERO]], label %[[END_LABEL:[a-z0-9.]+]], label %[[ISNOTZERO_LABEL:[0-9]+]]
|
||||
// CHECK-ARM-X64: ; <label>:[[END_LABEL]]:
|
||||
// CHECK-ARM-X64: [[RESULT:%[a-z0-9._]+]] = phi i8 [ 0, %[[ISZERO_LABEL:[0-9]+]] ], [ 1, %[[ISNOTZERO_LABEL]] ]
|
||||
// CHECK-ARM-X64: ret i8 [[RESULT]]
|
||||
// CHECK-ARM-X64: ; <label>:[[ISNOTZERO_LABEL]]:
|
||||
// CHECK-ARM-X64: [[REVINDEX:%[0-9]+]] = tail call i64 @llvm.ctlz.i64(i64 %Mask, i1 true)
|
||||
// CHECK-ARM-X64: [[TRUNC_REVINDEX:%[0-9]+]] = trunc i64 [[REVINDEX]] to i32
|
||||
// CHECK-ARM-X64: [[INDEX:%[0-9]+]] = xor i32 [[TRUNC_REVINDEX]], 63
|
||||
// CHECK-ARM-X64: store i32 [[INDEX]], i32* %Index, align 4
|
||||
// CHECK-ARM-X64: br label %[[END_LABEL]]
|
||||
#endif
|
||||
|
||||
void *test_InterlockedExchangePointer(void * volatile *Target, void *Value) {
|
||||
return _InterlockedExchangePointer(Target, Value);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue