--- /dev/null
+/* PR tree-optimization/114760 */
+/* { dg-do compile } */
+/* { dg-require-effective-target clz } */
+/* { dg-require-effective-target ctz } */
+/* { dg-options "-O3 -fdump-tree-optimized" } */
+
+unsigned
+ntz32_1 (unsigned x)
+{
+ int n = 32;
+ while (x != 0)
+ {
+ n = n - 1;
+ x = x * 2;
+ }
+ return n;
+}
+
+unsigned
+ntz32_2 (unsigned x)
+{
+ int n = 32;
+ while (x != 0)
+ {
+ n = n - 1;
+ x = x + x;
+ }
+ return n;
+}
+
+unsigned
+ntz32_3 (unsigned x)
+{
+ int n = 32;
+ while (x != 0)
+ {
+ n = n - 1;
+ x = x << 1;
+ }
+ return n;
+}
+
+#define PREC (__CHAR_BIT__ * __SIZEOF_INT__)
+int
+nlz32_1 (unsigned int b) {
+ int c = PREC;
+
+ while (b != 0) {
+ b >>= 1;
+ c --;
+ }
+
+ return c;
+}
+
+int
+nlz32_2 (unsigned int b) {
+ int c = PREC;
+
+ while (b != 0) {
+ b /= 2;
+ c --;
+ }
+
+ return c;
+}
+
+/* { dg-final { scan-tree-dump-times "__builtin_ctz|\\.CTZ" 3 "optimized" } } */
+/* { dg-final { scan-tree-dump-times "__builtin_clz|\\.CLZ" 2 "optimized" } } */
\ No newline at end of file
--- /dev/null
+/* PR tree-optimization/114760 */
+/* { dg-do compile } */
+/* { dg-require-effective-target clz } */
+/* { dg-options "-O3 -fdump-tree-optimized" } */
+
+// Check that for signed type, there's no CLZ.
+#define PREC (__CHAR_BIT__ * __SIZEOF_INT__)
+int
+no_nlz32 (int b) {
+ int c = PREC;
+
+ while (b != 0) {
+ b /= 2;
+ c --;
+ }
+
+ return c;
+}
+
+/* { dg-final { scan-tree-dump-not "__builtin_ctz|\\.CLZ" "optimized" } } */
\ No newline at end of file
return call;
}
+/* Returns true if STMT is equivalent to x << 1. */
+
+static bool
+is_lshift_by_1 (gassign *stmt)
+{
+ if (gimple_assign_rhs_code (stmt) == LSHIFT_EXPR
+ && integer_onep (gimple_assign_rhs2 (stmt)))
+ return true;
+ if (gimple_assign_rhs_code (stmt) == MULT_EXPR
+ && tree_fits_shwi_p (gimple_assign_rhs2 (stmt))
+ && tree_to_shwi (gimple_assign_rhs2 (stmt)) == 2)
+ return true;
+ return false;
+}
+
+/* Returns true if STMT is equivalent to x >> 1. */
+
+static bool
+is_rshift_by_1 (gassign *stmt)
+{
+ if (!TYPE_UNSIGNED (TREE_TYPE (gimple_assign_lhs (stmt))))
+ return false;
+ if (gimple_assign_rhs_code (stmt) == RSHIFT_EXPR
+ && integer_onep (gimple_assign_rhs2 (stmt)))
+ return true;
+ if (gimple_assign_rhs_code (stmt) == TRUNC_DIV_EXPR
+ && tree_fits_shwi_p (gimple_assign_rhs2 (stmt))
+ && tree_to_shwi (gimple_assign_rhs2 (stmt)) == 2)
+ return true;
+ return false;
+}
+
/* See comment below for number_of_iterations_bitcount.
For c[lt]z, we have:
/* Make sure iv_2_stmt is a logical shift by one stmt:
iv_2 = iv_1 {<<|>>} 1 */
- if (!is_gimple_assign (iv_2_stmt)
- || (gimple_assign_rhs_code (iv_2_stmt) != LSHIFT_EXPR
- && (gimple_assign_rhs_code (iv_2_stmt) != RSHIFT_EXPR
- || !TYPE_UNSIGNED (TREE_TYPE (gimple_assign_lhs (iv_2_stmt)))))
- || !integer_onep (gimple_assign_rhs2 (iv_2_stmt)))
+ if (!is_gimple_assign (iv_2_stmt))
+ return false;
+ bool left_shift = false;
+ if (!((left_shift = is_lshift_by_1 (as_a <gassign *> (iv_2_stmt)))
+ || is_rshift_by_1 (as_a <gassign *> (iv_2_stmt))))
return false;
-
- bool left_shift = (gimple_assign_rhs_code (iv_2_stmt) == LSHIFT_EXPR);
tree iv_1 = gimple_assign_rhs1 (iv_2_stmt);
/* Make sure iv_2_stmt is a logical shift by one stmt:
iv_2 = iv_1 {>>|<<} 1 */
- if (!is_gimple_assign (iv_2_stmt)
- || (gimple_assign_rhs_code (iv_2_stmt) != LSHIFT_EXPR
- && (gimple_assign_rhs_code (iv_2_stmt) != RSHIFT_EXPR
- || !TYPE_UNSIGNED (TREE_TYPE (gimple_assign_lhs (iv_2_stmt)))))
- || !integer_onep (gimple_assign_rhs2 (iv_2_stmt)))
+ if (!is_gimple_assign (iv_2_stmt))
+ return false;
+ bool left_shift = false;
+ if (!((left_shift = is_lshift_by_1 (as_a <gassign *> (iv_2_stmt)))
+ || is_rshift_by_1 (as_a <gassign *> (iv_2_stmt))))
return false;
-
- bool left_shift = (gimple_assign_rhs_code (iv_2_stmt) == LSHIFT_EXPR);
tree iv_1 = gimple_assign_rhs1 (iv_2_stmt);