#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"
#define ABSTRACTABLE_INSN_P(X) (INSN_P (X) && !JUMP_P (X))
#define HASH_INIT 1023
#ifndef SEQ_CALL_COST_MULTIPLIER
#define SEQ_CALL_COST_MULTIPLIER 2
#endif
#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); \
} \
}
typedef struct matching_seq_def
{
rtx insn;
unsigned long idx;
int matching_length;
int abstracted_length;
int cost;
struct matching_seq_def *next_matching_seq;
} *matching_seq;
typedef struct pattern_seq_def
{
rtx insn;
unsigned long idx;
int gain;
int abstracted_length;
int cost;
rtx link_reg;
matching_seq matching_seqs;
struct pattern_seq_def *next_pattern_seq;
} *pattern_seq;
typedef struct seq_block_def
{
int length;
rtx label;
matching_seq matching_seqs;
struct seq_block_def *next_seq_block;
} *seq_block;
typedef struct hash_bucket_def
{
unsigned int hash;
htab_t seq_candidates;
} *p_hash_bucket;
typedef struct hash_elem_def
{
unsigned long idx;
rtx insn;
int length;
} *p_hash_elem;
static htab_t hash_buckets;
static pattern_seq pattern_seqs;
static seq_block seq_blocks;
static int seq_call_cost;
static int seq_jump_cost;
static int seq_return_cost;
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;
}
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;
}
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;
tmp_bucket.hash = compute_hash (insn);
bucket = htab_find (hash_buckets, &tmp_bucket);
if (bucket)
{
tmp_elem.insn = insn;
elem = htab_find (bucket->seq_candidates, &tmp_elem);
if (elem)
cost = elem->length;
}
if (cost == -1)
{
cost = get_attr_length (insn);
if (elem)
elem->length = cost;
}
return cost != 0 ? cost : COSTS_N_INSNS (1);
}
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);
}
}
static void
match_seqs (p_hash_elem e0, p_hash_elem e1)
{
int len;
int cost;
matching_seq mseq, p_prev, p_next;
matching_length (e0->insn, e1->insn, &len, &cost);
if (cost <= seq_call_cost)
return;
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;
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;
}
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;
}
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;
}
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;
bitmap_initialize (&stack_reg_live, NULL);
FOR_EACH_BB (bb)
{
regset_head live;
struct propagate_block_info *pbi;
rtx 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);
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);
}
CLEAR_REG_SET (&live);
free_propagate_block_info (pbi);
}
#endif
pattern_seqs = 0;
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
bitmap_clear (&stack_reg_live);
#endif
}
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]);
}
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;
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);
for (x = BB_END (bb); x != insn;)
x = propagate_one_insn (pbi, x);
renumbered_reg_set_to_hard_reg_set (&hlive, &live);
AND_COMPL_HARD_REG_SET (*regs, hlive);
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_propagate_block_info (pbi);
CLEAR_REG_SET (&live);
}
static void
recompute_gain_for_pattern_seq (pattern_seq pseq)
{
matching_seq mseq;
rtx x;
int i;
int hascall;
HARD_REG_SET linkregs;
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);
for (mseq = pseq->matching_seqs; mseq; mseq = mseq->next_matching_seq)
{
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;
RECOMPUTE_COST (mseq);
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;
}
}
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;
}
RECOMPUTE_COST (pseq);
if (pseq->cost <= seq_call_cost)
{
pseq->gain = -1;
return;
}
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);
}
if (mseq->cost > seq_call_cost)
pseq->gain += mseq->cost - seq_call_cost;
}
if (pseq->gain <= 0)
return;
clear_regs_live_in_seq (&linkregs, pseq->insn, pseq->abstracted_length);
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);
}
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);
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
if (TEST_HARD_REG_BIT (linkregs, i))
{
pseq->link_reg = gen_rtx_REG (Pmode, i);
break;
}
if (!pseq->link_reg)
pseq->gain = 0;
}
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);
}
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);
}
}
}
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);
(*pseq)->gain = 0;
}
else
{
if (mlen < (*mseq)->matching_length)
{
(*mseq)->cost = mcost;
(*mseq)->matching_length = mlen;
(*pseq)->gain = 0;
}
mseq = &(*mseq)->next_matching_seq;
}
}
pseq = &(*pseq)->next_pattern_seq;
}
}
len--;
insn = prev_insn_in_block (insn);
}
}
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;
}
static void
determine_seq_blocks (void)
{
seq_block sb;
matching_seq *mseq;
matching_seq m;
seq_blocks = 0;
for (mseq = &pattern_seqs->matching_seqs; *mseq;)
{
if ((*mseq)->cost <= seq_call_cost)
{
mseq = &(*mseq)->next_matching_seq;
continue;
}
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;
}
}
}
m = *mseq;
*mseq = m->next_matching_seq;
m->next_matching_seq = sb->matching_seqs;
sb->matching_seqs = m;
}
}
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;
}
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);
}
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);
}
}
}
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);
retlabel = block_label_after (insn);
LABEL_PRESERVE_P (retlabel) = 1;
retjmp = emit_jump_insn_after (gen_indirect_jump (pattern_seqs->link_reg),
BB_END (bb));
emit_barrier_after (BB_END (bb));
while (EDGE_COUNT (bb->succs) != 0)
remove_edge (EDGE_SUCC (bb, 0));
make_edge (bb, BLOCK_FOR_INSN (retlabel), EDGE_ABNORMAL);
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);
}
saveinsn = emit_insn_after (gen_move_insn (pattern_seqs->link_reg,
gen_symbol_ref_rtx_for_label
(retlabel)), BB_END (bb));
SET_REGNO_REG_SET (bb->il.rtl->global_live_at_end,
REGNO (pattern_seqs->link_reg));
}
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);
retlabel = block_label_after (insn);
LABEL_PRESERVE_P (retlabel) = 1;
for (i = 0; i < sb->length; i++)
insn = prev_insn_in_block (insn);
delete_basic_block (split_block (bb, insn)->dest);
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;
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;
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);
}
}
}
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);
}
}
static void
abstract_best_seq (void)
{
pattern_seq bestpseq;
determine_seq_blocks ();
split_blocks_after_seqs ();
split_pattern_seq ();
erase_matching_seqs ();
free_seq_blocks ();
regs_ever_live[REGNO (pattern_seqs->link_reg)] = 1;
bestpseq = pattern_seqs;
pattern_seqs = bestpseq->next_pattern_seq;
free_pattern_seq (bestpseq);
}
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");
}
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));
}
static unsigned int
htab_hash_bucket (const void *p)
{
p_hash_bucket bucket = (p_hash_bucket) p;
return bucket->hash;
}
static int
htab_eq_bucket (const void *p0, const void *p1)
{
return htab_hash_bucket (p0) == htab_hash_bucket (p1);
}
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);
}
static unsigned int
htab_hash_elem (const void *p)
{
p_hash_elem elem = (p_hash_elem) p;
return htab_hash_pointer (elem->insn);
}
static int
htab_eq_elem (const void *p0, const void *p1)
{
return htab_hash_elem (p0) == htab_hash_elem (p1);
}
static void
htab_del_elem (void *p)
{
p_hash_elem elem = (p_hash_elem) p;
free (elem);
}
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;
tmp_bucket.hash = compute_hash (insn);
bucket = htab_find (hash_buckets, &tmp_bucket);
if (!bucket)
{
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;
}
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);
slot = htab_find_slot (bucket->seq_candidates, elem, INSERT);
*slot = elem;
insn_idx++;
}
}
}
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);
rtx_jump = gen_indirect_jump (reg);
rtx_store = gen_rtx_SET (VOIDmode, reg, gen_symbol_ref_rtx_for_label (label));
rtx_return = gen_jump (label);
seq_jump_cost = compute_rtx_cost (make_jump_insn_raw (rtx_jump));
seq_call_cost = seq_jump_cost + compute_rtx_cost (make_insn_raw (rtx_store));
seq_return_cost = compute_rtx_cost (make_jump_insn_raw (rtx_return));
seq_call_cost = (int)(seq_call_cost * (double)SEQ_CALL_COST_MULTIPLIER);
}
static void
rtl_seqabstr (void)
{
int iter;
hash_buckets = htab_create (HASH_INIT, htab_hash_bucket , htab_eq_bucket ,
htab_del_bucket);
fill_hash_bucket ();
compute_init_costs ();
collect_pattern_seqs ();
dump_pattern_seqs ();
for (iter = 1;; iter++)
{
recompute_gain ();
if (!pattern_seqs)
break;
dump_best_pattern_seq (iter);
update_pattern_seqs ();
abstract_best_seq ();
}
htab_delete (hash_buckets);
if (iter > 1)
{
count_or_remove_death_notes (NULL, 1);
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));
}
}
static bool
gate_rtl_seqabstr (void)
{
return flag_rtl_seqabstr;
}
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));
rtl_seqabstr ();
return 0;
}
struct tree_opt_pass pass_rtl_seqabstr = {
"seqabstr",
gate_rtl_seqabstr,
rest_of_rtl_seqabstr,
NULL,
NULL,
0,
TV_SEQABSTR,
0,
0,
0,
0,
TODO_dump_func |
TODO_ggc_collect,
'Q'
};