summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCraig Topper <craig.topper@intel.com>2019-03-24 00:56:52 +0000
committerCraig Topper <craig.topper@intel.com>2019-03-24 00:56:52 +0000
commit8a55120a7d72bed6c93749e0a6dbd0a2fcd873dd (patch)
treead93f7270a7441416dce8a450e53217e39331220
parentb4bcb2930e135762b2820fe85ba4a8cb65e431be (diff)
[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 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@356848 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--lib/Headers/ia32intrin.h108
-rw-r--r--lib/Headers/immintrin.h12
-rw-r--r--test/CodeGen/bitscan-builtins.c33
-rw-r--r--test/CodeGen/x86-bswap.c29
4 files changed, 167 insertions, 15 deletions
diff --git a/lib/Headers/ia32intrin.h b/lib/Headers/ia32intrin.h
index 837ea369cd..6bd57ec2f0 100644
--- a/lib/Headers/ia32intrin.h
+++ b/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 <x86intrin.h>
+ *
+ * This intrinsic corresponds to the <c> BSF </c> instruction or the
+ * <c> TZCNT </c> 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 <x86intrin.h>
+ *
+ * This intrinsic corresponds to the <c> BSR </c> instruction or the
+ * <c> LZCNT </c> instruction and an <c> XOR </c>.
+ *
+ * \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 <x86intrin.h>
+ *
+ * This intrinsic corresponds to the <c> BSWAP </c> 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 <x86intrin.h>
+ *
+ * This intrinsic corresponds to the <c> BSF </c> instruction or the
+ * <c> TZCNT </c> 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 <x86intrin.h>
+ *
+ * This intrinsic corresponds to the <c> BSR </c> instruction or the
+ * <c> LZCNT </c> instruction and an <c> XOR </c>.
+ *
+ * \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 <x86intrin.h>
+ *
+ * This intrinsic corresponds to the <c> BSWAP </c> 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 <x86intrin.h>
diff --git a/lib/Headers/immintrin.h b/lib/Headers/immintrin.h
index 19edd4ac4a..634db600b0 100644
--- a/lib/Headers/immintrin.h
+++ b/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/test/CodeGen/bitscan-builtins.c b/test/CodeGen/bitscan-builtins.c
index 25dfa40462..176d829127 100644
--- a/test/CodeGen/bitscan-builtins.c
+++ b/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 <immintrin.h>
+#include <x86intrin.h>
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/test/CodeGen/x86-bswap.c b/test/CodeGen/x86-bswap.c
new file mode 100644
index 0000000000..adf8b7846a
--- /dev/null
+++ b/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 <x86intrin.h>
+
+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);
+}
+
+