]> granicus.if.org Git - clang/commitdiff
[Builltins][X86] Provide implementations of __lzcnt16, __lzcnt, __lzcnt64 for MS...
authorCraig Topper <craig.topper@intel.com>
Fri, 14 Dec 2018 00:21:02 +0000 (00:21 +0000)
committerCraig Topper <craig.topper@intel.com>
Fri, 14 Dec 2018 00:21:02 +0000 (00:21 +0000)
intrin.h had forward declarations for these and lzcntintrin.h had implementations that were only available with -mlzcnt or a -march that supported the lzcnt feature.

For MS compatibility we should always have these builtins available regardless of X86 being the target or the CPU support the lzcnt instruction. The backends should be able to gracefully fallback to something support even if its just shifts and bit ops.

Unfortunately, gcc also implements 2 of the 3 function names here on X86 when lzcnt feature is enabled.

This patch adds builtins for these for MSVC compatibility and drops the forward declarations from intrin.h. To keep the gcc compatibility the two intrinsics that collided have been turned into macros that use the X86 specific builtins with the lzcnt feature check. These macros are only defined when _MSC_VER is not defined. Without them being macros we can get a redefinition error because -ms-extensions doesn't seem to set _MSC_VER but does make the MS builtins available.

Should fix PR40014

Differential Revision: https://reviews.llvm.org/D55677

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@349098 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Basic/Builtins.def
lib/CodeGen/CGBuiltin.cpp
lib/Headers/intrin.h
lib/Headers/lzcntintrin.h
test/CodeGen/ms-intrinsics-other.c

index 7d8226def3176cb1a16a51a9ccd47398c2653267..924af436700a1e4b0cad109a89a3fcd62f12bdd6 100644 (file)
@@ -818,20 +818,23 @@ LANGBUILTIN(_interlockedbittestandset_acq,   "UcNiD*Ni", "n", ALL_MS_LANGUAGES)
 LANGBUILTIN(_interlockedbittestandset_nf,    "UcNiD*Ni", "n", ALL_MS_LANGUAGES)
 LANGBUILTIN(_interlockedbittestandset_rel,   "UcNiD*Ni", "n", ALL_MS_LANGUAGES)
 LANGBUILTIN(__noop,           "i.",  "n", ALL_MS_LANGUAGES)
-LANGBUILTIN(__popcnt16, "UsUs",     "nc", ALL_MS_LANGUAGES)
-LANGBUILTIN(__popcnt,   "UiUi",     "nc", ALL_MS_LANGUAGES)
-LANGBUILTIN(__popcnt64, "ULLiULLi", "nc", ALL_MS_LANGUAGES)
+LANGBUILTIN(__lzcnt16, "UsUs",    "nc", ALL_MS_LANGUAGES)
+LANGBUILTIN(__lzcnt,   "UiUi",    "nc", ALL_MS_LANGUAGES)
+LANGBUILTIN(__lzcnt64, "UWiUWi",  "nc", ALL_MS_LANGUAGES)
+LANGBUILTIN(__popcnt16, "UsUs",   "nc", ALL_MS_LANGUAGES)
+LANGBUILTIN(__popcnt,   "UiUi",   "nc", ALL_MS_LANGUAGES)
+LANGBUILTIN(__popcnt64, "UWiUWi", "nc", ALL_MS_LANGUAGES)
 LANGBUILTIN(_ReturnAddress, "v*", "n", ALL_MS_LANGUAGES)
 LANGBUILTIN(_rotl8,  "UcUcUc",    "n", ALL_MS_LANGUAGES)
 LANGBUILTIN(_rotl16, "UsUsUc",    "n", ALL_MS_LANGUAGES)
 LANGBUILTIN(_rotl,   "UiUii",     "n", ALL_MS_LANGUAGES)
 LANGBUILTIN(_lrotl,  "UNiUNii",   "n", ALL_MS_LANGUAGES)
-LANGBUILTIN(_rotl64, "ULLiULLii", "n", ALL_MS_LANGUAGES)
+LANGBUILTIN(_rotl64, "UWiUWii",   "n", ALL_MS_LANGUAGES)
 LANGBUILTIN(_rotr8,  "UcUcUc",    "n", ALL_MS_LANGUAGES)
 LANGBUILTIN(_rotr16, "UsUsUc",    "n", ALL_MS_LANGUAGES)
 LANGBUILTIN(_rotr,   "UiUii",     "n", ALL_MS_LANGUAGES)
 LANGBUILTIN(_lrotr,  "UNiUNii",   "n", ALL_MS_LANGUAGES)
-LANGBUILTIN(_rotr64, "ULLiULLii", "n", ALL_MS_LANGUAGES)
+LANGBUILTIN(_rotr64, "UWiUWii",   "n", ALL_MS_LANGUAGES)
 LANGBUILTIN(__va_start,       "vc**.", "nt", ALL_MS_LANGUAGES)
 LANGBUILTIN(__fastfail, "vUi",    "nr", ALL_MS_LANGUAGES)
 
index e587d04d834304495dead0131917bae5022170f8..f1df98309f574e8641b6b957f50b275c62909632 100644 (file)
@@ -1802,6 +1802,21 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
                                      "cast");
     return RValue::get(Result);
   }
+  case Builtin::BI__lzcnt16:
+  case Builtin::BI__lzcnt:
+  case Builtin::BI__lzcnt64: {
+    Value *ArgValue = EmitScalarExpr(E->getArg(0));
+
+    llvm::Type *ArgType = ArgValue->getType();
+    Value *F = CGM.getIntrinsic(Intrinsic::ctlz, ArgType);
+
+    llvm::Type *ResultType = ConvertType(E->getType());
+    Value *Result = Builder.CreateCall(F, {ArgValue, Builder.getFalse()});
+    if (Result->getType() != ResultType)
+      Result = Builder.CreateIntCast(Result, ResultType, /*isSigned*/true,
+                                     "cast");
+    return RValue::get(Result);
+  }
   case Builtin::BI__popcnt16:
   case Builtin::BI__popcnt:
   case Builtin::BI__popcnt64:
index e872ef10a9c388523497779eec34eb9df9d389ca..b2028ff5ba0bde6df86bd1ac122cd68f13601f32 100644 (file)
@@ -90,8 +90,6 @@ void __inwordstring(unsigned short, unsigned short *, unsigned long);
 void __lidt(void *);
 unsigned __int64 __ll_lshift(unsigned __int64, int);
 __int64 __ll_rshift(__int64, int);
-unsigned int __lzcnt(unsigned int);
-unsigned short __lzcnt16(unsigned short);
 static __inline__
 void __movsb(unsigned char *, unsigned char const *, size_t);
 static __inline__
@@ -219,7 +217,6 @@ void __incgsbyte(unsigned long);
 void __incgsdword(unsigned long);
 void __incgsqword(unsigned long);
 void __incgsword(unsigned long);
-unsigned __int64 __lzcnt64(unsigned __int64);
 static __inline__
 void __movsq(unsigned long long *, unsigned long long const *, size_t);
 static __inline__
index f2674d2a5ab12bb2eda055b3d016509b4a6ecfb9..35c1651cc4a80d953e52c0a3ec7eb04014c9216c 100644 (file)
@@ -31,6 +31,7 @@
 /* Define the default attributes for the functions in this file. */
 #define __DEFAULT_FN_ATTRS __attribute__((__always_inline__, __nodebug__, __target__("lzcnt")))
 
+#ifndef _MSC_VER
 /// Counts the number of leading zero bits in the operand.
 ///
 /// \headerfile <x86intrin.h>
 ///    An unsigned 16-bit integer whose leading zeros are to be counted.
 /// \returns An unsigned 16-bit integer containing the number of leading zero
 ///    bits in the operand.
-static __inline__ unsigned short __DEFAULT_FN_ATTRS
-__lzcnt16(unsigned short __X)
-{
-  return __builtin_ia32_lzcnt_u16(__X);
-}
+#define __lzcnt16(X) __builtin_ia32_lzcnt_u16((unsigned short)(X))
+#endif // _MSC_VER
 
 /// Counts the number of leading zero bits in the operand.
 ///
@@ -82,6 +80,7 @@ _lzcnt_u32(unsigned int __X)
 }
 
 #ifdef __x86_64__
+#ifndef _MSC_VER
 /// Counts the number of leading zero bits in the operand.
 ///
 /// \headerfile <x86intrin.h>
@@ -93,11 +92,8 @@ _lzcnt_u32(unsigned int __X)
 /// \returns An unsigned 64-bit integer containing the number of leading zero
 ///    bits in the operand.
 /// \see _lzcnt_u64
-static __inline__ unsigned long long __DEFAULT_FN_ATTRS
-__lzcnt64(unsigned long long __X)
-{
-  return __builtin_ia32_lzcnt_u64(__X);
-}
+#define __lzcnt64(X) __builtin_ia32_lzcnt_u64((unsigned long long)(X))
+#endif // _MSC_VER
 
 /// Counts the number of leading zero bits in the operand.
 ///
index 65d7670584621374fa56fbb0e9b22debffa561be..adc8ac98e5738c1bcfd59342d3b87e0e0bfd2e1d 100644 (file)
@@ -148,3 +148,51 @@ LONG test_InterlockedDecrement(LONG volatile *Addend) {
 // CHECK: [[RESULT:%[0-9]+]] = add i32 [[TMP]], -1
 // CHECK: ret i32 [[RESULT]]
 // CHECK: }
+
+unsigned short test__lzcnt16(unsigned short x) {
+  return __lzcnt16(x);
+}
+// CHECK: i16 @test__lzcnt16
+// CHECK:  [[RESULT:%[0-9]+]] = tail call i16 @llvm.ctlz.i16(i16 %x, i1 false)
+// CHECK: ret i16 [[RESULT]]
+// CHECK: }
+
+unsigned int test__lzcnt(unsigned int x) {
+  return __lzcnt(x);
+}
+// CHECK: i32 @test__lzcnt
+// CHECK:  [[RESULT:%[0-9]+]] = tail call i32 @llvm.ctlz.i32(i32 %x, i1 false)
+// CHECK: ret i32 [[RESULT]]
+// CHECK: }
+
+unsigned __int64 test__lzcnt64(unsigned __int64 x) {
+  return __lzcnt64(x);
+}
+// CHECK: i64 @test__lzcnt64
+// CHECK:  [[RESULT:%[0-9]+]] = tail call i64 @llvm.ctlz.i64(i64 %x, i1 false)
+// CHECK: ret i64 [[RESULT]]
+// CHECK: }
+
+unsigned short test__popcnt16(unsigned short x) {
+  return __popcnt16(x);
+}
+// CHECK: i16 @test__popcnt16
+// CHECK:  [[RESULT:%[0-9]+]] = tail call i16 @llvm.ctpop.i16(i16 %x)
+// CHECK: ret i16 [[RESULT]]
+// CHECK: }
+
+unsigned int test__popcnt(unsigned int x) {
+  return __popcnt(x);
+}
+// CHECK: i32 @test__popcnt
+// CHECK:  [[RESULT:%[0-9]+]] = tail call i32 @llvm.ctpop.i32(i32 %x)
+// CHECK: ret i32 [[RESULT]]
+// CHECK: }
+
+unsigned __int64 test__popcnt64(unsigned __int64 x) {
+  return __popcnt64(x);
+}
+// CHECK: i64 @test__popcnt64
+// CHECK:  [[RESULT:%[0-9]+]] = tail call i64 @llvm.ctpop.i64(i64 %x)
+// CHECK: ret i64 [[RESULT]]
+// CHECK: }