diff options
Diffstat (limited to 'lib/gcc/arm-none-eabi/13.2.1/plugin/include/basic-block.h')
-rw-r--r-- | lib/gcc/arm-none-eabi/13.2.1/plugin/include/basic-block.h | 642 |
1 files changed, 642 insertions, 0 deletions
diff --git a/lib/gcc/arm-none-eabi/13.2.1/plugin/include/basic-block.h b/lib/gcc/arm-none-eabi/13.2.1/plugin/include/basic-block.h new file mode 100644 index 0000000..29191e5 --- /dev/null +++ b/lib/gcc/arm-none-eabi/13.2.1/plugin/include/basic-block.h @@ -0,0 +1,642 @@ +/* Define control flow data structures for the CFG. + Copyright (C) 1987-2023 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 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/>. */ + +#ifndef GCC_BASIC_BLOCK_H +#define GCC_BASIC_BLOCK_H + +#include <profile-count.h> + +/* Control flow edge information. */ +class GTY((user)) edge_def { +public: + /* The two blocks at the ends of the edge. */ + basic_block src; + basic_block dest; + + /* Instructions queued on the edge. */ + union edge_def_insns { + gimple_seq g; + rtx_insn *r; + } insns; + + /* Auxiliary info specific to a pass. */ + void *aux; + + /* Location of any goto implicit in the edge. */ + location_t goto_locus; + + /* The index number corresponding to this edge in the edge vector + dest->preds. */ + unsigned int dest_idx; + + int flags; /* see cfg-flags.def */ + profile_probability probability; + + /* Return count of edge E. */ + inline profile_count count () const; +}; + +/* Masks for edge.flags. */ +#define DEF_EDGE_FLAG(NAME,IDX) EDGE_##NAME = 1 << IDX , +enum cfg_edge_flags { +#include "cfg-flags.def" + LAST_CFG_EDGE_FLAG /* this is only used for EDGE_ALL_FLAGS */ +}; +#undef DEF_EDGE_FLAG + +/* Bit mask for all edge flags. */ +#define EDGE_ALL_FLAGS ((LAST_CFG_EDGE_FLAG - 1) * 2 - 1) + +/* The following four flags all indicate something special about an edge. + Test the edge flags on EDGE_COMPLEX to detect all forms of "strange" + control flow transfers. */ +#define EDGE_COMPLEX \ + (EDGE_ABNORMAL | EDGE_ABNORMAL_CALL | EDGE_EH | EDGE_PRESERVE) + +struct GTY(()) rtl_bb_info { + /* The first insn of the block is embedded into bb->il.x. */ + /* The last insn of the block. */ + rtx_insn *end_; + + /* In CFGlayout mode points to insn notes/jumptables to be placed just before + and after the block. */ + rtx_insn *header_; + rtx_insn *footer_; +}; + +struct GTY(()) gimple_bb_info { + /* Sequence of statements in this block. */ + gimple_seq seq; + + /* PHI nodes for this block. */ + gimple_seq phi_nodes; +}; + +/* A basic block is a sequence of instructions with only one entry and + only one exit. If any one of the instructions are executed, they + will all be executed, and in sequence from first to last. + + There may be COND_EXEC instructions in the basic block. The + COND_EXEC *instructions* will be executed -- but if the condition + is false the conditionally executed *expressions* will of course + not be executed. We don't consider the conditionally executed + expression (which might have side-effects) to be in a separate + basic block because the program counter will always be at the same + location after the COND_EXEC instruction, regardless of whether the + condition is true or not. + + Basic blocks need not start with a label nor end with a jump insn. + For example, a previous basic block may just "conditionally fall" + into the succeeding basic block, and the last basic block need not + end with a jump insn. Block 0 is a descendant of the entry block. + + A basic block beginning with two labels cannot have notes between + the labels. + + Data for jump tables are stored in jump_insns that occur in no + basic block even though these insns can follow or precede insns in + basic blocks. */ + +/* Basic block information indexed by block number. */ +struct GTY((chain_next ("%h.next_bb"), chain_prev ("%h.prev_bb"))) basic_block_def { + /* The edges into and out of the block. */ + vec<edge, va_gc> *preds; + vec<edge, va_gc> *succs; + + /* Auxiliary info specific to a pass. */ + void *GTY ((skip (""))) aux; + + /* Innermost loop containing the block. */ + class loop *loop_father; + + /* The dominance and postdominance information node. */ + struct et_node * GTY ((skip (""))) dom[2]; + + /* Previous and next blocks in the chain. */ + basic_block prev_bb; + basic_block next_bb; + + union basic_block_il_dependent { + struct gimple_bb_info GTY ((tag ("0"))) gimple; + struct { + rtx_insn *head_; + struct rtl_bb_info * rtl; + } GTY ((tag ("1"))) x; + } GTY ((desc ("((%1.flags & BB_RTL) != 0)"))) il; + + /* Various flags. See cfg-flags.def. */ + int flags; + + /* The index of this block. */ + int index; + + /* Expected number of executions: calculated in profile.cc. */ + profile_count count; +}; + +/* This ensures that struct gimple_bb_info is smaller than + struct rtl_bb_info, so that inlining the former into basic_block_def + is the better choice. */ +STATIC_ASSERT (sizeof (rtl_bb_info) >= sizeof (gimple_bb_info)); + +#define BB_FREQ_MAX 10000 + +/* Masks for basic_block.flags. */ +#define DEF_BASIC_BLOCK_FLAG(NAME,IDX) BB_##NAME = 1 << IDX , +enum cfg_bb_flags +{ +#include "cfg-flags.def" + LAST_CFG_BB_FLAG /* this is only used for BB_ALL_FLAGS */ +}; +#undef DEF_BASIC_BLOCK_FLAG + +/* Bit mask for all basic block flags. */ +#define BB_ALL_FLAGS ((LAST_CFG_BB_FLAG - 1) * 2 - 1) + +/* Bit mask for all basic block flags that must be preserved. These are + the bit masks that are *not* cleared by clear_bb_flags. */ +#define BB_FLAGS_TO_PRESERVE \ + (BB_DISABLE_SCHEDULE | BB_RTL | BB_NON_LOCAL_GOTO_TARGET \ + | BB_HOT_PARTITION | BB_COLD_PARTITION) + +/* Dummy bitmask for convenience in the hot/cold partitioning code. */ +#define BB_UNPARTITIONED 0 + +/* Partitions, to be used when partitioning hot and cold basic blocks into + separate sections. */ +#define BB_PARTITION(bb) ((bb)->flags & (BB_HOT_PARTITION|BB_COLD_PARTITION)) +#define BB_SET_PARTITION(bb, part) do { \ + basic_block bb_ = (bb); \ + bb_->flags = ((bb_->flags & ~(BB_HOT_PARTITION|BB_COLD_PARTITION)) \ + | (part)); \ +} while (0) + +#define BB_COPY_PARTITION(dstbb, srcbb) \ + BB_SET_PARTITION (dstbb, BB_PARTITION (srcbb)) + +/* Defines for accessing the fields of the CFG structure for function FN. */ +#define ENTRY_BLOCK_PTR_FOR_FN(FN) ((FN)->cfg->x_entry_block_ptr) +#define EXIT_BLOCK_PTR_FOR_FN(FN) ((FN)->cfg->x_exit_block_ptr) +#define basic_block_info_for_fn(FN) ((FN)->cfg->x_basic_block_info) +#define n_basic_blocks_for_fn(FN) ((FN)->cfg->x_n_basic_blocks) +#define n_edges_for_fn(FN) ((FN)->cfg->x_n_edges) +#define last_basic_block_for_fn(FN) ((FN)->cfg->x_last_basic_block) +#define label_to_block_map_for_fn(FN) ((FN)->cfg->x_label_to_block_map) +#define profile_status_for_fn(FN) ((FN)->cfg->x_profile_status) + +#define BASIC_BLOCK_FOR_FN(FN,N) \ + ((*basic_block_info_for_fn (FN))[(N)]) +#define SET_BASIC_BLOCK_FOR_FN(FN,N,BB) \ + ((*basic_block_info_for_fn (FN))[(N)] = (BB)) + +/* For iterating over basic blocks. */ +#define FOR_BB_BETWEEN(BB, FROM, TO, DIR) \ + for (BB = FROM; BB != TO; BB = BB->DIR) + +#define FOR_EACH_BB_FN(BB, FN) \ + FOR_BB_BETWEEN (BB, (FN)->cfg->x_entry_block_ptr->next_bb, (FN)->cfg->x_exit_block_ptr, next_bb) + +#define FOR_EACH_BB_REVERSE_FN(BB, FN) \ + FOR_BB_BETWEEN (BB, (FN)->cfg->x_exit_block_ptr->prev_bb, (FN)->cfg->x_entry_block_ptr, prev_bb) + +/* For iterating over insns in basic block. */ +#define FOR_BB_INSNS(BB, INSN) \ + for ((INSN) = BB_HEAD (BB); \ + (INSN) && (INSN) != NEXT_INSN (BB_END (BB)); \ + (INSN) = NEXT_INSN (INSN)) + +/* For iterating over insns in basic block when we might remove the + current insn. */ +#define FOR_BB_INSNS_SAFE(BB, INSN, CURR) \ + for ((INSN) = BB_HEAD (BB), (CURR) = (INSN) ? NEXT_INSN ((INSN)): NULL; \ + (INSN) && (INSN) != NEXT_INSN (BB_END (BB)); \ + (INSN) = (CURR), (CURR) = (INSN) ? NEXT_INSN ((INSN)) : NULL) + +#define FOR_BB_INSNS_REVERSE(BB, INSN) \ + for ((INSN) = BB_END (BB); \ + (INSN) && (INSN) != PREV_INSN (BB_HEAD (BB)); \ + (INSN) = PREV_INSN (INSN)) + +#define FOR_BB_INSNS_REVERSE_SAFE(BB, INSN, CURR) \ + for ((INSN) = BB_END (BB),(CURR) = (INSN) ? PREV_INSN ((INSN)) : NULL; \ + (INSN) && (INSN) != PREV_INSN (BB_HEAD (BB)); \ + (INSN) = (CURR), (CURR) = (INSN) ? PREV_INSN ((INSN)) : NULL) + +/* Cycles through _all_ basic blocks, even the fake ones (entry and + exit block). */ + +#define FOR_ALL_BB_FN(BB, FN) \ + for (BB = ENTRY_BLOCK_PTR_FOR_FN (FN); BB; BB = BB->next_bb) + + +/* Stuff for recording basic block info. */ + +/* For now, these will be functions (so that they can include checked casts + to rtx_insn. Once the underlying fields are converted from rtx + to rtx_insn, these can be converted back to macros. */ + +#define BB_HEAD(B) (B)->il.x.head_ +#define BB_END(B) (B)->il.x.rtl->end_ +#define BB_HEADER(B) (B)->il.x.rtl->header_ +#define BB_FOOTER(B) (B)->il.x.rtl->footer_ + +/* Special block numbers [markers] for entry and exit. + Neither of them is supposed to hold actual statements. */ +#define ENTRY_BLOCK (0) +#define EXIT_BLOCK (1) + +/* The two blocks that are always in the cfg. */ +#define NUM_FIXED_BLOCKS (2) + +/* This is the value which indicates no edge is present. */ +#define EDGE_INDEX_NO_EDGE -1 + +/* EDGE_INDEX returns an integer index for an edge, or EDGE_INDEX_NO_EDGE + if there is no edge between the 2 basic blocks. */ +#define EDGE_INDEX(el, pred, succ) (find_edge_index ((el), (pred), (succ))) + +/* INDEX_EDGE_PRED_BB and INDEX_EDGE_SUCC_BB return a pointer to the basic + block which is either the pred or succ end of the indexed edge. */ +#define INDEX_EDGE_PRED_BB(el, index) ((el)->index_to_edge[(index)]->src) +#define INDEX_EDGE_SUCC_BB(el, index) ((el)->index_to_edge[(index)]->dest) + +/* INDEX_EDGE returns a pointer to the edge. */ +#define INDEX_EDGE(el, index) ((el)->index_to_edge[(index)]) + +/* Number of edges in the compressed edge list. */ +#define NUM_EDGES(el) ((el)->num_edges) + +/* BB is assumed to contain conditional jump. Return the fallthru edge. */ +#define FALLTHRU_EDGE(bb) (EDGE_SUCC ((bb), 0)->flags & EDGE_FALLTHRU \ + ? EDGE_SUCC ((bb), 0) : EDGE_SUCC ((bb), 1)) + +/* BB is assumed to contain conditional jump. Return the branch edge. */ +#define BRANCH_EDGE(bb) (EDGE_SUCC ((bb), 0)->flags & EDGE_FALLTHRU \ + ? EDGE_SUCC ((bb), 1) : EDGE_SUCC ((bb), 0)) + +/* Return expected execution frequency of the edge E. */ +#define EDGE_FREQUENCY(e) e->count ().to_frequency (cfun) + +/* Compute a scale factor (or probability) suitable for scaling of + gcov_type values via apply_probability() and apply_scale(). */ +#define GCOV_COMPUTE_SCALE(num,den) \ + ((den) ? RDIV ((num) * REG_BR_PROB_BASE, (den)) : REG_BR_PROB_BASE) + +/* Return nonzero if edge is critical. */ +#define EDGE_CRITICAL_P(e) (EDGE_COUNT ((e)->src->succs) >= 2 \ + && EDGE_COUNT ((e)->dest->preds) >= 2) + +#define EDGE_COUNT(ev) vec_safe_length (ev) +#define EDGE_I(ev,i) (*ev)[(i)] +#define EDGE_PRED(bb,i) (*(bb)->preds)[(i)] +#define EDGE_SUCC(bb,i) (*(bb)->succs)[(i)] + +/* Returns true if BB has precisely one successor. */ + +inline bool +single_succ_p (const_basic_block bb) +{ + return EDGE_COUNT (bb->succs) == 1; +} + +/* Returns true if BB has precisely one predecessor. */ + +inline bool +single_pred_p (const_basic_block bb) +{ + return EDGE_COUNT (bb->preds) == 1; +} + +/* Returns the single successor edge of basic block BB. Aborts if + BB does not have exactly one successor. */ + +inline edge +single_succ_edge (const_basic_block bb) +{ + gcc_checking_assert (single_succ_p (bb)); + return EDGE_SUCC (bb, 0); +} + +/* Returns the single predecessor edge of basic block BB. Aborts + if BB does not have exactly one predecessor. */ + +inline edge +single_pred_edge (const_basic_block bb) +{ + gcc_checking_assert (single_pred_p (bb)); + return EDGE_PRED (bb, 0); +} + +/* Returns the single successor block of basic block BB. Aborts + if BB does not have exactly one successor. */ + +inline basic_block +single_succ (const_basic_block bb) +{ + return single_succ_edge (bb)->dest; +} + +/* Returns the single predecessor block of basic block BB. Aborts + if BB does not have exactly one predecessor.*/ + +inline basic_block +single_pred (const_basic_block bb) +{ + return single_pred_edge (bb)->src; +} + +/* Iterator object for edges. */ + +struct edge_iterator { + unsigned index; + vec<edge, va_gc> **container; +}; + +inline vec<edge, va_gc> * +ei_container (edge_iterator i) +{ + gcc_checking_assert (i.container); + return *i.container; +} + +#define ei_start(iter) ei_start_1 (&(iter)) +#define ei_last(iter) ei_last_1 (&(iter)) + +/* Return an iterator pointing to the start of an edge vector. */ +inline edge_iterator +ei_start_1 (vec<edge, va_gc> **ev) +{ + edge_iterator i; + + i.index = 0; + i.container = ev; + + return i; +} + +/* Return an iterator pointing to the last element of an edge + vector. */ +inline edge_iterator +ei_last_1 (vec<edge, va_gc> **ev) +{ + edge_iterator i; + + i.index = EDGE_COUNT (*ev) - 1; + i.container = ev; + + return i; +} + +/* Is the iterator `i' at the end of the sequence? */ +inline bool +ei_end_p (edge_iterator i) +{ + return (i.index == EDGE_COUNT (ei_container (i))); +} + +/* Is the iterator `i' at one position before the end of the + sequence? */ +inline bool +ei_one_before_end_p (edge_iterator i) +{ + return (i.index + 1 == EDGE_COUNT (ei_container (i))); +} + +/* Advance the iterator to the next element. */ +inline void +ei_next (edge_iterator *i) +{ + gcc_checking_assert (i->index < EDGE_COUNT (ei_container (*i))); + i->index++; +} + +/* Move the iterator to the previous element. */ +inline void +ei_prev (edge_iterator *i) +{ + gcc_checking_assert (i->index > 0); + i->index--; +} + +/* Return the edge pointed to by the iterator `i'. */ +inline edge +ei_edge (edge_iterator i) +{ + return EDGE_I (ei_container (i), i.index); +} + +/* Return an edge pointed to by the iterator. Do it safely so that + NULL is returned when the iterator is pointing at the end of the + sequence. */ +inline edge +ei_safe_edge (edge_iterator i) +{ + return !ei_end_p (i) ? ei_edge (i) : NULL; +} + +/* Return 1 if we should continue to iterate. Return 0 otherwise. + *Edge P is set to the next edge if we are to continue to iterate + and NULL otherwise. */ + +inline bool +ei_cond (edge_iterator ei, edge *p) +{ + if (!ei_end_p (ei)) + { + *p = ei_edge (ei); + return 1; + } + else + { + *p = NULL; + return 0; + } +} + +/* This macro serves as a convenient way to iterate each edge in a + vector of predecessor or successor edges. It must not be used when + an element might be removed during the traversal, otherwise + elements will be missed. Instead, use a for-loop like that shown + in the following pseudo-code: + + FOR (ei = ei_start (bb->succs); (e = ei_safe_edge (ei)); ) + { + IF (e != taken_edge) + remove_edge (e); + ELSE + ei_next (&ei); + } +*/ + +#define FOR_EACH_EDGE(EDGE,ITER,EDGE_VEC) \ + for ((ITER) = ei_start ((EDGE_VEC)); \ + ei_cond ((ITER), &(EDGE)); \ + ei_next (&(ITER))) + +#define CLEANUP_EXPENSIVE 1 /* Do relatively expensive optimizations + except for edge forwarding */ +#define CLEANUP_CROSSJUMP 2 /* Do crossjumping. */ +#define CLEANUP_POST_REGSTACK 4 /* We run after reg-stack and need + to care REG_DEAD notes. */ +#define CLEANUP_THREADING 8 /* Do jump threading. */ +#define CLEANUP_NO_INSN_DEL 16 /* Do not try to delete trivially dead + insns. */ +#define CLEANUP_CFGLAYOUT 32 /* Do cleanup in cfglayout mode. */ +#define CLEANUP_CFG_CHANGED 64 /* The caller changed the CFG. */ +#define CLEANUP_NO_PARTITIONING 128 /* Do not try to fix partitions. */ +#define CLEANUP_FORCE_FAST_DCE 0x100 /* Force run_fast_dce to be called + at least once. */ + +/* Return true if BB is in a transaction. */ + +inline bool +bb_in_transaction (basic_block bb) +{ + return bb->flags & BB_IN_TRANSACTION; +} + +/* Return true when one of the predecessor edges of BB is marked with EDGE_EH. */ +inline bool +bb_has_eh_pred (basic_block bb) +{ + edge e; + edge_iterator ei; + + FOR_EACH_EDGE (e, ei, bb->preds) + { + if (e->flags & EDGE_EH) + return true; + } + return false; +} + +/* Return true when one of the predecessor edges of BB is marked with EDGE_ABNORMAL. */ +inline bool +bb_has_abnormal_pred (basic_block bb) +{ + edge e; + edge_iterator ei; + + FOR_EACH_EDGE (e, ei, bb->preds) + { + if (e->flags & EDGE_ABNORMAL) + return true; + } + return false; +} + +/* Return the fallthru edge in EDGES if it exists, NULL otherwise. */ +inline edge +find_fallthru_edge (vec<edge, va_gc> *edges) +{ + edge e; + edge_iterator ei; + + FOR_EACH_EDGE (e, ei, edges) + if (e->flags & EDGE_FALLTHRU) + break; + + return e; +} + +/* Check tha probability is sane. */ + +inline void +check_probability (int prob) +{ + gcc_checking_assert (prob >= 0 && prob <= REG_BR_PROB_BASE); +} + +/* Given PROB1 and PROB2, return PROB1*PROB2/REG_BR_PROB_BASE. + Used to combine BB probabilities. */ + +inline int +combine_probabilities (int prob1, int prob2) +{ + check_probability (prob1); + check_probability (prob2); + return RDIV (prob1 * prob2, REG_BR_PROB_BASE); +} + +/* Apply scale factor SCALE on frequency or count FREQ. Use this + interface when potentially scaling up, so that SCALE is not + constrained to be < REG_BR_PROB_BASE. */ + +inline gcov_type +apply_scale (gcov_type freq, gcov_type scale) +{ + return RDIV (freq * scale, REG_BR_PROB_BASE); +} + +/* Apply probability PROB on frequency or count FREQ. */ + +inline gcov_type +apply_probability (gcov_type freq, int prob) +{ + check_probability (prob); + return apply_scale (freq, prob); +} + +/* Return inverse probability for PROB. */ + +inline int +inverse_probability (int prob1) +{ + check_probability (prob1); + return REG_BR_PROB_BASE - prob1; +} + +/* Return true if BB has at least one abnormal outgoing edge. */ + +inline bool +has_abnormal_or_eh_outgoing_edge_p (basic_block bb) +{ + edge e; + edge_iterator ei; + + FOR_EACH_EDGE (e, ei, bb->succs) + if (e->flags & (EDGE_ABNORMAL | EDGE_EH)) + return true; + + return false; +} + +/* Return true when one of the predecessor edges of BB is marked with + EDGE_ABNORMAL_CALL or EDGE_EH. */ + +inline bool +has_abnormal_call_or_eh_pred_edge_p (basic_block bb) +{ + edge e; + edge_iterator ei; + + FOR_EACH_EDGE (e, ei, bb->preds) + if (e->flags & (EDGE_ABNORMAL_CALL | EDGE_EH)) + return true; + + return false; +} + +/* Return count of edge E. */ +inline profile_count edge_def::count () const +{ + return src->count.apply_probability (probability); +} + +#endif /* GCC_BASIC_BLOCK_H */ |