diff --git a/gcc/testsuite/g++.dg/pr93674.C b/gcc/testsuite/g++.dg/pr93674.C new file mode 100644 index 0000000..8c59f1b --- /dev/null +++ b/gcc/testsuite/g++.dg/pr93674.C @@ -0,0 +1,16 @@ +// { dg-do compile } +// { dg-options "-O3 -std=c++14 -fstrict-enums -pedantic -fdump-tree-optimized" } +enum some_enum { x = 1000 }; +void sink(some_enum); + +int __attribute__((noinline)) func() { + int sum = 0; + for (int i = 0; i < 3; ++i) { + for (int j = 3; j >= 0; --j) { + sink((some_enum)(i + j)); + } + } + return sum; +} + +// { dg-final { scan-tree-dump-not "some_enum ivtmp" "optimized" } } diff --git a/gcc/tree-ssa-loop-ivopts.c b/gcc/tree-ssa-loop-ivopts.c index 1ce6d8b..fc48035 100644 --- a/gcc/tree-ssa-loop-ivopts.c +++ b/gcc/tree-ssa-loop-ivopts.c @@ -3479,8 +3479,27 @@ add_iv_candidate_for_use (struct ivopts_data *data, struct iv_use *use) { poly_uint64 offset; tree base; - tree basetype; struct iv *iv = use->iv; + tree basetype = TREE_TYPE (iv->base); + + if (TREE_CODE (basetype) == ENUMERAL_TYPE && flag_strict_enums + && CONVERT_EXPR_P (iv->base)) + { + /* In case of -fstrict-enums, if it's enumeral type use converted from + other iv, only add candidate for the source iv. */ + base = TREE_OPERAND (iv->base, 0); + basetype = TREE_TYPE (base); + if (!INTEGRAL_TYPE_P (basetype)) + return; + + tree step = iv->step; + + if (basetype == generic_type_for (basetype)) + step = fold_convert (basetype, step); + + add_candidate (data, base, step, false, NULL); + return; + } add_candidate (data, iv->base, iv->step, false, use); @@ -3488,7 +3507,6 @@ add_iv_candidate_for_use (struct ivopts_data *data, struct iv_use *use) record_common_cand (data, iv->base, iv->step, use); /* Record common candidate with initial value zero. */ - basetype = TREE_TYPE (iv->base); if (POINTER_TYPE_P (basetype)) basetype = sizetype; record_common_cand (data, build_int_cst (basetype, 0), iv->step, use); @@ -4834,6 +4852,21 @@ get_computation_cost (struct ivopts_data *data, struct iv_use *use, /* Check if we have enough precision to express the values of use. */ if (TYPE_PRECISION (utype) > TYPE_PRECISION (ctype)) return infinite_cost; + /* Check if cand can represent values of use for strict enums. */ + else if (TREE_CODE (ctype) == ENUMERAL_TYPE && flag_strict_enums) + { + if (TYPE_UNSIGNED (ctype) && !TYPE_UNSIGNED (utype)) + return infinite_cost; + + tree cmin = TYPE_MIN_VALUE (ctype), cmax = TYPE_MAX_VALUE (ctype); + if ((!TYPE_UNSIGNED (ctype) && TYPE_UNSIGNED (utype)) + && (tree_int_cst_lt (integer_zero_node, cmin) + || tree_int_cst_lt (cmax, TYPE_MAX_VALUE (utype)))) + return infinite_cost; + else if (tree_int_cst_lt (TYPE_MIN_VALUE (utype), cmin) + || tree_int_cst_lt (cmax, TYPE_MAX_VALUE (utype))) + return infinite_cost; + } if (address_p || (use->iv->base_object @@ -5312,6 +5345,13 @@ may_eliminate_iv (struct ivopts_data *data, if (TREE_CODE (cand->iv->step) != INTEGER_CST) return false; + tree ctype = TREE_TYPE (cand->iv->base); + /* Don't eliminate with enumeral type cand in case of -fstrict-enums. */ + if (flag_strict_enums + && TREE_CODE (ctype) == ENUMERAL_TYPE + && ctype != TREE_TYPE (use->iv->base)) + return false; + /* For now works only for exits that dominate the loop latch. TODO: extend to other conditions inside loop body. */ ex_bb = gimple_bb (use->stmt);