Hello! Attached patch removes invalid substitution of zero-extended HImode operands with HImode operation. CLZ returns different value when operating on SImode value vs. HImode value.
2017-06-08 Uros Bizjak <ubiz...@gmail.com> PR target/81015 Revert: 2016-12-14 Uros Bizjak <ubiz...@gmail.com> PR target/59874 * config/i386/i386.md (*ctzhi2): New insn_and_split pattern. (*clzhi2): Ditto. testsuite/ChangeLog: 2017-06-08 Uros Bizjak <ubiz...@gmail.com> PR target/81015 * gcc.target/i386/pr59874-1.c (foo): Call __builtin_ctzs. * gcc.target/i386/pr59874-2.c (foo): Call __builtin_clzs. * gcc.target/i386/pr81015.c: New test. Bootstrapped and regression tested on x86_64-linux-gnu {,-m32}. Committed to mainline SVN, will be committed to gcc-7 branch. Uros.
Index: config/i386/i386.md =================================================================== --- config/i386/i386.md (revision 249018) +++ config/i386/i386.md (working copy) @@ -12762,24 +12762,6 @@ (set_attr "znver1_decode" "vector") (set_attr "mode" "<MODE>")]) -(define_insn_and_split "*ctzhi2" - [(set (match_operand:SI 0 "register_operand") - (ctz:SI - (zero_extend:SI (match_operand:HI 1 "nonimmediate_operand")))) - (clobber (reg:CC FLAGS_REG))] - "TARGET_BMI - && can_create_pseudo_p ()" - "#" - "&& 1" - [(const_int 0)] -{ - rtx tmp = gen_reg_rtx (HImode); - - emit_insn (gen_tzcnt_hi (tmp, operands[1])); - emit_insn (gen_zero_extendhisi2 (operands[0], tmp)); - DONE; -}) - (define_insn_and_split "ctz<mode>2" [(set (match_operand:SWI48 0 "register_operand" "=r") (ctz:SWI48 @@ -12899,24 +12881,6 @@ operands[2] = GEN_INT (GET_MODE_BITSIZE (<MODE>mode)-1); }) -(define_insn_and_split "*clzhi2" - [(set (match_operand:SI 0 "register_operand") - (clz:SI - (zero_extend:SI (match_operand:HI 1 "nonimmediate_operand")))) - (clobber (reg:CC FLAGS_REG))] - "TARGET_LZCNT - && can_create_pseudo_p ()" - "#" - "&& 1" - [(const_int 0)] -{ - rtx tmp = gen_reg_rtx (HImode); - - emit_insn (gen_lzcnt_hi (tmp, operands[1])); - emit_insn (gen_zero_extendhisi2 (operands[0], tmp)); - DONE; -}) - (define_insn_and_split "clz<mode>2_lzcnt" [(set (match_operand:SWI48 0 "register_operand" "=r") (clz:SWI48 Index: testsuite/gcc.target/i386/pr59874-1.c =================================================================== --- testsuite/gcc.target/i386/pr59874-1.c (revision 249018) +++ testsuite/gcc.target/i386/pr59874-1.c (working copy) @@ -6,5 +6,5 @@ unsigned int foo (unsigned short x) { - return x ? __builtin_ctz (x) : 16U; + return x ? __builtin_ctzs (x) : 16U; } Index: testsuite/gcc.target/i386/pr59874-2.c =================================================================== --- testsuite/gcc.target/i386/pr59874-2.c (revision 249018) +++ testsuite/gcc.target/i386/pr59874-2.c (working copy) @@ -6,5 +6,5 @@ unsigned int foo (unsigned short x) { - return x ? __builtin_clz (x) : 16U; + return x ? __builtin_clzs (x) : 16U; } Index: testsuite/gcc.target/i386/pr81015.c =================================================================== --- testsuite/gcc.target/i386/pr81015.c (nonexistent) +++ testsuite/gcc.target/i386/pr81015.c (working copy) @@ -0,0 +1,21 @@ +/* { dg-do run } */ +/* { dg-options "-O2 -mlzcnt" } */ +/* { dg-require-effective-target lzcnt } */ + +#include "lzcnt-check.h" + +int +__attribute__ ((noinline, noclone)) +foo (unsigned short a) +{ + return __builtin_clz (a); +} + +static void +lzcnt_test () +{ + int res = foo (1); + + if (res != 31) + abort (); +}