aboutsummaryrefslogtreecommitdiffstats
path: root/gcc-4.2.1-5666.3/gcc/rtl-factoring.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc-4.2.1-5666.3/gcc/rtl-factoring.c')
-rw-r--r--gcc-4.2.1-5666.3/gcc/rtl-factoring.c1448
1 files changed, 0 insertions, 1448 deletions
diff --git a/gcc-4.2.1-5666.3/gcc/rtl-factoring.c b/gcc-4.2.1-5666.3/gcc/rtl-factoring.c
deleted file mode 100644
index 8113306e0..000000000
--- a/gcc-4.2.1-5666.3/gcc/rtl-factoring.c
+++ /dev/null
@@ -1,1448 +0,0 @@
-/* RTL factoring (sequence abstraction).
- Copyright (C) 2004, 2005, 2006 Free Software Foundation, Inc.
-
-This file is part of GCC.
-
-GCC is free software; you can redistribute it and/or modify it under
-the terms of the GNU General Public License as published by the Free
-Software Foundation; either version 2, or (at your option) any later
-version.
-
-GCC is distributed in the hope that it will be useful, but WITHOUT ANY
-WARRANTY; without even the implied warranty of MERCHANTABILITY or
-FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
-for more details.
-
-You should have received a copy of the GNU General Public License
-along with GCC; see the file COPYING. If not, write to the Free
-Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
-02110-1301, USA. */
-
-#include "config.h"
-#include "system.h"
-#include "coretypes.h"
-#include "tm.h"
-#include "rtl.h"
-#include "obstack.h"
-#include "basic-block.h"
-#include "resource.h"
-#include "flags.h"
-#include "ggc.h"
-#include "regs.h"
-#include "params.h"
-#include "expr.h"
-#include "tm_p.h"
-#include "tree-pass.h"
-#include "tree-flow.h"
-#include "timevar.h"
-#include "output.h"
-#include "addresses.h"
-
-/* Sequence abstraction:
-
- It is a size optimization method. The main idea of this technique is to
- find identical sequences of code, which can be turned into procedures and
- then replace all occurrences with calls to the newly created subroutine.
- It is kind of an opposite of function inlining.
-
- There are four major parts of this file:
-
- sequence fingerprint
- In order to avoid the comparison of every insn with every other, hash
- value will be designed for every insn by COMPUTE_HASH.
- These hash values are used for grouping the sequence candidates. So
- we only need to compare every insn with every other in same hash group.
-
- FILL_HASH_BUCKET creates all hash values and stores into HASH_BUCKETS.
- The result is used by COLLECT_PATTERN_SEQS.
-
- code matching
- In code matching the algorithm compares every two possible sequence
- candidates which last insns are in the same hash group. If these
- sequences are identical they will be stored and do further searches for
- finding more sequences which are identical with the first one.
-
- COLLECT_PATTERN_SEQS does the code matching and stores the results into
- PATTERN_SEQS.
-
- gain computation
- This part computes the gain of abstraction which could be archived when
- turning the pattern sequence into a pseudo-function and its matching
- sequences into pseudo-calls. After it the most effective sequences will
- be marked for abstraction.
-
- RECOMPUTE_GAIN does the gain computation. The sequences with the maximum
- gain is on the top of PATTERN_SEQS.
-
- abstract code
- This part turns the pattern sequence into a pseudo-function and its
- matching sequences into pseudo-calls.
-
- ABSTRACT_BEST_SEQ does the code merging.
-
-
- C code example:
-
- // Original source // After sequence abstraction
- { {
- void *jump_label;
- ... ...
- jump_label = &&exit_0;
- entry_0:
- I0; I0;
- I1; I1;
- I2; I2;
- I3; I3;
- goto *jump_label;
- exit_0:
- ... ...
- jump_label = &&exit_1;
- goto entry_0;
- I0;
- I1;
- I2;
- I3;
- exit_1:
- ... ...
- jump_label = &&exit_2;
- goto entry_0;
- I0;
- I1;
- I2;
- I3;
- exit_2:
- ... ...
- jump_label = &&exit_3;
- goto entry_0;
- I0;
- I1;
- I2;
- I3;
- exit_3:
- ... ...
- } }
-
-
- TODO:
- - Use REG_ALLOC_ORDER when choosing link register.
- - Handle JUMP_INSNs. Also handle volatile function calls (handle them
- similar to unconditional jumps.)
- - Test command line option -fpic.
-*/
-
-/* Predicate yielding nonzero iff X is an abstractable insn. Non-jump insns are
- abstractable. */
-#define ABSTRACTABLE_INSN_P(X) (INSN_P (X) && !JUMP_P (X))
-
-/* First parameter of the htab_create function call. */
-#define HASH_INIT 1023
-
-/* Multiplier for cost of sequence call to avoid abstracting short
- sequences. */
-#ifndef SEQ_CALL_COST_MULTIPLIER
-#define SEQ_CALL_COST_MULTIPLIER 2
-#endif
-
-/* Recomputes the cost of MSEQ pattern/matching sequence. */
-#define RECOMPUTE_COST(SEQ) \
-{ \
- int l; \
- rtx x = SEQ->insn; \
- SEQ->cost = 0; \
- for (l = 0; l < SEQ->abstracted_length; l++) \
- { \
- SEQ->cost += compute_rtx_cost (x); \
- x = prev_insn_in_block (x); \
- } \
-}
-
-/* A sequence matching a pattern sequence. */
-typedef struct matching_seq_def
-{
- /* The last insn in the matching sequence. */
- rtx insn;
-
- /* Index of INSN instruction. */
- unsigned long idx;
-
- /* The number of insns matching in this sequence and the pattern sequence.
- */
- int matching_length;
-
- /* The number of insns selected to abstract from this sequence. Less than
- or equal to MATCHING_LENGTH. */
- int abstracted_length;
-
- /* The cost of the sequence. */
- int cost;
-
- /* The next sequence in the chain matching the same pattern. */
- struct matching_seq_def *next_matching_seq;
-} *matching_seq;
-
-
-/* A pattern instruction sequence. */
-typedef struct pattern_seq_def
-{
- /* The last insn in the pattern sequence. */
- rtx insn;
-
- /* Index of INSN instruction. */
- unsigned long idx;
-
- /* The gain of transforming the pattern sequence into a pseudo-function and
- the matching sequences into pseudo-calls. */
- int gain;
-
- /* The maximum of the ABSTRACTED_LENGTH of the matching sequences. */
- int abstracted_length;
-
- /* The cost of the sequence. */
- int cost;
-
- /* The register used to hold the return address during the pseudo-call. */
- rtx link_reg;
-
- /* The sequences matching this pattern. */
- matching_seq matching_seqs;
-
- /* The next pattern sequence in the chain. */
- struct pattern_seq_def *next_pattern_seq;
-} *pattern_seq;
-
-
-/* A block of a pattern sequence. */
-typedef struct seq_block_def
-{
- /* The number of insns in the block. */
- int length;
-
- /* The code_label of the block. */
- rtx label;
-
- /* The sequences entering the pattern sequence at LABEL. */
- matching_seq matching_seqs;
-
- /* The next block in the chain. The blocks are sorted by LENGTH in
- ascending order. */
- struct seq_block_def *next_seq_block;
-} *seq_block;
-
-/* Contains same sequence candidates for further searching. */
-typedef struct hash_bucket_def
-{
- /* The hash value of the group. */
- unsigned int hash;
-
- /* List of sequence candidates. */
- htab_t seq_candidates;
-} *p_hash_bucket;
-
-/* Contains the last insn of the sequence, and its index value. */
-typedef struct hash_elem_def
-{
- /* Unique index; ordered by FILL_HASH_BUCKET. */
- unsigned long idx;
-
- /* The last insn in the sequence. */
- rtx insn;
-
- /* The cached length of the insn. */
- int length;
-} *p_hash_elem;
-
-/* The list of same sequence candidates. */
-static htab_t hash_buckets;
-
-/* The pattern sequences collected from the current functions. */
-static pattern_seq pattern_seqs;
-
-/* The blocks of the current pattern sequence. */
-static seq_block seq_blocks;
-
-/* Cost of calling sequence. */
-static int seq_call_cost;
-
-/* Cost of jump. */
-static int seq_jump_cost;
-
-/* Cost of returning. */
-static int seq_return_cost;
-
-/* Returns the first insn preceding INSN for which INSN_P is true and belongs to
- the same basic block. Returns NULL_RTX if no such insn can be found. */
-
-static rtx
-prev_insn_in_block (rtx insn)
-{
- basic_block bb = BLOCK_FOR_INSN (insn);
-
- if (!bb)
- return NULL_RTX;
-
- while (insn != BB_HEAD (bb))
- {
- insn = PREV_INSN (insn);
- if (INSN_P (insn))
- return insn;
- }
- return NULL_RTX;
-}
-
-/* Returns the hash value of INSN. */
-
-static unsigned int
-compute_hash (rtx insn)
-{
- unsigned int hash = 0;
- rtx prev;
-
- hash = INSN_CODE (insn) * 100;
-
- prev = prev_insn_in_block (insn);
- if (prev)
- hash += INSN_CODE (prev);
-
- return hash;
-}
-
-/* Compute the cost of INSN rtx for abstraction. */
-
-static int
-compute_rtx_cost (rtx insn)
-{
- struct hash_bucket_def tmp_bucket;
- p_hash_bucket bucket;
- struct hash_elem_def tmp_elem;
- p_hash_elem elem = NULL;
- int cost = -1;
-
- /* Compute hash value for INSN. */
- tmp_bucket.hash = compute_hash (insn);
-
- /* Select the hash group. */
- bucket = htab_find (hash_buckets, &tmp_bucket);
-
- if (bucket)
- {
- tmp_elem.insn = insn;
-
- /* Select the insn. */
- elem = htab_find (bucket->seq_candidates, &tmp_elem);
-
- /* If INSN is parsed the cost will be the cached length. */
- if (elem)
- cost = elem->length;
- }
-
- /* If we can't parse the INSN cost will be the instruction length. */
- if (cost == -1)
- {
- cost = get_attr_length (insn);
-
- /* Cache the length. */
- if (elem)
- elem->length = cost;
- }
-
- /* If we can't get an accurate estimate for a complex instruction,
- assume that it has the same cost as a single fast instruction. */
- return cost != 0 ? cost : COSTS_N_INSNS (1);
-}
-
-/* Determines the number of common insns in the sequences ending in INSN1 and
- INSN2. Returns with LEN number of common insns and COST cost of sequence.
-*/
-
-static void
-matching_length (rtx insn1, rtx insn2, int* len, int* cost)
-{
- rtx x1;
- rtx x2;
-
- x1 = insn1;
- x2 = insn2;
- *len = 0;
- *cost = 0;
- while (x1 && x2 && (x1 != insn2) && (x2 != insn1)
- && rtx_equal_p (PATTERN (x1), PATTERN (x2)))
- {
- (*len)++;
- (*cost) += compute_rtx_cost (x1);
- x1 = prev_insn_in_block (x1);
- x2 = prev_insn_in_block (x2);
- }
-}
-
-/* Adds E0 as a pattern sequence to PATTERN_SEQS with E1 as a matching
- sequence. */
-
-static void
-match_seqs (p_hash_elem e0, p_hash_elem e1)
-{
- int len;
- int cost;
- matching_seq mseq, p_prev, p_next;
-
- /* Determines the cost of the sequence and return without doing anything
- if it is too small to produce any gain. */
- matching_length (e0->insn, e1->insn, &len, &cost);
- if (cost <= seq_call_cost)
- return;
-
- /* Prepend a new PATTERN_SEQ to PATTERN_SEQS if the last pattern sequence
- does not end in E0->INSN. This assumes that once the E0->INSN changes
- the old value will never appear again. */
- if (!pattern_seqs || pattern_seqs->insn != e0->insn)
- {
- pattern_seq pseq =
- (pattern_seq) xmalloc (sizeof (struct pattern_seq_def));
- pseq->insn = e0->insn;
- pseq->idx = e0->idx;
- pseq->gain = 0; /* Set to zero to force recomputing. */
- pseq->abstracted_length = 0;
- pseq->cost = 0;
- pseq->link_reg = NULL_RTX;
- pseq->matching_seqs = NULL;
- pseq->next_pattern_seq = pattern_seqs;
- pattern_seqs = pseq;
- }
-
- /* Find the position of E1 in the matching sequences list. */
- p_prev = NULL;
- p_next = pattern_seqs->matching_seqs;
- while (p_next && p_next->idx < e1->idx)
- {
- p_prev = p_next;
- p_next = p_next->next_matching_seq;
- }
-
- /* Add a new E1 matching sequence to the pattern sequence. We know that
- it ends in E0->INSN. */
- mseq = (matching_seq) xmalloc (sizeof (struct matching_seq_def));
- mseq->insn = e1->insn;
- mseq->idx = e1->idx;
- mseq->matching_length = len;
- mseq->abstracted_length = 0;
- mseq->cost = cost;
-
- if (p_prev == NULL)
- pattern_seqs->matching_seqs = mseq;
- else
- p_prev->next_matching_seq = mseq;
- mseq->next_matching_seq = p_next;
-}
-
-/* Collects all pattern sequences and their matching sequences and puts them
- into PATTERN_SEQS. */
-
-static void
-collect_pattern_seqs (void)
-{
- htab_iterator hti0, hti1, hti2;
- p_hash_bucket hash_bucket;
- p_hash_elem e0, e1;
-#ifdef STACK_REGS
- basic_block bb;
- bitmap_head stack_reg_live;
-
- /* Extra initialization step to ensure that no stack registers (if present)
- are live across abnormal edges. Set a flag in STACK_REG_LIVE for an insn
- if a stack register is live after the insn. */
- bitmap_initialize (&stack_reg_live, NULL);
-
- FOR_EACH_BB (bb)
- {
- regset_head live;
- struct propagate_block_info *pbi;
- rtx insn;
-
- /* Initialize liveness propagation. */
- INIT_REG_SET (&live);
- COPY_REG_SET (&live, bb->il.rtl->global_live_at_end);
- pbi = init_propagate_block_info (bb, &live, NULL, NULL, 0);
-
- /* Propagate liveness info and mark insns where a stack reg is live. */
- insn = BB_END (bb);
- while (1)
- {
- int reg;
- for (reg = FIRST_STACK_REG; reg <= LAST_STACK_REG; reg++)
- {
- if (REGNO_REG_SET_P (&live, reg))
- {
- bitmap_set_bit (&stack_reg_live, INSN_UID (insn));
- break;
- }
- }
-
- if (insn == BB_HEAD (bb))
- break;
- insn = propagate_one_insn (pbi, insn);
- }
-
- /* Free unused data. */
- CLEAR_REG_SET (&live);
- free_propagate_block_info (pbi);
- }
-#endif
-
- /* Initialize PATTERN_SEQS to empty. */
- pattern_seqs = 0;
-
- /* Try to match every abstractable insn with every other insn in the same
- HASH_BUCKET. */
-
- FOR_EACH_HTAB_ELEMENT (hash_buckets, hash_bucket, p_hash_bucket, hti0)
- if (htab_elements (hash_bucket->seq_candidates) > 1)
- FOR_EACH_HTAB_ELEMENT (hash_bucket->seq_candidates, e0, p_hash_elem, hti1)
- FOR_EACH_HTAB_ELEMENT (hash_bucket->seq_candidates, e1, p_hash_elem,
- hti2)
- if (e0 != e1
-#ifdef STACK_REGS
- && !bitmap_bit_p (&stack_reg_live, INSN_UID (e0->insn))
- && !bitmap_bit_p (&stack_reg_live, INSN_UID (e1->insn))
-#endif
- )
- match_seqs (e0, e1);
-#ifdef STACK_REGS
- /* Free unused data. */
- bitmap_clear (&stack_reg_live);
-#endif
-}
-
-/* Transforms a regset to a HARD_REG_SET. Every hard register in REGS is added
- to hregs. Additionally, the hard counterpart of every renumbered pseudo
- register is also added. */
-
-static void
-renumbered_reg_set_to_hard_reg_set (HARD_REG_SET * hregs, regset regs)
-{
- int r;
-
- REG_SET_TO_HARD_REG_SET (*hregs, regs);
- for (r = FIRST_PSEUDO_REGISTER; r < max_regno; r++)
- if (REGNO_REG_SET_P (regs, r) && reg_renumber[r] >= 0)
- SET_HARD_REG_BIT (*hregs, reg_renumber[r]);
-}
-
-/* Clears the bits in REGS for all registers, which are live in the sequence
- give by its last INSN and its LENGTH. */
-
-static void
-clear_regs_live_in_seq (HARD_REG_SET * regs, rtx insn, int length)
-{
- basic_block bb;
- regset_head live;
- HARD_REG_SET hlive;
- struct propagate_block_info *pbi;
- rtx x;
- int i;
-
- /* Initialize liveness propagation. */
- bb = BLOCK_FOR_INSN (insn);
- INIT_REG_SET (&live);
- COPY_REG_SET (&live, bb->il.rtl->global_live_at_end);
- pbi = init_propagate_block_info (bb, &live, NULL, NULL, 0);
-
- /* Propagate until INSN if found. */
- for (x = BB_END (bb); x != insn;)
- x = propagate_one_insn (pbi, x);
-
- /* Clear registers live after INSN. */
- renumbered_reg_set_to_hard_reg_set (&hlive, &live);
- AND_COMPL_HARD_REG_SET (*regs, hlive);
-
- /* Clear registers live in and before the sequence. */
- for (i = 0; i < length;)
- {
- rtx prev = propagate_one_insn (pbi, x);
-
- if (INSN_P (x))
- {
- renumbered_reg_set_to_hard_reg_set (&hlive, &live);
- AND_COMPL_HARD_REG_SET (*regs, hlive);
- i++;
- }
-
- x = prev;
- }
-
- /* Free unused data. */
- free_propagate_block_info (pbi);
- CLEAR_REG_SET (&live);
-}
-
-/* Computes the gain of turning PSEQ into a pseudo-function and its matching
- sequences into pseudo-calls. Also computes and caches the number of insns to
- abstract from the matching sequences. */
-
-static void
-recompute_gain_for_pattern_seq (pattern_seq pseq)
-{
- matching_seq mseq;
- rtx x;
- int i;
- int hascall;
- HARD_REG_SET linkregs;
-
- /* Initialize data. */
- SET_HARD_REG_SET (linkregs);
- pseq->link_reg = NULL_RTX;
- pseq->abstracted_length = 0;
-
- pseq->gain = -(seq_call_cost - seq_jump_cost + seq_return_cost);
-
- /* Determine ABSTRACTED_LENGTH and COST for matching sequences of PSEQ.
- ABSTRACTED_LENGTH may be less than MATCHING_LENGTH if sequences in the
- same block overlap. */
-
- for (mseq = pseq->matching_seqs; mseq; mseq = mseq->next_matching_seq)
- {
- /* Determine ABSTRACTED_LENGTH. */
- if (mseq->next_matching_seq)
- mseq->abstracted_length = (int)(mseq->next_matching_seq->idx -
- mseq->idx);
- else
- mseq->abstracted_length = mseq->matching_length;
-
- if (mseq->abstracted_length > mseq->matching_length)
- mseq->abstracted_length = mseq->matching_length;
-
- /* Compute the cost of sequence. */
- RECOMPUTE_COST (mseq);
-
- /* If COST is big enough registers live in this matching sequence
- should not be used as a link register. Also set ABSTRACTED_LENGTH
- of PSEQ. */
- if (mseq->cost > seq_call_cost)
- {
- clear_regs_live_in_seq (&linkregs, mseq->insn,
- mseq->abstracted_length);
- if (mseq->abstracted_length > pseq->abstracted_length)
- pseq->abstracted_length = mseq->abstracted_length;
- }
- }
-
- /* Modify ABSTRACTED_LENGTH of PSEQ if pattern sequence overlaps with one
- of the matching sequences. */
- for (mseq = pseq->matching_seqs; mseq; mseq = mseq->next_matching_seq)
- {
- x = pseq->insn;
- for (i = 0; (i < pseq->abstracted_length) && (x != mseq->insn); i++)
- x = prev_insn_in_block (x);
- pseq->abstracted_length = i;
- }
-
- /* Compute the cost of pattern sequence. */
- RECOMPUTE_COST (pseq);
-
- /* No gain if COST is too small. */
- if (pseq->cost <= seq_call_cost)
- {
- pseq->gain = -1;
- return;
- }
-
- /* Ensure that no matching sequence is longer than the pattern sequence. */
- for (mseq = pseq->matching_seqs; mseq; mseq = mseq->next_matching_seq)
- {
- if (mseq->abstracted_length > pseq->abstracted_length)
- {
- mseq->abstracted_length = pseq->abstracted_length;
- RECOMPUTE_COST (mseq);
- }
- /* Once the length is stabilizing the gain can be calculated. */
- if (mseq->cost > seq_call_cost)
- pseq->gain += mseq->cost - seq_call_cost;
- }
-
- /* No need to do further work if there is no gain. */
- if (pseq->gain <= 0)
- return;
-
- /* Should not use registers live in the pattern sequence as link register.
- */
- clear_regs_live_in_seq (&linkregs, pseq->insn, pseq->abstracted_length);
-
- /* Determine whether pattern sequence contains a call_insn. */
- hascall = 0;
- x = pseq->insn;
- for (i = 0; i < pseq->abstracted_length; i++)
- {
- if (CALL_P (x))
- {
- hascall = 1;
- break;
- }
- x = prev_insn_in_block (x);
- }
-
- /* Should not use a register as a link register if - it is a fixed
- register, or - the sequence contains a call insn and the register is a
- call used register, or - the register needs to be saved if used in a
- function but was not used before (since saving it can invalidate already
- computed frame pointer offsets), or - the register cannot be used as a
- base register. */
-
- for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
- if (fixed_regs[i]
-#ifdef REGNO_OK_FOR_INDIRECT_JUMP_P
- || (!REGNO_OK_FOR_INDIRECT_JUMP_P (i, Pmode))
-#else
- || (!ok_for_base_p_1 (i, Pmode, MEM, SCRATCH))
- || (!reg_class_subset_p (REGNO_REG_CLASS (i),
- base_reg_class (VOIDmode, MEM, SCRATCH)))
-#endif
- || (hascall && call_used_regs[i])
- || (!call_used_regs[i] && !regs_ever_live[i]))
- CLEAR_HARD_REG_BIT (linkregs, i);
-
- /* Find an appropriate register to be used as the link register. */
- for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
- if (TEST_HARD_REG_BIT (linkregs, i))
- {
- pseq->link_reg = gen_rtx_REG (Pmode, i);
- break;
- }
-
- /* Abstraction is not possible if no link register is available, so set
- gain to 0. */
- if (!pseq->link_reg)
- pseq->gain = 0;
-}
-
-/* Deallocates memory occupied by PSEQ and its matching seqs. */
-
-static void
-free_pattern_seq (pattern_seq pseq)
-{
- while (pseq->matching_seqs)
- {
- matching_seq mseq = pseq->matching_seqs;
- pseq->matching_seqs = mseq->next_matching_seq;
- free (mseq);
- }
- free (pseq);
-}
-
-
-/* Computes the gain for pattern sequences. Pattern sequences producing no gain
- are deleted. The pattern sequence with the biggest gain is moved to the first
- place of PATTERN_SEQS. */
-
-static void
-recompute_gain (void)
-{
- pattern_seq *pseq;
- int maxgain;
-
- maxgain = 0;
- for (pseq = &pattern_seqs; *pseq;)
- {
- if ((*pseq)->gain <= 0)
- recompute_gain_for_pattern_seq (*pseq);
-
- if ((*pseq)->gain > 0)
- {
- if ((*pseq)->gain > maxgain)
- {
- pattern_seq temp = *pseq;
- (*pseq) = temp->next_pattern_seq;
- temp->next_pattern_seq = pattern_seqs;
- pattern_seqs = temp;
- maxgain = pattern_seqs->gain;
- }
- else
- {
- pseq = &(*pseq)->next_pattern_seq;
- }
- }
- else
- {
- pattern_seq temp = *pseq;
- *pseq = temp->next_pattern_seq;
- free_pattern_seq (temp);
- }
- }
-}
-
-/* Updated those pattern sequences and matching sequences, which overlap with
- the sequence given by INSN and LEN. Deletes sequences shrinking below a
- limit. */
-
-static void
-erase_from_pattern_seqs (rtx insn, int len)
-{
- pattern_seq *pseq;
- matching_seq *mseq;
- rtx x;
- int plen, mlen;
- int pcost, mcost;
-
- while (len > 0)
- {
- for (pseq = &pattern_seqs; *pseq;)
- {
- plen = 0;
- pcost = 0;
- for (x = (*pseq)->insn; x && (x != insn);
- x = prev_insn_in_block (x))
- {
- plen++;
- pcost += compute_rtx_cost (x);
- }
-
- if (pcost <= seq_call_cost)
- {
- pattern_seq temp = *pseq;
- *pseq = temp->next_pattern_seq;
- free_pattern_seq (temp);
- }
- else
- {
- for (mseq = &(*pseq)->matching_seqs; *mseq;)
- {
- mlen = 0;
- mcost = 0;
- for (x = (*mseq)->insn;
- x && (x != insn) && (mlen < plen)
- && (mlen < (*mseq)->matching_length);
- x = prev_insn_in_block (x))
- {
- mlen++;
- mcost += compute_rtx_cost (x);
- }
-
- if (mcost <= seq_call_cost)
- {
- matching_seq temp = *mseq;
- *mseq = temp->next_matching_seq;
- free (temp);
- /* Set to 0 to force gain recomputation. */
- (*pseq)->gain = 0;
- }
- else
- {
- if (mlen < (*mseq)->matching_length)
- {
- (*mseq)->cost = mcost;
- (*mseq)->matching_length = mlen;
- /* Set to 0 to force gain recomputation. */
- (*pseq)->gain = 0;
- }
- mseq = &(*mseq)->next_matching_seq;
- }
- }
-
- pseq = &(*pseq)->next_pattern_seq;
- }
- }
-
- len--;
- insn = prev_insn_in_block (insn);
- }
-}
-
-/* Updates those pattern sequences and matching sequences, which overlap with
- the pattern sequence with the biggest gain and its matching sequences. */
-
-static void
-update_pattern_seqs (void)
-{
- pattern_seq bestpseq;
- matching_seq mseq;
-
- bestpseq = pattern_seqs;
- pattern_seqs = bestpseq->next_pattern_seq;
-
- for (mseq = bestpseq->matching_seqs; mseq; mseq = mseq->next_matching_seq)
- if (mseq->cost > seq_call_cost)
- erase_from_pattern_seqs (mseq->insn, mseq->abstracted_length);
- erase_from_pattern_seqs (bestpseq->insn, bestpseq->abstracted_length);
-
- bestpseq->next_pattern_seq = pattern_seqs;
- pattern_seqs = bestpseq;
-}
-
-/* Groups together those matching sequences of the best pattern sequence, which
- have the same ABSTRACTED_LENGTH and puts these groups in ascending order.
- SEQ_BLOCKS contains the result. */
-
-static void
-determine_seq_blocks (void)
-{
- seq_block sb;
- matching_seq *mseq;
- matching_seq m;
-
- /* Initialize SEQ_BLOCKS to empty. */
- seq_blocks = 0;
-
- /* Process all matching sequences. */
- for (mseq = &pattern_seqs->matching_seqs; *mseq;)
- {
- /* Deal only with matching sequences being long enough. */
- if ((*mseq)->cost <= seq_call_cost)
- {
- mseq = &(*mseq)->next_matching_seq;
- continue;
- }
-
- /* Ensure that SB contains a seq_block with the appropriate length.
- Insert a new seq_block if necessary. */
- if (!seq_blocks || ((*mseq)->abstracted_length < seq_blocks->length))
- {
- sb = (seq_block) xmalloc (sizeof (struct seq_block_def));
- sb->length = (*mseq)->abstracted_length;
- sb->label = NULL_RTX;
- sb->matching_seqs = 0;
- sb->next_seq_block = seq_blocks;
- seq_blocks = sb;
- }
- else
- {
- for (sb = seq_blocks; sb; sb = sb->next_seq_block)
- {
- if ((*mseq)->abstracted_length == sb->length)
- break;
- if (!sb->next_seq_block
- || ((*mseq)->abstracted_length <
- sb->next_seq_block->length))
- {
- seq_block temp =
- (seq_block) xmalloc (sizeof (struct seq_block_def));
- temp->length = (*mseq)->abstracted_length;
- temp->label = NULL_RTX;
- temp->matching_seqs = 0;
- temp->next_seq_block = sb->next_seq_block;
- sb->next_seq_block = temp;
- }
- }
- }
-
- /* Remove the matching sequence from the linked list of the pattern
- sequence and link it to SB. */
- m = *mseq;
- *mseq = m->next_matching_seq;
- m->next_matching_seq = sb->matching_seqs;
- sb->matching_seqs = m;
- }
-}
-
-/* Builds a symbol_ref for LABEL. */
-
-static rtx
-gen_symbol_ref_rtx_for_label (rtx label)
-{
- char name[20];
- rtx sym;
-
- ASM_GENERATE_INTERNAL_LABEL (name, "L", CODE_LABEL_NUMBER (label));
- sym = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (name));
- SYMBOL_REF_FLAGS (sym) = SYMBOL_FLAG_LOCAL;
- return sym;
-}
-
-/* Ensures that INSN is the last insn in its block and returns the block label
- of the next block. */
-
-static rtx
-block_label_after (rtx insn)
-{
- basic_block bb = BLOCK_FOR_INSN (insn);
- if ((insn == BB_END (bb)) && (bb->next_bb != EXIT_BLOCK_PTR))
- return block_label (bb->next_bb);
- else
- return block_label (split_block (bb, insn)->dest);
-}
-
-/* Ensures that the last insns of the best pattern and its matching sequences
- are the last insns in their block. Additionally, extends the live set at the
- end of the pattern sequence with the live sets at the end of the matching
- sequences. */
-
-static void
-split_blocks_after_seqs (void)
-{
- seq_block sb;
- matching_seq mseq;
-
- block_label_after (pattern_seqs->insn);
- for (sb = seq_blocks; sb; sb = sb->next_seq_block)
- {
- for (mseq = sb->matching_seqs; mseq; mseq = mseq->next_matching_seq)
- {
- block_label_after (mseq->insn);
- IOR_REG_SET (BLOCK_FOR_INSN (pattern_seqs->insn)->
- il.rtl->global_live_at_end,
- BLOCK_FOR_INSN (mseq->insn)->il.rtl->global_live_at_end);
- }
- }
-}
-
-/* Splits the best pattern sequence according to SEQ_BLOCKS. Emits pseudo-call
- and -return insns before and after the sequence. */
-
-static void
-split_pattern_seq (void)
-{
- rtx insn;
- basic_block bb;
- rtx retlabel, retjmp, saveinsn;
- int i;
- seq_block sb;
-
- insn = pattern_seqs->insn;
- bb = BLOCK_FOR_INSN (insn);
-
- /* Get the label after the sequence. This will be the return address. The
- label will be referenced using a symbol_ref so protect it from
- deleting. */
- retlabel = block_label_after (insn);
- LABEL_PRESERVE_P (retlabel) = 1;
-
- /* Emit an indirect jump via the link register after the sequence acting
- as the return insn. Also emit a barrier and update the basic block. */
- retjmp = emit_jump_insn_after (gen_indirect_jump (pattern_seqs->link_reg),
- BB_END (bb));
- emit_barrier_after (BB_END (bb));
-
- /* Replace all outgoing edges with a new one to the block of RETLABEL. */
- while (EDGE_COUNT (bb->succs) != 0)
- remove_edge (EDGE_SUCC (bb, 0));
- make_edge (bb, BLOCK_FOR_INSN (retlabel), EDGE_ABNORMAL);
-
- /* Split the sequence according to SEQ_BLOCKS and cache the label of the
- resulting basic blocks. */
- i = 0;
- for (sb = seq_blocks; sb; sb = sb->next_seq_block)
- {
- for (; i < sb->length; i++)
- insn = prev_insn_in_block (insn);
-
- sb->label = block_label (split_block (bb, insn)->dest);
- }
-
- /* Emit an insn saving the return address to the link register before the
- sequence. */
- saveinsn = emit_insn_after (gen_move_insn (pattern_seqs->link_reg,
- gen_symbol_ref_rtx_for_label
- (retlabel)), BB_END (bb));
- /* Update liveness info. */
- SET_REGNO_REG_SET (bb->il.rtl->global_live_at_end,
- REGNO (pattern_seqs->link_reg));
-}
-
-/* Deletes the insns of the matching sequences of the best pattern sequence and
- replaces them with pseudo-calls to the pattern sequence. */
-
-static void
-erase_matching_seqs (void)
-{
- seq_block sb;
- matching_seq mseq;
- rtx insn;
- basic_block bb;
- rtx retlabel, saveinsn, callinsn;
- int i;
-
- for (sb = seq_blocks; sb; sb = sb->next_seq_block)
- {
- for (mseq = sb->matching_seqs; mseq; mseq = mseq->next_matching_seq)
- {
- insn = mseq->insn;
- bb = BLOCK_FOR_INSN (insn);
-
- /* Get the label after the sequence. This will be the return
- address. The label will be referenced using a symbol_ref so
- protect it from deleting. */
- retlabel = block_label_after (insn);
- LABEL_PRESERVE_P (retlabel) = 1;
-
- /* Delete the insns of the sequence. */
- for (i = 0; i < sb->length; i++)
- insn = prev_insn_in_block (insn);
- delete_basic_block (split_block (bb, insn)->dest);
-
- /* Emit an insn saving the return address to the link register
- before the deleted sequence. */
- saveinsn = emit_insn_after (gen_move_insn (pattern_seqs->link_reg,
- gen_symbol_ref_rtx_for_label
- (retlabel)),
- BB_END (bb));
- BLOCK_FOR_INSN (saveinsn) = bb;
-
- /* Emit a jump to the appropriate part of the pattern sequence
- after the save insn. Also update the basic block. */
- callinsn = emit_jump_insn_after (gen_jump (sb->label), saveinsn);
- JUMP_LABEL (callinsn) = sb->label;
- LABEL_NUSES (sb->label)++;
- BLOCK_FOR_INSN (callinsn) = bb;
- BB_END (bb) = callinsn;
-
- /* Maintain control flow and liveness information. */
- SET_REGNO_REG_SET (bb->il.rtl->global_live_at_end,
- REGNO (pattern_seqs->link_reg));
- emit_barrier_after (BB_END (bb));
- make_single_succ_edge (bb, BLOCK_FOR_INSN (sb->label), 0);
- IOR_REG_SET (bb->il.rtl->global_live_at_end,
- BLOCK_FOR_INSN (sb->label)->il.rtl->global_live_at_start);
-
- make_edge (BLOCK_FOR_INSN (seq_blocks->label),
- BLOCK_FOR_INSN (retlabel), EDGE_ABNORMAL);
- }
- }
-}
-
-/* Deallocates SEQ_BLOCKS and all the matching sequences. */
-
-static void
-free_seq_blocks (void)
-{
- while (seq_blocks)
- {
- seq_block sb = seq_blocks;
- while (sb->matching_seqs)
- {
- matching_seq mseq = sb->matching_seqs;
- sb->matching_seqs = mseq->next_matching_seq;
- free (mseq);
- }
- seq_blocks = sb->next_seq_block;
- free (sb);
- }
-}
-
-/* Transforms the best pattern sequence into a pseudo-function and its matching
- sequences to pseudo-calls. Afterwards the best pattern sequence is removed
- from PATTERN_SEQS. */
-
-static void
-abstract_best_seq (void)
-{
- pattern_seq bestpseq;
-
- /* Do the abstraction. */
- determine_seq_blocks ();
- split_blocks_after_seqs ();
- split_pattern_seq ();
- erase_matching_seqs ();
- free_seq_blocks ();
-
- /* Record the usage of the link register. */
- regs_ever_live[REGNO (pattern_seqs->link_reg)] = 1;
-
- /* Remove the best pattern sequence. */
- bestpseq = pattern_seqs;
- pattern_seqs = bestpseq->next_pattern_seq;
- free_pattern_seq (bestpseq);
-}
-
-/* Prints info on the pattern sequences to the dump file. */
-
-static void
-dump_pattern_seqs (void)
-{
- pattern_seq pseq;
- matching_seq mseq;
-
- if (!dump_file)
- return;
-
- fprintf (dump_file, ";; Pattern sequences\n");
- for (pseq = pattern_seqs; pseq; pseq = pseq->next_pattern_seq)
- {
- fprintf (dump_file, "Pattern sequence at insn %d matches sequences at",
- INSN_UID (pseq->insn));
- for (mseq = pseq->matching_seqs; mseq; mseq = mseq->next_matching_seq)
- {
- fprintf (dump_file, " insn %d (length %d)", INSN_UID (mseq->insn),
- mseq->matching_length);
- if (mseq->next_matching_seq)
- fprintf (dump_file, ",");
- }
- fprintf (dump_file, ".\n");
- }
- fprintf (dump_file, "\n");
-}
-
-/* Prints info on the best pattern sequence transformed in the ITER-th
- iteration to the dump file. */
-
-static void
-dump_best_pattern_seq (int iter)
-{
- matching_seq mseq;
-
- if (!dump_file)
- return;
-
- fprintf (dump_file, ";; Iteration %d\n", iter);
- fprintf (dump_file,
- "Best pattern sequence with %d gain is at insn %d (length %d).\n",
- pattern_seqs->gain, INSN_UID (pattern_seqs->insn),
- pattern_seqs->abstracted_length);
- fprintf (dump_file, "Matching sequences are at");
- for (mseq = pattern_seqs->matching_seqs; mseq;
- mseq = mseq->next_matching_seq)
- {
- fprintf (dump_file, " insn %d (length %d)", INSN_UID (mseq->insn),
- mseq->abstracted_length);
- if (mseq->next_matching_seq)
- fprintf (dump_file, ",");
- }
- fprintf (dump_file, ".\n");
- fprintf (dump_file, "Using reg %d as link register.\n\n",
- REGNO (pattern_seqs->link_reg));
-}
-
-/* Htab hash function for hash_bucket_def structure. */
-
-static unsigned int
-htab_hash_bucket (const void *p)
-{
- p_hash_bucket bucket = (p_hash_bucket) p;
- return bucket->hash;
-}
-
-/* Htab equal function for hash_bucket_def structure. */
-
-static int
-htab_eq_bucket (const void *p0, const void *p1)
-{
- return htab_hash_bucket (p0) == htab_hash_bucket (p1);
-}
-
-/* Htab delete function for hash_bucket_def structure. */
-
-static void
-htab_del_bucket (void *p)
-{
- p_hash_bucket bucket = (p_hash_bucket) p;
-
- if (bucket->seq_candidates)
- htab_delete (bucket->seq_candidates);
-
- free (bucket);
-}
-
-/* Htab hash function for hash_bucket_def structure. */
-
-static unsigned int
-htab_hash_elem (const void *p)
-{
- p_hash_elem elem = (p_hash_elem) p;
- return htab_hash_pointer (elem->insn);
-}
-
-/* Htab equal function for hash_bucket_def structure. */
-
-static int
-htab_eq_elem (const void *p0, const void *p1)
-{
- return htab_hash_elem (p0) == htab_hash_elem (p1);
-}
-
-/* Htab delete function for hash_bucket_def structure. */
-
-static void
-htab_del_elem (void *p)
-{
- p_hash_elem elem = (p_hash_elem) p;
- free (elem);
-}
-
-/* Creates a hash value for each sequence candidate and saves them
- in HASH_BUCKET. */
-
-static void
-fill_hash_bucket (void)
-{
- basic_block bb;
- rtx insn;
- void **slot;
- p_hash_bucket bucket;
- struct hash_bucket_def tmp_bucket;
- p_hash_elem elem;
- unsigned long insn_idx;
-
- insn_idx = 0;
- FOR_EACH_BB (bb)
- {
- FOR_BB_INSNS_REVERSE (bb, insn)
- {
- if (!ABSTRACTABLE_INSN_P (insn))
- continue;
-
- /* Compute hash value for INSN. */
- tmp_bucket.hash = compute_hash (insn);
-
- /* Select the hash group. */
- bucket = htab_find (hash_buckets, &tmp_bucket);
-
- if (!bucket)
- {
- /* Create a new hash group. */
- bucket = (p_hash_bucket) xcalloc (1,
- sizeof (struct hash_bucket_def));
- bucket->hash = tmp_bucket.hash;
- bucket->seq_candidates = NULL;
-
- slot = htab_find_slot (hash_buckets, &tmp_bucket, INSERT);
- *slot = bucket;
- }
-
- /* Create new list for storing sequence candidates. */
- if (!bucket->seq_candidates)
- bucket->seq_candidates = htab_create (HASH_INIT,
- htab_hash_elem,
- htab_eq_elem,
- htab_del_elem);
-
- elem = (p_hash_elem) xcalloc (1, sizeof (struct hash_elem_def));
- elem->insn = insn;
- elem->idx = insn_idx;
- elem->length = get_attr_length (insn);
-
- /* Insert INSN into BUCKET hash bucket. */
- slot = htab_find_slot (bucket->seq_candidates, elem, INSERT);
- *slot = elem;
-
- insn_idx++;
- }
- }
-}
-
-/* Computes the cost of calling sequence and the cost of return. */
-
-static void
-compute_init_costs (void)
-{
- rtx rtx_jump, rtx_store, rtx_return, reg, label;
- basic_block bb;
-
- FOR_EACH_BB (bb)
- if (BB_HEAD (bb))
- break;
-
- label = block_label (bb);
- reg = gen_rtx_REG (Pmode, 0);
-
- /* Pattern for indirect jump. */
- rtx_jump = gen_indirect_jump (reg);
-
- /* Pattern for storing address. */
- rtx_store = gen_rtx_SET (VOIDmode, reg, gen_symbol_ref_rtx_for_label (label));
-
- /* Pattern for return insn. */
- rtx_return = gen_jump (label);
-
- /* The cost of jump. */
- seq_jump_cost = compute_rtx_cost (make_jump_insn_raw (rtx_jump));
-
- /* The cost of calling sequence. */
- seq_call_cost = seq_jump_cost + compute_rtx_cost (make_insn_raw (rtx_store));
-
- /* The cost of return. */
- seq_return_cost = compute_rtx_cost (make_jump_insn_raw (rtx_return));
-
- /* Simple heuristic for minimal sequence cost. */
- seq_call_cost = (int)(seq_call_cost * (double)SEQ_CALL_COST_MULTIPLIER);
-}
-
-/* Finds equivalent insn sequences in the current function and retains only one
- instance of them which is turned into a pseudo-function. The additional
- copies are erased and replaced by pseudo-calls to the retained sequence. */
-
-static void
-rtl_seqabstr (void)
-{
- int iter;
-
- /* Create a hash list for COLLECT_PATTERN_SEQS. */
- hash_buckets = htab_create (HASH_INIT, htab_hash_bucket , htab_eq_bucket ,
- htab_del_bucket);
- fill_hash_bucket ();
-
- /* Compute the common cost of abstraction. */
- compute_init_costs ();
-
- /* Build an initial set of pattern sequences from the current function. */
- collect_pattern_seqs ();
- dump_pattern_seqs ();
-
- /* Iterate until there are no sequences to abstract. */
- for (iter = 1;; iter++)
- {
- /* Recompute gain for sequences if necessary and select sequence with
- biggest gain. */
- recompute_gain ();
- if (!pattern_seqs)
- break;
- dump_best_pattern_seq (iter);
- /* Update the cached info of the other sequences and force gain
- recomputation where needed. */
- update_pattern_seqs ();
- /* Turn best sequences into pseudo-functions and -calls. */
- abstract_best_seq ();
- }
-
- /* Cleanup hash tables. */
- htab_delete (hash_buckets);
-
- if (iter > 1)
- {
- /* Update notes. */
- count_or_remove_death_notes (NULL, 1);
-
- life_analysis (PROP_DEATH_NOTES | PROP_SCAN_DEAD_CODE
- | PROP_KILL_DEAD_CODE);
-
- /* Extra cleanup. */
- cleanup_cfg (CLEANUP_EXPENSIVE |
- CLEANUP_UPDATE_LIFE |
- (flag_crossjumping ? CLEANUP_CROSSJUMP : 0));
- }
-}
-
-/* The gate function for TREE_OPT_PASS. */
-
-static bool
-gate_rtl_seqabstr (void)
-{
- return flag_rtl_seqabstr;
-}
-
-/* The entry point of the sequence abstraction algorithm. */
-
-static unsigned int
-rest_of_rtl_seqabstr (void)
-{
- life_analysis (PROP_DEATH_NOTES | PROP_SCAN_DEAD_CODE | PROP_KILL_DEAD_CODE);
-
- cleanup_cfg (CLEANUP_EXPENSIVE |
- CLEANUP_UPDATE_LIFE |
- (flag_crossjumping ? CLEANUP_CROSSJUMP : 0));
-
- /* Abstract out common insn sequences. */
- rtl_seqabstr ();
- return 0;
-}
-
-struct tree_opt_pass pass_rtl_seqabstr = {
- "seqabstr", /* name */
- gate_rtl_seqabstr, /* gate */
- rest_of_rtl_seqabstr, /* execute */
- NULL, /* sub */
- NULL, /* next */
- 0, /* static_pass_number */
- TV_SEQABSTR, /* tv_id */
- 0, /* properties_required */
- 0, /* properties_provided */
- 0, /* properties_destroyed */
- 0, /* todo_flags_start */
- TODO_dump_func |
- TODO_ggc_collect, /* todo_flags_finish */
- 'Q' /* letter */
-};