aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/ChangeLog8
-rw-r--r--gcc/config/i386/i386.c104
-rw-r--r--gcc/testsuite/ChangeLog3
-rw-r--r--gcc/testsuite/gcc.target/i386/pr78057.c42
4 files changed, 157 insertions, 0 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 299ffe4..4d88ef7 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,5 +1,13 @@
2016-10-21 Jakub Jelinek <jakub@redhat.com>
+ PR target/78057
+ * config/i386/i386.c: Include fold-const-call.h, tree-vrp.h
+ and tree-ssanames.h.
+ (ix86_fold_builtin): Fold IX86_BUILTIN_[LT]ZCNT{16,32,64}
+ with INTEGER_CST argument.
+ (ix86_gimple_fold_builtin): New function.
+ (TARGET_GIMPLE_FOLD_BUILTIN): Define.
+
* dwarf2out.c (ranges_table): Change into vec<dw_ranges, va_gc> *.
(ranges_by_label): Change into vec<dw_ranges_by_label, va_gc> *.
(ranges_table_allocated, ranges_table_in_use,
diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
index 618d974..69ad339 100644
--- a/gcc/config/i386/i386.c
+++ b/gcc/config/i386/i386.c
@@ -77,6 +77,9 @@ along with GCC; see the file COPYING3. If not see
#include "case-cfn-macros.h"
#include "regrename.h"
#include "dojump.h"
+#include "fold-const-call.h"
+#include "tree-vrp.h"
+#include "tree-ssanames.h"
/* This file should be included last. */
#include "target-def.h"
@@ -33332,6 +33335,40 @@ ix86_fold_builtin (tree fndecl, int n_args,
return build_real (type, inf);
}
+ case IX86_BUILTIN_TZCNT16:
+ case IX86_BUILTIN_TZCNT32:
+ case IX86_BUILTIN_TZCNT64:
+ gcc_assert (n_args == 1);
+ if (TREE_CODE (args[0]) == INTEGER_CST)
+ {
+ tree type = TREE_TYPE (TREE_TYPE (fndecl));
+ tree arg = args[0];
+ if (fn_code == IX86_BUILTIN_TZCNT16)
+ arg = fold_convert (short_unsigned_type_node, arg);
+ if (integer_zerop (arg))
+ return build_int_cst (type, TYPE_PRECISION (TREE_TYPE (arg)));
+ else
+ return fold_const_call (CFN_CTZ, type, arg);
+ }
+ break;
+
+ case IX86_BUILTIN_LZCNT16:
+ case IX86_BUILTIN_LZCNT32:
+ case IX86_BUILTIN_LZCNT64:
+ gcc_assert (n_args == 1);
+ if (TREE_CODE (args[0]) == INTEGER_CST)
+ {
+ tree type = TREE_TYPE (TREE_TYPE (fndecl));
+ tree arg = args[0];
+ if (fn_code == IX86_BUILTIN_LZCNT16)
+ arg = fold_convert (short_unsigned_type_node, arg);
+ if (integer_zerop (arg))
+ return build_int_cst (type, TYPE_PRECISION (TREE_TYPE (arg)));
+ else
+ return fold_const_call (CFN_CLZ, type, arg);
+ }
+ break;
+
default:
break;
}
@@ -33344,6 +33381,70 @@ ix86_fold_builtin (tree fndecl, int n_args,
return NULL_TREE;
}
+/* Fold a MD builtin (use ix86_fold_builtin for folding into
+ constant) in GIMPLE. */
+
+bool
+ix86_gimple_fold_builtin (gimple_stmt_iterator *gsi)
+{
+ gimple *stmt = gsi_stmt (*gsi);
+ tree fndecl = gimple_call_fndecl (stmt);
+ gcc_checking_assert (fndecl && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_MD);
+ int n_args = gimple_call_num_args (stmt);
+ enum ix86_builtins fn_code = (enum ix86_builtins) DECL_FUNCTION_CODE (fndecl);
+ tree decl = NULL_TREE;
+ tree arg0;
+
+ switch (fn_code)
+ {
+ case IX86_BUILTIN_TZCNT32:
+ decl = builtin_decl_implicit (BUILT_IN_CTZ);
+ goto fold_tzcnt_lzcnt;
+
+ case IX86_BUILTIN_TZCNT64:
+ decl = builtin_decl_implicit (BUILT_IN_CTZLL);
+ goto fold_tzcnt_lzcnt;
+
+ case IX86_BUILTIN_LZCNT32:
+ decl = builtin_decl_implicit (BUILT_IN_CLZ);
+ goto fold_tzcnt_lzcnt;
+
+ case IX86_BUILTIN_LZCNT64:
+ decl = builtin_decl_implicit (BUILT_IN_CLZLL);
+ goto fold_tzcnt_lzcnt;
+
+ fold_tzcnt_lzcnt:
+ gcc_assert (n_args == 1);
+ arg0 = gimple_call_arg (stmt, 0);
+ if (TREE_CODE (arg0) == SSA_NAME && decl && gimple_call_lhs (stmt))
+ {
+ int prec = TYPE_PRECISION (TREE_TYPE (arg0));
+ /* If arg0 is provably non-zero, optimize into generic
+ __builtin_c[tl]z{,ll} function the middle-end handles
+ better. */
+ if (!expr_not_equal_to (arg0, wi::zero (prec)))
+ return false;
+
+ location_t loc = gimple_location (stmt);
+ gimple *g = gimple_build_call (decl, 1, arg0);
+ gimple_set_location (g, loc);
+ tree lhs = make_ssa_name (integer_type_node);
+ gimple_call_set_lhs (g, lhs);
+ gsi_insert_before (gsi, g, GSI_SAME_STMT);
+ g = gimple_build_assign (gimple_call_lhs (stmt), NOP_EXPR, lhs);
+ gimple_set_location (g, loc);
+ gsi_replace (gsi, g, true);
+ return true;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return false;
+}
+
/* Make builtins to detect cpu type and features supported. NAME is
the builtin name, CODE is the builtin code, and FTYPE is the function
type of the builtin. */
@@ -50531,6 +50632,9 @@ ix86_addr_space_zero_address_valid (addr_space_t as)
#undef TARGET_FOLD_BUILTIN
#define TARGET_FOLD_BUILTIN ix86_fold_builtin
+#undef TARGET_GIMPLE_FOLD_BUILTIN
+#define TARGET_GIMPLE_FOLD_BUILTIN ix86_gimple_fold_builtin
+
#undef TARGET_COMPARE_VERSION_PRIORITY
#define TARGET_COMPARE_VERSION_PRIORITY ix86_compare_version_priority
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index fafdbfc..0754aec 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,5 +1,8 @@
2016-10-21 Jakub Jelinek <jakub@redhat.com>
+ PR target/78057
+ * gcc.target/i386/pr78057.c: New test.
+
* g++.dg/debug/dwarf2/constexpr-var-1.C: New test.
2016-10-21 Paul Thomas <pault@gcc.gnu.org>
diff --git a/gcc/testsuite/gcc.target/i386/pr78057.c b/gcc/testsuite/gcc.target/i386/pr78057.c
new file mode 100644
index 0000000..493a533
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr78057.c
@@ -0,0 +1,42 @@
+/* PR target/78057 */
+/* { dg-do compile } */
+/* { dg-options "-O2 -mbmi -mlzcnt -fdump-tree-optimized" } */
+
+extern void link_error (void);
+
+int
+foo (int x)
+{
+ if (__builtin_ia32_tzcnt_u16 (16) != 4
+ || __builtin_ia32_tzcnt_u16 (0) != 16
+ || __builtin_ia32_lzcnt_u16 (0x1ff) != 7
+ || __builtin_ia32_lzcnt_u16 (0) != 16
+ || __builtin_ia32_tzcnt_u32 (8) != 3
+ || __builtin_ia32_tzcnt_u32 (0) != 32
+ || __builtin_ia32_lzcnt_u32 (0x3fffffff) != 2
+ || __builtin_ia32_lzcnt_u32 (0) != 32
+#ifdef __x86_64__
+ || __builtin_ia32_tzcnt_u64 (4) != 2
+ || __builtin_ia32_tzcnt_u64 (0) != 64
+ || __builtin_ia32_lzcnt_u64 (0x1fffffff) != 35
+ || __builtin_ia32_lzcnt_u64 (0) != 64
+#endif
+ )
+ link_error ();
+ x += 2;
+ if (x == 0)
+ return 5;
+ return __builtin_ia32_tzcnt_u32 (x)
+ + __builtin_ia32_lzcnt_u32 (x)
+#ifdef __x86_64__
+ + __builtin_ia32_tzcnt_u64 (x)
+ + __builtin_ia32_lzcnt_u64 (x)
+#endif
+ ;
+}
+
+/* { dg-final { scan-tree-dump-not "link_error" "optimized" } } */
+/* { dg-final { scan-tree-dump-not "__builtin_ia32_\[lt]zcnt" "optimized" } } */
+/* { dg-final { scan-tree-dump-times "__builtin_ctz " 1 "optimized" } } */
+/* { dg-final { scan-tree-dump-times "__builtin_clz " 1 "optimized" } } */
+/* { dg-final { scan-tree-dump-times "__builtin_ctzll " 1 "optimized" { target lp64 } } } */