static tree maybe_get_single_definition (tree t) { if (TREE_CODE (t) == SSA_NAME) { gimple g = SSA_NAME_DEF_STMT (t); if (gimple_assign_single_p (g)) return gimple_assign_rhs1 (g); } return NULL_TREE; }
static enum ssa_prop_result copy_prop_visit_stmt (gimple stmt, edge *taken_edge_p, tree *result_p) { enum ssa_prop_result retval; if (dump_file && (dump_flags & TDF_DETAILS)) { fprintf (dump_file, "\nVisiting statement:\n"); print_gimple_stmt (dump_file, stmt, 0, dump_flags); fprintf (dump_file, "\n"); } if (gimple_assign_single_p (stmt) && TREE_CODE (gimple_assign_lhs (stmt)) == SSA_NAME && (TREE_CODE (gimple_assign_rhs1 (stmt)) == SSA_NAME || is_gimple_min_invariant (gimple_assign_rhs1 (stmt)))) { /* If the statement is a copy assignment, evaluate its RHS to see if the lattice value of its output has changed. */ retval = copy_prop_visit_assignment (stmt, result_p); } else if (gimple_code (stmt) == GIMPLE_COND) { /* See if we can determine which edge goes out of a conditional jump. */ retval = copy_prop_visit_cond_stmt (stmt, taken_edge_p); } else retval = SSA_PROP_VARYING; if (retval == SSA_PROP_VARYING) { tree def; ssa_op_iter i; /* Any other kind of statement is not interesting for constant propagation and, therefore, not worth simulating. */ if (dump_file && (dump_flags & TDF_DETAILS)) fprintf (dump_file, "No interesting values produced.\n"); /* The assignment is not a copy operation. Don't visit this statement again and mark all the definitions in the statement to be copies of nothing. */ FOR_EACH_SSA_TREE_OPERAND (def, stmt, i, SSA_OP_ALL_DEFS) set_copy_of_val (def, def); } return retval; }
static tree lhs_of_dominating_assert (tree op, basic_block bb, gimple stmt) { imm_use_iterator imm_iter; gimple use_stmt; use_operand_p use_p; FOR_EACH_IMM_USE_FAST (use_p, imm_iter, op) { use_stmt = USE_STMT (use_p); if (use_stmt != stmt && gimple_assign_single_p (use_stmt) && TREE_CODE (gimple_assign_rhs1 (use_stmt)) == ASSERT_EXPR && TREE_OPERAND (gimple_assign_rhs1 (use_stmt), 0) == op && dominated_by_p (CDI_DOMINATORS, bb, gimple_bb (use_stmt))) { return gimple_assign_lhs (use_stmt); } }
static tree get_real_ref_rhs (tree expr) { switch (TREE_CODE (expr)) { case SSA_NAME: { /* Given a self-assign statement, say foo.x = foo.x, the IR (after SSA) looks like: D.1797_14 = foo.x; foo.x ={v} D.1797_14; So if the rhs EXPR is an SSA_NAME of a temp variable, e.g. D.1797_14, we need to grab the rhs of its SSA def statement (i.e. foo.x). */ tree vdecl = SSA_NAME_VAR (expr); if ((!vdecl || DECL_ARTIFICIAL (vdecl)) && !gimple_nop_p (SSA_NAME_DEF_STMT (expr))) { gimple def_stmt = SSA_NAME_DEF_STMT (expr); /* We are only interested in an assignment with a single rhs operand because if it is not, the original assignment will not possibly be a self-assignment. */ if (gimple_assign_single_p (def_stmt)) return get_real_ref_rhs (gimple_assign_rhs1 (def_stmt)); else return NULL_TREE; } else return vdecl; } case VAR_DECL: case PARM_DECL: case FIELD_DECL: case COMPONENT_REF: case MEM_REF: case ARRAY_REF: return expr; default: return NULL_TREE; } }
bool may_propagate_copy_into_stmt (gimple dest, tree orig) { tree type_d; tree type_o; /* If the statement is a switch or a single-rhs assignment, then the expression to be replaced by the propagation may be an SSA_NAME. Fortunately, there is an explicit tree for the expression, so we delegate to may_propagate_copy. */ if (gimple_assign_single_p (dest)) return may_propagate_copy (gimple_assign_rhs1 (dest), orig); else if (gimple_code (dest) == GIMPLE_SWITCH) return may_propagate_copy (gimple_switch_index (dest), orig); /* In other cases, the expression is not materialized, so there is no destination to pass to may_propagate_copy. On the other hand, the expression cannot be an SSA_NAME, so the analysis is much simpler. */ if (TREE_CODE (orig) == SSA_NAME && (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (orig) || TREE_CODE (SSA_NAME_VAR (orig)) == MEMORY_PARTITION_TAG)) return false; if (is_gimple_assign (dest)) type_d = TREE_TYPE (gimple_assign_lhs (dest)); else if (gimple_code (dest) == GIMPLE_COND) type_d = boolean_type_node; else if (is_gimple_call (dest) && gimple_call_lhs (dest) != NULL_TREE) type_d = TREE_TYPE (gimple_call_lhs (dest)); else gcc_unreachable (); type_o = TREE_TYPE (orig); if (!useless_type_conversion_p (type_d, type_o)) return false; return true; }
static void warn_self_assign (gimple stmt) { tree rhs, lhs; /* Check assigment statement. */ if (gimple_assign_single_p (stmt)) { rhs = get_real_ref_rhs (gimple_assign_rhs1 (stmt)); if (!rhs) return; lhs = gimple_assign_lhs (stmt); if (TREE_CODE (lhs) == SSA_NAME) { lhs = SSA_NAME_VAR (lhs); if (!lhs || DECL_ARTIFICIAL (lhs)) return; } compare_and_warn (stmt, lhs, rhs); } /* Check overloaded operator '=' (if enabled). */ else if (check_operator_eq && is_gimple_call (stmt)) { tree fdecl = gimple_call_fndecl (stmt); if (fdecl && (DECL_NAME (fdecl) == maybe_get_identifier ("operator="))) { /* If 'operator=' takes reference operands, the arguments will be ADDR_EXPR trees. In this case, just remove the address-taken operator before we compare the lhs and rhs. */ lhs = gimple_call_arg (stmt, 0); if (TREE_CODE (lhs) == ADDR_EXPR) lhs = TREE_OPERAND (lhs, 0); rhs = gimple_call_arg (stmt, 1); if (TREE_CODE (rhs) == ADDR_EXPR) rhs = TREE_OPERAND (rhs, 0); compare_and_warn (stmt, lhs, rhs); } } }
static bool can_propagate_from (gimple def_stmt) { use_operand_p use_p; ssa_op_iter iter; gcc_assert (is_gimple_assign (def_stmt)); /* If the rhs has side-effects we cannot propagate from it. */ if (gimple_has_volatile_ops (def_stmt)) return false; /* If the rhs is a load we cannot propagate from it. */ if (TREE_CODE_CLASS (gimple_assign_rhs_code (def_stmt)) == tcc_reference || TREE_CODE_CLASS (gimple_assign_rhs_code (def_stmt)) == tcc_declaration) return false; /* Constants can be always propagated. */ if (gimple_assign_single_p (def_stmt) && is_gimple_min_invariant (gimple_assign_rhs1 (def_stmt))) return true; /* We cannot propagate ssa names that occur in abnormal phi nodes. */ FOR_EACH_SSA_USE_OPERAND (use_p, def_stmt, iter, SSA_OP_USE) if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (USE_FROM_PTR (use_p))) return false; /* If the definition is a conversion of a pointer to a function type, then we can not apply optimizations as some targets require function pointers to be canonicalized and in this case this optimization could eliminate a necessary canonicalization. */ if (CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (def_stmt))) { tree rhs = gimple_assign_rhs1 (def_stmt); if (POINTER_TYPE_P (TREE_TYPE (rhs)) && TREE_CODE (TREE_TYPE (TREE_TYPE (rhs))) == FUNCTION_TYPE) return false; } return true; }
void propagate_tree_value_into_stmt (gimple_stmt_iterator *gsi, tree val) { gimple stmt = gsi_stmt (*gsi); if (is_gimple_assign (stmt)) { tree expr = NULL_TREE; if (gimple_assign_single_p (stmt)) expr = gimple_assign_rhs1 (stmt); propagate_tree_value (&expr, val); gimple_assign_set_rhs_from_tree (gsi, expr); stmt = gsi_stmt (*gsi); } else if (gimple_code (stmt) == GIMPLE_COND) { tree lhs = NULL_TREE; tree rhs = fold_convert (TREE_TYPE (val), integer_zero_node); propagate_tree_value (&lhs, val); gimple_cond_set_code (stmt, NE_EXPR); gimple_cond_set_lhs (stmt, lhs); gimple_cond_set_rhs (stmt, rhs); } else if (is_gimple_call (stmt) && gimple_call_lhs (stmt) != NULL_TREE) { gimple new_stmt; tree expr = NULL_TREE; propagate_tree_value (&expr, val); new_stmt = gimple_build_assign (gimple_call_lhs (stmt), expr); copy_virtual_operands (new_stmt, stmt); move_ssa_defining_stmt_for_defs (new_stmt, stmt); gsi_replace (gsi, new_stmt, false); } else if (gimple_code (stmt) == GIMPLE_SWITCH) propagate_tree_value (gimple_switch_index_ptr (stmt), val); else gcc_unreachable (); }
void propagate_tree_value_into_stmt (gimple_stmt_iterator *gsi, tree val) { gimple stmt = gsi_stmt (*gsi); if (is_gimple_assign (stmt)) { tree expr = NULL_TREE; if (gimple_assign_single_p (stmt)) expr = gimple_assign_rhs1 (stmt); propagate_tree_value (&expr, val); gimple_assign_set_rhs_from_tree (gsi, expr); } else if (gimple_code (stmt) == GIMPLE_COND) { tree lhs = NULL_TREE; tree rhs = build_zero_cst (TREE_TYPE (val)); propagate_tree_value (&lhs, val); gimple_cond_set_code (stmt, NE_EXPR); gimple_cond_set_lhs (stmt, lhs); gimple_cond_set_rhs (stmt, rhs); } else if (is_gimple_call (stmt) && gimple_call_lhs (stmt) != NULL_TREE) { tree expr = NULL_TREE; bool res; propagate_tree_value (&expr, val); res = update_call_from_tree (gsi, expr); gcc_assert (res); } else if (gimple_code (stmt) == GIMPLE_SWITCH) propagate_tree_value (gimple_switch_index_ptr (stmt), val); else gcc_unreachable (); }
static tree get_non_ssa_expr (tree expr) { if (!expr) return NULL_TREE; switch (TREE_CODE (expr)) { case VAR_DECL: case PARM_DECL: case FIELD_DECL: { if (DECL_NAME (expr)) return expr; else return NULL_TREE; } case COMPONENT_REF: { tree base, orig_base = TREE_OPERAND (expr, 0); tree component, orig_component = TREE_OPERAND (expr, 1); base = get_non_ssa_expr (orig_base); if (!base) return NULL_TREE; component = get_non_ssa_expr (orig_component); if (!component) return NULL_TREE; /* If either BASE or COMPONENT is converted, build a new component reference tree. */ if (base != orig_base || component != orig_component) return build3 (COMPONENT_REF, TREE_TYPE (component), base, component, NULL_TREE); else return expr; } case MEM_REF: { tree orig_base = TREE_OPERAND (expr, 0); if (TREE_CODE (orig_base) == SSA_NAME) { tree base = get_non_ssa_expr (orig_base); if (!base) return NULL_TREE; return fold_build2 (MEM_REF, TREE_TYPE (expr), base, TREE_OPERAND (expr, 1)); } return expr; } case ARRAY_REF: { tree array, orig_array = TREE_OPERAND (expr, 0); tree index, orig_index = TREE_OPERAND (expr, 1); array = get_non_ssa_expr (orig_array); if (!array) return NULL_TREE; index = get_non_ssa_expr (orig_index); if (!index) return NULL_TREE; /* If either ARRAY or INDEX is converted, build a new array reference tree. */ if (array != orig_array || index != orig_index) return build4 (ARRAY_REF, TREE_TYPE (expr), array, index, TREE_OPERAND (expr, 2), TREE_OPERAND (expr, 3)); else return expr; } case SSA_NAME: { tree vdecl = SSA_NAME_VAR (expr); if ((!vdecl || DECL_ARTIFICIAL (vdecl)) && !gimple_nop_p (SSA_NAME_DEF_STMT (expr))) { gimple def_stmt = SSA_NAME_DEF_STMT (expr); if (gimple_assign_single_p (def_stmt)) vdecl = gimple_assign_rhs1 (def_stmt); } return get_non_ssa_expr (vdecl); } case INTEGER_CST: return expr; default: /* Return NULL_TREE for any other kind of tree nodes. */ return NULL_TREE; } }
tree avail_exprs_stack::lookup_avail_expr (gimple *stmt, bool insert, bool tbaa_p) { expr_hash_elt **slot; tree lhs; /* Get LHS of phi, assignment, or call; else NULL_TREE. */ if (gimple_code (stmt) == GIMPLE_PHI) lhs = gimple_phi_result (stmt); else lhs = gimple_get_lhs (stmt); class expr_hash_elt element (stmt, lhs); if (dump_file && (dump_flags & TDF_DETAILS)) { fprintf (dump_file, "LKUP "); element.print (dump_file); } /* Don't bother remembering constant assignments and copy operations. Constants and copy operations are handled by the constant/copy propagator in optimize_stmt. */ if (element.expr()->kind == EXPR_SINGLE && (TREE_CODE (element.expr()->ops.single.rhs) == SSA_NAME || is_gimple_min_invariant (element.expr()->ops.single.rhs))) return NULL_TREE; /* Finally try to find the expression in the main expression hash table. */ slot = m_avail_exprs->find_slot (&element, (insert ? INSERT : NO_INSERT)); if (slot == NULL) { return NULL_TREE; } else if (*slot == NULL) { class expr_hash_elt *element2 = new expr_hash_elt (element); *slot = element2; record_expr (element2, NULL, '2'); return NULL_TREE; } /* If we found a redundant memory operation do an alias walk to check if we can re-use it. */ if (gimple_vuse (stmt) != (*slot)->vop ()) { tree vuse1 = (*slot)->vop (); tree vuse2 = gimple_vuse (stmt); /* If we have a load of a register and a candidate in the hash with vuse1 then try to reach its stmt by walking up the virtual use-def chain using walk_non_aliased_vuses. But don't do this when removing expressions from the hash. */ ao_ref ref; if (!(vuse1 && vuse2 && gimple_assign_single_p (stmt) && TREE_CODE (gimple_assign_lhs (stmt)) == SSA_NAME && (ao_ref_init (&ref, gimple_assign_rhs1 (stmt)), ref.base_alias_set = ref.ref_alias_set = tbaa_p ? -1 : 0, true) && walk_non_aliased_vuses (&ref, vuse2, vuse_eq, NULL, NULL, vuse1) != NULL)) { if (insert) { class expr_hash_elt *element2 = new expr_hash_elt (element); /* Insert the expr into the hash by replacing the current entry and recording the value to restore in the avail_exprs_stack. */ record_expr (element2, *slot, '2'); *slot = element2; } return NULL_TREE; } } /* Extract the LHS of the assignment so that it can be used as the current definition of another variable. */ lhs = (*slot)->lhs (); /* Valueize the result. */ if (TREE_CODE (lhs) == SSA_NAME) { tree tem = SSA_NAME_VALUE (lhs); if (tem) lhs = tem; } if (dump_file && (dump_flags & TDF_DETAILS)) { fprintf (dump_file, "FIND: "); print_generic_expr (dump_file, lhs, 0); fprintf (dump_file, "\n"); } return lhs; }