From: Craig Topper Date: Sun, 24 Mar 2019 00:56:52 +0000 (+0000) Subject: [X86] Add BSR/BSF/BSWAP intrinsics to ia32intrin.h to match gcc. X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=88f4054f48c56b816a555569ccd6e94c7072ab26;p=platform%2Fupstream%2Fllvm.git [X86] Add BSR/BSF/BSWAP intrinsics to ia32intrin.h to match gcc. Summary: These are all implemented by icc as well. I made bit_scan_forward/reverse forward to the __bsfd/__bsrq since we also have __bsfq/__bsrq. Note, when lzcnt is enabled the bsr intrinsics generates lzcnt+xor instead of bsr. Reviewers: RKSimon, spatel Subscribers: cfe-commits, llvm-commits Tags: #clang Differential Revision: https://reviews.llvm.org/D59682 llvm-svn: 356848 --- diff --git a/clang/lib/Headers/ia32intrin.h b/clang/lib/Headers/ia32intrin.h index 837ea36..6bd57ec 100644 --- a/clang/lib/Headers/ia32intrin.h +++ b/clang/lib/Headers/ia32intrin.h @@ -28,6 +28,114 @@ #ifndef __IA32INTRIN_H #define __IA32INTRIN_H +/** Find the first set bit starting from the lsb. Result is undefined if + * input is 0. + * + * \headerfile + * + * This intrinsic corresponds to the BSF instruction or the + * TZCNT instruction. + * + * \param __A + * A 32-bit integer operand. + * \returns A 32-bit integer containing the bit number. + */ +static __inline__ int __attribute__((__always_inline__, __nodebug__)) +__bsfd(int __A) { + return __builtin_ctz(__A); +} + +/** Find the first set bit starting from the msb. Result is undefined if + * input is 0. + * + * \headerfile + * + * This intrinsic corresponds to the BSR instruction or the + * LZCNT instruction and an XOR . + * + * \param __A + * A 32-bit integer operand. + * \returns A 32-bit integer containing the bit number. + */ +static __inline__ int __attribute__((__always_inline__, __nodebug__)) +__bsrd(int __A) { + return 31 - __builtin_clz(__A); +} + +/** Swaps the bytes in the input. Converting little endian to big endian or + * vice versa. + * + * \headerfile + * + * This intrinsic corresponds to the BSWAP instruction. + * + * \param __A + * A 32-bit integer operand. + * \returns A 32-bit integer containing the swapped bytes. + */ +static __inline__ int __attribute__((__always_inline__, __nodebug__)) +__bswapd(int __A) { + return __builtin_bswap32(__A); +} + +#define _bswap(A) __bswapd((A)) +#define _bit_scan_forward(A) __bsfd((A)) +#define _bit_scan_reverse(A) __bsrd((A)) + +#ifdef __x86_64__ +/** Find the first set bit starting from the lsb. Result is undefined if + * input is 0. + * + * \headerfile + * + * This intrinsic corresponds to the BSF instruction or the + * TZCNT instruction. + * + * \param __A + * A 64-bit integer operand. + * \returns A 32-bit integer containing the bit number. + */ +static __inline__ int __attribute__((__always_inline__, __nodebug__)) +__bsfq(long long __A) { + return __builtin_ctzll(__A); +} + +/** Find the first set bit starting from the msb. Result is undefined if + * input is 0. + * + * \headerfile + * + * This intrinsic corresponds to the BSR instruction or the + * LZCNT instruction and an XOR . + * + * \param __A + * A 64-bit integer operand. + * \returns A 32-bit integer containing the bit number. + */ +static __inline__ int __attribute__((__always_inline__, __nodebug__)) +__bsrq(long long __A) { + return 63 - __builtin_clzll(__A); +} + +/** Swaps the bytes in the input. Converting little endian to big endian or + * vice versa. + * + * \headerfile + * + * This intrinsic corresponds to the BSWAP instruction. + * + * \param __A + * A 64-bit integer operand. + * \returns A 64-bit integer containing the swapped bytes. + */ +static __inline__ long long __attribute__((__always_inline__, __nodebug__)) +__bswapq(long long __A) { + return __builtin_bswap64(__A); +} + +#define _bswap64(A) __bswapq((A)) +#endif + /** Counts the number of bits in the source operand having a value of 1. * * \headerfile diff --git a/clang/lib/Headers/immintrin.h b/clang/lib/Headers/immintrin.h index 19edd4a..634db60 100644 --- a/clang/lib/Headers/immintrin.h +++ b/clang/lib/Headers/immintrin.h @@ -241,18 +241,6 @@ _rdrand64_step(unsigned long long *__p) #endif #endif /* __RDRND__ */ -/* __bit_scan_forward */ -static __inline__ int __attribute__((__always_inline__, __nodebug__)) -_bit_scan_forward(int __A) { - return __builtin_ctz(__A); -} - -/* __bit_scan_reverse */ -static __inline__ int __attribute__((__always_inline__, __nodebug__)) -_bit_scan_reverse(int __A) { - return 31 - __builtin_clz(__A); -} - #if !defined(_MSC_VER) || __has_feature(modules) || defined(__FSGSBASE__) #ifdef __x86_64__ static __inline__ unsigned int __attribute__((__always_inline__, __nodebug__, __target__("fsgsbase"))) diff --git a/clang/test/CodeGen/bitscan-builtins.c b/clang/test/CodeGen/bitscan-builtins.c index 25dfa40..176d829 100644 --- a/clang/test/CodeGen/bitscan-builtins.c +++ b/clang/test/CodeGen/bitscan-builtins.c @@ -3,18 +3,45 @@ // PR33722 // RUN: %clang_cc1 -ffreestanding -triple x86_64-unknown-unknown -fms-extensions -fms-compatibility-version=19.00 -emit-llvm -o - %s | FileCheck %s -#include +#include int test_bit_scan_forward(int a) { return _bit_scan_forward(a); // CHECK: @test_bit_scan_forward -// CHECK: %[[call:.*]] = call i32 @llvm.cttz.i32( +// CHECK: %[[call:.*]] = call i32 @llvm.cttz.i32(i32 %{{.*}}, i1 true) // CHECK: ret i32 %[[call]] } int test_bit_scan_reverse(int a) { return _bit_scan_reverse(a); -// CHECK: %[[call:.*]] = call i32 @llvm.ctlz.i32( +// CHECK: %[[call:.*]] = call i32 @llvm.ctlz.i32(i32 %{{.*}}, i1 true) // CHECK: %[[sub:.*]] = sub nsw i32 31, %[[call]] // CHECK: ret i32 %[[sub]] } + +int test__bsfd(int X) { +// CHECK: @test__bsfd +// CHECK: %[[call:.*]] = call i32 @llvm.cttz.i32(i32 %{{.*}}, i1 true) + return __bsfd(X); +} + +int test__bsfq(long long X) { +// CHECK: @test__bsfq +// CHECK: %[[call:.*]] = call i64 @llvm.cttz.i64(i64 %{{.*}}, i1 true) + return __bsfq(X); +} + +int test__bsrd(int X) { +// CHECK: @test__bsrd +// CHECK: %[[call:.*]] = call i32 @llvm.ctlz.i32(i32 %{{.*}}, i1 true) +// CHECK: %[[sub:.*]] = sub nsw i32 31, %[[call]] + return __bsrd(X); +} + +int test__bsrq(long long X) { +// CHECK: @test__bsrq +// CHECK: %[[call:.*]] = call i64 @llvm.ctlz.i64(i64 %{{.*}}, i1 true) +// CHECK: %[[cast:.*]] = trunc i64 %[[call]] to i32 +// CHECK: %[[sub:.*]] = sub nsw i32 63, %[[cast]] + return __bsrq(X); +} diff --git a/clang/test/CodeGen/x86-bswap.c b/clang/test/CodeGen/x86-bswap.c new file mode 100644 index 0000000..adf8b78 --- /dev/null +++ b/clang/test/CodeGen/x86-bswap.c @@ -0,0 +1,29 @@ +// RUN: %clang_cc1 -ffreestanding %s -triple=x86_64-apple-darwin -emit-llvm -o - | FileCheck %s + +#include + +int test__bswapd(int X) { +// CHECK-LABEL: @test__bswapd +// CHECK: call i32 @llvm.bswap.i32 + return __bswapd(X); +} + +int test_bswap(int X) { +// CHECK-LABEL: @test_bswap +// CHECK: call i32 @llvm.bswap.i32 + return _bswap(X); +} + +long test__bswapq(long long X) { +// CHECK-LABEL: @test__bswapq +// CHECK: call i64 @llvm.bswap.i64 + return __bswapq(X); +} + +long test_bswap64(long long X) { +// CHECK-LABEL: @test_bswap64 +// CHECK: call i64 @llvm.bswap.i64 + return _bswap64(X); +} + +