123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353 |
- /* Integrated Register Allocator. Changing code and generating moves.
- Copyright (C) 2006-2015 Free Software Foundation, Inc.
- Contributed by Vladimir Makarov <vmakarov@redhat.com>.
- 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 3, 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 COPYING3. If not see
- <http://www.gnu.org/licenses/>. */
- /* When we have more one region, we need to change the original RTL
- code after coloring. Let us consider two allocnos representing the
- same pseudo-register outside and inside a region respectively.
- They can get different hard-registers. The reload pass works on
- pseudo registers basis and there is no way to say the reload that
- pseudo could be in different registers and it is even more
- difficult to say in what places of the code the pseudo should have
- particular hard-registers. So in this case IRA has to create and
- use a new pseudo-register inside the region and adds code to move
- allocno values on the region's borders. This is done by the code
- in this file.
- The code makes top-down traversal of the regions and generate new
- pseudos and the move code on the region borders. In some
- complicated cases IRA can create a new pseudo used temporarily to
- move allocno values when a swap of values stored in two
- hard-registers is needed (e.g. two allocnos representing different
- pseudos outside region got respectively hard registers 1 and 2 and
- the corresponding allocnos inside the region got respectively hard
- registers 2 and 1). At this stage, the new pseudo is marked as
- spilled.
- IRA still creates the pseudo-register and the moves on the region
- borders even when the both corresponding allocnos were assigned to
- the same hard-register. It is done because, if the reload pass for
- some reason spills a pseudo-register representing the original
- pseudo outside or inside the region, the effect will be smaller
- because another pseudo will still be in the hard-register. In most
- cases, this is better then spilling the original pseudo in its
- whole live-range. If reload does not change the allocation for the
- two pseudo-registers, the trivial move will be removed by
- post-reload optimizations.
- IRA does not generate a new pseudo and moves for the allocno values
- if the both allocnos representing an original pseudo inside and
- outside region assigned to the same hard register when the register
- pressure in the region for the corresponding pressure class is less
- than number of available hard registers for given pressure class.
- IRA also does some optimizations to remove redundant moves which is
- transformed into stores by the reload pass on CFG edges
- representing exits from the region.
- IRA tries to reduce duplication of code generated on CFG edges
- which are enters and exits to/from regions by moving some code to
- the edge sources or destinations when it is possible. */
- #include "config.h"
- #include "system.h"
- #include "coretypes.h"
- #include "tm.h"
- #include "regs.h"
- #include "rtl.h"
- #include "tm_p.h"
- #include "target.h"
- #include "flags.h"
- #include "obstack.h"
- #include "bitmap.h"
- #include "hard-reg-set.h"
- #include "predict.h"
- #include "vec.h"
- #include "hashtab.h"
- #include "hash-set.h"
- #include "machmode.h"
- #include "input.h"
- #include "function.h"
- #include "dominance.h"
- #include "cfg.h"
- #include "cfgrtl.h"
- #include "cfgbuild.h"
- #include "basic-block.h"
- #include "symtab.h"
- #include "statistics.h"
- #include "double-int.h"
- #include "real.h"
- #include "fixed-value.h"
- #include "alias.h"
- #include "wide-int.h"
- #include "inchash.h"
- #include "tree.h"
- #include "insn-config.h"
- #include "expmed.h"
- #include "dojump.h"
- #include "explow.h"
- #include "calls.h"
- #include "emit-rtl.h"
- #include "varasm.h"
- #include "stmt.h"
- #include "expr.h"
- #include "recog.h"
- #include "params.h"
- #include "reload.h"
- #include "df.h"
- #include "ira-int.h"
- /* Data used to emit live range split insns and to flattening IR. */
- ira_emit_data_t ira_allocno_emit_data;
- /* Definitions for vectors of pointers. */
- typedef void *void_p;
- /* Pointers to data allocated for allocnos being created during
- emitting. Usually there are quite few such allocnos because they
- are created only for resolving loop in register shuffling. */
- static vec<void_p> new_allocno_emit_data_vec;
- /* Allocate and initiate the emit data. */
- void
- ira_initiate_emit_data (void)
- {
- ira_allocno_t a;
- ira_allocno_iterator ai;
- ira_allocno_emit_data
- = (ira_emit_data_t) ira_allocate (ira_allocnos_num
- * sizeof (struct ira_emit_data));
- memset (ira_allocno_emit_data, 0,
- ira_allocnos_num * sizeof (struct ira_emit_data));
- FOR_EACH_ALLOCNO (a, ai)
- ALLOCNO_ADD_DATA (a) = ira_allocno_emit_data + ALLOCNO_NUM (a);
- new_allocno_emit_data_vec.create (50);
- }
- /* Free the emit data. */
- void
- ira_finish_emit_data (void)
- {
- void_p p;
- ira_allocno_t a;
- ira_allocno_iterator ai;
- ira_free (ira_allocno_emit_data);
- FOR_EACH_ALLOCNO (a, ai)
- ALLOCNO_ADD_DATA (a) = NULL;
- for (;new_allocno_emit_data_vec.length () != 0;)
- {
- p = new_allocno_emit_data_vec.pop ();
- ira_free (p);
- }
- new_allocno_emit_data_vec.release ();
- }
- /* Create and return a new allocno with given REGNO and
- LOOP_TREE_NODE. Allocate emit data for it. */
- static ira_allocno_t
- create_new_allocno (int regno, ira_loop_tree_node_t loop_tree_node)
- {
- ira_allocno_t a;
- a = ira_create_allocno (regno, false, loop_tree_node);
- ALLOCNO_ADD_DATA (a) = ira_allocate (sizeof (struct ira_emit_data));
- memset (ALLOCNO_ADD_DATA (a), 0, sizeof (struct ira_emit_data));
- new_allocno_emit_data_vec.safe_push (ALLOCNO_ADD_DATA (a));
- return a;
- }
- /* See comments below. */
- typedef struct move *move_t;
- /* The structure represents an allocno move. Both allocnos have the
- same original regno but different allocation. */
- struct move
- {
- /* The allocnos involved in the move. */
- ira_allocno_t from, to;
- /* The next move in the move sequence. */
- move_t next;
- /* Used for finding dependencies. */
- bool visited_p;
- /* The size of the following array. */
- int deps_num;
- /* Moves on which given move depends on. Dependency can be cyclic.
- It means we need a temporary to generates the moves. Sequence
- A1->A2, B1->B2 where A1 and B2 are assigned to reg R1 and A2 and
- B1 are assigned to reg R2 is an example of the cyclic
- dependencies. */
- move_t *deps;
- /* First insn generated for the move. */
- rtx_insn *insn;
- };
- /* Array of moves (indexed by BB index) which should be put at the
- start/end of the corresponding basic blocks. */
- static move_t *at_bb_start, *at_bb_end;
- /* Max regno before renaming some pseudo-registers. For example, the
- same pseudo-register can be renamed in a loop if its allocation is
- different outside the loop. */
- static int max_regno_before_changing;
- /* Return new move of allocnos TO and FROM. */
- static move_t
- create_move (ira_allocno_t to, ira_allocno_t from)
- {
- move_t move;
- move = (move_t) ira_allocate (sizeof (struct move));
- move->deps = NULL;
- move->deps_num = 0;
- move->to = to;
- move->from = from;
- move->next = NULL;
- move->insn = NULL;
- move->visited_p = false;
- return move;
- }
- /* Free memory for MOVE and its dependencies. */
- static void
- free_move (move_t move)
- {
- if (move->deps != NULL)
- ira_free (move->deps);
- ira_free (move);
- }
- /* Free memory for list of the moves given by its HEAD. */
- static void
- free_move_list (move_t head)
- {
- move_t next;
- for (; head != NULL; head = next)
- {
- next = head->next;
- free_move (head);
- }
- }
- /* Return TRUE if the move list LIST1 and LIST2 are equal (two
- moves are equal if they involve the same allocnos). */
- static bool
- eq_move_lists_p (move_t list1, move_t list2)
- {
- for (; list1 != NULL && list2 != NULL;
- list1 = list1->next, list2 = list2->next)
- if (list1->from != list2->from || list1->to != list2->to)
- return false;
- return list1 == list2;
- }
- /* Print move list LIST into file F. */
- static void
- print_move_list (FILE *f, move_t list)
- {
- for (; list != NULL; list = list->next)
- fprintf (f, " a%dr%d->a%dr%d",
- ALLOCNO_NUM (list->from), ALLOCNO_REGNO (list->from),
- ALLOCNO_NUM (list->to), ALLOCNO_REGNO (list->to));
- fprintf (f, "\n");
- }
- extern void ira_debug_move_list (move_t list);
- /* Print move list LIST into stderr. */
- void
- ira_debug_move_list (move_t list)
- {
- print_move_list (stderr, list);
- }
- /* This recursive function changes pseudo-registers in *LOC if it is
- necessary. The function returns TRUE if a change was done. */
- static bool
- change_regs (rtx *loc)
- {
- int i, regno, result = false;
- const char *fmt;
- enum rtx_code code;
- rtx reg;
- if (*loc == NULL_RTX)
- return false;
- code = GET_CODE (*loc);
- if (code == REG)
- {
- regno = REGNO (*loc);
- if (regno < FIRST_PSEUDO_REGISTER)
- return false;
- if (regno >= max_regno_before_changing)
- /* It is a shared register which was changed already. */
- return false;
- if (ira_curr_regno_allocno_map[regno] == NULL)
- return false;
- reg = allocno_emit_reg (ira_curr_regno_allocno_map[regno]);
- if (reg == *loc)
- return false;
- *loc = reg;
- return true;
- }
- fmt = GET_RTX_FORMAT (code);
- for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
- {
- if (fmt[i] == 'e')
- result = change_regs (&XEXP (*loc, i)) || result;
- else if (fmt[i] == 'E')
- {
- int j;
- for (j = XVECLEN (*loc, i) - 1; j >= 0; j--)
- result = change_regs (&XVECEXP (*loc, i, j)) || result;
- }
- }
- return result;
- }
- static bool
- change_regs_in_insn (rtx_insn **insn_ptr)
- {
- rtx rtx = *insn_ptr;
- bool result = change_regs (&rtx);
- *insn_ptr = as_a <rtx_insn *> (rtx);
- return result;
- }
- /* Attach MOVE to the edge E. The move is attached to the head of the
- list if HEAD_P is TRUE. */
- static void
- add_to_edge_list (edge e, move_t move, bool head_p)
- {
- move_t last;
- if (head_p || e->aux == NULL)
- {
- move->next = (move_t) e->aux;
- e->aux = move;
- }
- else
- {
- for (last = (move_t) e->aux; last->next != NULL; last = last->next)
- ;
- last->next = move;
- move->next = NULL;
- }
- }
- /* Create and return new pseudo-register with the same attributes as
- ORIGINAL_REG. */
- rtx
- ira_create_new_reg (rtx original_reg)
- {
- rtx new_reg;
- new_reg = gen_reg_rtx (GET_MODE (original_reg));
- ORIGINAL_REGNO (new_reg) = ORIGINAL_REGNO (original_reg);
- REG_USERVAR_P (new_reg) = REG_USERVAR_P (original_reg);
- REG_POINTER (new_reg) = REG_POINTER (original_reg);
- REG_ATTRS (new_reg) = REG_ATTRS (original_reg);
- if (internal_flag_ira_verbose > 3 && ira_dump_file != NULL)
- fprintf (ira_dump_file, " Creating newreg=%i from oldreg=%i\n",
- REGNO (new_reg), REGNO (original_reg));
- ira_expand_reg_equiv ();
- return new_reg;
- }
- /* Return TRUE if loop given by SUBNODE inside the loop given by
- NODE. */
- static bool
- subloop_tree_node_p (ira_loop_tree_node_t subnode, ira_loop_tree_node_t node)
- {
- for (; subnode != NULL; subnode = subnode->parent)
- if (subnode == node)
- return true;
- return false;
- }
- /* Set up member `reg' to REG for allocnos which has the same regno as
- ALLOCNO and which are inside the loop corresponding to ALLOCNO. */
- static void
- set_allocno_reg (ira_allocno_t allocno, rtx reg)
- {
- int regno;
- ira_allocno_t a;
- ira_loop_tree_node_t node;
- node = ALLOCNO_LOOP_TREE_NODE (allocno);
- for (a = ira_regno_allocno_map[ALLOCNO_REGNO (allocno)];
- a != NULL;
- a = ALLOCNO_NEXT_REGNO_ALLOCNO (a))
- if (subloop_tree_node_p (ALLOCNO_LOOP_TREE_NODE (a), node))
- ALLOCNO_EMIT_DATA (a)->reg = reg;
- for (a = ALLOCNO_CAP (allocno); a != NULL; a = ALLOCNO_CAP (a))
- ALLOCNO_EMIT_DATA (a)->reg = reg;
- regno = ALLOCNO_REGNO (allocno);
- for (a = allocno;;)
- {
- if (a == NULL || (a = ALLOCNO_CAP (a)) == NULL)
- {
- node = node->parent;
- if (node == NULL)
- break;
- a = node->regno_allocno_map[regno];
- }
- if (a == NULL)
- continue;
- if (ALLOCNO_EMIT_DATA (a)->child_renamed_p)
- break;
- ALLOCNO_EMIT_DATA (a)->child_renamed_p = true;
- }
- }
- /* Return true if there is an entry to given loop not from its parent
- (or grandparent) block. For example, it is possible for two
- adjacent loops inside another loop. */
- static bool
- entered_from_non_parent_p (ira_loop_tree_node_t loop_node)
- {
- ira_loop_tree_node_t bb_node, src_loop_node, parent;
- edge e;
- edge_iterator ei;
- for (bb_node = loop_node->children;
- bb_node != NULL;
- bb_node = bb_node->next)
- if (bb_node->bb != NULL)
- {
- FOR_EACH_EDGE (e, ei, bb_node->bb->preds)
- if (e->src != ENTRY_BLOCK_PTR_FOR_FN (cfun)
- && (src_loop_node = IRA_BB_NODE (e->src)->parent) != loop_node)
- {
- for (parent = src_loop_node->parent;
- parent != NULL;
- parent = parent->parent)
- if (parent == loop_node)
- break;
- if (parent != NULL)
- /* That is an exit from a nested loop -- skip it. */
- continue;
- for (parent = loop_node->parent;
- parent != NULL;
- parent = parent->parent)
- if (src_loop_node == parent)
- break;
- if (parent == NULL)
- return true;
- }
- }
- return false;
- }
- /* Set up ENTERED_FROM_NON_PARENT_P for each loop region. */
- static void
- setup_entered_from_non_parent_p (void)
- {
- unsigned int i;
- loop_p loop;
- ira_assert (current_loops != NULL);
- FOR_EACH_VEC_SAFE_ELT (get_loops (cfun), i, loop)
- if (ira_loop_nodes[i].regno_allocno_map != NULL)
- ira_loop_nodes[i].entered_from_non_parent_p
- = entered_from_non_parent_p (&ira_loop_nodes[i]);
- }
- /* Return TRUE if move of SRC_ALLOCNO (assigned to hard register) to
- DEST_ALLOCNO (assigned to memory) can be removed because it does
- not change value of the destination. One possible reason for this
- is the situation when SRC_ALLOCNO is not modified in the
- corresponding loop. */
- static bool
- store_can_be_removed_p (ira_allocno_t src_allocno, ira_allocno_t dest_allocno)
- {
- int regno, orig_regno;
- ira_allocno_t a;
- ira_loop_tree_node_t node;
- ira_assert (ALLOCNO_CAP_MEMBER (src_allocno) == NULL
- && ALLOCNO_CAP_MEMBER (dest_allocno) == NULL);
- orig_regno = ALLOCNO_REGNO (src_allocno);
- regno = REGNO (allocno_emit_reg (dest_allocno));
- for (node = ALLOCNO_LOOP_TREE_NODE (src_allocno);
- node != NULL;
- node = node->parent)
- {
- a = node->regno_allocno_map[orig_regno];
- ira_assert (a != NULL);
- if (REGNO (allocno_emit_reg (a)) == (unsigned) regno)
- /* We achieved the destination and everything is ok. */
- return true;
- else if (bitmap_bit_p (node->modified_regnos, orig_regno))
- return false;
- else if (node->entered_from_non_parent_p)
- /* If there is a path from a destination loop block to the
- source loop header containing basic blocks of non-parents
- (grandparents) of the source loop, we should have checked
- modifications of the pseudo on this path too to decide
- about possibility to remove the store. It could be done by
- solving a data-flow problem. Unfortunately such global
- solution would complicate IR flattening. Therefore we just
- prohibit removal of the store in such complicated case. */
- return false;
- }
- /* It is actually a loop entry -- do not remove the store. */
- return false;
- }
- /* Generate and attach moves to the edge E. This looks at the final
- regnos of allocnos living on the edge with the same original regno
- to figure out when moves should be generated. */
- static void
- generate_edge_moves (edge e)
- {
- ira_loop_tree_node_t src_loop_node, dest_loop_node;
- unsigned int regno;
- bitmap_iterator bi;
- ira_allocno_t src_allocno, dest_allocno, *src_map, *dest_map;
- move_t move;
- bitmap regs_live_in_dest, regs_live_out_src;
- src_loop_node = IRA_BB_NODE (e->src)->parent;
- dest_loop_node = IRA_BB_NODE (e->dest)->parent;
- e->aux = NULL;
- if (src_loop_node == dest_loop_node)
- return;
- src_map = src_loop_node->regno_allocno_map;
- dest_map = dest_loop_node->regno_allocno_map;
- regs_live_in_dest = df_get_live_in (e->dest);
- regs_live_out_src = df_get_live_out (e->src);
- EXECUTE_IF_SET_IN_REG_SET (regs_live_in_dest,
- FIRST_PSEUDO_REGISTER, regno, bi)
- if (bitmap_bit_p (regs_live_out_src, regno))
- {
- src_allocno = src_map[regno];
- dest_allocno = dest_map[regno];
- if (REGNO (allocno_emit_reg (src_allocno))
- == REGNO (allocno_emit_reg (dest_allocno)))
- continue;
- /* Remove unnecessary stores at the region exit. We should do
- this for readonly memory for sure and this is guaranteed by
- that we never generate moves on region borders (see
- checking in function change_loop). */
- if (ALLOCNO_HARD_REGNO (dest_allocno) < 0
- && ALLOCNO_HARD_REGNO (src_allocno) >= 0
- && store_can_be_removed_p (src_allocno, dest_allocno))
- {
- ALLOCNO_EMIT_DATA (src_allocno)->mem_optimized_dest = dest_allocno;
- ALLOCNO_EMIT_DATA (dest_allocno)->mem_optimized_dest_p = true;
- if (internal_flag_ira_verbose > 3 && ira_dump_file != NULL)
- fprintf (ira_dump_file, " Remove r%d:a%d->a%d(mem)\n",
- regno, ALLOCNO_NUM (src_allocno),
- ALLOCNO_NUM (dest_allocno));
- continue;
- }
- move = create_move (dest_allocno, src_allocno);
- add_to_edge_list (e, move, true);
- }
- }
- /* Bitmap of allocnos local for the current loop. */
- static bitmap local_allocno_bitmap;
- /* This bitmap is used to find that we need to generate and to use a
- new pseudo-register when processing allocnos with the same original
- regno. */
- static bitmap used_regno_bitmap;
- /* This bitmap contains regnos of allocnos which were renamed locally
- because the allocnos correspond to disjoint live ranges in loops
- with a common parent. */
- static bitmap renamed_regno_bitmap;
- /* Change (if necessary) pseudo-registers inside loop given by loop
- tree node NODE. */
- static void
- change_loop (ira_loop_tree_node_t node)
- {
- bitmap_iterator bi;
- unsigned int i;
- int regno;
- bool used_p;
- ira_allocno_t allocno, parent_allocno, *map;
- rtx_insn *insn;
- rtx original_reg;
- enum reg_class aclass, pclass;
- ira_loop_tree_node_t parent;
- if (node != ira_loop_tree_root)
- {
- ira_assert (current_loops != NULL);
-
- if (node->bb != NULL)
- {
- FOR_BB_INSNS (node->bb, insn)
- if (INSN_P (insn) && change_regs_in_insn (&insn))
- {
- df_insn_rescan (insn);
- df_notes_rescan (insn);
- }
- return;
- }
- if (internal_flag_ira_verbose > 3 && ira_dump_file != NULL)
- fprintf (ira_dump_file,
- " Changing RTL for loop %d (header bb%d)\n",
- node->loop_num, node->loop->header->index);
- parent = ira_curr_loop_tree_node->parent;
- map = parent->regno_allocno_map;
- EXECUTE_IF_SET_IN_REG_SET (ira_curr_loop_tree_node->border_allocnos,
- 0, i, bi)
- {
- allocno = ira_allocnos[i];
- regno = ALLOCNO_REGNO (allocno);
- aclass = ALLOCNO_CLASS (allocno);
- pclass = ira_pressure_class_translate[aclass];
- parent_allocno = map[regno];
- ira_assert (regno < ira_reg_equiv_len);
- /* We generate the same hard register move because the
- reload pass can put an allocno into memory in this case
- we will have live range splitting. If it does not happen
- such the same hard register moves will be removed. The
- worst case when the both allocnos are put into memory by
- the reload is very rare. */
- if (parent_allocno != NULL
- && (ALLOCNO_HARD_REGNO (allocno)
- == ALLOCNO_HARD_REGNO (parent_allocno))
- && (ALLOCNO_HARD_REGNO (allocno) < 0
- || (parent->reg_pressure[pclass] + 1
- <= ira_class_hard_regs_num[pclass])
- || TEST_HARD_REG_BIT (ira_prohibited_mode_move_regs
- [ALLOCNO_MODE (allocno)],
- ALLOCNO_HARD_REGNO (allocno))
- /* don't create copies because reload can spill an
- allocno set by copy although the allocno will not
- get memory slot. */
- || ira_equiv_no_lvalue_p (regno)
- || (pic_offset_table_rtx != NULL
- && (ALLOCNO_REGNO (allocno)
- == (int) REGNO (pic_offset_table_rtx)))))
- continue;
- original_reg = allocno_emit_reg (allocno);
- if (parent_allocno == NULL
- || (REGNO (allocno_emit_reg (parent_allocno))
- == REGNO (original_reg)))
- {
- if (internal_flag_ira_verbose > 3 && ira_dump_file)
- fprintf (ira_dump_file, " %i vs parent %i:",
- ALLOCNO_HARD_REGNO (allocno),
- ALLOCNO_HARD_REGNO (parent_allocno));
- set_allocno_reg (allocno, ira_create_new_reg (original_reg));
- }
- }
- }
- /* Rename locals: Local allocnos with same regno in different loops
- might get the different hard register. So we need to change
- ALLOCNO_REG. */
- bitmap_and_compl (local_allocno_bitmap,
- ira_curr_loop_tree_node->all_allocnos,
- ira_curr_loop_tree_node->border_allocnos);
- EXECUTE_IF_SET_IN_REG_SET (local_allocno_bitmap, 0, i, bi)
- {
- allocno = ira_allocnos[i];
- regno = ALLOCNO_REGNO (allocno);
- if (ALLOCNO_CAP_MEMBER (allocno) != NULL)
- continue;
- used_p = !bitmap_set_bit (used_regno_bitmap, regno);
- ALLOCNO_EMIT_DATA (allocno)->somewhere_renamed_p = true;
- if (! used_p)
- continue;
- bitmap_set_bit (renamed_regno_bitmap, regno);
- set_allocno_reg (allocno, ira_create_new_reg (allocno_emit_reg (allocno)));
- }
- }
- /* Process to set up flag somewhere_renamed_p. */
- static void
- set_allocno_somewhere_renamed_p (void)
- {
- unsigned int regno;
- ira_allocno_t allocno;
- ira_allocno_iterator ai;
- FOR_EACH_ALLOCNO (allocno, ai)
- {
- regno = ALLOCNO_REGNO (allocno);
- if (bitmap_bit_p (renamed_regno_bitmap, regno)
- && REGNO (allocno_emit_reg (allocno)) == regno)
- ALLOCNO_EMIT_DATA (allocno)->somewhere_renamed_p = true;
- }
- }
- /* Return TRUE if move lists on all edges given in vector VEC are
- equal. */
- static bool
- eq_edge_move_lists_p (vec<edge, va_gc> *vec)
- {
- move_t list;
- int i;
- list = (move_t) EDGE_I (vec, 0)->aux;
- for (i = EDGE_COUNT (vec) - 1; i > 0; i--)
- if (! eq_move_lists_p (list, (move_t) EDGE_I (vec, i)->aux))
- return false;
- return true;
- }
- /* Look at all entry edges (if START_P) or exit edges of basic block
- BB and put move lists at the BB start or end if it is possible. In
- other words, this decreases code duplication of allocno moves. */
- static void
- unify_moves (basic_block bb, bool start_p)
- {
- int i;
- edge e;
- move_t list;
- vec<edge, va_gc> *vec;
- vec = (start_p ? bb->preds : bb->succs);
- if (EDGE_COUNT (vec) == 0 || ! eq_edge_move_lists_p (vec))
- return;
- e = EDGE_I (vec, 0);
- list = (move_t) e->aux;
- if (! start_p && control_flow_insn_p (BB_END (bb)))
- return;
- e->aux = NULL;
- for (i = EDGE_COUNT (vec) - 1; i > 0; i--)
- {
- e = EDGE_I (vec, i);
- free_move_list ((move_t) e->aux);
- e->aux = NULL;
- }
- if (start_p)
- at_bb_start[bb->index] = list;
- else
- at_bb_end[bb->index] = list;
- }
- /* Last move (in move sequence being processed) setting up the
- corresponding hard register. */
- static move_t hard_regno_last_set[FIRST_PSEUDO_REGISTER];
- /* If the element value is equal to CURR_TICK then the corresponding
- element in `hard_regno_last_set' is defined and correct. */
- static int hard_regno_last_set_check[FIRST_PSEUDO_REGISTER];
- /* Last move (in move sequence being processed) setting up the
- corresponding allocno. */
- static move_t *allocno_last_set;
- /* If the element value is equal to CURR_TICK then the corresponding
- element in . `allocno_last_set' is defined and correct. */
- static int *allocno_last_set_check;
- /* Definition of vector of moves. */
- /* This vec contains moves sorted topologically (depth-first) on their
- dependency graph. */
- static vec<move_t> move_vec;
- /* The variable value is used to check correctness of values of
- elements of arrays `hard_regno_last_set' and
- `allocno_last_set_check'. */
- static int curr_tick;
- /* This recursive function traverses dependencies of MOVE and produces
- topological sorting (in depth-first order). */
- static void
- traverse_moves (move_t move)
- {
- int i;
- if (move->visited_p)
- return;
- move->visited_p = true;
- for (i = move->deps_num - 1; i >= 0; i--)
- traverse_moves (move->deps[i]);
- move_vec.safe_push (move);
- }
- /* Remove unnecessary moves in the LIST, makes topological sorting,
- and removes cycles on hard reg dependencies by introducing new
- allocnos assigned to memory and additional moves. It returns the
- result move list. */
- static move_t
- modify_move_list (move_t list)
- {
- int i, n, nregs, hard_regno;
- ira_allocno_t to, from;
- move_t move, new_move, set_move, first, last;
- if (list == NULL)
- return NULL;
- /* Create move deps. */
- curr_tick++;
- for (move = list; move != NULL; move = move->next)
- {
- to = move->to;
- if ((hard_regno = ALLOCNO_HARD_REGNO (to)) < 0)
- continue;
- nregs = hard_regno_nregs[hard_regno][ALLOCNO_MODE (to)];
- for (i = 0; i < nregs; i++)
- {
- hard_regno_last_set[hard_regno + i] = move;
- hard_regno_last_set_check[hard_regno + i] = curr_tick;
- }
- }
- for (move = list; move != NULL; move = move->next)
- {
- from = move->from;
- to = move->to;
- if ((hard_regno = ALLOCNO_HARD_REGNO (from)) >= 0)
- {
- nregs = hard_regno_nregs[hard_regno][ALLOCNO_MODE (from)];
- for (n = i = 0; i < nregs; i++)
- if (hard_regno_last_set_check[hard_regno + i] == curr_tick
- && (ALLOCNO_REGNO (hard_regno_last_set[hard_regno + i]->to)
- != ALLOCNO_REGNO (from)))
- n++;
- move->deps = (move_t *) ira_allocate (n * sizeof (move_t));
- for (n = i = 0; i < nregs; i++)
- if (hard_regno_last_set_check[hard_regno + i] == curr_tick
- && (ALLOCNO_REGNO (hard_regno_last_set[hard_regno + i]->to)
- != ALLOCNO_REGNO (from)))
- move->deps[n++] = hard_regno_last_set[hard_regno + i];
- move->deps_num = n;
- }
- }
- /* Topological sorting: */
- move_vec.truncate (0);
- for (move = list; move != NULL; move = move->next)
- traverse_moves (move);
- last = NULL;
- for (i = (int) move_vec.length () - 1; i >= 0; i--)
- {
- move = move_vec[i];
- move->next = NULL;
- if (last != NULL)
- last->next = move;
- last = move;
- }
- first = move_vec.last ();
- /* Removing cycles: */
- curr_tick++;
- move_vec.truncate (0);
- for (move = first; move != NULL; move = move->next)
- {
- from = move->from;
- to = move->to;
- if ((hard_regno = ALLOCNO_HARD_REGNO (from)) >= 0)
- {
- nregs = hard_regno_nregs[hard_regno][ALLOCNO_MODE (from)];
- for (i = 0; i < nregs; i++)
- if (hard_regno_last_set_check[hard_regno + i] == curr_tick
- && ALLOCNO_HARD_REGNO
- (hard_regno_last_set[hard_regno + i]->to) >= 0)
- {
- int n, j;
- ira_allocno_t new_allocno;
- set_move = hard_regno_last_set[hard_regno + i];
- /* It does not matter what loop_tree_node (of TO or
- FROM) to use for the new allocno because of
- subsequent IRA internal representation
- flattening. */
- new_allocno
- = create_new_allocno (ALLOCNO_REGNO (set_move->to),
- ALLOCNO_LOOP_TREE_NODE (set_move->to));
- ALLOCNO_MODE (new_allocno) = ALLOCNO_MODE (set_move->to);
- ira_set_allocno_class (new_allocno,
- ALLOCNO_CLASS (set_move->to));
- ira_create_allocno_objects (new_allocno);
- ALLOCNO_ASSIGNED_P (new_allocno) = true;
- ALLOCNO_HARD_REGNO (new_allocno) = -1;
- ALLOCNO_EMIT_DATA (new_allocno)->reg
- = ira_create_new_reg (allocno_emit_reg (set_move->to));
- /* Make it possibly conflicting with all earlier
- created allocnos. Cases where temporary allocnos
- created to remove the cycles are quite rare. */
- n = ALLOCNO_NUM_OBJECTS (new_allocno);
- gcc_assert (n == ALLOCNO_NUM_OBJECTS (set_move->to));
- for (j = 0; j < n; j++)
- {
- ira_object_t new_obj = ALLOCNO_OBJECT (new_allocno, j);
- OBJECT_MIN (new_obj) = 0;
- OBJECT_MAX (new_obj) = ira_objects_num - 1;
- }
- new_move = create_move (set_move->to, new_allocno);
- set_move->to = new_allocno;
- move_vec.safe_push (new_move);
- ira_move_loops_num++;
- if (internal_flag_ira_verbose > 2 && ira_dump_file != NULL)
- fprintf (ira_dump_file,
- " Creating temporary allocno a%dr%d\n",
- ALLOCNO_NUM (new_allocno),
- REGNO (allocno_emit_reg (new_allocno)));
- }
- }
- if ((hard_regno = ALLOCNO_HARD_REGNO (to)) < 0)
- continue;
- nregs = hard_regno_nregs[hard_regno][ALLOCNO_MODE (to)];
- for (i = 0; i < nregs; i++)
- {
- hard_regno_last_set[hard_regno + i] = move;
- hard_regno_last_set_check[hard_regno + i] = curr_tick;
- }
- }
- for (i = (int) move_vec.length () - 1; i >= 0; i--)
- {
- move = move_vec[i];
- move->next = NULL;
- last->next = move;
- last = move;
- }
- return first;
- }
- /* Generate RTX move insns from the move list LIST. This updates
- allocation cost using move execution frequency FREQ. */
- static rtx_insn *
- emit_move_list (move_t list, int freq)
- {
- rtx to, from, dest;
- int to_regno, from_regno, cost, regno;
- rtx_insn *result, *insn;
- rtx set;
- machine_mode mode;
- enum reg_class aclass;
- grow_reg_equivs ();
- start_sequence ();
- for (; list != NULL; list = list->next)
- {
- start_sequence ();
- to = allocno_emit_reg (list->to);
- to_regno = REGNO (to);
- from = allocno_emit_reg (list->from);
- from_regno = REGNO (from);
- emit_move_insn (to, from);
- list->insn = get_insns ();
- end_sequence ();
- for (insn = list->insn; insn != NULL_RTX; insn = NEXT_INSN (insn))
- {
- /* The reload needs to have set up insn codes. If the
- reload sets up insn codes by itself, it may fail because
- insns will have hard registers instead of pseudos and
- there may be no machine insn with given hard
- registers. */
- recog_memoized (insn);
- /* Add insn to equiv init insn list if it is necessary.
- Otherwise reload will not remove this insn if it decides
- to use the equivalence. */
- if ((set = single_set (insn)) != NULL_RTX)
- {
- dest = SET_DEST (set);
- if (GET_CODE (dest) == SUBREG)
- dest = SUBREG_REG (dest);
- ira_assert (REG_P (dest));
- regno = REGNO (dest);
- if (regno >= ira_reg_equiv_len
- || (ira_reg_equiv[regno].invariant == NULL_RTX
- && ira_reg_equiv[regno].constant == NULL_RTX))
- continue; /* regno has no equivalence. */
- ira_assert ((int) reg_equivs->length () > regno);
- reg_equiv_init (regno)
- = gen_rtx_INSN_LIST (VOIDmode, insn, reg_equiv_init (regno));
- }
- }
- if (ira_use_lra_p)
- ira_update_equiv_info_by_shuffle_insn (to_regno, from_regno, list->insn);
- emit_insn (list->insn);
- mode = ALLOCNO_MODE (list->to);
- aclass = ALLOCNO_CLASS (list->to);
- cost = 0;
- if (ALLOCNO_HARD_REGNO (list->to) < 0)
- {
- if (ALLOCNO_HARD_REGNO (list->from) >= 0)
- {
- cost = ira_memory_move_cost[mode][aclass][0] * freq;
- ira_store_cost += cost;
- }
- }
- else if (ALLOCNO_HARD_REGNO (list->from) < 0)
- {
- if (ALLOCNO_HARD_REGNO (list->to) >= 0)
- {
- cost = ira_memory_move_cost[mode][aclass][0] * freq;
- ira_load_cost += cost;
- }
- }
- else
- {
- ira_init_register_move_cost_if_necessary (mode);
- cost = ira_register_move_cost[mode][aclass][aclass] * freq;
- ira_shuffle_cost += cost;
- }
- ira_overall_cost += cost;
- }
- result = get_insns ();
- end_sequence ();
- return result;
- }
- /* Generate RTX move insns from move lists attached to basic blocks
- and edges. */
- static void
- emit_moves (void)
- {
- basic_block bb;
- edge_iterator ei;
- edge e;
- rtx_insn *insns, *tmp;
- FOR_EACH_BB_FN (bb, cfun)
- {
- if (at_bb_start[bb->index] != NULL)
- {
- at_bb_start[bb->index] = modify_move_list (at_bb_start[bb->index]);
- insns = emit_move_list (at_bb_start[bb->index],
- REG_FREQ_FROM_BB (bb));
- tmp = BB_HEAD (bb);
- if (LABEL_P (tmp))
- tmp = NEXT_INSN (tmp);
- if (NOTE_INSN_BASIC_BLOCK_P (tmp))
- tmp = NEXT_INSN (tmp);
- if (tmp == BB_HEAD (bb))
- emit_insn_before (insns, tmp);
- else if (tmp != NULL_RTX)
- emit_insn_after (insns, PREV_INSN (tmp));
- else
- emit_insn_after (insns, get_last_insn ());
- }
- if (at_bb_end[bb->index] != NULL)
- {
- at_bb_end[bb->index] = modify_move_list (at_bb_end[bb->index]);
- insns = emit_move_list (at_bb_end[bb->index], REG_FREQ_FROM_BB (bb));
- ira_assert (! control_flow_insn_p (BB_END (bb)));
- emit_insn_after (insns, BB_END (bb));
- }
- FOR_EACH_EDGE (e, ei, bb->succs)
- {
- if (e->aux == NULL)
- continue;
- ira_assert ((e->flags & EDGE_ABNORMAL) == 0
- || ! EDGE_CRITICAL_P (e));
- e->aux = modify_move_list ((move_t) e->aux);
- insert_insn_on_edge
- (emit_move_list ((move_t) e->aux,
- REG_FREQ_FROM_EDGE_FREQ (EDGE_FREQUENCY (e))),
- e);
- if (e->src->next_bb != e->dest)
- ira_additional_jumps_num++;
- }
- }
- }
- /* Update costs of A and corresponding allocnos on upper levels on the
- loop tree from reading (if READ_P) or writing A on an execution
- path with FREQ. */
- static void
- update_costs (ira_allocno_t a, bool read_p, int freq)
- {
- ira_loop_tree_node_t parent;
- for (;;)
- {
- ALLOCNO_NREFS (a)++;
- ALLOCNO_FREQ (a) += freq;
- ALLOCNO_MEMORY_COST (a)
- += (ira_memory_move_cost[ALLOCNO_MODE (a)][ALLOCNO_CLASS (a)]
- [read_p ? 1 : 0] * freq);
- if (ALLOCNO_CAP (a) != NULL)
- a = ALLOCNO_CAP (a);
- else if ((parent = ALLOCNO_LOOP_TREE_NODE (a)->parent) == NULL
- || (a = parent->regno_allocno_map[ALLOCNO_REGNO (a)]) == NULL)
- break;
- }
- }
- /* Process moves from LIST with execution FREQ to add ranges, copies,
- and modify costs for allocnos involved in the moves. All regnos
- living through the list is in LIVE_THROUGH, and the loop tree node
- used to find corresponding allocnos is NODE. */
- static void
- add_range_and_copies_from_move_list (move_t list, ira_loop_tree_node_t node,
- bitmap live_through, int freq)
- {
- int start, n;
- unsigned int regno;
- move_t move;
- ira_allocno_t a;
- ira_copy_t cp;
- live_range_t r;
- bitmap_iterator bi;
- HARD_REG_SET hard_regs_live;
- if (list == NULL)
- return;
- n = 0;
- EXECUTE_IF_SET_IN_BITMAP (live_through, FIRST_PSEUDO_REGISTER, regno, bi)
- n++;
- REG_SET_TO_HARD_REG_SET (hard_regs_live, live_through);
- /* This is a trick to guarantee that new ranges is not merged with
- the old ones. */
- ira_max_point++;
- start = ira_max_point;
- for (move = list; move != NULL; move = move->next)
- {
- ira_allocno_t from = move->from;
- ira_allocno_t to = move->to;
- int nr, i;
- bitmap_clear_bit (live_through, ALLOCNO_REGNO (from));
- bitmap_clear_bit (live_through, ALLOCNO_REGNO (to));
- nr = ALLOCNO_NUM_OBJECTS (to);
- for (i = 0; i < nr; i++)
- {
- ira_object_t to_obj = ALLOCNO_OBJECT (to, i);
- if (OBJECT_CONFLICT_ARRAY (to_obj) == NULL)
- {
- if (internal_flag_ira_verbose > 2 && ira_dump_file != NULL)
- fprintf (ira_dump_file, " Allocate conflicts for a%dr%d\n",
- ALLOCNO_NUM (to), REGNO (allocno_emit_reg (to)));
- ira_allocate_object_conflicts (to_obj, n);
- }
- }
- ior_hard_reg_conflicts (from, &hard_regs_live);
- ior_hard_reg_conflicts (to, &hard_regs_live);
- update_costs (from, true, freq);
- update_costs (to, false, freq);
- cp = ira_add_allocno_copy (from, to, freq, false, move->insn, NULL);
- if (internal_flag_ira_verbose > 2 && ira_dump_file != NULL)
- fprintf (ira_dump_file, " Adding cp%d:a%dr%d-a%dr%d\n",
- cp->num, ALLOCNO_NUM (cp->first),
- REGNO (allocno_emit_reg (cp->first)),
- ALLOCNO_NUM (cp->second),
- REGNO (allocno_emit_reg (cp->second)));
- nr = ALLOCNO_NUM_OBJECTS (from);
- for (i = 0; i < nr; i++)
- {
- ira_object_t from_obj = ALLOCNO_OBJECT (from, i);
- r = OBJECT_LIVE_RANGES (from_obj);
- if (r == NULL || r->finish >= 0)
- {
- ira_add_live_range_to_object (from_obj, start, ira_max_point);
- if (internal_flag_ira_verbose > 2 && ira_dump_file != NULL)
- fprintf (ira_dump_file,
- " Adding range [%d..%d] to allocno a%dr%d\n",
- start, ira_max_point, ALLOCNO_NUM (from),
- REGNO (allocno_emit_reg (from)));
- }
- else
- {
- r->finish = ira_max_point;
- if (internal_flag_ira_verbose > 2 && ira_dump_file != NULL)
- fprintf (ira_dump_file,
- " Adding range [%d..%d] to allocno a%dr%d\n",
- r->start, ira_max_point, ALLOCNO_NUM (from),
- REGNO (allocno_emit_reg (from)));
- }
- }
- ira_max_point++;
- nr = ALLOCNO_NUM_OBJECTS (to);
- for (i = 0; i < nr; i++)
- {
- ira_object_t to_obj = ALLOCNO_OBJECT (to, i);
- ira_add_live_range_to_object (to_obj, ira_max_point, -1);
- }
- ira_max_point++;
- }
- for (move = list; move != NULL; move = move->next)
- {
- int nr, i;
- nr = ALLOCNO_NUM_OBJECTS (move->to);
- for (i = 0; i < nr; i++)
- {
- ira_object_t to_obj = ALLOCNO_OBJECT (move->to, i);
- r = OBJECT_LIVE_RANGES (to_obj);
- if (r->finish < 0)
- {
- r->finish = ira_max_point - 1;
- if (internal_flag_ira_verbose > 2 && ira_dump_file != NULL)
- fprintf (ira_dump_file,
- " Adding range [%d..%d] to allocno a%dr%d\n",
- r->start, r->finish, ALLOCNO_NUM (move->to),
- REGNO (allocno_emit_reg (move->to)));
- }
- }
- }
- EXECUTE_IF_SET_IN_BITMAP (live_through, FIRST_PSEUDO_REGISTER, regno, bi)
- {
- ira_allocno_t to;
- int nr, i;
- a = node->regno_allocno_map[regno];
- if ((to = ALLOCNO_EMIT_DATA (a)->mem_optimized_dest) != NULL)
- a = to;
- nr = ALLOCNO_NUM_OBJECTS (a);
- for (i = 0; i < nr; i++)
- {
- ira_object_t obj = ALLOCNO_OBJECT (a, i);
- ira_add_live_range_to_object (obj, start, ira_max_point - 1);
- }
- if (internal_flag_ira_verbose > 2 && ira_dump_file != NULL)
- fprintf
- (ira_dump_file,
- " Adding range [%d..%d] to live through %s allocno a%dr%d\n",
- start, ira_max_point - 1,
- to != NULL ? "upper level" : "",
- ALLOCNO_NUM (a), REGNO (allocno_emit_reg (a)));
- }
- }
- /* Process all move list to add ranges, conflicts, copies, and modify
- costs for allocnos involved in the moves. */
- static void
- add_ranges_and_copies (void)
- {
- basic_block bb;
- edge_iterator ei;
- edge e;
- ira_loop_tree_node_t node;
- bitmap live_through;
- live_through = ira_allocate_bitmap ();
- FOR_EACH_BB_FN (bb, cfun)
- {
- /* It does not matter what loop_tree_node (of source or
- destination block) to use for searching allocnos by their
- regnos because of subsequent IR flattening. */
- node = IRA_BB_NODE (bb)->parent;
- bitmap_copy (live_through, df_get_live_in (bb));
- add_range_and_copies_from_move_list
- (at_bb_start[bb->index], node, live_through, REG_FREQ_FROM_BB (bb));
- bitmap_copy (live_through, df_get_live_out (bb));
- add_range_and_copies_from_move_list
- (at_bb_end[bb->index], node, live_through, REG_FREQ_FROM_BB (bb));
- FOR_EACH_EDGE (e, ei, bb->succs)
- {
- bitmap_and (live_through,
- df_get_live_in (e->dest), df_get_live_out (bb));
- add_range_and_copies_from_move_list
- ((move_t) e->aux, node, live_through,
- REG_FREQ_FROM_EDGE_FREQ (EDGE_FREQUENCY (e)));
- }
- }
- ira_free_bitmap (live_through);
- }
- /* The entry function changes code and generates shuffling allocnos on
- region borders for the regional (LOOPS_P is TRUE in this case)
- register allocation. */
- void
- ira_emit (bool loops_p)
- {
- basic_block bb;
- rtx_insn *insn;
- edge_iterator ei;
- edge e;
- ira_allocno_t a;
- ira_allocno_iterator ai;
- size_t sz;
- FOR_EACH_ALLOCNO (a, ai)
- ALLOCNO_EMIT_DATA (a)->reg = regno_reg_rtx[ALLOCNO_REGNO (a)];
- if (! loops_p)
- return;
- sz = sizeof (move_t) * last_basic_block_for_fn (cfun);
- at_bb_start = (move_t *) ira_allocate (sz);
- memset (at_bb_start, 0, sz);
- at_bb_end = (move_t *) ira_allocate (sz);
- memset (at_bb_end, 0, sz);
- local_allocno_bitmap = ira_allocate_bitmap ();
- used_regno_bitmap = ira_allocate_bitmap ();
- renamed_regno_bitmap = ira_allocate_bitmap ();
- max_regno_before_changing = max_reg_num ();
- ira_traverse_loop_tree (true, ira_loop_tree_root, change_loop, NULL);
- set_allocno_somewhere_renamed_p ();
- ira_free_bitmap (used_regno_bitmap);
- ira_free_bitmap (renamed_regno_bitmap);
- ira_free_bitmap (local_allocno_bitmap);
- setup_entered_from_non_parent_p ();
- FOR_EACH_BB_FN (bb, cfun)
- {
- at_bb_start[bb->index] = NULL;
- at_bb_end[bb->index] = NULL;
- FOR_EACH_EDGE (e, ei, bb->succs)
- if (e->dest != EXIT_BLOCK_PTR_FOR_FN (cfun))
- generate_edge_moves (e);
- }
- allocno_last_set
- = (move_t *) ira_allocate (sizeof (move_t) * max_reg_num ());
- allocno_last_set_check
- = (int *) ira_allocate (sizeof (int) * max_reg_num ());
- memset (allocno_last_set_check, 0, sizeof (int) * max_reg_num ());
- memset (hard_regno_last_set_check, 0, sizeof (hard_regno_last_set_check));
- curr_tick = 0;
- FOR_EACH_BB_FN (bb, cfun)
- unify_moves (bb, true);
- FOR_EACH_BB_FN (bb, cfun)
- unify_moves (bb, false);
- move_vec.create (ira_allocnos_num);
- emit_moves ();
- add_ranges_and_copies ();
- /* Clean up: */
- FOR_EACH_BB_FN (bb, cfun)
- {
- free_move_list (at_bb_start[bb->index]);
- free_move_list (at_bb_end[bb->index]);
- FOR_EACH_EDGE (e, ei, bb->succs)
- {
- free_move_list ((move_t) e->aux);
- e->aux = NULL;
- }
- }
- move_vec.release ();
- ira_free (allocno_last_set_check);
- ira_free (allocno_last_set);
- commit_edge_insertions ();
- /* Fix insn codes. It is necessary to do it before reload because
- reload assumes initial insn codes defined. The insn codes can be
- invalidated by CFG infrastructure for example in jump
- redirection. */
- FOR_EACH_BB_FN (bb, cfun)
- FOR_BB_INSNS_REVERSE (bb, insn)
- if (INSN_P (insn))
- recog_memoized (insn);
- ira_free (at_bb_end);
- ira_free (at_bb_start);
- }
|