public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [Patch, i386, testsuite] Fix for PR49547, new tescases for lzcnt instruction
@ 2011-07-26 15:40 Kirill Yukhin
  2011-07-26 15:45 ` Mike Stump
  0 siblings, 1 reply; 25+ messages in thread
From: Kirill Yukhin @ 2011-07-26 15:40 UTC (permalink / raw)
  To: gcc-patches List, Uros Bizjak, H.J. Lu, Kirill Yukhin

[-- Attachment #1: Type: text/plain, Size: 2111 bytes --]

Hi,
I've prepared a patch for http://gcc.gnu.org/bugzilla/show_bug.cgi?id=49547

I've also prepared a bunch of tests for lzcnt instuction generation.

ChangeLog entry:
2011-07-26  Kirill Yukhin  <kirill.yukhin@intel.com>

	PR target/49547
        * config/i386/abmintrin.h (head): Added check if __LZCNT__ is defined.
        (__lzcnt32): Fixed name according to Spec.
        * config/i386/bmiintrin.h (head): Updated year for Copyright.
        (__lzcnt_u16): Removed.
        (__lzcnt_u32): Removed.
        (__lzcnt_u64): Likewise.
        * config/i386/cpuid.h: New bit defined.
        * config/i386/driver-i386.c (host_detect_local_cpu): Detect
        LZCNT feature.
        * config/i386/i386-c.c (ix86_target_macros_internal): Define
        __LZCNT__ if needed.
        * config/i386/i386.c (ix86_target_string): New entry to array.
        (ix86_option_override_internal): Handling LZCNT option.
        (ix86_valid_target_attribute_inner_p): Likewise.
        (bdesc_args): built-in for LZCNT is extended to work under
        another flag.
        * config/i386/i386.h (TARGET_LZCNT): New.
        (CLZ_DEFINED_VALUE_AT_ZERO): Updated flag name.
        * config/i386/i386.md (clz<mode>2): Target fixed.
        (clz<mode>2_lzcnt): Likewise.
        * doc/invoke.texi: Added mention of -mlzcnt option.
        * doc/extend.texi: Likewise.


testsuite/ChangeLog entry:
2011-07-26  Kirill Yukhin  <kirill.yukhin@intel.com>

	* lib/target-supports.exp (check_lzcnt_hw_available): New.
	(check_effective_target_lzcnt_runtime): Likewise.
	(check_effective_target_lzcnt): Likewise.
	* gcc.target/i386/lzcnt-1.c: New test.
	* gcc.target/i386/lzcnt-2.c: Likewise.
	* gcc.target/i386/lzcnt-2a.c: Likewise.
	* gcc.target/i386/lzcnt-3.c: New test.
	* gcc.target/i386/lzcnt-4.c: Likewise.
	* gcc.target/i386/lzcnt-4a.c: Likewise.
	* gcc.target/i386/lzcnt-5.c: Likewise.
	* gcc.target/i386/lzcnt-6.c: Likewise.
	* gcc.target/i386/lzcnt-6a.c: Likewise.
	* gcc.target/i386/lzcnt-check.h: New driver to run LZCNT-*
	tests only if HW available.

Bootstrapped, make-check-ed. No new fails.
OK for trunk?

Thanks, K

[-- Attachment #2: lzcnt.gcc.patch --]
[-- Type: application/octet-stream, Size: 20075 bytes --]

diff --git a/gcc/config/i386/abmintrin.h b/gcc/config/i386/abmintrin.h
index 9d87f57..2b5f56b 100644
--- a/gcc/config/i386/abmintrin.h
+++ b/gcc/config/i386/abmintrin.h
@@ -25,8 +25,8 @@
 # error "Never use <abmintrin.h> directly; include <x86intrin.h> instead."
 #endif
 
-#ifndef __ABM__
-# error "ABM instruction set not enabled"
+#if !defined (__ABM__) && !defined(__LZCNT__)
+# error "ABM (LZCNT) instruction set not enabled"
 #endif /* __ABM__ */
 
 #ifndef _ABMINTRIN_H_INCLUDED
@@ -39,7 +39,7 @@ __lzcnt16 (unsigned short __X)
 }
 
 extern __inline unsigned int __attribute__((__gnu_inline__, __always_inline__, __artificial__))
-__lzcnt (unsigned int __X)
+__lzcnt32 (unsigned int __X)
 {
   return __builtin_clz (__X);
 }
diff --git a/gcc/config/i386/bmiintrin.h b/gcc/config/i386/bmiintrin.h
index 225f2ec..1699c61 100644
--- a/gcc/config/i386/bmiintrin.h
+++ b/gcc/config/i386/bmiintrin.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2010 Free Software Foundation, Inc.
+/* Copyright (C) 2010, 2011 Free Software Foundation, Inc.
 
    This file is part of GCC.
 
@@ -33,12 +33,6 @@
 #define _BMIINTRIN_H_INCLUDED
 
 extern __inline unsigned short __attribute__((__gnu_inline__, __always_inline__, __artificial__))
-__lzcnt_u16 (unsigned short __X)
-{
-  return __builtin_clzs (__X);
-}
-
-extern __inline unsigned short __attribute__((__gnu_inline__, __always_inline__, __artificial__))
 __tzcnt_u16 (unsigned short __X)
 {
   return __builtin_ctzs (__X);
@@ -79,12 +73,6 @@ __blsr_u32 (unsigned int __X)
   return tmp;
 }
 
-extern __inline unsigned int __attribute__((__gnu_inline__, __always_inline__, __artificial__))
-__lzcnt_u32 (unsigned int __X)
-{
-  return __builtin_clz (__X);
-}
-
 
 extern __inline unsigned int __attribute__((__gnu_inline__, __always_inline__, __artificial__))
 __tzcnt_u32 (unsigned int __X)
@@ -129,12 +117,6 @@ __blsr_u64 (unsigned long long __X)
 }
 
 extern __inline unsigned long long __attribute__((__gnu_inline__, __always_inline__, __artificial__))
-__lzcnt_u64 (unsigned long long __X)
-{
-  return __builtin_clzll (__X);
-}
-
-extern __inline unsigned long long __attribute__((__gnu_inline__, __always_inline__, __artificial__))
 __tzcnt_u64 (unsigned long long __X)
 {
   return __builtin_ctzll (__X);
diff --git a/gcc/config/i386/cpuid.h b/gcc/config/i386/cpuid.h
index 3c3f47b..8826c28 100644
--- a/gcc/config/i386/cpuid.h
+++ b/gcc/config/i386/cpuid.h
@@ -24,6 +24,7 @@
 /* %ecx */
 #define bit_SSE3	(1 << 0)
 #define bit_PCLMUL	(1 << 1)
+#define bit_LZCNT	(1 << 5)
 #define bit_SSSE3	(1 << 9)
 #define bit_FMA		(1 << 12)
 #define bit_CMPXCHG16B	(1 << 13)
diff --git a/gcc/config/i386/driver-i386.c b/gcc/config/i386/driver-i386.c
index ecd8958..5823987 100644
--- a/gcc/config/i386/driver-i386.c
+++ b/gcc/config/i386/driver-i386.c
@@ -396,7 +396,7 @@ const char *host_detect_local_cpu (int argc, const char **argv)
   unsigned int has_popcnt = 0, has_aes = 0, has_avx = 0;
   unsigned int has_pclmul = 0, has_abm = 0, has_lwp = 0;
   unsigned int has_fma = 0, has_fma4 = 0, has_xop = 0;
-  unsigned int has_bmi = 0, has_tbm = 0;
+  unsigned int has_bmi = 0, has_tbm = 0, has_lzcnt = 0;
 
   bool arch;
 
@@ -465,6 +465,7 @@ const char *host_detect_local_cpu (int argc, const char **argv)
       has_fma4 = ecx & bit_FMA4;
       has_xop = ecx & bit_XOP;
       has_tbm = ecx & bit_TBM;
+      has_lzcnt = ecx & bit_LZCNT;
 
       has_longmode = edx & bit_LM;
       has_3dnowp = edx & bit_3DNOWP;
@@ -717,10 +718,11 @@ const char *host_detect_local_cpu (int argc, const char **argv)
       const char *avx = has_avx ? " -mavx" : " -mno-avx";
       const char *sse4_2 = has_sse4_2 ? " -msse4.2" : " -mno-sse4.2";
       const char *sse4_1 = has_sse4_1 ? " -msse4.1" : " -mno-sse4.1";
+      const char *lzcnt = has_lzcnt ? " -mlzcnt" : " -mnolzcnt";
 
       options = concat (options, cx16, sahf, movbe, ase, pclmul,
 			popcnt, abm, lwp, fma, fma4, xop, bmi, tbm,
-			avx, sse4_2, sse4_1, NULL);
+			avx, sse4_2, sse4_1, lzcnt, NULL);
     }
 
 done:
diff --git a/gcc/config/i386/i386-c.c b/gcc/config/i386/i386-c.c
index 5cbcfd5..1fc333c 100644
--- a/gcc/config/i386/i386-c.c
+++ b/gcc/config/i386/i386-c.c
@@ -271,6 +271,8 @@ ix86_target_macros_internal (int isa_flag,
     def_or_undef (parse_in, "__ABM__");
   if (isa_flag & OPTION_MASK_ISA_BMI)
     def_or_undef (parse_in, "__BMI__");
+  if (isa_flag & OPTION_MASK_ISA_LZCNT)
+    def_or_undef (parse_in, "__LZCNT__");
   if (isa_flag & OPTION_MASK_ISA_TBM)
     def_or_undef (parse_in, "__TBM__");
   if (isa_flag & OPTION_MASK_ISA_POPCNT)
diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
index 96263ed..a60b2ae 100644
--- a/gcc/config/i386/i386.c
+++ b/gcc/config/i386/i386.c
@@ -2663,6 +2663,7 @@ ix86_target_string (int isa, int flags, const char *arch, const char *tune,
     { "-mmmx",		OPTION_MASK_ISA_MMX },
     { "-mabm",		OPTION_MASK_ISA_ABM },
     { "-mbmi",		OPTION_MASK_ISA_BMI },
+    { "-mlzcnt",	OPTION_MASK_ISA_LZCNT },
     { "-mtbm",		OPTION_MASK_ISA_TBM },
     { "-mpopcnt",	OPTION_MASK_ISA_POPCNT },
     { "-mmovbe",	OPTION_MASK_ISA_MOVBE },
@@ -2917,7 +2918,8 @@ ix86_option_override_internal (bool main_args_p)
       PTA_RDRND = 1 << 25,
       PTA_F16C = 1 << 26,
       PTA_BMI = 1 << 27,
-      PTA_TBM = 1 << 28
+      PTA_TBM = 1 << 28,
+      PTA_LZCNT = 1 << 29
       /* if this reaches 32, need to widen struct pta flags below */
     };
 
@@ -3281,6 +3283,9 @@ ix86_option_override_internal (bool main_args_p)
 	if (processor_alias_table[i].flags & PTA_BMI
 	    && !(ix86_isa_flags_explicit & OPTION_MASK_ISA_BMI))
 	  ix86_isa_flags |= OPTION_MASK_ISA_BMI;
+	if (processor_alias_table[i].flags & (PTA_LZCNT | PTA_ABM)
+	    && !(ix86_isa_flags_explicit & OPTION_MASK_ISA_LZCNT))
+	  ix86_isa_flags |= OPTION_MASK_ISA_LZCNT;
 	if (processor_alias_table[i].flags & PTA_TBM
 	    && !(ix86_isa_flags_explicit & OPTION_MASK_ISA_TBM))
 	  ix86_isa_flags |= OPTION_MASK_ISA_TBM;
@@ -3528,6 +3533,10 @@ ix86_option_override_internal (bool main_args_p)
   if (TARGET_SSE4_2 || TARGET_ABM)
     ix86_isa_flags |= OPTION_MASK_ISA_POPCNT & ~ix86_isa_flags_explicit;
 
+  /* Turn on lzcnt instruction for -mabm.  */
+  if (TARGET_ABM)
+    ix86_isa_flags |= OPTION_MASK_ISA_LZCNT & ~ix86_isa_flags_explicit;
+
   /* Validate -mpreferred-stack-boundary= value or default it to
      PREFERRED_STACK_BOUNDARY_DEFAULT.  */
   ix86_preferred_stack_boundary = PREFERRED_STACK_BOUNDARY_DEFAULT;
@@ -4033,6 +4042,7 @@ ix86_valid_target_attribute_inner_p (tree args, char *p_strings[],
     IX86_ATTR_ISA ("3dnow",	OPT_m3dnow),
     IX86_ATTR_ISA ("abm",	OPT_mabm),
     IX86_ATTR_ISA ("bmi",	OPT_mbmi),
+    IX86_ATTR_ISA ("lzcnt",	OPT_mlzcnt),
     IX86_ATTR_ISA ("tbm",	OPT_mtbm),
     IX86_ATTR_ISA ("aes",	OPT_maes),
     IX86_ATTR_ISA ("avx",	OPT_mavx),
@@ -24936,7 +24946,7 @@ static const struct builtin_description bdesc_args[] =
   { OPTION_MASK_ISA_AVX, CODE_FOR_copysignv8sf3,  "__builtin_ia32_copysignps256", IX86_BUILTIN_CPYSGNPS256, UNKNOWN, (int) V8SF_FTYPE_V8SF_V8SF },
   { OPTION_MASK_ISA_AVX, CODE_FOR_copysignv4df3,  "__builtin_ia32_copysignpd256", IX86_BUILTIN_CPYSGNPD256, UNKNOWN, (int) V4DF_FTYPE_V4DF_V4DF },
 
-  { OPTION_MASK_ISA_ABM, CODE_FOR_clzhi2_abm,   "__builtin_clzs",   IX86_BUILTIN_CLZS,    UNKNOWN,     (int) UINT16_FTYPE_UINT16 },
+  { OPTION_MASK_ISA_ABM | OPTION_MASK_ISA_LZCNT, CODE_FOR_clzhi2_lzcnt,   "__builtin_clzs",   IX86_BUILTIN_CLZS,    UNKNOWN,     (int) UINT16_FTYPE_UINT16 },
 
   /* BMI */
   { OPTION_MASK_ISA_BMI, CODE_FOR_bmi_bextr_si, "__builtin_ia32_bextr_u32", IX86_BUILTIN_BEXTR32, UNKNOWN, (int) UINT_FTYPE_UINT_UINT },
diff --git a/gcc/config/i386/i386.h b/gcc/config/i386/i386.h
index 20c9a8f..f43586d 100644
--- a/gcc/config/i386/i386.h
+++ b/gcc/config/i386/i386.h
@@ -61,6 +61,7 @@ see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
 #define TARGET_ROUND	OPTION_ISA_ROUND
 #define TARGET_ABM	OPTION_ISA_ABM
 #define TARGET_BMI	OPTION_ISA_BMI
+#define TARGET_LZCNT	OPTION_ISA_LZCNT
 #define TARGET_TBM	OPTION_ISA_TBM
 #define TARGET_POPCNT	OPTION_ISA_POPCNT
 #define TARGET_SAHF	OPTION_ISA_SAHF
@@ -2288,7 +2289,7 @@ extern void debug_dispatch_window (int);
 #define CTZ_DEFINED_VALUE_AT_ZERO(MODE, VALUE) \
 	((VALUE) = GET_MODE_BITSIZE (MODE), TARGET_BMI)
 #define CLZ_DEFINED_VALUE_AT_ZERO(MODE, VALUE) \
-	((VALUE) = GET_MODE_BITSIZE (MODE), TARGET_BMI)
+	((VALUE) = GET_MODE_BITSIZE (MODE), TARGET_LZCNT)
 
 
 /* Flags returned by ix86_get_callcvt ().  */
diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md
index b704fa7..e623109 100644
--- a/gcc/config/i386/i386.md
+++ b/gcc/config/i386/i386.md
@@ -11876,19 +11876,19 @@
       (clobber (reg:CC FLAGS_REG))])]
   ""
 {
-  if (TARGET_ABM)
+  if (TARGET_LZCNT)
     {
-      emit_insn (gen_clz<mode>2_abm (operands[0], operands[1]));
+      emit_insn (gen_clz<mode>2_lzcnt (operands[0], operands[1]));
       DONE;
     }
   operands[2] = GEN_INT (GET_MODE_BITSIZE (<MODE>mode)-1);
 })
 
-(define_insn "clz<mode>2_abm"
+(define_insn "clz<mode>2_lzcnt"
   [(set (match_operand:SWI248 0 "register_operand" "=r")
 	(clz:SWI248 (match_operand:SWI248 1 "nonimmediate_operand" "rm")))
    (clobber (reg:CC FLAGS_REG))]
-  "TARGET_ABM || TARGET_BMI"
+  "TARGET_LZCNT"
   "lzcnt{<imodesuffix>}\t{%1, %0|%0, %1}"
   [(set_attr "prefix_rep" "1")
    (set_attr "type" "bitmanip")
diff --git a/gcc/config/i386/i386.opt b/gcc/config/i386/i386.opt
index 5e6b5df..f197dd8 100644
--- a/gcc/config/i386/i386.opt
+++ b/gcc/config/i386/i386.opt
@@ -489,6 +489,10 @@ mbmi
 Target Report Mask(ISA_BMI) Var(ix86_isa_flags) Save
 Support BMI built-in functions and code generation
 
+mlzcnt
+Target Report Mask(ISA_LZCNT) Var(ix86_isa_flags) Save
+Support LZCNT built-in function and code generation
+
 mtbm
 Target Report Mask(ISA_TBM) Var(ix86_isa_flags) Save
 Support TBM built-in functions and code generation
diff --git a/gcc/config/i386/x86intrin.h b/gcc/config/i386/x86intrin.h
index 36b43df..0d4211a 100644
--- a/gcc/config/i386/x86intrin.h
+++ b/gcc/config/i386/x86intrin.h
@@ -77,7 +77,7 @@
 #include <lwpintrin.h>
 #endif
 
-#ifdef __ABM__
+#if defined (__ABM__) || defined(__LZCNT__)
 #include <abmintrin.h>
 #endif
 
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index dcbf29f..d705720 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -9673,6 +9673,11 @@ All of them generate the machine instruction that is part of the name.
 @smallexample
 unsigned int __builtin_ia32_bextr_u32(unsigned int, unsigned int);
 unsigned long long __builtin_ia32_bextr_u64 (unsigned long long, unsigned long long);
+@end smallexample
+
+The following built-in functions are available when @option{-mlzcnt} is used.
+All of them generate the machine instruction that is part of the name.
+@smallexample
 unsigned short __builtin_ia32_lzcnt_16(unsigned short);
 unsigned int __builtin_ia32_lzcnt_u32(unsigned int);
 unsigned long long __builtin_ia32_lzcnt_u64 (unsigned long long);
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 7783786..137f256 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -606,8 +606,8 @@ Objective-C and Objective-C++ Dialects}.
 -mcld -mcx16 -msahf -mmovbe -mcrc32 -mrecip -mvzeroupper @gol
 -mmmx  -msse  -msse2 -msse3 -mssse3 -msse4.1 -msse4.2 -msse4 -mavx @gol
 -maes -mpclmul -mfsgsbase -mrdrnd -mf16c -mfma @gol
--msse4a -m3dnow -mpopcnt -mabm -mbmi -mtbm -mfma4 -mxop -mlwp @gol
--mthreads  -mno-align-stringops  -minline-all-stringops @gol
+-msse4a -m3dnow -mpopcnt -mabm -mbmi -mtbm -mfma4 -mxop -mlzcnt @gol
+-mlwp -mthreads  -mno-align-stringops  -minline-all-stringops @gol
 -minline-stringops-dynamically -mstringop-strategy=@var{alg} @gol
 -mpush-args  -maccumulate-outgoing-args  -m128bit-long-double @gol
 -m96bit-long-double  -mregparm=@var{num}  -msseregparm @gol
@@ -12687,6 +12687,8 @@ preferred alignment to @option{-mpreferred-stack-boundary=2}.
 @itemx -mno-abm
 @itemx -mbmi
 @itemx -mno-bmi
+@itemx -mlzcnt
+@itemx -mno-lzcnt
 @itemx -mtbm
 @itemx -mno-tbm
 @opindex mmmx
@@ -12697,7 +12699,7 @@ preferred alignment to @option{-mpreferred-stack-boundary=2}.
 @opindex mno-3dnow
 These switches enable or disable the use of instructions in the MMX, SSE,
 SSE2, SSE3, SSSE3, SSE4.1, AVX, AES, PCLMUL, FSGSBASE, RDRND, F16C, FMA,
-SSE4A, FMA4, XOP, LWP, ABM, BMI, or 3DNow!@: extended instruction sets.
+SSE4A, FMA4, XOP, LWP, ABM, BMI, LZCNT or 3DNow!@: extended instruction sets.
 These extensions are also available as built-in functions: see
 @ref{X86 Built-in Functions}, for details of the functions enabled and
 disabled by these switches.
diff --git a/gcc/testsuite/gcc.target/i386/lzcnt-1.c b/gcc/testsuite/gcc.target/i386/lzcnt-1.c
new file mode 100644
index 0000000..f6240d1b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/lzcnt-1.c
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -mlzcnt " } */
+/* { dg-final { scan-assembler "lzcntw\[^\\n]*(%|)ax" } } */
+
+#include <x86intrin.h>
+
+unsigned int
+func_lzcnt16 (unsigned int X)
+{
+  return __lzcnt16(X);
+}
diff --git a/gcc/testsuite/gcc.target/i386/lzcnt-2.c b/gcc/testsuite/gcc.target/i386/lzcnt-2.c
new file mode 100644
index 0000000..1228499
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/lzcnt-2.c
@@ -0,0 +1,35 @@
+/* { dg-do run { target { lzcnt } } } */
+/* { dg-options "-O2 -mlzcnt -fno-inline" } */
+
+#include <x86intrin.h>
+
+#include "lzcnt-check.h"
+
+short calc_lzcnt_u16 (short src)
+{
+  int i;
+  short res = 0;
+
+  while ( (res<16) && (((src>>(15-res))&1) == 0))
+    ++res;
+
+  return res;
+}
+
+static void
+lzcnt_test ()
+{
+  unsigned i;
+  short src = 0x7ace;
+  short res, res_ref;
+
+  for (i=0; i<5; ++i) {
+    src = src >> i;
+
+    res_ref = calc_lzcnt_u16 (src);
+    res = __lzcnt16 (src);
+
+    if (res != res_ref)
+      abort();
+  }
+}
diff --git a/gcc/testsuite/gcc.target/i386/lzcnt-2a.c b/gcc/testsuite/gcc.target/i386/lzcnt-2a.c
new file mode 100644
index 0000000..fe1069f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/lzcnt-2a.c
@@ -0,0 +1,6 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -mlzcnt" } */
+
+#include "lzcnt-2.c"
+
+/* { dg-final { scan-assembler "lzcntw" } } */
diff --git a/gcc/testsuite/gcc.target/i386/lzcnt-3.c b/gcc/testsuite/gcc.target/i386/lzcnt-3.c
new file mode 100644
index 0000000..1477951
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/lzcnt-3.c
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-options "-O0 -mlzcnt " } */
+/* { dg-final { scan-assembler "lzcntl\[^\\n]*(%|)eax" } } */
+
+#include <x86intrin.h>
+
+unsigned int
+func_lzcnt32 (unsigned int X)
+{
+  return __lzcnt32(X);
+}
diff --git a/gcc/testsuite/gcc.target/i386/lzcnt-4.c b/gcc/testsuite/gcc.target/i386/lzcnt-4.c
new file mode 100644
index 0000000..864c857
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/lzcnt-4.c
@@ -0,0 +1,35 @@
+/* { dg-do run { target { lzcnt } } } */
+/* { dg-options "-O2 -mlzcnt -fno-inline" } */
+
+#include <x86intrin.h>
+
+#include "lzcnt-check.h"
+
+int calc_lzcnt_u32 (int src)
+{
+  int i;
+  int res = 0;
+
+  while ( (res<32) && (((src>>(31-res))&1) == 0))
+    ++res;
+
+  return res;
+}
+
+static void
+lzcnt_test ()
+{
+  unsigned i;
+  int src = 0xce7ace0;
+  int res, res_ref;
+
+  for (i=0; i<5; ++i) {
+    src = src >> i;
+
+    res_ref = calc_lzcnt_u32 (src);
+    res = __lzcnt32 (src);
+
+    if (res != res_ref)
+      abort();
+  }
+}
diff --git a/gcc/testsuite/gcc.target/i386/lzcnt-4a.c b/gcc/testsuite/gcc.target/i386/lzcnt-4a.c
new file mode 100644
index 0000000..6bba6a9
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/lzcnt-4a.c
@@ -0,0 +1,6 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -mlzcnt" } */
+
+#include "lzcnt-4.c"
+
+/* { dg-final { scan-assembler "lzcntl" } } */
diff --git a/gcc/testsuite/gcc.target/i386/lzcnt-5.c b/gcc/testsuite/gcc.target/i386/lzcnt-5.c
new file mode 100644
index 0000000..a4b9aaf
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/lzcnt-5.c
@@ -0,0 +1,11 @@
+/* { dg-do compile { target { ! ia32 } } } */
+/* { dg-options "-O2 -mlzcnt" } */
+/* { dg-final { scan-assembler "lzcntq\[^\\n]*(%|)rax" } } */
+
+#include <x86intrin.h>
+
+unsigned int
+func_lzcnt64 (unsigned long long X)
+{
+  return __lzcnt64(X);
+}
diff --git a/gcc/testsuite/gcc.target/i386/lzcnt-6.c b/gcc/testsuite/gcc.target/i386/lzcnt-6.c
new file mode 100644
index 0000000..e649e63
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/lzcnt-6.c
@@ -0,0 +1,35 @@
+/* { dg-do run { target { lzcnt && { ! ia32 } } } } */
+/* { dg-options "-O2 -mlzcnt -fno-inline" } */
+
+#include <x86intrin.h>
+
+#include "lzcnt-check.h"
+
+long long calc_lzcnt_u64 (long long src)
+{
+  int i;
+  int res = 0;
+
+  while ( (res<64) && (((src>>(63-res))&1) == 0))
+    ++res;
+
+  return res;
+}
+
+static void
+lzcnt_test ()
+{
+  unsigned i;
+  long long src = 0xce7ace0ce7ace0;
+  long long res, res_ref;
+
+  for (i=0; i<5; ++i) {
+    src = src >> i;
+
+    res_ref = calc_lzcnt_u64 (src);
+    res = __lzcnt64 (src);
+
+    if (res != res_ref)
+      abort();
+  }
+}
diff --git a/gcc/testsuite/gcc.target/i386/lzcnt-6a.c b/gcc/testsuite/gcc.target/i386/lzcnt-6a.c
new file mode 100644
index 0000000..2090093
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/lzcnt-6a.c
@@ -0,0 +1,6 @@
+/* { dg-do compile { target { ! ia32 } } } */
+/* { dg-options "-O2 -mlzcnt" } */
+
+#include "lzcnt-6.c"
+
+/* { dg-final { scan-assembler "lzcntq" } } */
diff --git a/gcc/testsuite/gcc.target/i386/lzcnt-check.h b/gcc/testsuite/gcc.target/i386/lzcnt-check.h
new file mode 100644
index 0000000..8aad834
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/lzcnt-check.h
@@ -0,0 +1,37 @@
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "cpuid.h"
+
+static void lzcnt_test (void);
+
+static void
+__attribute__ ((noinline))
+do_test (void)
+{
+  lzcnt_test ();
+}
+
+int
+main ()
+{
+  unsigned int eax, ebx, ecx, edx;
+
+  if (!__get_cpuid (0x80000001, &eax, &ebx, &ecx, &edx))
+    return 0;
+
+  /* Run LZCNT test only if host has LZCNT support.  */
+  if (ecx & bit_LZCNT)
+    {
+      do_test ();
+#ifdef DEBUG
+      printf ("PASSED\n");
+#endif
+    }
+#ifdef DEBUG
+  else
+    printf ("SKIPPED\n");
+#endif
+
+  return 0;
+}
diff --git a/gcc/testsuite/lib/target-supports.exp b/gcc/testsuite/lib/target-supports.exp
index f7027bd..858aa2a 100644
--- a/gcc/testsuite/lib/target-supports.exp
+++ b/gcc/testsuite/lib/target-supports.exp
@@ -1152,6 +1152,30 @@ proc check_avx_hw_available { } {
     }]
 }
 
+# Return 1 if the target supports executing LZCNT instruction, 0
+# otherwise.  Cache the result.
+
+proc check_lzcnt_hw_available { } {
+    return [check_cached_effective_target lzcnt_hw_available {
+	# If this is not the right target then we can skip the test.
+	if { !([istarget x86_64-*-*] || [istarget i?86-*-*]) } {
+	    expr 0
+	} else {
+	    check_runtime_nocache lzcnt_hw_available {
+		#include "cpuid.h"
+		int main ()
+		{
+		  unsigned int eax, ebx, ecx, edx;
+		  if (__get_cpuid (0x80000001, &eax, &ebx, &ecx, &edx))
+		    return !(ecx & bit_LZCNT);
+		  return 1;
+		}
+	    } ""
+	}
+    }]
+}
+
+
 # Return 1 if the target supports running SSE executables, 0 otherwise.
 
 proc check_effective_target_sse_runtime { } {
@@ -1185,6 +1209,16 @@ proc check_effective_target_avx_runtime { } {
     return 0
 }
 
+# Return 1 if the target supports running AVX executables, 0 otherwise.
+
+proc check_effective_target_lzcnt_runtime { } {
+    if { [check_effective_target_lzcnt]
+	 && [check_lzcnt_hw_available] } {
+	return 1
+    }
+    return 0
+}
+
 # Return 1 if the target supports executing VSX instructions, 0
 # otherwise.  Cache the result.
 
@@ -3809,6 +3843,17 @@ proc check_effective_target_avx { } {
     } "-O2 -mavx" ]
 }
 
+# Return 1 if lzcnt instruction can be compiled.
+
+proc check_effective_target_lzcnt { } {
+    return [check_no_compiler_messages avx object {
+	void _lzcnt (void)
+	{
+	   __builtin_clzs (0);
+	}
+    } "-O2 -mlzcnt" ]
+}
+
 # Return 1 if sse instructions can be compiled.
 proc check_effective_target_sse { } {
     return [check_no_compiler_messages sse object {

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [Patch, i386, testsuite] Fix for PR49547, new tescases for lzcnt instruction
  2011-07-26 15:40 [Patch, i386, testsuite] Fix for PR49547, new tescases for lzcnt instruction Kirill Yukhin
@ 2011-07-26 15:45 ` Mike Stump
  2011-07-26 16:43   ` Uros Bizjak
  0 siblings, 1 reply; 25+ messages in thread
From: Mike Stump @ 2011-07-26 15:45 UTC (permalink / raw)
  To: Kirill Yukhin; +Cc: gcc-patches List, Uros Bizjak, H.J. Lu, Kirill Yukhin

On Jul 26, 2011, at 7:50 AM, Kirill Yukhin <kirill.yukhin@gmail.com> wrote:
> I've also prepared a bunch of tests for lzcnt instuction generation..

> /ChangeLog entry:
> 2011-07-26  Kirill Yukhin  <kirill.yukhin@intel.com>
> 
>    * lib/target-supports.exp (check_lzcnt_hw_available): New.
>    (check_effective_target_lzcnt_runtime): Likewise.
>    (check_effective_target_lzcnt): Likewise.

For target supports, could you add an x86 to the name somewhere...

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [Patch, i386, testsuite] Fix for PR49547, new tescases for lzcnt instruction
  2011-07-26 15:45 ` Mike Stump
@ 2011-07-26 16:43   ` Uros Bizjak
  2011-07-27  8:06     ` Kirill Yukhin
  0 siblings, 1 reply; 25+ messages in thread
From: Uros Bizjak @ 2011-07-26 16:43 UTC (permalink / raw)
  To: Mike Stump; +Cc: Kirill Yukhin, gcc-patches List, H.J. Lu

On Tue, Jul 26, 2011 at 5:40 PM, Mike Stump <mikestump@comcast.net> wrote:
> On Jul 26, 2011, at 7:50 AM, Kirill Yukhin <kirill.yukhin@gmail.com> wrote:
>> I've also prepared a bunch of tests for lzcnt instuction generation..
>
>> /ChangeLog entry:
>> 2011-07-26  Kirill Yukhin  <kirill.yukhin@intel.com>
>>
>>    * lib/target-supports.exp (check_lzcnt_hw_available): New.
>>    (check_effective_target_lzcnt_runtime): Likewise.
>>    (check_effective_target_lzcnt): Likewise.
>
> For target supports, could you add an x86 to the name somewhere...

Actually, please implement LZCNT detection in gcc.target/i386
directory, since it is used only in this directory. You wull need only
check_effective_target_lzcnt in gcc.target/i386/i386.exp, runtime
detection should be handled in lzcnt-check.h. Oh, bonus points if you
implement avx-os-support.h (to check OS support with xgetbv insn) and
use it in all *-check.h that check for AVX runtime (including your new
lzcnt-check.h).

Other than that, your new option should be tested in
gcc.target/i386/sse-12.c, gcc.target/i386/sse-13.c,
gcc.target/i386/sse-14.c, g++.dg/other/i386-2.C and
g++.dg/other/i386-3.C. See these testcases for further details.

Uros.

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [Patch, i386, testsuite] Fix for PR49547, new tescases for lzcnt instruction
  2011-07-26 16:43   ` Uros Bizjak
@ 2011-07-27  8:06     ` Kirill Yukhin
  2011-07-27  8:12       ` Uros Bizjak
  0 siblings, 1 reply; 25+ messages in thread
From: Kirill Yukhin @ 2011-07-27  8:06 UTC (permalink / raw)
  To: Uros Bizjak; +Cc: Mike Stump, gcc-patches List, H.J. Lu

Thanks for inputs! I'll do it today.

Just ine point.
How AVX is connected to LZCNT features?
AVX requires OS support since it has wider registers etc.
LZCNT need no support from OS side, so from my point of view it is
redundant to check in lzcnt-check.h presence of AVX support from OS
side.
Or I get you wrong?

Thanks, K

On Tue, Jul 26, 2011 at 7:56 PM, Uros Bizjak <ubizjak@gmail.com> wrote:
> On Tue, Jul 26, 2011 at 5:40 PM, Mike Stump <mikestump@comcast.net> wrote:
>> On Jul 26, 2011, at 7:50 AM, Kirill Yukhin <kirill.yukhin@gmail.com> wrote:
>>> I've also prepared a bunch of tests for lzcnt instuction generation..
>>
>>> /ChangeLog entry:
>>> 2011-07-26  Kirill Yukhin  <kirill.yukhin@intel.com>
>>>
>>>    * lib/target-supports.exp (check_lzcnt_hw_available): New.
>>>    (check_effective_target_lzcnt_runtime): Likewise.
>>>    (check_effective_target_lzcnt): Likewise.
>>
>> For target supports, could you add an x86 to the name somewhere...
>
> Actually, please implement LZCNT detection in gcc.target/i386
> directory, since it is used only in this directory. You wull need only
> check_effective_target_lzcnt in gcc.target/i386/i386.exp, runtime
> detection should be handled in lzcnt-check.h. Oh, bonus points if you
> implement avx-os-support.h (to check OS support with xgetbv insn) and
> use it in all *-check.h that check for AVX runtime (including your new
> lzcnt-check.h).
>
> Other than that, your new option should be tested in
> gcc.target/i386/sse-12.c, gcc.target/i386/sse-13.c,
> gcc.target/i386/sse-14.c, g++.dg/other/i386-2.C and
> g++.dg/other/i386-3.C. See these testcases for further details.
>
> Uros.
>

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [Patch, i386, testsuite] Fix for PR49547, new tescases for lzcnt instruction
  2011-07-27  8:06     ` Kirill Yukhin
@ 2011-07-27  8:12       ` Uros Bizjak
  2011-07-27 11:16         ` Kirill Yukhin
  0 siblings, 1 reply; 25+ messages in thread
From: Uros Bizjak @ 2011-07-27  8:12 UTC (permalink / raw)
  To: Kirill Yukhin; +Cc: Mike Stump, gcc-patches List, H.J. Lu

On Wed, Jul 27, 2011 at 9:05 AM, Kirill Yukhin <kirill.yukhin@gmail.com> wrote:
> Thanks for inputs! I'll do it today.
>
> Just ine point.
> How AVX is connected to LZCNT features?
> AVX requires OS support since it has wider registers etc.
> LZCNT need no support from OS side, so from my point of view it is
> redundant to check in lzcnt-check.h presence of AVX support from OS
> side.
> Or I get you wrong?

Ah, I see. I got distracted by the wrong comment in your patch:

+# Return 1 if the target supports running AVX executables, 0 otherwise.
+
+proc check_effective_target_lzcnt_runtime { } {
+    if { [check_effective_target_lzcnt]
+	 && [check_lzcnt_hw_available] } {
+	return 1
+    }
+    return 0
+}

(I will add avx-os-support.h myself later today).

Uros.

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [Patch, i386, testsuite] Fix for PR49547, new tescases for lzcnt instruction
  2011-07-27  8:12       ` Uros Bizjak
@ 2011-07-27 11:16         ` Kirill Yukhin
  2011-07-27 11:58           ` Uros Bizjak
  0 siblings, 1 reply; 25+ messages in thread
From: Kirill Yukhin @ 2011-07-27 11:16 UTC (permalink / raw)
  To: Uros Bizjak; +Cc: Mike Stump, gcc-patches List, H.J. Lu

[-- Attachment #1: Type: text/plain, Size: 2069 bytes --]

Sorry, for misunderstanding I've introduced with error in my comment.
Your inputs are fixed. Since they don't touch sources, just testsuite,
I am posting only tesuite/ChangeLog updated entry.

tesuite/ChangeLog entry:
2011-07-27  Kirill Yukhin  <kirill.yukhin@intel.com>

	* gcc.target/i386/i386.exp (check_effective_target_lzcnt): New.
	* gcc.target/i386/lzcnt-1.c: New test.
	* gcc.target/i386/lzcnt-2.c: Likewise.
	* gcc.target/i386/lzcnt-2a.c: Likewise.
	* gcc.target/i386/lzcnt-3.c: New test.
	* gcc.target/i386/lzcnt-4.c: Likewise.
	* gcc.target/i386/lzcnt-4a.c: Likewise.
	* gcc.target/i386/lzcnt-5.c: Likewise.
	* gcc.target/i386/lzcnt-6.c: Likewise.
	* gcc.target/i386/lzcnt-6a.c: Likewise.
	* gcc.target/i386/lzcnt-check.h: New driver to run LZCNT-*
	tests only if HW available.
	* gcc.target/i386/sse-12.c: Added -mlzcnt switch.
	* gcc.target/i386/sse-13.c: Likewise.
	* gcc.target/i386/sse-14.c: Likewise.
	* g++.dg/other/i386-2.C: Likewise.
	* g++.dg/other/i386-3.C: Likewise.


Patch attached.
Changes were bootstrapped and make-check-ed (lzcnt ones under simulator).
Is it OK for now?

Thanks, K

On Wed, Jul 27, 2011 at 11:22 AM, Uros Bizjak <ubizjak@gmail.com> wrote:
> On Wed, Jul 27, 2011 at 9:05 AM, Kirill Yukhin <kirill.yukhin@gmail.com> wrote:
>> Thanks for inputs! I'll do it today.
>>
>> Just ine point.
>> How AVX is connected to LZCNT features?
>> AVX requires OS support since it has wider registers etc.
>> LZCNT need no support from OS side, so from my point of view it is
>> redundant to check in lzcnt-check.h presence of AVX support from OS
>> side.
>> Or I get you wrong?
>
> Ah, I see. I got distracted by the wrong comment in your patch:
>
> +# Return 1 if the target supports running AVX executables, 0 otherwise.
> +
> +proc check_effective_target_lzcnt_runtime { } {
> +    if { [check_effective_target_lzcnt]
> +        && [check_lzcnt_hw_available] } {
> +       return 1
> +    }
> +    return 0
> +}
>
> (I will add avx-os-support.h myself later today).
>
> Uros.
>

[-- Attachment #2: lzcnt-2.gcc.patch --]
[-- Type: application/octet-stream, Size: 22426 bytes --]

diff --git a/gcc/config/i386/abmintrin.h b/gcc/config/i386/abmintrin.h
index 9d87f57..2b5f56b 100644
--- a/gcc/config/i386/abmintrin.h
+++ b/gcc/config/i386/abmintrin.h
@@ -25,8 +25,8 @@
 # error "Never use <abmintrin.h> directly; include <x86intrin.h> instead."
 #endif
 
-#ifndef __ABM__
-# error "ABM instruction set not enabled"
+#if !defined (__ABM__) && !defined(__LZCNT__)
+# error "ABM (LZCNT) instruction set not enabled"
 #endif /* __ABM__ */
 
 #ifndef _ABMINTRIN_H_INCLUDED
@@ -39,7 +39,7 @@ __lzcnt16 (unsigned short __X)
 }
 
 extern __inline unsigned int __attribute__((__gnu_inline__, __always_inline__, __artificial__))
-__lzcnt (unsigned int __X)
+__lzcnt32 (unsigned int __X)
 {
   return __builtin_clz (__X);
 }
diff --git a/gcc/config/i386/bmiintrin.h b/gcc/config/i386/bmiintrin.h
index 225f2ec..1699c61 100644
--- a/gcc/config/i386/bmiintrin.h
+++ b/gcc/config/i386/bmiintrin.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2010 Free Software Foundation, Inc.
+/* Copyright (C) 2010, 2011 Free Software Foundation, Inc.
 
    This file is part of GCC.
 
@@ -33,12 +33,6 @@
 #define _BMIINTRIN_H_INCLUDED
 
 extern __inline unsigned short __attribute__((__gnu_inline__, __always_inline__, __artificial__))
-__lzcnt_u16 (unsigned short __X)
-{
-  return __builtin_clzs (__X);
-}
-
-extern __inline unsigned short __attribute__((__gnu_inline__, __always_inline__, __artificial__))
 __tzcnt_u16 (unsigned short __X)
 {
   return __builtin_ctzs (__X);
@@ -79,12 +73,6 @@ __blsr_u32 (unsigned int __X)
   return tmp;
 }
 
-extern __inline unsigned int __attribute__((__gnu_inline__, __always_inline__, __artificial__))
-__lzcnt_u32 (unsigned int __X)
-{
-  return __builtin_clz (__X);
-}
-
 
 extern __inline unsigned int __attribute__((__gnu_inline__, __always_inline__, __artificial__))
 __tzcnt_u32 (unsigned int __X)
@@ -129,12 +117,6 @@ __blsr_u64 (unsigned long long __X)
 }
 
 extern __inline unsigned long long __attribute__((__gnu_inline__, __always_inline__, __artificial__))
-__lzcnt_u64 (unsigned long long __X)
-{
-  return __builtin_clzll (__X);
-}
-
-extern __inline unsigned long long __attribute__((__gnu_inline__, __always_inline__, __artificial__))
 __tzcnt_u64 (unsigned long long __X)
 {
   return __builtin_ctzll (__X);
diff --git a/gcc/config/i386/cpuid.h b/gcc/config/i386/cpuid.h
index 3c3f47b..8826c28 100644
--- a/gcc/config/i386/cpuid.h
+++ b/gcc/config/i386/cpuid.h
@@ -24,6 +24,7 @@
 /* %ecx */
 #define bit_SSE3	(1 << 0)
 #define bit_PCLMUL	(1 << 1)
+#define bit_LZCNT	(1 << 5)
 #define bit_SSSE3	(1 << 9)
 #define bit_FMA		(1 << 12)
 #define bit_CMPXCHG16B	(1 << 13)
diff --git a/gcc/config/i386/driver-i386.c b/gcc/config/i386/driver-i386.c
index ecd8958..5823987 100644
--- a/gcc/config/i386/driver-i386.c
+++ b/gcc/config/i386/driver-i386.c
@@ -396,7 +396,7 @@ const char *host_detect_local_cpu (int argc, const char **argv)
   unsigned int has_popcnt = 0, has_aes = 0, has_avx = 0;
   unsigned int has_pclmul = 0, has_abm = 0, has_lwp = 0;
   unsigned int has_fma = 0, has_fma4 = 0, has_xop = 0;
-  unsigned int has_bmi = 0, has_tbm = 0;
+  unsigned int has_bmi = 0, has_tbm = 0, has_lzcnt = 0;
 
   bool arch;
 
@@ -465,6 +465,7 @@ const char *host_detect_local_cpu (int argc, const char **argv)
       has_fma4 = ecx & bit_FMA4;
       has_xop = ecx & bit_XOP;
       has_tbm = ecx & bit_TBM;
+      has_lzcnt = ecx & bit_LZCNT;
 
       has_longmode = edx & bit_LM;
       has_3dnowp = edx & bit_3DNOWP;
@@ -717,10 +718,11 @@ const char *host_detect_local_cpu (int argc, const char **argv)
       const char *avx = has_avx ? " -mavx" : " -mno-avx";
       const char *sse4_2 = has_sse4_2 ? " -msse4.2" : " -mno-sse4.2";
       const char *sse4_1 = has_sse4_1 ? " -msse4.1" : " -mno-sse4.1";
+      const char *lzcnt = has_lzcnt ? " -mlzcnt" : " -mnolzcnt";
 
       options = concat (options, cx16, sahf, movbe, ase, pclmul,
 			popcnt, abm, lwp, fma, fma4, xop, bmi, tbm,
-			avx, sse4_2, sse4_1, NULL);
+			avx, sse4_2, sse4_1, lzcnt, NULL);
     }
 
 done:
diff --git a/gcc/config/i386/i386-c.c b/gcc/config/i386/i386-c.c
index 5cbcfd5..1fc333c 100644
--- a/gcc/config/i386/i386-c.c
+++ b/gcc/config/i386/i386-c.c
@@ -271,6 +271,8 @@ ix86_target_macros_internal (int isa_flag,
     def_or_undef (parse_in, "__ABM__");
   if (isa_flag & OPTION_MASK_ISA_BMI)
     def_or_undef (parse_in, "__BMI__");
+  if (isa_flag & OPTION_MASK_ISA_LZCNT)
+    def_or_undef (parse_in, "__LZCNT__");
   if (isa_flag & OPTION_MASK_ISA_TBM)
     def_or_undef (parse_in, "__TBM__");
   if (isa_flag & OPTION_MASK_ISA_POPCNT)
diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
index 96263ed..a60b2ae 100644
--- a/gcc/config/i386/i386.c
+++ b/gcc/config/i386/i386.c
@@ -2663,6 +2663,7 @@ ix86_target_string (int isa, int flags, const char *arch, const char *tune,
     { "-mmmx",		OPTION_MASK_ISA_MMX },
     { "-mabm",		OPTION_MASK_ISA_ABM },
     { "-mbmi",		OPTION_MASK_ISA_BMI },
+    { "-mlzcnt",	OPTION_MASK_ISA_LZCNT },
     { "-mtbm",		OPTION_MASK_ISA_TBM },
     { "-mpopcnt",	OPTION_MASK_ISA_POPCNT },
     { "-mmovbe",	OPTION_MASK_ISA_MOVBE },
@@ -2917,7 +2918,8 @@ ix86_option_override_internal (bool main_args_p)
       PTA_RDRND = 1 << 25,
       PTA_F16C = 1 << 26,
       PTA_BMI = 1 << 27,
-      PTA_TBM = 1 << 28
+      PTA_TBM = 1 << 28,
+      PTA_LZCNT = 1 << 29
       /* if this reaches 32, need to widen struct pta flags below */
     };
 
@@ -3281,6 +3283,9 @@ ix86_option_override_internal (bool main_args_p)
 	if (processor_alias_table[i].flags & PTA_BMI
 	    && !(ix86_isa_flags_explicit & OPTION_MASK_ISA_BMI))
 	  ix86_isa_flags |= OPTION_MASK_ISA_BMI;
+	if (processor_alias_table[i].flags & (PTA_LZCNT | PTA_ABM)
+	    && !(ix86_isa_flags_explicit & OPTION_MASK_ISA_LZCNT))
+	  ix86_isa_flags |= OPTION_MASK_ISA_LZCNT;
 	if (processor_alias_table[i].flags & PTA_TBM
 	    && !(ix86_isa_flags_explicit & OPTION_MASK_ISA_TBM))
 	  ix86_isa_flags |= OPTION_MASK_ISA_TBM;
@@ -3528,6 +3533,10 @@ ix86_option_override_internal (bool main_args_p)
   if (TARGET_SSE4_2 || TARGET_ABM)
     ix86_isa_flags |= OPTION_MASK_ISA_POPCNT & ~ix86_isa_flags_explicit;
 
+  /* Turn on lzcnt instruction for -mabm.  */
+  if (TARGET_ABM)
+    ix86_isa_flags |= OPTION_MASK_ISA_LZCNT & ~ix86_isa_flags_explicit;
+
   /* Validate -mpreferred-stack-boundary= value or default it to
      PREFERRED_STACK_BOUNDARY_DEFAULT.  */
   ix86_preferred_stack_boundary = PREFERRED_STACK_BOUNDARY_DEFAULT;
@@ -4033,6 +4042,7 @@ ix86_valid_target_attribute_inner_p (tree args, char *p_strings[],
     IX86_ATTR_ISA ("3dnow",	OPT_m3dnow),
     IX86_ATTR_ISA ("abm",	OPT_mabm),
     IX86_ATTR_ISA ("bmi",	OPT_mbmi),
+    IX86_ATTR_ISA ("lzcnt",	OPT_mlzcnt),
     IX86_ATTR_ISA ("tbm",	OPT_mtbm),
     IX86_ATTR_ISA ("aes",	OPT_maes),
     IX86_ATTR_ISA ("avx",	OPT_mavx),
@@ -24936,7 +24946,7 @@ static const struct builtin_description bdesc_args[] =
   { OPTION_MASK_ISA_AVX, CODE_FOR_copysignv8sf3,  "__builtin_ia32_copysignps256", IX86_BUILTIN_CPYSGNPS256, UNKNOWN, (int) V8SF_FTYPE_V8SF_V8SF },
   { OPTION_MASK_ISA_AVX, CODE_FOR_copysignv4df3,  "__builtin_ia32_copysignpd256", IX86_BUILTIN_CPYSGNPD256, UNKNOWN, (int) V4DF_FTYPE_V4DF_V4DF },
 
-  { OPTION_MASK_ISA_ABM, CODE_FOR_clzhi2_abm,   "__builtin_clzs",   IX86_BUILTIN_CLZS,    UNKNOWN,     (int) UINT16_FTYPE_UINT16 },
+  { OPTION_MASK_ISA_ABM | OPTION_MASK_ISA_LZCNT, CODE_FOR_clzhi2_lzcnt,   "__builtin_clzs",   IX86_BUILTIN_CLZS,    UNKNOWN,     (int) UINT16_FTYPE_UINT16 },
 
   /* BMI */
   { OPTION_MASK_ISA_BMI, CODE_FOR_bmi_bextr_si, "__builtin_ia32_bextr_u32", IX86_BUILTIN_BEXTR32, UNKNOWN, (int) UINT_FTYPE_UINT_UINT },
diff --git a/gcc/config/i386/i386.h b/gcc/config/i386/i386.h
index 20c9a8f..f43586d 100644
--- a/gcc/config/i386/i386.h
+++ b/gcc/config/i386/i386.h
@@ -61,6 +61,7 @@ see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
 #define TARGET_ROUND	OPTION_ISA_ROUND
 #define TARGET_ABM	OPTION_ISA_ABM
 #define TARGET_BMI	OPTION_ISA_BMI
+#define TARGET_LZCNT	OPTION_ISA_LZCNT
 #define TARGET_TBM	OPTION_ISA_TBM
 #define TARGET_POPCNT	OPTION_ISA_POPCNT
 #define TARGET_SAHF	OPTION_ISA_SAHF
@@ -2288,7 +2289,7 @@ extern void debug_dispatch_window (int);
 #define CTZ_DEFINED_VALUE_AT_ZERO(MODE, VALUE) \
 	((VALUE) = GET_MODE_BITSIZE (MODE), TARGET_BMI)
 #define CLZ_DEFINED_VALUE_AT_ZERO(MODE, VALUE) \
-	((VALUE) = GET_MODE_BITSIZE (MODE), TARGET_BMI)
+	((VALUE) = GET_MODE_BITSIZE (MODE), TARGET_LZCNT)
 
 
 /* Flags returned by ix86_get_callcvt ().  */
diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md
index b704fa7..e623109 100644
--- a/gcc/config/i386/i386.md
+++ b/gcc/config/i386/i386.md
@@ -11876,19 +11876,19 @@
       (clobber (reg:CC FLAGS_REG))])]
   ""
 {
-  if (TARGET_ABM)
+  if (TARGET_LZCNT)
     {
-      emit_insn (gen_clz<mode>2_abm (operands[0], operands[1]));
+      emit_insn (gen_clz<mode>2_lzcnt (operands[0], operands[1]));
       DONE;
     }
   operands[2] = GEN_INT (GET_MODE_BITSIZE (<MODE>mode)-1);
 })
 
-(define_insn "clz<mode>2_abm"
+(define_insn "clz<mode>2_lzcnt"
   [(set (match_operand:SWI248 0 "register_operand" "=r")
 	(clz:SWI248 (match_operand:SWI248 1 "nonimmediate_operand" "rm")))
    (clobber (reg:CC FLAGS_REG))]
-  "TARGET_ABM || TARGET_BMI"
+  "TARGET_LZCNT"
   "lzcnt{<imodesuffix>}\t{%1, %0|%0, %1}"
   [(set_attr "prefix_rep" "1")
    (set_attr "type" "bitmanip")
diff --git a/gcc/config/i386/i386.opt b/gcc/config/i386/i386.opt
index 5e6b5df..f197dd8 100644
--- a/gcc/config/i386/i386.opt
+++ b/gcc/config/i386/i386.opt
@@ -489,6 +489,10 @@ mbmi
 Target Report Mask(ISA_BMI) Var(ix86_isa_flags) Save
 Support BMI built-in functions and code generation
 
+mlzcnt
+Target Report Mask(ISA_LZCNT) Var(ix86_isa_flags) Save
+Support LZCNT built-in function and code generation
+
 mtbm
 Target Report Mask(ISA_TBM) Var(ix86_isa_flags) Save
 Support TBM built-in functions and code generation
diff --git a/gcc/config/i386/x86intrin.h b/gcc/config/i386/x86intrin.h
index 36b43df..0d4211a 100644
--- a/gcc/config/i386/x86intrin.h
+++ b/gcc/config/i386/x86intrin.h
@@ -77,7 +77,7 @@
 #include <lwpintrin.h>
 #endif
 
-#ifdef __ABM__
+#if defined (__ABM__) || defined(__LZCNT__)
 #include <abmintrin.h>
 #endif
 
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index dcbf29f..d705720 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -9673,6 +9673,11 @@ All of them generate the machine instruction that is part of the name.
 @smallexample
 unsigned int __builtin_ia32_bextr_u32(unsigned int, unsigned int);
 unsigned long long __builtin_ia32_bextr_u64 (unsigned long long, unsigned long long);
+@end smallexample
+
+The following built-in functions are available when @option{-mlzcnt} is used.
+All of them generate the machine instruction that is part of the name.
+@smallexample
 unsigned short __builtin_ia32_lzcnt_16(unsigned short);
 unsigned int __builtin_ia32_lzcnt_u32(unsigned int);
 unsigned long long __builtin_ia32_lzcnt_u64 (unsigned long long);
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 7783786..137f256 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -606,8 +606,8 @@ Objective-C and Objective-C++ Dialects}.
 -mcld -mcx16 -msahf -mmovbe -mcrc32 -mrecip -mvzeroupper @gol
 -mmmx  -msse  -msse2 -msse3 -mssse3 -msse4.1 -msse4.2 -msse4 -mavx @gol
 -maes -mpclmul -mfsgsbase -mrdrnd -mf16c -mfma @gol
--msse4a -m3dnow -mpopcnt -mabm -mbmi -mtbm -mfma4 -mxop -mlwp @gol
--mthreads  -mno-align-stringops  -minline-all-stringops @gol
+-msse4a -m3dnow -mpopcnt -mabm -mbmi -mtbm -mfma4 -mxop -mlzcnt @gol
+-mlwp -mthreads  -mno-align-stringops  -minline-all-stringops @gol
 -minline-stringops-dynamically -mstringop-strategy=@var{alg} @gol
 -mpush-args  -maccumulate-outgoing-args  -m128bit-long-double @gol
 -m96bit-long-double  -mregparm=@var{num}  -msseregparm @gol
@@ -12687,6 +12687,8 @@ preferred alignment to @option{-mpreferred-stack-boundary=2}.
 @itemx -mno-abm
 @itemx -mbmi
 @itemx -mno-bmi
+@itemx -mlzcnt
+@itemx -mno-lzcnt
 @itemx -mtbm
 @itemx -mno-tbm
 @opindex mmmx
@@ -12697,7 +12699,7 @@ preferred alignment to @option{-mpreferred-stack-boundary=2}.
 @opindex mno-3dnow
 These switches enable or disable the use of instructions in the MMX, SSE,
 SSE2, SSE3, SSSE3, SSE4.1, AVX, AES, PCLMUL, FSGSBASE, RDRND, F16C, FMA,
-SSE4A, FMA4, XOP, LWP, ABM, BMI, or 3DNow!@: extended instruction sets.
+SSE4A, FMA4, XOP, LWP, ABM, BMI, LZCNT or 3DNow!@: extended instruction sets.
 These extensions are also available as built-in functions: see
 @ref{X86 Built-in Functions}, for details of the functions enabled and
 disabled by these switches.
diff --git a/gcc/testsuite/g++.dg/other/i386-2.C b/gcc/testsuite/g++.dg/other/i386-2.C
index 1a445f1..ed183c7 100644
--- a/gcc/testsuite/g++.dg/other/i386-2.C
+++ b/gcc/testsuite/g++.dg/other/i386-2.C
@@ -1,5 +1,5 @@
 /* { dg-do compile { target i?86-*-* x86_64-*-* } } */
-/* { dg-options "-O -pedantic-errors -march=k8 -msse4a -m3dnow -mavx -mfma4 -mxop -maes -mpclmul -mpopcnt -mabm -mbmi -mtbm -mlwp -mfsgsbase -mrdrnd -mf16c" } */
+/* { dg-options "-O -pedantic-errors -march=k8 -msse4a -m3dnow -mavx -mfma4 -mxop -maes -mpclmul -mpopcnt -mabm -mlzcnt -mbmi -mtbm -mlwp -mfsgsbase -mrdrnd -mf16c" } */
 
 /* Test that {,x,e,p,t,s,w,a,b,i}mmintrin.h, mm3dnow.h, fma4intrin.h,
    xopintrin.h, abmintrin.h, bmiintrin.h, tbmintrin.h, lwpintrin.h,
diff --git a/gcc/testsuite/g++.dg/other/i386-3.C b/gcc/testsuite/g++.dg/other/i386-3.C
index 66eec14..626f972 100644
--- a/gcc/testsuite/g++.dg/other/i386-3.C
+++ b/gcc/testsuite/g++.dg/other/i386-3.C
@@ -1,5 +1,5 @@
 /* { dg-do compile { target i?86-*-* x86_64-*-* } } */
-/* { dg-options "-O -fkeep-inline-functions -march=k8 -msse4a -m3dnow -mavx -mfma4 -mxop -maes -mpclmul -mpopcnt -mabm -mbmi -mtbm -mlwp -mfsgsbase -mrdrnd -mf16c" } */
+/* { dg-options "-O -fkeep-inline-functions -march=k8 -msse4a -m3dnow -mavx -mfma4 -mxop -maes -mpclmul -mpopcnt -mabm -mlzcnt -mbmi -mtbm -mlwp -mfsgsbase -mrdrnd -mf16c" } */
 
 /* Test that {,x,e,p,t,s,w,a,b,i}mmintrin.h, mm3dnow.h, fma4intrin.h,
    xopintrin.h, abmintrin.h, bmiintrin.h, tbmintrin.h, lwpintrin.h,
diff --git a/gcc/testsuite/gcc.target/i386/i386.exp b/gcc/testsuite/gcc.target/i386/i386.exp
index 32dbf5e..8a8fae5 100644
--- a/gcc/testsuite/gcc.target/i386/i386.exp
+++ b/gcc/testsuite/gcc.target/i386/i386.exp
@@ -186,6 +186,16 @@ proc check_effective_target_xop { } {
     } "-O2 -mxop" ]
 }
 
+# Return 1 if lzcnt instruction can be compiled.
+proc check_effective_target_lzcnt { } {
+    return [check_no_compiler_messages avx object {
+	void _lzcnt (void)
+	{
+	   __builtin_clzs (0);
+	}
+    } "-O2 -mlzcnt" ]
+}
+
 # If the linker used understands -M <mapfile>, pass it to clear hardware
 # capabilities set by the Sun assembler.
 set clearcap_ldflags "-Wl,-M,$srcdir/$subdir/clearcap.map"
diff --git a/gcc/testsuite/gcc.target/i386/lzcnt-1.c b/gcc/testsuite/gcc.target/i386/lzcnt-1.c
new file mode 100644
index 0000000..f6240d1b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/lzcnt-1.c
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -mlzcnt " } */
+/* { dg-final { scan-assembler "lzcntw\[^\\n]*(%|)ax" } } */
+
+#include <x86intrin.h>
+
+unsigned int
+func_lzcnt16 (unsigned int X)
+{
+  return __lzcnt16(X);
+}
diff --git a/gcc/testsuite/gcc.target/i386/lzcnt-2.c b/gcc/testsuite/gcc.target/i386/lzcnt-2.c
new file mode 100644
index 0000000..1228499
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/lzcnt-2.c
@@ -0,0 +1,35 @@
+/* { dg-do run { target { lzcnt } } } */
+/* { dg-options "-O2 -mlzcnt -fno-inline" } */
+
+#include <x86intrin.h>
+
+#include "lzcnt-check.h"
+
+short calc_lzcnt_u16 (short src)
+{
+  int i;
+  short res = 0;
+
+  while ( (res<16) && (((src>>(15-res))&1) == 0))
+    ++res;
+
+  return res;
+}
+
+static void
+lzcnt_test ()
+{
+  unsigned i;
+  short src = 0x7ace;
+  short res, res_ref;
+
+  for (i=0; i<5; ++i) {
+    src = src >> i;
+
+    res_ref = calc_lzcnt_u16 (src);
+    res = __lzcnt16 (src);
+
+    if (res != res_ref)
+      abort();
+  }
+}
diff --git a/gcc/testsuite/gcc.target/i386/lzcnt-2a.c b/gcc/testsuite/gcc.target/i386/lzcnt-2a.c
new file mode 100644
index 0000000..fe1069f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/lzcnt-2a.c
@@ -0,0 +1,6 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -mlzcnt" } */
+
+#include "lzcnt-2.c"
+
+/* { dg-final { scan-assembler "lzcntw" } } */
diff --git a/gcc/testsuite/gcc.target/i386/lzcnt-3.c b/gcc/testsuite/gcc.target/i386/lzcnt-3.c
new file mode 100644
index 0000000..1477951
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/lzcnt-3.c
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-options "-O0 -mlzcnt " } */
+/* { dg-final { scan-assembler "lzcntl\[^\\n]*(%|)eax" } } */
+
+#include <x86intrin.h>
+
+unsigned int
+func_lzcnt32 (unsigned int X)
+{
+  return __lzcnt32(X);
+}
diff --git a/gcc/testsuite/gcc.target/i386/lzcnt-4.c b/gcc/testsuite/gcc.target/i386/lzcnt-4.c
new file mode 100644
index 0000000..864c857
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/lzcnt-4.c
@@ -0,0 +1,35 @@
+/* { dg-do run { target { lzcnt } } } */
+/* { dg-options "-O2 -mlzcnt -fno-inline" } */
+
+#include <x86intrin.h>
+
+#include "lzcnt-check.h"
+
+int calc_lzcnt_u32 (int src)
+{
+  int i;
+  int res = 0;
+
+  while ( (res<32) && (((src>>(31-res))&1) == 0))
+    ++res;
+
+  return res;
+}
+
+static void
+lzcnt_test ()
+{
+  unsigned i;
+  int src = 0xce7ace0;
+  int res, res_ref;
+
+  for (i=0; i<5; ++i) {
+    src = src >> i;
+
+    res_ref = calc_lzcnt_u32 (src);
+    res = __lzcnt32 (src);
+
+    if (res != res_ref)
+      abort();
+  }
+}
diff --git a/gcc/testsuite/gcc.target/i386/lzcnt-4a.c b/gcc/testsuite/gcc.target/i386/lzcnt-4a.c
new file mode 100644
index 0000000..6bba6a9
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/lzcnt-4a.c
@@ -0,0 +1,6 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -mlzcnt" } */
+
+#include "lzcnt-4.c"
+
+/* { dg-final { scan-assembler "lzcntl" } } */
diff --git a/gcc/testsuite/gcc.target/i386/lzcnt-5.c b/gcc/testsuite/gcc.target/i386/lzcnt-5.c
new file mode 100644
index 0000000..a4b9aaf
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/lzcnt-5.c
@@ -0,0 +1,11 @@
+/* { dg-do compile { target { ! ia32 } } } */
+/* { dg-options "-O2 -mlzcnt" } */
+/* { dg-final { scan-assembler "lzcntq\[^\\n]*(%|)rax" } } */
+
+#include <x86intrin.h>
+
+unsigned int
+func_lzcnt64 (unsigned long long X)
+{
+  return __lzcnt64(X);
+}
diff --git a/gcc/testsuite/gcc.target/i386/lzcnt-6.c b/gcc/testsuite/gcc.target/i386/lzcnt-6.c
new file mode 100644
index 0000000..e649e63
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/lzcnt-6.c
@@ -0,0 +1,35 @@
+/* { dg-do run { target { lzcnt && { ! ia32 } } } } */
+/* { dg-options "-O2 -mlzcnt -fno-inline" } */
+
+#include <x86intrin.h>
+
+#include "lzcnt-check.h"
+
+long long calc_lzcnt_u64 (long long src)
+{
+  int i;
+  int res = 0;
+
+  while ( (res<64) && (((src>>(63-res))&1) == 0))
+    ++res;
+
+  return res;
+}
+
+static void
+lzcnt_test ()
+{
+  unsigned i;
+  long long src = 0xce7ace0ce7ace0;
+  long long res, res_ref;
+
+  for (i=0; i<5; ++i) {
+    src = src >> i;
+
+    res_ref = calc_lzcnt_u64 (src);
+    res = __lzcnt64 (src);
+
+    if (res != res_ref)
+      abort();
+  }
+}
diff --git a/gcc/testsuite/gcc.target/i386/lzcnt-6a.c b/gcc/testsuite/gcc.target/i386/lzcnt-6a.c
new file mode 100644
index 0000000..2090093
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/lzcnt-6a.c
@@ -0,0 +1,6 @@
+/* { dg-do compile { target { ! ia32 } } } */
+/* { dg-options "-O2 -mlzcnt" } */
+
+#include "lzcnt-6.c"
+
+/* { dg-final { scan-assembler "lzcntq" } } */
diff --git a/gcc/testsuite/gcc.target/i386/lzcnt-check.h b/gcc/testsuite/gcc.target/i386/lzcnt-check.h
new file mode 100644
index 0000000..8aad834
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/lzcnt-check.h
@@ -0,0 +1,37 @@
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "cpuid.h"
+
+static void lzcnt_test (void);
+
+static void
+__attribute__ ((noinline))
+do_test (void)
+{
+  lzcnt_test ();
+}
+
+int
+main ()
+{
+  unsigned int eax, ebx, ecx, edx;
+
+  if (!__get_cpuid (0x80000001, &eax, &ebx, &ecx, &edx))
+    return 0;
+
+  /* Run LZCNT test only if host has LZCNT support.  */
+  if (ecx & bit_LZCNT)
+    {
+      do_test ();
+#ifdef DEBUG
+      printf ("PASSED\n");
+#endif
+    }
+#ifdef DEBUG
+  else
+    printf ("SKIPPED\n");
+#endif
+
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/i386/sse-12.c b/gcc/testsuite/gcc.target/i386/sse-12.c
index 4f8aaec..59e659e 100644
--- a/gcc/testsuite/gcc.target/i386/sse-12.c
+++ b/gcc/testsuite/gcc.target/i386/sse-12.c
@@ -3,7 +3,7 @@
    popcntintrin.h and mm_malloc.h are usable
    with -O -std=c89 -pedantic-errors.  */
 /* { dg-do compile } */
-/* { dg-options "-O -std=c89 -pedantic-errors -march=k8 -msse4a -m3dnow -mavx -mfma4 -mxop -maes -mpclmul -mpopcnt -mabm -mbmi -mtbm -mlwp -mfsgsbase -mrdrnd -mf16c" } */
+/* { dg-options "-O -std=c89 -pedantic-errors -march=k8 -msse4a -m3dnow -mavx -mfma4 -mxop -maes -mpclmul -mpopcnt -mabm -mlzcnt -mbmi -mtbm -mlwp -mfsgsbase -mrdrnd -mf16c" } */
 
 #include <x86intrin.h>
 
diff --git a/gcc/testsuite/gcc.target/i386/sse-13.c b/gcc/testsuite/gcc.target/i386/sse-13.c
index 188b2e6..836272d 100644
--- a/gcc/testsuite/gcc.target/i386/sse-13.c
+++ b/gcc/testsuite/gcc.target/i386/sse-13.c
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O2 -Werror-implicit-function-declaration -march=k8 -msse4a -m3dnow -mavx -mfma4 -mxop -maes -mpclmul -mpopcnt -mabm -mbmi -mtbm -mlwp -mfsgsbase -mrdrnd -mf16c" } */
+/* { dg-options "-O2 -Werror-implicit-function-declaration -march=k8 -msse4a -m3dnow -mavx -mfma4 -mxop -maes -mpclmul -mpopcnt -mabm -mlzcnt -mbmi -mtbm -mlwp -mfsgsbase -mrdrnd -mf16c" } */
 
 #include <mm_malloc.h>
 
diff --git a/gcc/testsuite/gcc.target/i386/sse-14.c b/gcc/testsuite/gcc.target/i386/sse-14.c
index 22ea61f..af42781 100644
--- a/gcc/testsuite/gcc.target/i386/sse-14.c
+++ b/gcc/testsuite/gcc.target/i386/sse-14.c
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O0 -Werror-implicit-function-declaration -march=k8 -msse4a -m3dnow -mavx -mfma4 -mxop -maes -mpclmul -mpopcnt -mabm -mbmi -mtbm -mlwp -mfsgsbase -mrdrnd -mf16c" } */
+/* { dg-options "-O0 -Werror-implicit-function-declaration -march=k8 -msse4a -m3dnow -mavx -mfma4 -mxop -maes -mpclmul -mpopcnt -mabm -mlzcnt -mbmi -mtbm -mlwp -mfsgsbase -mrdrnd -mf16c" } */
 
 #include <mm_malloc.h>
 

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [Patch, i386, testsuite] Fix for PR49547, new tescases for lzcnt instruction
  2011-07-27 11:16         ` Kirill Yukhin
@ 2011-07-27 11:58           ` Uros Bizjak
  2011-07-27 14:27             ` Kirill Yukhin
  0 siblings, 1 reply; 25+ messages in thread
From: Uros Bizjak @ 2011-07-27 11:58 UTC (permalink / raw)
  To: Kirill Yukhin; +Cc: Mike Stump, gcc-patches List, H.J. Lu, Jagasia, Harsha

On Wed, Jul 27, 2011 at 12:56 PM, Kirill Yukhin <kirill.yukhin@gmail.com> wrote:
> Sorry, for misunderstanding I've introduced with error in my comment.
> Your inputs are fixed. Since they don't touch sources, just testsuite,
> I am posting only tesuite/ChangeLog updated entry.

> tesuite/ChangeLog entry:
> 2011-07-27  Kirill Yukhin  <kirill.yukhin@intel.com>
>
>        * gcc.target/i386/i386.exp (check_effective_target_lzcnt): New.
>        * gcc.target/i386/lzcnt-1.c: New test.
>        * gcc.target/i386/lzcnt-2.c: Likewise.
>        * gcc.target/i386/lzcnt-2a.c: Likewise.
>        * gcc.target/i386/lzcnt-3.c: New test.
>        * gcc.target/i386/lzcnt-4.c: Likewise.
>        * gcc.target/i386/lzcnt-4a.c: Likewise.
>        * gcc.target/i386/lzcnt-5.c: Likewise.
>        * gcc.target/i386/lzcnt-6.c: Likewise.
>        * gcc.target/i386/lzcnt-6a.c: Likewise.
>        * gcc.target/i386/lzcnt-check.h: New driver to run LZCNT-*
>        tests only if HW available.

New.

>        * gcc.target/i386/sse-12.c: Added -mlzcnt switch.

* gcc.target/i386/sse-12.c (dg-compile): Add -mlzcnt.

>        * gcc.target/i386/sse-13.c: Likewise.
>        * gcc.target/i386/sse-14.c: Likewise.
>        * g++.dg/other/i386-2.C: Likewise.
>        * g++.dg/other/i386-3.C: Likewise.
>
>
> Patch attached.

Patch also includes non-testsuite changes, please update ChangeLog
entry as follows:

> 2011-07-26  Kirill Yukhin  <kirill.yukhin@intel.com>
>
>        PR target/49547
>       * config/i386/abmintrin.h (head): Added check if __LZCNT__ is defined.

Check if __LZCNT__ is defined.

>       (__lzcnt32): Fixed name according to Spec.

Rename to ...

>       * config/i386/bmiintrin.h (head): Updated year for Copyright.

Update copyright year.

>       (__lzcnt_u16): Removed.
>       (__lzcnt_u32): Removed.
>       (__lzcnt_u64): Likewise.
>       * config/i386/cpuid.h: New bit defined.

* config/i386/cpuid.h (__bit_LZCNT): New define.

>       * config/i386/driver-i386.c (host_detect_local_cpu): Detect
>       LZCNT feature.
>       * config/i386/i386-c.c (ix86_target_macros_internal): Define
>       __LZCNT__ if needed.
>       * config/i386/i386.c (ix86_target_string): New entry to array.

New option -mlzcnt.

>       (ix86_option_override_internal): Handling LZCNT option.

Handle ...

>       (ix86_valid_target_attribute_inner_p): Likewise.
>       (bdesc_args): built-in for LZCNT is extended to work under
>       another flag.

(struct builtin_description bdesc_args) <IX86_BUILTIN_CLZS>: Update.

>       * config/i386/i386.h (TARGET_LZCNT): New.
>       (CLZ_DEFINED_VALUE_AT_ZERO): Updated flag name.

... : Update.

>       * config/i386/i386.md (clz<mode>2): Target fixed.

... : Update insn constraint.

>       (clz<mode>2_lzcnt): Likewise.
>       * doc/invoke.texi: Added mention of -mlzcnt option.

Mention  -mlzcnt option.

>       * doc/extend.texi: Likewise.

> Changes were bootstrapped and make-check-ed (lzcnt ones under simulator).
> Is it OK for now?

Testsuite changes are OK, with a few nits, see below. The patch is OK
in principle, but since it touches public header, we need also OK from
AMD (CC'd).

+++ b/gcc/testsuite/gcc.target/i386/lzcnt-2.c
+  while ( (res<16) && (((src>>(15-res))&1) == 0))

Please watch whitespace.

+++ b/gcc/testsuite/gcc.target/i386/lzcnt-4.c
+  while ( (res<32) && (((src>>(31-res))&1) == 0))

Same here.

+++ b/gcc/testsuite/gcc.target/i386/lzcnt-6.c
+  while ( (res<64) && (((src>>(63-res))&1) == 0))

And here.

Uros.

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [Patch, i386, testsuite] Fix for PR49547, new tescases for lzcnt instruction
  2011-07-27 11:58           ` Uros Bizjak
@ 2011-07-27 14:27             ` Kirill Yukhin
  2011-07-27 14:42               ` H.J. Lu
  0 siblings, 1 reply; 25+ messages in thread
From: Kirill Yukhin @ 2011-07-27 14:27 UTC (permalink / raw)
  To: Uros Bizjak; +Cc: Mike Stump, gcc-patches List, H.J. Lu, Jagasia, Harsha

[-- Attachment #1: Type: text/plain, Size: 5785 bytes --]

Okay,
Uros, thanks for correcting me. Here is updated Changelogs and patch.

ChangeLog entry:
2011-07-27  Kirill Yukhin  <kirill.yukhin@intel.com>

	PR target/49547
	* config/i386/abmintrin.h (head): Check if __LZCNT__ is defined.
	(__lzcnt): Rename to ...
	(__lzcnt32): ... this.
	* config/i386/bmiintrin.h (head): Update copyright year.
	(__lzcnt_u16): Removed.
	(__lzcnt_u32): Removed.
	(__lzcnt_u64): Likewise.
	* config/i386/cpuid.h: New define.
	* config/i386/driver-i386.c (host_detect_local_cpu): Detect
	LZCNT feature.
	* config/i386/i386-c.c (ix86_target_macros_internal): Define
	__LZCNT__ if needed.
	* config/i386/i386.c (ix86_target_string): New option -mlzcnt.
	(ix86_option_override_internal): Handle LZCNT option.
	(ix86_valid_target_attribute_inner_p): Likewise.
	(struct builtin_description bdesc_args) <IX86_BUILTIN_CLZS>: Update.
	* config/i386/i386.h (TARGET_LZCNT): New.
	(CLZ_DEFINED_VALUE_AT_ZERO): Update.
	* config/i386/i386.md (clz<mode>2): Update insn constraint.
	(clz<mode>2_lzcnt): Likewise.
	* doc/invoke.texi: Mention -mlzcnt option.
	* doc/extend.texi: Likewise.

testsuite/ChangeLog entry:
2011-07-27  Kirill Yukhin  <kirill.yukhin@intel.com>

	* gcc.target/i386/i386.exp (check_effective_target_lzcnt): New.
	* gcc.target/i386/lzcnt-1.c: New test.
	* gcc.target/i386/lzcnt-2.c: Likewise.
	* gcc.target/i386/lzcnt-2a.c: Likewise.
	* gcc.target/i386/lzcnt-3.c: Likewise.
	* gcc.target/i386/lzcnt-4.c: Likewise.
	* gcc.target/i386/lzcnt-4a.c: Likewise.
	* gcc.target/i386/lzcnt-5.c: Likewise.
	* gcc.target/i386/lzcnt-6.c: Likewise.
	* gcc.target/i386/lzcnt-6a.c: Likewise.
	* gcc.target/i386/lzcnt-check.h: Likewise.
	* gcc.target/i386/sse-12.c (dg-compile): Add -mlzcnt.
	* gcc.target/i386/sse-13.c: Likewise.
	* gcc.target/i386/sse-14.c: Likewise.
	* g++.dg/other/i386-2.C: Likewise.
	* g++.dg/other/i386-3.C: Likewise.

Harsha, is it OK for trunk?

Thanks, K


On Wed, Jul 27, 2011 at 3:23 PM, Uros Bizjak <ubizjak@gmail.com> wrote:
> On Wed, Jul 27, 2011 at 12:56 PM, Kirill Yukhin <kirill.yukhin@gmail.com> wrote:
>> Sorry, for misunderstanding I've introduced with error in my comment.
>> Your inputs are fixed. Since they don't touch sources, just testsuite,
>> I am posting only tesuite/ChangeLog updated entry.
>
>> tesuite/ChangeLog entry:
>> 2011-07-27  Kirill Yukhin  <kirill.yukhin@intel.com>
>>
>>        * gcc.target/i386/i386.exp (check_effective_target_lzcnt): New.
>>        * gcc.target/i386/lzcnt-1.c: New test.
>>        * gcc.target/i386/lzcnt-2.c: Likewise.
>>        * gcc.target/i386/lzcnt-2a.c: Likewise.
>>        * gcc.target/i386/lzcnt-3.c: New test.
>>        * gcc.target/i386/lzcnt-4.c: Likewise.
>>        * gcc.target/i386/lzcnt-4a.c: Likewise.
>>        * gcc.target/i386/lzcnt-5.c: Likewise.
>>        * gcc.target/i386/lzcnt-6.c: Likewise.
>>        * gcc.target/i386/lzcnt-6a.c: Likewise.
>>        * gcc.target/i386/lzcnt-check.h: New driver to run LZCNT-*
>>        tests only if HW available.
>
> New.
>
>>        * gcc.target/i386/sse-12.c: Added -mlzcnt switch.
>
> * gcc.target/i386/sse-12.c (dg-compile): Add -mlzcnt.
>
>>        * gcc.target/i386/sse-13.c: Likewise.
>>        * gcc.target/i386/sse-14.c: Likewise.
>>        * g++.dg/other/i386-2.C: Likewise.
>>        * g++.dg/other/i386-3.C: Likewise.
>>
>>
>> Patch attached.
>
> Patch also includes non-testsuite changes, please update ChangeLog
> entry as follows:
>
>> 2011-07-26  Kirill Yukhin  <kirill.yukhin@intel.com>
>>
>>        PR target/49547
>>       * config/i386/abmintrin.h (head): Added check if __LZCNT__ is defined.
>
> Check if __LZCNT__ is defined.
>
>>       (__lzcnt32): Fixed name according to Spec.
>
> Rename to ...
>
>>       * config/i386/bmiintrin.h (head): Updated year for Copyright.
>
> Update copyright year.
>
>>       (__lzcnt_u16): Removed.
>>       (__lzcnt_u32): Removed.
>>       (__lzcnt_u64): Likewise.
>>       * config/i386/cpuid.h: New bit defined.
>
> * config/i386/cpuid.h (__bit_LZCNT): New define.
>
>>       * config/i386/driver-i386.c (host_detect_local_cpu): Detect
>>       LZCNT feature.
>>       * config/i386/i386-c.c (ix86_target_macros_internal): Define
>>       __LZCNT__ if needed.
>>       * config/i386/i386.c (ix86_target_string): New entry to array.
>
> New option -mlzcnt.
>
>>       (ix86_option_override_internal): Handling LZCNT option.
>
> Handle ...
>
>>       (ix86_valid_target_attribute_inner_p): Likewise.
>>       (bdesc_args): built-in for LZCNT is extended to work under
>>       another flag.
>
> (struct builtin_description bdesc_args) <IX86_BUILTIN_CLZS>: Update.
>
>>       * config/i386/i386.h (TARGET_LZCNT): New.
>>       (CLZ_DEFINED_VALUE_AT_ZERO): Updated flag name.
>
> ... : Update.
>
>>       * config/i386/i386.md (clz<mode>2): Target fixed.
>
> ... : Update insn constraint.
>
>>       (clz<mode>2_lzcnt): Likewise.
>>       * doc/invoke.texi: Added mention of -mlzcnt option.
>
> Mention  -mlzcnt option.
>
>>       * doc/extend.texi: Likewise.
>
>> Changes were bootstrapped and make-check-ed (lzcnt ones under simulator).
>> Is it OK for now?
>
> Testsuite changes are OK, with a few nits, see below. The patch is OK
> in principle, but since it touches public header, we need also OK from
> AMD (CC'd).
>
> +++ b/gcc/testsuite/gcc.target/i386/lzcnt-2.c
> +  while ( (res<16) && (((src>>(15-res))&1) == 0))
>
> Please watch whitespace.
>
> +++ b/gcc/testsuite/gcc.target/i386/lzcnt-4.c
> +  while ( (res<32) && (((src>>(31-res))&1) == 0))
>
> Same here.
>
> +++ b/gcc/testsuite/gcc.target/i386/lzcnt-6.c
> +  while ( (res<64) && (((src>>(63-res))&1) == 0))
>
> And here.
>
> Uros.
>

[-- Attachment #2: lzcnt-3.gcc.patch --]
[-- Type: application/octet-stream, Size: 22447 bytes --]

diff --git a/gcc/config/i386/abmintrin.h b/gcc/config/i386/abmintrin.h
index 9d87f57..2b5f56b 100644
--- a/gcc/config/i386/abmintrin.h
+++ b/gcc/config/i386/abmintrin.h
@@ -25,8 +25,8 @@
 # error "Never use <abmintrin.h> directly; include <x86intrin.h> instead."
 #endif
 
-#ifndef __ABM__
-# error "ABM instruction set not enabled"
+#if !defined (__ABM__) && !defined(__LZCNT__)
+# error "ABM (LZCNT) instruction set not enabled"
 #endif /* __ABM__ */
 
 #ifndef _ABMINTRIN_H_INCLUDED
@@ -39,7 +39,7 @@ __lzcnt16 (unsigned short __X)
 }
 
 extern __inline unsigned int __attribute__((__gnu_inline__, __always_inline__, __artificial__))
-__lzcnt (unsigned int __X)
+__lzcnt32 (unsigned int __X)
 {
   return __builtin_clz (__X);
 }
diff --git a/gcc/config/i386/bmiintrin.h b/gcc/config/i386/bmiintrin.h
index 225f2ec..1699c61 100644
--- a/gcc/config/i386/bmiintrin.h
+++ b/gcc/config/i386/bmiintrin.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2010 Free Software Foundation, Inc.
+/* Copyright (C) 2010, 2011 Free Software Foundation, Inc.
 
    This file is part of GCC.
 
@@ -33,12 +33,6 @@
 #define _BMIINTRIN_H_INCLUDED
 
 extern __inline unsigned short __attribute__((__gnu_inline__, __always_inline__, __artificial__))
-__lzcnt_u16 (unsigned short __X)
-{
-  return __builtin_clzs (__X);
-}
-
-extern __inline unsigned short __attribute__((__gnu_inline__, __always_inline__, __artificial__))
 __tzcnt_u16 (unsigned short __X)
 {
   return __builtin_ctzs (__X);
@@ -79,12 +73,6 @@ __blsr_u32 (unsigned int __X)
   return tmp;
 }
 
-extern __inline unsigned int __attribute__((__gnu_inline__, __always_inline__, __artificial__))
-__lzcnt_u32 (unsigned int __X)
-{
-  return __builtin_clz (__X);
-}
-
 
 extern __inline unsigned int __attribute__((__gnu_inline__, __always_inline__, __artificial__))
 __tzcnt_u32 (unsigned int __X)
@@ -129,12 +117,6 @@ __blsr_u64 (unsigned long long __X)
 }
 
 extern __inline unsigned long long __attribute__((__gnu_inline__, __always_inline__, __artificial__))
-__lzcnt_u64 (unsigned long long __X)
-{
-  return __builtin_clzll (__X);
-}
-
-extern __inline unsigned long long __attribute__((__gnu_inline__, __always_inline__, __artificial__))
 __tzcnt_u64 (unsigned long long __X)
 {
   return __builtin_ctzll (__X);
diff --git a/gcc/config/i386/cpuid.h b/gcc/config/i386/cpuid.h
index 3c3f47b..8826c28 100644
--- a/gcc/config/i386/cpuid.h
+++ b/gcc/config/i386/cpuid.h
@@ -24,6 +24,7 @@
 /* %ecx */
 #define bit_SSE3	(1 << 0)
 #define bit_PCLMUL	(1 << 1)
+#define bit_LZCNT	(1 << 5)
 #define bit_SSSE3	(1 << 9)
 #define bit_FMA		(1 << 12)
 #define bit_CMPXCHG16B	(1 << 13)
diff --git a/gcc/config/i386/driver-i386.c b/gcc/config/i386/driver-i386.c
index ecd8958..5823987 100644
--- a/gcc/config/i386/driver-i386.c
+++ b/gcc/config/i386/driver-i386.c
@@ -396,7 +396,7 @@ const char *host_detect_local_cpu (int argc, const char **argv)
   unsigned int has_popcnt = 0, has_aes = 0, has_avx = 0;
   unsigned int has_pclmul = 0, has_abm = 0, has_lwp = 0;
   unsigned int has_fma = 0, has_fma4 = 0, has_xop = 0;
-  unsigned int has_bmi = 0, has_tbm = 0;
+  unsigned int has_bmi = 0, has_tbm = 0, has_lzcnt = 0;
 
   bool arch;
 
@@ -465,6 +465,7 @@ const char *host_detect_local_cpu (int argc, const char **argv)
       has_fma4 = ecx & bit_FMA4;
       has_xop = ecx & bit_XOP;
       has_tbm = ecx & bit_TBM;
+      has_lzcnt = ecx & bit_LZCNT;
 
       has_longmode = edx & bit_LM;
       has_3dnowp = edx & bit_3DNOWP;
@@ -717,10 +718,11 @@ const char *host_detect_local_cpu (int argc, const char **argv)
       const char *avx = has_avx ? " -mavx" : " -mno-avx";
       const char *sse4_2 = has_sse4_2 ? " -msse4.2" : " -mno-sse4.2";
       const char *sse4_1 = has_sse4_1 ? " -msse4.1" : " -mno-sse4.1";
+      const char *lzcnt = has_lzcnt ? " -mlzcnt" : " -mnolzcnt";
 
       options = concat (options, cx16, sahf, movbe, ase, pclmul,
 			popcnt, abm, lwp, fma, fma4, xop, bmi, tbm,
-			avx, sse4_2, sse4_1, NULL);
+			avx, sse4_2, sse4_1, lzcnt, NULL);
     }
 
 done:
diff --git a/gcc/config/i386/i386-c.c b/gcc/config/i386/i386-c.c
index 5cbcfd5..1fc333c 100644
--- a/gcc/config/i386/i386-c.c
+++ b/gcc/config/i386/i386-c.c
@@ -271,6 +271,8 @@ ix86_target_macros_internal (int isa_flag,
     def_or_undef (parse_in, "__ABM__");
   if (isa_flag & OPTION_MASK_ISA_BMI)
     def_or_undef (parse_in, "__BMI__");
+  if (isa_flag & OPTION_MASK_ISA_LZCNT)
+    def_or_undef (parse_in, "__LZCNT__");
   if (isa_flag & OPTION_MASK_ISA_TBM)
     def_or_undef (parse_in, "__TBM__");
   if (isa_flag & OPTION_MASK_ISA_POPCNT)
diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
index 960622a..019184b 100644
--- a/gcc/config/i386/i386.c
+++ b/gcc/config/i386/i386.c
@@ -2663,6 +2663,7 @@ ix86_target_string (int isa, int flags, const char *arch, const char *tune,
     { "-mmmx",		OPTION_MASK_ISA_MMX },
     { "-mabm",		OPTION_MASK_ISA_ABM },
     { "-mbmi",		OPTION_MASK_ISA_BMI },
+    { "-mlzcnt",	OPTION_MASK_ISA_LZCNT },
     { "-mtbm",		OPTION_MASK_ISA_TBM },
     { "-mpopcnt",	OPTION_MASK_ISA_POPCNT },
     { "-mmovbe",	OPTION_MASK_ISA_MOVBE },
@@ -2917,7 +2918,8 @@ ix86_option_override_internal (bool main_args_p)
       PTA_RDRND = 1 << 25,
       PTA_F16C = 1 << 26,
       PTA_BMI = 1 << 27,
-      PTA_TBM = 1 << 28
+      PTA_TBM = 1 << 28,
+      PTA_LZCNT = 1 << 29
       /* if this reaches 32, need to widen struct pta flags below */
     };
 
@@ -3281,6 +3283,9 @@ ix86_option_override_internal (bool main_args_p)
 	if (processor_alias_table[i].flags & PTA_BMI
 	    && !(ix86_isa_flags_explicit & OPTION_MASK_ISA_BMI))
 	  ix86_isa_flags |= OPTION_MASK_ISA_BMI;
+	if (processor_alias_table[i].flags & (PTA_LZCNT | PTA_ABM)
+	    && !(ix86_isa_flags_explicit & OPTION_MASK_ISA_LZCNT))
+	  ix86_isa_flags |= OPTION_MASK_ISA_LZCNT;
 	if (processor_alias_table[i].flags & PTA_TBM
 	    && !(ix86_isa_flags_explicit & OPTION_MASK_ISA_TBM))
 	  ix86_isa_flags |= OPTION_MASK_ISA_TBM;
@@ -3528,6 +3533,10 @@ ix86_option_override_internal (bool main_args_p)
   if (TARGET_SSE4_2 || TARGET_ABM)
     ix86_isa_flags |= OPTION_MASK_ISA_POPCNT & ~ix86_isa_flags_explicit;
 
+  /* Turn on lzcnt instruction for -mabm.  */
+  if (TARGET_ABM)
+    ix86_isa_flags |= OPTION_MASK_ISA_LZCNT & ~ix86_isa_flags_explicit;
+
   /* Validate -mpreferred-stack-boundary= value or default it to
      PREFERRED_STACK_BOUNDARY_DEFAULT.  */
   ix86_preferred_stack_boundary = PREFERRED_STACK_BOUNDARY_DEFAULT;
@@ -4033,6 +4042,7 @@ ix86_valid_target_attribute_inner_p (tree args, char *p_strings[],
     IX86_ATTR_ISA ("3dnow",	OPT_m3dnow),
     IX86_ATTR_ISA ("abm",	OPT_mabm),
     IX86_ATTR_ISA ("bmi",	OPT_mbmi),
+    IX86_ATTR_ISA ("lzcnt",	OPT_mlzcnt),
     IX86_ATTR_ISA ("tbm",	OPT_mtbm),
     IX86_ATTR_ISA ("aes",	OPT_maes),
     IX86_ATTR_ISA ("avx",	OPT_mavx),
@@ -24945,7 +24955,7 @@ static const struct builtin_description bdesc_args[] =
   { OPTION_MASK_ISA_AVX, CODE_FOR_copysignv8sf3,  "__builtin_ia32_copysignps256", IX86_BUILTIN_CPYSGNPS256, UNKNOWN, (int) V8SF_FTYPE_V8SF_V8SF },
   { OPTION_MASK_ISA_AVX, CODE_FOR_copysignv4df3,  "__builtin_ia32_copysignpd256", IX86_BUILTIN_CPYSGNPD256, UNKNOWN, (int) V4DF_FTYPE_V4DF_V4DF },
 
-  { OPTION_MASK_ISA_ABM, CODE_FOR_clzhi2_abm,   "__builtin_clzs",   IX86_BUILTIN_CLZS,    UNKNOWN,     (int) UINT16_FTYPE_UINT16 },
+  { OPTION_MASK_ISA_ABM | OPTION_MASK_ISA_LZCNT, CODE_FOR_clzhi2_lzcnt,   "__builtin_clzs",   IX86_BUILTIN_CLZS,    UNKNOWN,     (int) UINT16_FTYPE_UINT16 },
 
   /* BMI */
   { OPTION_MASK_ISA_BMI, CODE_FOR_bmi_bextr_si, "__builtin_ia32_bextr_u32", IX86_BUILTIN_BEXTR32, UNKNOWN, (int) UINT_FTYPE_UINT_UINT },
diff --git a/gcc/config/i386/i386.h b/gcc/config/i386/i386.h
index 20c9a8f..f43586d 100644
--- a/gcc/config/i386/i386.h
+++ b/gcc/config/i386/i386.h
@@ -61,6 +61,7 @@ see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
 #define TARGET_ROUND	OPTION_ISA_ROUND
 #define TARGET_ABM	OPTION_ISA_ABM
 #define TARGET_BMI	OPTION_ISA_BMI
+#define TARGET_LZCNT	OPTION_ISA_LZCNT
 #define TARGET_TBM	OPTION_ISA_TBM
 #define TARGET_POPCNT	OPTION_ISA_POPCNT
 #define TARGET_SAHF	OPTION_ISA_SAHF
@@ -2288,7 +2289,7 @@ extern void debug_dispatch_window (int);
 #define CTZ_DEFINED_VALUE_AT_ZERO(MODE, VALUE) \
 	((VALUE) = GET_MODE_BITSIZE (MODE), TARGET_BMI)
 #define CLZ_DEFINED_VALUE_AT_ZERO(MODE, VALUE) \
-	((VALUE) = GET_MODE_BITSIZE (MODE), TARGET_BMI)
+	((VALUE) = GET_MODE_BITSIZE (MODE), TARGET_LZCNT)
 
 
 /* Flags returned by ix86_get_callcvt ().  */
diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md
index e91a299..f1efade 100644
--- a/gcc/config/i386/i386.md
+++ b/gcc/config/i386/i386.md
@@ -11801,19 +11801,19 @@
       (clobber (reg:CC FLAGS_REG))])]
   ""
 {
-  if (TARGET_ABM)
+  if (TARGET_LZCNT)
     {
-      emit_insn (gen_clz<mode>2_abm (operands[0], operands[1]));
+      emit_insn (gen_clz<mode>2_lzcnt (operands[0], operands[1]));
       DONE;
     }
   operands[2] = GEN_INT (GET_MODE_BITSIZE (<MODE>mode)-1);
 })
 
-(define_insn "clz<mode>2_abm"
+(define_insn "clz<mode>2_lzcnt"
   [(set (match_operand:SWI248 0 "register_operand" "=r")
 	(clz:SWI248 (match_operand:SWI248 1 "nonimmediate_operand" "rm")))
    (clobber (reg:CC FLAGS_REG))]
-  "TARGET_ABM || TARGET_BMI"
+  "TARGET_LZCNT"
   "lzcnt{<imodesuffix>}\t{%1, %0|%0, %1}"
   [(set_attr "prefix_rep" "1")
    (set_attr "type" "bitmanip")
diff --git a/gcc/config/i386/i386.opt b/gcc/config/i386/i386.opt
index 5e6b5df..f197dd8 100644
--- a/gcc/config/i386/i386.opt
+++ b/gcc/config/i386/i386.opt
@@ -489,6 +489,10 @@ mbmi
 Target Report Mask(ISA_BMI) Var(ix86_isa_flags) Save
 Support BMI built-in functions and code generation
 
+mlzcnt
+Target Report Mask(ISA_LZCNT) Var(ix86_isa_flags) Save
+Support LZCNT built-in function and code generation
+
 mtbm
 Target Report Mask(ISA_TBM) Var(ix86_isa_flags) Save
 Support TBM built-in functions and code generation
diff --git a/gcc/config/i386/x86intrin.h b/gcc/config/i386/x86intrin.h
index 36b43df..0d4211a 100644
--- a/gcc/config/i386/x86intrin.h
+++ b/gcc/config/i386/x86intrin.h
@@ -77,7 +77,7 @@
 #include <lwpintrin.h>
 #endif
 
-#ifdef __ABM__
+#if defined (__ABM__) || defined(__LZCNT__)
 #include <abmintrin.h>
 #endif
 
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index dcbf29f..d705720 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -9673,6 +9673,11 @@ All of them generate the machine instruction that is part of the name.
 @smallexample
 unsigned int __builtin_ia32_bextr_u32(unsigned int, unsigned int);
 unsigned long long __builtin_ia32_bextr_u64 (unsigned long long, unsigned long long);
+@end smallexample
+
+The following built-in functions are available when @option{-mlzcnt} is used.
+All of them generate the machine instruction that is part of the name.
+@smallexample
 unsigned short __builtin_ia32_lzcnt_16(unsigned short);
 unsigned int __builtin_ia32_lzcnt_u32(unsigned int);
 unsigned long long __builtin_ia32_lzcnt_u64 (unsigned long long);
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 7783786..137f256 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -606,8 +606,8 @@ Objective-C and Objective-C++ Dialects}.
 -mcld -mcx16 -msahf -mmovbe -mcrc32 -mrecip -mvzeroupper @gol
 -mmmx  -msse  -msse2 -msse3 -mssse3 -msse4.1 -msse4.2 -msse4 -mavx @gol
 -maes -mpclmul -mfsgsbase -mrdrnd -mf16c -mfma @gol
--msse4a -m3dnow -mpopcnt -mabm -mbmi -mtbm -mfma4 -mxop -mlwp @gol
--mthreads  -mno-align-stringops  -minline-all-stringops @gol
+-msse4a -m3dnow -mpopcnt -mabm -mbmi -mtbm -mfma4 -mxop -mlzcnt @gol
+-mlwp -mthreads  -mno-align-stringops  -minline-all-stringops @gol
 -minline-stringops-dynamically -mstringop-strategy=@var{alg} @gol
 -mpush-args  -maccumulate-outgoing-args  -m128bit-long-double @gol
 -m96bit-long-double  -mregparm=@var{num}  -msseregparm @gol
@@ -12687,6 +12687,8 @@ preferred alignment to @option{-mpreferred-stack-boundary=2}.
 @itemx -mno-abm
 @itemx -mbmi
 @itemx -mno-bmi
+@itemx -mlzcnt
+@itemx -mno-lzcnt
 @itemx -mtbm
 @itemx -mno-tbm
 @opindex mmmx
@@ -12697,7 +12699,7 @@ preferred alignment to @option{-mpreferred-stack-boundary=2}.
 @opindex mno-3dnow
 These switches enable or disable the use of instructions in the MMX, SSE,
 SSE2, SSE3, SSSE3, SSE4.1, AVX, AES, PCLMUL, FSGSBASE, RDRND, F16C, FMA,
-SSE4A, FMA4, XOP, LWP, ABM, BMI, or 3DNow!@: extended instruction sets.
+SSE4A, FMA4, XOP, LWP, ABM, BMI, LZCNT or 3DNow!@: extended instruction sets.
 These extensions are also available as built-in functions: see
 @ref{X86 Built-in Functions}, for details of the functions enabled and
 disabled by these switches.
diff --git a/gcc/testsuite/g++.dg/other/i386-2.C b/gcc/testsuite/g++.dg/other/i386-2.C
index 1a445f1..ed183c7 100644
--- a/gcc/testsuite/g++.dg/other/i386-2.C
+++ b/gcc/testsuite/g++.dg/other/i386-2.C
@@ -1,5 +1,5 @@
 /* { dg-do compile { target i?86-*-* x86_64-*-* } } */
-/* { dg-options "-O -pedantic-errors -march=k8 -msse4a -m3dnow -mavx -mfma4 -mxop -maes -mpclmul -mpopcnt -mabm -mbmi -mtbm -mlwp -mfsgsbase -mrdrnd -mf16c" } */
+/* { dg-options "-O -pedantic-errors -march=k8 -msse4a -m3dnow -mavx -mfma4 -mxop -maes -mpclmul -mpopcnt -mabm -mlzcnt -mbmi -mtbm -mlwp -mfsgsbase -mrdrnd -mf16c" } */
 
 /* Test that {,x,e,p,t,s,w,a,b,i}mmintrin.h, mm3dnow.h, fma4intrin.h,
    xopintrin.h, abmintrin.h, bmiintrin.h, tbmintrin.h, lwpintrin.h,
diff --git a/gcc/testsuite/g++.dg/other/i386-3.C b/gcc/testsuite/g++.dg/other/i386-3.C
index 66eec14..626f972 100644
--- a/gcc/testsuite/g++.dg/other/i386-3.C
+++ b/gcc/testsuite/g++.dg/other/i386-3.C
@@ -1,5 +1,5 @@
 /* { dg-do compile { target i?86-*-* x86_64-*-* } } */
-/* { dg-options "-O -fkeep-inline-functions -march=k8 -msse4a -m3dnow -mavx -mfma4 -mxop -maes -mpclmul -mpopcnt -mabm -mbmi -mtbm -mlwp -mfsgsbase -mrdrnd -mf16c" } */
+/* { dg-options "-O -fkeep-inline-functions -march=k8 -msse4a -m3dnow -mavx -mfma4 -mxop -maes -mpclmul -mpopcnt -mabm -mlzcnt -mbmi -mtbm -mlwp -mfsgsbase -mrdrnd -mf16c" } */
 
 /* Test that {,x,e,p,t,s,w,a,b,i}mmintrin.h, mm3dnow.h, fma4intrin.h,
    xopintrin.h, abmintrin.h, bmiintrin.h, tbmintrin.h, lwpintrin.h,
diff --git a/gcc/testsuite/gcc.target/i386/i386.exp b/gcc/testsuite/gcc.target/i386/i386.exp
index 32dbf5e..8a8fae5 100644
--- a/gcc/testsuite/gcc.target/i386/i386.exp
+++ b/gcc/testsuite/gcc.target/i386/i386.exp
@@ -186,6 +186,16 @@ proc check_effective_target_xop { } {
     } "-O2 -mxop" ]
 }
 
+# Return 1 if lzcnt instruction can be compiled.
+proc check_effective_target_lzcnt { } {
+    return [check_no_compiler_messages avx object {
+	void _lzcnt (void)
+	{
+	   __builtin_clzs (0);
+	}
+    } "-O2 -mlzcnt" ]
+}
+
 # If the linker used understands -M <mapfile>, pass it to clear hardware
 # capabilities set by the Sun assembler.
 set clearcap_ldflags "-Wl,-M,$srcdir/$subdir/clearcap.map"
diff --git a/gcc/testsuite/gcc.target/i386/lzcnt-1.c b/gcc/testsuite/gcc.target/i386/lzcnt-1.c
new file mode 100644
index 0000000..f6240d1b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/lzcnt-1.c
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -mlzcnt " } */
+/* { dg-final { scan-assembler "lzcntw\[^\\n]*(%|)ax" } } */
+
+#include <x86intrin.h>
+
+unsigned int
+func_lzcnt16 (unsigned int X)
+{
+  return __lzcnt16(X);
+}
diff --git a/gcc/testsuite/gcc.target/i386/lzcnt-2.c b/gcc/testsuite/gcc.target/i386/lzcnt-2.c
new file mode 100644
index 0000000..329a11f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/lzcnt-2.c
@@ -0,0 +1,35 @@
+/* { dg-do run { target { lzcnt } } } */
+/* { dg-options "-O2 -mlzcnt -fno-inline" } */
+
+#include <x86intrin.h>
+
+#include "lzcnt-check.h"
+
+short calc_lzcnt_u16 (short src)
+{
+  int i;
+  short res = 0;
+
+  while ((res < 16) && (((src >> (15 - res)) & 1) == 0))
+    ++res;
+
+  return res;
+}
+
+static void
+lzcnt_test ()
+{
+  unsigned i;
+  short src = 0x7ace;
+  short res, res_ref;
+
+  for (i=0; i<5; ++i) {
+    src = src >> i;
+
+    res_ref = calc_lzcnt_u16 (src);
+    res = __lzcnt16 (src);
+
+    if (res != res_ref)
+      abort();
+  }
+}
diff --git a/gcc/testsuite/gcc.target/i386/lzcnt-2a.c b/gcc/testsuite/gcc.target/i386/lzcnt-2a.c
new file mode 100644
index 0000000..fe1069f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/lzcnt-2a.c
@@ -0,0 +1,6 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -mlzcnt" } */
+
+#include "lzcnt-2.c"
+
+/* { dg-final { scan-assembler "lzcntw" } } */
diff --git a/gcc/testsuite/gcc.target/i386/lzcnt-3.c b/gcc/testsuite/gcc.target/i386/lzcnt-3.c
new file mode 100644
index 0000000..1477951
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/lzcnt-3.c
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-options "-O0 -mlzcnt " } */
+/* { dg-final { scan-assembler "lzcntl\[^\\n]*(%|)eax" } } */
+
+#include <x86intrin.h>
+
+unsigned int
+func_lzcnt32 (unsigned int X)
+{
+  return __lzcnt32(X);
+}
diff --git a/gcc/testsuite/gcc.target/i386/lzcnt-4.c b/gcc/testsuite/gcc.target/i386/lzcnt-4.c
new file mode 100644
index 0000000..2065326
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/lzcnt-4.c
@@ -0,0 +1,35 @@
+/* { dg-do run { target { lzcnt } } } */
+/* { dg-options "-O2 -mlzcnt -fno-inline" } */
+
+#include <x86intrin.h>
+
+#include "lzcnt-check.h"
+
+int calc_lzcnt_u32 (int src)
+{
+  int i;
+  int res = 0;
+
+  while ((res < 32) && (((src >> (31 - res)) & 1) == 0))
+    ++res;
+
+  return res;
+}
+
+static void
+lzcnt_test ()
+{
+  unsigned i;
+  int src = 0xce7ace0;
+  int res, res_ref;
+
+  for (i=0; i<5; ++i) {
+    src = src >> i;
+
+    res_ref = calc_lzcnt_u32 (src);
+    res = __lzcnt32 (src);
+
+    if (res != res_ref)
+      abort();
+  }
+}
diff --git a/gcc/testsuite/gcc.target/i386/lzcnt-4a.c b/gcc/testsuite/gcc.target/i386/lzcnt-4a.c
new file mode 100644
index 0000000..6bba6a9
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/lzcnt-4a.c
@@ -0,0 +1,6 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -mlzcnt" } */
+
+#include "lzcnt-4.c"
+
+/* { dg-final { scan-assembler "lzcntl" } } */
diff --git a/gcc/testsuite/gcc.target/i386/lzcnt-5.c b/gcc/testsuite/gcc.target/i386/lzcnt-5.c
new file mode 100644
index 0000000..a4b9aaf
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/lzcnt-5.c
@@ -0,0 +1,11 @@
+/* { dg-do compile { target { ! ia32 } } } */
+/* { dg-options "-O2 -mlzcnt" } */
+/* { dg-final { scan-assembler "lzcntq\[^\\n]*(%|)rax" } } */
+
+#include <x86intrin.h>
+
+unsigned int
+func_lzcnt64 (unsigned long long X)
+{
+  return __lzcnt64(X);
+}
diff --git a/gcc/testsuite/gcc.target/i386/lzcnt-6.c b/gcc/testsuite/gcc.target/i386/lzcnt-6.c
new file mode 100644
index 0000000..f0bf5da
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/lzcnt-6.c
@@ -0,0 +1,35 @@
+/* { dg-do run { target { lzcnt && { ! ia32 } } } } */
+/* { dg-options "-O2 -mlzcnt -fno-inline" } */
+
+#include <x86intrin.h>
+
+#include "lzcnt-check.h"
+
+long long calc_lzcnt_u64 (long long src)
+{
+  int i;
+  int res = 0;
+
+  while ((res < 64) && (((src >> (63 - res)) & 1) == 0))
+    ++res;
+
+  return res;
+}
+
+static void
+lzcnt_test ()
+{
+  unsigned i;
+  long long src = 0xce7ace0ce7ace0;
+  long long res, res_ref;
+
+  for (i=0; i<5; ++i) {
+    src = src >> i;
+
+    res_ref = calc_lzcnt_u64 (src);
+    res = __lzcnt64 (src);
+
+    if (res != res_ref)
+      abort();
+  }
+}
diff --git a/gcc/testsuite/gcc.target/i386/lzcnt-6a.c b/gcc/testsuite/gcc.target/i386/lzcnt-6a.c
new file mode 100644
index 0000000..2090093
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/lzcnt-6a.c
@@ -0,0 +1,6 @@
+/* { dg-do compile { target { ! ia32 } } } */
+/* { dg-options "-O2 -mlzcnt" } */
+
+#include "lzcnt-6.c"
+
+/* { dg-final { scan-assembler "lzcntq" } } */
diff --git a/gcc/testsuite/gcc.target/i386/lzcnt-check.h b/gcc/testsuite/gcc.target/i386/lzcnt-check.h
new file mode 100644
index 0000000..8aad834
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/lzcnt-check.h
@@ -0,0 +1,37 @@
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "cpuid.h"
+
+static void lzcnt_test (void);
+
+static void
+__attribute__ ((noinline))
+do_test (void)
+{
+  lzcnt_test ();
+}
+
+int
+main ()
+{
+  unsigned int eax, ebx, ecx, edx;
+
+  if (!__get_cpuid (0x80000001, &eax, &ebx, &ecx, &edx))
+    return 0;
+
+  /* Run LZCNT test only if host has LZCNT support.  */
+  if (ecx & bit_LZCNT)
+    {
+      do_test ();
+#ifdef DEBUG
+      printf ("PASSED\n");
+#endif
+    }
+#ifdef DEBUG
+  else
+    printf ("SKIPPED\n");
+#endif
+
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/i386/sse-12.c b/gcc/testsuite/gcc.target/i386/sse-12.c
index 4f8aaec..59e659e 100644
--- a/gcc/testsuite/gcc.target/i386/sse-12.c
+++ b/gcc/testsuite/gcc.target/i386/sse-12.c
@@ -3,7 +3,7 @@
    popcntintrin.h and mm_malloc.h are usable
    with -O -std=c89 -pedantic-errors.  */
 /* { dg-do compile } */
-/* { dg-options "-O -std=c89 -pedantic-errors -march=k8 -msse4a -m3dnow -mavx -mfma4 -mxop -maes -mpclmul -mpopcnt -mabm -mbmi -mtbm -mlwp -mfsgsbase -mrdrnd -mf16c" } */
+/* { dg-options "-O -std=c89 -pedantic-errors -march=k8 -msse4a -m3dnow -mavx -mfma4 -mxop -maes -mpclmul -mpopcnt -mabm -mlzcnt -mbmi -mtbm -mlwp -mfsgsbase -mrdrnd -mf16c" } */
 
 #include <x86intrin.h>
 
diff --git a/gcc/testsuite/gcc.target/i386/sse-13.c b/gcc/testsuite/gcc.target/i386/sse-13.c
index 188b2e6..836272d 100644
--- a/gcc/testsuite/gcc.target/i386/sse-13.c
+++ b/gcc/testsuite/gcc.target/i386/sse-13.c
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O2 -Werror-implicit-function-declaration -march=k8 -msse4a -m3dnow -mavx -mfma4 -mxop -maes -mpclmul -mpopcnt -mabm -mbmi -mtbm -mlwp -mfsgsbase -mrdrnd -mf16c" } */
+/* { dg-options "-O2 -Werror-implicit-function-declaration -march=k8 -msse4a -m3dnow -mavx -mfma4 -mxop -maes -mpclmul -mpopcnt -mabm -mlzcnt -mbmi -mtbm -mlwp -mfsgsbase -mrdrnd -mf16c" } */
 
 #include <mm_malloc.h>
 
diff --git a/gcc/testsuite/gcc.target/i386/sse-14.c b/gcc/testsuite/gcc.target/i386/sse-14.c
index 22ea61f..af42781 100644
--- a/gcc/testsuite/gcc.target/i386/sse-14.c
+++ b/gcc/testsuite/gcc.target/i386/sse-14.c
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O0 -Werror-implicit-function-declaration -march=k8 -msse4a -m3dnow -mavx -mfma4 -mxop -maes -mpclmul -mpopcnt -mabm -mbmi -mtbm -mlwp -mfsgsbase -mrdrnd -mf16c" } */
+/* { dg-options "-O0 -Werror-implicit-function-declaration -march=k8 -msse4a -m3dnow -mavx -mfma4 -mxop -maes -mpclmul -mpopcnt -mabm -mlzcnt -mbmi -mtbm -mlwp -mfsgsbase -mrdrnd -mf16c" } */
 
 #include <mm_malloc.h>
 

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [Patch, i386, testsuite] Fix for PR49547, new tescases for lzcnt instruction
  2011-07-27 14:27             ` Kirill Yukhin
@ 2011-07-27 14:42               ` H.J. Lu
  2011-07-27 15:00                 ` Kirill Yukhin
  2011-07-27 16:06                 ` Kirill Yukhin
  0 siblings, 2 replies; 25+ messages in thread
From: H.J. Lu @ 2011-07-27 14:42 UTC (permalink / raw)
  To: Kirill Yukhin; +Cc: Uros Bizjak, Mike Stump, gcc-patches List, Jagasia, Harsha

On Wed, Jul 27, 2011 at 7:06 AM, Kirill Yukhin <kirill.yukhin@gmail.com> wrote:
> Okay,
> Uros, thanks for correcting me. Here is updated Changelogs and patch.
>
> ChangeLog entry:
> 2011-07-27  Kirill Yukhin  <kirill.yukhin@intel.com>
>
>        PR target/49547
>        * config/i386/abmintrin.h (head): Check if __LZCNT__ is defined.
>        (__lzcnt): Rename to ...
>        (__lzcnt32): ... this.
>        * config/i386/bmiintrin.h (head): Update copyright year.
>        (__lzcnt_u16): Removed.
>        (__lzcnt_u32): Removed.
>        (__lzcnt_u64): Likewise.
>        * config/i386/cpuid.h: New define.
>        * config/i386/driver-i386.c (host_detect_local_cpu): Detect
>        LZCNT feature.
>        * config/i386/i386-c.c (ix86_target_macros_internal): Define
>        __LZCNT__ if needed.
>        * config/i386/i386.c (ix86_target_string): New option -mlzcnt.
>        (ix86_option_override_internal): Handle LZCNT option.
>        (ix86_valid_target_attribute_inner_p): Likewise.
>        (struct builtin_description bdesc_args) <IX86_BUILTIN_CLZS>: Update.
>        * config/i386/i386.h (TARGET_LZCNT): New.
>        (CLZ_DEFINED_VALUE_AT_ZERO): Update.
>        * config/i386/i386.md (clz<mode>2): Update insn constraint.
>        (clz<mode>2_lzcnt): Likewise.
>        * doc/invoke.texi: Mention -mlzcnt option.
>        * doc/extend.texi: Likewise.

Please mention config/i386/i386.opt.  It is very odd to include
abmintrin.h for lzcnt.  What if someone decides to add new intrinsics
for ABM?  I think it should be renamed to lzcntintrin.h and make
abmintrin.h include it instead.

H.J.

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [Patch, i386, testsuite] Fix for PR49547, new tescases for lzcnt instruction
  2011-07-27 14:42               ` H.J. Lu
@ 2011-07-27 15:00                 ` Kirill Yukhin
  2011-07-27 16:06                 ` Kirill Yukhin
  1 sibling, 0 replies; 25+ messages in thread
From: Kirill Yukhin @ 2011-07-27 15:00 UTC (permalink / raw)
  To: H.J. Lu; +Cc: Uros Bizjak, Mike Stump, gcc-patches List, Jagasia, Harsha

Good point, I forgot about ABM's another instruction - popcnt.
I'll do.

Thanks, K

On Wed, Jul 27, 2011 at 6:20 PM, H.J. Lu <hjl.tools@gmail.com> wrote:
> On Wed, Jul 27, 2011 at 7:06 AM, Kirill Yukhin <kirill.yukhin@gmail.com> wrote:
>> Okay,
>> Uros, thanks for correcting me. Here is updated Changelogs and patch.
>>
>> ChangeLog entry:
>> 2011-07-27  Kirill Yukhin  <kirill.yukhin@intel.com>
>>
>>        PR target/49547
>>        * config/i386/abmintrin.h (head): Check if __LZCNT__ is defined.
>>        (__lzcnt): Rename to ...
>>        (__lzcnt32): ... this.
>>        * config/i386/bmiintrin.h (head): Update copyright year.
>>        (__lzcnt_u16): Removed.
>>        (__lzcnt_u32): Removed.
>>        (__lzcnt_u64): Likewise.
>>        * config/i386/cpuid.h: New define.
>>        * config/i386/driver-i386.c (host_detect_local_cpu): Detect
>>        LZCNT feature.
>>        * config/i386/i386-c.c (ix86_target_macros_internal): Define
>>        __LZCNT__ if needed.
>>        * config/i386/i386.c (ix86_target_string): New option -mlzcnt.
>>        (ix86_option_override_internal): Handle LZCNT option.
>>        (ix86_valid_target_attribute_inner_p): Likewise.
>>        (struct builtin_description bdesc_args) <IX86_BUILTIN_CLZS>: Update.
>>        * config/i386/i386.h (TARGET_LZCNT): New.
>>        (CLZ_DEFINED_VALUE_AT_ZERO): Update.
>>        * config/i386/i386.md (clz<mode>2): Update insn constraint.
>>        (clz<mode>2_lzcnt): Likewise.
>>        * doc/invoke.texi: Mention -mlzcnt option.
>>        * doc/extend.texi: Likewise.
>
> Please mention config/i386/i386.opt.  It is very odd to include
> abmintrin.h for lzcnt.  What if someone decides to add new intrinsics
> for ABM?  I think it should be renamed to lzcntintrin.h and make
> abmintrin.h include it instead.
>
> H.J.
>

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [Patch, i386, testsuite] Fix for PR49547, new tescases for lzcnt instruction
  2011-07-27 14:42               ` H.J. Lu
  2011-07-27 15:00                 ` Kirill Yukhin
@ 2011-07-27 16:06                 ` Kirill Yukhin
  2011-07-27 16:10                   ` H.J. Lu
  1 sibling, 1 reply; 25+ messages in thread
From: Kirill Yukhin @ 2011-07-27 16:06 UTC (permalink / raw)
  To: H.J. Lu; +Cc: Uros Bizjak, Mike Stump, gcc-patches List, Jagasia, Harsha

Just have a closer look to ABM intrinsics support in GCC
Seems, we have popcnt support in separate file: popcntintrin.h

So, after I move lzcnt intrinsics to lzcntintrin.h, abmintrin will
become useless and have to be removed at all

K

On Wed, Jul 27, 2011 at 6:20 PM, H.J. Lu <hjl.tools@gmail.com> wrote:
> On Wed, Jul 27, 2011 at 7:06 AM, Kirill Yukhin <kirill.yukhin@gmail.com> wrote:
>> Okay,
>> Uros, thanks for correcting me. Here is updated Changelogs and patch.
>>
>> ChangeLog entry:
>> 2011-07-27  Kirill Yukhin  <kirill.yukhin@intel.com>
>>
>>        PR target/49547
>>        * config/i386/abmintrin.h (head): Check if __LZCNT__ is defined.
>>        (__lzcnt): Rename to ...
>>        (__lzcnt32): ... this.
>>        * config/i386/bmiintrin.h (head): Update copyright year.
>>        (__lzcnt_u16): Removed.
>>        (__lzcnt_u32): Removed.
>>        (__lzcnt_u64): Likewise.
>>        * config/i386/cpuid.h: New define.
>>        * config/i386/driver-i386.c (host_detect_local_cpu): Detect
>>        LZCNT feature.
>>        * config/i386/i386-c.c (ix86_target_macros_internal): Define
>>        __LZCNT__ if needed.
>>        * config/i386/i386.c (ix86_target_string): New option -mlzcnt.
>>        (ix86_option_override_internal): Handle LZCNT option.
>>        (ix86_valid_target_attribute_inner_p): Likewise.
>>        (struct builtin_description bdesc_args) <IX86_BUILTIN_CLZS>: Update.
>>        * config/i386/i386.h (TARGET_LZCNT): New.
>>        (CLZ_DEFINED_VALUE_AT_ZERO): Update.
>>        * config/i386/i386.md (clz<mode>2): Update insn constraint.
>>        (clz<mode>2_lzcnt): Likewise.
>>        * doc/invoke.texi: Mention -mlzcnt option.
>>        * doc/extend.texi: Likewise.
>
> Please mention config/i386/i386.opt.  It is very odd to include
> abmintrin.h for lzcnt.  What if someone decides to add new intrinsics
> for ABM?  I think it should be renamed to lzcntintrin.h and make
> abmintrin.h include it instead.
>
> H.J.
>

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [Patch, i386, testsuite] Fix for PR49547, new tescases for lzcnt instruction
  2011-07-27 16:06                 ` Kirill Yukhin
@ 2011-07-27 16:10                   ` H.J. Lu
  2011-07-27 16:22                     ` Kirill Yukhin
  0 siblings, 1 reply; 25+ messages in thread
From: H.J. Lu @ 2011-07-27 16:10 UTC (permalink / raw)
  To: Kirill Yukhin; +Cc: Uros Bizjak, Mike Stump, gcc-patches List, Jagasia, Harsha

On Wed, Jul 27, 2011 at 8:45 AM, Kirill Yukhin <kirill.yukhin@gmail.com> wrote:
> Just have a closer look to ABM intrinsics support in GCC
> Seems, we have popcnt support in separate file: popcntintrin.h
>
> So, after I move lzcnt intrinsics to lzcntintrin.h, abmintrin will
> become useless and have to be removed at all

We can't remove an installed header file.  It should just include
other header files.


H.J.
---

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [Patch, i386, testsuite] Fix for PR49547, new tescases for lzcnt instruction
  2011-07-27 16:10                   ` H.J. Lu
@ 2011-07-27 16:22                     ` Kirill Yukhin
  2011-07-27 17:18                       ` Uros Bizjak
  0 siblings, 1 reply; 25+ messages in thread
From: Kirill Yukhin @ 2011-07-27 16:22 UTC (permalink / raw)
  To: H.J. Lu; +Cc: Uros Bizjak, Mike Stump, gcc-patches List, Jagasia, Harsha

Than as it is ABM header, it should include two headers: lzcntinrin.h
and popcntintrin.h

But again, it seems useless to me. If we cannot remove empty header,
let it stay empty...

K

On Wed, Jul 27, 2011 at 7:53 PM, H.J. Lu <hjl.tools@gmail.com> wrote:
> On Wed, Jul 27, 2011 at 8:45 AM, Kirill Yukhin <kirill.yukhin@gmail.com> wrote:
>> Just have a closer look to ABM intrinsics support in GCC
>> Seems, we have popcnt support in separate file: popcntintrin.h
>>
>> So, after I move lzcnt intrinsics to lzcntintrin.h, abmintrin will
>> become useless and have to be removed at all
>
> We can't remove an installed header file.  It should just include
> other header files.
>
>
> H.J.
> ---
>

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [Patch, i386, testsuite] Fix for PR49547, new tescases for lzcnt instruction
  2011-07-27 16:22                     ` Kirill Yukhin
@ 2011-07-27 17:18                       ` Uros Bizjak
  2011-07-27 17:19                         ` H.J. Lu
  0 siblings, 1 reply; 25+ messages in thread
From: Uros Bizjak @ 2011-07-27 17:18 UTC (permalink / raw)
  To: Kirill Yukhin; +Cc: H.J. Lu, Mike Stump, gcc-patches List, Jagasia, Harsha

On Wed, Jul 27, 2011 at 6:12 PM, Kirill Yukhin <kirill.yukhin@gmail.com> wrote:
> Than as it is ABM header, it should include two headers: lzcntinrin.h
> and popcntintrin.h
>
> But again, it seems useless to me. If we cannot remove empty header,
> let it stay empty...
>
> K
>
> On Wed, Jul 27, 2011 at 7:53 PM, H.J. Lu <hjl.tools@gmail.com> wrote:
>> On Wed, Jul 27, 2011 at 8:45 AM, Kirill Yukhin <kirill.yukhin@gmail.com> wrote:
>>> Just have a closer look to ABM intrinsics support in GCC
>>> Seems, we have popcnt support in separate file: popcntintrin.h
>>>
>>> So, after I move lzcnt intrinsics to lzcntintrin.h, abmintrin will
>>> become useless and have to be removed at all
>>
>> We can't remove an installed header file.  It should just include
>> other header files.

ambintrin.h has:

#ifndef _X86INTRIN_H_INCLUDED
# error "Never use <abmintrin.h> directly; include <x86intrin.h> instead."
#endif

I see no problem in removing this header. It is not possible to
#include it directly.

Uros.

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [Patch, i386, testsuite] Fix for PR49547, new tescases for lzcnt instruction
  2011-07-27 17:18                       ` Uros Bizjak
@ 2011-07-27 17:19                         ` H.J. Lu
  2011-07-27 19:14                           ` Kirill Yukhin
  0 siblings, 1 reply; 25+ messages in thread
From: H.J. Lu @ 2011-07-27 17:19 UTC (permalink / raw)
  To: Uros Bizjak; +Cc: Kirill Yukhin, Mike Stump, gcc-patches List, Jagasia, Harsha

On Wed, Jul 27, 2011 at 9:49 AM, Uros Bizjak <ubizjak@gmail.com> wrote:
> On Wed, Jul 27, 2011 at 6:12 PM, Kirill Yukhin <kirill.yukhin@gmail.com> wrote:
>> Than as it is ABM header, it should include two headers: lzcntinrin.h
>> and popcntintrin.h
>>
>> But again, it seems useless to me. If we cannot remove empty header,
>> let it stay empty...
>>
>> K
>>
>> On Wed, Jul 27, 2011 at 7:53 PM, H.J. Lu <hjl.tools@gmail.com> wrote:
>>> On Wed, Jul 27, 2011 at 8:45 AM, Kirill Yukhin <kirill.yukhin@gmail.com> wrote:
>>>> Just have a closer look to ABM intrinsics support in GCC
>>>> Seems, we have popcnt support in separate file: popcntintrin.h
>>>>
>>>> So, after I move lzcnt intrinsics to lzcntintrin.h, abmintrin will
>>>> become useless and have to be removed at all
>>>
>>> We can't remove an installed header file.  It should just include
>>> other header files.
>
> ambintrin.h has:
>
> #ifndef _X86INTRIN_H_INCLUDED
> # error "Never use <abmintrin.h> directly; include <x86intrin.h> instead."
> #endif
>
> I see no problem in removing this header. It is not possible to
> #include it directly.
>

Sounds good to me.

-- 
H.J.

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [Patch, i386, testsuite] Fix for PR49547, new tescases for lzcnt instruction
  2011-07-27 17:19                         ` H.J. Lu
@ 2011-07-27 19:14                           ` Kirill Yukhin
  2011-08-01  8:22                             ` Kirill Yukhin
  0 siblings, 1 reply; 25+ messages in thread
From: Kirill Yukhin @ 2011-07-27 19:14 UTC (permalink / raw)
  To: H.J. Lu; +Cc: Uros Bizjak, Mike Stump, gcc-patches List, Jagasia, Harsha

[-- Attachment #1: Type: text/plain, Size: 2740 bytes --]

Okay, then here is an updated patch

updated ChangeLog entry:
2011-07-26  Kirill Yukhin  <kirill.yukhin@intel.com>

	PR target/49547
	* config.gcc (i[34567]86-*-*): Replace abmintrin.h with
	lzcntintrin.h.
	(x86_64-*-*): Likewise.
	* config/i386/i386.opt (mlzcnt): New.
	* config/i386/abmintrin.h: File removed.
	(__lzcnt_u16, __lzcnt, __lzcnt_u64): Moved to ...
	* config/i386/lzcntintrin.h: ... here. New file.
	(__lzcnt): Rename to ...
	(__lzcnt32): ... this.
	* config/i386/bmiintrin.h (head): Update copyright year.
	(__lzcnt_u16): Removed.
	(__lzcnt_u32): Likewise.
	(__lzcnt_u64): Likewise.
	* config/i386/x86intrin.h: Include lzcntintrin.h when __LZCNT__
	is defined, remove abmintrin.h.
	* config/i386/cpuid.h: New define.
	* config/i386/driver-i386.c (host_detect_local_cpu): Detect
	LZCNT feature.
	* config/i386/i386-c.c (ix86_target_macros_internal): Define
	__LZCNT__ if needed.
	* config/i386/i386.c (ix86_target_string): New option -mlzcnt.
	(ix86_option_override_internal): Handle LZCNT option.
	(ix86_valid_target_attribute_inner_p): Likewise.
	(struct builtin_description bdesc_args) <IX86_BUILTIN_CLZS>: Update.
	* config/i386/i386.h (TARGET_LZCNT): New.
	(CLZ_DEFINED_VALUE_AT_ZERO): Update.
	* config/i386/i386.md (clz<mode>2): Update insn constraint.
	(clz<mode>2_lzcnt): Likewise.
	* doc/invoke.texi: Mention -mlzcnt option.
	* doc/extend.texi: Likewise.

Bootstrapped successfully.
Ok?

K

On Wed, Jul 27, 2011 at 8:51 PM, H.J. Lu <hjl.tools@gmail.com> wrote:
> On Wed, Jul 27, 2011 at 9:49 AM, Uros Bizjak <ubizjak@gmail.com> wrote:
>> On Wed, Jul 27, 2011 at 6:12 PM, Kirill Yukhin <kirill.yukhin@gmail.com> wrote:
>>> Than as it is ABM header, it should include two headers: lzcntinrin.h
>>> and popcntintrin.h
>>>
>>> But again, it seems useless to me. If we cannot remove empty header,
>>> let it stay empty...
>>>
>>> K
>>>
>>> On Wed, Jul 27, 2011 at 7:53 PM, H.J. Lu <hjl.tools@gmail.com> wrote:
>>>> On Wed, Jul 27, 2011 at 8:45 AM, Kirill Yukhin <kirill.yukhin@gmail.com> wrote:
>>>>> Just have a closer look to ABM intrinsics support in GCC
>>>>> Seems, we have popcnt support in separate file: popcntintrin.h
>>>>>
>>>>> So, after I move lzcnt intrinsics to lzcntintrin.h, abmintrin will
>>>>> become useless and have to be removed at all
>>>>
>>>> We can't remove an installed header file.  It should just include
>>>> other header files.
>>
>> ambintrin.h has:
>>
>> #ifndef _X86INTRIN_H_INCLUDED
>> # error "Never use <abmintrin.h> directly; include <x86intrin.h> instead."
>> #endif
>>
>> I see no problem in removing this header. It is not possible to
>> #include it directly.
>>
>
> Sounds good to me.
>
> --
> H.J.
>

[-- Attachment #2: lzcnt-4.gcc.patch --]
[-- Type: application/octet-stream, Size: 26765 bytes --]

diff --git a/gcc/config.gcc b/gcc/config.gcc
index d7cf895..3481bab 100644
--- a/gcc/config.gcc
+++ b/gcc/config.gcc
@@ -351,7 +351,7 @@ i[34567]86-*-*)
 		       nmmintrin.h bmmintrin.h fma4intrin.h wmmintrin.h
 		       immintrin.h x86intrin.h avxintrin.h xopintrin.h
 		       ia32intrin.h cross-stdarg.h lwpintrin.h popcntintrin.h
-		       abmintrin.h bmiintrin.h tbmintrin.h"
+		       lzcntintrin.h bmiintrin.h tbmintrin.h"
 	;;
 x86_64-*-*)
 	cpu_type=i386
@@ -363,7 +363,7 @@ x86_64-*-*)
 		       nmmintrin.h bmmintrin.h fma4intrin.h wmmintrin.h
 		       immintrin.h x86intrin.h avxintrin.h xopintrin.h
 		       ia32intrin.h cross-stdarg.h lwpintrin.h popcntintrin.h
-		       abmintrin.h bmiintrin.h tbmintrin.h"
+		       lzcntintrin.h bmiintrin.h tbmintrin.h"
 	need_64bit_hwint=yes
 	;;
 ia64-*-*)
diff --git a/gcc/config/i386/abmintrin.h b/gcc/config/i386/abmintrin.h
deleted file mode 100644
index 9d87f57..0000000
--- a/gcc/config/i386/abmintrin.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/* Copyright (C) 2009 Free Software Foundation, Inc.
-
-   This file is part of GCC.
-
-   GCC is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3, or (at your option)
-   any later version.
-
-   GCC is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   Under Section 7 of GPL version 3, you are granted additional
-   permissions described in the GCC Runtime Library Exception, version
-   3.1, as published by the Free Software Foundation.
-
-   You should have received a copy of the GNU General Public License and
-   a copy of the GCC Runtime Library Exception along with this program;
-   see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
-   <http://www.gnu.org/licenses/>.  */
-
-#ifndef _X86INTRIN_H_INCLUDED
-# error "Never use <abmintrin.h> directly; include <x86intrin.h> instead."
-#endif
-
-#ifndef __ABM__
-# error "ABM instruction set not enabled"
-#endif /* __ABM__ */
-
-#ifndef _ABMINTRIN_H_INCLUDED
-#define _ABMINTRIN_H_INCLUDED
-
-extern __inline unsigned short __attribute__((__gnu_inline__, __always_inline__, __artificial__))
-__lzcnt16 (unsigned short __X)
-{
-  return __builtin_clzs (__X);
-}
-
-extern __inline unsigned int __attribute__((__gnu_inline__, __always_inline__, __artificial__))
-__lzcnt (unsigned int __X)
-{
-  return __builtin_clz (__X);
-}
-
-#ifdef __x86_64__
-extern __inline unsigned long __attribute__((__gnu_inline__, __always_inline__, __artificial__))
-__lzcnt64 (unsigned long __X)
-{
-  return __builtin_clzl (__X);
-}
-#endif
-
-#endif /* _ABMINTRIN_H_INCLUDED */
diff --git a/gcc/config/i386/bmiintrin.h b/gcc/config/i386/bmiintrin.h
index 225f2ec..1699c61 100644
--- a/gcc/config/i386/bmiintrin.h
+++ b/gcc/config/i386/bmiintrin.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2010 Free Software Foundation, Inc.
+/* Copyright (C) 2010, 2011 Free Software Foundation, Inc.
 
    This file is part of GCC.
 
@@ -33,12 +33,6 @@
 #define _BMIINTRIN_H_INCLUDED
 
 extern __inline unsigned short __attribute__((__gnu_inline__, __always_inline__, __artificial__))
-__lzcnt_u16 (unsigned short __X)
-{
-  return __builtin_clzs (__X);
-}
-
-extern __inline unsigned short __attribute__((__gnu_inline__, __always_inline__, __artificial__))
 __tzcnt_u16 (unsigned short __X)
 {
   return __builtin_ctzs (__X);
@@ -79,12 +73,6 @@ __blsr_u32 (unsigned int __X)
   return tmp;
 }
 
-extern __inline unsigned int __attribute__((__gnu_inline__, __always_inline__, __artificial__))
-__lzcnt_u32 (unsigned int __X)
-{
-  return __builtin_clz (__X);
-}
-
 
 extern __inline unsigned int __attribute__((__gnu_inline__, __always_inline__, __artificial__))
 __tzcnt_u32 (unsigned int __X)
@@ -129,12 +117,6 @@ __blsr_u64 (unsigned long long __X)
 }
 
 extern __inline unsigned long long __attribute__((__gnu_inline__, __always_inline__, __artificial__))
-__lzcnt_u64 (unsigned long long __X)
-{
-  return __builtin_clzll (__X);
-}
-
-extern __inline unsigned long long __attribute__((__gnu_inline__, __always_inline__, __artificial__))
 __tzcnt_u64 (unsigned long long __X)
 {
   return __builtin_ctzll (__X);
diff --git a/gcc/config/i386/cpuid.h b/gcc/config/i386/cpuid.h
index 3c3f47b..8826c28 100644
--- a/gcc/config/i386/cpuid.h
+++ b/gcc/config/i386/cpuid.h
@@ -24,6 +24,7 @@
 /* %ecx */
 #define bit_SSE3	(1 << 0)
 #define bit_PCLMUL	(1 << 1)
+#define bit_LZCNT	(1 << 5)
 #define bit_SSSE3	(1 << 9)
 #define bit_FMA		(1 << 12)
 #define bit_CMPXCHG16B	(1 << 13)
diff --git a/gcc/config/i386/driver-i386.c b/gcc/config/i386/driver-i386.c
index ecd8958..5823987 100644
--- a/gcc/config/i386/driver-i386.c
+++ b/gcc/config/i386/driver-i386.c
@@ -396,7 +396,7 @@ const char *host_detect_local_cpu (int argc, const char **argv)
   unsigned int has_popcnt = 0, has_aes = 0, has_avx = 0;
   unsigned int has_pclmul = 0, has_abm = 0, has_lwp = 0;
   unsigned int has_fma = 0, has_fma4 = 0, has_xop = 0;
-  unsigned int has_bmi = 0, has_tbm = 0;
+  unsigned int has_bmi = 0, has_tbm = 0, has_lzcnt = 0;
 
   bool arch;
 
@@ -465,6 +465,7 @@ const char *host_detect_local_cpu (int argc, const char **argv)
       has_fma4 = ecx & bit_FMA4;
       has_xop = ecx & bit_XOP;
       has_tbm = ecx & bit_TBM;
+      has_lzcnt = ecx & bit_LZCNT;
 
       has_longmode = edx & bit_LM;
       has_3dnowp = edx & bit_3DNOWP;
@@ -717,10 +718,11 @@ const char *host_detect_local_cpu (int argc, const char **argv)
       const char *avx = has_avx ? " -mavx" : " -mno-avx";
       const char *sse4_2 = has_sse4_2 ? " -msse4.2" : " -mno-sse4.2";
       const char *sse4_1 = has_sse4_1 ? " -msse4.1" : " -mno-sse4.1";
+      const char *lzcnt = has_lzcnt ? " -mlzcnt" : " -mnolzcnt";
 
       options = concat (options, cx16, sahf, movbe, ase, pclmul,
 			popcnt, abm, lwp, fma, fma4, xop, bmi, tbm,
-			avx, sse4_2, sse4_1, NULL);
+			avx, sse4_2, sse4_1, lzcnt, NULL);
     }
 
 done:
diff --git a/gcc/config/i386/i386-c.c b/gcc/config/i386/i386-c.c
index 5cbcfd5..1fc333c 100644
--- a/gcc/config/i386/i386-c.c
+++ b/gcc/config/i386/i386-c.c
@@ -271,6 +271,8 @@ ix86_target_macros_internal (int isa_flag,
     def_or_undef (parse_in, "__ABM__");
   if (isa_flag & OPTION_MASK_ISA_BMI)
     def_or_undef (parse_in, "__BMI__");
+  if (isa_flag & OPTION_MASK_ISA_LZCNT)
+    def_or_undef (parse_in, "__LZCNT__");
   if (isa_flag & OPTION_MASK_ISA_TBM)
     def_or_undef (parse_in, "__TBM__");
   if (isa_flag & OPTION_MASK_ISA_POPCNT)
diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
index 960622a..d0b92e2 100644
--- a/gcc/config/i386/i386.c
+++ b/gcc/config/i386/i386.c
@@ -2663,6 +2663,7 @@ ix86_target_string (int isa, int flags, const char *arch, const char *tune,
     { "-mmmx",		OPTION_MASK_ISA_MMX },
     { "-mabm",		OPTION_MASK_ISA_ABM },
     { "-mbmi",		OPTION_MASK_ISA_BMI },
+    { "-mlzcnt",	OPTION_MASK_ISA_LZCNT },
     { "-mtbm",		OPTION_MASK_ISA_TBM },
     { "-mpopcnt",	OPTION_MASK_ISA_POPCNT },
     { "-mmovbe",	OPTION_MASK_ISA_MOVBE },
@@ -2917,7 +2918,8 @@ ix86_option_override_internal (bool main_args_p)
       PTA_RDRND = 1 << 25,
       PTA_F16C = 1 << 26,
       PTA_BMI = 1 << 27,
-      PTA_TBM = 1 << 28
+      PTA_TBM = 1 << 28,
+      PTA_LZCNT = 1 << 29
       /* if this reaches 32, need to widen struct pta flags below */
     };
 
@@ -3281,6 +3283,9 @@ ix86_option_override_internal (bool main_args_p)
 	if (processor_alias_table[i].flags & PTA_BMI
 	    && !(ix86_isa_flags_explicit & OPTION_MASK_ISA_BMI))
 	  ix86_isa_flags |= OPTION_MASK_ISA_BMI;
+	if (processor_alias_table[i].flags & (PTA_LZCNT | PTA_ABM)
+	    && !(ix86_isa_flags_explicit & OPTION_MASK_ISA_LZCNT))
+	  ix86_isa_flags |= OPTION_MASK_ISA_LZCNT;
 	if (processor_alias_table[i].flags & PTA_TBM
 	    && !(ix86_isa_flags_explicit & OPTION_MASK_ISA_TBM))
 	  ix86_isa_flags |= OPTION_MASK_ISA_TBM;
@@ -3528,6 +3533,10 @@ ix86_option_override_internal (bool main_args_p)
   if (TARGET_SSE4_2 || TARGET_ABM)
     ix86_isa_flags |= OPTION_MASK_ISA_POPCNT & ~ix86_isa_flags_explicit;
 
+  /* Turn on lzcnt instruction for -mabm.  */
+  if (TARGET_ABM)
+    ix86_isa_flags |= OPTION_MASK_ISA_LZCNT & ~ix86_isa_flags_explicit;
+
   /* Validate -mpreferred-stack-boundary= value or default it to
      PREFERRED_STACK_BOUNDARY_DEFAULT.  */
   ix86_preferred_stack_boundary = PREFERRED_STACK_BOUNDARY_DEFAULT;
@@ -4033,6 +4042,7 @@ ix86_valid_target_attribute_inner_p (tree args, char *p_strings[],
     IX86_ATTR_ISA ("3dnow",	OPT_m3dnow),
     IX86_ATTR_ISA ("abm",	OPT_mabm),
     IX86_ATTR_ISA ("bmi",	OPT_mbmi),
+    IX86_ATTR_ISA ("lzcnt",	OPT_mlzcnt),
     IX86_ATTR_ISA ("tbm",	OPT_mtbm),
     IX86_ATTR_ISA ("aes",	OPT_maes),
     IX86_ATTR_ISA ("avx",	OPT_mavx),
@@ -24945,7 +24955,7 @@ static const struct builtin_description bdesc_args[] =
   { OPTION_MASK_ISA_AVX, CODE_FOR_copysignv8sf3,  "__builtin_ia32_copysignps256", IX86_BUILTIN_CPYSGNPS256, UNKNOWN, (int) V8SF_FTYPE_V8SF_V8SF },
   { OPTION_MASK_ISA_AVX, CODE_FOR_copysignv4df3,  "__builtin_ia32_copysignpd256", IX86_BUILTIN_CPYSGNPD256, UNKNOWN, (int) V4DF_FTYPE_V4DF_V4DF },
 
-  { OPTION_MASK_ISA_ABM, CODE_FOR_clzhi2_abm,   "__builtin_clzs",   IX86_BUILTIN_CLZS,    UNKNOWN,     (int) UINT16_FTYPE_UINT16 },
+  { OPTION_MASK_ISA_LZCNT, CODE_FOR_clzhi2_lzcnt,   "__builtin_clzs",   IX86_BUILTIN_CLZS,    UNKNOWN,     (int) UINT16_FTYPE_UINT16 },
 
   /* BMI */
   { OPTION_MASK_ISA_BMI, CODE_FOR_bmi_bextr_si, "__builtin_ia32_bextr_u32", IX86_BUILTIN_BEXTR32, UNKNOWN, (int) UINT_FTYPE_UINT_UINT },
diff --git a/gcc/config/i386/i386.h b/gcc/config/i386/i386.h
index 20c9a8f..f43586d 100644
--- a/gcc/config/i386/i386.h
+++ b/gcc/config/i386/i386.h
@@ -61,6 +61,7 @@ see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
 #define TARGET_ROUND	OPTION_ISA_ROUND
 #define TARGET_ABM	OPTION_ISA_ABM
 #define TARGET_BMI	OPTION_ISA_BMI
+#define TARGET_LZCNT	OPTION_ISA_LZCNT
 #define TARGET_TBM	OPTION_ISA_TBM
 #define TARGET_POPCNT	OPTION_ISA_POPCNT
 #define TARGET_SAHF	OPTION_ISA_SAHF
@@ -2288,7 +2289,7 @@ extern void debug_dispatch_window (int);
 #define CTZ_DEFINED_VALUE_AT_ZERO(MODE, VALUE) \
 	((VALUE) = GET_MODE_BITSIZE (MODE), TARGET_BMI)
 #define CLZ_DEFINED_VALUE_AT_ZERO(MODE, VALUE) \
-	((VALUE) = GET_MODE_BITSIZE (MODE), TARGET_BMI)
+	((VALUE) = GET_MODE_BITSIZE (MODE), TARGET_LZCNT)
 
 
 /* Flags returned by ix86_get_callcvt ().  */
diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md
index e91a299..f1efade 100644
--- a/gcc/config/i386/i386.md
+++ b/gcc/config/i386/i386.md
@@ -11801,19 +11801,19 @@
       (clobber (reg:CC FLAGS_REG))])]
   ""
 {
-  if (TARGET_ABM)
+  if (TARGET_LZCNT)
     {
-      emit_insn (gen_clz<mode>2_abm (operands[0], operands[1]));
+      emit_insn (gen_clz<mode>2_lzcnt (operands[0], operands[1]));
       DONE;
     }
   operands[2] = GEN_INT (GET_MODE_BITSIZE (<MODE>mode)-1);
 })
 
-(define_insn "clz<mode>2_abm"
+(define_insn "clz<mode>2_lzcnt"
   [(set (match_operand:SWI248 0 "register_operand" "=r")
 	(clz:SWI248 (match_operand:SWI248 1 "nonimmediate_operand" "rm")))
    (clobber (reg:CC FLAGS_REG))]
-  "TARGET_ABM || TARGET_BMI"
+  "TARGET_LZCNT"
   "lzcnt{<imodesuffix>}\t{%1, %0|%0, %1}"
   [(set_attr "prefix_rep" "1")
    (set_attr "type" "bitmanip")
diff --git a/gcc/config/i386/i386.opt b/gcc/config/i386/i386.opt
index 5e6b5df..f197dd8 100644
--- a/gcc/config/i386/i386.opt
+++ b/gcc/config/i386/i386.opt
@@ -489,6 +489,10 @@ mbmi
 Target Report Mask(ISA_BMI) Var(ix86_isa_flags) Save
 Support BMI built-in functions and code generation
 
+mlzcnt
+Target Report Mask(ISA_LZCNT) Var(ix86_isa_flags) Save
+Support LZCNT built-in function and code generation
+
 mtbm
 Target Report Mask(ISA_TBM) Var(ix86_isa_flags) Save
 Support TBM built-in functions and code generation
diff --git a/gcc/config/i386/lzcntintrin.h b/gcc/config/i386/lzcntintrin.h
new file mode 100644
index 0000000..4300811
--- /dev/null
+++ b/gcc/config/i386/lzcntintrin.h
@@ -0,0 +1,55 @@
+/* Copyright (C) 2009 Free Software Foundation, Inc.
+
+   This file is part of GCC.
+
+   GCC is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3, or (at your option)
+   any later version.
+
+   GCC is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   Under Section 7 of GPL version 3, you are granted additional
+   permissions described in the GCC Runtime Library Exception, version
+   3.1, as published by the Free Software Foundation.
+
+   You should have received a copy of the GNU General Public License and
+   a copy of the GCC Runtime Library Exception along with this program;
+   see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#ifndef _X86INTRIN_H_INCLUDED
+# error "Never use <lzcntintrin.h> directly; include <x86intrin.h> instead."
+#endif
+
+#ifndef __LZCNT__
+# error "LZCNT instruction is not enabled"
+#endif /* __LZCNT__ */
+
+#ifndef _LZCNTINTRIN_H_INCLUDED
+#define _LZCNTINTRIN_H_INCLUDED
+
+extern __inline unsigned short __attribute__((__gnu_inline__, __always_inline__, __artificial__))
+__lzcnt16 (unsigned short __X)
+{
+  return __builtin_clzs (__X);
+}
+
+extern __inline unsigned int __attribute__((__gnu_inline__, __always_inline__, __artificial__))
+__lzcnt32 (unsigned int __X)
+{
+  return __builtin_clz (__X);
+}
+
+#ifdef __x86_64__
+extern __inline unsigned long __attribute__((__gnu_inline__, __always_inline__, __artificial__))
+__lzcnt64 (unsigned long __X)
+{
+  return __builtin_clzl (__X);
+}
+#endif
+
+#endif /* _LZCNTINTRIN_H_INCLUDED */
diff --git a/gcc/config/i386/x86intrin.h b/gcc/config/i386/x86intrin.h
index 36b43df..88456f9 100644
--- a/gcc/config/i386/x86intrin.h
+++ b/gcc/config/i386/x86intrin.h
@@ -77,10 +77,6 @@
 #include <lwpintrin.h>
 #endif
 
-#ifdef __ABM__
-#include <abmintrin.h>
-#endif
-
 #ifdef __BMI__
 #include <bmiintrin.h>
 #endif
@@ -89,6 +85,10 @@
 #include <tbmintrin.h>
 #endif
 
+#ifdef __LZCNT__
+#include <lzcntintrin.h>
+#endif
+
 #ifdef __POPCNT__
 #include <popcntintrin.h>
 #endif
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index dcbf29f..d705720 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -9673,6 +9673,11 @@ All of them generate the machine instruction that is part of the name.
 @smallexample
 unsigned int __builtin_ia32_bextr_u32(unsigned int, unsigned int);
 unsigned long long __builtin_ia32_bextr_u64 (unsigned long long, unsigned long long);
+@end smallexample
+
+The following built-in functions are available when @option{-mlzcnt} is used.
+All of them generate the machine instruction that is part of the name.
+@smallexample
 unsigned short __builtin_ia32_lzcnt_16(unsigned short);
 unsigned int __builtin_ia32_lzcnt_u32(unsigned int);
 unsigned long long __builtin_ia32_lzcnt_u64 (unsigned long long);
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 7783786..137f256 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -606,8 +606,8 @@ Objective-C and Objective-C++ Dialects}.
 -mcld -mcx16 -msahf -mmovbe -mcrc32 -mrecip -mvzeroupper @gol
 -mmmx  -msse  -msse2 -msse3 -mssse3 -msse4.1 -msse4.2 -msse4 -mavx @gol
 -maes -mpclmul -mfsgsbase -mrdrnd -mf16c -mfma @gol
--msse4a -m3dnow -mpopcnt -mabm -mbmi -mtbm -mfma4 -mxop -mlwp @gol
--mthreads  -mno-align-stringops  -minline-all-stringops @gol
+-msse4a -m3dnow -mpopcnt -mabm -mbmi -mtbm -mfma4 -mxop -mlzcnt @gol
+-mlwp -mthreads  -mno-align-stringops  -minline-all-stringops @gol
 -minline-stringops-dynamically -mstringop-strategy=@var{alg} @gol
 -mpush-args  -maccumulate-outgoing-args  -m128bit-long-double @gol
 -m96bit-long-double  -mregparm=@var{num}  -msseregparm @gol
@@ -12687,6 +12687,8 @@ preferred alignment to @option{-mpreferred-stack-boundary=2}.
 @itemx -mno-abm
 @itemx -mbmi
 @itemx -mno-bmi
+@itemx -mlzcnt
+@itemx -mno-lzcnt
 @itemx -mtbm
 @itemx -mno-tbm
 @opindex mmmx
@@ -12697,7 +12699,7 @@ preferred alignment to @option{-mpreferred-stack-boundary=2}.
 @opindex mno-3dnow
 These switches enable or disable the use of instructions in the MMX, SSE,
 SSE2, SSE3, SSSE3, SSE4.1, AVX, AES, PCLMUL, FSGSBASE, RDRND, F16C, FMA,
-SSE4A, FMA4, XOP, LWP, ABM, BMI, or 3DNow!@: extended instruction sets.
+SSE4A, FMA4, XOP, LWP, ABM, BMI, LZCNT or 3DNow!@: extended instruction sets.
 These extensions are also available as built-in functions: see
 @ref{X86 Built-in Functions}, for details of the functions enabled and
 disabled by these switches.
diff --git a/gcc/testsuite/g++.dg/other/i386-2.C b/gcc/testsuite/g++.dg/other/i386-2.C
index 1a445f1..ed183c7 100644
--- a/gcc/testsuite/g++.dg/other/i386-2.C
+++ b/gcc/testsuite/g++.dg/other/i386-2.C
@@ -1,5 +1,5 @@
 /* { dg-do compile { target i?86-*-* x86_64-*-* } } */
-/* { dg-options "-O -pedantic-errors -march=k8 -msse4a -m3dnow -mavx -mfma4 -mxop -maes -mpclmul -mpopcnt -mabm -mbmi -mtbm -mlwp -mfsgsbase -mrdrnd -mf16c" } */
+/* { dg-options "-O -pedantic-errors -march=k8 -msse4a -m3dnow -mavx -mfma4 -mxop -maes -mpclmul -mpopcnt -mabm -mlzcnt -mbmi -mtbm -mlwp -mfsgsbase -mrdrnd -mf16c" } */
 
 /* Test that {,x,e,p,t,s,w,a,b,i}mmintrin.h, mm3dnow.h, fma4intrin.h,
    xopintrin.h, abmintrin.h, bmiintrin.h, tbmintrin.h, lwpintrin.h,
diff --git a/gcc/testsuite/g++.dg/other/i386-3.C b/gcc/testsuite/g++.dg/other/i386-3.C
index 66eec14..626f972 100644
--- a/gcc/testsuite/g++.dg/other/i386-3.C
+++ b/gcc/testsuite/g++.dg/other/i386-3.C
@@ -1,5 +1,5 @@
 /* { dg-do compile { target i?86-*-* x86_64-*-* } } */
-/* { dg-options "-O -fkeep-inline-functions -march=k8 -msse4a -m3dnow -mavx -mfma4 -mxop -maes -mpclmul -mpopcnt -mabm -mbmi -mtbm -mlwp -mfsgsbase -mrdrnd -mf16c" } */
+/* { dg-options "-O -fkeep-inline-functions -march=k8 -msse4a -m3dnow -mavx -mfma4 -mxop -maes -mpclmul -mpopcnt -mabm -mlzcnt -mbmi -mtbm -mlwp -mfsgsbase -mrdrnd -mf16c" } */
 
 /* Test that {,x,e,p,t,s,w,a,b,i}mmintrin.h, mm3dnow.h, fma4intrin.h,
    xopintrin.h, abmintrin.h, bmiintrin.h, tbmintrin.h, lwpintrin.h,
diff --git a/gcc/testsuite/gcc.target/i386/i386.exp b/gcc/testsuite/gcc.target/i386/i386.exp
index 32dbf5e..8a8fae5 100644
--- a/gcc/testsuite/gcc.target/i386/i386.exp
+++ b/gcc/testsuite/gcc.target/i386/i386.exp
@@ -186,6 +186,16 @@ proc check_effective_target_xop { } {
     } "-O2 -mxop" ]
 }
 
+# Return 1 if lzcnt instruction can be compiled.
+proc check_effective_target_lzcnt { } {
+    return [check_no_compiler_messages avx object {
+	void _lzcnt (void)
+	{
+	   __builtin_clzs (0);
+	}
+    } "-O2 -mlzcnt" ]
+}
+
 # If the linker used understands -M <mapfile>, pass it to clear hardware
 # capabilities set by the Sun assembler.
 set clearcap_ldflags "-Wl,-M,$srcdir/$subdir/clearcap.map"
diff --git a/gcc/testsuite/gcc.target/i386/lzcnt-1.c b/gcc/testsuite/gcc.target/i386/lzcnt-1.c
new file mode 100644
index 0000000..f6240d1b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/lzcnt-1.c
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -mlzcnt " } */
+/* { dg-final { scan-assembler "lzcntw\[^\\n]*(%|)ax" } } */
+
+#include <x86intrin.h>
+
+unsigned int
+func_lzcnt16 (unsigned int X)
+{
+  return __lzcnt16(X);
+}
diff --git a/gcc/testsuite/gcc.target/i386/lzcnt-2.c b/gcc/testsuite/gcc.target/i386/lzcnt-2.c
new file mode 100644
index 0000000..329a11f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/lzcnt-2.c
@@ -0,0 +1,35 @@
+/* { dg-do run { target { lzcnt } } } */
+/* { dg-options "-O2 -mlzcnt -fno-inline" } */
+
+#include <x86intrin.h>
+
+#include "lzcnt-check.h"
+
+short calc_lzcnt_u16 (short src)
+{
+  int i;
+  short res = 0;
+
+  while ((res < 16) && (((src >> (15 - res)) & 1) == 0))
+    ++res;
+
+  return res;
+}
+
+static void
+lzcnt_test ()
+{
+  unsigned i;
+  short src = 0x7ace;
+  short res, res_ref;
+
+  for (i=0; i<5; ++i) {
+    src = src >> i;
+
+    res_ref = calc_lzcnt_u16 (src);
+    res = __lzcnt16 (src);
+
+    if (res != res_ref)
+      abort();
+  }
+}
diff --git a/gcc/testsuite/gcc.target/i386/lzcnt-2a.c b/gcc/testsuite/gcc.target/i386/lzcnt-2a.c
new file mode 100644
index 0000000..fe1069f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/lzcnt-2a.c
@@ -0,0 +1,6 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -mlzcnt" } */
+
+#include "lzcnt-2.c"
+
+/* { dg-final { scan-assembler "lzcntw" } } */
diff --git a/gcc/testsuite/gcc.target/i386/lzcnt-3.c b/gcc/testsuite/gcc.target/i386/lzcnt-3.c
new file mode 100644
index 0000000..1477951
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/lzcnt-3.c
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-options "-O0 -mlzcnt " } */
+/* { dg-final { scan-assembler "lzcntl\[^\\n]*(%|)eax" } } */
+
+#include <x86intrin.h>
+
+unsigned int
+func_lzcnt32 (unsigned int X)
+{
+  return __lzcnt32(X);
+}
diff --git a/gcc/testsuite/gcc.target/i386/lzcnt-4.c b/gcc/testsuite/gcc.target/i386/lzcnt-4.c
new file mode 100644
index 0000000..2065326
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/lzcnt-4.c
@@ -0,0 +1,35 @@
+/* { dg-do run { target { lzcnt } } } */
+/* { dg-options "-O2 -mlzcnt -fno-inline" } */
+
+#include <x86intrin.h>
+
+#include "lzcnt-check.h"
+
+int calc_lzcnt_u32 (int src)
+{
+  int i;
+  int res = 0;
+
+  while ((res < 32) && (((src >> (31 - res)) & 1) == 0))
+    ++res;
+
+  return res;
+}
+
+static void
+lzcnt_test ()
+{
+  unsigned i;
+  int src = 0xce7ace0;
+  int res, res_ref;
+
+  for (i=0; i<5; ++i) {
+    src = src >> i;
+
+    res_ref = calc_lzcnt_u32 (src);
+    res = __lzcnt32 (src);
+
+    if (res != res_ref)
+      abort();
+  }
+}
diff --git a/gcc/testsuite/gcc.target/i386/lzcnt-4a.c b/gcc/testsuite/gcc.target/i386/lzcnt-4a.c
new file mode 100644
index 0000000..6bba6a9
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/lzcnt-4a.c
@@ -0,0 +1,6 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -mlzcnt" } */
+
+#include "lzcnt-4.c"
+
+/* { dg-final { scan-assembler "lzcntl" } } */
diff --git a/gcc/testsuite/gcc.target/i386/lzcnt-5.c b/gcc/testsuite/gcc.target/i386/lzcnt-5.c
new file mode 100644
index 0000000..a4b9aaf
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/lzcnt-5.c
@@ -0,0 +1,11 @@
+/* { dg-do compile { target { ! ia32 } } } */
+/* { dg-options "-O2 -mlzcnt" } */
+/* { dg-final { scan-assembler "lzcntq\[^\\n]*(%|)rax" } } */
+
+#include <x86intrin.h>
+
+unsigned int
+func_lzcnt64 (unsigned long long X)
+{
+  return __lzcnt64(X);
+}
diff --git a/gcc/testsuite/gcc.target/i386/lzcnt-6.c b/gcc/testsuite/gcc.target/i386/lzcnt-6.c
new file mode 100644
index 0000000..f0bf5da
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/lzcnt-6.c
@@ -0,0 +1,35 @@
+/* { dg-do run { target { lzcnt && { ! ia32 } } } } */
+/* { dg-options "-O2 -mlzcnt -fno-inline" } */
+
+#include <x86intrin.h>
+
+#include "lzcnt-check.h"
+
+long long calc_lzcnt_u64 (long long src)
+{
+  int i;
+  int res = 0;
+
+  while ((res < 64) && (((src >> (63 - res)) & 1) == 0))
+    ++res;
+
+  return res;
+}
+
+static void
+lzcnt_test ()
+{
+  unsigned i;
+  long long src = 0xce7ace0ce7ace0;
+  long long res, res_ref;
+
+  for (i=0; i<5; ++i) {
+    src = src >> i;
+
+    res_ref = calc_lzcnt_u64 (src);
+    res = __lzcnt64 (src);
+
+    if (res != res_ref)
+      abort();
+  }
+}
diff --git a/gcc/testsuite/gcc.target/i386/lzcnt-6a.c b/gcc/testsuite/gcc.target/i386/lzcnt-6a.c
new file mode 100644
index 0000000..2090093
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/lzcnt-6a.c
@@ -0,0 +1,6 @@
+/* { dg-do compile { target { ! ia32 } } } */
+/* { dg-options "-O2 -mlzcnt" } */
+
+#include "lzcnt-6.c"
+
+/* { dg-final { scan-assembler "lzcntq" } } */
diff --git a/gcc/testsuite/gcc.target/i386/lzcnt-check.h b/gcc/testsuite/gcc.target/i386/lzcnt-check.h
new file mode 100644
index 0000000..8aad834
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/lzcnt-check.h
@@ -0,0 +1,37 @@
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "cpuid.h"
+
+static void lzcnt_test (void);
+
+static void
+__attribute__ ((noinline))
+do_test (void)
+{
+  lzcnt_test ();
+}
+
+int
+main ()
+{
+  unsigned int eax, ebx, ecx, edx;
+
+  if (!__get_cpuid (0x80000001, &eax, &ebx, &ecx, &edx))
+    return 0;
+
+  /* Run LZCNT test only if host has LZCNT support.  */
+  if (ecx & bit_LZCNT)
+    {
+      do_test ();
+#ifdef DEBUG
+      printf ("PASSED\n");
+#endif
+    }
+#ifdef DEBUG
+  else
+    printf ("SKIPPED\n");
+#endif
+
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/i386/sse-12.c b/gcc/testsuite/gcc.target/i386/sse-12.c
index 4f8aaec..59e659e 100644
--- a/gcc/testsuite/gcc.target/i386/sse-12.c
+++ b/gcc/testsuite/gcc.target/i386/sse-12.c
@@ -3,7 +3,7 @@
    popcntintrin.h and mm_malloc.h are usable
    with -O -std=c89 -pedantic-errors.  */
 /* { dg-do compile } */
-/* { dg-options "-O -std=c89 -pedantic-errors -march=k8 -msse4a -m3dnow -mavx -mfma4 -mxop -maes -mpclmul -mpopcnt -mabm -mbmi -mtbm -mlwp -mfsgsbase -mrdrnd -mf16c" } */
+/* { dg-options "-O -std=c89 -pedantic-errors -march=k8 -msse4a -m3dnow -mavx -mfma4 -mxop -maes -mpclmul -mpopcnt -mabm -mlzcnt -mbmi -mtbm -mlwp -mfsgsbase -mrdrnd -mf16c" } */
 
 #include <x86intrin.h>
 
diff --git a/gcc/testsuite/gcc.target/i386/sse-13.c b/gcc/testsuite/gcc.target/i386/sse-13.c
index 188b2e6..836272d 100644
--- a/gcc/testsuite/gcc.target/i386/sse-13.c
+++ b/gcc/testsuite/gcc.target/i386/sse-13.c
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O2 -Werror-implicit-function-declaration -march=k8 -msse4a -m3dnow -mavx -mfma4 -mxop -maes -mpclmul -mpopcnt -mabm -mbmi -mtbm -mlwp -mfsgsbase -mrdrnd -mf16c" } */
+/* { dg-options "-O2 -Werror-implicit-function-declaration -march=k8 -msse4a -m3dnow -mavx -mfma4 -mxop -maes -mpclmul -mpopcnt -mabm -mlzcnt -mbmi -mtbm -mlwp -mfsgsbase -mrdrnd -mf16c" } */
 
 #include <mm_malloc.h>
 
diff --git a/gcc/testsuite/gcc.target/i386/sse-14.c b/gcc/testsuite/gcc.target/i386/sse-14.c
index 22ea61f..af42781 100644
--- a/gcc/testsuite/gcc.target/i386/sse-14.c
+++ b/gcc/testsuite/gcc.target/i386/sse-14.c
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O0 -Werror-implicit-function-declaration -march=k8 -msse4a -m3dnow -mavx -mfma4 -mxop -maes -mpclmul -mpopcnt -mabm -mbmi -mtbm -mlwp -mfsgsbase -mrdrnd -mf16c" } */
+/* { dg-options "-O0 -Werror-implicit-function-declaration -march=k8 -msse4a -m3dnow -mavx -mfma4 -mxop -maes -mpclmul -mpopcnt -mabm -mlzcnt -mbmi -mtbm -mlwp -mfsgsbase -mrdrnd -mf16c" } */
 
 #include <mm_malloc.h>
 

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [Patch, i386, testsuite] Fix for PR49547, new tescases for lzcnt instruction
  2011-07-27 19:14                           ` Kirill Yukhin
@ 2011-08-01  8:22                             ` Kirill Yukhin
  2011-08-01  8:37                               ` Uros Bizjak
  0 siblings, 1 reply; 25+ messages in thread
From: Kirill Yukhin @ 2011-08-01  8:22 UTC (permalink / raw)
  To: H.J. Lu; +Cc: Uros Bizjak, Mike Stump, gcc-patches List, Jagasia, Harsha

Ping.

--
K

On Wed, Jul 27, 2011 at 10:23 PM, Kirill Yukhin <kirill.yukhin@gmail.com> wrote:
> Okay, then here is an updated patch
>
> updated ChangeLog entry:
> 2011-07-26  Kirill Yukhin  <kirill.yukhin@intel.com>
>
>        PR target/49547
>        * config.gcc (i[34567]86-*-*): Replace abmintrin.h with
>        lzcntintrin.h.
>        (x86_64-*-*): Likewise.
>        * config/i386/i386.opt (mlzcnt): New.
>        * config/i386/abmintrin.h: File removed.
>        (__lzcnt_u16, __lzcnt, __lzcnt_u64): Moved to ...
>        * config/i386/lzcntintrin.h: ... here. New file.
>        (__lzcnt): Rename to ...
>        (__lzcnt32): ... this.
>        * config/i386/bmiintrin.h (head): Update copyright year.
>        (__lzcnt_u16): Removed.
>        (__lzcnt_u32): Likewise.
>        (__lzcnt_u64): Likewise.
>        * config/i386/x86intrin.h: Include lzcntintrin.h when __LZCNT__
>        is defined, remove abmintrin.h.
>        * config/i386/cpuid.h: New define.
>        * config/i386/driver-i386.c (host_detect_local_cpu): Detect
>        LZCNT feature.
>        * config/i386/i386-c.c (ix86_target_macros_internal): Define
>        __LZCNT__ if needed.
>        * config/i386/i386.c (ix86_target_string): New option -mlzcnt.
>        (ix86_option_override_internal): Handle LZCNT option.
>        (ix86_valid_target_attribute_inner_p): Likewise.
>        (struct builtin_description bdesc_args) <IX86_BUILTIN_CLZS>: Update.
>        * config/i386/i386.h (TARGET_LZCNT): New.
>        (CLZ_DEFINED_VALUE_AT_ZERO): Update.
>        * config/i386/i386.md (clz<mode>2): Update insn constraint.
>        (clz<mode>2_lzcnt): Likewise.
>        * doc/invoke.texi: Mention -mlzcnt option.
>        * doc/extend.texi: Likewise.
>
> Bootstrapped successfully.
> Ok?
>
> K
>
> On Wed, Jul 27, 2011 at 8:51 PM, H.J. Lu <hjl.tools@gmail.com> wrote:
>> On Wed, Jul 27, 2011 at 9:49 AM, Uros Bizjak <ubizjak@gmail.com> wrote:
>>> On Wed, Jul 27, 2011 at 6:12 PM, Kirill Yukhin <kirill.yukhin@gmail.com> wrote:
>>>> Than as it is ABM header, it should include two headers: lzcntinrin.h
>>>> and popcntintrin.h
>>>>
>>>> But again, it seems useless to me. If we cannot remove empty header,
>>>> let it stay empty...
>>>>
>>>> K
>>>>
>>>> On Wed, Jul 27, 2011 at 7:53 PM, H.J. Lu <hjl.tools@gmail.com> wrote:
>>>>> On Wed, Jul 27, 2011 at 8:45 AM, Kirill Yukhin <kirill.yukhin@gmail.com> wrote:
>>>>>> Just have a closer look to ABM intrinsics support in GCC
>>>>>> Seems, we have popcnt support in separate file: popcntintrin.h
>>>>>>
>>>>>> So, after I move lzcnt intrinsics to lzcntintrin.h, abmintrin will
>>>>>> become useless and have to be removed at all
>>>>>
>>>>> We can't remove an installed header file.  It should just include
>>>>> other header files.
>>>
>>> ambintrin.h has:
>>>
>>> #ifndef _X86INTRIN_H_INCLUDED
>>> # error "Never use <abmintrin.h> directly; include <x86intrin.h> instead."
>>> #endif
>>>
>>> I see no problem in removing this header. It is not possible to
>>> #include it directly.
>>>
>>
>> Sounds good to me.
>>
>> --
>> H.J.
>>
>

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [Patch, i386, testsuite] Fix for PR49547, new tescases for lzcnt instruction
  2011-08-01  8:22                             ` Kirill Yukhin
@ 2011-08-01  8:37                               ` Uros Bizjak
  2011-08-01  9:04                                 ` Kirill Yukhin
  0 siblings, 1 reply; 25+ messages in thread
From: Uros Bizjak @ 2011-08-01  8:37 UTC (permalink / raw)
  To: Kirill Yukhin; +Cc: H.J. Lu, Mike Stump, gcc-patches List, Jagasia, Harsha

On Mon, Aug 1, 2011 at 10:21 AM, Kirill Yukhin <kirill.yukhin@gmail.com> wrote:

>> Okay, then here is an updated patch
>>
>> updated ChangeLog entry:
>> 2011-07-26  Kirill Yukhin  <kirill.yukhin@intel.com>
>>
>>        PR target/49547
>>        * config.gcc (i[34567]86-*-*): Replace abmintrin.h with
>>        lzcntintrin.h.
>>        (x86_64-*-*): Likewise.
>>        * config/i386/i386.opt (mlzcnt): New.
>>        * config/i386/abmintrin.h: File removed.
>>        (__lzcnt_u16, __lzcnt, __lzcnt_u64): Moved to ...
>>        * config/i386/lzcntintrin.h: ... here. New file.
>>        (__lzcnt): Rename to ...
>>        (__lzcnt32): ... this.
>>        * config/i386/bmiintrin.h (head): Update copyright year.
>>        (__lzcnt_u16): Removed.
>>        (__lzcnt_u32): Likewise.
>>        (__lzcnt_u64): Likewise.
>>        * config/i386/x86intrin.h: Include lzcntintrin.h when __LZCNT__
>>        is defined, remove abmintrin.h.
>>        * config/i386/cpuid.h: New define.
>>        * config/i386/driver-i386.c (host_detect_local_cpu): Detect
>>        LZCNT feature.
>>        * config/i386/i386-c.c (ix86_target_macros_internal): Define
>>        __LZCNT__ if needed.
>>        * config/i386/i386.c (ix86_target_string): New option -mlzcnt.
>>        (ix86_option_override_internal): Handle LZCNT option.
>>        (ix86_valid_target_attribute_inner_p): Likewise.
>>        (struct builtin_description bdesc_args) <IX86_BUILTIN_CLZS>: Update.
>>        * config/i386/i386.h (TARGET_LZCNT): New.
>>        (CLZ_DEFINED_VALUE_AT_ZERO): Update.
>>        * config/i386/i386.md (clz<mode>2): Update insn constraint.
>>        (clz<mode>2_lzcnt): Likewise.
>>        * doc/invoke.texi: Mention -mlzcnt option.
>>        * doc/extend.texi: Likewise.
>>
>> Bootstrapped successfully.

OK for mainline.

Uros.

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [Patch, i386, testsuite] Fix for PR49547, new tescases for lzcnt instruction
  2011-08-01  8:37                               ` Uros Bizjak
@ 2011-08-01  9:04                                 ` Kirill Yukhin
  2011-08-01 12:21                                   ` Kirill Yukhin
  0 siblings, 1 reply; 25+ messages in thread
From: Kirill Yukhin @ 2011-08-01  9:04 UTC (permalink / raw)
  To: Uros Bizjak; +Cc: H.J. Lu, Mike Stump, gcc-patches List, Jagasia, Harsha

Thanks!
Guys with waa rights, could anybody commit my fix?

Thanks, K

>
> OK for mainline.
>
> Uros.
>

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [Patch, i386, testsuite] Fix for PR49547, new tescases for lzcnt instruction
  2011-08-01  9:04                                 ` Kirill Yukhin
@ 2011-08-01 12:21                                   ` Kirill Yukhin
  2011-08-01 12:26                                     ` H.J. Lu
  0 siblings, 1 reply; 25+ messages in thread
From: Kirill Yukhin @ 2011-08-01 12:21 UTC (permalink / raw)
  To: Uros Bizjak; +Cc: H.J. Lu, Mike Stump, gcc-patches List, Jagasia, Harsha

[-- Attachment #1: Type: text/plain, Size: 332 bytes --]

I've merged my changes with trunk (there was a conflict) and fixed typo.
Updated patch is attached. Waiting for commit...

Thanks, K

On Mon, Aug 1, 2011 at 1:03 PM, Kirill Yukhin <kirill.yukhin@gmail.com> wrote:
> Thanks!
> Guys with waa rights, could anybody commit my fix?
>
> Thanks, K
>
>>
>> OK for mainline.
>>
>> Uros.
>>
>

[-- Attachment #2: lzcnt-5.gcc.patch --]
[-- Type: application/octet-stream, Size: 26732 bytes --]

diff --git a/gcc/config.gcc b/gcc/config.gcc
index 02cc556..94f15d8 100644
--- a/gcc/config.gcc
+++ b/gcc/config.gcc
@@ -352,7 +352,7 @@ i[34567]86-*-*)
 		       nmmintrin.h bmmintrin.h fma4intrin.h wmmintrin.h
 		       immintrin.h x86intrin.h avxintrin.h xopintrin.h
 		       ia32intrin.h cross-stdarg.h lwpintrin.h popcntintrin.h
-		       abmintrin.h bmiintrin.h tbmintrin.h"
+		       lzcntintrin.h bmiintrin.h tbmintrin.h"
 	;;
 x86_64-*-*)
 	cpu_type=i386
@@ -364,7 +364,7 @@ x86_64-*-*)
 		       nmmintrin.h bmmintrin.h fma4intrin.h wmmintrin.h
 		       immintrin.h x86intrin.h avxintrin.h xopintrin.h
 		       ia32intrin.h cross-stdarg.h lwpintrin.h popcntintrin.h
-		       abmintrin.h bmiintrin.h tbmintrin.h"
+		       lzcntintrin.h bmiintrin.h tbmintrin.h"
 	need_64bit_hwint=yes
 	;;
 ia64-*-*)
diff --git a/gcc/config/i386/abmintrin.h b/gcc/config/i386/abmintrin.h
deleted file mode 100644
index 9d87f57..0000000
--- a/gcc/config/i386/abmintrin.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/* Copyright (C) 2009 Free Software Foundation, Inc.
-
-   This file is part of GCC.
-
-   GCC is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3, or (at your option)
-   any later version.
-
-   GCC is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   Under Section 7 of GPL version 3, you are granted additional
-   permissions described in the GCC Runtime Library Exception, version
-   3.1, as published by the Free Software Foundation.
-
-   You should have received a copy of the GNU General Public License and
-   a copy of the GCC Runtime Library Exception along with this program;
-   see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
-   <http://www.gnu.org/licenses/>.  */
-
-#ifndef _X86INTRIN_H_INCLUDED
-# error "Never use <abmintrin.h> directly; include <x86intrin.h> instead."
-#endif
-
-#ifndef __ABM__
-# error "ABM instruction set not enabled"
-#endif /* __ABM__ */
-
-#ifndef _ABMINTRIN_H_INCLUDED
-#define _ABMINTRIN_H_INCLUDED
-
-extern __inline unsigned short __attribute__((__gnu_inline__, __always_inline__, __artificial__))
-__lzcnt16 (unsigned short __X)
-{
-  return __builtin_clzs (__X);
-}
-
-extern __inline unsigned int __attribute__((__gnu_inline__, __always_inline__, __artificial__))
-__lzcnt (unsigned int __X)
-{
-  return __builtin_clz (__X);
-}
-
-#ifdef __x86_64__
-extern __inline unsigned long __attribute__((__gnu_inline__, __always_inline__, __artificial__))
-__lzcnt64 (unsigned long __X)
-{
-  return __builtin_clzl (__X);
-}
-#endif
-
-#endif /* _ABMINTRIN_H_INCLUDED */
diff --git a/gcc/config/i386/bmiintrin.h b/gcc/config/i386/bmiintrin.h
index 225f2ec..1699c61 100644
--- a/gcc/config/i386/bmiintrin.h
+++ b/gcc/config/i386/bmiintrin.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2010 Free Software Foundation, Inc.
+/* Copyright (C) 2010, 2011 Free Software Foundation, Inc.
 
    This file is part of GCC.
 
@@ -33,12 +33,6 @@
 #define _BMIINTRIN_H_INCLUDED
 
 extern __inline unsigned short __attribute__((__gnu_inline__, __always_inline__, __artificial__))
-__lzcnt_u16 (unsigned short __X)
-{
-  return __builtin_clzs (__X);
-}
-
-extern __inline unsigned short __attribute__((__gnu_inline__, __always_inline__, __artificial__))
 __tzcnt_u16 (unsigned short __X)
 {
   return __builtin_ctzs (__X);
@@ -79,12 +73,6 @@ __blsr_u32 (unsigned int __X)
   return tmp;
 }
 
-extern __inline unsigned int __attribute__((__gnu_inline__, __always_inline__, __artificial__))
-__lzcnt_u32 (unsigned int __X)
-{
-  return __builtin_clz (__X);
-}
-
 
 extern __inline unsigned int __attribute__((__gnu_inline__, __always_inline__, __artificial__))
 __tzcnt_u32 (unsigned int __X)
@@ -129,12 +117,6 @@ __blsr_u64 (unsigned long long __X)
 }
 
 extern __inline unsigned long long __attribute__((__gnu_inline__, __always_inline__, __artificial__))
-__lzcnt_u64 (unsigned long long __X)
-{
-  return __builtin_clzll (__X);
-}
-
-extern __inline unsigned long long __attribute__((__gnu_inline__, __always_inline__, __artificial__))
 __tzcnt_u64 (unsigned long long __X)
 {
   return __builtin_ctzll (__X);
diff --git a/gcc/config/i386/cpuid.h b/gcc/config/i386/cpuid.h
index 3c3f47b..8826c28 100644
--- a/gcc/config/i386/cpuid.h
+++ b/gcc/config/i386/cpuid.h
@@ -24,6 +24,7 @@
 /* %ecx */
 #define bit_SSE3	(1 << 0)
 #define bit_PCLMUL	(1 << 1)
+#define bit_LZCNT	(1 << 5)
 #define bit_SSSE3	(1 << 9)
 #define bit_FMA		(1 << 12)
 #define bit_CMPXCHG16B	(1 << 13)
diff --git a/gcc/config/i386/driver-i386.c b/gcc/config/i386/driver-i386.c
index ecd8958..5823987 100644
--- a/gcc/config/i386/driver-i386.c
+++ b/gcc/config/i386/driver-i386.c
@@ -396,7 +396,7 @@ const char *host_detect_local_cpu (int argc, const char **argv)
   unsigned int has_popcnt = 0, has_aes = 0, has_avx = 0;
   unsigned int has_pclmul = 0, has_abm = 0, has_lwp = 0;
   unsigned int has_fma = 0, has_fma4 = 0, has_xop = 0;
-  unsigned int has_bmi = 0, has_tbm = 0;
+  unsigned int has_bmi = 0, has_tbm = 0, has_lzcnt = 0;
 
   bool arch;
 
@@ -465,6 +465,7 @@ const char *host_detect_local_cpu (int argc, const char **argv)
       has_fma4 = ecx & bit_FMA4;
       has_xop = ecx & bit_XOP;
       has_tbm = ecx & bit_TBM;
+      has_lzcnt = ecx & bit_LZCNT;
 
       has_longmode = edx & bit_LM;
       has_3dnowp = edx & bit_3DNOWP;
@@ -717,10 +718,11 @@ const char *host_detect_local_cpu (int argc, const char **argv)
       const char *avx = has_avx ? " -mavx" : " -mno-avx";
       const char *sse4_2 = has_sse4_2 ? " -msse4.2" : " -mno-sse4.2";
       const char *sse4_1 = has_sse4_1 ? " -msse4.1" : " -mno-sse4.1";
+      const char *lzcnt = has_lzcnt ? " -mlzcnt" : " -mnolzcnt";
 
       options = concat (options, cx16, sahf, movbe, ase, pclmul,
 			popcnt, abm, lwp, fma, fma4, xop, bmi, tbm,
-			avx, sse4_2, sse4_1, NULL);
+			avx, sse4_2, sse4_1, lzcnt, NULL);
     }
 
 done:
diff --git a/gcc/config/i386/i386-c.c b/gcc/config/i386/i386-c.c
index 5cbcfd5..1fc333c 100644
--- a/gcc/config/i386/i386-c.c
+++ b/gcc/config/i386/i386-c.c
@@ -271,6 +271,8 @@ ix86_target_macros_internal (int isa_flag,
     def_or_undef (parse_in, "__ABM__");
   if (isa_flag & OPTION_MASK_ISA_BMI)
     def_or_undef (parse_in, "__BMI__");
+  if (isa_flag & OPTION_MASK_ISA_LZCNT)
+    def_or_undef (parse_in, "__LZCNT__");
   if (isa_flag & OPTION_MASK_ISA_TBM)
     def_or_undef (parse_in, "__TBM__");
   if (isa_flag & OPTION_MASK_ISA_POPCNT)
diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
index f751e74..5ffdf50 100644
--- a/gcc/config/i386/i386.c
+++ b/gcc/config/i386/i386.c
@@ -2663,6 +2663,7 @@ ix86_target_string (int isa, int flags, const char *arch, const char *tune,
     { "-mmmx",		OPTION_MASK_ISA_MMX },
     { "-mabm",		OPTION_MASK_ISA_ABM },
     { "-mbmi",		OPTION_MASK_ISA_BMI },
+    { "-mlzcnt",	OPTION_MASK_ISA_LZCNT },
     { "-mtbm",		OPTION_MASK_ISA_TBM },
     { "-mpopcnt",	OPTION_MASK_ISA_POPCNT },
     { "-mmovbe",	OPTION_MASK_ISA_MOVBE },
@@ -2917,7 +2918,8 @@ ix86_option_override_internal (bool main_args_p)
       PTA_RDRND = 1 << 25,
       PTA_F16C = 1 << 26,
       PTA_BMI = 1 << 27,
-      PTA_TBM = 1 << 28
+      PTA_TBM = 1 << 28,
+      PTA_LZCNT = 1 << 29
       /* if this reaches 32, need to widen struct pta flags below */
     };
 
@@ -3278,6 +3280,9 @@ ix86_option_override_internal (bool main_args_p)
 	if (processor_alias_table[i].flags & PTA_BMI
 	    && !(ix86_isa_flags_explicit & OPTION_MASK_ISA_BMI))
 	  ix86_isa_flags |= OPTION_MASK_ISA_BMI;
+	if (processor_alias_table[i].flags & (PTA_LZCNT | PTA_ABM)
+	    && !(ix86_isa_flags_explicit & OPTION_MASK_ISA_LZCNT))
+	  ix86_isa_flags |= OPTION_MASK_ISA_LZCNT;
 	if (processor_alias_table[i].flags & PTA_TBM
 	    && !(ix86_isa_flags_explicit & OPTION_MASK_ISA_TBM))
 	  ix86_isa_flags |= OPTION_MASK_ISA_TBM;
@@ -3525,6 +3530,10 @@ ix86_option_override_internal (bool main_args_p)
   if (TARGET_SSE4_2 || TARGET_ABM)
     ix86_isa_flags |= OPTION_MASK_ISA_POPCNT & ~ix86_isa_flags_explicit;
 
+  /* Turn on lzcnt instruction for -mabm.  */
+  if (TARGET_ABM)
+    ix86_isa_flags |= OPTION_MASK_ISA_LZCNT & ~ix86_isa_flags_explicit;
+
   /* Validate -mpreferred-stack-boundary= value or default it to
      PREFERRED_STACK_BOUNDARY_DEFAULT.  */
   ix86_preferred_stack_boundary = PREFERRED_STACK_BOUNDARY_DEFAULT;
@@ -4030,6 +4039,7 @@ ix86_valid_target_attribute_inner_p (tree args, char *p_strings[],
     IX86_ATTR_ISA ("3dnow",	OPT_m3dnow),
     IX86_ATTR_ISA ("abm",	OPT_mabm),
     IX86_ATTR_ISA ("bmi",	OPT_mbmi),
+    IX86_ATTR_ISA ("lzcnt",	OPT_mlzcnt),
     IX86_ATTR_ISA ("tbm",	OPT_mtbm),
     IX86_ATTR_ISA ("aes",	OPT_maes),
     IX86_ATTR_ISA ("avx",	OPT_mavx),
@@ -24939,7 +24949,7 @@ static const struct builtin_description bdesc_args[] =
   { OPTION_MASK_ISA_AVX, CODE_FOR_copysignv8sf3,  "__builtin_ia32_copysignps256", IX86_BUILTIN_CPYSGNPS256, UNKNOWN, (int) V8SF_FTYPE_V8SF_V8SF },
   { OPTION_MASK_ISA_AVX, CODE_FOR_copysignv4df3,  "__builtin_ia32_copysignpd256", IX86_BUILTIN_CPYSGNPD256, UNKNOWN, (int) V4DF_FTYPE_V4DF_V4DF },
 
-  { OPTION_MASK_ISA_ABM, CODE_FOR_clzhi2_abm,   "__builtin_clzs",   IX86_BUILTIN_CLZS,    UNKNOWN,     (int) UINT16_FTYPE_UINT16 },
+  { OPTION_MASK_ISA_LZCNT, CODE_FOR_clzhi2_lzcnt,   "__builtin_clzs",   IX86_BUILTIN_CLZS,    UNKNOWN,     (int) UINT16_FTYPE_UINT16 },
 
   /* BMI */
   { OPTION_MASK_ISA_BMI, CODE_FOR_bmi_bextr_si, "__builtin_ia32_bextr_u32", IX86_BUILTIN_BEXTR32, UNKNOWN, (int) UINT_FTYPE_UINT_UINT },
diff --git a/gcc/config/i386/i386.h b/gcc/config/i386/i386.h
index 20c9a8f..f43586d 100644
--- a/gcc/config/i386/i386.h
+++ b/gcc/config/i386/i386.h
@@ -61,6 +61,7 @@ see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
 #define TARGET_ROUND	OPTION_ISA_ROUND
 #define TARGET_ABM	OPTION_ISA_ABM
 #define TARGET_BMI	OPTION_ISA_BMI
+#define TARGET_LZCNT	OPTION_ISA_LZCNT
 #define TARGET_TBM	OPTION_ISA_TBM
 #define TARGET_POPCNT	OPTION_ISA_POPCNT
 #define TARGET_SAHF	OPTION_ISA_SAHF
@@ -2288,7 +2289,7 @@ extern void debug_dispatch_window (int);
 #define CTZ_DEFINED_VALUE_AT_ZERO(MODE, VALUE) \
 	((VALUE) = GET_MODE_BITSIZE (MODE), TARGET_BMI)
 #define CLZ_DEFINED_VALUE_AT_ZERO(MODE, VALUE) \
-	((VALUE) = GET_MODE_BITSIZE (MODE), TARGET_BMI)
+	((VALUE) = GET_MODE_BITSIZE (MODE), TARGET_LZCNT)
 
 
 /* Flags returned by ix86_get_callcvt ().  */
diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md
index 5dfa43e..0c78f92 100644
--- a/gcc/config/i386/i386.md
+++ b/gcc/config/i386/i386.md
@@ -11801,19 +11801,19 @@
       (clobber (reg:CC FLAGS_REG))])]
   ""
 {
-  if (TARGET_ABM)
+  if (TARGET_LZCNT)
     {
-      emit_insn (gen_clz<mode>2_abm (operands[0], operands[1]));
+      emit_insn (gen_clz<mode>2_lzcnt (operands[0], operands[1]));
       DONE;
     }
   operands[2] = GEN_INT (GET_MODE_BITSIZE (<MODE>mode)-1);
 })
 
-(define_insn "clz<mode>2_abm"
+(define_insn "clz<mode>2_lzcnt"
   [(set (match_operand:SWI248 0 "register_operand" "=r")
 	(clz:SWI248 (match_operand:SWI248 1 "nonimmediate_operand" "rm")))
    (clobber (reg:CC FLAGS_REG))]
-  "TARGET_ABM || TARGET_BMI"
+  "TARGET_LZCNT"
   "lzcnt{<imodesuffix>}\t{%1, %0|%0, %1}"
   [(set_attr "prefix_rep" "1")
    (set_attr "type" "bitmanip")
diff --git a/gcc/config/i386/i386.opt b/gcc/config/i386/i386.opt
index 5e6b5df..f197dd8 100644
--- a/gcc/config/i386/i386.opt
+++ b/gcc/config/i386/i386.opt
@@ -489,6 +489,10 @@ mbmi
 Target Report Mask(ISA_BMI) Var(ix86_isa_flags) Save
 Support BMI built-in functions and code generation
 
+mlzcnt
+Target Report Mask(ISA_LZCNT) Var(ix86_isa_flags) Save
+Support LZCNT built-in function and code generation
+
 mtbm
 Target Report Mask(ISA_TBM) Var(ix86_isa_flags) Save
 Support TBM built-in functions and code generation
diff --git a/gcc/config/i386/lzcntintrin.h b/gcc/config/i386/lzcntintrin.h
new file mode 100644
index 0000000..4300811
--- /dev/null
+++ b/gcc/config/i386/lzcntintrin.h
@@ -0,0 +1,55 @@
+/* Copyright (C) 2009 Free Software Foundation, Inc.
+
+   This file is part of GCC.
+
+   GCC is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3, or (at your option)
+   any later version.
+
+   GCC is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   Under Section 7 of GPL version 3, you are granted additional
+   permissions described in the GCC Runtime Library Exception, version
+   3.1, as published by the Free Software Foundation.
+
+   You should have received a copy of the GNU General Public License and
+   a copy of the GCC Runtime Library Exception along with this program;
+   see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#ifndef _X86INTRIN_H_INCLUDED
+# error "Never use <lzcntintrin.h> directly; include <x86intrin.h> instead."
+#endif
+
+#ifndef __LZCNT__
+# error "LZCNT instruction is not enabled"
+#endif /* __LZCNT__ */
+
+#ifndef _LZCNTINTRIN_H_INCLUDED
+#define _LZCNTINTRIN_H_INCLUDED
+
+extern __inline unsigned short __attribute__((__gnu_inline__, __always_inline__, __artificial__))
+__lzcnt16 (unsigned short __X)
+{
+  return __builtin_clzs (__X);
+}
+
+extern __inline unsigned int __attribute__((__gnu_inline__, __always_inline__, __artificial__))
+__lzcnt32 (unsigned int __X)
+{
+  return __builtin_clz (__X);
+}
+
+#ifdef __x86_64__
+extern __inline unsigned long __attribute__((__gnu_inline__, __always_inline__, __artificial__))
+__lzcnt64 (unsigned long __X)
+{
+  return __builtin_clzl (__X);
+}
+#endif
+
+#endif /* _LZCNTINTRIN_H_INCLUDED */
diff --git a/gcc/config/i386/x86intrin.h b/gcc/config/i386/x86intrin.h
index 36b43df..88456f9 100644
--- a/gcc/config/i386/x86intrin.h
+++ b/gcc/config/i386/x86intrin.h
@@ -77,10 +77,6 @@
 #include <lwpintrin.h>
 #endif
 
-#ifdef __ABM__
-#include <abmintrin.h>
-#endif
-
 #ifdef __BMI__
 #include <bmiintrin.h>
 #endif
@@ -89,6 +85,10 @@
 #include <tbmintrin.h>
 #endif
 
+#ifdef __LZCNT__
+#include <lzcntintrin.h>
+#endif
+
 #ifdef __POPCNT__
 #include <popcntintrin.h>
 #endif
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index 0c95a79..480a8b0 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -9676,6 +9676,11 @@ All of them generate the machine instruction that is part of the name.
 @smallexample
 unsigned int __builtin_ia32_bextr_u32(unsigned int, unsigned int);
 unsigned long long __builtin_ia32_bextr_u64 (unsigned long long, unsigned long long);
+@end smallexample
+
+The following built-in functions are available when @option{-mlzcnt} is used.
+All of them generate the machine instruction that is part of the name.
+@smallexample
 unsigned short __builtin_ia32_lzcnt_16(unsigned short);
 unsigned int __builtin_ia32_lzcnt_u32(unsigned int);
 unsigned long long __builtin_ia32_lzcnt_u64 (unsigned long long);
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index db9a5da..c378360 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -606,8 +606,8 @@ Objective-C and Objective-C++ Dialects}.
 -mcld -mcx16 -msahf -mmovbe -mcrc32 -mrecip -mvzeroupper @gol
 -mmmx  -msse  -msse2 -msse3 -mssse3 -msse4.1 -msse4.2 -msse4 -mavx @gol
 -maes -mpclmul -mfsgsbase -mrdrnd -mf16c -mfma @gol
--msse4a -m3dnow -mpopcnt -mabm -mbmi -mtbm -mfma4 -mxop -mlwp @gol
--mthreads  -mno-align-stringops  -minline-all-stringops @gol
+-msse4a -m3dnow -mpopcnt -mabm -mbmi -mtbm -mfma4 -mxop -mlzcnt @gol
+-mlwp -mthreads  -mno-align-stringops  -minline-all-stringops @gol
 -minline-stringops-dynamically -mstringop-strategy=@var{alg} @gol
 -mpush-args  -maccumulate-outgoing-args  -m128bit-long-double @gol
 -m96bit-long-double  -mregparm=@var{num}  -msseregparm @gol
@@ -12692,6 +12692,8 @@ preferred alignment to @option{-mpreferred-stack-boundary=2}.
 @itemx -mno-abm
 @itemx -mbmi
 @itemx -mno-bmi
+@itemx -mlzcnt
+@itemx -mno-lzcnt
 @itemx -mtbm
 @itemx -mno-tbm
 @opindex mmmx
@@ -12702,7 +12704,7 @@ preferred alignment to @option{-mpreferred-stack-boundary=2}.
 @opindex mno-3dnow
 These switches enable or disable the use of instructions in the MMX, SSE,
 SSE2, SSE3, SSSE3, SSE4.1, AVX, AES, PCLMUL, FSGSBASE, RDRND, F16C, FMA,
-SSE4A, FMA4, XOP, LWP, ABM, BMI, or 3DNow!@: extended instruction sets.
+SSE4A, FMA4, XOP, LWP, ABM, BMI, LZCNT or 3DNow!@: extended instruction sets.
 These extensions are also available as built-in functions: see
 @ref{X86 Built-in Functions}, for details of the functions enabled and
 disabled by these switches.
diff --git a/gcc/testsuite/g++.dg/other/i386-2.C b/gcc/testsuite/g++.dg/other/i386-2.C
index 1a445f1..ed183c7 100644
--- a/gcc/testsuite/g++.dg/other/i386-2.C
+++ b/gcc/testsuite/g++.dg/other/i386-2.C
@@ -1,5 +1,5 @@
 /* { dg-do compile { target i?86-*-* x86_64-*-* } } */
-/* { dg-options "-O -pedantic-errors -march=k8 -msse4a -m3dnow -mavx -mfma4 -mxop -maes -mpclmul -mpopcnt -mabm -mbmi -mtbm -mlwp -mfsgsbase -mrdrnd -mf16c" } */
+/* { dg-options "-O -pedantic-errors -march=k8 -msse4a -m3dnow -mavx -mfma4 -mxop -maes -mpclmul -mpopcnt -mabm -mlzcnt -mbmi -mtbm -mlwp -mfsgsbase -mrdrnd -mf16c" } */
 
 /* Test that {,x,e,p,t,s,w,a,b,i}mmintrin.h, mm3dnow.h, fma4intrin.h,
    xopintrin.h, abmintrin.h, bmiintrin.h, tbmintrin.h, lwpintrin.h,
diff --git a/gcc/testsuite/g++.dg/other/i386-3.C b/gcc/testsuite/g++.dg/other/i386-3.C
index 66eec14..626f972 100644
--- a/gcc/testsuite/g++.dg/other/i386-3.C
+++ b/gcc/testsuite/g++.dg/other/i386-3.C
@@ -1,5 +1,5 @@
 /* { dg-do compile { target i?86-*-* x86_64-*-* } } */
-/* { dg-options "-O -fkeep-inline-functions -march=k8 -msse4a -m3dnow -mavx -mfma4 -mxop -maes -mpclmul -mpopcnt -mabm -mbmi -mtbm -mlwp -mfsgsbase -mrdrnd -mf16c" } */
+/* { dg-options "-O -fkeep-inline-functions -march=k8 -msse4a -m3dnow -mavx -mfma4 -mxop -maes -mpclmul -mpopcnt -mabm -mlzcnt -mbmi -mtbm -mlwp -mfsgsbase -mrdrnd -mf16c" } */
 
 /* Test that {,x,e,p,t,s,w,a,b,i}mmintrin.h, mm3dnow.h, fma4intrin.h,
    xopintrin.h, abmintrin.h, bmiintrin.h, tbmintrin.h, lwpintrin.h,
diff --git a/gcc/testsuite/gcc.target/i386/i386.exp b/gcc/testsuite/gcc.target/i386/i386.exp
index 13d8cff..c9698fb 100644
--- a/gcc/testsuite/gcc.target/i386/i386.exp
+++ b/gcc/testsuite/gcc.target/i386/i386.exp
@@ -186,6 +186,16 @@ proc check_effective_target_xop { } {
     } "-O2 -mxop" ]
 }
 
+# Return 1 if lzcnt instruction can be compiled.
+proc check_effective_target_lzcnt { } {
+    return [check_no_compiler_messages lzcnt object {
+	void _lzcnt (void)
+	{
+	   __builtin_clzs (0);
+	}
+    } "-O2 -mlzcnt" ]
+}
+
 # Return 1 if bmi instructions can be compiled.
 proc check_effective_target_bmi { } {
     return [check_no_compiler_messages bmi object {
diff --git a/gcc/testsuite/gcc.target/i386/lzcnt-1.c b/gcc/testsuite/gcc.target/i386/lzcnt-1.c
new file mode 100644
index 0000000..f6240d1b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/lzcnt-1.c
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -mlzcnt " } */
+/* { dg-final { scan-assembler "lzcntw\[^\\n]*(%|)ax" } } */
+
+#include <x86intrin.h>
+
+unsigned int
+func_lzcnt16 (unsigned int X)
+{
+  return __lzcnt16(X);
+}
diff --git a/gcc/testsuite/gcc.target/i386/lzcnt-2.c b/gcc/testsuite/gcc.target/i386/lzcnt-2.c
new file mode 100644
index 0000000..329a11f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/lzcnt-2.c
@@ -0,0 +1,35 @@
+/* { dg-do run { target { lzcnt } } } */
+/* { dg-options "-O2 -mlzcnt -fno-inline" } */
+
+#include <x86intrin.h>
+
+#include "lzcnt-check.h"
+
+short calc_lzcnt_u16 (short src)
+{
+  int i;
+  short res = 0;
+
+  while ((res < 16) && (((src >> (15 - res)) & 1) == 0))
+    ++res;
+
+  return res;
+}
+
+static void
+lzcnt_test ()
+{
+  unsigned i;
+  short src = 0x7ace;
+  short res, res_ref;
+
+  for (i=0; i<5; ++i) {
+    src = src >> i;
+
+    res_ref = calc_lzcnt_u16 (src);
+    res = __lzcnt16 (src);
+
+    if (res != res_ref)
+      abort();
+  }
+}
diff --git a/gcc/testsuite/gcc.target/i386/lzcnt-2a.c b/gcc/testsuite/gcc.target/i386/lzcnt-2a.c
new file mode 100644
index 0000000..fe1069f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/lzcnt-2a.c
@@ -0,0 +1,6 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -mlzcnt" } */
+
+#include "lzcnt-2.c"
+
+/* { dg-final { scan-assembler "lzcntw" } } */
diff --git a/gcc/testsuite/gcc.target/i386/lzcnt-3.c b/gcc/testsuite/gcc.target/i386/lzcnt-3.c
new file mode 100644
index 0000000..1477951
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/lzcnt-3.c
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-options "-O0 -mlzcnt " } */
+/* { dg-final { scan-assembler "lzcntl\[^\\n]*(%|)eax" } } */
+
+#include <x86intrin.h>
+
+unsigned int
+func_lzcnt32 (unsigned int X)
+{
+  return __lzcnt32(X);
+}
diff --git a/gcc/testsuite/gcc.target/i386/lzcnt-4.c b/gcc/testsuite/gcc.target/i386/lzcnt-4.c
new file mode 100644
index 0000000..2065326
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/lzcnt-4.c
@@ -0,0 +1,35 @@
+/* { dg-do run { target { lzcnt } } } */
+/* { dg-options "-O2 -mlzcnt -fno-inline" } */
+
+#include <x86intrin.h>
+
+#include "lzcnt-check.h"
+
+int calc_lzcnt_u32 (int src)
+{
+  int i;
+  int res = 0;
+
+  while ((res < 32) && (((src >> (31 - res)) & 1) == 0))
+    ++res;
+
+  return res;
+}
+
+static void
+lzcnt_test ()
+{
+  unsigned i;
+  int src = 0xce7ace0;
+  int res, res_ref;
+
+  for (i=0; i<5; ++i) {
+    src = src >> i;
+
+    res_ref = calc_lzcnt_u32 (src);
+    res = __lzcnt32 (src);
+
+    if (res != res_ref)
+      abort();
+  }
+}
diff --git a/gcc/testsuite/gcc.target/i386/lzcnt-4a.c b/gcc/testsuite/gcc.target/i386/lzcnt-4a.c
new file mode 100644
index 0000000..6bba6a9
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/lzcnt-4a.c
@@ -0,0 +1,6 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -mlzcnt" } */
+
+#include "lzcnt-4.c"
+
+/* { dg-final { scan-assembler "lzcntl" } } */
diff --git a/gcc/testsuite/gcc.target/i386/lzcnt-5.c b/gcc/testsuite/gcc.target/i386/lzcnt-5.c
new file mode 100644
index 0000000..a4b9aaf
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/lzcnt-5.c
@@ -0,0 +1,11 @@
+/* { dg-do compile { target { ! ia32 } } } */
+/* { dg-options "-O2 -mlzcnt" } */
+/* { dg-final { scan-assembler "lzcntq\[^\\n]*(%|)rax" } } */
+
+#include <x86intrin.h>
+
+unsigned int
+func_lzcnt64 (unsigned long long X)
+{
+  return __lzcnt64(X);
+}
diff --git a/gcc/testsuite/gcc.target/i386/lzcnt-6.c b/gcc/testsuite/gcc.target/i386/lzcnt-6.c
new file mode 100644
index 0000000..f0bf5da
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/lzcnt-6.c
@@ -0,0 +1,35 @@
+/* { dg-do run { target { lzcnt && { ! ia32 } } } } */
+/* { dg-options "-O2 -mlzcnt -fno-inline" } */
+
+#include <x86intrin.h>
+
+#include "lzcnt-check.h"
+
+long long calc_lzcnt_u64 (long long src)
+{
+  int i;
+  int res = 0;
+
+  while ((res < 64) && (((src >> (63 - res)) & 1) == 0))
+    ++res;
+
+  return res;
+}
+
+static void
+lzcnt_test ()
+{
+  unsigned i;
+  long long src = 0xce7ace0ce7ace0;
+  long long res, res_ref;
+
+  for (i=0; i<5; ++i) {
+    src = src >> i;
+
+    res_ref = calc_lzcnt_u64 (src);
+    res = __lzcnt64 (src);
+
+    if (res != res_ref)
+      abort();
+  }
+}
diff --git a/gcc/testsuite/gcc.target/i386/lzcnt-6a.c b/gcc/testsuite/gcc.target/i386/lzcnt-6a.c
new file mode 100644
index 0000000..2090093
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/lzcnt-6a.c
@@ -0,0 +1,6 @@
+/* { dg-do compile { target { ! ia32 } } } */
+/* { dg-options "-O2 -mlzcnt" } */
+
+#include "lzcnt-6.c"
+
+/* { dg-final { scan-assembler "lzcntq" } } */
diff --git a/gcc/testsuite/gcc.target/i386/lzcnt-check.h b/gcc/testsuite/gcc.target/i386/lzcnt-check.h
new file mode 100644
index 0000000..8aad834
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/lzcnt-check.h
@@ -0,0 +1,37 @@
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "cpuid.h"
+
+static void lzcnt_test (void);
+
+static void
+__attribute__ ((noinline))
+do_test (void)
+{
+  lzcnt_test ();
+}
+
+int
+main ()
+{
+  unsigned int eax, ebx, ecx, edx;
+
+  if (!__get_cpuid (0x80000001, &eax, &ebx, &ecx, &edx))
+    return 0;
+
+  /* Run LZCNT test only if host has LZCNT support.  */
+  if (ecx & bit_LZCNT)
+    {
+      do_test ();
+#ifdef DEBUG
+      printf ("PASSED\n");
+#endif
+    }
+#ifdef DEBUG
+  else
+    printf ("SKIPPED\n");
+#endif
+
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/i386/sse-12.c b/gcc/testsuite/gcc.target/i386/sse-12.c
index 4f8aaec..59e659e 100644
--- a/gcc/testsuite/gcc.target/i386/sse-12.c
+++ b/gcc/testsuite/gcc.target/i386/sse-12.c
@@ -3,7 +3,7 @@
    popcntintrin.h and mm_malloc.h are usable
    with -O -std=c89 -pedantic-errors.  */
 /* { dg-do compile } */
-/* { dg-options "-O -std=c89 -pedantic-errors -march=k8 -msse4a -m3dnow -mavx -mfma4 -mxop -maes -mpclmul -mpopcnt -mabm -mbmi -mtbm -mlwp -mfsgsbase -mrdrnd -mf16c" } */
+/* { dg-options "-O -std=c89 -pedantic-errors -march=k8 -msse4a -m3dnow -mavx -mfma4 -mxop -maes -mpclmul -mpopcnt -mabm -mlzcnt -mbmi -mtbm -mlwp -mfsgsbase -mrdrnd -mf16c" } */
 
 #include <x86intrin.h>
 
diff --git a/gcc/testsuite/gcc.target/i386/sse-13.c b/gcc/testsuite/gcc.target/i386/sse-13.c
index 188b2e6..836272d 100644
--- a/gcc/testsuite/gcc.target/i386/sse-13.c
+++ b/gcc/testsuite/gcc.target/i386/sse-13.c
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O2 -Werror-implicit-function-declaration -march=k8 -msse4a -m3dnow -mavx -mfma4 -mxop -maes -mpclmul -mpopcnt -mabm -mbmi -mtbm -mlwp -mfsgsbase -mrdrnd -mf16c" } */
+/* { dg-options "-O2 -Werror-implicit-function-declaration -march=k8 -msse4a -m3dnow -mavx -mfma4 -mxop -maes -mpclmul -mpopcnt -mabm -mlzcnt -mbmi -mtbm -mlwp -mfsgsbase -mrdrnd -mf16c" } */
 
 #include <mm_malloc.h>
 
diff --git a/gcc/testsuite/gcc.target/i386/sse-14.c b/gcc/testsuite/gcc.target/i386/sse-14.c
index 22ea61f..af42781 100644
--- a/gcc/testsuite/gcc.target/i386/sse-14.c
+++ b/gcc/testsuite/gcc.target/i386/sse-14.c
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O0 -Werror-implicit-function-declaration -march=k8 -msse4a -m3dnow -mavx -mfma4 -mxop -maes -mpclmul -mpopcnt -mabm -mbmi -mtbm -mlwp -mfsgsbase -mrdrnd -mf16c" } */
+/* { dg-options "-O0 -Werror-implicit-function-declaration -march=k8 -msse4a -m3dnow -mavx -mfma4 -mxop -maes -mpclmul -mpopcnt -mabm -mlzcnt -mbmi -mtbm -mlwp -mfsgsbase -mrdrnd -mf16c" } */
 
 #include <mm_malloc.h>
 

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [Patch, i386, testsuite] Fix for PR49547, new tescases for lzcnt instruction
  2011-08-01 12:21                                   ` Kirill Yukhin
@ 2011-08-01 12:26                                     ` H.J. Lu
  2011-08-01 12:36                                       ` Kirill Yukhin
  0 siblings, 1 reply; 25+ messages in thread
From: H.J. Lu @ 2011-08-01 12:26 UTC (permalink / raw)
  To: Kirill Yukhin; +Cc: Uros Bizjak, Mike Stump, gcc-patches List, Jagasia, Harsha

On Mon, Aug 1, 2011 at 5:20 AM, Kirill Yukhin <kirill.yukhin@gmail.com> wrote:
> I've merged my changes with trunk (there was a conflict) and fixed typo.
> Updated patch is attached. Waiting for commit...
>
> Thanks, K
>
> On Mon, Aug 1, 2011 at 1:03 PM, Kirill Yukhin <kirill.yukhin@gmail.com> wrote:
>> Thanks!
>> Guys with waa rights, could anybody commit my fix?
>>
>> Thanks, K
>>
>>>
>>> OK for mainline.
>>>
>>> Uros.
>>>
>>


+# Return 1 if lzcnt instruction can be compiled.
+proc check_effective_target_lzcnt { } {
+    return [check_no_compiler_messages lzcnt object {
+       void _lzcnt (void)
+       {
+          __builtin_clzs (0);
+       }
+    } "-O2 -mlzcnt" ]
+}

GCC may optimize this away.  Please fix it similar to:

http://gcc.gnu.org/ml/gcc-patches/2011-07/msg02463.html

-- 
H.J.

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [Patch, i386, testsuite] Fix for PR49547, new tescases for lzcnt instruction
  2011-08-01 12:26                                     ` H.J. Lu
@ 2011-08-01 12:36                                       ` Kirill Yukhin
  2011-08-01 12:50                                         ` H.J. Lu
  0 siblings, 1 reply; 25+ messages in thread
From: Kirill Yukhin @ 2011-08-01 12:36 UTC (permalink / raw)
  To: H.J. Lu; +Cc: Uros Bizjak, Mike Stump, gcc-patches List, Jagasia, Harsha

[-- Attachment #1: Type: text/plain, Size: 1057 bytes --]

Hi HJ,
Thanks for input. I've missed it.
Done. Updated patch is attached.

Thanks, K

On Mon, Aug 1, 2011 at 4:26 PM, H.J. Lu <hjl.tools@gmail.com> wrote:
> On Mon, Aug 1, 2011 at 5:20 AM, Kirill Yukhin <kirill.yukhin@gmail.com> wrote:
>> I've merged my changes with trunk (there was a conflict) and fixed typo.
>> Updated patch is attached. Waiting for commit...
>>
>> Thanks, K
>>
>> On Mon, Aug 1, 2011 at 1:03 PM, Kirill Yukhin <kirill.yukhin@gmail.com> wrote:
>>> Thanks!
>>> Guys with waa rights, could anybody commit my fix?
>>>
>>> Thanks, K
>>>
>>>>
>>>> OK for mainline.
>>>>
>>>> Uros.
>>>>
>>>
>
>
> +# Return 1 if lzcnt instruction can be compiled.
> +proc check_effective_target_lzcnt { } {
> +    return [check_no_compiler_messages lzcnt object {
> +       void _lzcnt (void)
> +       {
> +          __builtin_clzs (0);
> +       }
> +    } "-O2 -mlzcnt" ]
> +}
>
> GCC may optimize this away.  Please fix it similar to:
>
> http://gcc.gnu.org/ml/gcc-patches/2011-07/msg02463.html
>
> --
> H.J.
>

[-- Attachment #2: lzcnt-5.gcc.patch --]
[-- Type: application/octet-stream, Size: 26745 bytes --]

diff --git a/gcc/config.gcc b/gcc/config.gcc
index 02cc556..94f15d8 100644
--- a/gcc/config.gcc
+++ b/gcc/config.gcc
@@ -352,7 +352,7 @@ i[34567]86-*-*)
 		       nmmintrin.h bmmintrin.h fma4intrin.h wmmintrin.h
 		       immintrin.h x86intrin.h avxintrin.h xopintrin.h
 		       ia32intrin.h cross-stdarg.h lwpintrin.h popcntintrin.h
-		       abmintrin.h bmiintrin.h tbmintrin.h"
+		       lzcntintrin.h bmiintrin.h tbmintrin.h"
 	;;
 x86_64-*-*)
 	cpu_type=i386
@@ -364,7 +364,7 @@ x86_64-*-*)
 		       nmmintrin.h bmmintrin.h fma4intrin.h wmmintrin.h
 		       immintrin.h x86intrin.h avxintrin.h xopintrin.h
 		       ia32intrin.h cross-stdarg.h lwpintrin.h popcntintrin.h
-		       abmintrin.h bmiintrin.h tbmintrin.h"
+		       lzcntintrin.h bmiintrin.h tbmintrin.h"
 	need_64bit_hwint=yes
 	;;
 ia64-*-*)
diff --git a/gcc/config/i386/abmintrin.h b/gcc/config/i386/abmintrin.h
deleted file mode 100644
index 9d87f57..0000000
--- a/gcc/config/i386/abmintrin.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/* Copyright (C) 2009 Free Software Foundation, Inc.
-
-   This file is part of GCC.
-
-   GCC is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3, or (at your option)
-   any later version.
-
-   GCC is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   Under Section 7 of GPL version 3, you are granted additional
-   permissions described in the GCC Runtime Library Exception, version
-   3.1, as published by the Free Software Foundation.
-
-   You should have received a copy of the GNU General Public License and
-   a copy of the GCC Runtime Library Exception along with this program;
-   see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
-   <http://www.gnu.org/licenses/>.  */
-
-#ifndef _X86INTRIN_H_INCLUDED
-# error "Never use <abmintrin.h> directly; include <x86intrin.h> instead."
-#endif
-
-#ifndef __ABM__
-# error "ABM instruction set not enabled"
-#endif /* __ABM__ */
-
-#ifndef _ABMINTRIN_H_INCLUDED
-#define _ABMINTRIN_H_INCLUDED
-
-extern __inline unsigned short __attribute__((__gnu_inline__, __always_inline__, __artificial__))
-__lzcnt16 (unsigned short __X)
-{
-  return __builtin_clzs (__X);
-}
-
-extern __inline unsigned int __attribute__((__gnu_inline__, __always_inline__, __artificial__))
-__lzcnt (unsigned int __X)
-{
-  return __builtin_clz (__X);
-}
-
-#ifdef __x86_64__
-extern __inline unsigned long __attribute__((__gnu_inline__, __always_inline__, __artificial__))
-__lzcnt64 (unsigned long __X)
-{
-  return __builtin_clzl (__X);
-}
-#endif
-
-#endif /* _ABMINTRIN_H_INCLUDED */
diff --git a/gcc/config/i386/bmiintrin.h b/gcc/config/i386/bmiintrin.h
index 225f2ec..1699c61 100644
--- a/gcc/config/i386/bmiintrin.h
+++ b/gcc/config/i386/bmiintrin.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2010 Free Software Foundation, Inc.
+/* Copyright (C) 2010, 2011 Free Software Foundation, Inc.
 
    This file is part of GCC.
 
@@ -33,12 +33,6 @@
 #define _BMIINTRIN_H_INCLUDED
 
 extern __inline unsigned short __attribute__((__gnu_inline__, __always_inline__, __artificial__))
-__lzcnt_u16 (unsigned short __X)
-{
-  return __builtin_clzs (__X);
-}
-
-extern __inline unsigned short __attribute__((__gnu_inline__, __always_inline__, __artificial__))
 __tzcnt_u16 (unsigned short __X)
 {
   return __builtin_ctzs (__X);
@@ -79,12 +73,6 @@ __blsr_u32 (unsigned int __X)
   return tmp;
 }
 
-extern __inline unsigned int __attribute__((__gnu_inline__, __always_inline__, __artificial__))
-__lzcnt_u32 (unsigned int __X)
-{
-  return __builtin_clz (__X);
-}
-
 
 extern __inline unsigned int __attribute__((__gnu_inline__, __always_inline__, __artificial__))
 __tzcnt_u32 (unsigned int __X)
@@ -129,12 +117,6 @@ __blsr_u64 (unsigned long long __X)
 }
 
 extern __inline unsigned long long __attribute__((__gnu_inline__, __always_inline__, __artificial__))
-__lzcnt_u64 (unsigned long long __X)
-{
-  return __builtin_clzll (__X);
-}
-
-extern __inline unsigned long long __attribute__((__gnu_inline__, __always_inline__, __artificial__))
 __tzcnt_u64 (unsigned long long __X)
 {
   return __builtin_ctzll (__X);
diff --git a/gcc/config/i386/cpuid.h b/gcc/config/i386/cpuid.h
index 3c3f47b..8826c28 100644
--- a/gcc/config/i386/cpuid.h
+++ b/gcc/config/i386/cpuid.h
@@ -24,6 +24,7 @@
 /* %ecx */
 #define bit_SSE3	(1 << 0)
 #define bit_PCLMUL	(1 << 1)
+#define bit_LZCNT	(1 << 5)
 #define bit_SSSE3	(1 << 9)
 #define bit_FMA		(1 << 12)
 #define bit_CMPXCHG16B	(1 << 13)
diff --git a/gcc/config/i386/driver-i386.c b/gcc/config/i386/driver-i386.c
index ecd8958..5823987 100644
--- a/gcc/config/i386/driver-i386.c
+++ b/gcc/config/i386/driver-i386.c
@@ -396,7 +396,7 @@ const char *host_detect_local_cpu (int argc, const char **argv)
   unsigned int has_popcnt = 0, has_aes = 0, has_avx = 0;
   unsigned int has_pclmul = 0, has_abm = 0, has_lwp = 0;
   unsigned int has_fma = 0, has_fma4 = 0, has_xop = 0;
-  unsigned int has_bmi = 0, has_tbm = 0;
+  unsigned int has_bmi = 0, has_tbm = 0, has_lzcnt = 0;
 
   bool arch;
 
@@ -465,6 +465,7 @@ const char *host_detect_local_cpu (int argc, const char **argv)
       has_fma4 = ecx & bit_FMA4;
       has_xop = ecx & bit_XOP;
       has_tbm = ecx & bit_TBM;
+      has_lzcnt = ecx & bit_LZCNT;
 
       has_longmode = edx & bit_LM;
       has_3dnowp = edx & bit_3DNOWP;
@@ -717,10 +718,11 @@ const char *host_detect_local_cpu (int argc, const char **argv)
       const char *avx = has_avx ? " -mavx" : " -mno-avx";
       const char *sse4_2 = has_sse4_2 ? " -msse4.2" : " -mno-sse4.2";
       const char *sse4_1 = has_sse4_1 ? " -msse4.1" : " -mno-sse4.1";
+      const char *lzcnt = has_lzcnt ? " -mlzcnt" : " -mnolzcnt";
 
       options = concat (options, cx16, sahf, movbe, ase, pclmul,
 			popcnt, abm, lwp, fma, fma4, xop, bmi, tbm,
-			avx, sse4_2, sse4_1, NULL);
+			avx, sse4_2, sse4_1, lzcnt, NULL);
     }
 
 done:
diff --git a/gcc/config/i386/i386-c.c b/gcc/config/i386/i386-c.c
index 5cbcfd5..1fc333c 100644
--- a/gcc/config/i386/i386-c.c
+++ b/gcc/config/i386/i386-c.c
@@ -271,6 +271,8 @@ ix86_target_macros_internal (int isa_flag,
     def_or_undef (parse_in, "__ABM__");
   if (isa_flag & OPTION_MASK_ISA_BMI)
     def_or_undef (parse_in, "__BMI__");
+  if (isa_flag & OPTION_MASK_ISA_LZCNT)
+    def_or_undef (parse_in, "__LZCNT__");
   if (isa_flag & OPTION_MASK_ISA_TBM)
     def_or_undef (parse_in, "__TBM__");
   if (isa_flag & OPTION_MASK_ISA_POPCNT)
diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
index f751e74..5ffdf50 100644
--- a/gcc/config/i386/i386.c
+++ b/gcc/config/i386/i386.c
@@ -2663,6 +2663,7 @@ ix86_target_string (int isa, int flags, const char *arch, const char *tune,
     { "-mmmx",		OPTION_MASK_ISA_MMX },
     { "-mabm",		OPTION_MASK_ISA_ABM },
     { "-mbmi",		OPTION_MASK_ISA_BMI },
+    { "-mlzcnt",	OPTION_MASK_ISA_LZCNT },
     { "-mtbm",		OPTION_MASK_ISA_TBM },
     { "-mpopcnt",	OPTION_MASK_ISA_POPCNT },
     { "-mmovbe",	OPTION_MASK_ISA_MOVBE },
@@ -2917,7 +2918,8 @@ ix86_option_override_internal (bool main_args_p)
       PTA_RDRND = 1 << 25,
       PTA_F16C = 1 << 26,
       PTA_BMI = 1 << 27,
-      PTA_TBM = 1 << 28
+      PTA_TBM = 1 << 28,
+      PTA_LZCNT = 1 << 29
       /* if this reaches 32, need to widen struct pta flags below */
     };
 
@@ -3278,6 +3280,9 @@ ix86_option_override_internal (bool main_args_p)
 	if (processor_alias_table[i].flags & PTA_BMI
 	    && !(ix86_isa_flags_explicit & OPTION_MASK_ISA_BMI))
 	  ix86_isa_flags |= OPTION_MASK_ISA_BMI;
+	if (processor_alias_table[i].flags & (PTA_LZCNT | PTA_ABM)
+	    && !(ix86_isa_flags_explicit & OPTION_MASK_ISA_LZCNT))
+	  ix86_isa_flags |= OPTION_MASK_ISA_LZCNT;
 	if (processor_alias_table[i].flags & PTA_TBM
 	    && !(ix86_isa_flags_explicit & OPTION_MASK_ISA_TBM))
 	  ix86_isa_flags |= OPTION_MASK_ISA_TBM;
@@ -3525,6 +3530,10 @@ ix86_option_override_internal (bool main_args_p)
   if (TARGET_SSE4_2 || TARGET_ABM)
     ix86_isa_flags |= OPTION_MASK_ISA_POPCNT & ~ix86_isa_flags_explicit;
 
+  /* Turn on lzcnt instruction for -mabm.  */
+  if (TARGET_ABM)
+    ix86_isa_flags |= OPTION_MASK_ISA_LZCNT & ~ix86_isa_flags_explicit;
+
   /* Validate -mpreferred-stack-boundary= value or default it to
      PREFERRED_STACK_BOUNDARY_DEFAULT.  */
   ix86_preferred_stack_boundary = PREFERRED_STACK_BOUNDARY_DEFAULT;
@@ -4030,6 +4039,7 @@ ix86_valid_target_attribute_inner_p (tree args, char *p_strings[],
     IX86_ATTR_ISA ("3dnow",	OPT_m3dnow),
     IX86_ATTR_ISA ("abm",	OPT_mabm),
     IX86_ATTR_ISA ("bmi",	OPT_mbmi),
+    IX86_ATTR_ISA ("lzcnt",	OPT_mlzcnt),
     IX86_ATTR_ISA ("tbm",	OPT_mtbm),
     IX86_ATTR_ISA ("aes",	OPT_maes),
     IX86_ATTR_ISA ("avx",	OPT_mavx),
@@ -24939,7 +24949,7 @@ static const struct builtin_description bdesc_args[] =
   { OPTION_MASK_ISA_AVX, CODE_FOR_copysignv8sf3,  "__builtin_ia32_copysignps256", IX86_BUILTIN_CPYSGNPS256, UNKNOWN, (int) V8SF_FTYPE_V8SF_V8SF },
   { OPTION_MASK_ISA_AVX, CODE_FOR_copysignv4df3,  "__builtin_ia32_copysignpd256", IX86_BUILTIN_CPYSGNPD256, UNKNOWN, (int) V4DF_FTYPE_V4DF_V4DF },
 
-  { OPTION_MASK_ISA_ABM, CODE_FOR_clzhi2_abm,   "__builtin_clzs",   IX86_BUILTIN_CLZS,    UNKNOWN,     (int) UINT16_FTYPE_UINT16 },
+  { OPTION_MASK_ISA_LZCNT, CODE_FOR_clzhi2_lzcnt,   "__builtin_clzs",   IX86_BUILTIN_CLZS,    UNKNOWN,     (int) UINT16_FTYPE_UINT16 },
 
   /* BMI */
   { OPTION_MASK_ISA_BMI, CODE_FOR_bmi_bextr_si, "__builtin_ia32_bextr_u32", IX86_BUILTIN_BEXTR32, UNKNOWN, (int) UINT_FTYPE_UINT_UINT },
diff --git a/gcc/config/i386/i386.h b/gcc/config/i386/i386.h
index 20c9a8f..f43586d 100644
--- a/gcc/config/i386/i386.h
+++ b/gcc/config/i386/i386.h
@@ -61,6 +61,7 @@ see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
 #define TARGET_ROUND	OPTION_ISA_ROUND
 #define TARGET_ABM	OPTION_ISA_ABM
 #define TARGET_BMI	OPTION_ISA_BMI
+#define TARGET_LZCNT	OPTION_ISA_LZCNT
 #define TARGET_TBM	OPTION_ISA_TBM
 #define TARGET_POPCNT	OPTION_ISA_POPCNT
 #define TARGET_SAHF	OPTION_ISA_SAHF
@@ -2288,7 +2289,7 @@ extern void debug_dispatch_window (int);
 #define CTZ_DEFINED_VALUE_AT_ZERO(MODE, VALUE) \
 	((VALUE) = GET_MODE_BITSIZE (MODE), TARGET_BMI)
 #define CLZ_DEFINED_VALUE_AT_ZERO(MODE, VALUE) \
-	((VALUE) = GET_MODE_BITSIZE (MODE), TARGET_BMI)
+	((VALUE) = GET_MODE_BITSIZE (MODE), TARGET_LZCNT)
 
 
 /* Flags returned by ix86_get_callcvt ().  */
diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md
index 5dfa43e..0c78f92 100644
--- a/gcc/config/i386/i386.md
+++ b/gcc/config/i386/i386.md
@@ -11801,19 +11801,19 @@
       (clobber (reg:CC FLAGS_REG))])]
   ""
 {
-  if (TARGET_ABM)
+  if (TARGET_LZCNT)
     {
-      emit_insn (gen_clz<mode>2_abm (operands[0], operands[1]));
+      emit_insn (gen_clz<mode>2_lzcnt (operands[0], operands[1]));
       DONE;
     }
   operands[2] = GEN_INT (GET_MODE_BITSIZE (<MODE>mode)-1);
 })
 
-(define_insn "clz<mode>2_abm"
+(define_insn "clz<mode>2_lzcnt"
   [(set (match_operand:SWI248 0 "register_operand" "=r")
 	(clz:SWI248 (match_operand:SWI248 1 "nonimmediate_operand" "rm")))
    (clobber (reg:CC FLAGS_REG))]
-  "TARGET_ABM || TARGET_BMI"
+  "TARGET_LZCNT"
   "lzcnt{<imodesuffix>}\t{%1, %0|%0, %1}"
   [(set_attr "prefix_rep" "1")
    (set_attr "type" "bitmanip")
diff --git a/gcc/config/i386/i386.opt b/gcc/config/i386/i386.opt
index 5e6b5df..f197dd8 100644
--- a/gcc/config/i386/i386.opt
+++ b/gcc/config/i386/i386.opt
@@ -489,6 +489,10 @@ mbmi
 Target Report Mask(ISA_BMI) Var(ix86_isa_flags) Save
 Support BMI built-in functions and code generation
 
+mlzcnt
+Target Report Mask(ISA_LZCNT) Var(ix86_isa_flags) Save
+Support LZCNT built-in function and code generation
+
 mtbm
 Target Report Mask(ISA_TBM) Var(ix86_isa_flags) Save
 Support TBM built-in functions and code generation
diff --git a/gcc/config/i386/lzcntintrin.h b/gcc/config/i386/lzcntintrin.h
new file mode 100644
index 0000000..4300811
--- /dev/null
+++ b/gcc/config/i386/lzcntintrin.h
@@ -0,0 +1,55 @@
+/* Copyright (C) 2009 Free Software Foundation, Inc.
+
+   This file is part of GCC.
+
+   GCC is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3, or (at your option)
+   any later version.
+
+   GCC is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   Under Section 7 of GPL version 3, you are granted additional
+   permissions described in the GCC Runtime Library Exception, version
+   3.1, as published by the Free Software Foundation.
+
+   You should have received a copy of the GNU General Public License and
+   a copy of the GCC Runtime Library Exception along with this program;
+   see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#ifndef _X86INTRIN_H_INCLUDED
+# error "Never use <lzcntintrin.h> directly; include <x86intrin.h> instead."
+#endif
+
+#ifndef __LZCNT__
+# error "LZCNT instruction is not enabled"
+#endif /* __LZCNT__ */
+
+#ifndef _LZCNTINTRIN_H_INCLUDED
+#define _LZCNTINTRIN_H_INCLUDED
+
+extern __inline unsigned short __attribute__((__gnu_inline__, __always_inline__, __artificial__))
+__lzcnt16 (unsigned short __X)
+{
+  return __builtin_clzs (__X);
+}
+
+extern __inline unsigned int __attribute__((__gnu_inline__, __always_inline__, __artificial__))
+__lzcnt32 (unsigned int __X)
+{
+  return __builtin_clz (__X);
+}
+
+#ifdef __x86_64__
+extern __inline unsigned long __attribute__((__gnu_inline__, __always_inline__, __artificial__))
+__lzcnt64 (unsigned long __X)
+{
+  return __builtin_clzl (__X);
+}
+#endif
+
+#endif /* _LZCNTINTRIN_H_INCLUDED */
diff --git a/gcc/config/i386/x86intrin.h b/gcc/config/i386/x86intrin.h
index 36b43df..88456f9 100644
--- a/gcc/config/i386/x86intrin.h
+++ b/gcc/config/i386/x86intrin.h
@@ -77,10 +77,6 @@
 #include <lwpintrin.h>
 #endif
 
-#ifdef __ABM__
-#include <abmintrin.h>
-#endif
-
 #ifdef __BMI__
 #include <bmiintrin.h>
 #endif
@@ -89,6 +85,10 @@
 #include <tbmintrin.h>
 #endif
 
+#ifdef __LZCNT__
+#include <lzcntintrin.h>
+#endif
+
 #ifdef __POPCNT__
 #include <popcntintrin.h>
 #endif
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index 0c95a79..480a8b0 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -9676,6 +9676,11 @@ All of them generate the machine instruction that is part of the name.
 @smallexample
 unsigned int __builtin_ia32_bextr_u32(unsigned int, unsigned int);
 unsigned long long __builtin_ia32_bextr_u64 (unsigned long long, unsigned long long);
+@end smallexample
+
+The following built-in functions are available when @option{-mlzcnt} is used.
+All of them generate the machine instruction that is part of the name.
+@smallexample
 unsigned short __builtin_ia32_lzcnt_16(unsigned short);
 unsigned int __builtin_ia32_lzcnt_u32(unsigned int);
 unsigned long long __builtin_ia32_lzcnt_u64 (unsigned long long);
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index db9a5da..c378360 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -606,8 +606,8 @@ Objective-C and Objective-C++ Dialects}.
 -mcld -mcx16 -msahf -mmovbe -mcrc32 -mrecip -mvzeroupper @gol
 -mmmx  -msse  -msse2 -msse3 -mssse3 -msse4.1 -msse4.2 -msse4 -mavx @gol
 -maes -mpclmul -mfsgsbase -mrdrnd -mf16c -mfma @gol
--msse4a -m3dnow -mpopcnt -mabm -mbmi -mtbm -mfma4 -mxop -mlwp @gol
--mthreads  -mno-align-stringops  -minline-all-stringops @gol
+-msse4a -m3dnow -mpopcnt -mabm -mbmi -mtbm -mfma4 -mxop -mlzcnt @gol
+-mlwp -mthreads  -mno-align-stringops  -minline-all-stringops @gol
 -minline-stringops-dynamically -mstringop-strategy=@var{alg} @gol
 -mpush-args  -maccumulate-outgoing-args  -m128bit-long-double @gol
 -m96bit-long-double  -mregparm=@var{num}  -msseregparm @gol
@@ -12692,6 +12692,8 @@ preferred alignment to @option{-mpreferred-stack-boundary=2}.
 @itemx -mno-abm
 @itemx -mbmi
 @itemx -mno-bmi
+@itemx -mlzcnt
+@itemx -mno-lzcnt
 @itemx -mtbm
 @itemx -mno-tbm
 @opindex mmmx
@@ -12702,7 +12704,7 @@ preferred alignment to @option{-mpreferred-stack-boundary=2}.
 @opindex mno-3dnow
 These switches enable or disable the use of instructions in the MMX, SSE,
 SSE2, SSE3, SSSE3, SSE4.1, AVX, AES, PCLMUL, FSGSBASE, RDRND, F16C, FMA,
-SSE4A, FMA4, XOP, LWP, ABM, BMI, or 3DNow!@: extended instruction sets.
+SSE4A, FMA4, XOP, LWP, ABM, BMI, LZCNT or 3DNow!@: extended instruction sets.
 These extensions are also available as built-in functions: see
 @ref{X86 Built-in Functions}, for details of the functions enabled and
 disabled by these switches.
diff --git a/gcc/testsuite/g++.dg/other/i386-2.C b/gcc/testsuite/g++.dg/other/i386-2.C
index 1a445f1..ed183c7 100644
--- a/gcc/testsuite/g++.dg/other/i386-2.C
+++ b/gcc/testsuite/g++.dg/other/i386-2.C
@@ -1,5 +1,5 @@
 /* { dg-do compile { target i?86-*-* x86_64-*-* } } */
-/* { dg-options "-O -pedantic-errors -march=k8 -msse4a -m3dnow -mavx -mfma4 -mxop -maes -mpclmul -mpopcnt -mabm -mbmi -mtbm -mlwp -mfsgsbase -mrdrnd -mf16c" } */
+/* { dg-options "-O -pedantic-errors -march=k8 -msse4a -m3dnow -mavx -mfma4 -mxop -maes -mpclmul -mpopcnt -mabm -mlzcnt -mbmi -mtbm -mlwp -mfsgsbase -mrdrnd -mf16c" } */
 
 /* Test that {,x,e,p,t,s,w,a,b,i}mmintrin.h, mm3dnow.h, fma4intrin.h,
    xopintrin.h, abmintrin.h, bmiintrin.h, tbmintrin.h, lwpintrin.h,
diff --git a/gcc/testsuite/g++.dg/other/i386-3.C b/gcc/testsuite/g++.dg/other/i386-3.C
index 66eec14..626f972 100644
--- a/gcc/testsuite/g++.dg/other/i386-3.C
+++ b/gcc/testsuite/g++.dg/other/i386-3.C
@@ -1,5 +1,5 @@
 /* { dg-do compile { target i?86-*-* x86_64-*-* } } */
-/* { dg-options "-O -fkeep-inline-functions -march=k8 -msse4a -m3dnow -mavx -mfma4 -mxop -maes -mpclmul -mpopcnt -mabm -mbmi -mtbm -mlwp -mfsgsbase -mrdrnd -mf16c" } */
+/* { dg-options "-O -fkeep-inline-functions -march=k8 -msse4a -m3dnow -mavx -mfma4 -mxop -maes -mpclmul -mpopcnt -mabm -mlzcnt -mbmi -mtbm -mlwp -mfsgsbase -mrdrnd -mf16c" } */
 
 /* Test that {,x,e,p,t,s,w,a,b,i}mmintrin.h, mm3dnow.h, fma4intrin.h,
    xopintrin.h, abmintrin.h, bmiintrin.h, tbmintrin.h, lwpintrin.h,
diff --git a/gcc/testsuite/gcc.target/i386/i386.exp b/gcc/testsuite/gcc.target/i386/i386.exp
index 13d8cff..3dcba25 100644
--- a/gcc/testsuite/gcc.target/i386/i386.exp
+++ b/gcc/testsuite/gcc.target/i386/i386.exp
@@ -186,6 +186,16 @@ proc check_effective_target_xop { } {
     } "-O2 -mxop" ]
 }
 
+# Return 1 if lzcnt instruction can be compiled.
+proc check_effective_target_lzcnt { } {
+    return [check_no_compiler_messages lzcnt object {
+	unsigned short _lzcnt (void)
+	{
+	   return __builtin_clzs (0);
+	}
+    } "-mlzcnt" ]
+}
+
 # Return 1 if bmi instructions can be compiled.
 proc check_effective_target_bmi { } {
     return [check_no_compiler_messages bmi object {
diff --git a/gcc/testsuite/gcc.target/i386/lzcnt-1.c b/gcc/testsuite/gcc.target/i386/lzcnt-1.c
new file mode 100644
index 0000000..f6240d1b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/lzcnt-1.c
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -mlzcnt " } */
+/* { dg-final { scan-assembler "lzcntw\[^\\n]*(%|)ax" } } */
+
+#include <x86intrin.h>
+
+unsigned int
+func_lzcnt16 (unsigned int X)
+{
+  return __lzcnt16(X);
+}
diff --git a/gcc/testsuite/gcc.target/i386/lzcnt-2.c b/gcc/testsuite/gcc.target/i386/lzcnt-2.c
new file mode 100644
index 0000000..329a11f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/lzcnt-2.c
@@ -0,0 +1,35 @@
+/* { dg-do run { target { lzcnt } } } */
+/* { dg-options "-O2 -mlzcnt -fno-inline" } */
+
+#include <x86intrin.h>
+
+#include "lzcnt-check.h"
+
+short calc_lzcnt_u16 (short src)
+{
+  int i;
+  short res = 0;
+
+  while ((res < 16) && (((src >> (15 - res)) & 1) == 0))
+    ++res;
+
+  return res;
+}
+
+static void
+lzcnt_test ()
+{
+  unsigned i;
+  short src = 0x7ace;
+  short res, res_ref;
+
+  for (i=0; i<5; ++i) {
+    src = src >> i;
+
+    res_ref = calc_lzcnt_u16 (src);
+    res = __lzcnt16 (src);
+
+    if (res != res_ref)
+      abort();
+  }
+}
diff --git a/gcc/testsuite/gcc.target/i386/lzcnt-2a.c b/gcc/testsuite/gcc.target/i386/lzcnt-2a.c
new file mode 100644
index 0000000..fe1069f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/lzcnt-2a.c
@@ -0,0 +1,6 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -mlzcnt" } */
+
+#include "lzcnt-2.c"
+
+/* { dg-final { scan-assembler "lzcntw" } } */
diff --git a/gcc/testsuite/gcc.target/i386/lzcnt-3.c b/gcc/testsuite/gcc.target/i386/lzcnt-3.c
new file mode 100644
index 0000000..1477951
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/lzcnt-3.c
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-options "-O0 -mlzcnt " } */
+/* { dg-final { scan-assembler "lzcntl\[^\\n]*(%|)eax" } } */
+
+#include <x86intrin.h>
+
+unsigned int
+func_lzcnt32 (unsigned int X)
+{
+  return __lzcnt32(X);
+}
diff --git a/gcc/testsuite/gcc.target/i386/lzcnt-4.c b/gcc/testsuite/gcc.target/i386/lzcnt-4.c
new file mode 100644
index 0000000..2065326
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/lzcnt-4.c
@@ -0,0 +1,35 @@
+/* { dg-do run { target { lzcnt } } } */
+/* { dg-options "-O2 -mlzcnt -fno-inline" } */
+
+#include <x86intrin.h>
+
+#include "lzcnt-check.h"
+
+int calc_lzcnt_u32 (int src)
+{
+  int i;
+  int res = 0;
+
+  while ((res < 32) && (((src >> (31 - res)) & 1) == 0))
+    ++res;
+
+  return res;
+}
+
+static void
+lzcnt_test ()
+{
+  unsigned i;
+  int src = 0xce7ace0;
+  int res, res_ref;
+
+  for (i=0; i<5; ++i) {
+    src = src >> i;
+
+    res_ref = calc_lzcnt_u32 (src);
+    res = __lzcnt32 (src);
+
+    if (res != res_ref)
+      abort();
+  }
+}
diff --git a/gcc/testsuite/gcc.target/i386/lzcnt-4a.c b/gcc/testsuite/gcc.target/i386/lzcnt-4a.c
new file mode 100644
index 0000000..6bba6a9
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/lzcnt-4a.c
@@ -0,0 +1,6 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -mlzcnt" } */
+
+#include "lzcnt-4.c"
+
+/* { dg-final { scan-assembler "lzcntl" } } */
diff --git a/gcc/testsuite/gcc.target/i386/lzcnt-5.c b/gcc/testsuite/gcc.target/i386/lzcnt-5.c
new file mode 100644
index 0000000..a4b9aaf
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/lzcnt-5.c
@@ -0,0 +1,11 @@
+/* { dg-do compile { target { ! ia32 } } } */
+/* { dg-options "-O2 -mlzcnt" } */
+/* { dg-final { scan-assembler "lzcntq\[^\\n]*(%|)rax" } } */
+
+#include <x86intrin.h>
+
+unsigned int
+func_lzcnt64 (unsigned long long X)
+{
+  return __lzcnt64(X);
+}
diff --git a/gcc/testsuite/gcc.target/i386/lzcnt-6.c b/gcc/testsuite/gcc.target/i386/lzcnt-6.c
new file mode 100644
index 0000000..f0bf5da
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/lzcnt-6.c
@@ -0,0 +1,35 @@
+/* { dg-do run { target { lzcnt && { ! ia32 } } } } */
+/* { dg-options "-O2 -mlzcnt -fno-inline" } */
+
+#include <x86intrin.h>
+
+#include "lzcnt-check.h"
+
+long long calc_lzcnt_u64 (long long src)
+{
+  int i;
+  int res = 0;
+
+  while ((res < 64) && (((src >> (63 - res)) & 1) == 0))
+    ++res;
+
+  return res;
+}
+
+static void
+lzcnt_test ()
+{
+  unsigned i;
+  long long src = 0xce7ace0ce7ace0;
+  long long res, res_ref;
+
+  for (i=0; i<5; ++i) {
+    src = src >> i;
+
+    res_ref = calc_lzcnt_u64 (src);
+    res = __lzcnt64 (src);
+
+    if (res != res_ref)
+      abort();
+  }
+}
diff --git a/gcc/testsuite/gcc.target/i386/lzcnt-6a.c b/gcc/testsuite/gcc.target/i386/lzcnt-6a.c
new file mode 100644
index 0000000..2090093
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/lzcnt-6a.c
@@ -0,0 +1,6 @@
+/* { dg-do compile { target { ! ia32 } } } */
+/* { dg-options "-O2 -mlzcnt" } */
+
+#include "lzcnt-6.c"
+
+/* { dg-final { scan-assembler "lzcntq" } } */
diff --git a/gcc/testsuite/gcc.target/i386/lzcnt-check.h b/gcc/testsuite/gcc.target/i386/lzcnt-check.h
new file mode 100644
index 0000000..8aad834
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/lzcnt-check.h
@@ -0,0 +1,37 @@
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "cpuid.h"
+
+static void lzcnt_test (void);
+
+static void
+__attribute__ ((noinline))
+do_test (void)
+{
+  lzcnt_test ();
+}
+
+int
+main ()
+{
+  unsigned int eax, ebx, ecx, edx;
+
+  if (!__get_cpuid (0x80000001, &eax, &ebx, &ecx, &edx))
+    return 0;
+
+  /* Run LZCNT test only if host has LZCNT support.  */
+  if (ecx & bit_LZCNT)
+    {
+      do_test ();
+#ifdef DEBUG
+      printf ("PASSED\n");
+#endif
+    }
+#ifdef DEBUG
+  else
+    printf ("SKIPPED\n");
+#endif
+
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/i386/sse-12.c b/gcc/testsuite/gcc.target/i386/sse-12.c
index 4f8aaec..59e659e 100644
--- a/gcc/testsuite/gcc.target/i386/sse-12.c
+++ b/gcc/testsuite/gcc.target/i386/sse-12.c
@@ -3,7 +3,7 @@
    popcntintrin.h and mm_malloc.h are usable
    with -O -std=c89 -pedantic-errors.  */
 /* { dg-do compile } */
-/* { dg-options "-O -std=c89 -pedantic-errors -march=k8 -msse4a -m3dnow -mavx -mfma4 -mxop -maes -mpclmul -mpopcnt -mabm -mbmi -mtbm -mlwp -mfsgsbase -mrdrnd -mf16c" } */
+/* { dg-options "-O -std=c89 -pedantic-errors -march=k8 -msse4a -m3dnow -mavx -mfma4 -mxop -maes -mpclmul -mpopcnt -mabm -mlzcnt -mbmi -mtbm -mlwp -mfsgsbase -mrdrnd -mf16c" } */
 
 #include <x86intrin.h>
 
diff --git a/gcc/testsuite/gcc.target/i386/sse-13.c b/gcc/testsuite/gcc.target/i386/sse-13.c
index 188b2e6..836272d 100644
--- a/gcc/testsuite/gcc.target/i386/sse-13.c
+++ b/gcc/testsuite/gcc.target/i386/sse-13.c
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O2 -Werror-implicit-function-declaration -march=k8 -msse4a -m3dnow -mavx -mfma4 -mxop -maes -mpclmul -mpopcnt -mabm -mbmi -mtbm -mlwp -mfsgsbase -mrdrnd -mf16c" } */
+/* { dg-options "-O2 -Werror-implicit-function-declaration -march=k8 -msse4a -m3dnow -mavx -mfma4 -mxop -maes -mpclmul -mpopcnt -mabm -mlzcnt -mbmi -mtbm -mlwp -mfsgsbase -mrdrnd -mf16c" } */
 
 #include <mm_malloc.h>
 
diff --git a/gcc/testsuite/gcc.target/i386/sse-14.c b/gcc/testsuite/gcc.target/i386/sse-14.c
index 22ea61f..af42781 100644
--- a/gcc/testsuite/gcc.target/i386/sse-14.c
+++ b/gcc/testsuite/gcc.target/i386/sse-14.c
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O0 -Werror-implicit-function-declaration -march=k8 -msse4a -m3dnow -mavx -mfma4 -mxop -maes -mpclmul -mpopcnt -mabm -mbmi -mtbm -mlwp -mfsgsbase -mrdrnd -mf16c" } */
+/* { dg-options "-O0 -Werror-implicit-function-declaration -march=k8 -msse4a -m3dnow -mavx -mfma4 -mxop -maes -mpclmul -mpopcnt -mabm -mlzcnt -mbmi -mtbm -mlwp -mfsgsbase -mrdrnd -mf16c" } */
 
 #include <mm_malloc.h>
 

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [Patch, i386, testsuite] Fix for PR49547, new tescases for lzcnt instruction
  2011-08-01 12:36                                       ` Kirill Yukhin
@ 2011-08-01 12:50                                         ` H.J. Lu
  2011-08-01 13:13                                           ` Kirill Yukhin
  0 siblings, 1 reply; 25+ messages in thread
From: H.J. Lu @ 2011-08-01 12:50 UTC (permalink / raw)
  To: Kirill Yukhin; +Cc: Uros Bizjak, Mike Stump, gcc-patches List, Jagasia, Harsha

On Mon, Aug 1, 2011 at 5:36 AM, Kirill Yukhin <kirill.yukhin@gmail.com> wrote:
> Hi HJ,
> Thanks for input. I've missed it.
> Done. Updated patch is attached.

Compiler may still optimize it away.  You need to replace 0 with
a function parameter.  Please see:

http://gcc.gnu.org/ml/gcc-patches/2011-07/msg02463.html


H.J.
---
> Thanks, K
>
> On Mon, Aug 1, 2011 at 4:26 PM, H.J. Lu <hjl.tools@gmail.com> wrote:
>> On Mon, Aug 1, 2011 at 5:20 AM, Kirill Yukhin <kirill.yukhin@gmail.com> wrote:
>>> I've merged my changes with trunk (there was a conflict) and fixed typo.
>>> Updated patch is attached. Waiting for commit...
>>>
>>> Thanks, K
>>>
>>> On Mon, Aug 1, 2011 at 1:03 PM, Kirill Yukhin <kirill.yukhin@gmail.com> wrote:
>>>> Thanks!
>>>> Guys with waa rights, could anybody commit my fix?
>>>>
>>>> Thanks, K
>>>>
>>>>>
>>>>> OK for mainline.
>>>>>
>>>>> Uros.
>>>>>
>>>>
>>
>>
>> +# Return 1 if lzcnt instruction can be compiled.
>> +proc check_effective_target_lzcnt { } {
>> +    return [check_no_compiler_messages lzcnt object {
>> +       void _lzcnt (void)
>> +       {
>> +          __builtin_clzs (0);
>> +       }
>> +    } "-O2 -mlzcnt" ]
>> +}
>>
>> GCC may optimize this away.  Please fix it similar to:
>>
>> http://gcc.gnu.org/ml/gcc-patches/2011-07/msg02463.html
>>
>

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [Patch, i386, testsuite] Fix for PR49547, new tescases for lzcnt instruction
  2011-08-01 12:50                                         ` H.J. Lu
@ 2011-08-01 13:13                                           ` Kirill Yukhin
  2011-08-02  0:33                                             ` H.J. Lu
  0 siblings, 1 reply; 25+ messages in thread
From: Kirill Yukhin @ 2011-08-01 13:13 UTC (permalink / raw)
  To: H.J. Lu; +Cc: Uros Bizjak, Mike Stump, gcc-patches List, Jagasia, Harsha

[-- Attachment #1: Type: text/plain, Size: 1524 bytes --]

Done.
Updated patch is attached.

Thanks, K

On Mon, Aug 1, 2011 at 4:49 PM, H.J. Lu <hjl.tools@gmail.com> wrote:
> On Mon, Aug 1, 2011 at 5:36 AM, Kirill Yukhin <kirill.yukhin@gmail.com> wrote:
>> Hi HJ,
>> Thanks for input. I've missed it.
>> Done. Updated patch is attached.
>
> Compiler may still optimize it away.  You need to replace 0 with
> a function parameter.  Please see:
>
> http://gcc.gnu.org/ml/gcc-patches/2011-07/msg02463.html
>
>
> H.J.
> ---
>> Thanks, K
>>
>> On Mon, Aug 1, 2011 at 4:26 PM, H.J. Lu <hjl.tools@gmail.com> wrote:
>>> On Mon, Aug 1, 2011 at 5:20 AM, Kirill Yukhin <kirill.yukhin@gmail.com> wrote:
>>>> I've merged my changes with trunk (there was a conflict) and fixed typo.
>>>> Updated patch is attached. Waiting for commit...
>>>>
>>>> Thanks, K
>>>>
>>>> On Mon, Aug 1, 2011 at 1:03 PM, Kirill Yukhin <kirill.yukhin@gmail.com> wrote:
>>>>> Thanks!
>>>>> Guys with waa rights, could anybody commit my fix?
>>>>>
>>>>> Thanks, K
>>>>>
>>>>>>
>>>>>> OK for mainline.
>>>>>>
>>>>>> Uros.
>>>>>>
>>>>>
>>>
>>>
>>> +# Return 1 if lzcnt instruction can be compiled.
>>> +proc check_effective_target_lzcnt { } {
>>> +    return [check_no_compiler_messages lzcnt object {
>>> +       void _lzcnt (void)
>>> +       {
>>> +          __builtin_clzs (0);
>>> +       }
>>> +    } "-O2 -mlzcnt" ]
>>> +}
>>>
>>> GCC may optimize this away.  Please fix it similar to:
>>>
>>> http://gcc.gnu.org/ml/gcc-patches/2011-07/msg02463.html
>>>
>>
>

[-- Attachment #2: lzcnt-6.gcc.patch --]
[-- Type: application/octet-stream, Size: 26761 bytes --]

diff --git a/gcc/config.gcc b/gcc/config.gcc
index 02cc556..94f15d8 100644
--- a/gcc/config.gcc
+++ b/gcc/config.gcc
@@ -352,7 +352,7 @@ i[34567]86-*-*)
 		       nmmintrin.h bmmintrin.h fma4intrin.h wmmintrin.h
 		       immintrin.h x86intrin.h avxintrin.h xopintrin.h
 		       ia32intrin.h cross-stdarg.h lwpintrin.h popcntintrin.h
-		       abmintrin.h bmiintrin.h tbmintrin.h"
+		       lzcntintrin.h bmiintrin.h tbmintrin.h"
 	;;
 x86_64-*-*)
 	cpu_type=i386
@@ -364,7 +364,7 @@ x86_64-*-*)
 		       nmmintrin.h bmmintrin.h fma4intrin.h wmmintrin.h
 		       immintrin.h x86intrin.h avxintrin.h xopintrin.h
 		       ia32intrin.h cross-stdarg.h lwpintrin.h popcntintrin.h
-		       abmintrin.h bmiintrin.h tbmintrin.h"
+		       lzcntintrin.h bmiintrin.h tbmintrin.h"
 	need_64bit_hwint=yes
 	;;
 ia64-*-*)
diff --git a/gcc/config/i386/abmintrin.h b/gcc/config/i386/abmintrin.h
deleted file mode 100644
index 9d87f57..0000000
--- a/gcc/config/i386/abmintrin.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/* Copyright (C) 2009 Free Software Foundation, Inc.
-
-   This file is part of GCC.
-
-   GCC is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3, or (at your option)
-   any later version.
-
-   GCC is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   Under Section 7 of GPL version 3, you are granted additional
-   permissions described in the GCC Runtime Library Exception, version
-   3.1, as published by the Free Software Foundation.
-
-   You should have received a copy of the GNU General Public License and
-   a copy of the GCC Runtime Library Exception along with this program;
-   see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
-   <http://www.gnu.org/licenses/>.  */
-
-#ifndef _X86INTRIN_H_INCLUDED
-# error "Never use <abmintrin.h> directly; include <x86intrin.h> instead."
-#endif
-
-#ifndef __ABM__
-# error "ABM instruction set not enabled"
-#endif /* __ABM__ */
-
-#ifndef _ABMINTRIN_H_INCLUDED
-#define _ABMINTRIN_H_INCLUDED
-
-extern __inline unsigned short __attribute__((__gnu_inline__, __always_inline__, __artificial__))
-__lzcnt16 (unsigned short __X)
-{
-  return __builtin_clzs (__X);
-}
-
-extern __inline unsigned int __attribute__((__gnu_inline__, __always_inline__, __artificial__))
-__lzcnt (unsigned int __X)
-{
-  return __builtin_clz (__X);
-}
-
-#ifdef __x86_64__
-extern __inline unsigned long __attribute__((__gnu_inline__, __always_inline__, __artificial__))
-__lzcnt64 (unsigned long __X)
-{
-  return __builtin_clzl (__X);
-}
-#endif
-
-#endif /* _ABMINTRIN_H_INCLUDED */
diff --git a/gcc/config/i386/bmiintrin.h b/gcc/config/i386/bmiintrin.h
index 225f2ec..1699c61 100644
--- a/gcc/config/i386/bmiintrin.h
+++ b/gcc/config/i386/bmiintrin.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2010 Free Software Foundation, Inc.
+/* Copyright (C) 2010, 2011 Free Software Foundation, Inc.
 
    This file is part of GCC.
 
@@ -33,12 +33,6 @@
 #define _BMIINTRIN_H_INCLUDED
 
 extern __inline unsigned short __attribute__((__gnu_inline__, __always_inline__, __artificial__))
-__lzcnt_u16 (unsigned short __X)
-{
-  return __builtin_clzs (__X);
-}
-
-extern __inline unsigned short __attribute__((__gnu_inline__, __always_inline__, __artificial__))
 __tzcnt_u16 (unsigned short __X)
 {
   return __builtin_ctzs (__X);
@@ -79,12 +73,6 @@ __blsr_u32 (unsigned int __X)
   return tmp;
 }
 
-extern __inline unsigned int __attribute__((__gnu_inline__, __always_inline__, __artificial__))
-__lzcnt_u32 (unsigned int __X)
-{
-  return __builtin_clz (__X);
-}
-
 
 extern __inline unsigned int __attribute__((__gnu_inline__, __always_inline__, __artificial__))
 __tzcnt_u32 (unsigned int __X)
@@ -129,12 +117,6 @@ __blsr_u64 (unsigned long long __X)
 }
 
 extern __inline unsigned long long __attribute__((__gnu_inline__, __always_inline__, __artificial__))
-__lzcnt_u64 (unsigned long long __X)
-{
-  return __builtin_clzll (__X);
-}
-
-extern __inline unsigned long long __attribute__((__gnu_inline__, __always_inline__, __artificial__))
 __tzcnt_u64 (unsigned long long __X)
 {
   return __builtin_ctzll (__X);
diff --git a/gcc/config/i386/cpuid.h b/gcc/config/i386/cpuid.h
index 3c3f47b..8826c28 100644
--- a/gcc/config/i386/cpuid.h
+++ b/gcc/config/i386/cpuid.h
@@ -24,6 +24,7 @@
 /* %ecx */
 #define bit_SSE3	(1 << 0)
 #define bit_PCLMUL	(1 << 1)
+#define bit_LZCNT	(1 << 5)
 #define bit_SSSE3	(1 << 9)
 #define bit_FMA		(1 << 12)
 #define bit_CMPXCHG16B	(1 << 13)
diff --git a/gcc/config/i386/driver-i386.c b/gcc/config/i386/driver-i386.c
index ecd8958..5823987 100644
--- a/gcc/config/i386/driver-i386.c
+++ b/gcc/config/i386/driver-i386.c
@@ -396,7 +396,7 @@ const char *host_detect_local_cpu (int argc, const char **argv)
   unsigned int has_popcnt = 0, has_aes = 0, has_avx = 0;
   unsigned int has_pclmul = 0, has_abm = 0, has_lwp = 0;
   unsigned int has_fma = 0, has_fma4 = 0, has_xop = 0;
-  unsigned int has_bmi = 0, has_tbm = 0;
+  unsigned int has_bmi = 0, has_tbm = 0, has_lzcnt = 0;
 
   bool arch;
 
@@ -465,6 +465,7 @@ const char *host_detect_local_cpu (int argc, const char **argv)
       has_fma4 = ecx & bit_FMA4;
       has_xop = ecx & bit_XOP;
       has_tbm = ecx & bit_TBM;
+      has_lzcnt = ecx & bit_LZCNT;
 
       has_longmode = edx & bit_LM;
       has_3dnowp = edx & bit_3DNOWP;
@@ -717,10 +718,11 @@ const char *host_detect_local_cpu (int argc, const char **argv)
       const char *avx = has_avx ? " -mavx" : " -mno-avx";
       const char *sse4_2 = has_sse4_2 ? " -msse4.2" : " -mno-sse4.2";
       const char *sse4_1 = has_sse4_1 ? " -msse4.1" : " -mno-sse4.1";
+      const char *lzcnt = has_lzcnt ? " -mlzcnt" : " -mnolzcnt";
 
       options = concat (options, cx16, sahf, movbe, ase, pclmul,
 			popcnt, abm, lwp, fma, fma4, xop, bmi, tbm,
-			avx, sse4_2, sse4_1, NULL);
+			avx, sse4_2, sse4_1, lzcnt, NULL);
     }
 
 done:
diff --git a/gcc/config/i386/i386-c.c b/gcc/config/i386/i386-c.c
index 5cbcfd5..1fc333c 100644
--- a/gcc/config/i386/i386-c.c
+++ b/gcc/config/i386/i386-c.c
@@ -271,6 +271,8 @@ ix86_target_macros_internal (int isa_flag,
     def_or_undef (parse_in, "__ABM__");
   if (isa_flag & OPTION_MASK_ISA_BMI)
     def_or_undef (parse_in, "__BMI__");
+  if (isa_flag & OPTION_MASK_ISA_LZCNT)
+    def_or_undef (parse_in, "__LZCNT__");
   if (isa_flag & OPTION_MASK_ISA_TBM)
     def_or_undef (parse_in, "__TBM__");
   if (isa_flag & OPTION_MASK_ISA_POPCNT)
diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
index f751e74..5ffdf50 100644
--- a/gcc/config/i386/i386.c
+++ b/gcc/config/i386/i386.c
@@ -2663,6 +2663,7 @@ ix86_target_string (int isa, int flags, const char *arch, const char *tune,
     { "-mmmx",		OPTION_MASK_ISA_MMX },
     { "-mabm",		OPTION_MASK_ISA_ABM },
     { "-mbmi",		OPTION_MASK_ISA_BMI },
+    { "-mlzcnt",	OPTION_MASK_ISA_LZCNT },
     { "-mtbm",		OPTION_MASK_ISA_TBM },
     { "-mpopcnt",	OPTION_MASK_ISA_POPCNT },
     { "-mmovbe",	OPTION_MASK_ISA_MOVBE },
@@ -2917,7 +2918,8 @@ ix86_option_override_internal (bool main_args_p)
       PTA_RDRND = 1 << 25,
       PTA_F16C = 1 << 26,
       PTA_BMI = 1 << 27,
-      PTA_TBM = 1 << 28
+      PTA_TBM = 1 << 28,
+      PTA_LZCNT = 1 << 29
       /* if this reaches 32, need to widen struct pta flags below */
     };
 
@@ -3278,6 +3280,9 @@ ix86_option_override_internal (bool main_args_p)
 	if (processor_alias_table[i].flags & PTA_BMI
 	    && !(ix86_isa_flags_explicit & OPTION_MASK_ISA_BMI))
 	  ix86_isa_flags |= OPTION_MASK_ISA_BMI;
+	if (processor_alias_table[i].flags & (PTA_LZCNT | PTA_ABM)
+	    && !(ix86_isa_flags_explicit & OPTION_MASK_ISA_LZCNT))
+	  ix86_isa_flags |= OPTION_MASK_ISA_LZCNT;
 	if (processor_alias_table[i].flags & PTA_TBM
 	    && !(ix86_isa_flags_explicit & OPTION_MASK_ISA_TBM))
 	  ix86_isa_flags |= OPTION_MASK_ISA_TBM;
@@ -3525,6 +3530,10 @@ ix86_option_override_internal (bool main_args_p)
   if (TARGET_SSE4_2 || TARGET_ABM)
     ix86_isa_flags |= OPTION_MASK_ISA_POPCNT & ~ix86_isa_flags_explicit;
 
+  /* Turn on lzcnt instruction for -mabm.  */
+  if (TARGET_ABM)
+    ix86_isa_flags |= OPTION_MASK_ISA_LZCNT & ~ix86_isa_flags_explicit;
+
   /* Validate -mpreferred-stack-boundary= value or default it to
      PREFERRED_STACK_BOUNDARY_DEFAULT.  */
   ix86_preferred_stack_boundary = PREFERRED_STACK_BOUNDARY_DEFAULT;
@@ -4030,6 +4039,7 @@ ix86_valid_target_attribute_inner_p (tree args, char *p_strings[],
     IX86_ATTR_ISA ("3dnow",	OPT_m3dnow),
     IX86_ATTR_ISA ("abm",	OPT_mabm),
     IX86_ATTR_ISA ("bmi",	OPT_mbmi),
+    IX86_ATTR_ISA ("lzcnt",	OPT_mlzcnt),
     IX86_ATTR_ISA ("tbm",	OPT_mtbm),
     IX86_ATTR_ISA ("aes",	OPT_maes),
     IX86_ATTR_ISA ("avx",	OPT_mavx),
@@ -24939,7 +24949,7 @@ static const struct builtin_description bdesc_args[] =
   { OPTION_MASK_ISA_AVX, CODE_FOR_copysignv8sf3,  "__builtin_ia32_copysignps256", IX86_BUILTIN_CPYSGNPS256, UNKNOWN, (int) V8SF_FTYPE_V8SF_V8SF },
   { OPTION_MASK_ISA_AVX, CODE_FOR_copysignv4df3,  "__builtin_ia32_copysignpd256", IX86_BUILTIN_CPYSGNPD256, UNKNOWN, (int) V4DF_FTYPE_V4DF_V4DF },
 
-  { OPTION_MASK_ISA_ABM, CODE_FOR_clzhi2_abm,   "__builtin_clzs",   IX86_BUILTIN_CLZS,    UNKNOWN,     (int) UINT16_FTYPE_UINT16 },
+  { OPTION_MASK_ISA_LZCNT, CODE_FOR_clzhi2_lzcnt,   "__builtin_clzs",   IX86_BUILTIN_CLZS,    UNKNOWN,     (int) UINT16_FTYPE_UINT16 },
 
   /* BMI */
   { OPTION_MASK_ISA_BMI, CODE_FOR_bmi_bextr_si, "__builtin_ia32_bextr_u32", IX86_BUILTIN_BEXTR32, UNKNOWN, (int) UINT_FTYPE_UINT_UINT },
diff --git a/gcc/config/i386/i386.h b/gcc/config/i386/i386.h
index 20c9a8f..f43586d 100644
--- a/gcc/config/i386/i386.h
+++ b/gcc/config/i386/i386.h
@@ -61,6 +61,7 @@ see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
 #define TARGET_ROUND	OPTION_ISA_ROUND
 #define TARGET_ABM	OPTION_ISA_ABM
 #define TARGET_BMI	OPTION_ISA_BMI
+#define TARGET_LZCNT	OPTION_ISA_LZCNT
 #define TARGET_TBM	OPTION_ISA_TBM
 #define TARGET_POPCNT	OPTION_ISA_POPCNT
 #define TARGET_SAHF	OPTION_ISA_SAHF
@@ -2288,7 +2289,7 @@ extern void debug_dispatch_window (int);
 #define CTZ_DEFINED_VALUE_AT_ZERO(MODE, VALUE) \
 	((VALUE) = GET_MODE_BITSIZE (MODE), TARGET_BMI)
 #define CLZ_DEFINED_VALUE_AT_ZERO(MODE, VALUE) \
-	((VALUE) = GET_MODE_BITSIZE (MODE), TARGET_BMI)
+	((VALUE) = GET_MODE_BITSIZE (MODE), TARGET_LZCNT)
 
 
 /* Flags returned by ix86_get_callcvt ().  */
diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md
index 5dfa43e..0c78f92 100644
--- a/gcc/config/i386/i386.md
+++ b/gcc/config/i386/i386.md
@@ -11801,19 +11801,19 @@
       (clobber (reg:CC FLAGS_REG))])]
   ""
 {
-  if (TARGET_ABM)
+  if (TARGET_LZCNT)
     {
-      emit_insn (gen_clz<mode>2_abm (operands[0], operands[1]));
+      emit_insn (gen_clz<mode>2_lzcnt (operands[0], operands[1]));
       DONE;
     }
   operands[2] = GEN_INT (GET_MODE_BITSIZE (<MODE>mode)-1);
 })
 
-(define_insn "clz<mode>2_abm"
+(define_insn "clz<mode>2_lzcnt"
   [(set (match_operand:SWI248 0 "register_operand" "=r")
 	(clz:SWI248 (match_operand:SWI248 1 "nonimmediate_operand" "rm")))
    (clobber (reg:CC FLAGS_REG))]
-  "TARGET_ABM || TARGET_BMI"
+  "TARGET_LZCNT"
   "lzcnt{<imodesuffix>}\t{%1, %0|%0, %1}"
   [(set_attr "prefix_rep" "1")
    (set_attr "type" "bitmanip")
diff --git a/gcc/config/i386/i386.opt b/gcc/config/i386/i386.opt
index 5e6b5df..f197dd8 100644
--- a/gcc/config/i386/i386.opt
+++ b/gcc/config/i386/i386.opt
@@ -489,6 +489,10 @@ mbmi
 Target Report Mask(ISA_BMI) Var(ix86_isa_flags) Save
 Support BMI built-in functions and code generation
 
+mlzcnt
+Target Report Mask(ISA_LZCNT) Var(ix86_isa_flags) Save
+Support LZCNT built-in function and code generation
+
 mtbm
 Target Report Mask(ISA_TBM) Var(ix86_isa_flags) Save
 Support TBM built-in functions and code generation
diff --git a/gcc/config/i386/lzcntintrin.h b/gcc/config/i386/lzcntintrin.h
new file mode 100644
index 0000000..4300811
--- /dev/null
+++ b/gcc/config/i386/lzcntintrin.h
@@ -0,0 +1,55 @@
+/* Copyright (C) 2009 Free Software Foundation, Inc.
+
+   This file is part of GCC.
+
+   GCC is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3, or (at your option)
+   any later version.
+
+   GCC is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   Under Section 7 of GPL version 3, you are granted additional
+   permissions described in the GCC Runtime Library Exception, version
+   3.1, as published by the Free Software Foundation.
+
+   You should have received a copy of the GNU General Public License and
+   a copy of the GCC Runtime Library Exception along with this program;
+   see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#ifndef _X86INTRIN_H_INCLUDED
+# error "Never use <lzcntintrin.h> directly; include <x86intrin.h> instead."
+#endif
+
+#ifndef __LZCNT__
+# error "LZCNT instruction is not enabled"
+#endif /* __LZCNT__ */
+
+#ifndef _LZCNTINTRIN_H_INCLUDED
+#define _LZCNTINTRIN_H_INCLUDED
+
+extern __inline unsigned short __attribute__((__gnu_inline__, __always_inline__, __artificial__))
+__lzcnt16 (unsigned short __X)
+{
+  return __builtin_clzs (__X);
+}
+
+extern __inline unsigned int __attribute__((__gnu_inline__, __always_inline__, __artificial__))
+__lzcnt32 (unsigned int __X)
+{
+  return __builtin_clz (__X);
+}
+
+#ifdef __x86_64__
+extern __inline unsigned long __attribute__((__gnu_inline__, __always_inline__, __artificial__))
+__lzcnt64 (unsigned long __X)
+{
+  return __builtin_clzl (__X);
+}
+#endif
+
+#endif /* _LZCNTINTRIN_H_INCLUDED */
diff --git a/gcc/config/i386/x86intrin.h b/gcc/config/i386/x86intrin.h
index 36b43df..88456f9 100644
--- a/gcc/config/i386/x86intrin.h
+++ b/gcc/config/i386/x86intrin.h
@@ -77,10 +77,6 @@
 #include <lwpintrin.h>
 #endif
 
-#ifdef __ABM__
-#include <abmintrin.h>
-#endif
-
 #ifdef __BMI__
 #include <bmiintrin.h>
 #endif
@@ -89,6 +85,10 @@
 #include <tbmintrin.h>
 #endif
 
+#ifdef __LZCNT__
+#include <lzcntintrin.h>
+#endif
+
 #ifdef __POPCNT__
 #include <popcntintrin.h>
 #endif
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index 0c95a79..480a8b0 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -9676,6 +9676,11 @@ All of them generate the machine instruction that is part of the name.
 @smallexample
 unsigned int __builtin_ia32_bextr_u32(unsigned int, unsigned int);
 unsigned long long __builtin_ia32_bextr_u64 (unsigned long long, unsigned long long);
+@end smallexample
+
+The following built-in functions are available when @option{-mlzcnt} is used.
+All of them generate the machine instruction that is part of the name.
+@smallexample
 unsigned short __builtin_ia32_lzcnt_16(unsigned short);
 unsigned int __builtin_ia32_lzcnt_u32(unsigned int);
 unsigned long long __builtin_ia32_lzcnt_u64 (unsigned long long);
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index db9a5da..c378360 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -606,8 +606,8 @@ Objective-C and Objective-C++ Dialects}.
 -mcld -mcx16 -msahf -mmovbe -mcrc32 -mrecip -mvzeroupper @gol
 -mmmx  -msse  -msse2 -msse3 -mssse3 -msse4.1 -msse4.2 -msse4 -mavx @gol
 -maes -mpclmul -mfsgsbase -mrdrnd -mf16c -mfma @gol
--msse4a -m3dnow -mpopcnt -mabm -mbmi -mtbm -mfma4 -mxop -mlwp @gol
--mthreads  -mno-align-stringops  -minline-all-stringops @gol
+-msse4a -m3dnow -mpopcnt -mabm -mbmi -mtbm -mfma4 -mxop -mlzcnt @gol
+-mlwp -mthreads  -mno-align-stringops  -minline-all-stringops @gol
 -minline-stringops-dynamically -mstringop-strategy=@var{alg} @gol
 -mpush-args  -maccumulate-outgoing-args  -m128bit-long-double @gol
 -m96bit-long-double  -mregparm=@var{num}  -msseregparm @gol
@@ -12692,6 +12692,8 @@ preferred alignment to @option{-mpreferred-stack-boundary=2}.
 @itemx -mno-abm
 @itemx -mbmi
 @itemx -mno-bmi
+@itemx -mlzcnt
+@itemx -mno-lzcnt
 @itemx -mtbm
 @itemx -mno-tbm
 @opindex mmmx
@@ -12702,7 +12704,7 @@ preferred alignment to @option{-mpreferred-stack-boundary=2}.
 @opindex mno-3dnow
 These switches enable or disable the use of instructions in the MMX, SSE,
 SSE2, SSE3, SSSE3, SSE4.1, AVX, AES, PCLMUL, FSGSBASE, RDRND, F16C, FMA,
-SSE4A, FMA4, XOP, LWP, ABM, BMI, or 3DNow!@: extended instruction sets.
+SSE4A, FMA4, XOP, LWP, ABM, BMI, LZCNT or 3DNow!@: extended instruction sets.
 These extensions are also available as built-in functions: see
 @ref{X86 Built-in Functions}, for details of the functions enabled and
 disabled by these switches.
diff --git a/gcc/testsuite/g++.dg/other/i386-2.C b/gcc/testsuite/g++.dg/other/i386-2.C
index 1a445f1..ed183c7 100644
--- a/gcc/testsuite/g++.dg/other/i386-2.C
+++ b/gcc/testsuite/g++.dg/other/i386-2.C
@@ -1,5 +1,5 @@
 /* { dg-do compile { target i?86-*-* x86_64-*-* } } */
-/* { dg-options "-O -pedantic-errors -march=k8 -msse4a -m3dnow -mavx -mfma4 -mxop -maes -mpclmul -mpopcnt -mabm -mbmi -mtbm -mlwp -mfsgsbase -mrdrnd -mf16c" } */
+/* { dg-options "-O -pedantic-errors -march=k8 -msse4a -m3dnow -mavx -mfma4 -mxop -maes -mpclmul -mpopcnt -mabm -mlzcnt -mbmi -mtbm -mlwp -mfsgsbase -mrdrnd -mf16c" } */
 
 /* Test that {,x,e,p,t,s,w,a,b,i}mmintrin.h, mm3dnow.h, fma4intrin.h,
    xopintrin.h, abmintrin.h, bmiintrin.h, tbmintrin.h, lwpintrin.h,
diff --git a/gcc/testsuite/g++.dg/other/i386-3.C b/gcc/testsuite/g++.dg/other/i386-3.C
index 66eec14..626f972 100644
--- a/gcc/testsuite/g++.dg/other/i386-3.C
+++ b/gcc/testsuite/g++.dg/other/i386-3.C
@@ -1,5 +1,5 @@
 /* { dg-do compile { target i?86-*-* x86_64-*-* } } */
-/* { dg-options "-O -fkeep-inline-functions -march=k8 -msse4a -m3dnow -mavx -mfma4 -mxop -maes -mpclmul -mpopcnt -mabm -mbmi -mtbm -mlwp -mfsgsbase -mrdrnd -mf16c" } */
+/* { dg-options "-O -fkeep-inline-functions -march=k8 -msse4a -m3dnow -mavx -mfma4 -mxop -maes -mpclmul -mpopcnt -mabm -mlzcnt -mbmi -mtbm -mlwp -mfsgsbase -mrdrnd -mf16c" } */
 
 /* Test that {,x,e,p,t,s,w,a,b,i}mmintrin.h, mm3dnow.h, fma4intrin.h,
    xopintrin.h, abmintrin.h, bmiintrin.h, tbmintrin.h, lwpintrin.h,
diff --git a/gcc/testsuite/gcc.target/i386/i386.exp b/gcc/testsuite/gcc.target/i386/i386.exp
index 13d8cff..167b79b 100644
--- a/gcc/testsuite/gcc.target/i386/i386.exp
+++ b/gcc/testsuite/gcc.target/i386/i386.exp
@@ -186,6 +186,16 @@ proc check_effective_target_xop { } {
     } "-O2 -mxop" ]
 }
 
+# Return 1 if lzcnt instruction can be compiled.
+proc check_effective_target_lzcnt { } {
+    return [check_no_compiler_messages lzcnt object {
+	unsigned short _lzcnt (unsigned short __X)
+	{
+	   return __builtin_clzs (__X);
+	}
+    } "-mlzcnt" ]
+}
+
 # Return 1 if bmi instructions can be compiled.
 proc check_effective_target_bmi { } {
     return [check_no_compiler_messages bmi object {
diff --git a/gcc/testsuite/gcc.target/i386/lzcnt-1.c b/gcc/testsuite/gcc.target/i386/lzcnt-1.c
new file mode 100644
index 0000000..f6240d1b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/lzcnt-1.c
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -mlzcnt " } */
+/* { dg-final { scan-assembler "lzcntw\[^\\n]*(%|)ax" } } */
+
+#include <x86intrin.h>
+
+unsigned int
+func_lzcnt16 (unsigned int X)
+{
+  return __lzcnt16(X);
+}
diff --git a/gcc/testsuite/gcc.target/i386/lzcnt-2.c b/gcc/testsuite/gcc.target/i386/lzcnt-2.c
new file mode 100644
index 0000000..329a11f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/lzcnt-2.c
@@ -0,0 +1,35 @@
+/* { dg-do run { target { lzcnt } } } */
+/* { dg-options "-O2 -mlzcnt -fno-inline" } */
+
+#include <x86intrin.h>
+
+#include "lzcnt-check.h"
+
+short calc_lzcnt_u16 (short src)
+{
+  int i;
+  short res = 0;
+
+  while ((res < 16) && (((src >> (15 - res)) & 1) == 0))
+    ++res;
+
+  return res;
+}
+
+static void
+lzcnt_test ()
+{
+  unsigned i;
+  short src = 0x7ace;
+  short res, res_ref;
+
+  for (i=0; i<5; ++i) {
+    src = src >> i;
+
+    res_ref = calc_lzcnt_u16 (src);
+    res = __lzcnt16 (src);
+
+    if (res != res_ref)
+      abort();
+  }
+}
diff --git a/gcc/testsuite/gcc.target/i386/lzcnt-2a.c b/gcc/testsuite/gcc.target/i386/lzcnt-2a.c
new file mode 100644
index 0000000..fe1069f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/lzcnt-2a.c
@@ -0,0 +1,6 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -mlzcnt" } */
+
+#include "lzcnt-2.c"
+
+/* { dg-final { scan-assembler "lzcntw" } } */
diff --git a/gcc/testsuite/gcc.target/i386/lzcnt-3.c b/gcc/testsuite/gcc.target/i386/lzcnt-3.c
new file mode 100644
index 0000000..1477951
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/lzcnt-3.c
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-options "-O0 -mlzcnt " } */
+/* { dg-final { scan-assembler "lzcntl\[^\\n]*(%|)eax" } } */
+
+#include <x86intrin.h>
+
+unsigned int
+func_lzcnt32 (unsigned int X)
+{
+  return __lzcnt32(X);
+}
diff --git a/gcc/testsuite/gcc.target/i386/lzcnt-4.c b/gcc/testsuite/gcc.target/i386/lzcnt-4.c
new file mode 100644
index 0000000..2065326
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/lzcnt-4.c
@@ -0,0 +1,35 @@
+/* { dg-do run { target { lzcnt } } } */
+/* { dg-options "-O2 -mlzcnt -fno-inline" } */
+
+#include <x86intrin.h>
+
+#include "lzcnt-check.h"
+
+int calc_lzcnt_u32 (int src)
+{
+  int i;
+  int res = 0;
+
+  while ((res < 32) && (((src >> (31 - res)) & 1) == 0))
+    ++res;
+
+  return res;
+}
+
+static void
+lzcnt_test ()
+{
+  unsigned i;
+  int src = 0xce7ace0;
+  int res, res_ref;
+
+  for (i=0; i<5; ++i) {
+    src = src >> i;
+
+    res_ref = calc_lzcnt_u32 (src);
+    res = __lzcnt32 (src);
+
+    if (res != res_ref)
+      abort();
+  }
+}
diff --git a/gcc/testsuite/gcc.target/i386/lzcnt-4a.c b/gcc/testsuite/gcc.target/i386/lzcnt-4a.c
new file mode 100644
index 0000000..6bba6a9
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/lzcnt-4a.c
@@ -0,0 +1,6 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -mlzcnt" } */
+
+#include "lzcnt-4.c"
+
+/* { dg-final { scan-assembler "lzcntl" } } */
diff --git a/gcc/testsuite/gcc.target/i386/lzcnt-5.c b/gcc/testsuite/gcc.target/i386/lzcnt-5.c
new file mode 100644
index 0000000..a4b9aaf
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/lzcnt-5.c
@@ -0,0 +1,11 @@
+/* { dg-do compile { target { ! ia32 } } } */
+/* { dg-options "-O2 -mlzcnt" } */
+/* { dg-final { scan-assembler "lzcntq\[^\\n]*(%|)rax" } } */
+
+#include <x86intrin.h>
+
+unsigned int
+func_lzcnt64 (unsigned long long X)
+{
+  return __lzcnt64(X);
+}
diff --git a/gcc/testsuite/gcc.target/i386/lzcnt-6.c b/gcc/testsuite/gcc.target/i386/lzcnt-6.c
new file mode 100644
index 0000000..f0bf5da
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/lzcnt-6.c
@@ -0,0 +1,35 @@
+/* { dg-do run { target { lzcnt && { ! ia32 } } } } */
+/* { dg-options "-O2 -mlzcnt -fno-inline" } */
+
+#include <x86intrin.h>
+
+#include "lzcnt-check.h"
+
+long long calc_lzcnt_u64 (long long src)
+{
+  int i;
+  int res = 0;
+
+  while ((res < 64) && (((src >> (63 - res)) & 1) == 0))
+    ++res;
+
+  return res;
+}
+
+static void
+lzcnt_test ()
+{
+  unsigned i;
+  long long src = 0xce7ace0ce7ace0;
+  long long res, res_ref;
+
+  for (i=0; i<5; ++i) {
+    src = src >> i;
+
+    res_ref = calc_lzcnt_u64 (src);
+    res = __lzcnt64 (src);
+
+    if (res != res_ref)
+      abort();
+  }
+}
diff --git a/gcc/testsuite/gcc.target/i386/lzcnt-6a.c b/gcc/testsuite/gcc.target/i386/lzcnt-6a.c
new file mode 100644
index 0000000..2090093
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/lzcnt-6a.c
@@ -0,0 +1,6 @@
+/* { dg-do compile { target { ! ia32 } } } */
+/* { dg-options "-O2 -mlzcnt" } */
+
+#include "lzcnt-6.c"
+
+/* { dg-final { scan-assembler "lzcntq" } } */
diff --git a/gcc/testsuite/gcc.target/i386/lzcnt-check.h b/gcc/testsuite/gcc.target/i386/lzcnt-check.h
new file mode 100644
index 0000000..8aad834
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/lzcnt-check.h
@@ -0,0 +1,37 @@
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "cpuid.h"
+
+static void lzcnt_test (void);
+
+static void
+__attribute__ ((noinline))
+do_test (void)
+{
+  lzcnt_test ();
+}
+
+int
+main ()
+{
+  unsigned int eax, ebx, ecx, edx;
+
+  if (!__get_cpuid (0x80000001, &eax, &ebx, &ecx, &edx))
+    return 0;
+
+  /* Run LZCNT test only if host has LZCNT support.  */
+  if (ecx & bit_LZCNT)
+    {
+      do_test ();
+#ifdef DEBUG
+      printf ("PASSED\n");
+#endif
+    }
+#ifdef DEBUG
+  else
+    printf ("SKIPPED\n");
+#endif
+
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/i386/sse-12.c b/gcc/testsuite/gcc.target/i386/sse-12.c
index 4f8aaec..59e659e 100644
--- a/gcc/testsuite/gcc.target/i386/sse-12.c
+++ b/gcc/testsuite/gcc.target/i386/sse-12.c
@@ -3,7 +3,7 @@
    popcntintrin.h and mm_malloc.h are usable
    with -O -std=c89 -pedantic-errors.  */
 /* { dg-do compile } */
-/* { dg-options "-O -std=c89 -pedantic-errors -march=k8 -msse4a -m3dnow -mavx -mfma4 -mxop -maes -mpclmul -mpopcnt -mabm -mbmi -mtbm -mlwp -mfsgsbase -mrdrnd -mf16c" } */
+/* { dg-options "-O -std=c89 -pedantic-errors -march=k8 -msse4a -m3dnow -mavx -mfma4 -mxop -maes -mpclmul -mpopcnt -mabm -mlzcnt -mbmi -mtbm -mlwp -mfsgsbase -mrdrnd -mf16c" } */
 
 #include <x86intrin.h>
 
diff --git a/gcc/testsuite/gcc.target/i386/sse-13.c b/gcc/testsuite/gcc.target/i386/sse-13.c
index 188b2e6..836272d 100644
--- a/gcc/testsuite/gcc.target/i386/sse-13.c
+++ b/gcc/testsuite/gcc.target/i386/sse-13.c
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O2 -Werror-implicit-function-declaration -march=k8 -msse4a -m3dnow -mavx -mfma4 -mxop -maes -mpclmul -mpopcnt -mabm -mbmi -mtbm -mlwp -mfsgsbase -mrdrnd -mf16c" } */
+/* { dg-options "-O2 -Werror-implicit-function-declaration -march=k8 -msse4a -m3dnow -mavx -mfma4 -mxop -maes -mpclmul -mpopcnt -mabm -mlzcnt -mbmi -mtbm -mlwp -mfsgsbase -mrdrnd -mf16c" } */
 
 #include <mm_malloc.h>
 
diff --git a/gcc/testsuite/gcc.target/i386/sse-14.c b/gcc/testsuite/gcc.target/i386/sse-14.c
index 22ea61f..af42781 100644
--- a/gcc/testsuite/gcc.target/i386/sse-14.c
+++ b/gcc/testsuite/gcc.target/i386/sse-14.c
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O0 -Werror-implicit-function-declaration -march=k8 -msse4a -m3dnow -mavx -mfma4 -mxop -maes -mpclmul -mpopcnt -mabm -mbmi -mtbm -mlwp -mfsgsbase -mrdrnd -mf16c" } */
+/* { dg-options "-O0 -Werror-implicit-function-declaration -march=k8 -msse4a -m3dnow -mavx -mfma4 -mxop -maes -mpclmul -mpopcnt -mabm -mlzcnt -mbmi -mtbm -mlwp -mfsgsbase -mrdrnd -mf16c" } */
 
 #include <mm_malloc.h>
 

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [Patch, i386, testsuite] Fix for PR49547, new tescases for lzcnt instruction
  2011-08-01 13:13                                           ` Kirill Yukhin
@ 2011-08-02  0:33                                             ` H.J. Lu
  0 siblings, 0 replies; 25+ messages in thread
From: H.J. Lu @ 2011-08-02  0:33 UTC (permalink / raw)
  To: Kirill Yukhin; +Cc: Uros Bizjak, Mike Stump, gcc-patches List, Jagasia, Harsha

On Mon, Aug 1, 2011 at 6:13 AM, Kirill Yukhin <kirill.yukhin@gmail.com> wrote:
> Done.
> Updated patch is attached.
>
> Thanks, K
>
> On Mon, Aug 1, 2011 at 4:49 PM, H.J. Lu <hjl.tools@gmail.com> wrote:
>> On Mon, Aug 1, 2011 at 5:36 AM, Kirill Yukhin <kirill.yukhin@gmail.com> wrote:
>>> Hi HJ,
>>> Thanks for input. I've missed it.
>>> Done. Updated patch is attached.
>>
>> Compiler may still optimize it away.  You need to replace 0 with
>> a function parameter.  Please see:
>>
>> http://gcc.gnu.org/ml/gcc-patches/2011-07/msg02463.html
>>
>>
>> H.J.
>> ---
>>> Thanks, K
>>>
>>> On Mon, Aug 1, 2011 at 4:26 PM, H.J. Lu <hjl.tools@gmail.com> wrote:
>>>> On Mon, Aug 1, 2011 at 5:20 AM, Kirill Yukhin <kirill.yukhin@gmail.com> wrote:
>>>>> I've merged my changes with trunk (there was a conflict) and fixed typo.
>>>>> Updated patch is attached. Waiting for commit...
>>>>>
>>>>> Thanks, K
>>>>>
>>>>> On Mon, Aug 1, 2011 at 1:03 PM, Kirill Yukhin <kirill.yukhin@gmail.com> wrote:
>>>>>> Thanks!
>>>>>> Guys with waa rights, could anybody commit my fix?
>>>>>>
>>>>>> Thanks, K
>>>>>>
>>>>>>>
>>>>>>> OK for mainline.
>>>>>>>
>>>>>>> Uros.
>>>>>>>
>>>>>>
>>>>
>>>>
>>>> +# Return 1 if lzcnt instruction can be compiled.
>>>> +proc check_effective_target_lzcnt { } {
>>>> +    return [check_no_compiler_messages lzcnt object {
>>>> +       void _lzcnt (void)
>>>> +       {
>>>> +          __builtin_clzs (0);
>>>> +       }
>>>> +    } "-O2 -mlzcnt" ]
>>>> +}
>>>>
>>>> GCC may optimize this away.  Please fix it similar to:
>>>>
>>>> http://gcc.gnu.org/ml/gcc-patches/2011-07/msg02463.html
>>>>
>>>
>>
>

We should use long long on 64bit intrinsic.  I checked
in this as an obvious fix.

-- 
H.J.
---
Index: ChangeLog
===================================================================
--- ChangeLog	(revision 177080)
+++ ChangeLog	(working copy)
@@ -1,3 +1,8 @@
+2011-08-01  H.J. Lu  <hongjiu.lu@intel.com>
+
+	* config/i386/lzcntintrin.h (__lzcnt64): Replace long with
+	long long.
+
 2011-08-01  Sebastian Pop  <sebastian.pop@amd.com>
 	    Joseph Myers  <joseph@codesourcery.com>

Index: config/i386/lzcntintrin.h
===================================================================
--- config/i386/lzcntintrin.h	(revision 177080)
+++ config/i386/lzcntintrin.h	(working copy)
@@ -45,10 +45,10 @@ __lzcnt32 (unsigned int __X)
 }

 #ifdef __x86_64__
-extern __inline unsigned long __attribute__((__gnu_inline__, __always_inline__,
 __artificial__))
-__lzcnt64 (unsigned long __X)
+extern __inline unsigned long long __attribute__((__gnu_inline__, __always_inli
ne__, __artificial__))
+__lzcnt64 (unsigned long long __X)
 {
-  return __builtin_clzl (__X);
+  return __builtin_clzll (__X);
 }
 #endif

^ permalink raw reply	[flat|nested] 25+ messages in thread

end of thread, other threads:[~2011-08-02  0:33 UTC | newest]

Thread overview: 25+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-07-26 15:40 [Patch, i386, testsuite] Fix for PR49547, new tescases for lzcnt instruction Kirill Yukhin
2011-07-26 15:45 ` Mike Stump
2011-07-26 16:43   ` Uros Bizjak
2011-07-27  8:06     ` Kirill Yukhin
2011-07-27  8:12       ` Uros Bizjak
2011-07-27 11:16         ` Kirill Yukhin
2011-07-27 11:58           ` Uros Bizjak
2011-07-27 14:27             ` Kirill Yukhin
2011-07-27 14:42               ` H.J. Lu
2011-07-27 15:00                 ` Kirill Yukhin
2011-07-27 16:06                 ` Kirill Yukhin
2011-07-27 16:10                   ` H.J. Lu
2011-07-27 16:22                     ` Kirill Yukhin
2011-07-27 17:18                       ` Uros Bizjak
2011-07-27 17:19                         ` H.J. Lu
2011-07-27 19:14                           ` Kirill Yukhin
2011-08-01  8:22                             ` Kirill Yukhin
2011-08-01  8:37                               ` Uros Bizjak
2011-08-01  9:04                                 ` Kirill Yukhin
2011-08-01 12:21                                   ` Kirill Yukhin
2011-08-01 12:26                                     ` H.J. Lu
2011-08-01 12:36                                       ` Kirill Yukhin
2011-08-01 12:50                                         ` H.J. Lu
2011-08-01 13:13                                           ` Kirill Yukhin
2011-08-02  0:33                                             ` H.J. Lu

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).