static struct mem_ref_group * gather_memory_references (struct loop *loop, bool *no_other_refs) { basic_block *body = get_loop_body_in_dom_order (loop); basic_block bb; unsigned i; gimple_stmt_iterator bsi; gimple stmt; tree lhs, rhs; struct mem_ref_group *refs = NULL; *no_other_refs = true; /* Scan the loop body in order, so that the former references precede the later ones. */ for (i = 0; i < loop->num_nodes; i++) { bb = body[i]; if (bb->loop_father != loop) continue; for (bsi = gsi_start_bb (bb); !gsi_end_p (bsi); gsi_next (&bsi)) { stmt = gsi_stmt (bsi); if (gimple_code (stmt) != GIMPLE_ASSIGN) { if (!ZERO_SSA_OPERANDS (stmt, SSA_OP_ALL_VIRTUALS) || (is_gimple_call (stmt) && !(gimple_call_flags (stmt) & ECF_CONST))) *no_other_refs = false; continue; } lhs = gimple_assign_lhs (stmt); rhs = gimple_assign_rhs1 (stmt); if (REFERENCE_CLASS_P (rhs)) *no_other_refs &= gather_memory_references_ref (loop, &refs, rhs, false, stmt); if (REFERENCE_CLASS_P (lhs)) *no_other_refs &= gather_memory_references_ref (loop, &refs, lhs, true, stmt); } } free (body); return refs; }
static struct mem_ref_group * gather_memory_references (struct loop *loop, bool *no_other_refs) { basic_block *body = get_loop_body_in_dom_order (loop); basic_block bb; unsigned i; block_stmt_iterator bsi; tree stmt, lhs, rhs, call; struct mem_ref_group *refs = NULL; *no_other_refs = true; /* Scan the loop body in order, so that the former references precede the later ones. */ for (i = 0; i < loop->num_nodes; i++) { bb = body[i]; if (bb->loop_father != loop) continue; for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi)) { stmt = bsi_stmt (bsi); call = get_call_expr_in (stmt); if (call && !(call_expr_flags (call) & ECF_CONST)) *no_other_refs = false; if (TREE_CODE (stmt) != GIMPLE_MODIFY_STMT) { if (!ZERO_SSA_OPERANDS (stmt, SSA_OP_ALL_VIRTUALS)) *no_other_refs = false; continue; } lhs = GIMPLE_STMT_OPERAND (stmt, 0); rhs = GIMPLE_STMT_OPERAND (stmt, 1); if (REFERENCE_CLASS_P (rhs)) *no_other_refs &= gather_memory_references_ref (loop, &refs, rhs, false, stmt); if (REFERENCE_CLASS_P (lhs)) *no_other_refs &= gather_memory_references_ref (loop, &refs, lhs, true, stmt); } } free (body); return refs; }
static bool bb_no_side_effects_p (basic_block bb) { gimple_stmt_iterator gsi; for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) { gimple stmt = gsi_stmt (gsi); if (gimple_has_volatile_ops (stmt) || !ZERO_SSA_OPERANDS (stmt, SSA_OP_ALL_VIRTUALS)) return false; } return true; }
static bool stmt_may_generate_copy (gimple stmt) { if (gimple_code (stmt) == GIMPLE_PHI) return !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (gimple_phi_result (stmt)); if (gimple_code (stmt) != GIMPLE_ASSIGN) return false; /* If the statement has volatile operands, it won't generate a useful copy. */ if (gimple_has_volatile_ops (stmt)) return false; /* Statements with loads and/or stores will never generate a useful copy. */ if (!ZERO_SSA_OPERANDS (stmt, SSA_OP_ALL_VIRTUALS)) return false; /* Otherwise, the only statements that generate useful copies are assignments whose RHS is just an SSA name that doesn't flow through abnormal edges. */ return (gimple_assign_rhs_code (stmt) == SSA_NAME && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (gimple_assign_rhs1 (stmt))); }
static inline bool is_replaceable_p (gimple stmt) { use_operand_p use_p; tree def; gimple use_stmt; location_t locus1, locus2; tree block1, block2; /* Only consider modify stmts. */ if (!is_gimple_assign (stmt)) return false; /* If the statement may throw an exception, it cannot be replaced. */ if (stmt_could_throw_p (stmt)) return false; /* Punt if there is more than 1 def. */ def = SINGLE_SSA_TREE_OPERAND (stmt, SSA_OP_DEF); if (!def) return false; /* Only consider definitions which have a single use. */ if (!single_imm_use (def, &use_p, &use_stmt)) return false; /* If the use isn't in this block, it wont be replaced either. */ if (gimple_bb (use_stmt) != gimple_bb (stmt)) return false; locus1 = gimple_location (stmt); block1 = gimple_block (stmt); if (gimple_code (use_stmt) == GIMPLE_PHI) { locus2 = 0; block2 = NULL_TREE; } else { locus2 = gimple_location (use_stmt); block2 = gimple_block (use_stmt); } if (!optimize && ((locus1 && locus1 != locus2) || (block1 && block1 != block2))) return false; /* Used in this block, but at the TOP of the block, not the end. */ if (gimple_code (use_stmt) == GIMPLE_PHI) return false; /* There must be no VDEFs. */ if (!(ZERO_SSA_OPERANDS (stmt, SSA_OP_VDEF))) return false; /* Without alias info we can't move around loads. */ if (gimple_references_memory_p (stmt) && !optimize) return false; /* Float expressions must go through memory if float-store is on. */ if (flag_float_store && FLOAT_TYPE_P (gimple_expr_type (stmt))) return false; /* An assignment with a register variable on the RHS is not replaceable. */ if (gimple_assign_rhs_code (stmt) == VAR_DECL && DECL_HARD_REGISTER (gimple_assign_rhs1 (stmt))) return false; /* No function calls can be replaced. */ if (is_gimple_call (stmt)) return false; /* Leave any stmt with volatile operands alone as well. */ if (gimple_has_volatile_ops (stmt)) return false; return true; }
static unsigned int get_rank (tree e) { operand_entry_t vr; /* Constants have rank 0. */ if (is_gimple_min_invariant (e)) return 0; /* SSA_NAME's have the rank of the expression they are the result of. For globals and uninitialized values, the rank is 0. For function arguments, use the pre-setup rank. For PHI nodes, stores, asm statements, etc, we use the rank of the BB. For simple operations, the rank is the maximum rank of any of its operands, or the bb_rank, whichever is less. I make no claims that this is optimal, however, it gives good results. */ if (TREE_CODE (e) == SSA_NAME) { tree stmt; tree rhs; unsigned int rank, maxrank; int i; if (TREE_CODE (SSA_NAME_VAR (e)) == PARM_DECL && e == default_def (SSA_NAME_VAR (e))) return find_operand_rank (e)->rank; stmt = SSA_NAME_DEF_STMT (e); if (bb_for_stmt (stmt) == NULL) return 0; if (TREE_CODE (stmt) != MODIFY_EXPR || !ZERO_SSA_OPERANDS (stmt, SSA_OP_VIRTUAL_DEFS)) return bb_rank[bb_for_stmt (stmt)->index]; /* If we already have a rank for this expression, use that. */ vr = find_operand_rank (e); if (vr) return vr->rank; /* Otherwise, find the maximum rank for the operands, or the bb rank, whichever is less. */ rank = 0; maxrank = bb_rank[bb_for_stmt(stmt)->index]; rhs = TREE_OPERAND (stmt, 1); if (TREE_CODE_LENGTH (TREE_CODE (rhs)) == 0) rank = MAX (rank, get_rank (rhs)); else { for (i = 0; i < TREE_CODE_LENGTH (TREE_CODE (rhs)) && TREE_OPERAND (rhs, i) && rank != maxrank; i++) rank = MAX(rank, get_rank (TREE_OPERAND (rhs, i))); } if (dump_file && (dump_flags & TDF_DETAILS)) { fprintf (dump_file, "Rank for "); print_generic_expr (dump_file, e, 0); fprintf (dump_file, " is %d\n", (rank + 1)); } /* Note the rank in the hashtable so we don't recompute it. */ insert_operand_rank (e, (rank + 1)); return (rank + 1); } /* Globals, etc, are rank 0 */ return 0; }