aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc')
-rw-r--r--gcc/builtins.cc277
-rw-r--r--gcc/builtins.def6
-rw-r--r--gcc/c-family/c-common.cc74
-rw-r--r--gcc/c-family/c-gimplify.cc22
-rw-r--r--gcc/c/c-typeck.cc18
-rw-r--r--gcc/cp/call.cc14
-rw-r--r--gcc/cp/cp-gimplify.cc4
-rw-r--r--gcc/doc/extend.texi42
-rw-r--r--gcc/fold-const-call.cc68
-rw-r--r--gcc/genmatch.cc66
-rw-r--r--gcc/gimple-lower-bitint.cc527
-rw-r--r--gcc/gimple-range-op.cc67
-rw-r--r--gcc/match.pd202
-rw-r--r--gcc/testsuite/c-c++-common/pr111309-1.c470
-rw-r--r--gcc/testsuite/c-c++-common/pr111309-2.c85
-rw-r--r--gcc/testsuite/gcc.dg/torture/bitint-43.c306
-rw-r--r--gcc/testsuite/gcc.dg/torture/bitint-44.c306
-rw-r--r--gcc/tree-ssa-forwprop.cc8
-rw-r--r--gcc/tree-ssa-loop-niter.cc10
-rw-r--r--gcc/tree-ssa-phiopt.cc66
-rw-r--r--gcc/tree-vect-patterns.cc65
-rw-r--r--gcc/tree-vect-stmts.cc16
22 files changed, 2576 insertions, 143 deletions
diff --git a/gcc/builtins.cc b/gcc/builtins.cc
index cb90bd0..5ece0d2 100644
--- a/gcc/builtins.cc
+++ b/gcc/builtins.cc
@@ -9573,6 +9573,271 @@ fold_builtin_arith_overflow (location_t loc, enum built_in_function fcode,
return build2_loc (loc, COMPOUND_EXPR, boolean_type_node, store, ovfres);
}
+/* Fold __builtin_{clz,ctz,clrsb,ffs,parity,popcount}g into corresponding
+ internal function. */
+
+static tree
+fold_builtin_bit_query (location_t loc, enum built_in_function fcode,
+ tree arg0, tree arg1)
+{
+ enum internal_fn ifn;
+ enum built_in_function fcodei, fcodel, fcodell;
+ tree arg0_type = TREE_TYPE (arg0);
+ tree cast_type = NULL_TREE;
+ int addend = 0;
+
+ switch (fcode)
+ {
+ case BUILT_IN_CLZG:
+ if (arg1 && TREE_CODE (arg1) != INTEGER_CST)
+ return NULL_TREE;
+ ifn = IFN_CLZ;
+ fcodei = BUILT_IN_CLZ;
+ fcodel = BUILT_IN_CLZL;
+ fcodell = BUILT_IN_CLZLL;
+ break;
+ case BUILT_IN_CTZG:
+ if (arg1 && TREE_CODE (arg1) != INTEGER_CST)
+ return NULL_TREE;
+ ifn = IFN_CTZ;
+ fcodei = BUILT_IN_CTZ;
+ fcodel = BUILT_IN_CTZL;
+ fcodell = BUILT_IN_CTZLL;
+ break;
+ case BUILT_IN_CLRSBG:
+ ifn = IFN_CLRSB;
+ fcodei = BUILT_IN_CLRSB;
+ fcodel = BUILT_IN_CLRSBL;
+ fcodell = BUILT_IN_CLRSBLL;
+ break;
+ case BUILT_IN_FFSG:
+ ifn = IFN_FFS;
+ fcodei = BUILT_IN_FFS;
+ fcodel = BUILT_IN_FFSL;
+ fcodell = BUILT_IN_FFSLL;
+ break;
+ case BUILT_IN_PARITYG:
+ ifn = IFN_PARITY;
+ fcodei = BUILT_IN_PARITY;
+ fcodel = BUILT_IN_PARITYL;
+ fcodell = BUILT_IN_PARITYLL;
+ break;
+ case BUILT_IN_POPCOUNTG:
+ ifn = IFN_POPCOUNT;
+ fcodei = BUILT_IN_POPCOUNT;
+ fcodel = BUILT_IN_POPCOUNTL;
+ fcodell = BUILT_IN_POPCOUNTLL;
+ break;
+ default:
+ gcc_unreachable ();
+ }
+
+ if (TYPE_PRECISION (arg0_type)
+ <= TYPE_PRECISION (long_long_unsigned_type_node))
+ {
+ if (TYPE_PRECISION (arg0_type) <= TYPE_PRECISION (unsigned_type_node))
+
+ cast_type = (TYPE_UNSIGNED (arg0_type)
+ ? unsigned_type_node : integer_type_node);
+ else if (TYPE_PRECISION (arg0_type)
+ <= TYPE_PRECISION (long_unsigned_type_node))
+ {
+ cast_type = (TYPE_UNSIGNED (arg0_type)
+ ? long_unsigned_type_node : long_integer_type_node);
+ fcodei = fcodel;
+ }
+ else
+ {
+ cast_type = (TYPE_UNSIGNED (arg0_type)
+ ? long_long_unsigned_type_node
+ : long_long_integer_type_node);
+ fcodei = fcodell;
+ }
+ }
+ else if (TYPE_PRECISION (arg0_type) <= MAX_FIXED_MODE_SIZE)
+ {
+ cast_type
+ = build_nonstandard_integer_type (MAX_FIXED_MODE_SIZE,
+ TYPE_UNSIGNED (arg0_type));
+ gcc_assert (TYPE_PRECISION (cast_type)
+ == 2 * TYPE_PRECISION (long_long_unsigned_type_node));
+ fcodei = END_BUILTINS;
+ }
+ else
+ fcodei = END_BUILTINS;
+ if (cast_type)
+ {
+ switch (fcode)
+ {
+ case BUILT_IN_CLZG:
+ case BUILT_IN_CLRSBG:
+ addend = TYPE_PRECISION (arg0_type) - TYPE_PRECISION (cast_type);
+ break;
+ default:
+ break;
+ }
+ arg0 = fold_convert (cast_type, arg0);
+ arg0_type = cast_type;
+ }
+
+ if (arg1)
+ arg1 = fold_convert (integer_type_node, arg1);
+
+ tree arg2 = arg1;
+ if (fcode == BUILT_IN_CLZG && addend)
+ {
+ if (arg1)
+ arg0 = save_expr (arg0);
+ arg2 = NULL_TREE;
+ }
+ tree call = NULL_TREE, tem;
+ if (TYPE_PRECISION (arg0_type) == MAX_FIXED_MODE_SIZE
+ && (TYPE_PRECISION (arg0_type)
+ == 2 * TYPE_PRECISION (long_long_unsigned_type_node)))
+ {
+ /* __int128 expansions using up to 2 long long builtins. */
+ arg0 = save_expr (arg0);
+ tree type = (TYPE_UNSIGNED (arg0_type)
+ ? long_long_unsigned_type_node
+ : long_long_integer_type_node);
+ tree hi = fold_build2 (RSHIFT_EXPR, arg0_type, arg0,
+ build_int_cst (integer_type_node,
+ MAX_FIXED_MODE_SIZE / 2));
+ hi = fold_convert (type, hi);
+ tree lo = fold_convert (type, arg0);
+ switch (fcode)
+ {
+ case BUILT_IN_CLZG:
+ call = fold_builtin_bit_query (loc, fcode, lo, NULL_TREE);
+ call = fold_build2 (PLUS_EXPR, integer_type_node, call,
+ build_int_cst (integer_type_node,
+ MAX_FIXED_MODE_SIZE / 2));
+ if (arg2)
+ call = fold_build3 (COND_EXPR, integer_type_node,
+ fold_build2 (NE_EXPR, boolean_type_node,
+ lo, build_zero_cst (type)),
+ call, arg2);
+ call = fold_build3 (COND_EXPR, integer_type_node,
+ fold_build2 (NE_EXPR, boolean_type_node,
+ hi, build_zero_cst (type)),
+ fold_builtin_bit_query (loc, fcode, hi,
+ NULL_TREE),
+ call);
+ break;
+ case BUILT_IN_CTZG:
+ call = fold_builtin_bit_query (loc, fcode, hi, NULL_TREE);
+ call = fold_build2 (PLUS_EXPR, integer_type_node, call,
+ build_int_cst (integer_type_node,
+ MAX_FIXED_MODE_SIZE / 2));
+ if (arg2)
+ call = fold_build3 (COND_EXPR, integer_type_node,
+ fold_build2 (NE_EXPR, boolean_type_node,
+ hi, build_zero_cst (type)),
+ call, arg2);
+ call = fold_build3 (COND_EXPR, integer_type_node,
+ fold_build2 (NE_EXPR, boolean_type_node,
+ lo, build_zero_cst (type)),
+ fold_builtin_bit_query (loc, fcode, lo,
+ NULL_TREE),
+ call);
+ break;
+ case BUILT_IN_CLRSBG:
+ tem = fold_builtin_bit_query (loc, fcode, lo, NULL_TREE);
+ tem = fold_build2 (PLUS_EXPR, integer_type_node, tem,
+ build_int_cst (integer_type_node,
+ MAX_FIXED_MODE_SIZE / 2));
+ tem = fold_build3 (COND_EXPR, integer_type_node,
+ fold_build2 (LT_EXPR, boolean_type_node,
+ fold_build2 (BIT_XOR_EXPR, type,
+ lo, hi),
+ build_zero_cst (type)),
+ build_int_cst (integer_type_node,
+ MAX_FIXED_MODE_SIZE / 2 - 1),
+ tem);
+ call = fold_builtin_bit_query (loc, fcode, hi, NULL_TREE);
+ call = save_expr (call);
+ call = fold_build3 (COND_EXPR, integer_type_node,
+ fold_build2 (NE_EXPR, boolean_type_node,
+ call,
+ build_int_cst (integer_type_node,
+ MAX_FIXED_MODE_SIZE
+ / 2 - 1)),
+ call, tem);
+ break;
+ case BUILT_IN_FFSG:
+ call = fold_builtin_bit_query (loc, fcode, hi, NULL_TREE);
+ call = fold_build2 (PLUS_EXPR, integer_type_node, call,
+ build_int_cst (integer_type_node,
+ MAX_FIXED_MODE_SIZE / 2));
+ call = fold_build3 (COND_EXPR, integer_type_node,
+ fold_build2 (NE_EXPR, boolean_type_node,
+ hi, build_zero_cst (type)),
+ call, integer_zero_node);
+ call = fold_build3 (COND_EXPR, integer_type_node,
+ fold_build2 (NE_EXPR, boolean_type_node,
+ lo, build_zero_cst (type)),
+ fold_builtin_bit_query (loc, fcode, lo,
+ NULL_TREE),
+ call);
+ break;
+ case BUILT_IN_PARITYG:
+ call = fold_builtin_bit_query (loc, fcode,
+ fold_build2 (BIT_XOR_EXPR, type,
+ lo, hi), NULL_TREE);
+ break;
+ case BUILT_IN_POPCOUNTG:
+ call = fold_build2 (PLUS_EXPR, integer_type_node,
+ fold_builtin_bit_query (loc, fcode, hi,
+ NULL_TREE),
+ fold_builtin_bit_query (loc, fcode, lo,
+ NULL_TREE));
+ break;
+ default:
+ gcc_unreachable ();
+ }
+ }
+ else
+ {
+ /* Only keep second argument to IFN_CLZ/IFN_CTZ if it is the
+ value defined at zero during GIMPLE, or for large/huge _BitInt
+ (which are then lowered during bitint lowering). */
+ if (arg2 && TREE_CODE (TREE_TYPE (arg0)) != BITINT_TYPE)
+ {
+ int val;
+ if (fcode == BUILT_IN_CLZG)
+ {
+ if (CLZ_DEFINED_VALUE_AT_ZERO (SCALAR_TYPE_MODE (arg0_type),
+ val) != 2
+ || wi::to_widest (arg2) != val)
+ arg2 = NULL_TREE;
+ }
+ else if (CTZ_DEFINED_VALUE_AT_ZERO (SCALAR_TYPE_MODE (arg0_type),
+ val) != 2
+ || wi::to_widest (arg2) != val)
+ arg2 = NULL_TREE;
+ if (!direct_internal_fn_supported_p (ifn, arg0_type,
+ OPTIMIZE_FOR_BOTH))
+ arg2 = NULL_TREE;
+ }
+ if (fcodei == END_BUILTINS || arg2)
+ call = build_call_expr_internal_loc (loc, ifn, integer_type_node,
+ arg2 ? 2 : 1, arg0, arg2);
+ else
+ call = build_call_expr_loc (loc, builtin_decl_explicit (fcodei), 1,
+ arg0);
+ }
+ if (addend)
+ call = fold_build2 (PLUS_EXPR, integer_type_node, call,
+ build_int_cst (integer_type_node, addend));
+ if (arg1 && arg2 == NULL_TREE)
+ call = fold_build3 (COND_EXPR, integer_type_node,
+ fold_build2 (NE_EXPR, boolean_type_node,
+ arg0, build_zero_cst (arg0_type)),
+ call, arg1);
+
+ return call;
+}
+
/* Fold __builtin_{add,sub}c{,l,ll} into pair of internal functions
that return both result of arithmetics and overflowed boolean
flag in a complex integer result. */
@@ -9824,6 +10089,14 @@ fold_builtin_1 (location_t loc, tree expr, tree fndecl, tree arg0)
return build_empty_stmt (loc);
break;
+ case BUILT_IN_CLZG:
+ case BUILT_IN_CTZG:
+ case BUILT_IN_CLRSBG:
+ case BUILT_IN_FFSG:
+ case BUILT_IN_PARITYG:
+ case BUILT_IN_POPCOUNTG:
+ return fold_builtin_bit_query (loc, fcode, arg0, NULL_TREE);
+
default:
break;
}
@@ -9913,6 +10186,10 @@ fold_builtin_2 (location_t loc, tree expr, tree fndecl, tree arg0, tree arg1)
case BUILT_IN_ATOMIC_IS_LOCK_FREE:
return fold_builtin_atomic_is_lock_free (arg0, arg1);
+ case BUILT_IN_CLZG:
+ case BUILT_IN_CTZG:
+ return fold_builtin_bit_query (loc, fcode, arg0, arg1);
+
default:
break;
}
diff --git a/gcc/builtins.def b/gcc/builtins.def
index a6fdb22..33e6cad 100644
--- a/gcc/builtins.def
+++ b/gcc/builtins.def
@@ -962,15 +962,18 @@ DEF_GCC_BUILTIN (BUILT_IN_CLZ, "clz", BT_FN_INT_UINT, ATTR_CONST_NOTHROW_
DEF_GCC_BUILTIN (BUILT_IN_CLZIMAX, "clzimax", BT_FN_INT_UINTMAX, ATTR_CONST_NOTHROW_LEAF_LIST)
DEF_GCC_BUILTIN (BUILT_IN_CLZL, "clzl", BT_FN_INT_ULONG, ATTR_CONST_NOTHROW_LEAF_LIST)
DEF_GCC_BUILTIN (BUILT_IN_CLZLL, "clzll", BT_FN_INT_ULONGLONG, ATTR_CONST_NOTHROW_LEAF_LIST)
+DEF_GCC_BUILTIN (BUILT_IN_CLZG, "clzg", BT_FN_INT_VAR, ATTR_CONST_NOTHROW_TYPEGENERIC_LEAF)
DEF_GCC_BUILTIN (BUILT_IN_CONSTANT_P, "constant_p", BT_FN_INT_VAR, ATTR_CONST_NOTHROW_LEAF_LIST)
DEF_GCC_BUILTIN (BUILT_IN_CTZ, "ctz", BT_FN_INT_UINT, ATTR_CONST_NOTHROW_LEAF_LIST)
DEF_GCC_BUILTIN (BUILT_IN_CTZIMAX, "ctzimax", BT_FN_INT_UINTMAX, ATTR_CONST_NOTHROW_LEAF_LIST)
DEF_GCC_BUILTIN (BUILT_IN_CTZL, "ctzl", BT_FN_INT_ULONG, ATTR_CONST_NOTHROW_LEAF_LIST)
DEF_GCC_BUILTIN (BUILT_IN_CTZLL, "ctzll", BT_FN_INT_ULONGLONG, ATTR_CONST_NOTHROW_LEAF_LIST)
+DEF_GCC_BUILTIN (BUILT_IN_CTZG, "ctzg", BT_FN_INT_VAR, ATTR_CONST_NOTHROW_TYPEGENERIC_LEAF)
DEF_GCC_BUILTIN (BUILT_IN_CLRSB, "clrsb", BT_FN_INT_INT, ATTR_CONST_NOTHROW_LEAF_LIST)
DEF_GCC_BUILTIN (BUILT_IN_CLRSBIMAX, "clrsbimax", BT_FN_INT_INTMAX, ATTR_CONST_NOTHROW_LEAF_LIST)
DEF_GCC_BUILTIN (BUILT_IN_CLRSBL, "clrsbl", BT_FN_INT_LONG, ATTR_CONST_NOTHROW_LEAF_LIST)
DEF_GCC_BUILTIN (BUILT_IN_CLRSBLL, "clrsbll", BT_FN_INT_LONGLONG, ATTR_CONST_NOTHROW_LEAF_LIST)
+DEF_GCC_BUILTIN (BUILT_IN_CLRSBG, "clrsbg", BT_FN_INT_VAR, ATTR_CONST_NOTHROW_TYPEGENERIC_LEAF)
DEF_EXT_LIB_BUILTIN (BUILT_IN_DCGETTEXT, "dcgettext", BT_FN_STRING_CONST_STRING_CONST_STRING_INT, ATTR_FORMAT_ARG_2)
DEF_EXT_LIB_BUILTIN (BUILT_IN_DGETTEXT, "dgettext", BT_FN_STRING_CONST_STRING_CONST_STRING, ATTR_FORMAT_ARG_2)
DEF_GCC_BUILTIN (BUILT_IN_DWARF_CFA, "dwarf_cfa", BT_FN_PTR, ATTR_NULL)
@@ -993,6 +996,7 @@ DEF_EXT_LIB_BUILTIN (BUILT_IN_FFS, "ffs", BT_FN_INT_INT, ATTR_CONST_NOTHROW_L
DEF_EXT_LIB_BUILTIN (BUILT_IN_FFSIMAX, "ffsimax", BT_FN_INT_INTMAX, ATTR_CONST_NOTHROW_LEAF_LIST)
DEF_EXT_LIB_BUILTIN (BUILT_IN_FFSL, "ffsl", BT_FN_INT_LONG, ATTR_CONST_NOTHROW_LEAF_LIST)
DEF_EXT_LIB_BUILTIN (BUILT_IN_FFSLL, "ffsll", BT_FN_INT_LONGLONG, ATTR_CONST_NOTHROW_LEAF_LIST)
+DEF_GCC_BUILTIN (BUILT_IN_FFSG, "ffsg", BT_FN_INT_VAR, ATTR_CONST_NOTHROW_TYPEGENERIC_LEAF)
DEF_EXT_LIB_BUILTIN (BUILT_IN_FORK, "fork", BT_FN_PID, ATTR_NOTHROW_LIST)
DEF_GCC_BUILTIN (BUILT_IN_FRAME_ADDRESS, "frame_address", BT_FN_PTR_UINT, ATTR_NULL)
/* [trans-mem]: Adjust BUILT_IN_TM_FREE if BUILT_IN_FREE is changed. */
@@ -1041,10 +1045,12 @@ DEF_GCC_BUILTIN (BUILT_IN_PARITY, "parity", BT_FN_INT_UINT, ATTR_CONST_NO
DEF_GCC_BUILTIN (BUILT_IN_PARITYIMAX, "parityimax", BT_FN_INT_UINTMAX, ATTR_CONST_NOTHROW_LEAF_LIST)
DEF_GCC_BUILTIN (BUILT_IN_PARITYL, "parityl", BT_FN_INT_ULONG, ATTR_CONST_NOTHROW_LEAF_LIST)
DEF_GCC_BUILTIN (BUILT_IN_PARITYLL, "parityll", BT_FN_INT_ULONGLONG, ATTR_CONST_NOTHROW_LEAF_LIST)
+DEF_GCC_BUILTIN (BUILT_IN_PARITYG, "parityg", BT_FN_INT_VAR, ATTR_CONST_NOTHROW_TYPEGENERIC_LEAF)
DEF_GCC_BUILTIN (BUILT_IN_POPCOUNT, "popcount", BT_FN_INT_UINT, ATTR_CONST_NOTHROW_LEAF_LIST)
DEF_GCC_BUILTIN (BUILT_IN_POPCOUNTIMAX, "popcountimax", BT_FN_INT_UINTMAX, ATTR_CONST_NOTHROW_LEAF_LIST)
DEF_GCC_BUILTIN (BUILT_IN_POPCOUNTL, "popcountl", BT_FN_INT_ULONG, ATTR_CONST_NOTHROW_LEAF_LIST)
DEF_GCC_BUILTIN (BUILT_IN_POPCOUNTLL, "popcountll", BT_FN_INT_ULONGLONG, ATTR_CONST_NOTHROW_LEAF_LIST)
+DEF_GCC_BUILTIN (BUILT_IN_POPCOUNTG, "popcountg", BT_FN_INT_VAR, ATTR_CONST_NOTHROW_TYPEGENERIC_LEAF)
DEF_EXT_LIB_BUILTIN (BUILT_IN_POSIX_MEMALIGN, "posix_memalign", BT_FN_INT_PTRPTR_SIZE_SIZE, ATTR_NOTHROW_NONNULL_LEAF)
DEF_GCC_BUILTIN (BUILT_IN_PREFETCH, "prefetch", BT_FN_VOID_CONST_PTR_VAR, ATTR_NOVOPS_LEAF_LIST)
DEF_LIB_BUILTIN (BUILT_IN_REALLOC, "realloc", BT_FN_PTR_PTR_SIZE, ATTR_ALLOC_WARN_UNUSED_RESULT_SIZE_2_NOTHROW_LEAF_LIST)
diff --git a/gcc/c-family/c-common.cc b/gcc/c-family/c-common.cc
index 77faf17..a619429 100644
--- a/gcc/c-family/c-common.cc
+++ b/gcc/c-family/c-common.cc
@@ -6475,14 +6475,14 @@ check_builtin_function_arguments (location_t loc, vec<location_t> arg_loc,
}
if (TREE_CODE (TREE_TYPE (args[2])) == ENUMERAL_TYPE)
{
- error_at (ARG_LOCATION (2), "argument 3 in call to function "
- "%qE has enumerated type", fndecl);
+ error_at (ARG_LOCATION (2), "argument %u in call to function "
+ "%qE has enumerated type", 3, fndecl);
return false;
}
else if (TREE_CODE (TREE_TYPE (args[2])) == BOOLEAN_TYPE)
{
- error_at (ARG_LOCATION (2), "argument 3 in call to function "
- "%qE has boolean type", fndecl);
+ error_at (ARG_LOCATION (2), "argument %u in call to function "
+ "%qE has boolean type", 3, fndecl);
return false;
}
return true;
@@ -6522,6 +6522,72 @@ check_builtin_function_arguments (location_t loc, vec<location_t> arg_loc,
}
return false;
+ case BUILT_IN_CLZG:
+ case BUILT_IN_CTZG:
+ case BUILT_IN_CLRSBG:
+ case BUILT_IN_FFSG:
+ case BUILT_IN_PARITYG:
+ case BUILT_IN_POPCOUNTG:
+ if (nargs == 2
+ && (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_CLZG
+ || DECL_FUNCTION_CODE (fndecl) == BUILT_IN_CTZG))
+ {
+ if (!INTEGRAL_TYPE_P (TREE_TYPE (args[1])))
+ {
+ error_at (ARG_LOCATION (1), "argument %u in call to function "
+ "%qE does not have integral type", 2, fndecl);
+ return false;
+ }
+ if ((TYPE_PRECISION (TREE_TYPE (args[1]))
+ > TYPE_PRECISION (integer_type_node))
+ || (TYPE_PRECISION (TREE_TYPE (args[1]))
+ == TYPE_PRECISION (integer_type_node)
+ && TYPE_UNSIGNED (TREE_TYPE (args[1]))))
+ {
+ error_at (ARG_LOCATION (1), "argument %u in call to function "
+ "%qE does not have %<int%> type", 2, fndecl);
+ return false;
+ }
+ }
+ else if (!builtin_function_validate_nargs (loc, fndecl, nargs, 1))
+ return false;
+
+ if (!INTEGRAL_TYPE_P (TREE_TYPE (args[0])))
+ {
+ error_at (ARG_LOCATION (0), "argument %u in call to function "
+ "%qE does not have integral type", 1, fndecl);
+ return false;
+ }
+ if (TREE_CODE (TREE_TYPE (args[0])) == ENUMERAL_TYPE)
+ {
+ error_at (ARG_LOCATION (0), "argument %u in call to function "
+ "%qE has enumerated type", 1, fndecl);
+ return false;
+ }
+ if (TREE_CODE (TREE_TYPE (args[0])) == BOOLEAN_TYPE)
+ {
+ error_at (ARG_LOCATION (0), "argument %u in call to function "
+ "%qE has boolean type", 1, fndecl);
+ return false;
+ }
+ if (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_FFSG
+ || DECL_FUNCTION_CODE (fndecl) == BUILT_IN_CLRSBG)
+ {
+ if (TYPE_UNSIGNED (TREE_TYPE (args[0])))
+ {
+ error_at (ARG_LOCATION (0), "argument 1 in call to function "
+ "%qE has unsigned type", fndecl);
+ return false;
+ }
+ }
+ else if (!TYPE_UNSIGNED (TREE_TYPE (args[0])))
+ {
+ error_at (ARG_LOCATION (0), "argument 1 in call to function "
+ "%qE has signed type", fndecl);
+ return false;
+ }
+ return true;
+
default:
return true;
}
diff --git a/gcc/c-family/c-gimplify.cc b/gcc/c-family/c-gimplify.cc
index 17b0610..2f44e12 100644
--- a/gcc/c-family/c-gimplify.cc
+++ b/gcc/c-family/c-gimplify.cc
@@ -818,6 +818,28 @@ c_gimplify_expr (tree *expr_p, gimple_seq *pre_p ATTRIBUTE_UNUSED,
break;
}
+ case CALL_EXPR:
+ {
+ tree fndecl = get_callee_fndecl (*expr_p);
+ if (fndecl
+ && fndecl_built_in_p (fndecl, BUILT_IN_CLZG, BUILT_IN_CTZG)
+ && call_expr_nargs (*expr_p) == 2
+ && TREE_CODE (CALL_EXPR_ARG (*expr_p, 1)) != INTEGER_CST)
+ {
+ tree a = save_expr (CALL_EXPR_ARG (*expr_p, 0));
+ tree c = build_call_expr_loc (EXPR_LOCATION (*expr_p),
+ fndecl, 1, a);
+ *expr_p = build3_loc (EXPR_LOCATION (*expr_p), COND_EXPR,
+ integer_type_node,
+ build2_loc (EXPR_LOCATION (*expr_p),
+ NE_EXPR, boolean_type_node, a,
+ build_zero_cst (TREE_TYPE (a))),
+ c, CALL_EXPR_ARG (*expr_p, 1));
+ return GS_OK;
+ }
+ break;
+ }
+
default:;
}
diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc
index 366ca88..1dbb447 100644
--- a/gcc/c/c-typeck.cc
+++ b/gcc/c/c-typeck.cc
@@ -3416,6 +3416,7 @@ convert_arguments (location_t loc, vec<location_t> arg_loc, tree typelist,
&& lookup_attribute ("type generic", TYPE_ATTRIBUTES (TREE_TYPE (fundecl)));
bool type_generic_remove_excess_precision = false;
bool type_generic_overflow_p = false;
+ bool type_generic_bit_query = false;
tree selector;
/* Change pointer to function to the function itself for
@@ -3471,6 +3472,17 @@ convert_arguments (location_t loc, vec<location_t> arg_loc, tree typelist,
type_generic_overflow_p = true;
break;
+ case BUILT_IN_CLZG:
+ case BUILT_IN_CTZG:
+ case BUILT_IN_CLRSBG:
+ case BUILT_IN_FFSG:
+ case BUILT_IN_PARITYG:
+ case BUILT_IN_POPCOUNTG:
+ /* The first argument of these type-generic builtins
+ should not be promoted. */
+ type_generic_bit_query = true;
+ break;
+
default:
break;
}
@@ -3606,11 +3618,13 @@ convert_arguments (location_t loc, vec<location_t> arg_loc, tree typelist,
}
}
else if ((excess_precision && !type_generic)
- || (type_generic_overflow_p && parmnum == 2))
+ || (type_generic_overflow_p && parmnum == 2)
+ || (type_generic_bit_query && parmnum == 0))
/* A "double" argument with excess precision being passed
without a prototype or in variable arguments.
The last argument of __builtin_*_overflow_p should not be
- promoted. */
+ promoted, similarly the first argument of
+ __builtin_{clz,ctz,clrsb,ffs,parity,popcount}g. */
parmval = convert (valtype, val);
else if ((invalid_func_diag =
targetm.calls.invalid_arg_for_unprototyped_fn (typelist, fundecl, val)))
diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc
index 4516677..709fd74 100644
--- a/gcc/cp/call.cc
+++ b/gcc/cp/call.cc
@@ -9290,7 +9290,9 @@ convert_for_arg_passing (tree type, tree val, tsubst_flags_t complain)
This is true for some builtins which don't act like normal functions.
Return 2 if just decay_conversion and removal of excess precision should
be done, 1 if just decay_conversion. Return 3 for special treatment of
- the 3rd argument for __builtin_*_overflow_p. */
+ the 3rd argument for __builtin_*_overflow_p. Return 4 for special
+ treatment of the 1st argument for
+ __builtin_{clz,ctz,clrsb,ffs,parity,popcount}g. */
int
magic_varargs_p (tree fn)
@@ -9317,6 +9319,14 @@ magic_varargs_p (tree fn)
case BUILT_IN_FPCLASSIFY:
return 2;
+ case BUILT_IN_CLZG:
+ case BUILT_IN_CTZG:
+ case BUILT_IN_CLRSBG:
+ case BUILT_IN_FFSG:
+ case BUILT_IN_PARITYG:
+ case BUILT_IN_POPCOUNTG:
+ return 4;
+
default:
return lookup_attribute ("type generic",
TYPE_ATTRIBUTES (TREE_TYPE (fn))) != 0;
@@ -10122,7 +10132,7 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain)
for (; arg_index < vec_safe_length (args); ++arg_index)
{
tree a = (*args)[arg_index];
- if (magic == 3 && arg_index == 2)
+ if ((magic == 3 && arg_index == 2) || (magic == 4 && arg_index == 0))
{
/* Do no conversions for certain magic varargs. */
a = mark_type_use (a);
diff --git a/gcc/cp/cp-gimplify.cc b/gcc/cp/cp-gimplify.cc
index 9375a11..795c811 100644
--- a/gcc/cp/cp-gimplify.cc
+++ b/gcc/cp/cp-gimplify.cc
@@ -771,6 +771,10 @@ cp_gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p)
default:
break;
}
+ else if (decl
+ && fndecl_built_in_p (decl, BUILT_IN_CLZG, BUILT_IN_CTZG))
+ ret = (enum gimplify_status) c_gimplify_expr (expr_p, pre_p,
+ post_p);
}
break;
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index 7cdfdf8..406ccc9 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -14960,6 +14960,48 @@ Similar to @code{__builtin_parity}, except the argument type is
@code{unsigned long long}.
@enddefbuiltin
+@defbuiltin{int __builtin_ffsg (...)}
+Similar to @code{__builtin_ffs}, except the argument is type-generic
+signed integer (standard, extended or bit-precise). No integral argument
+promotions are performed on the argument.
+@enddefbuiltin
+
+@defbuiltin{int __builtin_clzg (...)}
+Similar to @code{__builtin_clz}, except the argument is type-generic
+unsigned integer (standard, extended or bit-precise) and there is
+optional second argument with int type. No integral argument promotions
+are performed on the first argument. If two arguments are specified,
+and first argument is 0, the result is the second argument. If only
+one argument is specified and it is 0, the result is undefined.
+@enddefbuiltin
+
+@defbuiltin{int __builtin_ctzg (...)}
+Similar to @code{__builtin_ctz}, except the argument is type-generic
+unsigned integer (standard, extended or bit-precise) and there is
+optional second argument with int type. No integral argument promotions
+are performed on the first argument. If two arguments are specified,
+and first argument is 0, the result is the second argument. If only
+one argument is specified and it is 0, the result is undefined.
+@enddefbuiltin
+
+@defbuiltin{int __builtin_clrsbg (...)}
+Similar to @code{__builtin_clrsb}, except the argument is type-generic
+signed integer (standard, extended or bit-precise). No integral argument
+promotions are performed on the argument.
+@enddefbuiltin
+
+@defbuiltin{int __builtin_popcountg (...)}
+Similar to @code{__builtin_popcount}, except the argument is type-generic
+unsigned integer (standard, extended or bit-precise). No integral argument
+promotions are performed on the argument.
+@enddefbuiltin
+
+@defbuiltin{int __builtin_parityg (...)}
+Similar to @code{__builtin_parity}, except the argument is type-generic
+unsigned integer (standard, extended or bit-precise). No integral argument
+promotions are performed on the argument.
+@enddefbuiltin
+
@defbuiltin{double __builtin_powi (double, int)}
@defbuiltinx{float __builtin_powif (float, int)}
@defbuiltinx{{long double} __builtin_powil (long double, int)}
diff --git a/gcc/fold-const-call.cc b/gcc/fold-const-call.cc
index 04be3d2..36f4ecc 100644
--- a/gcc/fold-const-call.cc
+++ b/gcc/fold-const-call.cc
@@ -27,7 +27,7 @@ along with GCC; see the file COPYING3. If not see
#include "fold-const.h"
#include "fold-const-call.h"
#include "case-cfn-macros.h"
-#include "tm.h" /* For C[LT]Z_DEFINED_AT_ZERO. */
+#include "tm.h" /* For C[LT]Z_DEFINED_VALUE_AT_ZERO. */
#include "builtins.h"
#include "gimple-expr.h"
#include "tree-vector-builder.h"
@@ -1017,14 +1017,18 @@ fold_const_call_ss (wide_int *result, combined_fn fn, const wide_int_ref &arg,
switch (fn)
{
CASE_CFN_FFS:
+ case CFN_BUILT_IN_FFSG:
*result = wi::shwi (wi::ffs (arg), precision);
return true;
CASE_CFN_CLZ:
+ case CFN_BUILT_IN_CLZG:
{
int tmp;
if (wi::ne_p (arg, 0))
tmp = wi::clz (arg);
+ else if (TREE_CODE (arg_type) == BITINT_TYPE)
+ tmp = TYPE_PRECISION (arg_type);
else if (!CLZ_DEFINED_VALUE_AT_ZERO (SCALAR_INT_TYPE_MODE (arg_type),
tmp))
tmp = TYPE_PRECISION (arg_type);
@@ -1033,10 +1037,13 @@ fold_const_call_ss (wide_int *result, combined_fn fn, const wide_int_ref &arg,
}
CASE_CFN_CTZ:
+ case CFN_BUILT_IN_CTZG:
{
int tmp;
if (wi::ne_p (arg, 0))
tmp = wi::ctz (arg);
+ else if (TREE_CODE (arg_type) == BITINT_TYPE)
+ tmp = TYPE_PRECISION (arg_type);
else if (!CTZ_DEFINED_VALUE_AT_ZERO (SCALAR_INT_TYPE_MODE (arg_type),
tmp))
tmp = TYPE_PRECISION (arg_type);
@@ -1045,14 +1052,17 @@ fold_const_call_ss (wide_int *result, combined_fn fn, const wide_int_ref &arg,
}
CASE_CFN_CLRSB:
+ case CFN_BUILT_IN_CLRSBG:
*result = wi::shwi (wi::clrsb (arg), precision);
return true;
CASE_CFN_POPCOUNT:
+ case CFN_BUILT_IN_POPCOUNTG:
*result = wi::shwi (wi::popcount (arg), precision);
return true;
CASE_CFN_PARITY:
+ case CFN_BUILT_IN_PARITYG:
*result = wi::shwi (wi::parity (arg), precision);
return true;
@@ -1531,6 +1541,49 @@ fold_const_call_sss (real_value *result, combined_fn fn,
/* Try to evaluate:
+ *RESULT = FN (ARG0, ARG1)
+
+ where ARG_TYPE is the type of ARG0 and PRECISION is the number of bits in
+ the result. Return true on success. */
+
+static bool
+fold_const_call_sss (wide_int *result, combined_fn fn,
+ const wide_int_ref &arg0, const wide_int_ref &arg1,
+ unsigned int precision, tree arg_type ATTRIBUTE_UNUSED)
+{
+ switch (fn)
+ {
+ case CFN_CLZ:
+ case CFN_BUILT_IN_CLZG:
+ {
+ int tmp;
+ if (wi::ne_p (arg0, 0))
+ tmp = wi::clz (arg0);
+ else
+ tmp = arg1.to_shwi ();
+ *result = wi::shwi (tmp, precision);
+ return true;
+ }
+
+ case CFN_CTZ:
+ case CFN_BUILT_IN_CTZG:
+ {
+ int tmp;
+ if (wi::ne_p (arg0, 0))
+ tmp = wi::ctz (arg0);
+ else
+ tmp = arg1.to_shwi ();
+ *result = wi::shwi (tmp, precision);
+ return true;
+ }
+
+ default:
+ return false;
+ }
+}
+
+/* Try to evaluate:
+
RESULT = fn (ARG0, ARG1)
where FORMAT is the format of the real and imaginary parts of RESULT
@@ -1565,6 +1618,19 @@ fold_const_call_1 (combined_fn fn, tree type, tree arg0, tree arg1)
machine_mode arg0_mode = TYPE_MODE (TREE_TYPE (arg0));
machine_mode arg1_mode = TYPE_MODE (TREE_TYPE (arg1));
+ if (integer_cst_p (arg0) && integer_cst_p (arg1))
+ {
+ if (SCALAR_INT_MODE_P (mode))
+ {
+ wide_int result;
+ if (fold_const_call_sss (&result, fn, wi::to_wide (arg0),
+ wi::to_wide (arg1), TYPE_PRECISION (type),
+ TREE_TYPE (arg0)))
+ return wide_int_to_tree (type, result);
+ }
+ return NULL_TREE;
+ }
+
if (mode == arg0_mode
&& real_cst_p (arg0)
&& real_cst_p (arg1))
diff --git a/gcc/genmatch.cc b/gcc/genmatch.cc
index 4572342..3488764 100644
--- a/gcc/genmatch.cc
+++ b/gcc/genmatch.cc
@@ -1896,8 +1896,14 @@ cmp_operand (operand *o1, operand *o2)
{
expr *e1 = static_cast<expr *>(o1);
expr *e2 = static_cast<expr *>(o2);
- return (e1->operation == e2->operation
- && e1->is_generic == e2->is_generic);
+ if (e1->operation != e2->operation
+ || e1->is_generic != e2->is_generic)
+ return false;
+ if (e1->operation->kind == id_base::FN
+ /* For function calls also compare number of arguments. */
+ && e1->ops.length () != e2->ops.length ())
+ return false;
+ return true;
}
else
return false;
@@ -3071,6 +3077,26 @@ dt_operand::gen_generic_expr (FILE *f, int indent, const char *opname)
return 0;
}
+/* Compare 2 fns or generic_fns vector entries for vector sorting.
+ Same operation entries with different number of arguments should
+ be adjacent. */
+
+static int
+fns_cmp (const void *p1, const void *p2)
+{
+ dt_operand *op1 = *(dt_operand *const *) p1;
+ dt_operand *op2 = *(dt_operand *const *) p2;
+ expr *e1 = as_a <expr *> (op1->op);
+ expr *e2 = as_a <expr *> (op2->op);
+ id_base *b1 = e1->operation;
+ id_base *b2 = e2->operation;
+ if (b1->hashval < b2->hashval)
+ return -1;
+ if (b1->hashval > b2->hashval)
+ return 1;
+ return strcmp (b1->id, b2->id);
+}
+
/* Generate matching code for the children of the decision tree node. */
void
@@ -3144,6 +3170,8 @@ dt_node::gen_kids (FILE *f, int indent, bool gimple, int depth)
Like DT_TRUE, DT_MATCH serves as a barrier as it can cause
dependent matches to get out-of-order. Generate code now
for what we have collected sofar. */
+ fns.qsort (fns_cmp);
+ generic_fns.qsort (fns_cmp);
gen_kids_1 (f, indent, gimple, depth, gimple_exprs, generic_exprs,
fns, generic_fns, preds, others);
/* And output the true operand itself. */
@@ -3160,6 +3188,8 @@ dt_node::gen_kids (FILE *f, int indent, bool gimple, int depth)
}
/* Generate code for the remains. */
+ fns.qsort (fns_cmp);
+ generic_fns.qsort (fns_cmp);
gen_kids_1 (f, indent, gimple, depth, gimple_exprs, generic_exprs,
fns, generic_fns, preds, others);
}
@@ -3257,14 +3287,21 @@ dt_node::gen_kids_1 (FILE *f, int indent, bool gimple, int depth,
indent += 4;
fprintf_indent (f, indent, "{\n");
+ id_base *last_op = NULL;
for (unsigned i = 0; i < fns_len; ++i)
{
expr *e = as_a <expr *>(fns[i]->op);
- if (user_id *u = dyn_cast <user_id *> (e->operation))
- for (auto id : u->substitutes)
- fprintf_indent (f, indent, "case %s:\n", id->id);
- else
- fprintf_indent (f, indent, "case %s:\n", e->operation->id);
+ if (e->operation != last_op)
+ {
+ if (i)
+ fprintf_indent (f, indent, " break;\n");
+ if (user_id *u = dyn_cast <user_id *> (e->operation))
+ for (auto id : u->substitutes)
+ fprintf_indent (f, indent, "case %s:\n", id->id);
+ else
+ fprintf_indent (f, indent, "case %s:\n", e->operation->id);
+ }
+ last_op = e->operation;
/* We need to be defensive against bogus prototypes allowing
calls with not enough arguments. */
fprintf_indent (f, indent,
@@ -3273,9 +3310,9 @@ dt_node::gen_kids_1 (FILE *f, int indent, bool gimple, int depth,
fprintf_indent (f, indent, " {\n");
fns[i]->gen (f, indent + 6, true, depth);
fprintf_indent (f, indent, " }\n");
- fprintf_indent (f, indent, " break;\n");
}
+ fprintf_indent (f, indent, " break;\n");
fprintf_indent (f, indent, "default:;\n");
fprintf_indent (f, indent, "}\n");
indent -= 4;
@@ -3335,18 +3372,25 @@ dt_node::gen_kids_1 (FILE *f, int indent, bool gimple, int depth,
" {\n");
indent += 4;
+ id_base *last_op = NULL;
for (unsigned j = 0; j < generic_fns.length (); ++j)
{
expr *e = as_a <expr *>(generic_fns[j]->op);
gcc_assert (e->operation->kind == id_base::FN);
- fprintf_indent (f, indent, "case %s:\n", e->operation->id);
+ if (e->operation != last_op)
+ {
+ if (j)
+ fprintf_indent (f, indent, " break;\n");
+ fprintf_indent (f, indent, "case %s:\n", e->operation->id);
+ }
+ last_op = e->operation;
fprintf_indent (f, indent, " if (call_expr_nargs (%s) == %d)\n"
" {\n", kid_opname, e->ops.length ());
generic_fns[j]->gen (f, indent + 6, false, depth);
- fprintf_indent (f, indent, " }\n"
- " break;\n");
+ fprintf_indent (f, indent, " }\n");
}
+ fprintf_indent (f, indent, " break;\n");
fprintf_indent (f, indent, "default:;\n");
indent -= 4;
diff --git a/gcc/gimple-lower-bitint.cc b/gcc/gimple-lower-bitint.cc
index 6655859..c429cb2 100644
--- a/gcc/gimple-lower-bitint.cc
+++ b/gcc/gimple-lower-bitint.cc
@@ -427,6 +427,7 @@ struct bitint_large_huge
void lower_mul_overflow (tree, gimple *);
void lower_cplxpart_stmt (tree, gimple *);
void lower_complexexpr_stmt (gimple *);
+ void lower_bit_query (gimple *);
void lower_call (tree, gimple *);
void lower_asm (gimple *);
void lower_stmt (gimple *);
@@ -4455,6 +4456,524 @@ bitint_large_huge::lower_complexexpr_stmt (gimple *stmt)
insert_before (g);
}
+/* Lower a .{CLZ,CTZ,CLRSB,FFS,PARITY,POPCOUNT} call with one large/huge _BitInt
+ argument. */
+
+void
+bitint_large_huge::lower_bit_query (gimple *stmt)
+{
+ tree arg0 = gimple_call_arg (stmt, 0);
+ tree arg1 = (gimple_call_num_args (stmt) == 2
+ ? gimple_call_arg (stmt, 1) : NULL_TREE);
+ tree lhs = gimple_call_lhs (stmt);
+ gimple *g;
+
+ if (!lhs)
+ {
+ gimple_stmt_iterator gsi = gsi_for_stmt (stmt);
+ gsi_remove (&gsi, true);
+ return;
+ }
+ tree type = TREE_TYPE (arg0);
+ gcc_assert (TREE_CODE (type) == BITINT_TYPE);
+ bitint_prec_kind kind = bitint_precision_kind (type);
+ gcc_assert (kind >= bitint_prec_large);
+ enum internal_fn ifn = gimple_call_internal_fn (stmt);
+ enum built_in_function fcode = END_BUILTINS;
+ gcc_assert (TYPE_PRECISION (unsigned_type_node) == limb_prec
+ || TYPE_PRECISION (long_unsigned_type_node) == limb_prec
+ || TYPE_PRECISION (long_long_unsigned_type_node) == limb_prec);
+ switch (ifn)
+ {
+ case IFN_CLZ:
+ if (TYPE_PRECISION (unsigned_type_node) == limb_prec)
+ fcode = BUILT_IN_CLZ;
+ else if (TYPE_PRECISION (long_unsigned_type_node) == limb_prec)
+ fcode = BUILT_IN_CLZL;
+ else
+ fcode = BUILT_IN_CLZLL;
+ break;
+ case IFN_FFS:
+ /* .FFS (X) is .CTZ (X, -1) + 1, though under the hood
+ we don't add the addend at the end. */
+ arg1 = integer_zero_node;
+ /* FALLTHRU */
+ case IFN_CTZ:
+ if (TYPE_PRECISION (unsigned_type_node) == limb_prec)
+ fcode = BUILT_IN_CTZ;
+ else if (TYPE_PRECISION (long_unsigned_type_node) == limb_prec)
+ fcode = BUILT_IN_CTZL;
+ else
+ fcode = BUILT_IN_CTZLL;
+ m_upwards = true;
+ break;
+ case IFN_CLRSB:
+ if (TYPE_PRECISION (unsigned_type_node) == limb_prec)
+ fcode = BUILT_IN_CLRSB;
+ else if (TYPE_PRECISION (long_unsigned_type_node) == limb_prec)
+ fcode = BUILT_IN_CLRSBL;
+ else
+ fcode = BUILT_IN_CLRSBLL;
+ break;
+ case IFN_PARITY:
+ if (TYPE_PRECISION (unsigned_type_node) == limb_prec)
+ fcode = BUILT_IN_PARITY;
+ else if (TYPE_PRECISION (long_unsigned_type_node) == limb_prec)
+ fcode = BUILT_IN_PARITYL;
+ else
+ fcode = BUILT_IN_PARITYLL;
+ m_upwards = true;
+ break;
+ case IFN_POPCOUNT:
+ if (TYPE_PRECISION (unsigned_type_node) == limb_prec)
+ fcode = BUILT_IN_POPCOUNT;
+ else if (TYPE_PRECISION (long_unsigned_type_node) == limb_prec)
+ fcode = BUILT_IN_POPCOUNTL;
+ else
+ fcode = BUILT_IN_POPCOUNTLL;
+ m_upwards = true;
+ break;
+ default:
+ gcc_unreachable ();
+ }
+ tree fndecl = builtin_decl_explicit (fcode), res = NULL_TREE;
+ unsigned cnt = 0, rem = 0, end = 0, prec = TYPE_PRECISION (type);
+ struct bq_details { edge e; tree val, addend; } *bqp = NULL;
+ basic_block edge_bb = NULL;
+ if (m_upwards)
+ {
+ tree idx = NULL_TREE, idx_first = NULL_TREE, idx_next = NULL_TREE;
+ if (kind == bitint_prec_large)
+ cnt = CEIL (prec, limb_prec);
+ else
+ {
+ rem = (prec % (2 * limb_prec));
+ end = (prec - rem) / limb_prec;
+ cnt = 2 + CEIL (rem, limb_prec);
+ idx = idx_first = create_loop (size_zero_node, &idx_next);
+ }
+
+ if (ifn == IFN_CTZ || ifn == IFN_FFS)
+ {
+ gimple_stmt_iterator gsi = gsi_for_stmt (stmt);
+ gsi_prev (&gsi);
+ edge e = split_block (gsi_bb (gsi), gsi_stmt (gsi));
+ edge_bb = e->src;
+ if (kind == bitint_prec_large)
+ {
+ m_gsi = gsi_last_bb (edge_bb);
+ if (!gsi_end_p (m_gsi))
+ gsi_next (&m_gsi);
+ }
+ bqp = XALLOCAVEC (struct bq_details, cnt);
+ }
+ else
+ m_after_stmt = stmt;
+ if (kind != bitint_prec_large)
+ m_upwards_2limb = end;
+
+ for (unsigned i = 0; i < cnt; i++)
+ {
+ m_data_cnt = 0;
+ if (kind == bitint_prec_large)
+ idx = size_int (i);
+ else if (i >= 2)
+ idx = size_int (end + (i > 2));
+
+ tree rhs1 = handle_operand (arg0, idx);
+ if (!useless_type_conversion_p (m_limb_type, TREE_TYPE (rhs1)))
+ {
+ if (!TYPE_UNSIGNED (TREE_TYPE (rhs1)))
+ rhs1 = add_cast (unsigned_type_for (TREE_TYPE (rhs1)), rhs1);
+ rhs1 = add_cast (m_limb_type, rhs1);
+ }
+
+ tree in, out, tem;
+ if (ifn == IFN_PARITY)
+ in = prepare_data_in_out (build_zero_cst (m_limb_type), idx, &out);
+ else if (ifn == IFN_FFS)
+ in = prepare_data_in_out (integer_one_node, idx, &out);
+ else
+ in = prepare_data_in_out (integer_zero_node, idx, &out);
+
+ switch (ifn)
+ {
+ case IFN_CTZ:
+ case IFN_FFS:
+ g = gimple_build_cond (NE_EXPR, rhs1,
+ build_zero_cst (m_limb_type),
+ NULL_TREE, NULL_TREE);
+ insert_before (g);
+ edge e1, e2;
+ e1 = split_block (gsi_bb (m_gsi), g);
+ e1->flags = EDGE_FALSE_VALUE;
+ e2 = make_edge (e1->src, gimple_bb (stmt), EDGE_TRUE_VALUE);
+ e1->probability = profile_probability::unlikely ();
+ e2->probability = e1->probability.invert ();
+ if (i == 0)
+ set_immediate_dominator (CDI_DOMINATORS, e2->dest, e2->src);
+ m_gsi = gsi_after_labels (e1->dest);
+ bqp[i].e = e2;
+ bqp[i].val = rhs1;
+ if (tree_fits_uhwi_p (idx))
+ bqp[i].addend
+ = build_int_cst (integer_type_node,
+ tree_to_uhwi (idx) * limb_prec
+ + (ifn == IFN_FFS));
+ else
+ {
+ bqp[i].addend = in;
+ if (i == 1)
+ res = out;
+ else
+ res = make_ssa_name (integer_type_node);
+ g = gimple_build_assign (res, PLUS_EXPR, in,
+ build_int_cst (integer_type_node,
+ limb_prec));
+ insert_before (g);
+ m_data[m_data_cnt] = res;
+ }
+ break;
+ case IFN_PARITY:
+ if (!integer_zerop (in))
+ {
+ if (kind == bitint_prec_huge && i == 1)
+ res = out;
+ else
+ res = make_ssa_name (m_limb_type);
+ g = gimple_build_assign (res, BIT_XOR_EXPR, in, rhs1);
+ insert_before (g);
+ }
+ else
+ res = rhs1;
+ m_data[m_data_cnt] = res;
+ break;
+ case IFN_POPCOUNT:
+ g = gimple_build_call (fndecl, 1, rhs1);
+ tem = make_ssa_name (integer_type_node);
+ gimple_call_set_lhs (g, tem);
+ insert_before (g);
+ if (!integer_zerop (in))
+ {
+ if (kind == bitint_prec_huge && i == 1)
+ res = out;
+ else
+ res = make_ssa_name (integer_type_node);
+ g = gimple_build_assign (res, PLUS_EXPR, in, tem);
+ insert_before (g);
+ }
+ else
+ res = tem;
+ m_data[m_data_cnt] = res;
+ break;
+ default:
+ gcc_unreachable ();
+ }
+
+ m_first = false;
+ if (kind == bitint_prec_huge && i <= 1)
+ {
+ if (i == 0)
+ {
+ idx = make_ssa_name (sizetype);
+ g = gimple_build_assign (idx, PLUS_EXPR, idx_first,
+ size_one_node);
+ insert_before (g);
+ }
+ else
+ {
+ g = gimple_build_assign (idx_next, PLUS_EXPR, idx_first,
+ size_int (2));
+ insert_before (g);
+ g = gimple_build_cond (NE_EXPR, idx_next, size_int (end),
+ NULL_TREE, NULL_TREE);
+ insert_before (g);
+ if (ifn == IFN_CTZ || ifn == IFN_FFS)
+ m_gsi = gsi_after_labels (edge_bb);
+ else
+ m_gsi = gsi_for_stmt (stmt);
+ }
+ }
+ }
+ }
+ else
+ {
+ tree idx = NULL_TREE, idx_next = NULL_TREE, first = NULL_TREE;
+ int sub_one = 0;
+ if (kind == bitint_prec_large)
+ cnt = CEIL (prec, limb_prec);
+ else
+ {
+ rem = prec % limb_prec;
+ if (rem == 0 && (!TYPE_UNSIGNED (type) || ifn == IFN_CLRSB))
+ rem = limb_prec;
+ end = (prec - rem) / limb_prec;
+ cnt = 1 + (rem != 0);
+ if (ifn == IFN_CLRSB)
+ sub_one = 1;
+ }
+
+ gimple_stmt_iterator gsi = gsi_for_stmt (stmt);
+ gsi_prev (&gsi);
+ edge e = split_block (gsi_bb (gsi), gsi_stmt (gsi));
+ edge_bb = e->src;
+ m_gsi = gsi_last_bb (edge_bb);
+ if (!gsi_end_p (m_gsi))
+ gsi_next (&m_gsi);
+
+ if (ifn == IFN_CLZ)
+ bqp = XALLOCAVEC (struct bq_details, cnt);
+ else
+ {
+ gsi = gsi_for_stmt (stmt);
+ gsi_prev (&gsi);
+ e = split_block (gsi_bb (gsi), gsi_stmt (gsi));
+ edge_bb = e->src;
+ bqp = XALLOCAVEC (struct bq_details, 2 * cnt);
+ }
+
+ for (unsigned i = 0; i < cnt; i++)
+ {
+ m_data_cnt = 0;
+ if (kind == bitint_prec_large)
+ idx = size_int (cnt - i - 1);
+ else if (i == cnt - 1)
+ idx = create_loop (size_int (end - 1), &idx_next);
+ else
+ idx = size_int (end);
+
+ tree rhs1 = handle_operand (arg0, idx);
+ if (!useless_type_conversion_p (m_limb_type, TREE_TYPE (rhs1)))
+ {
+ if (ifn == IFN_CLZ && !TYPE_UNSIGNED (TREE_TYPE (rhs1)))
+ rhs1 = add_cast (unsigned_type_for (TREE_TYPE (rhs1)), rhs1);
+ else if (ifn == IFN_CLRSB && TYPE_UNSIGNED (TREE_TYPE (rhs1)))
+ rhs1 = add_cast (signed_type_for (TREE_TYPE (rhs1)), rhs1);
+ rhs1 = add_cast (m_limb_type, rhs1);
+ }
+
+ if (ifn == IFN_CLZ)
+ {
+ g = gimple_build_cond (NE_EXPR, rhs1,
+ build_zero_cst (m_limb_type),
+ NULL_TREE, NULL_TREE);
+ insert_before (g);
+ edge e1 = split_block (gsi_bb (m_gsi), g);
+ e1->flags = EDGE_FALSE_VALUE;
+ edge e2 = make_edge (e1->src, gimple_bb (stmt), EDGE_TRUE_VALUE);
+ e1->probability = profile_probability::unlikely ();
+ e2->probability = e1->probability.invert ();
+ if (i == 0)
+ set_immediate_dominator (CDI_DOMINATORS, e2->dest, e2->src);
+ m_gsi = gsi_after_labels (e1->dest);
+ bqp[i].e = e2;
+ bqp[i].val = rhs1;
+ }
+ else
+ {
+ if (i == 0)
+ {
+ first = rhs1;
+ g = gimple_build_assign (make_ssa_name (m_limb_type),
+ PLUS_EXPR, rhs1,
+ build_int_cst (m_limb_type, 1));
+ insert_before (g);
+ g = gimple_build_cond (GT_EXPR, gimple_assign_lhs (g),
+ build_int_cst (m_limb_type, 1),
+ NULL_TREE, NULL_TREE);
+ insert_before (g);
+ }
+ else
+ {
+ g = gimple_build_assign (make_ssa_name (m_limb_type),
+ BIT_XOR_EXPR, rhs1, first);
+ insert_before (g);
+ tree stype = signed_type_for (m_limb_type);
+ g = gimple_build_cond (LT_EXPR,
+ add_cast (stype,
+ gimple_assign_lhs (g)),
+ build_zero_cst (stype),
+ NULL_TREE, NULL_TREE);
+ insert_before (g);
+ edge e1 = split_block (gsi_bb (m_gsi), g);
+ e1->flags = EDGE_FALSE_VALUE;
+ edge e2 = make_edge (e1->src, gimple_bb (stmt),
+ EDGE_TRUE_VALUE);
+ e1->probability = profile_probability::unlikely ();
+ e2->probability = e1->probability.invert ();
+ if (i == 1)
+ set_immediate_dominator (CDI_DOMINATORS, e2->dest,
+ e2->src);
+ m_gsi = gsi_after_labels (e1->dest);
+ bqp[2 * i].e = e2;
+ g = gimple_build_cond (NE_EXPR, rhs1, first,
+ NULL_TREE, NULL_TREE);
+ insert_before (g);
+ }
+ edge e1 = split_block (gsi_bb (m_gsi), g);
+ e1->flags = EDGE_FALSE_VALUE;
+ edge e2 = make_edge (e1->src, edge_bb, EDGE_TRUE_VALUE);
+ e1->probability = profile_probability::unlikely ();
+ e2->probability = e1->probability.invert ();
+ if (i == 0)
+ set_immediate_dominator (CDI_DOMINATORS, e2->dest, e2->src);
+ m_gsi = gsi_after_labels (e1->dest);
+ bqp[2 * i + 1].e = e2;
+ bqp[i].val = rhs1;
+ }
+ if (tree_fits_uhwi_p (idx))
+ bqp[i].addend
+ = build_int_cst (integer_type_node,
+ (int) prec
+ - (((int) tree_to_uhwi (idx) + 1)
+ * limb_prec) - sub_one);
+ else
+ {
+ tree in, out;
+ in = build_int_cst (integer_type_node, rem - sub_one);
+ m_first = true;
+ in = prepare_data_in_out (in, idx, &out);
+ out = m_data[m_data_cnt + 1];
+ bqp[i].addend = in;
+ g = gimple_build_assign (out, PLUS_EXPR, in,
+ build_int_cst (integer_type_node,
+ limb_prec));
+ insert_before (g);
+ m_data[m_data_cnt] = out;
+ }
+
+ m_first = false;
+ if (kind == bitint_prec_huge && i == cnt - 1)
+ {
+ g = gimple_build_assign (idx_next, PLUS_EXPR, idx,
+ size_int (-1));
+ insert_before (g);
+ g = gimple_build_cond (NE_EXPR, idx, size_zero_node,
+ NULL_TREE, NULL_TREE);
+ insert_before (g);
+ edge true_edge, false_edge;
+ extract_true_false_edges_from_block (gsi_bb (m_gsi),
+ &true_edge, &false_edge);
+ m_gsi = gsi_after_labels (false_edge->dest);
+ }
+ }
+ }
+ switch (ifn)
+ {
+ case IFN_CLZ:
+ case IFN_CTZ:
+ case IFN_FFS:
+ gphi *phi1, *phi2, *phi3;
+ basic_block bb;
+ bb = gsi_bb (m_gsi);
+ remove_edge (find_edge (bb, gimple_bb (stmt)));
+ phi1 = create_phi_node (make_ssa_name (m_limb_type),
+ gimple_bb (stmt));
+ phi2 = create_phi_node (make_ssa_name (integer_type_node),
+ gimple_bb (stmt));
+ for (unsigned i = 0; i < cnt; i++)
+ {
+ add_phi_arg (phi1, bqp[i].val, bqp[i].e, UNKNOWN_LOCATION);
+ add_phi_arg (phi2, bqp[i].addend, bqp[i].e, UNKNOWN_LOCATION);
+ }
+ if (arg1 == NULL_TREE)
+ {
+ g = gimple_build_builtin_unreachable (m_loc);
+ insert_before (g);
+ }
+ m_gsi = gsi_for_stmt (stmt);
+ g = gimple_build_call (fndecl, 1, gimple_phi_result (phi1));
+ gimple_call_set_lhs (g, make_ssa_name (integer_type_node));
+ insert_before (g);
+ if (arg1 == NULL_TREE)
+ g = gimple_build_assign (lhs, PLUS_EXPR,
+ gimple_phi_result (phi2),
+ gimple_call_lhs (g));
+ else
+ {
+ g = gimple_build_assign (make_ssa_name (integer_type_node),
+ PLUS_EXPR, gimple_phi_result (phi2),
+ gimple_call_lhs (g));
+ insert_before (g);
+ edge e1 = split_block (gimple_bb (stmt), g);
+ edge e2 = make_edge (bb, e1->dest, EDGE_FALLTHRU);
+ e2->probability = profile_probability::always ();
+ set_immediate_dominator (CDI_DOMINATORS, e1->dest,
+ get_immediate_dominator (CDI_DOMINATORS,
+ e1->src));
+ phi3 = create_phi_node (make_ssa_name (integer_type_node), e1->dest);
+ add_phi_arg (phi3, gimple_assign_lhs (g), e1, UNKNOWN_LOCATION);
+ add_phi_arg (phi3, arg1, e2, UNKNOWN_LOCATION);
+ m_gsi = gsi_for_stmt (stmt);
+ g = gimple_build_assign (lhs, gimple_phi_result (phi3));
+ }
+ gsi_replace (&m_gsi, g, true);
+ break;
+ case IFN_CLRSB:
+ bb = gsi_bb (m_gsi);
+ remove_edge (find_edge (bb, edge_bb));
+ edge e;
+ e = make_edge (bb, gimple_bb (stmt), EDGE_FALLTHRU);
+ e->probability = profile_probability::always ();
+ set_immediate_dominator (CDI_DOMINATORS, gimple_bb (stmt),
+ get_immediate_dominator (CDI_DOMINATORS,
+ edge_bb));
+ phi1 = create_phi_node (make_ssa_name (m_limb_type),
+ edge_bb);
+ phi2 = create_phi_node (make_ssa_name (integer_type_node),
+ edge_bb);
+ phi3 = create_phi_node (make_ssa_name (integer_type_node),
+ gimple_bb (stmt));
+ for (unsigned i = 0; i < cnt; i++)
+ {
+ add_phi_arg (phi1, bqp[i].val, bqp[2 * i + 1].e, UNKNOWN_LOCATION);
+ add_phi_arg (phi2, bqp[i].addend, bqp[2 * i + 1].e,
+ UNKNOWN_LOCATION);
+ tree a = bqp[i].addend;
+ if (i && kind == bitint_prec_large)
+ a = int_const_binop (PLUS_EXPR, a, integer_minus_one_node);
+ if (i)
+ add_phi_arg (phi3, a, bqp[2 * i].e, UNKNOWN_LOCATION);
+ }
+ add_phi_arg (phi3, build_int_cst (integer_type_node, prec - 1), e,
+ UNKNOWN_LOCATION);
+ m_gsi = gsi_after_labels (edge_bb);
+ g = gimple_build_call (fndecl, 1,
+ add_cast (signed_type_for (m_limb_type),
+ gimple_phi_result (phi1)));
+ gimple_call_set_lhs (g, make_ssa_name (integer_type_node));
+ insert_before (g);
+ g = gimple_build_assign (make_ssa_name (integer_type_node),
+ PLUS_EXPR, gimple_call_lhs (g),
+ gimple_phi_result (phi2));
+ insert_before (g);
+ if (kind != bitint_prec_large)
+ {
+ g = gimple_build_assign (make_ssa_name (integer_type_node),
+ PLUS_EXPR, gimple_assign_lhs (g),
+ integer_one_node);
+ insert_before (g);
+ }
+ add_phi_arg (phi3, gimple_assign_lhs (g),
+ find_edge (edge_bb, gimple_bb (stmt)), UNKNOWN_LOCATION);
+ m_gsi = gsi_for_stmt (stmt);
+ g = gimple_build_assign (lhs, gimple_phi_result (phi3));
+ gsi_replace (&m_gsi, g, true);
+ break;
+ case IFN_PARITY:
+ g = gimple_build_call (fndecl, 1, res);
+ gimple_call_set_lhs (g, lhs);
+ gsi_replace (&m_gsi, g, true);
+ break;
+ case IFN_POPCOUNT:
+ g = gimple_build_assign (lhs, res);
+ gsi_replace (&m_gsi, g, true);
+ break;
+ default:
+ gcc_unreachable ();
+ }
+}
+
/* Lower a call statement with one or more large/huge _BitInt
arguments or large/huge _BitInt return value. */
@@ -4476,6 +4995,14 @@ bitint_large_huge::lower_call (tree obj, gimple *stmt)
case IFN_UBSAN_CHECK_MUL:
lower_mul_overflow (obj, stmt);
return;
+ case IFN_CLZ:
+ case IFN_CTZ:
+ case IFN_CLRSB:
+ case IFN_FFS:
+ case IFN_PARITY:
+ case IFN_POPCOUNT:
+ lower_bit_query (stmt);
+ return;
default:
break;
}
diff --git a/gcc/gimple-range-op.cc b/gcc/gimple-range-op.cc
index 67b3c3d..26c42da 100644
--- a/gcc/gimple-range-op.cc
+++ b/gcc/gimple-range-op.cc
@@ -908,39 +908,34 @@ public:
cfn_clz (bool internal) { m_gimple_call_internal_p = internal; }
using range_operator::fold_range;
virtual bool fold_range (irange &r, tree type, const irange &lh,
- const irange &, relation_trio) const;
+ const irange &rh, relation_trio) const;
private:
bool m_gimple_call_internal_p;
} op_cfn_clz (false), op_cfn_clz_internal (true);
bool
cfn_clz::fold_range (irange &r, tree type, const irange &lh,
- const irange &, relation_trio) const
+ const irange &rh, relation_trio) const
{
// __builtin_c[lt]z* return [0, prec-1], except when the
// argument is 0, but that is undefined behavior.
//
// For __builtin_c[lt]z* consider argument of 0 always undefined
- // behavior, for internal fns depending on C?Z_DEFINED_VALUE_AT_ZERO.
+ // behavior, for internal fns likewise, unless it has 2 arguments,
+ // then the second argument is the value at zero.
if (lh.undefined_p ())
return false;
int prec = TYPE_PRECISION (lh.type ());
int mini = 0;
int maxi = prec - 1;
- int zerov = 0;
- scalar_int_mode mode = SCALAR_INT_TYPE_MODE (lh.type ());
if (m_gimple_call_internal_p)
{
- if (optab_handler (clz_optab, mode) != CODE_FOR_nothing
- && CLZ_DEFINED_VALUE_AT_ZERO (mode, zerov) == 2)
- {
- // Only handle the single common value.
- if (zerov == prec)
- maxi = prec;
- else
- // Magic value to give up, unless we can prove arg is non-zero.
- mini = -2;
- }
+ // Only handle the single common value.
+ if (rh.lower_bound () == prec)
+ maxi = prec;
+ else
+ // Magic value to give up, unless we can prove arg is non-zero.
+ mini = -2;
}
// From clz of minimum we can compute result maximum.
@@ -985,37 +980,31 @@ public:
cfn_ctz (bool internal) { m_gimple_call_internal_p = internal; }
using range_operator::fold_range;
virtual bool fold_range (irange &r, tree type, const irange &lh,
- const irange &, relation_trio) const;
+ const irange &rh, relation_trio) const;
private:
bool m_gimple_call_internal_p;
} op_cfn_ctz (false), op_cfn_ctz_internal (true);
bool
cfn_ctz::fold_range (irange &r, tree type, const irange &lh,
- const irange &, relation_trio) const
+ const irange &rh, relation_trio) const
{
if (lh.undefined_p ())
return false;
int prec = TYPE_PRECISION (lh.type ());
int mini = 0;
int maxi = prec - 1;
- int zerov = 0;
- scalar_int_mode mode = SCALAR_INT_TYPE_MODE (lh.type ());
if (m_gimple_call_internal_p)
{
- if (optab_handler (ctz_optab, mode) != CODE_FOR_nothing
- && CTZ_DEFINED_VALUE_AT_ZERO (mode, zerov) == 2)
- {
- // Handle only the two common values.
- if (zerov == -1)
- mini = -1;
- else if (zerov == prec)
- maxi = prec;
- else
- // Magic value to give up, unless we can prove arg is non-zero.
- mini = -2;
- }
+ // Handle only the two common values.
+ if (rh.lower_bound () == -1)
+ mini = -1;
+ else if (rh.lower_bound () == prec)
+ maxi = prec;
+ else
+ // Magic value to give up, unless we can prove arg is non-zero.
+ mini = -2;
}
// If arg is non-zero, then use [0, prec - 1].
if (!range_includes_zero_p (&lh))
@@ -1288,16 +1277,24 @@ gimple_range_op_handler::maybe_builtin_call ()
CASE_CFN_CLZ:
m_op1 = gimple_call_arg (call, 0);
- if (gimple_call_internal_p (call))
- m_operator = &op_cfn_clz_internal;
+ if (gimple_call_internal_p (call)
+ && gimple_call_num_args (call) == 2)
+ {
+ m_op2 = gimple_call_arg (call, 1);
+ m_operator = &op_cfn_clz_internal;
+ }
else
m_operator = &op_cfn_clz;
break;
CASE_CFN_CTZ:
m_op1 = gimple_call_arg (call, 0);
- if (gimple_call_internal_p (call))
- m_operator = &op_cfn_ctz_internal;
+ if (gimple_call_internal_p (call)
+ && gimple_call_num_args (call) == 2)
+ {
+ m_op2 = gimple_call_arg (call, 1);
+ m_operator = &op_cfn_ctz_internal;
+ }
else
m_operator = &op_cfn_ctz;
break;
diff --git a/gcc/match.pd b/gcc/match.pd
index 281c6c0..59791f4 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -8536,31 +8536,34 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
(op (clz:s@2 @0) INTEGER_CST@1)
(if (integer_zerop (@1) && single_use (@2))
/* clz(X) == 0 is (int)X < 0 and clz(X) != 0 is (int)X >= 0. */
- (with { tree type0 = TREE_TYPE (@0);
- tree stype = signed_type_for (type0);
- HOST_WIDE_INT val = 0;
- /* Punt on hypothetical weird targets. */
- if (clz == CFN_CLZ
- && CLZ_DEFINED_VALUE_AT_ZERO (SCALAR_TYPE_MODE (type0),
- val) == 2
- && val == 0)
- stype = NULL_TREE;
- }
- (if (stype)
- (cmp (convert:stype @0) { build_zero_cst (stype); })))
+ (with { tree stype = signed_type_for (TREE_TYPE (@0)); }
+ (cmp (convert:stype @0) { build_zero_cst (stype); }))
/* clz(X) == (prec-1) is X == 1 and clz(X) != (prec-1) is X != 1. */
- (with { bool ok = true;
- HOST_WIDE_INT val = 0;
- tree type0 = TREE_TYPE (@0);
- /* Punt on hypothetical weird targets. */
- if (clz == CFN_CLZ
- && CLZ_DEFINED_VALUE_AT_ZERO (SCALAR_TYPE_MODE (type0),
- val) == 2
- && val == TYPE_PRECISION (type0) - 1)
- ok = false;
- }
- (if (ok && wi::to_wide (@1) == (TYPE_PRECISION (type0) - 1))
- (op @0 { build_one_cst (type0); })))))))
+ (if (wi::to_wide (@1) == TYPE_PRECISION (TREE_TYPE (@0)) - 1)
+ (op @0 { build_one_cst (TREE_TYPE (@0)); }))))))
+(for op (eq ne)
+ cmp (lt ge)
+ (simplify
+ (op (IFN_CLZ:s@2 @0 @3) INTEGER_CST@1)
+ (if (integer_zerop (@1) && single_use (@2))
+ /* clz(X) == 0 is (int)X < 0 and clz(X) != 0 is (int)X >= 0. */
+ (with { tree type0 = TREE_TYPE (@0);
+ tree stype = signed_type_for (TREE_TYPE (@0));
+ /* Punt if clz(0) == 0. */
+ if (integer_zerop (@3))
+ stype = NULL_TREE;
+ }
+ (if (stype)
+ (cmp (convert:stype @0) { build_zero_cst (stype); })))
+ /* clz(X) == (prec-1) is X == 1 and clz(X) != (prec-1) is X != 1. */
+ (with { bool ok = true;
+ tree type0 = TREE_TYPE (@0);
+ /* Punt if clz(0) == prec - 1. */
+ if (wi::to_widest (@3) == TYPE_PRECISION (type0) - 1)
+ ok = false;
+ }
+ (if (ok && wi::to_wide (@1) == (TYPE_PRECISION (type0) - 1))
+ (op @0 { build_one_cst (type0); }))))))
/* CTZ simplifications. */
(for ctz (CTZ)
@@ -8585,22 +8588,14 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
val++;
}
}
- bool zero_res = false;
- HOST_WIDE_INT zero_val = 0;
tree type0 = TREE_TYPE (@0);
int prec = TYPE_PRECISION (type0);
- if (ctz == CFN_CTZ
- && CTZ_DEFINED_VALUE_AT_ZERO (SCALAR_TYPE_MODE (type0),
- zero_val) == 2)
- zero_res = true;
}
- (if (val <= 0)
- (if (ok && (!zero_res || zero_val >= val))
- { constant_boolean_node (cmp == EQ_EXPR ? true : false, type); })
- (if (val >= prec)
- (if (ok && (!zero_res || zero_val < val))
- { constant_boolean_node (cmp == EQ_EXPR ? false : true, type); })
- (if (ok && (!zero_res || zero_val < 0 || zero_val >= prec))
+ (if (ok && prec <= MAX_FIXED_MODE_SIZE)
+ (if (val <= 0)
+ { constant_boolean_node (cmp == EQ_EXPR ? true : false, type); }
+ (if (val >= prec)
+ { constant_boolean_node (cmp == EQ_EXPR ? false : true, type); }
(cmp (bit_and @0 { wide_int_to_tree (type0,
wi::mask (val, false, prec)); })
{ build_zero_cst (type0); })))))))
@@ -8608,19 +8603,68 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
(simplify
/* __builtin_ctz (x) == C -> (x & ((1 << (C + 1)) - 1)) == (1 << C). */
(op (ctz:s @0) INTEGER_CST@1)
- (with { bool zero_res = false;
- HOST_WIDE_INT zero_val = 0;
- tree type0 = TREE_TYPE (@0);
+ (with { tree type0 = TREE_TYPE (@0);
int prec = TYPE_PRECISION (type0);
- if (ctz == CFN_CTZ
- && CTZ_DEFINED_VALUE_AT_ZERO (SCALAR_TYPE_MODE (type0),
- zero_val) == 2)
- zero_res = true;
}
+ (if (prec <= MAX_FIXED_MODE_SIZE)
+ (if (tree_int_cst_sgn (@1) < 0 || wi::to_widest (@1) >= prec)
+ { constant_boolean_node (op == EQ_EXPR ? false : true, type); }
+ (op (bit_and @0 { wide_int_to_tree (type0,
+ wi::mask (tree_to_uhwi (@1) + 1,
+ false, prec)); })
+ { wide_int_to_tree (type0,
+ wi::shifted_mask (tree_to_uhwi (@1), 1,
+ false, prec)); })))))))
+(for op (ge gt le lt)
+ cmp (eq eq ne ne)
+ (simplify
+ /* __builtin_ctz (x) >= C -> (x & ((1 << C) - 1)) == 0. */
+ (op (IFN_CTZ:s @0 @2) INTEGER_CST@1)
+ (with { bool ok = true;
+ HOST_WIDE_INT val = 0;
+ if (!tree_fits_shwi_p (@1))
+ ok = false;
+ else
+ {
+ val = tree_to_shwi (@1);
+ /* Canonicalize to >= or <. */
+ if (op == GT_EXPR || op == LE_EXPR)
+ {
+ if (val == HOST_WIDE_INT_MAX)
+ ok = false;
+ else
+ val++;
+ }
+ }
+ HOST_WIDE_INT zero_val = tree_to_shwi (@2);
+ tree type0 = TREE_TYPE (@0);
+ int prec = TYPE_PRECISION (type0);
+ if (prec > MAX_FIXED_MODE_SIZE)
+ ok = false;
+ }
+ (if (val <= 0)
+ (if (ok && zero_val >= val)
+ { constant_boolean_node (cmp == EQ_EXPR ? true : false, type); })
+ (if (val >= prec)
+ (if (ok && zero_val < val)
+ { constant_boolean_node (cmp == EQ_EXPR ? false : true, type); })
+ (if (ok && (zero_val < 0 || zero_val >= prec))
+ (cmp (bit_and @0 { wide_int_to_tree (type0,
+ wi::mask (val, false, prec)); })
+ { build_zero_cst (type0); })))))))
+(for op (eq ne)
+ (simplify
+ /* __builtin_ctz (x) == C -> (x & ((1 << (C + 1)) - 1)) == (1 << C). */
+ (op (IFN_CTZ:s @0 @2) INTEGER_CST@1)
+ (with { HOST_WIDE_INT zero_val = tree_to_shwi (@2);
+ tree type0 = TREE_TYPE (@0);
+ int prec = TYPE_PRECISION (type0);
+ }
+ (if (prec <= MAX_FIXED_MODE_SIZE)
(if (tree_int_cst_sgn (@1) < 0 || wi::to_widest (@1) >= prec)
- (if (!zero_res || zero_val != wi::to_widest (@1))
+ (if (zero_val != wi::to_widest (@1))
{ constant_boolean_node (op == EQ_EXPR ? false : true, type); })
- (if (!zero_res || zero_val < 0 || zero_val >= prec)
+ (if (zero_val < 0 || zero_val >= prec)
(op (bit_and @0 { wide_int_to_tree (type0,
wi::mask (tree_to_uhwi (@1) + 1,
false, prec)); })
@@ -8757,13 +8801,38 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
(cond (ne @0 integer_zerop@1) (func (convert?@3 @0)) INTEGER_CST@2)
(with { int val;
internal_fn ifn = IFN_LAST;
- if (direct_internal_fn_supported_p (IFN_CLZ, type, OPTIMIZE_FOR_BOTH)
- && CLZ_DEFINED_VALUE_AT_ZERO (SCALAR_INT_TYPE_MODE (type),
- val) == 2)
+ if (TREE_CODE (TREE_TYPE (@3)) == BITINT_TYPE)
+ {
+ if (tree_fits_shwi_p (@2))
+ {
+ HOST_WIDE_INT valw = tree_to_shwi (@2);
+ if ((int) valw == valw)
+ {
+ val = valw;
+ ifn = IFN_CLZ;
+ }
+ }
+ }
+ else if (direct_internal_fn_supported_p (IFN_CLZ, TREE_TYPE (@3),
+ OPTIMIZE_FOR_BOTH)
+ && CLZ_DEFINED_VALUE_AT_ZERO
+ (SCALAR_INT_TYPE_MODE (TREE_TYPE (@3)), val) == 2)
ifn = IFN_CLZ;
}
(if (ifn == IFN_CLZ && wi::to_widest (@2) == val)
- (IFN_CLZ @3)))))
+ (IFN_CLZ @3 @2)))))
+(simplify
+ (cond (ne @0 integer_zerop@1) (IFN_CLZ (convert?@3 @0) INTEGER_CST@2) @2)
+ (with { int val;
+ internal_fn ifn = IFN_LAST;
+ if (TREE_CODE (TREE_TYPE (@3)) == BITINT_TYPE)
+ ifn = IFN_CLZ;
+ else if (direct_internal_fn_supported_p (IFN_CLZ, TREE_TYPE (@3),
+ OPTIMIZE_FOR_BOTH))
+ ifn = IFN_CLZ;
+ }
+ (if (ifn == IFN_CLZ)
+ (IFN_CLZ @3 @2))))
/* a != 0 ? CTZ(a) : CST -> .CTZ(a) where CST is the result of the internal function for 0. */
(for func (CTZ)
@@ -8771,13 +8840,38 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
(cond (ne @0 integer_zerop@1) (func (convert?@3 @0)) INTEGER_CST@2)
(with { int val;
internal_fn ifn = IFN_LAST;
- if (direct_internal_fn_supported_p (IFN_CTZ, type, OPTIMIZE_FOR_BOTH)
- && CTZ_DEFINED_VALUE_AT_ZERO (SCALAR_INT_TYPE_MODE (type),
- val) == 2)
+ if (TREE_CODE (TREE_TYPE (@3)) == BITINT_TYPE)
+ {
+ if (tree_fits_shwi_p (@2))
+ {
+ HOST_WIDE_INT valw = tree_to_shwi (@2);
+ if ((int) valw == valw)
+ {
+ val = valw;
+ ifn = IFN_CTZ;
+ }
+ }
+ }
+ else if (direct_internal_fn_supported_p (IFN_CTZ, TREE_TYPE (@3),
+ OPTIMIZE_FOR_BOTH)
+ && CTZ_DEFINED_VALUE_AT_ZERO
+ (SCALAR_INT_TYPE_MODE (TREE_TYPE (@3)), val) == 2)
ifn = IFN_CTZ;
}
(if (ifn == IFN_CTZ && wi::to_widest (@2) == val)
- (IFN_CTZ @3)))))
+ (IFN_CTZ @3 @2)))))
+(simplify
+ (cond (ne @0 integer_zerop@1) (IFN_CTZ (convert?@3 @0) INTEGER_CST@2) @2)
+ (with { int val;
+ internal_fn ifn = IFN_LAST;
+ if (TREE_CODE (TREE_TYPE (@3)) == BITINT_TYPE)
+ ifn = IFN_CTZ;
+ else if (direct_internal_fn_supported_p (IFN_CTZ, TREE_TYPE (@3),
+ OPTIMIZE_FOR_BOTH))
+ ifn = IFN_CTZ;
+ }
+ (if (ifn == IFN_CTZ)
+ (IFN_CTZ @3 @2))))
#endif
/* Common POPCOUNT/PARITY simplifications. */
diff --git a/gcc/testsuite/c-c++-common/pr111309-1.c b/gcc/testsuite/c-c++-common/pr111309-1.c
new file mode 100644
index 0000000..fdf3bf1
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr111309-1.c
@@ -0,0 +1,470 @@
+/* PR c/111309 */
+/* { dg-do run } */
+/* { dg-options "-O2" } */
+
+__attribute__((noipa)) int
+clzc (unsigned char x)
+{
+ return __builtin_clzg (x);
+}
+
+__attribute__((noipa)) int
+clzc2 (unsigned char x, int y)
+{
+ return __builtin_clzg (x, y);
+}
+
+__attribute__((noipa)) int
+clzs (unsigned short x)
+{
+ return __builtin_clzg (x);
+}
+
+__attribute__((noipa)) int
+clzs2 (unsigned short x)
+{
+ return __builtin_clzg (x, -2);
+}
+
+__attribute__((noipa)) int
+clzi (unsigned int x)
+{
+ return __builtin_clzg (x);
+}
+
+__attribute__((noipa)) int
+clzi2 (unsigned int x, int y)
+{
+ return __builtin_clzg (x, y);
+}
+
+__attribute__((noipa)) int
+clzl (unsigned long x)
+{
+ return __builtin_clzg (x);
+}
+
+__attribute__((noipa)) int
+clzl2 (unsigned long x)
+{
+ return __builtin_clzg (x, -1);
+}
+
+__attribute__((noipa)) int
+clzL (unsigned long long x)
+{
+ return __builtin_clzg (x);
+}
+
+__attribute__((noipa)) int
+clzL2 (unsigned long long x, int y)
+{
+ return __builtin_clzg (x, y);
+}
+
+#ifdef __SIZEOF_INT128__
+__attribute__((noipa)) int
+clzI (unsigned __int128 x)
+{
+ return __builtin_clzg (x);
+}
+
+__attribute__((noipa)) int
+clzI2 (unsigned __int128 x, int y)
+{
+ return __builtin_clzg (x, y);
+}
+#endif
+
+__attribute__((noipa)) int
+ctzc (unsigned char x)
+{
+ return __builtin_ctzg (x);
+}
+
+__attribute__((noipa)) int
+ctzc2 (unsigned char x, int y)
+{
+ return __builtin_ctzg (x, y);
+}
+
+__attribute__((noipa)) int
+ctzs (unsigned short x)
+{
+ return __builtin_ctzg (x);
+}
+
+__attribute__((noipa)) int
+ctzs2 (unsigned short x, int y)
+{
+ return __builtin_ctzg (x, y);
+}
+
+__attribute__((noipa)) int
+ctzi (unsigned int x)
+{
+ return __builtin_ctzg (x);
+}
+
+__attribute__((noipa)) int
+ctzi2 (unsigned int x, int y)
+{
+ return __builtin_ctzg (x, y);
+}
+
+__attribute__((noipa)) int
+ctzl (unsigned long x)
+{
+ return __builtin_ctzg (x);
+}
+
+__attribute__((noipa)) int
+ctzl2 (unsigned long x, int y)
+{
+ return __builtin_ctzg (x, y);
+}
+
+__attribute__((noipa)) int
+ctzL (unsigned long long x)
+{
+ return __builtin_ctzg (x);
+}
+
+__attribute__((noipa)) int
+ctzL2 (unsigned long long x, int y)
+{
+ return __builtin_ctzg (x, y);
+}
+
+#ifdef __SIZEOF_INT128__
+__attribute__((noipa)) int
+ctzI (unsigned __int128 x)
+{
+ return __builtin_ctzg (x);
+}
+
+__attribute__((noipa)) int
+ctzI2 (unsigned __int128 x)
+{
+ return __builtin_ctzg (x, __SIZEOF_INT128__ * __CHAR_BIT__);
+}
+#endif
+
+__attribute__((noipa)) int
+clrsbc (signed char x)
+{
+ return __builtin_clrsbg (x);
+}
+
+__attribute__((noipa)) int
+clrsbs (signed short x)
+{
+ return __builtin_clrsbg (x);
+}
+
+__attribute__((noipa)) int
+clrsbi (signed int x)
+{
+ return __builtin_clrsbg (x);
+}
+
+__attribute__((noipa)) int
+clrsbl (signed long x)
+{
+ return __builtin_clrsbg (x);
+}
+
+__attribute__((noipa)) int
+clrsbL (signed long long x)
+{
+ return __builtin_clrsbg (x);
+}
+
+#ifdef __SIZEOF_INT128__
+__attribute__((noipa)) int
+clrsbI (signed __int128 x)
+{
+ return __builtin_clrsbg (x);
+}
+#endif
+
+__attribute__((noipa)) int
+ffsc (signed char x)
+{
+ return __builtin_ffsg (x);
+}
+
+__attribute__((noipa)) int
+ffss (signed short x)
+{
+ return __builtin_ffsg (x);
+}
+
+__attribute__((noipa)) int
+ffsi (signed int x)
+{
+ return __builtin_ffsg (x);
+}
+
+__attribute__((noipa)) int
+ffsl (signed long x)
+{
+ return __builtin_ffsg (x);
+}
+
+__attribute__((noipa)) int
+ffsL (signed long long x)
+{
+ return __builtin_ffsg (x);
+}
+
+#ifdef __SIZEOF_INT128__
+__attribute__((noipa)) int
+ffsI (signed __int128 x)
+{
+ return __builtin_ffsg (x);
+}
+#endif
+
+__attribute__((noipa)) int
+parityc (unsigned char x)
+{
+ return __builtin_parityg (x);
+}
+
+__attribute__((noipa)) int
+paritys (unsigned short x)
+{
+ return __builtin_parityg (x);
+}
+
+__attribute__((noipa)) int
+parityi (unsigned int x)
+{
+ return __builtin_parityg (x);
+}
+
+__attribute__((noipa)) int
+parityl (unsigned long x)
+{
+ return __builtin_parityg (x);
+}
+
+__attribute__((noipa)) int
+parityL (unsigned long long x)
+{
+ return __builtin_parityg (x);
+}
+
+#ifdef __SIZEOF_INT128__
+__attribute__((noipa)) int
+parityI (unsigned __int128 x)
+{
+ return __builtin_parityg (x);
+}
+#endif
+
+__attribute__((noipa)) int
+popcountc (unsigned char x)
+{
+ return __builtin_popcountg (x);
+}
+
+__attribute__((noipa)) int
+popcounts (unsigned short x)
+{
+ return __builtin_popcountg (x);
+}
+
+__attribute__((noipa)) int
+popcounti (unsigned int x)
+{
+ return __builtin_popcountg (x);
+}
+
+__attribute__((noipa)) int
+popcountl (unsigned long x)
+{
+ return __builtin_popcountg (x);
+}
+
+__attribute__((noipa)) int
+popcountL (unsigned long long x)
+{
+ return __builtin_popcountg (x);
+}
+
+#ifdef __SIZEOF_INT128__
+__attribute__((noipa)) int
+popcountI (unsigned __int128 x)
+{
+ return __builtin_popcountg (x);
+}
+#endif
+
+int
+main ()
+{
+ if (__builtin_clzg ((unsigned char) 1) != __CHAR_BIT__ - 1
+ || __builtin_clzg ((unsigned short) 2, -2) != __SIZEOF_SHORT__ * __CHAR_BIT__ - 2
+ || __builtin_clzg (0U, 42) != 42
+ || __builtin_clzg (0U, -1) != -1
+ || __builtin_clzg (1U) != __SIZEOF_INT__ * __CHAR_BIT__ - 1
+ || __builtin_clzg (2UL, -1) != __SIZEOF_LONG__ * __CHAR_BIT__ - 2
+ || __builtin_clzg (5ULL) != __SIZEOF_LONG_LONG__ * __CHAR_BIT__ - 3
+#ifdef __SIZEOF_INT128__
+ || __builtin_clzg ((unsigned __int128) 9) != __SIZEOF_INT128__ * __CHAR_BIT__ - 4
+#endif
+ || __builtin_clzg (~0U, -5) != 0
+ || __builtin_clzg (~0ULL >> 2) != 2
+ || __builtin_ctzg ((unsigned char) 1) != 0
+ || __builtin_ctzg ((unsigned short) 28) != 2
+ || __builtin_ctzg (0U, 32) != 32
+ || __builtin_ctzg (0U, -42) != -42
+ || __builtin_ctzg (1U) != 0
+ || __builtin_ctzg (16UL, -1) != 4
+ || __builtin_ctzg (5ULL << 52, 0) != 52
+#ifdef __SIZEOF_INT128__
+ || __builtin_ctzg (((unsigned __int128) 9) << 72) != 72
+#endif
+ || __builtin_clrsbg ((signed char) 0) != __CHAR_BIT__ - 1
+ || __builtin_clrsbg ((signed short) -1) != __SIZEOF_SHORT__ * __CHAR_BIT__ - 1
+ || __builtin_clrsbg (0) != __SIZEOF_INT__ * __CHAR_BIT__ - 1
+ || __builtin_clrsbg (-1L) != __SIZEOF_LONG__ * __CHAR_BIT__ - 1
+ || __builtin_clrsbg (0LL) != __SIZEOF_LONG_LONG__ * __CHAR_BIT__ - 1
+#ifdef __SIZEOF_INT128__
+ || __builtin_clrsbg ((__int128) -1) != __SIZEOF_INT128__ * __CHAR_BIT__ - 1
+#endif
+ || __builtin_clrsbg (0x1afb) != __SIZEOF_INT__ * __CHAR_BIT__ - 14
+ || __builtin_clrsbg (-2) != __SIZEOF_INT__ * __CHAR_BIT__ - 2
+ || __builtin_clrsbg (1L) != __SIZEOF_LONG__ * __CHAR_BIT__ - 2
+ || __builtin_clrsbg (-4LL) != __SIZEOF_LONG_LONG__ * __CHAR_BIT__ - 3
+ || __builtin_ffsg ((signed char) 0) != 0
+ || __builtin_ffsg ((signed short) 0) != 0
+ || __builtin_ffsg (0) != 0
+ || __builtin_ffsg (0L) != 0
+ || __builtin_ffsg (0LL) != 0
+#ifdef __SIZEOF_INT128__
+ || __builtin_ffsg ((__int128) 0) != 0
+#endif
+ || __builtin_ffsg ((signed char) 4) != 3
+ || __builtin_ffsg ((signed short) 8) != 4
+ || __builtin_ffsg (1) != 1
+ || __builtin_ffsg (2L) != 2
+ || __builtin_ffsg (28LL) != 3
+ || __builtin_parityg ((unsigned char) 1) != 1
+ || __builtin_parityg ((unsigned short) 2) != 1
+ || __builtin_parityg (0U) != 0
+ || __builtin_parityg (3U) != 0
+ || __builtin_parityg (0UL) != 0
+ || __builtin_parityg (7UL) != 1
+ || __builtin_parityg (0ULL) != 0
+#ifdef __SIZEOF_INT128__
+ || __builtin_parityg ((unsigned __int128) 0) != 0
+#endif
+ || __builtin_parityg ((unsigned char) ~0U) != 0
+ || __builtin_parityg ((unsigned short) ~0U) != 0
+ || __builtin_parityg (~0U) != 0
+ || __builtin_parityg (~0UL) != 0
+ || __builtin_parityg (~0ULL) != 0
+#ifdef __SIZEOF_INT128__
+ || __builtin_parityg (~(unsigned __int128) 0) != 0
+#endif
+ || __builtin_popcountg (0U) != 0
+ || __builtin_popcountg (0UL) != 0
+ || __builtin_popcountg (0ULL) != 0
+#ifdef __SIZEOF_INT128__
+ || __builtin_popcountg ((unsigned __int128) 0) != 0
+#endif
+ || __builtin_popcountg ((unsigned char) ~0U) != __CHAR_BIT__
+ || __builtin_popcountg ((unsigned short) ~0U) != __SIZEOF_SHORT__ * __CHAR_BIT__
+ || __builtin_popcountg (~0U) != __SIZEOF_INT__ * __CHAR_BIT__
+ || __builtin_popcountg (~0UL) != __SIZEOF_LONG__ * __CHAR_BIT__
+ || __builtin_popcountg (~0ULL) != __SIZEOF_LONG_LONG__ * __CHAR_BIT__
+#ifdef __SIZEOF_INT128__
+ || __builtin_popcountg (~(unsigned __int128) 0) != __SIZEOF_INT128__ * __CHAR_BIT__
+#endif
+ || 0)
+ __builtin_abort ();
+ if (clzc (1) != __CHAR_BIT__ - 1
+ || clzs2 (2) != __SIZEOF_SHORT__ * __CHAR_BIT__ - 2
+ || clzi2 (0U, 42) != 42
+ || clzi2 (0U, -1) != -1
+ || clzi (1U) != __SIZEOF_INT__ * __CHAR_BIT__ - 1
+ || clzl2 (2UL) != __SIZEOF_LONG__ * __CHAR_BIT__ - 2
+ || clzL (5ULL) != __SIZEOF_LONG_LONG__ * __CHAR_BIT__ - 3
+#ifdef __SIZEOF_INT128__
+ || clzI ((unsigned __int128) 9) != __SIZEOF_INT128__ * __CHAR_BIT__ - 4
+#endif
+ || clzi2 (~0U, -5) != 0
+ || clzL (~0ULL >> 2) != 2
+ || ctzc (1) != 0
+ || ctzs (28) != 2
+ || ctzi2 (0U, 32) != 32
+ || ctzi2 (0U, -42) != -42
+ || ctzi (1U) != 0
+ || ctzl2 (16UL, -1) != 4
+ || ctzL2 (5ULL << 52, 0) != 52
+#ifdef __SIZEOF_INT128__
+ || ctzI (((unsigned __int128) 9) << 72) != 72
+#endif
+ || clrsbc (0) != __CHAR_BIT__ - 1
+ || clrsbs (-1) != __SIZEOF_SHORT__ * __CHAR_BIT__ - 1
+ || clrsbi (0) != __SIZEOF_INT__ * __CHAR_BIT__ - 1
+ || clrsbl (-1L) != __SIZEOF_LONG__ * __CHAR_BIT__ - 1
+ || clrsbL (0LL) != __SIZEOF_LONG_LONG__ * __CHAR_BIT__ - 1
+#ifdef __SIZEOF_INT128__
+ || clrsbI (-1) != __SIZEOF_INT128__ * __CHAR_BIT__ - 1
+#endif
+ || clrsbi (0x1afb) != __SIZEOF_INT__ * __CHAR_BIT__ - 14
+ || clrsbi (-2) != __SIZEOF_INT__ * __CHAR_BIT__ - 2
+ || clrsbl (1L) != __SIZEOF_LONG__ * __CHAR_BIT__ - 2
+ || clrsbL (-4LL) != __SIZEOF_LONG_LONG__ * __CHAR_BIT__ - 3
+ || ffsc (0) != 0
+ || ffss (0) != 0
+ || ffsi (0) != 0
+ || ffsl (0L) != 0
+ || ffsL (0LL) != 0
+#ifdef __SIZEOF_INT128__
+ || ffsI (0) != 0
+#endif
+ || ffsc (4) != 3
+ || ffss (8) != 4
+ || ffsi (1) != 1
+ || ffsl (2L) != 2
+ || ffsL (28LL) != 3
+ || parityc (1) != 1
+ || paritys (2) != 1
+ || parityi (0U) != 0
+ || parityi (3U) != 0
+ || parityl (0UL) != 0
+ || parityl (7UL) != 1
+ || parityL (0ULL) != 0
+#ifdef __SIZEOF_INT128__
+ || parityI (0) != 0
+#endif
+ || parityc ((unsigned char) ~0U) != 0
+ || paritys ((unsigned short) ~0U) != 0
+ || parityi (~0U) != 0
+ || parityl (~0UL) != 0
+ || parityL (~0ULL) != 0
+#ifdef __SIZEOF_INT128__
+ || parityI (~(unsigned __int128) 0) != 0
+#endif
+ || popcounti (0U) != 0
+ || popcountl (0UL) != 0
+ || popcountL (0ULL) != 0
+#ifdef __SIZEOF_INT128__
+ || popcountI (0) != 0
+#endif
+ || popcountc ((unsigned char) ~0U) != __CHAR_BIT__
+ || popcounts ((unsigned short) ~0U) != __SIZEOF_SHORT__ * __CHAR_BIT__
+ || popcounti (~0U) != __SIZEOF_INT__ * __CHAR_BIT__
+ || popcountl (~0UL) != __SIZEOF_LONG__ * __CHAR_BIT__
+ || popcountL (~0ULL) != __SIZEOF_LONG_LONG__ * __CHAR_BIT__
+#ifdef __SIZEOF_INT128__
+ || popcountI (~(unsigned __int128) 0) != __SIZEOF_INT128__ * __CHAR_BIT__
+#endif
+ || 0)
+ __builtin_abort ();
+}
diff --git a/gcc/testsuite/c-c++-common/pr111309-2.c b/gcc/testsuite/c-c++-common/pr111309-2.c
new file mode 100644
index 0000000..535208b
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr111309-2.c
@@ -0,0 +1,85 @@
+/* PR c/111309 */
+/* { dg-do compile } */
+/* { dg-additional-options "-std=c99" { target c } } */
+
+#ifndef __cplusplus
+#define bool _Bool
+#define true ((_Bool) 1)
+#define false ((_Bool) 0)
+#endif
+
+void
+foo (void)
+{
+ enum E { E0 = 0 };
+ struct S { int s; } s;
+ __builtin_clzg (); /* { dg-error "too few arguments" } */
+ __builtin_clzg (0U, 1, 2); /* { dg-error "too many arguments" } */
+ __builtin_clzg (0); /* { dg-error "has signed type" } */
+ __builtin_clzg (0.0); /* { dg-error "does not have integral type" } */
+ __builtin_clzg (s); /* { dg-error "does not have integral type" } */
+ __builtin_clzg (true); /* { dg-error "has boolean type" } */
+ __builtin_clzg (E0); /* { dg-error "has signed type" "" { target c } } */
+ /* { dg-error "has enumerated type" "" { target c++ } .-1 } */
+ __builtin_clzg (0, 0); /* { dg-error "has signed type" } */
+ __builtin_clzg (0.0, 0); /* { dg-error "does not have integral type" } */
+ __builtin_clzg (s, 0); /* { dg-error "does not have integral type" } */
+ __builtin_clzg (true, 0); /* { dg-error "has boolean type" } */
+ __builtin_clzg (E0, 0); /* { dg-error "has signed type" "" { target c } } */
+ /* { dg-error "has enumerated type" "" { target c++ } .-1 } */
+ __builtin_clzg (0U, 2.0); /* { dg-error "does not have integral type" } */
+ __builtin_clzg (0U, s); /* { dg-error "does not have integral type" } */
+ __builtin_clzg (0U, 2LL); /* { dg-error "does not have 'int' type" } */
+ __builtin_clzg (0U, 2U); /* { dg-error "does not have 'int' type" } */
+ __builtin_clzg (0U, true);
+ __builtin_clzg (0U, E0); /* { dg-error "does not have 'int' type" "" { target c++ } } */
+ __builtin_ctzg (); /* { dg-error "too few arguments" } */
+ __builtin_ctzg (0U, 1, 2); /* { dg-error "too many arguments" } */
+ __builtin_ctzg (0); /* { dg-error "has signed type" } */
+ __builtin_ctzg (0.0); /* { dg-error "does not have integral type" } */
+ __builtin_ctzg (s); /* { dg-error "does not have integral type" } */
+ __builtin_ctzg (true); /* { dg-error "has boolean type" } */
+ __builtin_ctzg (E0); /* { dg-error "has signed type" "" { target c } } */
+ /* { dg-error "has enumerated type" "" { target c++ } .-1 } */
+ __builtin_ctzg (0, 0); /* { dg-error "has signed type" } */
+ __builtin_ctzg (0.0, 0); /* { dg-error "does not have integral type" } */
+ __builtin_ctzg (s, 0); /* { dg-error "does not have integral type" } */
+ __builtin_ctzg (true, 0); /* { dg-error "has boolean type" } */
+ __builtin_ctzg (E0, 0); /* { dg-error "has signed type" "" { target c } } */
+ /* { dg-error "has enumerated type" "" { target c++ } .-1 } */
+ __builtin_ctzg (0U, 2.0); /* { dg-error "does not have integral type" } */
+ __builtin_ctzg (0U, 2LL); /* { dg-error "does not have 'int' type" } */
+ __builtin_ctzg (0U, 2U); /* { dg-error "does not have 'int' type" } */
+ __builtin_ctzg (0U, true);
+ __builtin_ctzg (0U, E0); /* { dg-error "does not have 'int' type" "" { target c++ } } */
+ __builtin_clrsbg (); /* { dg-error "too few arguments" } */
+ __builtin_clrsbg (0, 1); /* { dg-error "too many arguments" } */
+ __builtin_clrsbg (0U); /* { dg-error "has unsigned type" } */
+ __builtin_clrsbg (0.0); /* { dg-error "does not have integral type" } */
+ __builtin_clrsbg (s); /* { dg-error "does not have integral type" } */
+ __builtin_clrsbg (true); /* { dg-error "has boolean type" } */
+ __builtin_clrsbg (E0); /* { dg-error "has enumerated type" "" { target c++ } } */
+ __builtin_ffsg (); /* { dg-error "too few arguments" } */
+ __builtin_ffsg (0, 1); /* { dg-error "too many arguments" } */
+ __builtin_ffsg (0U); /* { dg-error "has unsigned type" } */
+ __builtin_ffsg (0.0); /* { dg-error "does not have integral type" } */
+ __builtin_ffsg (s); /* { dg-error "does not have integral type" } */
+ __builtin_ffsg (true); /* { dg-error "has boolean type" } */
+ __builtin_ffsg (E0); /* { dg-error "has enumerated type" "" { target c++ } } */
+ __builtin_parityg (); /* { dg-error "too few arguments" } */
+ __builtin_parityg (0U, 1); /* { dg-error "too many arguments" } */
+ __builtin_parityg (0); /* { dg-error "has signed type" } */
+ __builtin_parityg (0.0); /* { dg-error "does not have integral type" } */
+ __builtin_parityg (s); /* { dg-error "does not have integral type" } */
+ __builtin_parityg (true); /* { dg-error "has boolean type" } */
+ __builtin_parityg (E0); /* { dg-error "has signed type" "" { target c } } */
+ /* { dg-error "has enumerated type" "" { target c++ } .-1 } */
+ __builtin_popcountg (); /* { dg-error "too few arguments" } */
+ __builtin_popcountg (0U, 1); /* { dg-error "too many arguments" } */
+ __builtin_popcountg (0); /* { dg-error "has signed type" } */
+ __builtin_popcountg (0.0); /* { dg-error "does not have integral type" } */
+ __builtin_popcountg (s); /* { dg-error "does not have integral type" } */
+ __builtin_popcountg (true); /* { dg-error "has boolean type" } */
+ __builtin_popcountg (E0); /* { dg-error "has signed type" "" { target c } } */
+ /* { dg-error "has enumerated type" "" { target c++ } .-1 } */
+}
diff --git a/gcc/testsuite/gcc.dg/torture/bitint-43.c b/gcc/testsuite/gcc.dg/torture/bitint-43.c
new file mode 100644
index 0000000..4265bff
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/torture/bitint-43.c
@@ -0,0 +1,306 @@
+/* PR c/111309 */
+/* { dg-do run { target bitint } } */
+/* { dg-options "-std=c2x -pedantic-errors" } */
+/* { dg-skip-if "" { ! run_expensive_tests } { "*" } { "-O0" "-O2" } } */
+/* { dg-skip-if "" { ! run_expensive_tests } { "-flto" } { "" } } */
+
+#if __BITINT_MAXWIDTH__ >= 156
+__attribute__((noipa)) int
+clz156 (unsigned _BitInt(156) x)
+{
+ return __builtin_clzg (x);
+}
+
+__attribute__((noipa)) int
+clzd156 (unsigned _BitInt(156) x)
+{
+ return __builtin_clzg (x, __builtin_popcountg ((typeof (x)) ~(typeof (x)) 0));
+}
+
+__attribute__((noipa)) int
+clzD156 (unsigned _BitInt(156) x, int y)
+{
+ return __builtin_clzg (x, y);
+}
+
+__attribute__((noipa)) int
+ctz156 (unsigned _BitInt(156) x)
+{
+ return __builtin_ctzg (x);
+}
+
+__attribute__((noipa)) int
+ctzd156 (unsigned _BitInt(156) x)
+{
+ return __builtin_ctzg (x, __builtin_popcountg ((typeof (x)) ~(typeof (x)) 0));
+}
+
+__attribute__((noipa)) int
+ctzD156 (unsigned _BitInt(156) x, int y)
+{
+ return __builtin_ctzg (x, y);
+}
+
+__attribute__((noipa)) int
+clrsb156 (_BitInt(156) x)
+{
+ return __builtin_clrsbg (x);
+}
+
+__attribute__((noipa)) int
+ffs156 (_BitInt(156) x)
+{
+ return __builtin_ffsg (x);
+}
+
+__attribute__((noipa)) int
+parity156 (unsigned _BitInt(156) x)
+{
+ return __builtin_parityg (x);
+}
+
+__attribute__((noipa)) int
+popcount156 (unsigned _BitInt(156) x)
+{
+ return __builtin_popcountg (x);
+}
+#endif
+
+#if __BITINT_MAXWIDTH__ >= 192
+__attribute__((noipa)) int
+clz192 (unsigned _BitInt(192) x)
+{
+ return __builtin_clzg (x);
+}
+
+__attribute__((noipa)) int
+clzd192 (unsigned _BitInt(192) x)
+{
+ return __builtin_clzg (x, __builtin_popcountg ((typeof (x)) ~(typeof (x)) 0));
+}
+
+__attribute__((noipa)) int
+clzD192 (unsigned _BitInt(192) x, int y)
+{
+ return __builtin_clzg (x, y);
+}
+
+__attribute__((noipa)) int
+ctz192 (unsigned _BitInt(192) x)
+{
+ return __builtin_ctzg (x);
+}
+
+__attribute__((noipa)) int
+ctzd192 (unsigned _BitInt(192) x)
+{
+ return __builtin_ctzg (x, __builtin_popcountg ((typeof (x)) ~(typeof (x)) 0));
+}
+
+__attribute__((noipa)) int
+ctzD192 (unsigned _BitInt(192) x, int y)
+{
+ return __builtin_ctzg (x, y);
+}
+
+__attribute__((noipa)) int
+clrsb192 (_BitInt(192) x)
+{
+ return __builtin_clrsbg (x);
+}
+
+__attribute__((noipa)) int
+ffs192 (_BitInt(192) x)
+{
+ return __builtin_ffsg (x);
+}
+
+__attribute__((noipa)) int
+parity192 (unsigned _BitInt(192) x)
+{
+ return __builtin_parityg (x);
+}
+
+__attribute__((noipa)) int
+popcount192 (unsigned _BitInt(192) x)
+{
+ return __builtin_popcountg (x);
+}
+#endif
+
+int
+main ()
+{
+#if __BITINT_MAXWIDTH__ >= 156
+ if (clzd156 (0) != 156
+ || clzD156 (0, -1) != -1
+ || ctzd156 (0) != 156
+ || ctzD156 (0, 42) != 42
+ || clrsb156 (0) != 156 - 1
+ || ffs156 (0) != 0
+ || parity156 (0) != 0
+ || popcount156 (0) != 0
+ || __builtin_clzg ((unsigned _BitInt(156)) 0, 156 + 32) != 156 + 32
+ || __builtin_ctzg ((unsigned _BitInt(156)) 0, 156) != 156
+ || __builtin_clrsbg ((_BitInt(156)) 0) != 156 - 1
+ || __builtin_ffsg ((_BitInt(156)) 0) != 0
+ || __builtin_parityg ((unsigned _BitInt(156)) 0) != 0
+ || __builtin_popcountg ((unsigned _BitInt(156)) 0) != 0)
+ __builtin_abort ();
+ if (clz156 (-1) != 0
+ || clzd156 (-1) != 0
+ || clzD156 (-1, 0) != 0
+ || ctz156 (-1) != 0
+ || ctzd156 (-1) != 0
+ || ctzD156 (-1, 17) != 0
+ || clrsb156 (-1) != 156 - 1
+ || ffs156 (-1) != 1
+ || parity156 (-1) != 0
+ || popcount156 (-1) != 156
+ || __builtin_clzg ((unsigned _BitInt(156)) -1) != 0
+ || __builtin_clzg ((unsigned _BitInt(156)) -1, 156 + 32) != 0
+ || __builtin_ctzg ((unsigned _BitInt(156)) -1) != 0
+ || __builtin_ctzg ((unsigned _BitInt(156)) -1, 156) != 0
+ || __builtin_clrsbg ((_BitInt(156)) -1) != 156 - 1
+ || __builtin_ffsg ((_BitInt(156)) -1) != 1
+ || __builtin_parityg ((unsigned _BitInt(156)) -1) != 0
+ || __builtin_popcountg ((unsigned _BitInt(156)) -1) != 156)
+ __builtin_abort ();
+ if (clz156 (((unsigned _BitInt(156)) -1) >> 24) != 24
+ || clz156 (((unsigned _BitInt(156)) -1) >> 79) != 79
+ || clz156 (1) != 156 - 1
+ || clzd156 (((unsigned _BitInt(156)) -1) >> 139) != 139
+ || clzd156 (2) != 156 - 2
+ || ctz156 (((unsigned _BitInt(156)) -1) << 42) != 42
+ || ctz156 (((unsigned _BitInt(156)) -1) << 57) != 57
+ || ctz156 (0x4000000000000000000000uwb) != 86
+ || ctzd156 (((unsigned _BitInt(156)) -1) << 149) != 149
+ || ctzd156 (2) != 1
+ || clrsb156 ((unsigned _BitInt(156 - 4)) -1) != 3
+ || clrsb156 ((unsigned _BitInt(156 - 28)) -1) != 27
+ || clrsb156 ((unsigned _BitInt(156 - 29)) -1) != 28
+ || clrsb156 (~(unsigned _BitInt(156)) (unsigned _BitInt(156 - 68)) -1) != 67
+ || clrsb156 (~(unsigned _BitInt(156)) (unsigned _BitInt(156 - 92)) -1) != 91
+ || clrsb156 (~(unsigned _BitInt(156)) (unsigned _BitInt(156 - 93)) -1) != 92
+ || ffs156 (((unsigned _BitInt(156)) -1) << 42) != 43
+ || ffs156 (((unsigned _BitInt(156)) -1) << 57) != 58
+ || ffs156 (0x4000000000000000000000uwb) != 87
+ || ffs156 (((unsigned _BitInt(156)) -1) << 149) != 150
+ || ffs156 (2) != 2
+ || __builtin_clzg (((unsigned _BitInt(156)) -1) >> 24) != 24
+ || __builtin_clzg (((unsigned _BitInt(156)) -1) >> 79) != 79
+ || __builtin_clzg ((unsigned _BitInt(156)) 1) != 156 - 1
+ || __builtin_clzg (((unsigned _BitInt(156)) -1) >> 139, 156) != 139
+ || __builtin_clzg ((unsigned _BitInt(156)) 2, 156) != 156 - 2
+ || __builtin_ctzg (((unsigned _BitInt(156)) -1) << 42) != 42
+ || __builtin_ctzg (((unsigned _BitInt(156)) -1) << 57) != 57
+ || __builtin_ctzg ((unsigned _BitInt(156)) 0x4000000000000000000000uwb) != 86
+ || __builtin_ctzg (((unsigned _BitInt(156)) -1) << 149, 156) != 149
+ || __builtin_ctzg ((unsigned _BitInt(156)) 2, 156) != 1
+ || __builtin_clrsbg ((_BitInt(156)) (unsigned _BitInt(156 - 4)) -1) != 3
+ || __builtin_clrsbg ((_BitInt(156)) (unsigned _BitInt(156 - 28)) -1) != 27
+ || __builtin_clrsbg ((_BitInt(156)) (unsigned _BitInt(156 - 29)) -1) != 28
+ || __builtin_clrsbg ((_BitInt(156)) ~(unsigned _BitInt(156)) (unsigned _BitInt(156 - 68)) -1) != 67
+ || __builtin_clrsbg ((_BitInt(156)) ~(unsigned _BitInt(156)) (unsigned _BitInt(156 - 92)) -1) != 91
+ || __builtin_clrsbg ((_BitInt(156)) ~(unsigned _BitInt(156)) (unsigned _BitInt(156 - 93)) -1) != 92
+ || __builtin_ffsg ((_BitInt(156)) (((unsigned _BitInt(156)) -1) << 42)) != 43
+ || __builtin_ffsg ((_BitInt(156)) (((unsigned _BitInt(156)) -1) << 57)) != 58
+ || __builtin_ffsg ((_BitInt(156)) 0x4000000000000000000000uwb) != 87
+ || __builtin_ffsg ((_BitInt(156)) (((unsigned _BitInt(156)) -1) << 149)) != 150
+ || __builtin_ffsg ((_BitInt(156)) 2) != 2)
+ __builtin_abort ();
+ if (parity156 (23008250258685373142923325827291949461178444434uwb) != __builtin_parityg (23008250258685373142923325827291949461178444434uwb)
+ || parity156 (41771568792516301628132437740665810252917251244uwb) != __builtin_parityg (41771568792516301628132437740665810252917251244uwb)
+ || parity156 (5107402473866766219120283991834936835726115452uwb) != __builtin_parityg (5107402473866766219120283991834936835726115452uwb)
+ || popcount156 (50353291748276374580944955711958129678996395562uwb) != __builtin_popcountg (50353291748276374580944955711958129678996395562uwb)
+ || popcount156 (29091263616891212550063067166307725491211684496uwb) != __builtin_popcountg (29091263616891212550063067166307725491211684496uwb)
+ || popcount156 (64973284306583205619384799873110935608793072026uwb) != __builtin_popcountg (64973284306583205619384799873110935608793072026uwb))
+ __builtin_abort ();
+#endif
+#if __BITINT_MAXWIDTH__ >= 192
+ if (clzd192 (0) != 192
+ || clzD192 (0, 42) != 42
+ || ctzd192 (0) != 192
+ || ctzD192 (0, -1) != -1
+ || clrsb192 (0) != 192 - 1
+ || ffs192 (0) != 0
+ || parity192 (0) != 0
+ || popcount192 (0) != 0
+ || __builtin_clzg ((unsigned _BitInt(192)) 0, 192 + 32) != 192 + 32
+ || __builtin_ctzg ((unsigned _BitInt(192)) 0, 192) != 192
+ || __builtin_clrsbg ((_BitInt(192)) 0) != 192 - 1
+ || __builtin_ffsg ((_BitInt(192)) 0) != 0
+ || __builtin_parityg ((unsigned _BitInt(192)) 0) != 0
+ || __builtin_popcountg ((unsigned _BitInt(192)) 0) != 0)
+ __builtin_abort ();
+ if (clz192 (-1) != 0
+ || clzd192 (-1) != 0
+ || clzD192 (-1, 15) != 0
+ || ctz192 (-1) != 0
+ || ctzd192 (-1) != 0
+ || ctzD192 (-1, -57) != 0
+ || clrsb192 (-1) != 192 - 1
+ || ffs192 (-1) != 1
+ || parity192 (-1) != 0
+ || popcount192 (-1) != 192
+ || __builtin_clzg ((unsigned _BitInt(192)) -1) != 0
+ || __builtin_clzg ((unsigned _BitInt(192)) -1, 192 + 32) != 0
+ || __builtin_ctzg ((unsigned _BitInt(192)) -1) != 0
+ || __builtin_ctzg ((unsigned _BitInt(192)) -1, 192) != 0
+ || __builtin_clrsbg ((_BitInt(192)) -1) != 192 - 1
+ || __builtin_ffsg ((_BitInt(192)) -1) != 1
+ || __builtin_parityg ((unsigned _BitInt(192)) -1) != 0
+ || __builtin_popcountg ((unsigned _BitInt(192)) -1) != 192)
+ __builtin_abort ();
+ if (clz192 (((unsigned _BitInt(192)) -1) >> 24) != 24
+ || clz192 (((unsigned _BitInt(192)) -1) >> 79) != 79
+ || clz192 (1) != 192 - 1
+ || clzd192 (((unsigned _BitInt(192)) -1) >> 139) != 139
+ || clzd192 (2) != 192 - 2
+ || ctz192 (((unsigned _BitInt(192)) -1) << 42) != 42
+ || ctz192 (((unsigned _BitInt(192)) -1) << 57) != 57
+ || ctz192 (0x4000000000000000000000uwb) != 86
+ || ctzd192 (((unsigned _BitInt(192)) -1) << 149) != 149
+ || ctzd192 (2) != 1
+ || clrsb192 ((unsigned _BitInt(192 - 4)) -1) != 3
+ || clrsb192 ((unsigned _BitInt(192 - 28)) -1) != 27
+ || clrsb192 ((unsigned _BitInt(192 - 29)) -1) != 28
+ || clrsb192 (~(unsigned _BitInt(192)) (unsigned _BitInt(192 - 68)) -1) != 67
+ || clrsb192 (~(unsigned _BitInt(192)) (unsigned _BitInt(192 - 92)) -1) != 91
+ || clrsb192 (~(unsigned _BitInt(192)) (unsigned _BitInt(192 - 93)) -1) != 92
+ || ffs192 (((unsigned _BitInt(192)) -1) << 42) != 43
+ || ffs192 (((unsigned _BitInt(192)) -1) << 57) != 58
+ || ffs192 (0x4000000000000000000000uwb) != 87
+ || ffs192 (((unsigned _BitInt(192)) -1) << 149) != 150
+ || ffs192 (2) != 2
+ || __builtin_clzg (((unsigned _BitInt(192)) -1) >> 24) != 24
+ || __builtin_clzg (((unsigned _BitInt(192)) -1) >> 79) != 79
+ || __builtin_clzg ((unsigned _BitInt(192)) 1) != 192 - 1
+ || __builtin_clzg (((unsigned _BitInt(192)) -1) >> 139, 192) != 139
+ || __builtin_clzg ((unsigned _BitInt(192)) 2, 192) != 192 - 2
+ || __builtin_ctzg (((unsigned _BitInt(192)) -1) << 42) != 42
+ || __builtin_ctzg (((unsigned _BitInt(192)) -1) << 57) != 57
+ || __builtin_ctzg ((unsigned _BitInt(192)) 0x4000000000000000000000uwb) != 86
+ || __builtin_ctzg (((unsigned _BitInt(192)) -1) << 149, 192) != 149
+ || __builtin_ctzg ((unsigned _BitInt(192)) 2, 192) != 1
+ || __builtin_clrsbg ((_BitInt(192)) (unsigned _BitInt(192 - 4)) -1) != 3
+ || __builtin_clrsbg ((_BitInt(192)) (unsigned _BitInt(192 - 28)) -1) != 27
+ || __builtin_clrsbg ((_BitInt(192)) (unsigned _BitInt(192 - 29)) -1) != 28
+ || __builtin_clrsbg ((_BitInt(192)) ~(unsigned _BitInt(192)) (unsigned _BitInt(192 - 68)) -1) != 67
+ || __builtin_clrsbg ((_BitInt(192)) ~(unsigned _BitInt(192)) (unsigned _BitInt(192 - 92)) -1) != 91
+ || __builtin_clrsbg ((_BitInt(192)) ~(unsigned _BitInt(192)) (unsigned _BitInt(192 - 93)) -1) != 92
+ || __builtin_ffsg ((_BitInt(192)) (((unsigned _BitInt(192)) -1) << 42)) != 43
+ || __builtin_ffsg ((_BitInt(192)) (((unsigned _BitInt(192)) -1) << 57)) != 58
+ || __builtin_ffsg ((_BitInt(192)) 0x4000000000000000000000uwb) != 87
+ || __builtin_ffsg ((_BitInt(192)) (((unsigned _BitInt(192)) -1) << 149)) != 150
+ || __builtin_ffsg ((_BitInt(192)) 2) != 2)
+ __builtin_abort ();
+ if (parity192 (4692147078159863499615754634965484598760535154638668598762uwb) != __builtin_parityg (4692147078159863499615754634965484598760535154638668598762uwb)
+ || parity192 (1669461228546917627909935444501097256112222796898845183538uwb) != __builtin_parityg (1669461228546917627909935444501097256112222796898845183538uwb)
+ || parity192 (5107402473866766219120283991834936835726115452uwb) != __builtin_parityg (5107402473866766219120283991834936835726115452uwb)
+ || popcount192 (4033871057575185619108386380181511734118888391160164588976uwb) != __builtin_popcountg (4033871057575185619108386380181511734118888391160164588976uwb)
+ || popcount192 (58124766715713711628758119849579188845074973856704521119uwb) != __builtin_popcountg (58124766715713711628758119849579188845074973856704521119uwb)
+ || popcount192 (289948065236269174335700831610076764076947650072787325852uwb) != __builtin_popcountg (289948065236269174335700831610076764076947650072787325852uwb))
+ __builtin_abort ();
+#endif
+}
diff --git a/gcc/testsuite/gcc.dg/torture/bitint-44.c b/gcc/testsuite/gcc.dg/torture/bitint-44.c
new file mode 100644
index 0000000..938c0e9
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/torture/bitint-44.c
@@ -0,0 +1,306 @@
+/* PR c/111309 */
+/* { dg-do run { target bitint } } */
+/* { dg-options "-std=c2x -pedantic-errors" } */
+/* { dg-skip-if "" { ! run_expensive_tests } { "*" } { "-O0" "-O2" } } */
+/* { dg-skip-if "" { ! run_expensive_tests } { "-flto" } { "" } } */
+
+#if __BITINT_MAXWIDTH__ >= 512
+__attribute__((noipa)) int
+clz512 (unsigned _BitInt(512) x)
+{
+ return __builtin_clzg (x);
+}
+
+__attribute__((noipa)) int
+clzd512 (unsigned _BitInt(512) x)
+{
+ return __builtin_clzg (x, __builtin_popcountg ((typeof (x)) ~(typeof (x)) 0));
+}
+
+__attribute__((noipa)) int
+clzD512 (unsigned _BitInt(512) x, int y)
+{
+ return __builtin_clzg (x, y);
+}
+
+__attribute__((noipa)) int
+ctz512 (unsigned _BitInt(512) x)
+{
+ return __builtin_ctzg (x);
+}
+
+__attribute__((noipa)) int
+ctzd512 (unsigned _BitInt(512) x)
+{
+ return __builtin_ctzg (x, __builtin_popcountg ((typeof (x)) ~(typeof (x)) 0));
+}
+
+__attribute__((noipa)) int
+ctzD512 (unsigned _BitInt(512) x, int y)
+{
+ return __builtin_ctzg (x, y);
+}
+
+__attribute__((noipa)) int
+clrsb512 (_BitInt(512) x)
+{
+ return __builtin_clrsbg (x);
+}
+
+__attribute__((noipa)) int
+ffs512 (_BitInt(512) x)
+{
+ return __builtin_ffsg (x);
+}
+
+__attribute__((noipa)) int
+parity512 (unsigned _BitInt(512) x)
+{
+ return __builtin_parityg (x);
+}
+
+__attribute__((noipa)) int
+popcount512 (unsigned _BitInt(512) x)
+{
+ return __builtin_popcountg (x);
+}
+#endif
+
+#if __BITINT_MAXWIDTH__ >= 523
+__attribute__((noipa)) int
+clz523 (unsigned _BitInt(523) x)
+{
+ return __builtin_clzg (x);
+}
+
+__attribute__((noipa)) int
+clzd523 (unsigned _BitInt(523) x)
+{
+ return __builtin_clzg (x, __builtin_popcountg ((typeof (x)) ~(typeof (x)) 0));
+}
+
+__attribute__((noipa)) int
+clzD523 (unsigned _BitInt(523) x, int y)
+{
+ return __builtin_clzg (x, y);
+}
+
+__attribute__((noipa)) int
+ctz523 (unsigned _BitInt(523) x)
+{
+ return __builtin_ctzg (x);
+}
+
+__attribute__((noipa)) int
+ctzd523 (unsigned _BitInt(523) x)
+{
+ return __builtin_ctzg (x, __builtin_popcountg ((typeof (x)) ~(typeof (x)) 0));
+}
+
+__attribute__((noipa)) int
+ctzD523 (unsigned _BitInt(523) x, int y)
+{
+ return __builtin_ctzg (x, y);
+}
+
+__attribute__((noipa)) int
+clrsb523 (_BitInt(523) x)
+{
+ return __builtin_clrsbg (x);
+}
+
+__attribute__((noipa)) int
+ffs523 (_BitInt(523) x)
+{
+ return __builtin_ffsg (x);
+}
+
+__attribute__((noipa)) int
+parity523 (unsigned _BitInt(523) x)
+{
+ return __builtin_parityg (x);
+}
+
+__attribute__((noipa)) int
+popcount523 (unsigned _BitInt(523) x)
+{
+ return __builtin_popcountg (x);
+}
+#endif
+
+int
+main ()
+{
+#if __BITINT_MAXWIDTH__ >= 512
+ if (clzd512 (0) != 512
+ || clzD512 (0, -1) != -1
+ || ctzd512 (0) != 512
+ || ctzD512 (0, 42) != 42
+ || clrsb512 (0) != 512 - 1
+ || ffs512 (0) != 0
+ || parity512 (0) != 0
+ || popcount512 (0) != 0
+ || __builtin_clzg ((unsigned _BitInt(512)) 0, 512 + 32) != 512 + 32
+ || __builtin_ctzg ((unsigned _BitInt(512)) 0, 512) != 512
+ || __builtin_clrsbg ((_BitInt(512)) 0) != 512 - 1
+ || __builtin_ffsg ((_BitInt(512)) 0) != 0
+ || __builtin_parityg ((unsigned _BitInt(512)) 0) != 0
+ || __builtin_popcountg ((unsigned _BitInt(512)) 0) != 0)
+ __builtin_abort ();
+ if (clz512 (-1) != 0
+ || clzd512 (-1) != 0
+ || clzD512 (-1, 0) != 0
+ || ctz512 (-1) != 0
+ || ctzd512 (-1) != 0
+ || ctzD512 (-1, 17) != 0
+ || clrsb512 (-1) != 512 - 1
+ || ffs512 (-1) != 1
+ || parity512 (-1) != 0
+ || popcount512 (-1) != 512
+ || __builtin_clzg ((unsigned _BitInt(512)) -1) != 0
+ || __builtin_clzg ((unsigned _BitInt(512)) -1, 512 + 32) != 0
+ || __builtin_ctzg ((unsigned _BitInt(512)) -1) != 0
+ || __builtin_ctzg ((unsigned _BitInt(512)) -1, 512) != 0
+ || __builtin_clrsbg ((_BitInt(512)) -1) != 512 - 1
+ || __builtin_ffsg ((_BitInt(512)) -1) != 1
+ || __builtin_parityg ((unsigned _BitInt(512)) -1) != 0
+ || __builtin_popcountg ((unsigned _BitInt(512)) -1) != 512)
+ __builtin_abort ();
+ if (clz512 (((unsigned _BitInt(512)) -1) >> 24) != 24
+ || clz512 (((unsigned _BitInt(512)) -1) >> 79) != 79
+ || clz512 (1) != 512 - 1
+ || clzd512 (((unsigned _BitInt(512)) -1) >> 139) != 139
+ || clzd512 (2) != 512 - 2
+ || ctz512 (((unsigned _BitInt(512)) -1) << 42) != 42
+ || ctz512 (((unsigned _BitInt(512)) -1) << 57) != 57
+ || ctz512 (0x4000000000000000000000uwb) != 86
+ || ctzd512 (((unsigned _BitInt(512)) -1) << 149) != 149
+ || ctzd512 (2) != 1
+ || clrsb512 ((unsigned _BitInt(512 - 4)) -1) != 3
+ || clrsb512 ((unsigned _BitInt(512 - 28)) -1) != 27
+ || clrsb512 ((unsigned _BitInt(512 - 29)) -1) != 28
+ || clrsb512 (~(unsigned _BitInt(512)) (unsigned _BitInt(512 - 68)) -1) != 67
+ || clrsb512 (~(unsigned _BitInt(512)) (unsigned _BitInt(512 - 92)) -1) != 91
+ || clrsb512 (~(unsigned _BitInt(512)) (unsigned _BitInt(512 - 93)) -1) != 92
+ || ffs512 (((unsigned _BitInt(512)) -1) << 42) != 43
+ || ffs512 (((unsigned _BitInt(512)) -1) << 57) != 58
+ || ffs512 (0x4000000000000000000000uwb) != 87
+ || ffs512 (((unsigned _BitInt(512)) -1) << 149) != 150
+ || ffs512 (2) != 2
+ || __builtin_clzg (((unsigned _BitInt(512)) -1) >> 24) != 24
+ || __builtin_clzg (((unsigned _BitInt(512)) -1) >> 79) != 79
+ || __builtin_clzg ((unsigned _BitInt(512)) 1) != 512 - 1
+ || __builtin_clzg (((unsigned _BitInt(512)) -1) >> 139, 512) != 139
+ || __builtin_clzg ((unsigned _BitInt(512)) 2, 512) != 512 - 2
+ || __builtin_ctzg (((unsigned _BitInt(512)) -1) << 42) != 42
+ || __builtin_ctzg (((unsigned _BitInt(512)) -1) << 57) != 57
+ || __builtin_ctzg ((unsigned _BitInt(512)) 0x4000000000000000000000uwb) != 86
+ || __builtin_ctzg (((unsigned _BitInt(512)) -1) << 149, 512) != 149
+ || __builtin_ctzg ((unsigned _BitInt(512)) 2, 512) != 1
+ || __builtin_clrsbg ((_BitInt(512)) (unsigned _BitInt(512 - 4)) -1) != 3
+ || __builtin_clrsbg ((_BitInt(512)) (unsigned _BitInt(512 - 28)) -1) != 27
+ || __builtin_clrsbg ((_BitInt(512)) (unsigned _BitInt(512 - 29)) -1) != 28
+ || __builtin_clrsbg ((_BitInt(512)) ~(unsigned _BitInt(512)) (unsigned _BitInt(512 - 68)) -1) != 67
+ || __builtin_clrsbg ((_BitInt(512)) ~(unsigned _BitInt(512)) (unsigned _BitInt(512 - 92)) -1) != 91
+ || __builtin_clrsbg ((_BitInt(512)) ~(unsigned _BitInt(512)) (unsigned _BitInt(512 - 93)) -1) != 92
+ || __builtin_ffsg ((_BitInt(512)) (((unsigned _BitInt(512)) -1) << 42)) != 43
+ || __builtin_ffsg ((_BitInt(512)) (((unsigned _BitInt(512)) -1) << 57)) != 58
+ || __builtin_ffsg ((_BitInt(512)) 0x4000000000000000000000uwb) != 87
+ || __builtin_ffsg ((_BitInt(512)) (((unsigned _BitInt(512)) -1) << 149)) != 150
+ || __builtin_ffsg ((_BitInt(512)) 2) != 2)
+ __builtin_abort ();
+ if (parity512 (8278593062772967967574644592392030907507244457324713380127157444008480135136016412791369421272159911061801023217823646324038055629840240503699995274750141uwb) != __builtin_parityg (8278593062772967967574644592392030907507244457324713380127157444008480135136016412791369421272159911061801023217823646324038055629840240503699995274750141uwb)
+ || parity512 (663951521760319802637316646127146913163123967584512032007606686578544864655291546789196279408181546344880831465704154822174055168766759305688225967189384uwb) != __builtin_parityg (663951521760319802637316646127146913163123967584512032007606686578544864655291546789196279408181546344880831465704154822174055168766759305688225967189384uwb)
+ || parity512 (8114152627481936575035564712656624361256533214211179387274127464949371919139038942819974113641465089580051998523156404968195970853124179018281296621919217uwb) != __builtin_parityg (8114152627481936575035564712656624361256533214211179387274127464949371919139038942819974113641465089580051998523156404968195970853124179018281296621919217uwb)
+ || popcount512 (697171368046392901434470580443928282938585745214587494987284546386421344865289735592202298494880955572094546861862007016154025065165834164941207378563932uwb) != __builtin_popcountg (697171368046392901434470580443928282938585745214587494987284546386421344865289735592202298494880955572094546861862007016154025065165834164941207378563932uwb)
+ || popcount512 (12625357869391866487124235043239209385173615631331705015179232007319637649427586947822360147798041278948617160703315666047585702906648747835331939389354450uwb) != __builtin_popcountg (12625357869391866487124235043239209385173615631331705015179232007319637649427586947822360147798041278948617160703315666047585702906648747835331939389354450uwb)
+ || popcount512 (12989863959706456104163426941303698078341934896544520782734564901708926112239778316241786242633862403309192697330635825122310265805838908726925342761646021uwb) != __builtin_popcountg (12989863959706456104163426941303698078341934896544520782734564901708926112239778316241786242633862403309192697330635825122310265805838908726925342761646021uwb))
+ __builtin_abort ();
+#endif
+#if __BITINT_MAXWIDTH__ >= 523
+ if (clzd523 (0) != 523
+ || clzD523 (0, 42) != 42
+ || ctzd523 (0) != 523
+ || ctzD523 (0, -1) != -1
+ || clrsb523 (0) != 523 - 1
+ || ffs523 (0) != 0
+ || parity523 (0) != 0
+ || popcount523 (0) != 0
+ || __builtin_clzg ((unsigned _BitInt(523)) 0, 523 + 32) != 523 + 32
+ || __builtin_ctzg ((unsigned _BitInt(523)) 0, 523) != 523
+ || __builtin_clrsbg ((_BitInt(523)) 0) != 523 - 1
+ || __builtin_ffsg ((_BitInt(523)) 0) != 0
+ || __builtin_parityg ((unsigned _BitInt(523)) 0) != 0
+ || __builtin_popcountg ((unsigned _BitInt(523)) 0) != 0)
+ __builtin_abort ();
+ if (clz523 (-1) != 0
+ || clzd523 (-1) != 0
+ || clzD523 (-1, 15) != 0
+ || ctz523 (-1) != 0
+ || ctzd523 (-1) != 0
+ || ctzD523 (-1, -57) != 0
+ || clrsb523 (-1) != 523 - 1
+ || ffs523 (-1) != 1
+ || parity523 (-1) != 1
+ || popcount523 (-1) != 523
+ || __builtin_clzg ((unsigned _BitInt(523)) -1) != 0
+ || __builtin_clzg ((unsigned _BitInt(523)) -1, 523 + 32) != 0
+ || __builtin_ctzg ((unsigned _BitInt(523)) -1) != 0
+ || __builtin_ctzg ((unsigned _BitInt(523)) -1, 523) != 0
+ || __builtin_clrsbg ((_BitInt(523)) -1) != 523 - 1
+ || __builtin_ffsg ((_BitInt(523)) -1) != 1
+ || __builtin_parityg ((unsigned _BitInt(523)) -1) != 1
+ || __builtin_popcountg ((unsigned _BitInt(523)) -1) != 523)
+ __builtin_abort ();
+ if (clz523 (((unsigned _BitInt(523)) -1) >> 24) != 24
+ || clz523 (((unsigned _BitInt(523)) -1) >> 79) != 79
+ || clz523 (1) != 523 - 1
+ || clzd523 (((unsigned _BitInt(523)) -1) >> 139) != 139
+ || clzd523 (2) != 523 - 2
+ || ctz523 (((unsigned _BitInt(523)) -1) << 42) != 42
+ || ctz523 (((unsigned _BitInt(523)) -1) << 57) != 57
+ || ctz523 (0x4000000000000000000000uwb) != 86
+ || ctzd523 (((unsigned _BitInt(523)) -1) << 149) != 149
+ || ctzd523 (2) != 1
+ || clrsb523 ((unsigned _BitInt(523 - 4)) -1) != 3
+ || clrsb523 ((unsigned _BitInt(523 - 28)) -1) != 27
+ || clrsb523 ((unsigned _BitInt(523 - 29)) -1) != 28
+ || clrsb523 (~(unsigned _BitInt(523)) (unsigned _BitInt(523 - 68)) -1) != 67
+ || clrsb523 (~(unsigned _BitInt(523)) (unsigned _BitInt(523 - 92)) -1) != 91
+ || clrsb523 (~(unsigned _BitInt(523)) (unsigned _BitInt(523 - 93)) -1) != 92
+ || ffs523 (((unsigned _BitInt(523)) -1) << 42) != 43
+ || ffs523 (((unsigned _BitInt(523)) -1) << 57) != 58
+ || ffs523 (0x4000000000000000000000uwb) != 87
+ || ffs523 (((unsigned _BitInt(523)) -1) << 149) != 150
+ || ffs523 (2) != 2
+ || __builtin_clzg (((unsigned _BitInt(523)) -1) >> 24) != 24
+ || __builtin_clzg (((unsigned _BitInt(523)) -1) >> 79) != 79
+ || __builtin_clzg ((unsigned _BitInt(523)) 1) != 523 - 1
+ || __builtin_clzg (((unsigned _BitInt(523)) -1) >> 139, 523) != 139
+ || __builtin_clzg ((unsigned _BitInt(523)) 2, 523) != 523 - 2
+ || __builtin_ctzg (((unsigned _BitInt(523)) -1) << 42) != 42
+ || __builtin_ctzg (((unsigned _BitInt(523)) -1) << 57) != 57
+ || __builtin_ctzg ((unsigned _BitInt(523)) 0x4000000000000000000000uwb) != 86
+ || __builtin_ctzg (((unsigned _BitInt(523)) -1) << 149, 523) != 149
+ || __builtin_ctzg ((unsigned _BitInt(523)) 2, 523) != 1
+ || __builtin_clrsbg ((_BitInt(523)) (unsigned _BitInt(523 - 4)) -1) != 3
+ || __builtin_clrsbg ((_BitInt(523)) (unsigned _BitInt(523 - 28)) -1) != 27
+ || __builtin_clrsbg ((_BitInt(523)) (unsigned _BitInt(523 - 29)) -1) != 28
+ || __builtin_clrsbg ((_BitInt(523)) ~(unsigned _BitInt(523)) (unsigned _BitInt(523 - 68)) -1) != 67
+ || __builtin_clrsbg ((_BitInt(523)) ~(unsigned _BitInt(523)) (unsigned _BitInt(523 - 92)) -1) != 91
+ || __builtin_clrsbg ((_BitInt(523)) ~(unsigned _BitInt(523)) (unsigned _BitInt(523 - 93)) -1) != 92
+ || __builtin_ffsg ((_BitInt(523)) (((unsigned _BitInt(523)) -1) << 42)) != 43
+ || __builtin_ffsg ((_BitInt(523)) (((unsigned _BitInt(523)) -1) << 57)) != 58
+ || __builtin_ffsg ((_BitInt(523)) 0x4000000000000000000000uwb) != 87
+ || __builtin_ffsg ((_BitInt(523)) (((unsigned _BitInt(523)) -1) << 149)) != 150
+ || __builtin_ffsg ((_BitInt(523)) 2) != 2)
+ __builtin_abort ();
+ if (parity523 (14226628251091586975416900831427560438504550751597528218770815297642064445318137709184907300499591292677456563377096100346699421879373024906380724757049700104uwb) != __builtin_parityg (14226628251091586975416900831427560438504550751597528218770815297642064445318137709184907300499591292677456563377096100346699421879373024906380724757049700104uwb)
+ || parity523 (20688958227123188226117538663818621034852702121556301239818743230005799574164516085541310491875153692467123662601853835357822935286851364843928714141587045255uwb) != __builtin_parityg (20688958227123188226117538663818621034852702121556301239818743230005799574164516085541310491875153692467123662601853835357822935286851364843928714141587045255uwb)
+ || parity523 (8927708174664018648856542263215989788443763271738485875573765922613438023117960552135374015673598803453205044464280019640319125968982118836809392169156450404uwb) != __builtin_parityg (8927708174664018648856542263215989788443763271738485875573765922613438023117960552135374015673598803453205044464280019640319125968982118836809392169156450404uwb)
+ || popcount523 (27178327344587654457581274852432957423537947348354896748701960885269035920194935311522194372418922852798513401240689173265979378157685169921449935364246334672uwb) != __builtin_popcountg (27178327344587654457581274852432957423537947348354896748701960885269035920194935311522194372418922852798513401240689173265979378157685169921449935364246334672uwb)
+ || popcount523 (5307736750284212829931201546806718535860789684371772688568780952567669490917265125893664418036905110148872995350655890585853451175740907670080602411287166989uwb) != __builtin_popcountg (5307736750284212829931201546806718535860789684371772688568780952567669490917265125893664418036905110148872995350655890585853451175740907670080602411287166989uwb)
+ || popcount523 (21261096432069432668470452941790780841888331284195411465624030283325239673941548816191698556934198698768393659379577567450765073013688585051560340496749593370uwb) != __builtin_popcountg (21261096432069432668470452941790780841888331284195411465624030283325239673941548816191698556934198698768393659379577567450765073013688585051560340496749593370uwb))
+ __builtin_abort ();
+#endif
+}
diff --git a/gcc/tree-ssa-forwprop.cc b/gcc/tree-ssa-forwprop.cc
index d4e9202..d39dfc1 100644
--- a/gcc/tree-ssa-forwprop.cc
+++ b/gcc/tree-ssa-forwprop.cc
@@ -2381,6 +2381,7 @@ simplify_count_trailing_zeroes (gimple_stmt_iterator *gsi)
HOST_WIDE_INT type_size = tree_to_shwi (TYPE_SIZE (type));
bool zero_ok
= CTZ_DEFINED_VALUE_AT_ZERO (SCALAR_INT_TYPE_MODE (type), ctz_val) == 2;
+ int nargs = 2;
/* If the input value can't be zero, don't special case ctz (0). */
if (tree_expr_nonzero_p (res_ops[0]))
@@ -2388,6 +2389,7 @@ simplify_count_trailing_zeroes (gimple_stmt_iterator *gsi)
zero_ok = true;
zero_val = 0;
ctz_val = 0;
+ nargs = 1;
}
/* Skip if there is no value defined at zero, or if we can't easily
@@ -2399,7 +2401,11 @@ simplify_count_trailing_zeroes (gimple_stmt_iterator *gsi)
gimple_seq seq = NULL;
gimple *g;
- gcall *call = gimple_build_call_internal (IFN_CTZ, 1, res_ops[0]);
+ gcall *call
+ = gimple_build_call_internal (IFN_CTZ, nargs, res_ops[0],
+ nargs == 1 ? NULL_TREE
+ : build_int_cst (integer_type_node,
+ ctz_val));
gimple_set_location (call, gimple_location (stmt));
gimple_set_lhs (call, make_ssa_name (integer_type_node));
gimple_seq_add_stmt (&seq, call);
diff --git a/gcc/tree-ssa-loop-niter.cc b/gcc/tree-ssa-loop-niter.cc
index 718582a..2098bef 100644
--- a/gcc/tree-ssa-loop-niter.cc
+++ b/gcc/tree-ssa-loop-niter.cc
@@ -2235,14 +2235,18 @@ build_cltz_expr (tree src, bool leading, bool define_at_zero)
tree call;
if (use_ifn)
{
- call = build_call_expr_internal_loc (UNKNOWN_LOCATION, ifn,
- integer_type_node, 1, src);
int val;
int optab_defined_at_zero
= (leading
? CLZ_DEFINED_VALUE_AT_ZERO (SCALAR_INT_TYPE_MODE (utype), val)
: CTZ_DEFINED_VALUE_AT_ZERO (SCALAR_INT_TYPE_MODE (utype), val));
- if (define_at_zero && !(optab_defined_at_zero == 2 && val == prec))
+ tree arg2 = NULL_TREE;
+ if (define_at_zero && optab_defined_at_zero == 2 && val == prec)
+ arg2 = build_int_cst (integer_type_node, val);
+ call = build_call_expr_internal_loc (UNKNOWN_LOCATION, ifn,
+ integer_type_node, arg2 ? 2 : 1,
+ src, arg2);
+ if (define_at_zero && arg2 == NULL_TREE)
{
tree is_zero = fold_build2 (NE_EXPR, boolean_type_node, src,
build_zero_cst (TREE_TYPE (src)));
diff --git a/gcc/tree-ssa-phiopt.cc b/gcc/tree-ssa-phiopt.cc
index bb55a4f..ac80517 100644
--- a/gcc/tree-ssa-phiopt.cc
+++ b/gcc/tree-ssa-phiopt.cc
@@ -2863,18 +2863,26 @@ cond_removal_in_builtin_zero_pattern (basic_block cond_bb,
}
/* Check that we have a popcount/clz/ctz builtin. */
- if (!is_gimple_call (call) || gimple_call_num_args (call) != 1)
+ if (!is_gimple_call (call))
return false;
- arg = gimple_call_arg (call, 0);
lhs = gimple_get_lhs (call);
if (lhs == NULL_TREE)
return false;
combined_fn cfn = gimple_call_combined_fn (call);
+ if (gimple_call_num_args (call) != 1
+ && (gimple_call_num_args (call) != 2
+ || cfn == CFN_CLZ
+ || cfn == CFN_CTZ))
+ return false;
+
+ arg = gimple_call_arg (call, 0);
+
internal_fn ifn = IFN_LAST;
int val = 0;
+ bool any_val = false;
switch (cfn)
{
case CFN_BUILT_IN_BSWAP16:
@@ -2889,6 +2897,23 @@ cond_removal_in_builtin_zero_pattern (basic_block cond_bb,
if (INTEGRAL_TYPE_P (TREE_TYPE (arg)))
{
tree type = TREE_TYPE (arg);
+ if (TREE_CODE (type) == BITINT_TYPE)
+ {
+ if (gimple_call_num_args (call) == 1)
+ {
+ any_val = true;
+ ifn = IFN_CLZ;
+ break;
+ }
+ if (!tree_fits_shwi_p (gimple_call_arg (call, 1)))
+ return false;
+ HOST_WIDE_INT at_zero = tree_to_shwi (gimple_call_arg (call, 1));
+ if ((int) at_zero != at_zero)
+ return false;
+ ifn = IFN_CLZ;
+ val = at_zero;
+ break;
+ }
if (direct_internal_fn_supported_p (IFN_CLZ, type, OPTIMIZE_FOR_BOTH)
&& CLZ_DEFINED_VALUE_AT_ZERO (SCALAR_INT_TYPE_MODE (type),
val) == 2)
@@ -2902,6 +2927,23 @@ cond_removal_in_builtin_zero_pattern (basic_block cond_bb,
if (INTEGRAL_TYPE_P (TREE_TYPE (arg)))
{
tree type = TREE_TYPE (arg);
+ if (TREE_CODE (type) == BITINT_TYPE)
+ {
+ if (gimple_call_num_args (call) == 1)
+ {
+ any_val = true;
+ ifn = IFN_CTZ;
+ break;
+ }
+ if (!tree_fits_shwi_p (gimple_call_arg (call, 1)))
+ return false;
+ HOST_WIDE_INT at_zero = tree_to_shwi (gimple_call_arg (call, 1));
+ if ((int) at_zero != at_zero)
+ return false;
+ ifn = IFN_CTZ;
+ val = at_zero;
+ break;
+ }
if (direct_internal_fn_supported_p (IFN_CTZ, type, OPTIMIZE_FOR_BOTH)
&& CTZ_DEFINED_VALUE_AT_ZERO (SCALAR_INT_TYPE_MODE (type),
val) == 2)
@@ -2960,8 +3002,18 @@ cond_removal_in_builtin_zero_pattern (basic_block cond_bb,
/* Check PHI arguments. */
if (lhs != arg0
- || TREE_CODE (arg1) != INTEGER_CST
- || wi::to_wide (arg1) != val)
+ || TREE_CODE (arg1) != INTEGER_CST)
+ return false;
+ if (any_val)
+ {
+ if (!tree_fits_shwi_p (arg1))
+ return false;
+ HOST_WIDE_INT at_zero = tree_to_shwi (arg1);
+ if ((int) at_zero != at_zero)
+ return false;
+ val = at_zero;
+ }
+ else if (wi::to_wide (arg1) != val)
return false;
/* And insert the popcount/clz/ctz builtin and cast stmt before the
@@ -2974,13 +3026,15 @@ cond_removal_in_builtin_zero_pattern (basic_block cond_bb,
reset_flow_sensitive_info (gimple_get_lhs (cast));
}
gsi_from = gsi_for_stmt (call);
- if (ifn == IFN_LAST || gimple_call_internal_p (call))
+ if (ifn == IFN_LAST
+ || (gimple_call_internal_p (call) && gimple_call_num_args (call) == 2))
gsi_move_before (&gsi_from, &gsi);
else
{
/* For __builtin_c[lt]z* force .C[LT]Z ifn, because only
the latter is well defined at zero. */
- call = gimple_build_call_internal (ifn, 1, gimple_call_arg (call, 0));
+ call = gimple_build_call_internal (ifn, 2, gimple_call_arg (call, 0),
+ build_int_cst (integer_type_node, val));
gimple_call_set_lhs (call, lhs);
gsi_insert_before (&gsi, call, GSI_SAME_STMT);
gsi_remove (&gsi_from, true);
diff --git a/gcc/tree-vect-patterns.cc b/gcc/tree-vect-patterns.cc
index 6b6b412..7debe7f 100644
--- a/gcc/tree-vect-patterns.cc
+++ b/gcc/tree-vect-patterns.cc
@@ -1818,7 +1818,7 @@ vect_recog_ctz_ffs_pattern (vec_info *vinfo, stmt_vec_info stmt_vinfo,
tree new_var;
internal_fn ifn = IFN_LAST, ifnnew = IFN_LAST;
bool defined_at_zero = true, defined_at_zero_new = false;
- int val = 0, val_new = 0;
+ int val = 0, val_new = 0, val_cmp = 0;
int prec;
int sub = 0, add = 0;
location_t loc;
@@ -1826,7 +1826,8 @@ vect_recog_ctz_ffs_pattern (vec_info *vinfo, stmt_vec_info stmt_vinfo,
if (!is_gimple_call (call_stmt))
return NULL;
- if (gimple_call_num_args (call_stmt) != 1)
+ if (gimple_call_num_args (call_stmt) != 1
+ && gimple_call_num_args (call_stmt) != 2)
return NULL;
rhs_oprnd = gimple_call_arg (call_stmt, 0);
@@ -1846,9 +1847,10 @@ vect_recog_ctz_ffs_pattern (vec_info *vinfo, stmt_vec_info stmt_vinfo,
CASE_CFN_CTZ:
ifn = IFN_CTZ;
if (!gimple_call_internal_p (call_stmt)
- || CTZ_DEFINED_VALUE_AT_ZERO (SCALAR_INT_TYPE_MODE (rhs_type),
- val) != 2)
+ || gimple_call_num_args (call_stmt) != 2)
defined_at_zero = false;
+ else
+ val = tree_to_shwi (gimple_call_arg (call_stmt, 1));
break;
CASE_CFN_FFS:
ifn = IFN_FFS;
@@ -1907,6 +1909,7 @@ vect_recog_ctz_ffs_pattern (vec_info *vinfo, stmt_vec_info stmt_vinfo,
vect_pattern_detected ("vec_recog_ctz_ffs_pattern", call_stmt);
+ val_cmp = val_new;
if ((ifnnew == IFN_CLZ
&& defined_at_zero
&& defined_at_zero_new
@@ -1918,7 +1921,7 @@ vect_recog_ctz_ffs_pattern (vec_info *vinfo, stmt_vec_info stmt_vinfo,
.CTZ (X) = .POPCOUNT ((X - 1) & ~X). */
if (ifnnew == IFN_CLZ)
sub = prec;
- val_new = prec;
+ val_cmp = prec;
if (!TYPE_UNSIGNED (rhs_type))
{
@@ -1955,7 +1958,7 @@ vect_recog_ctz_ffs_pattern (vec_info *vinfo, stmt_vec_info stmt_vinfo,
/* .CTZ (X) = (PREC - 1) - .CLZ (X & -X)
.FFS (X) = PREC - .CLZ (X & -X). */
sub = prec - (ifn == IFN_CTZ);
- val_new = sub - val_new;
+ val_cmp = sub - val_new;
tree neg = vect_recog_temp_ssa_var (rhs_type, NULL);
pattern_stmt = gimple_build_assign (neg, NEGATE_EXPR, rhs_oprnd);
@@ -1974,7 +1977,7 @@ vect_recog_ctz_ffs_pattern (vec_info *vinfo, stmt_vec_info stmt_vinfo,
/* .CTZ (X) = PREC - .POPCOUNT (X | -X)
.FFS (X) = (PREC + 1) - .POPCOUNT (X | -X). */
sub = prec + (ifn == IFN_FFS);
- val_new = sub;
+ val_cmp = sub;
tree neg = vect_recog_temp_ssa_var (rhs_type, NULL);
pattern_stmt = gimple_build_assign (neg, NEGATE_EXPR, rhs_oprnd);
@@ -1992,12 +1995,18 @@ vect_recog_ctz_ffs_pattern (vec_info *vinfo, stmt_vec_info stmt_vinfo,
{
/* .FFS (X) = .CTZ (X) + 1. */
add = 1;
- val_new++;
+ val_cmp++;
}
/* Create B = .IFNNEW (A). */
new_var = vect_recog_temp_ssa_var (lhs_type, NULL);
- pattern_stmt = gimple_build_call_internal (ifnnew, 1, rhs_oprnd);
+ if ((ifnnew == IFN_CLZ || ifnnew == IFN_CTZ) && defined_at_zero_new)
+ pattern_stmt
+ = gimple_build_call_internal (ifnnew, 2, rhs_oprnd,
+ build_int_cst (integer_type_node,
+ val_new));
+ else
+ pattern_stmt = gimple_build_call_internal (ifnnew, 1, rhs_oprnd);
gimple_call_set_lhs (pattern_stmt, new_var);
gimple_set_location (pattern_stmt, loc);
*type_out = vec_type;
@@ -2023,7 +2032,7 @@ vect_recog_ctz_ffs_pattern (vec_info *vinfo, stmt_vec_info stmt_vinfo,
}
if (defined_at_zero
- && (!defined_at_zero_new || val != val_new))
+ && (!defined_at_zero_new || val != val_cmp))
{
append_pattern_def_seq (vinfo, stmt_vinfo, pattern_stmt, vec_type);
tree ret_var = vect_recog_temp_ssa_var (lhs_type, NULL);
@@ -2143,7 +2152,8 @@ vect_recog_popcount_clz_ctz_ffs_pattern (vec_info *vinfo,
return NULL;
}
- if (gimple_call_num_args (call_stmt) != 1)
+ if (gimple_call_num_args (call_stmt) != 1
+ && gimple_call_num_args (call_stmt) != 2)
return NULL;
rhs_oprnd = gimple_call_arg (call_stmt, 0);
@@ -2181,17 +2191,14 @@ vect_recog_popcount_clz_ctz_ffs_pattern (vec_info *vinfo,
return NULL;
addend = (TYPE_PRECISION (TREE_TYPE (rhs_oprnd))
- TYPE_PRECISION (lhs_type));
- if (gimple_call_internal_p (call_stmt))
+ if (gimple_call_internal_p (call_stmt)
+ && gimple_call_num_args (call_stmt) == 2)
{
int val1, val2;
- int d1
- = CLZ_DEFINED_VALUE_AT_ZERO
- (SCALAR_INT_TYPE_MODE (TREE_TYPE (rhs_oprnd)), val1);
+ val1 = tree_to_shwi (gimple_call_arg (call_stmt, 1));
int d2
= CLZ_DEFINED_VALUE_AT_ZERO (SCALAR_INT_TYPE_MODE (lhs_type),
val2);
- if (d1 != 2)
- break;
if (d2 != 2 || val1 != val2 + addend)
return NULL;
}
@@ -2200,17 +2207,14 @@ vect_recog_popcount_clz_ctz_ffs_pattern (vec_info *vinfo,
/* ctzll (x) == ctz (x) for unsigned or signed x != 0, so ok
if it is undefined at zero or if it matches also for the
defined value there. */
- if (gimple_call_internal_p (call_stmt))
+ if (gimple_call_internal_p (call_stmt)
+ && gimple_call_num_args (call_stmt) == 2)
{
int val1, val2;
- int d1
- = CTZ_DEFINED_VALUE_AT_ZERO
- (SCALAR_INT_TYPE_MODE (TREE_TYPE (rhs_oprnd)), val1);
+ val1 = tree_to_shwi (gimple_call_arg (call_stmt, 1));
int d2
= CTZ_DEFINED_VALUE_AT_ZERO (SCALAR_INT_TYPE_MODE (lhs_type),
val2);
- if (d1 != 2)
- break;
if (d2 != 2 || val1 != val2)
return NULL;
}
@@ -2260,7 +2264,20 @@ vect_recog_popcount_clz_ctz_ffs_pattern (vec_info *vinfo,
/* Create B = .POPCOUNT (A). */
new_var = vect_recog_temp_ssa_var (lhs_type, NULL);
- pattern_stmt = gimple_build_call_internal (ifn, 1, unprom_diff.op);
+ tree arg2 = NULL_TREE;
+ int val;
+ if (ifn == IFN_CLZ
+ && CLZ_DEFINED_VALUE_AT_ZERO (SCALAR_INT_TYPE_MODE (lhs_type),
+ val) == 2)
+ arg2 = build_int_cst (integer_type_node, val);
+ else if (ifn == IFN_CTZ
+ && CTZ_DEFINED_VALUE_AT_ZERO (SCALAR_INT_TYPE_MODE (lhs_type),
+ val) == 2)
+ arg2 = build_int_cst (integer_type_node, val);
+ if (arg2)
+ pattern_stmt = gimple_build_call_internal (ifn, 2, unprom_diff.op, arg2);
+ else
+ pattern_stmt = gimple_build_call_internal (ifn, 1, unprom_diff.op);
gimple_call_set_lhs (pattern_stmt, new_var);
gimple_set_location (pattern_stmt, gimple_location (last_stmt));
*type_out = vec_type;
diff --git a/gcc/tree-vect-stmts.cc b/gcc/tree-vect-stmts.cc
index ee89f47..96e4a6cf 100644
--- a/gcc/tree-vect-stmts.cc
+++ b/gcc/tree-vect-stmts.cc
@@ -3115,6 +3115,7 @@ vectorizable_call (vec_info *vinfo,
enum { NARROW, NONE, WIDEN } modifier;
size_t i, nargs;
tree lhs;
+ tree clz_ctz_arg1 = NULL_TREE;
if (!STMT_VINFO_RELEVANT_P (stmt_info) && !bb_vinfo)
return false;
@@ -3160,6 +3161,14 @@ vectorizable_call (vec_info *vinfo,
nargs = 0;
rhs_type = unsigned_type_node;
}
+ /* Similarly pretend IFN_CLZ and IFN_CTZ only has one argument, the second
+ argument just says whether it is well-defined at zero or not and what
+ value should be returned for it. */
+ if ((cfn == CFN_CLZ || cfn == CFN_CTZ) && nargs == 2)
+ {
+ nargs = 1;
+ clz_ctz_arg1 = gimple_call_arg (stmt, 1);
+ }
int mask_opno = -1;
if (internal_fn_p (cfn))
@@ -3425,6 +3434,8 @@ vectorizable_call (vec_info *vinfo,
ifn = cond_fn;
vect_nargs += 2;
}
+ if (clz_ctz_arg1)
+ ++vect_nargs;
if (modifier == NONE || ifn != IFN_LAST)
{
@@ -3462,6 +3473,9 @@ vectorizable_call (vec_info *vinfo,
}
if (masked_loop_p && reduc_idx >= 0)
vargs[varg++] = vargs[reduc_idx + 1];
+ if (clz_ctz_arg1)
+ vargs[varg++] = clz_ctz_arg1;
+
gimple *new_stmt;
if (modifier == NARROW)
{
@@ -3548,6 +3562,8 @@ vectorizable_call (vec_info *vinfo,
}
if (masked_loop_p && reduc_idx >= 0)
vargs[varg++] = vargs[reduc_idx + 1];
+ if (clz_ctz_arg1)
+ vargs[varg++] = clz_ctz_arg1;
if (len_opno >= 0 && len_loop_p)
{