diff options
author | Thomas Koenig <tkoenig@gcc.gnu.org> | 2021-01-03 21:40:04 +0100 |
---|---|---|
committer | Thomas Koenig <tkoenig@gcc.gnu.org> | 2021-01-03 21:40:04 +0100 |
commit | afae4a55ccaa0de95ea11e5f634084db6ab2f444 (patch) | |
tree | d632cc867d10410ba9fb750523be790b86846ac4 /gcc/gimple-range.cc | |
parent | 9d9a82ec8478ff52c7a9d61f58cd2a7b6295b5f9 (diff) | |
parent | d2eb616a0f7bea78164912aa438c29fe1ef5774a (diff) | |
download | gcc-afae4a55ccaa0de95ea11e5f634084db6ab2f444.zip gcc-afae4a55ccaa0de95ea11e5f634084db6ab2f444.tar.gz gcc-afae4a55ccaa0de95ea11e5f634084db6ab2f444.tar.bz2 |
Merge branch 'master' into devel/coarray_native
Diffstat (limited to 'gcc/gimple-range.cc')
-rw-r--r-- | gcc/gimple-range.cc | 224 |
1 files changed, 135 insertions, 89 deletions
diff --git a/gcc/gimple-range.cc b/gcc/gimple-range.cc index 267ebad..4f5d502 100644 --- a/gcc/gimple-range.cc +++ b/gcc/gimple-range.cc @@ -144,7 +144,7 @@ gimple_range_adjustment (irange &res, const gimple *stmt) } // Return a range in R for the tree EXPR. Return true if a range is -// representable. +// representable, and UNDEFINED/false if not. bool get_tree_range (irange &r, tree expr) @@ -157,11 +157,16 @@ get_tree_range (irange &r, tree expr) // Return false if the type isn't suported. if (!irange::supports_type_p (type)) - return false; + { + r.set_undefined (); + return false; + } switch (TREE_CODE (expr)) { case INTEGER_CST: + if (TREE_OVERFLOW_P (expr)) + expr = drop_tree_overflow (expr); r.set (expr, expr); return true; @@ -373,7 +378,8 @@ gimple_ranger::calc_stmt (irange &r, gimple *s, tree name) res = range_of_call (r, as_a<gcall *> (s)); else if (is_a<gassign *> (s) && gimple_assign_rhs_code (s) == COND_EXPR) res = range_of_cond_expr (r, as_a<gassign *> (s)); - else + + if (!res) { // If no name is specified, try the expression kind. if (!name) @@ -384,25 +390,24 @@ gimple_ranger::calc_stmt (irange &r, gimple *s, tree name) r.set_varying (t); return true; } + if (!gimple_range_ssa_p (name)) + return false; // We don't understand the stmt, so return the global range. r = gimple_range_global (name); return true; } - if (res) + + if (r.undefined_p ()) + return true; + + // We sometimes get compatible types copied from operands, make sure + // the correct type is being returned. + if (name && TREE_TYPE (name) != r.type ()) { - if (r.undefined_p ()) - return true; - // We sometimes get compatible types copied from operands, make sure - // the correct type is being returned. - if (name && TREE_TYPE (name) != r.type ()) - { - gcc_checking_assert (range_compatible_p (r.type (), - TREE_TYPE (name))); - range_cast (r, TREE_TYPE (name)); - } - return true; + gcc_checking_assert (range_compatible_p (r.type (), TREE_TYPE (name))); + range_cast (r, TREE_TYPE (name)); } - return false; + return true; } // Calculate a range for range_op statement S and return it in R. If any @@ -412,14 +417,23 @@ bool gimple_ranger::range_of_range_op (irange &r, gimple *s) { int_range_max range1, range2; + tree lhs = gimple_get_lhs (s); tree type = gimple_expr_type (s); gcc_checking_assert (irange::supports_type_p (type)); tree op1 = gimple_range_operand1 (s); tree op2 = gimple_range_operand2 (s); - if (range_of_non_trivial_assignment (r, s)) - return true; + if (lhs) + { + // Register potential dependencies for stale value tracking. + m_cache.register_dependency (lhs, op1); + m_cache.register_dependency (lhs, op2); + } + + if (gimple_code (s) == GIMPLE_ASSIGN + && gimple_assign_rhs_code (s) == ADDR_EXPR) + return range_of_address (r, s); if (range_of_expr (range1, op1, s)) { @@ -433,48 +447,84 @@ gimple_ranger::range_of_range_op (irange &r, gimple *s) return true; } -// Calculate the range of a non-trivial assignment. That is, is one -// inolving arithmetic on an SSA name (for example, an ADDR_EXPR). +// Calculate the range of an assignment containing an ADDR_EXPR. // Return the range in R. -// -// If a range cannot be calculated, return false. +// If a range cannot be calculated, set it to VARYING and return true. bool -gimple_ranger::range_of_non_trivial_assignment (irange &r, gimple *stmt) +gimple_ranger::range_of_address (irange &r, gimple *stmt) { - if (gimple_code (stmt) != GIMPLE_ASSIGN) - return false; + gcc_checking_assert (gimple_code (stmt) == GIMPLE_ASSIGN); + gcc_checking_assert (gimple_assign_rhs_code (stmt) == ADDR_EXPR); - tree base = gimple_range_base_of_assignment (stmt); - if (base) + bool strict_overflow_p; + tree expr = gimple_assign_rhs1 (stmt); + poly_int64 bitsize, bitpos; + tree offset; + machine_mode mode; + int unsignedp, reversep, volatilep; + tree base = get_inner_reference (TREE_OPERAND (expr, 0), &bitsize, + &bitpos, &offset, &mode, &unsignedp, + &reversep, &volatilep); + + + if (base != NULL_TREE + && TREE_CODE (base) == MEM_REF + && TREE_CODE (TREE_OPERAND (base, 0)) == SSA_NAME) { - if (TREE_CODE (base) == MEM_REF) + tree ssa = TREE_OPERAND (base, 0); + gcc_checking_assert (irange::supports_type_p (TREE_TYPE (ssa))); + range_of_expr (r, ssa, stmt); + range_cast (r, TREE_TYPE (gimple_assign_rhs1 (stmt))); + + poly_offset_int off = 0; + bool off_cst = false; + if (offset == NULL_TREE || TREE_CODE (offset) == INTEGER_CST) { - if (TREE_CODE (TREE_OPERAND (base, 0)) == SSA_NAME) - { - int_range_max range1; - tree ssa = TREE_OPERAND (base, 0); - if (range_of_expr (range1, ssa, stmt)) - { - tree type = TREE_TYPE (ssa); - range_operator *op = range_op_handler (POINTER_PLUS_EXPR, - type); - int_range<2> offset (TREE_OPERAND (base, 1), - TREE_OPERAND (base, 1)); - op->fold_range (r, type, range1, offset); - return true; - } - } - return false; + off = mem_ref_offset (base); + if (offset) + off += poly_offset_int::from (wi::to_poly_wide (offset), + SIGNED); + off <<= LOG2_BITS_PER_UNIT; + off += bitpos; + off_cst = true; } - if (gimple_assign_rhs_code (stmt) == ADDR_EXPR) + /* If &X->a is equal to X, the range of X is the result. */ + if (off_cst && known_eq (off, 0)) + return true; + else if (flag_delete_null_pointer_checks + && !TYPE_OVERFLOW_WRAPS (TREE_TYPE (expr))) + { + /* For -fdelete-null-pointer-checks -fno-wrapv-pointer we don't + allow going from non-NULL pointer to NULL. */ + if(!range_includes_zero_p (&r)) + return true; + } + /* If MEM_REF has a "positive" offset, consider it non-NULL + always, for -fdelete-null-pointer-checks also "negative" + ones. Punt for unknown offsets (e.g. variable ones). */ + if (!TYPE_OVERFLOW_WRAPS (TREE_TYPE (expr)) + && off_cst + && known_ne (off, 0) + && (flag_delete_null_pointer_checks || known_gt (off, 0))) { - // Handle "= &a" and return non-zero. r = range_nonzero (TREE_TYPE (gimple_assign_rhs1 (stmt))); return true; } + r = int_range<2> (TREE_TYPE (gimple_assign_rhs1 (stmt))); + return true; } - return false; + + // Handle "= &a". + if (tree_single_nonzero_warnv_p (expr, &strict_overflow_p)) + { + r = range_nonzero (TREE_TYPE (gimple_assign_rhs1 (stmt))); + return true; + } + + // Otherwise return varying. + r = int_range<2> (TREE_TYPE (gimple_assign_rhs1 (stmt))); + return true; } // Calculate a range for phi statement S and return it in R. @@ -498,6 +548,9 @@ gimple_ranger::range_of_phi (irange &r, gphi *phi) tree arg = gimple_phi_arg_def (phi, x); edge e = gimple_phi_arg_edge (phi, x); + // Register potential dependencies for stale value tracking. + m_cache.register_dependency (phi_def, arg); + range_on_edge (arg_range, e, arg); r.union_ (arg_range); // Once the value reaches varying, stop looking. @@ -582,8 +635,8 @@ range_of_builtin_ubsan_call (range_query &query, irange &r, gcall *call, int_range_max ir0, ir1; tree arg0 = gimple_call_arg (call, 0); tree arg1 = gimple_call_arg (call, 1); - gcc_assert (query.range_of_expr (ir0, arg0, call)); - gcc_assert (query.range_of_expr (ir1, arg1, call)); + query.range_of_expr (ir0, arg0, call); + query.range_of_expr (ir1, arg1, call); bool saved_flag_wrapv = flag_wrapv; // Pretend the arithmetic is wrapping. If there is any overflow, @@ -611,7 +664,7 @@ range_of_builtin_call (range_query &query, irange &r, gcall *call) tree type = gimple_call_return_type (call); tree arg; - int mini, maxi, zerov, prec; + int mini, maxi, zerov = 0, prec; scalar_int_mode mode; switch (func) @@ -638,7 +691,7 @@ range_of_builtin_call (range_query &query, irange &r, gcall *call) prec = TYPE_PRECISION (TREE_TYPE (arg)); mini = 0; maxi = prec; - gcc_assert (query.range_of_expr (r, arg, call)); + query.range_of_expr (r, arg, call); // If arg is non-zero, then ffs or popcount are non-zero. if (!range_includes_zero_p (&r)) mini = 1; @@ -682,7 +735,7 @@ range_of_builtin_call (range_query &query, irange &r, gcall *call) } } - gcc_assert (query.range_of_expr (r, arg, call)); + query.range_of_expr (r, arg, call); // From clz of minimum we can compute result maximum. if (r.constant_p ()) { @@ -747,7 +800,7 @@ range_of_builtin_call (range_query &query, irange &r, gcall *call) mini = -2; } } - gcc_assert (query.range_of_expr (r, arg, call)); + query.range_of_expr (r, arg, call); if (!r.undefined_p ()) { if (r.lower_bound () != 0) @@ -864,9 +917,9 @@ gimple_ranger::range_of_cond_expr (irange &r, gassign *s) if (!irange::supports_type_p (TREE_TYPE (op1))) return false; - gcc_assert (range_of_expr (cond_range, cond, s)); - gcc_assert (range_of_expr (range1, op1, s)); - gcc_assert (range_of_expr (range2, op2, s)); + range_of_expr (cond_range, cond, s); + range_of_expr (range1, op1, s); + range_of_expr (range2, op2, s); // If the condition is known, choose the appropriate expression. if (cond_range.singleton_p ()) @@ -894,7 +947,7 @@ gimple_ranger::range_of_expr (irange &r, tree expr, gimple *stmt) // If there is no statement, just get the global value. if (!stmt) { - if (!m_cache.m_globals.get_global_range (r, expr)) + if (!m_cache.get_global_range (r, expr)) r = gimple_range_global (expr); return true; } @@ -904,7 +957,7 @@ gimple_ranger::range_of_expr (irange &r, tree expr, gimple *stmt) // If name is defined in this block, try to get an range from S. if (def_stmt && gimple_bb (def_stmt) == bb) - gcc_assert (range_of_stmt (r, def_stmt, expr)); + range_of_stmt (r, def_stmt, expr); else // Otherwise OP comes from outside this block, use range on entry. range_on_entry (r, bb, expr); @@ -933,7 +986,7 @@ gimple_ranger::range_on_entry (irange &r, basic_block bb, tree name) gcc_checking_assert (gimple_range_ssa_p (name)); // Start with any known range - gcc_assert (range_of_stmt (r, SSA_NAME_DEF_STMT (name), name)); + range_of_stmt (r, SSA_NAME_DEF_STMT (name), name); // Now see if there is any on_entry value which may refine it. if (m_cache.block_range (entry_range, bb, name)) @@ -948,6 +1001,7 @@ gimple_ranger::range_on_exit (irange &r, basic_block bb, tree name) { // on-exit from the exit block? gcc_checking_assert (bb != EXIT_BLOCK_PTR_FOR_FN (cfun)); + gcc_checking_assert (gimple_range_ssa_p (name)); gimple *s = last_stmt (bb); // If there is no statement in the block and this isn't the entry @@ -956,7 +1010,7 @@ gimple_ranger::range_on_exit (irange &r, basic_block bb, tree name) if (!s && bb != ENTRY_BLOCK_PTR_FOR_FN (cfun)) range_on_entry (r, bb, name); else - gcc_assert (range_of_expr (r, name, s)); + range_of_expr (r, name, s); gcc_checking_assert (r.undefined_p () || range_compatible_p (r.type (), TREE_TYPE (name))); } @@ -971,10 +1025,7 @@ gimple_ranger::range_on_edge (irange &r, edge e, tree name) // PHI arguments can be constants, catch these here. if (!gimple_range_ssa_p (name)) - { - gcc_assert (range_of_expr (r, name)); - return true; - } + return range_of_expr (r, name); range_on_exit (r, e->src, name); gcc_checking_assert (r.undefined_p () @@ -991,33 +1042,36 @@ gimple_ranger::range_on_edge (irange &r, edge e, tree name) // provided it represents the SSA_NAME on the LHS of the statement. // It is only required if there is more than one lhs/output. Check // the global cache for NAME first to see if the evaluation can be -// avoided. If a range cannot be calculated, return false. +// avoided. If a range cannot be calculated, return false and UNDEFINED. bool gimple_ranger::range_of_stmt (irange &r, gimple *s, tree name) { - // If no name, simply call the base routine. + r.set_undefined (); + if (!name) name = gimple_get_lhs (s); + // If no name, simply call the base routine. if (!name) return calc_stmt (r, s, NULL_TREE); - gcc_checking_assert (TREE_CODE (name) == SSA_NAME && - irange::supports_type_p (TREE_TYPE (name))); + if (!gimple_range_ssa_p (name)) + return false; - // If this STMT has already been processed, return that value. - if (m_cache.m_globals.get_global_range (r, name)) + // Check if the stmt has already been processed, and is not stale. + if (m_cache.get_non_stale_global_range (r, name)) return true; - // Avoid infinite recursion by initializing global cache - int_range_max tmp = gimple_range_global (name); - m_cache.m_globals.set_global_range (name, tmp); - gcc_assert (calc_stmt (r, s, name)); + // Otherwise calculate a new value. + int_range_max tmp; + calc_stmt (tmp, s, name); - if (is_a<gphi *> (s)) - r.intersect (tmp); - m_cache.m_globals.set_global_range (name, r); + // Combine the new value with the old value. This is required because + // the way value propagation works, when the IL changes on the fly we + // can sometimes get different results. See PR 97741. + r.intersect (tmp); + m_cache.set_global_range (name, r); return true; } @@ -1040,7 +1094,7 @@ gimple_ranger::export_global_ranges () tree name = ssa_name (x); if (name && !SSA_NAME_IN_FREE_LIST (name) && gimple_range_ssa_p (name) - && m_cache.m_globals.get_global_range (r, name) + && m_cache.get_global_range (r, name) && !r.varying_p()) { // Make sure the new range is a subset of the old range. @@ -1084,7 +1138,7 @@ gimple_ranger::dump (FILE *f) edge e; int_range_max range; fprintf (f, "\n=========== BB %d ============\n", bb->index); - m_cache.m_on_entry.dump (f, bb); + m_cache.dump (f, bb); dump_bb (f, bb, 4, TDF_NONE); @@ -1094,7 +1148,7 @@ gimple_ranger::dump (FILE *f) tree name = ssa_name (x); if (gimple_range_ssa_p (name) && SSA_NAME_DEF_STMT (name) && gimple_bb (SSA_NAME_DEF_STMT (name)) == bb && - m_cache.m_globals.get_global_range (range, name)) + m_cache.get_global_range (range, name)) { if (!range.varying_p ()) { @@ -1146,15 +1200,7 @@ gimple_ranger::dump (FILE *f) } } - m_cache.m_globals.dump (dump_file); - fprintf (f, "\n"); - - if (dump_flags & TDF_DETAILS) - { - fprintf (f, "\nDUMPING GORI MAP\n"); - m_cache.dump (f); - fprintf (f, "\n"); - } + m_cache.dump (dump_file, (dump_flags & TDF_DETAILS) != 0); } // If SCEV has any information about phi node NAME, return it as a range in R. |