From: Andrew MacLeod Date: Thu, 12 Nov 2020 16:53:52 +0000 (-0500) Subject: Cleanup range of address calculations. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=47923622c663ffad8b14aa93706183290d4f6791;p=gcc.git Cleanup range of address calculations. Align EVRP and ranger for how ranges of ADDR_EXPR are calculated. gcc/ * gimple-range.cc: (gimple_ranger::range_of_range_op): Check for ADDR_EXPR and call range_of_address. (gimple_ranger::range_of_address): Rename from range_of_non_trivial_assignment and match vrp_stmt_computes_nonzero. * gimple-range.h: (range_of_address): Renamed. * range-op.cc: (pointer_table): Add INTEGER_CST handler. gcc/testsuite/ * gcc.dg/tree-ssa/pr78655.c: New. --- diff --git a/gcc/gimple-range.cc b/gcc/gimple-range.cc index 92a6335bec5..4f5d5024fa9 100644 --- a/gcc/gimple-range.cc +++ b/gcc/gimple-range.cc @@ -431,8 +431,9 @@ gimple_ranger::range_of_range_op (irange &r, gimple *s) m_cache.register_dependency (lhs, op2); } - if (range_of_non_trivial_assignment (r, s)) - return true; + 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)) { @@ -446,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. diff --git a/gcc/gimple-range.h b/gcc/gimple-range.h index 88d2ada324b..dde41e9e743 100644 --- a/gcc/gimple-range.h +++ b/gcc/gimple-range.h @@ -62,7 +62,7 @@ protected: ranger_cache m_cache; private: bool range_of_phi (irange &r, gphi *phi); - bool range_of_non_trivial_assignment (irange &r, gimple *s); + bool range_of_address (irange &r, gimple *s); bool range_of_builtin_call (irange &r, gcall *call); bool range_with_loop_info (irange &r, tree name); void range_of_ssa_name_with_loop_info (irange &, tree, class loop *, diff --git a/gcc/range-op.cc b/gcc/range-op.cc index 86d1af7fe54..b746aadb603 100644 --- a/gcc/range-op.cc +++ b/gcc/range-op.cc @@ -3328,6 +3328,7 @@ pointer_table::pointer_table () set (GT_EXPR, op_gt); set (GE_EXPR, op_ge); set (SSA_NAME, op_identity); + set (INTEGER_CST, op_integer_cst); set (ADDR_EXPR, op_addr); set (NOP_EXPR, op_convert); set (CONVERT_EXPR, op_convert); diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr78655.c b/gcc/testsuite/gcc.dg/tree-ssa/pr78655.c new file mode 100644 index 00000000000..e9158e07268 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr78655.c @@ -0,0 +1,37 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fno-tree-ccp -fno-tree-forwprop -fno-tree-fre -fdump-tree-evrp" } */ + +struct A{int a,b;}; +inline int*f1(struct A*p){return&p->a;} /* offset of 0. */ +inline int*f2(struct A*p){return&p->b;} /* Offset of non-zero. */ +inline int*g(struct A*p){return(int*)p+1;} /* Always non-zero offet. */ + +/* Should be able to eliminate all calls to bad(). */ + +void bad(void); + +int +main() +{ + struct A* ptr = 0; + struct A addr; + + if (f1 (ptr) != 0) + bad(); + if (f1 (&addr) == 0) + bad(); + + if (f2 (ptr) == 0) + bad(); + if (f2 (&addr) == 0) + bad(); + + if (g (ptr) == 0) + bad(); + if (g (&addr) == 0) + bad(); + +} + +/* { dg-final { scan-tree-dump-not "bad" "evrp"} } */ +