Mercurial > hg > CbC > CbC_gcc
diff gcc/tree-ssa-loop-niter.c @ 132:d34655255c78
update gcc-8.2
author | mir3636 |
---|---|
date | Thu, 25 Oct 2018 10:21:07 +0900 |
parents | 84e7813d76e9 |
children | 1830386684a0 |
line wrap: on
line diff
--- a/gcc/tree-ssa-loop-niter.c Thu Oct 25 08:08:40 2018 +0900 +++ b/gcc/tree-ssa-loop-niter.c Thu Oct 25 10:21:07 2018 +0900 @@ -1,5 +1,5 @@ /* Functions to determine/estimate number of iterations of a loop. - Copyright (C) 2004-2017 Free Software Foundation, Inc. + Copyright (C) 2004-2018 Free Software Foundation, Inc. This file is part of GCC. @@ -63,6 +63,10 @@ mpz_t below, up; }; +static bool number_of_iterations_popcount (loop_p loop, edge exit, + enum tree_code code, + struct tree_niter_desc *niter); + /* Splits expression EXPR to a variable part VAR and constant OFFSET. */ @@ -349,7 +353,7 @@ mpz_t minm, maxm; basic_block bb; wide_int minv, maxv; - enum value_range_type rtype = VR_VARYING; + enum value_range_kind rtype = VR_VARYING; /* If the expression is a constant, we know its value exactly. */ if (integer_zerop (var)) @@ -1987,7 +1991,7 @@ return expand_simple_operations (e, stop); else if (code == ADDR_EXPR) { - HOST_WIDE_INT offset; + poly_int64 offset; tree base = get_addr_base_and_unit_offset (TREE_OPERAND (e, 0), &offset); if (base @@ -2356,11 +2360,11 @@ tree iv0_niters = NULL_TREE; if (!simple_iv_with_niters (loop, loop_containing_stmt (stmt), - op0, &iv0, &iv0_niters, false)) - return false; + op0, &iv0, safe ? &iv0_niters : NULL, false)) + return number_of_iterations_popcount (loop, exit, code, niter); tree iv1_niters = NULL_TREE; if (!simple_iv_with_niters (loop, loop_containing_stmt (stmt), - op1, &iv1, &iv1_niters, false)) + op1, &iv1, safe ? &iv1_niters : NULL, false)) return false; /* Give up on complicated case. */ if (iv0_niters && iv1_niters) @@ -2430,6 +2434,188 @@ return (!integer_zerop (niter->assumptions)); } + +/* Utility function to check if OP is defined by a stmt + that is a val - 1. */ + +static bool +ssa_defined_by_minus_one_stmt_p (tree op, tree val) +{ + gimple *stmt; + return (TREE_CODE (op) == SSA_NAME + && (stmt = SSA_NAME_DEF_STMT (op)) + && is_gimple_assign (stmt) + && (gimple_assign_rhs_code (stmt) == PLUS_EXPR) + && val == gimple_assign_rhs1 (stmt) + && integer_minus_onep (gimple_assign_rhs2 (stmt))); +} + + +/* See if LOOP is a popcout implementation, determine NITER for the loop + + We match: + <bb 2> + goto <bb 4> + + <bb 3> + _1 = b_11 + -1 + b_6 = _1 & b_11 + + <bb 4> + b_11 = PHI <b_5(D)(2), b_6(3)> + + exit block + if (b_11 != 0) + goto <bb 3> + else + goto <bb 5> + + OR we match copy-header version: + if (b_5 != 0) + goto <bb 3> + else + goto <bb 4> + + <bb 3> + b_11 = PHI <b_5(2), b_6(3)> + _1 = b_11 + -1 + b_6 = _1 & b_11 + + exit block + if (b_6 != 0) + goto <bb 3> + else + goto <bb 4> + + If popcount pattern, update NITER accordingly. + i.e., set NITER to __builtin_popcount (b) + return true if we did, false otherwise. + + */ + +static bool +number_of_iterations_popcount (loop_p loop, edge exit, + enum tree_code code, + struct tree_niter_desc *niter) +{ + bool adjust = true; + tree iter; + HOST_WIDE_INT max; + adjust = true; + tree fn = NULL_TREE; + + /* Check loop terminating branch is like + if (b != 0). */ + gimple *stmt = last_stmt (exit->src); + if (!stmt + || gimple_code (stmt) != GIMPLE_COND + || code != NE_EXPR + || !integer_zerop (gimple_cond_rhs (stmt)) + || TREE_CODE (gimple_cond_lhs (stmt)) != SSA_NAME) + return false; + + gimple *and_stmt = SSA_NAME_DEF_STMT (gimple_cond_lhs (stmt)); + + /* Depending on copy-header is performed, feeding PHI stmts might be in + the loop header or loop latch, handle this. */ + if (gimple_code (and_stmt) == GIMPLE_PHI + && gimple_bb (and_stmt) == loop->header + && gimple_phi_num_args (and_stmt) == 2 + && (TREE_CODE (gimple_phi_arg_def (and_stmt, + loop_latch_edge (loop)->dest_idx)) + == SSA_NAME)) + { + /* SSA used in exit condition is defined by PHI stmt + b_11 = PHI <b_5(D)(2), b_6(3)> + from the PHI stmt, get the and_stmt + b_6 = _1 & b_11. */ + tree t = gimple_phi_arg_def (and_stmt, loop_latch_edge (loop)->dest_idx); + and_stmt = SSA_NAME_DEF_STMT (t); + adjust = false; + } + + /* Make sure it is indeed an and stmt (b_6 = _1 & b_11). */ + if (!is_gimple_assign (and_stmt) + || gimple_assign_rhs_code (and_stmt) != BIT_AND_EXPR) + return false; + + tree b_11 = gimple_assign_rhs1 (and_stmt); + tree _1 = gimple_assign_rhs2 (and_stmt); + + /* Check that _1 is defined by _b11 + -1 (_1 = b_11 + -1). + Also make sure that b_11 is the same in and_stmt and _1 defining stmt. + Also canonicalize if _1 and _b11 are revrsed. */ + if (ssa_defined_by_minus_one_stmt_p (b_11, _1)) + std::swap (b_11, _1); + else if (ssa_defined_by_minus_one_stmt_p (_1, b_11)) + ; + else + return false; + /* Check the recurrence: + ... = PHI <b_5(2), b_6(3)>. */ + gimple *phi = SSA_NAME_DEF_STMT (b_11); + if (gimple_code (phi) != GIMPLE_PHI + || (gimple_bb (phi) != loop_latch_edge (loop)->dest) + || (gimple_assign_lhs (and_stmt) + != gimple_phi_arg_def (phi, loop_latch_edge (loop)->dest_idx))) + return false; + + /* We found a match. Get the corresponding popcount builtin. */ + tree src = gimple_phi_arg_def (phi, loop_preheader_edge (loop)->dest_idx); + if (TYPE_PRECISION (TREE_TYPE (src)) == TYPE_PRECISION (integer_type_node)) + fn = builtin_decl_implicit (BUILT_IN_POPCOUNT); + else if (TYPE_PRECISION (TREE_TYPE (src)) == TYPE_PRECISION + (long_integer_type_node)) + fn = builtin_decl_implicit (BUILT_IN_POPCOUNTL); + else if (TYPE_PRECISION (TREE_TYPE (src)) == TYPE_PRECISION + (long_long_integer_type_node)) + fn = builtin_decl_implicit (BUILT_IN_POPCOUNTLL); + + /* ??? Support promoting char/short to int. */ + if (!fn) + return false; + + /* Update NITER params accordingly */ + tree utype = unsigned_type_for (TREE_TYPE (src)); + src = fold_convert (utype, src); + tree call = fold_convert (utype, build_call_expr (fn, 1, src)); + if (adjust) + iter = fold_build2 (MINUS_EXPR, utype, + call, + build_int_cst (utype, 1)); + else + iter = call; + + if (TREE_CODE (call) == INTEGER_CST) + max = tree_to_uhwi (call); + else + { + max = TYPE_PRECISION (TREE_TYPE (src)); + if (adjust) + max = max - 1; + } + + niter->niter = iter; + niter->assumptions = boolean_true_node; + + if (adjust) + { + tree may_be_zero = fold_build2 (EQ_EXPR, boolean_type_node, src, + build_zero_cst + (TREE_TYPE (src))); + niter->may_be_zero = + simplify_using_initial_conditions (loop, may_be_zero); + } + else + niter->may_be_zero = boolean_false_node; + + niter->max = max; + niter->bound = NULL_TREE; + niter->cmp = ERROR_MARK; + return true; +} + + /* Like number_of_iterations_exit_assumptions, but return TRUE only if the niter information holds unconditionally. */ @@ -2447,7 +2633,7 @@ return true; if (warn) - dump_printf_loc (MSG_MISSED_OPTIMIZATION, gimple_location_safe (stmt), + dump_printf_loc (MSG_MISSED_OPTIMIZATION, stmt, "missed loop optimization: niters analysis ends up " "with assumptions.\n"); @@ -3045,6 +3231,7 @@ char buf[WIDE_INT_PRINT_BUFFER_SIZE]; print_dec (i_bound, buf, TYPE_UNSIGNED (TREE_TYPE (loop->nb_iterations)) ? UNSIGNED : SIGNED); + auto_diagnostic_group d; if (warning_at (gimple_location (stmt), OPT_Waggressive_loop_optimizations, "iteration %s invokes undefined behavior", buf)) inform (gimple_location (estmt), "within this loop"); @@ -3510,6 +3697,12 @@ low = lower_bound_in_type (type, type); high = upper_bound_in_type (type, type); + wide_int minv, maxv; + if (get_range_info (def, &minv, &maxv) == VR_RANGE) + { + low = wide_int_to_tree (type, minv); + high = wide_int_to_tree (type, maxv); + } record_nonwrapping_iv (loop, base, step, stmt, low, high, false, true); } @@ -3901,7 +4094,7 @@ recomputing iteration bounds later in the compilation process will just introduce random roundoff errors. */ if (!loop->any_estimate - && loop->header->count > 0) + && loop->header->count.reliable_p ()) { gcov_type nit = expected_loop_iterations_unbounded (loop); bound = gcov_type_to_wide_int (nit); @@ -4480,7 +4673,7 @@ { tree type; wide_int minv, maxv, diff, step_wi; - enum value_range_type rtype; + enum value_range_kind rtype; if (TREE_CODE (step) != INTEGER_CST || !INTEGRAL_TYPE_P (TREE_TYPE (var))) return false;