diff options
author | Giuliano Belinassi <giuliano.belinassi@usp.br> | 2020-08-22 17:43:43 -0300 |
---|---|---|
committer | Giuliano Belinassi <giuliano.belinassi@usp.br> | 2020-08-22 17:43:43 -0300 |
commit | a926878ddbd5a98b272c22171ce58663fc04c3e0 (patch) | |
tree | 86af256e5d9a9c06263c00adc90e5fe348008c43 /gcc/tree-ssa-phiopt.c | |
parent | 542730f087133690b47e036dfd43eb0db8a650ce (diff) | |
parent | 07cbaed8ba7d1b6e4ab3a9f44175502a4e1ecdb1 (diff) | |
download | gcc-devel/autopar_devel.zip gcc-devel/autopar_devel.tar.gz gcc-devel/autopar_devel.tar.bz2 |
Merge branch 'autopar_rebase2' into autopar_develdevel/autopar_devel
Quickly commit changes in the rebase branch.
Diffstat (limited to 'gcc/tree-ssa-phiopt.c')
-rw-r--r-- | gcc/tree-ssa-phiopt.c | 215 |
1 files changed, 135 insertions, 80 deletions
diff --git a/gcc/tree-ssa-phiopt.c b/gcc/tree-ssa-phiopt.c index b1e0dce..b97f863 100644 --- a/gcc/tree-ssa-phiopt.c +++ b/gcc/tree-ssa-phiopt.c @@ -46,6 +46,7 @@ along with GCC; see the file COPYING3. If not see #include "tree-inline.h" #include "case-cfn-macros.h" #include "tree-eh.h" +#include "gimple-fold.h" static unsigned int tree_ssa_phiopt_worker (bool, bool, bool); static bool two_value_replacement (basic_block, basic_block, edge, gphi *, @@ -1362,23 +1363,21 @@ minmax_replacement (basic_block cond_bb, basic_block middle_bb, edge e0, edge e1, gimple *phi, tree arg0, tree arg1) { - tree result, type, rhs; - gcond *cond; - gassign *new_stmt; + tree result; edge true_edge, false_edge; - enum tree_code cmp, minmax, ass_code; - tree smaller, alt_smaller, larger, alt_larger, arg_true, arg_false; + enum tree_code minmax, ass_code; + tree smaller, larger, arg_true, arg_false; gimple_stmt_iterator gsi, gsi_from; - type = TREE_TYPE (PHI_RESULT (phi)); + tree type = TREE_TYPE (PHI_RESULT (phi)); /* The optimization may be unsafe due to NaNs. */ if (HONOR_NANS (type) || HONOR_SIGNED_ZEROS (type)) return false; - cond = as_a <gcond *> (last_stmt (cond_bb)); - cmp = gimple_cond_code (cond); - rhs = gimple_cond_rhs (cond); + gcond *cond = as_a <gcond *> (last_stmt (cond_bb)); + enum tree_code cmp = gimple_cond_code (cond); + tree rhs = gimple_cond_rhs (cond); /* Turn EQ/NE of extreme values to order comparisons. */ if ((cmp == NE_EXPR || cmp == EQ_EXPR) @@ -1401,8 +1400,8 @@ minmax_replacement (basic_block cond_bb, basic_block middle_bb, /* This transformation is only valid for order comparisons. Record which operand is smaller/larger if the result of the comparison is true. */ - alt_smaller = NULL_TREE; - alt_larger = NULL_TREE; + tree alt_smaller = NULL_TREE; + tree alt_larger = NULL_TREE; if (cmp == LT_EXPR || cmp == LE_EXPR) { smaller = gimple_cond_lhs (cond); @@ -1463,6 +1462,50 @@ minmax_replacement (basic_block cond_bb, basic_block middle_bb, else return false; + /* Handle the special case of (signed_type)x < 0 being equivalent + to x > MAX_VAL(signed_type) and (signed_type)x >= 0 equivalent + to x <= MAX_VAL(signed_type). */ + if ((cmp == GE_EXPR || cmp == LT_EXPR) + && INTEGRAL_TYPE_P (type) + && TYPE_UNSIGNED (type) + && integer_zerop (rhs)) + { + tree op = gimple_cond_lhs (cond); + if (TREE_CODE (op) == SSA_NAME + && INTEGRAL_TYPE_P (TREE_TYPE (op)) + && !TYPE_UNSIGNED (TREE_TYPE (op))) + { + gimple *def_stmt = SSA_NAME_DEF_STMT (op); + if (gimple_assign_cast_p (def_stmt)) + { + tree op1 = gimple_assign_rhs1 (def_stmt); + if (INTEGRAL_TYPE_P (TREE_TYPE (op1)) + && TYPE_UNSIGNED (TREE_TYPE (op1)) + && (TYPE_PRECISION (TREE_TYPE (op)) + == TYPE_PRECISION (TREE_TYPE (op1))) + && useless_type_conversion_p (type, TREE_TYPE (op1))) + { + wide_int w1 = wi::max_value (TREE_TYPE (op)); + wide_int w2 = wi::add (w1, 1); + if (cmp == LT_EXPR) + { + larger = op1; + smaller = wide_int_to_tree (TREE_TYPE (op1), w1); + alt_smaller = wide_int_to_tree (TREE_TYPE (op1), w2); + alt_larger = NULL_TREE; + } + else + { + smaller = op1; + larger = wide_int_to_tree (TREE_TYPE (op1), w1); + alt_larger = wide_int_to_tree (TREE_TYPE (op1), w2); + alt_smaller = NULL_TREE; + } + } + } + } + } + /* We need to know which is the true edge and which is the false edge so that we know if have abs or negative abs. */ extract_true_false_edges_from_block (cond_bb, &true_edge, &false_edge); @@ -1688,19 +1731,20 @@ minmax_replacement (basic_block cond_bb, basic_block middle_bb, gsi_move_before (&gsi_from, &gsi); } - /* Create an SSA var to hold the min/max result. If we're the only - things setting the target PHI, then we can clone the PHI - variable. Otherwise we must create a new one. */ - result = PHI_RESULT (phi); - if (EDGE_COUNT (gimple_bb (phi)->preds) == 2) - result = duplicate_ssa_name (result, NULL); - else - result = make_ssa_name (TREE_TYPE (result)); - /* Emit the statement to compute min/max. */ - new_stmt = gimple_build_assign (result, minmax, arg0, arg1); + gimple_seq stmts = NULL; + tree phi_result = PHI_RESULT (phi); + result = gimple_build (&stmts, minmax, TREE_TYPE (phi_result), arg0, arg1); + /* Duplicate range info if we're the only things setting the target PHI. */ + if (!gimple_seq_empty_p (stmts) + && EDGE_COUNT (gimple_bb (phi)->preds) == 2 + && !POINTER_TYPE_P (TREE_TYPE (phi_result)) + && SSA_NAME_RANGE_INFO (phi_result)) + duplicate_ssa_name_range_info (result, SSA_NAME_RANGE_TYPE (phi_result), + SSA_NAME_RANGE_INFO (phi_result)); + gsi = gsi_last_bb (cond_bb); - gsi_insert_before (&gsi, new_stmt, GSI_NEW_STMT); + gsi_insert_seq_before (&gsi, stmts, GSI_NEW_STMT); replace_phi_edge_with_variable (cond_bb, e1, phi, result); @@ -1986,26 +2030,33 @@ abs_replacement (basic_block cond_bb, basic_block middle_bb, ??? We currently are very conservative and assume that a load might trap even if a store doesn't (write-only memory). This probably is - overly conservative. */ + overly conservative. + + We currently support a special case that for !TREE_ADDRESSABLE automatic + variables, it could ignore whether something is a load or store because the + local stack should be always writable. */ -/* A hash-table of SSA_NAMEs, and in which basic block an MEM_REF - through it was seen, which would constitute a no-trap region for - same accesses. */ -struct name_to_bb +/* A hash-table of references (MEM_REF/ARRAY_REF/COMPONENT_REF), and in which + basic block an *_REF through it was seen, which would constitute a + no-trap region for same accesses. + + Size is needed to support 2 MEM_REFs of different types, like + MEM<double>(s_1) and MEM<long>(s_1), which would compare equal with + OEP_ADDRESS_OF. */ +struct ref_to_bb { - unsigned int ssa_name_ver; + tree exp; + HOST_WIDE_INT size; unsigned int phase; - bool store; - HOST_WIDE_INT offset, size; basic_block bb; }; /* Hashtable helpers. */ -struct ssa_names_hasher : free_ptr_hash <name_to_bb> +struct refs_hasher : free_ptr_hash<ref_to_bb> { - static inline hashval_t hash (const name_to_bb *); - static inline bool equal (const name_to_bb *, const name_to_bb *); + static inline hashval_t hash (const ref_to_bb *); + static inline bool equal (const ref_to_bb *, const ref_to_bb *); }; /* Used for quick clearing of the hash-table when we see calls. @@ -2015,28 +2066,29 @@ static unsigned int nt_call_phase; /* The hash function. */ inline hashval_t -ssa_names_hasher::hash (const name_to_bb *n) +refs_hasher::hash (const ref_to_bb *n) { - return n->ssa_name_ver ^ (((hashval_t) n->store) << 31) - ^ (n->offset << 6) ^ (n->size << 3); + inchash::hash hstate; + inchash::add_expr (n->exp, hstate, OEP_ADDRESS_OF); + hstate.add_hwi (n->size); + return hstate.end (); } /* The equality function of *P1 and *P2. */ inline bool -ssa_names_hasher::equal (const name_to_bb *n1, const name_to_bb *n2) +refs_hasher::equal (const ref_to_bb *n1, const ref_to_bb *n2) { - return n1->ssa_name_ver == n2->ssa_name_ver - && n1->store == n2->store - && n1->offset == n2->offset - && n1->size == n2->size; + return operand_equal_p (n1->exp, n2->exp, OEP_ADDRESS_OF) + && n1->size == n2->size; } class nontrapping_dom_walker : public dom_walker { public: nontrapping_dom_walker (cdi_direction direction, hash_set<tree> *ps) - : dom_walker (direction), m_nontrapping (ps), m_seen_ssa_names (128) {} + : dom_walker (direction), m_nontrapping (ps), m_seen_refs (128) + {} virtual edge before_dom_children (basic_block); virtual void after_dom_children (basic_block); @@ -2053,7 +2105,7 @@ private: hash_set<tree> *m_nontrapping; /* The hash table for remembering what we've seen. */ - hash_table<ssa_names_hasher> m_seen_ssa_names; + hash_table<refs_hasher> m_seen_refs; }; /* Called by walk_dominator_tree, when entering the block BB. */ @@ -2102,65 +2154,68 @@ nontrapping_dom_walker::after_dom_children (basic_block bb) } /* We see the expression EXP in basic block BB. If it's an interesting - expression (an MEM_REF through an SSA_NAME) possibly insert the - expression into the set NONTRAP or the hash table of seen expressions. - STORE is true if this expression is on the LHS, otherwise it's on - the RHS. */ + expression of: + 1) MEM_REF + 2) ARRAY_REF + 3) COMPONENT_REF + possibly insert the expression into the set NONTRAP or the hash table + of seen expressions. STORE is true if this expression is on the LHS, + otherwise it's on the RHS. */ void nontrapping_dom_walker::add_or_mark_expr (basic_block bb, tree exp, bool store) { HOST_WIDE_INT size; - if (TREE_CODE (exp) == MEM_REF - && TREE_CODE (TREE_OPERAND (exp, 0)) == SSA_NAME - && tree_fits_shwi_p (TREE_OPERAND (exp, 1)) + if ((TREE_CODE (exp) == MEM_REF || TREE_CODE (exp) == ARRAY_REF + || TREE_CODE (exp) == COMPONENT_REF) && (size = int_size_in_bytes (TREE_TYPE (exp))) > 0) { - tree name = TREE_OPERAND (exp, 0); - struct name_to_bb map; - name_to_bb **slot; - struct name_to_bb *n2bb; + struct ref_to_bb map; + ref_to_bb **slot; + struct ref_to_bb *r2bb; basic_block found_bb = 0; - /* Try to find the last seen MEM_REF through the same - SSA_NAME, which can trap. */ - map.ssa_name_ver = SSA_NAME_VERSION (name); - map.phase = 0; - map.bb = 0; - map.store = store; - map.offset = tree_to_shwi (TREE_OPERAND (exp, 1)); - map.size = size; + if (!store) + { + tree base = get_base_address (exp); + /* Only record a LOAD of a local variable without address-taken, as + the local stack is always writable. This allows cselim on a STORE + with a dominating LOAD. */ + if (!auto_var_p (base) || TREE_ADDRESSABLE (base)) + return; + } - slot = m_seen_ssa_names.find_slot (&map, INSERT); - n2bb = *slot; - if (n2bb && n2bb->phase >= nt_call_phase) - found_bb = n2bb->bb; + /* Try to find the last seen *_REF, which can trap. */ + map.exp = exp; + map.size = size; + slot = m_seen_refs.find_slot (&map, INSERT); + r2bb = *slot; + if (r2bb && r2bb->phase >= nt_call_phase) + found_bb = r2bb->bb; - /* If we've found a trapping MEM_REF, _and_ it dominates EXP - (it's in a basic block on the path from us to the dominator root) + /* If we've found a trapping *_REF, _and_ it dominates EXP + (it's in a basic block on the path from us to the dominator root) then we can't trap. */ if (found_bb && (((size_t)found_bb->aux) & 1) == 1) { m_nontrapping->add (exp); } else - { + { /* EXP might trap, so insert it into the hash table. */ - if (n2bb) + if (r2bb) { - n2bb->phase = nt_call_phase; - n2bb->bb = bb; + r2bb->phase = nt_call_phase; + r2bb->bb = bb; } else { - n2bb = XNEW (struct name_to_bb); - n2bb->ssa_name_ver = SSA_NAME_VERSION (name); - n2bb->phase = nt_call_phase; - n2bb->bb = bb; - n2bb->store = store; - n2bb->offset = map.offset; - n2bb->size = size; - *slot = n2bb; + r2bb = XNEW (struct ref_to_bb); + r2bb->phase = nt_call_phase; + r2bb->bb = bb; + r2bb->exp = exp; + r2bb->size = size; + *slot = r2bb; } } } |