-/* Helper for extract_mentioned_regs; ACCUM is used to accumulate used
- registers. */
-static rtx
-extract_mentioned_regs_helper (rtx x, rtx accum)
-{
- int i;
- enum rtx_code code;
- const char * fmt;
-
- /* Repeat is used to turn tail-recursion into iteration. */
- repeat:
-
- if (x == 0)
- return accum;
-
- code = GET_CODE (x);
- switch (code)
- {
- case REG:
- return alloc_EXPR_LIST (0, x, accum);
-
- case MEM:
- x = XEXP (x, 0);
- goto repeat;
-
- case PRE_DEC:
- case PRE_INC:
- case PRE_MODIFY:
- case POST_DEC:
- case POST_INC:
- case POST_MODIFY:
- /* We do not run this function with arguments having side effects. */
- gcc_unreachable ();
-
- case PC:
- case CC0: /*FIXME*/
- case CONST:
- case CONST_INT:
- case CONST_DOUBLE:
- case CONST_VECTOR:
- case SYMBOL_REF:
- case LABEL_REF:
- case ADDR_VEC:
- case ADDR_DIFF_VEC:
- return accum;
-
- default:
- break;
- }
-
- i = GET_RTX_LENGTH (code) - 1;
- fmt = GET_RTX_FORMAT (code);
-
- for (; i >= 0; i--)
- {
- if (fmt[i] == 'e')
- {
- rtx tem = XEXP (x, i);
-
- /* If we are about to do the last recursive call
- needed at this level, change it into iteration. */
- if (i == 0)
- {
- x = tem;
- goto repeat;
- }
-
- accum = extract_mentioned_regs_helper (tem, accum);
- }
- else if (fmt[i] == 'E')
- {
- int j;
-
- for (j = 0; j < XVECLEN (x, i); j++)
- accum = extract_mentioned_regs_helper (XVECEXP (x, i, j), accum);
- }
- }
-
- return accum;
-}
-
-/* Determine whether INSN is MEM store pattern that we will consider moving.
- REGS_SET_BEFORE is bitmap of registers set before (and including) the
- current insn, REGS_SET_AFTER is bitmap of registers set after (and
- including) the insn in this basic block. We must be passing through BB from
- head to end, as we are using this fact to speed things up.
-
- The results are stored this way:
-
- -- the first anticipatable expression is added into ANTIC_STORE_LIST
- -- if the processed expression is not anticipatable, NULL_RTX is added
- there instead, so that we can use it as indicator that no further
- expression of this type may be anticipatable
- -- if the expression is available, it is added as head of AVAIL_STORE_LIST;
- consequently, all of them but this head are dead and may be deleted.
- -- if the expression is not available, the insn due to that it fails to be
- available is stored in reaching_reg.
-
- The things are complicated a bit by fact that there already may be stores
- to the same MEM from other blocks; also caller must take care of the
- necessary cleanup of the temporary markers after end of the basic block.
- */
-
-static void
-find_moveable_store (rtx insn, int *regs_set_before, int *regs_set_after)
-{
- struct ls_expr * ptr;
- rtx dest, set, tmp;
- int check_anticipatable, check_available;
- basic_block bb = BLOCK_FOR_INSN (insn);
-
- set = single_set (insn);
- if (!set)
- return;
-
- dest = SET_DEST (set);
-
- if (! MEM_P (dest) || MEM_VOLATILE_P (dest)
- || GET_MODE (dest) == BLKmode)
- return;
-
- if (side_effects_p (dest))
- return;
-
- /* If we are handling exceptions, we must be careful with memory references
- that may trap. If we are not, the behavior is undefined, so we may just
- continue. */
- if (flag_non_call_exceptions && may_trap_p (dest))
- return;
-
- /* Even if the destination cannot trap, the source may. In this case we'd
- need to handle updating the REG_EH_REGION note. */
- if (find_reg_note (insn, REG_EH_REGION, NULL_RTX))
- return;
-
- /* Make sure that the SET_SRC of this store insns can be assigned to
- a register, or we will fail later on in replace_store_insn, which
- assumes that we can do this. But sometimes the target machine has
- oddities like MEM read-modify-write instruction. See for example
- PR24257. */
- if (!can_assign_to_reg_p (SET_SRC (set)))
- return;
-
- ptr = ldst_entry (dest);
- if (!ptr->pattern_regs)
- ptr->pattern_regs = extract_mentioned_regs (dest);
-
- /* Do not check for anticipatability if we either found one anticipatable
- store already, or tested for one and found out that it was killed. */
- check_anticipatable = 0;
- if (!ANTIC_STORE_LIST (ptr))
- check_anticipatable = 1;
- else
- {
- tmp = XEXP (ANTIC_STORE_LIST (ptr), 0);
- if (tmp != NULL_RTX
- && BLOCK_FOR_INSN (tmp) != bb)
- check_anticipatable = 1;
- }
- if (check_anticipatable)
- {
- if (store_killed_before (dest, ptr->pattern_regs, insn, bb, regs_set_before))
- tmp = NULL_RTX;
- else
- tmp = insn;
- ANTIC_STORE_LIST (ptr) = alloc_INSN_LIST (tmp,
- ANTIC_STORE_LIST (ptr));
- }
-
- /* It is not necessary to check whether store is available if we did
- it successfully before; if we failed before, do not bother to check
- until we reach the insn that caused us to fail. */
- check_available = 0;
- if (!AVAIL_STORE_LIST (ptr))
- check_available = 1;
- else
- {
- tmp = XEXP (AVAIL_STORE_LIST (ptr), 0);
- if (BLOCK_FOR_INSN (tmp) != bb)
- check_available = 1;
- }
- if (check_available)
- {
- /* Check that we have already reached the insn at that the check
- failed last time. */
- if (LAST_AVAIL_CHECK_FAILURE (ptr))
- {
- for (tmp = BB_END (bb);
- tmp != insn && tmp != LAST_AVAIL_CHECK_FAILURE (ptr);
- tmp = PREV_INSN (tmp))
- continue;
- if (tmp == insn)
- check_available = 0;
- }
- else
- check_available = store_killed_after (dest, ptr->pattern_regs, insn,
- bb, regs_set_after,
- &LAST_AVAIL_CHECK_FAILURE (ptr));
- }
- if (!check_available)
- AVAIL_STORE_LIST (ptr) = alloc_INSN_LIST (insn, AVAIL_STORE_LIST (ptr));
-}
-
-/* Find available and anticipatable stores. */
-
-static int
-compute_store_table (void)
-{
- int ret;
- basic_block bb;
- unsigned regno;
- rtx insn, pat, tmp;
- int *last_set_in, *already_set;
- struct ls_expr * ptr, **prev_next_ptr_ptr;
-
- max_gcse_regno = max_reg_num ();
-
- reg_set_in_block = sbitmap_vector_alloc (last_basic_block,
- max_gcse_regno);
- sbitmap_vector_zero (reg_set_in_block, last_basic_block);
- pre_ldst_mems = 0;
- pre_ldst_table = htab_create (13, pre_ldst_expr_hash,
- pre_ldst_expr_eq, NULL);
- last_set_in = XCNEWVEC (int, max_gcse_regno);
- already_set = XNEWVEC (int, max_gcse_regno);
-
- /* Find all the stores we care about. */
- FOR_EACH_BB (bb)
- {
- /* First compute the registers set in this block. */
- regvec = last_set_in;
-
- FOR_BB_INSNS (bb, insn)
- {
- if (! INSN_P (insn))
- continue;
-
- if (CALL_P (insn))
- {
- for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
- if (TEST_HARD_REG_BIT (regs_invalidated_by_call, regno))
- {
- last_set_in[regno] = INSN_UID (insn);
- SET_BIT (reg_set_in_block[bb->index], regno);
- }
- }
-
- pat = PATTERN (insn);
- compute_store_table_current_insn = insn;
- note_stores (pat, reg_set_info, reg_set_in_block[bb->index]);
- }
-
- /* Now find the stores. */
- memset (already_set, 0, sizeof (int) * max_gcse_regno);
- regvec = already_set;
- FOR_BB_INSNS (bb, insn)
- {
- if (! INSN_P (insn))
- continue;
-
- if (CALL_P (insn))
- {
- for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
- if (TEST_HARD_REG_BIT (regs_invalidated_by_call, regno))
- already_set[regno] = 1;
- }
-
- pat = PATTERN (insn);
- note_stores (pat, reg_set_info, NULL);
-
- /* Now that we've marked regs, look for stores. */
- find_moveable_store (insn, already_set, last_set_in);
-
- /* Unmark regs that are no longer set. */
- compute_store_table_current_insn = insn;
- note_stores (pat, reg_clear_last_set, last_set_in);
- if (CALL_P (insn))
- {
- for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
- if (TEST_HARD_REG_BIT (regs_invalidated_by_call, regno)
- && last_set_in[regno] == INSN_UID (insn))
- last_set_in[regno] = 0;
- }
- }
-
-#ifdef ENABLE_CHECKING
- /* last_set_in should now be all-zero. */
- for (regno = 0; regno < max_gcse_regno; regno++)
- gcc_assert (!last_set_in[regno]);
-#endif
-
- /* Clear temporary marks. */
- for (ptr = first_ls_expr (); ptr != NULL; ptr = next_ls_expr (ptr))
- {
- LAST_AVAIL_CHECK_FAILURE(ptr) = NULL_RTX;
- if (ANTIC_STORE_LIST (ptr)
- && (tmp = XEXP (ANTIC_STORE_LIST (ptr), 0)) == NULL_RTX)
- ANTIC_STORE_LIST (ptr) = XEXP (ANTIC_STORE_LIST (ptr), 1);
- }
- }
-
- /* Remove the stores that are not available anywhere, as there will
- be no opportunity to optimize them. */
- for (ptr = pre_ldst_mems, prev_next_ptr_ptr = &pre_ldst_mems;
- ptr != NULL;
- ptr = *prev_next_ptr_ptr)
- {
- if (!AVAIL_STORE_LIST (ptr))
- {
- *prev_next_ptr_ptr = ptr->next;
- htab_remove_elt_with_hash (pre_ldst_table, ptr, ptr->hash_index);
- free_ldst_entry (ptr);
- }
- else
- prev_next_ptr_ptr = &ptr->next;
- }
-
- ret = enumerate_ldsts ();
-
- if (dump_file)
- {
- fprintf (dump_file, "ST_avail and ST_antic (shown under loads..)\n");
- print_ldst_list (dump_file);
- }
-
- free (last_set_in);
- free (already_set);
- return ret;
-}
-
-/* Check to see if the load X is aliased with STORE_PATTERN.
- AFTER is true if we are checking the case when STORE_PATTERN occurs
- after the X. */
-
-static bool
-load_kills_store (rtx x, rtx store_pattern, int after)
-{
- if (after)
- return anti_dependence (x, store_pattern);
- else
- return true_dependence (store_pattern, GET_MODE (store_pattern), x,
- rtx_addr_varies_p);
-}
-
-/* Go through the entire insn X, looking for any loads which might alias
- STORE_PATTERN. Return true if found.
- AFTER is true if we are checking the case when STORE_PATTERN occurs
- after the insn X. */
-
-static bool
-find_loads (rtx x, rtx store_pattern, int after)
-{
- const char * fmt;
- int i, j;
- int ret = false;
-
- if (!x)
- return false;
-
- if (GET_CODE (x) == SET)
- x = SET_SRC (x);
-
- if (MEM_P (x))
- {
- if (load_kills_store (x, store_pattern, after))
- return true;
- }
-
- /* Recursively process the insn. */
- fmt = GET_RTX_FORMAT (GET_CODE (x));
-
- for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0 && !ret; i--)
- {
- if (fmt[i] == 'e')
- ret |= find_loads (XEXP (x, i), store_pattern, after);
- else if (fmt[i] == 'E')
- for (j = XVECLEN (x, i) - 1; j >= 0; j--)
- ret |= find_loads (XVECEXP (x, i, j), store_pattern, after);
- }
- return ret;
-}
-
-static inline bool
-store_killed_in_pat (rtx x, rtx pat, int after)
-{
- if (GET_CODE (pat) == SET)
- {
- rtx dest = SET_DEST (pat);
-
- if (GET_CODE (dest) == ZERO_EXTRACT)
- dest = XEXP (dest, 0);
-
- /* Check for memory stores to aliased objects. */
- if (MEM_P (dest)
- && !expr_equiv_p (dest, x))
- {
- if (after)
- {
- if (output_dependence (dest, x))
- return true;
- }
- else
- {
- if (output_dependence (x, dest))
- return true;
- }
- }
- }
-
- if (find_loads (pat, x, after))
- return true;
-
- return false;
-}
-
-/* Check if INSN kills the store pattern X (is aliased with it).
- AFTER is true if we are checking the case when store X occurs
- after the insn. Return true if it does. */
-
-static bool
-store_killed_in_insn (rtx x, rtx x_regs, rtx insn, int after)
-{
- rtx reg, base, note, pat;
-
- if (!INSN_P (insn))
- return false;
-
- if (CALL_P (insn))
- {
- /* A normal or pure call might read from pattern,
- but a const call will not. */
- if (! CONST_OR_PURE_CALL_P (insn) || pure_call_p (insn))
- return true;
-
- /* But even a const call reads its parameters. Check whether the
- base of some of registers used in mem is stack pointer. */
- for (reg = x_regs; reg; reg = XEXP (reg, 1))
- {
- base = find_base_term (XEXP (reg, 0));
- if (!base
- || (GET_CODE (base) == ADDRESS
- && GET_MODE (base) == Pmode
- && XEXP (base, 0) == stack_pointer_rtx))
- return true;
- }
-
- return false;
- }
-
- pat = PATTERN (insn);
- if (GET_CODE (pat) == SET)
- {
- if (store_killed_in_pat (x, pat, after))
- return true;
- }
- else if (GET_CODE (pat) == PARALLEL)
- {
- int i;
-
- for (i = 0; i < XVECLEN (pat, 0); i++)
- if (store_killed_in_pat (x, XVECEXP (pat, 0, i), after))
- return true;
- }
- else if (find_loads (PATTERN (insn), x, after))
- return true;
-
- /* If this insn has a REG_EQUAL or REG_EQUIV note referencing a memory
- location aliased with X, then this insn kills X. */
- note = find_reg_equal_equiv_note (insn);
- if (! note)
- return false;
- note = XEXP (note, 0);
-
- /* However, if the note represents a must alias rather than a may
- alias relationship, then it does not kill X. */
- if (expr_equiv_p (note, x))
- return false;
-
- /* See if there are any aliased loads in the note. */
- return find_loads (note, x, after);
-}
-
-/* Returns true if the expression X is loaded or clobbered on or after INSN
- within basic block BB. REGS_SET_AFTER is bitmap of registers set in
- or after the insn. X_REGS is list of registers mentioned in X. If the store
- is killed, return the last insn in that it occurs in FAIL_INSN. */
-
-static bool
-store_killed_after (rtx x, rtx x_regs, rtx insn, basic_block bb,
- int *regs_set_after, rtx *fail_insn)
-{
- rtx last = BB_END (bb), act;
-
- if (!store_ops_ok (x_regs, regs_set_after))
- {
- /* We do not know where it will happen. */
- if (fail_insn)
- *fail_insn = NULL_RTX;
- return true;
- }
-
- /* Scan from the end, so that fail_insn is determined correctly. */
- for (act = last; act != PREV_INSN (insn); act = PREV_INSN (act))
- if (store_killed_in_insn (x, x_regs, act, false))
- {
- if (fail_insn)
- *fail_insn = act;
- return true;
- }
-
- return false;
-}
-
-/* Returns true if the expression X is loaded or clobbered on or before INSN
- within basic block BB. X_REGS is list of registers mentioned in X.
- REGS_SET_BEFORE is bitmap of registers set before or in this insn. */
-static bool
-store_killed_before (rtx x, rtx x_regs, rtx insn, basic_block bb,
- int *regs_set_before)
-{
- rtx first = BB_HEAD (bb);
-
- if (!store_ops_ok (x_regs, regs_set_before))
- return true;
-
- for ( ; insn != PREV_INSN (first); insn = PREV_INSN (insn))
- if (store_killed_in_insn (x, x_regs, insn, true))
- return true;
-
- return false;
-}
-
-/* Fill in available, anticipatable, transparent and kill vectors in
- STORE_DATA, based on lists of available and anticipatable stores. */
-static void
-build_store_vectors (void)
-{
- basic_block bb;
- int *regs_set_in_block;
- rtx insn, st;
- struct ls_expr * ptr;
- unsigned regno;
-
- /* Build the gen_vector. This is any store in the table which is not killed
- by aliasing later in its block. */
- ae_gen = sbitmap_vector_alloc (last_basic_block, num_stores);
- sbitmap_vector_zero (ae_gen, last_basic_block);
-
- st_antloc = sbitmap_vector_alloc (last_basic_block, num_stores);
- sbitmap_vector_zero (st_antloc, last_basic_block);
-
- for (ptr = first_ls_expr (); ptr != NULL; ptr = next_ls_expr (ptr))
- {
- for (st = AVAIL_STORE_LIST (ptr); st != NULL; st = XEXP (st, 1))
- {
- insn = XEXP (st, 0);
- bb = BLOCK_FOR_INSN (insn);
-
- /* If we've already seen an available expression in this block,
- we can delete this one (It occurs earlier in the block). We'll
- copy the SRC expression to an unused register in case there
- are any side effects. */
- if (TEST_BIT (ae_gen[bb->index], ptr->index))
- {
- rtx r = gen_reg_rtx (GET_MODE (ptr->pattern));
- if (dump_file)
- fprintf (dump_file, "Removing redundant store:\n");
- replace_store_insn (r, XEXP (st, 0), bb, ptr);
- continue;
- }
- SET_BIT (ae_gen[bb->index], ptr->index);
- }
-
- for (st = ANTIC_STORE_LIST (ptr); st != NULL; st = XEXP (st, 1))
- {
- insn = XEXP (st, 0);
- bb = BLOCK_FOR_INSN (insn);
- SET_BIT (st_antloc[bb->index], ptr->index);
- }
- }
-
- ae_kill = sbitmap_vector_alloc (last_basic_block, num_stores);
- sbitmap_vector_zero (ae_kill, last_basic_block);
-
- transp = sbitmap_vector_alloc (last_basic_block, num_stores);
- sbitmap_vector_zero (transp, last_basic_block);
- regs_set_in_block = XNEWVEC (int, max_gcse_regno);
-
- FOR_EACH_BB (bb)
- {
- for (regno = 0; regno < max_gcse_regno; regno++)
- regs_set_in_block[regno] = TEST_BIT (reg_set_in_block[bb->index], regno);
-
- for (ptr = first_ls_expr (); ptr != NULL; ptr = next_ls_expr (ptr))
- {
- if (store_killed_after (ptr->pattern, ptr->pattern_regs, BB_HEAD (bb),
- bb, regs_set_in_block, NULL))
- {
- /* It should not be necessary to consider the expression
- killed if it is both anticipatable and available. */
- if (!TEST_BIT (st_antloc[bb->index], ptr->index)
- || !TEST_BIT (ae_gen[bb->index], ptr->index))
- SET_BIT (ae_kill[bb->index], ptr->index);
- }
- else
- SET_BIT (transp[bb->index], ptr->index);
- }
- }
-
- free (regs_set_in_block);
-
- if (dump_file)
- {
- dump_sbitmap_vector (dump_file, "st_antloc", "", st_antloc, last_basic_block);
- dump_sbitmap_vector (dump_file, "st_kill", "", ae_kill, last_basic_block);
- dump_sbitmap_vector (dump_file, "Transpt", "", transp, last_basic_block);
- dump_sbitmap_vector (dump_file, "st_avloc", "", ae_gen, last_basic_block);
- }
-}
-
-/* Insert an instruction at the beginning of a basic block, and update
- the BB_HEAD if needed. */
-
-static void
-insert_insn_start_basic_block (rtx insn, basic_block bb)
-{
- /* Insert at start of successor block. */
- rtx prev = PREV_INSN (BB_HEAD (bb));
- rtx before = BB_HEAD (bb);
- while (before != 0)
- {
- if (! LABEL_P (before)
- && !NOTE_INSN_BASIC_BLOCK_P (before))
- break;
- prev = before;
- if (prev == BB_END (bb))
- break;
- before = NEXT_INSN (before);
- }
-
- insn = emit_insn_after_noloc (insn, prev, bb);
-
- if (dump_file)
- {
- fprintf (dump_file, "STORE_MOTION insert store at start of BB %d:\n",
- bb->index);
- print_inline_rtx (dump_file, insn, 6);
- fprintf (dump_file, "\n");
- }
-}
-
-/* This routine will insert a store on an edge. EXPR is the ldst entry for
- the memory reference, and E is the edge to insert it on. Returns nonzero
- if an edge insertion was performed. */
-
-static int
-insert_store (struct ls_expr * expr, edge e)
-{
- rtx reg, insn;
- basic_block bb;
- edge tmp;
- edge_iterator ei;
-
- /* We did all the deleted before this insert, so if we didn't delete a
- store, then we haven't set the reaching reg yet either. */
- if (expr->reaching_reg == NULL_RTX)
- return 0;
-
- if (e->flags & EDGE_FAKE)
- return 0;
-
- reg = expr->reaching_reg;
- insn = gen_move_insn (copy_rtx (expr->pattern), reg);
-
- /* If we are inserting this expression on ALL predecessor edges of a BB,
- insert it at the start of the BB, and reset the insert bits on the other
- edges so we don't try to insert it on the other edges. */
- bb = e->dest;
- FOR_EACH_EDGE (tmp, ei, e->dest->preds)
- if (!(tmp->flags & EDGE_FAKE))
- {
- int index = EDGE_INDEX (edge_list, tmp->src, tmp->dest);
-
- gcc_assert (index != EDGE_INDEX_NO_EDGE);
- if (! TEST_BIT (pre_insert_map[index], expr->index))
- break;
- }
-
- /* If tmp is NULL, we found an insertion on every edge, blank the
- insertion vector for these edges, and insert at the start of the BB. */
- if (!tmp && bb != EXIT_BLOCK_PTR)
- {
- FOR_EACH_EDGE (tmp, ei, e->dest->preds)
- {
- int index = EDGE_INDEX (edge_list, tmp->src, tmp->dest);
- RESET_BIT (pre_insert_map[index], expr->index);
- }
- insert_insn_start_basic_block (insn, bb);
- return 0;
- }
-
- /* We can't put stores in the front of blocks pointed to by abnormal
- edges since that may put a store where one didn't used to be. */
- gcc_assert (!(e->flags & EDGE_ABNORMAL));
-
- insert_insn_on_edge (insn, e);
-
- if (dump_file)
- {
- fprintf (dump_file, "STORE_MOTION insert insn on edge (%d, %d):\n",
- e->src->index, e->dest->index);
- print_inline_rtx (dump_file, insn, 6);
- fprintf (dump_file, "\n");
- }
-
- return 1;
-}
-
-/* Remove any REG_EQUAL or REG_EQUIV notes containing a reference to the
- memory location in SMEXPR set in basic block BB.
-
- This could be rather expensive. */
-
-static void
-remove_reachable_equiv_notes (basic_block bb, struct ls_expr *smexpr)
-{
- edge_iterator *stack, ei;
- int sp;
- edge act;
- sbitmap visited = sbitmap_alloc (last_basic_block);
- rtx last, insn, note;
- rtx mem = smexpr->pattern;
-
- stack = XNEWVEC (edge_iterator, n_basic_blocks);
- sp = 0;
- ei = ei_start (bb->succs);
-
- sbitmap_zero (visited);
-
- act = (EDGE_COUNT (ei_container (ei)) > 0 ? EDGE_I (ei_container (ei), 0) : NULL);
- while (1)
- {
- if (!act)
- {
- if (!sp)
- {
- free (stack);
- sbitmap_free (visited);
- return;
- }
- act = ei_edge (stack[--sp]);
- }
- bb = act->dest;
-
- if (bb == EXIT_BLOCK_PTR
- || TEST_BIT (visited, bb->index))
- {
- if (!ei_end_p (ei))
- ei_next (&ei);
- act = (! ei_end_p (ei)) ? ei_edge (ei) : NULL;
- continue;
- }
- SET_BIT (visited, bb->index);
-
- if (TEST_BIT (st_antloc[bb->index], smexpr->index))
- {
- for (last = ANTIC_STORE_LIST (smexpr);
- BLOCK_FOR_INSN (XEXP (last, 0)) != bb;
- last = XEXP (last, 1))
- continue;
- last = XEXP (last, 0);
- }
- else
- last = NEXT_INSN (BB_END (bb));
-
- for (insn = BB_HEAD (bb); insn != last; insn = NEXT_INSN (insn))
- if (INSN_P (insn))
- {
- note = find_reg_equal_equiv_note (insn);
- if (!note || !expr_equiv_p (XEXP (note, 0), mem))
- continue;
-
- if (dump_file)
- fprintf (dump_file, "STORE_MOTION drop REG_EQUAL note at insn %d:\n",
- INSN_UID (insn));
- remove_note (insn, note);
- }
-
- if (!ei_end_p (ei))
- ei_next (&ei);
- act = (! ei_end_p (ei)) ? ei_edge (ei) : NULL;
-
- if (EDGE_COUNT (bb->succs) > 0)
- {
- if (act)
- stack[sp++] = ei;
- ei = ei_start (bb->succs);
- act = (EDGE_COUNT (ei_container (ei)) > 0 ? EDGE_I (ei_container (ei), 0) : NULL);
- }
- }
-}
-
-/* This routine will replace a store with a SET to a specified register. */
-
-static void
-replace_store_insn (rtx reg, rtx del, basic_block bb, struct ls_expr *smexpr)
-{
- rtx insn, mem, note, set, ptr, pair;
-
- mem = smexpr->pattern;
- insn = gen_move_insn (reg, SET_SRC (single_set (del)));
-
- for (ptr = ANTIC_STORE_LIST (smexpr); ptr; ptr = XEXP (ptr, 1))
- if (XEXP (ptr, 0) == del)
- {
- XEXP (ptr, 0) = insn;
- break;
- }
-
- /* Move the notes from the deleted insn to its replacement, and patch
- up the LIBCALL notes. */
- REG_NOTES (insn) = REG_NOTES (del);
-
- note = find_reg_note (insn, REG_RETVAL, NULL_RTX);
- if (note)
- {
- pair = XEXP (note, 0);
- note = find_reg_note (pair, REG_LIBCALL, NULL_RTX);
- XEXP (note, 0) = insn;
- }
- note = find_reg_note (insn, REG_LIBCALL, NULL_RTX);
- if (note)
- {
- pair = XEXP (note, 0);
- note = find_reg_note (pair, REG_RETVAL, NULL_RTX);
- XEXP (note, 0) = insn;
- }
-
- /* Emit the insn AFTER all the notes are transferred.
- This is cheaper since we avoid df rescanning for the note change. */
- insn = emit_insn_after (insn, del);
-
- if (dump_file)
- {
- fprintf (dump_file,
- "STORE_MOTION delete insn in BB %d:\n ", bb->index);
- print_inline_rtx (dump_file, del, 6);
- fprintf (dump_file, "\nSTORE MOTION replaced with insn:\n ");
- print_inline_rtx (dump_file, insn, 6);
- fprintf (dump_file, "\n");
- }
-
- delete_insn (del);
-
- /* Now we must handle REG_EQUAL notes whose contents is equal to the mem;
- they are no longer accurate provided that they are reached by this
- definition, so drop them. */
- for (; insn != NEXT_INSN (BB_END (bb)); insn = NEXT_INSN (insn))
- if (INSN_P (insn))
- {
- set = single_set (insn);
- if (!set)
- continue;
- if (expr_equiv_p (SET_DEST (set), mem))
- return;
- note = find_reg_equal_equiv_note (insn);
- if (!note || !expr_equiv_p (XEXP (note, 0), mem))
- continue;
-
- if (dump_file)
- fprintf (dump_file, "STORE_MOTION drop REG_EQUAL note at insn %d:\n",
- INSN_UID (insn));
- remove_note (insn, note);
- }
- remove_reachable_equiv_notes (bb, smexpr);
-}
-
-
-/* Delete a store, but copy the value that would have been stored into
- the reaching_reg for later storing. */
-
-static void
-delete_store (struct ls_expr * expr, basic_block bb)
-{
- rtx reg, i, del;
-
- if (expr->reaching_reg == NULL_RTX)
- expr->reaching_reg = gen_reg_rtx (GET_MODE (expr->pattern));
-
- reg = expr->reaching_reg;
-
- for (i = AVAIL_STORE_LIST (expr); i; i = XEXP (i, 1))
- {
- del = XEXP (i, 0);
- if (BLOCK_FOR_INSN (del) == bb)
- {
- /* We know there is only one since we deleted redundant
- ones during the available computation. */
- replace_store_insn (reg, del, bb, expr);
- break;
- }
- }
-}
-
-/* Free memory used by store motion. */
-
-static void
-free_store_memory (void)