From 5c35539b1ab41da8800ebb1fdc983237a7d9cdd7 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 7 Oct 1998 18:26:18 -0700 Subject: [PATCH] flow.c (find_basic_blocks): Calc upper bound for extra nops in max_uids_for_flow. * flow.c (find_basic_blocks): Calc upper bound for extra nops in max_uids_for_flow. (find_basic_blocks_1): Add a nop to the end of a basic block when a trailing call insn does not have abnormal control flow. * gcse.c (pre_transpout): New variable. (alloc_pre_mem, free_pre_mem, dump_pre_data): Bookkeeping for it. (compute_pre_transpout): Calculate it. (compute_pre_ppinout): Use it to eliminate impossible placements due to abnormal control flow through calls. (compute_pre_data): Call compute_pre_transpout. From-SVN: r22907 --- gcc/ChangeLog | 13 +++++++++ gcc/flow.c | 69 +++++++++++++++++++++++++++++++++---------- gcc/gcse.c | 81 ++++++++++++++++++++++++++++++++++++++++++++------- 3 files changed, 138 insertions(+), 25 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 74dab80df36..d7d849048b2 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,16 @@ +Thu Oct 8 01:25:22 1998 Richard Henderson + + * flow.c (find_basic_blocks): Calc upper bound for extra nops in + max_uids_for_flow. + (find_basic_blocks_1): Add a nop to the end of a basic block when + a trailing call insn does not have abnormal control flow. + * gcse.c (pre_transpout): New variable. + (alloc_pre_mem, free_pre_mem, dump_pre_data): Bookkeeping for it. + (compute_pre_transpout): Calculate it. + (compute_pre_ppinout): Use it to eliminate impossible placements + due to abnormal control flow through calls. + (compute_pre_data): Call compute_pre_transpout. + Wed Oct 7 21:40:24 1998 David S. Miller * config/sparc/sol2-sld-64.h (ASM_CPU_SPEC): Fix typo. diff --git a/gcc/flow.c b/gcc/flow.c index d6024369e74..773aaf2be96 100644 --- a/gcc/flow.c +++ b/gcc/flow.c @@ -306,6 +306,7 @@ find_basic_blocks (f, nregs, file, live_reachable_p) register int i; rtx nonlocal_label_list = nonlocal_label_rtx_list (); int in_libcall_block = 0; + int extra_uids_for_flow = 0; /* Count the basic blocks. Also find maximum insn uid value used. */ @@ -318,7 +319,6 @@ find_basic_blocks (f, nregs, file, live_reachable_p) for (insn = f, i = 0; insn; insn = NEXT_INSN (insn)) { - /* Track when we are inside in LIBCALL block. */ if (GET_RTX_CLASS (GET_CODE (insn)) == 'i' && find_reg_note (insn, REG_LIBCALL, NULL_RTX)) @@ -327,13 +327,33 @@ find_basic_blocks (f, nregs, file, live_reachable_p) code = GET_CODE (insn); if (INSN_UID (insn) > max_uid_for_flow) max_uid_for_flow = INSN_UID (insn); - if (code == CODE_LABEL - || (GET_RTX_CLASS (code) == 'i' - && (prev_code == JUMP_INSN - || (prev_code == CALL_INSN - && (nonlocal_label_list != 0 || eh_region)) - || prev_code == BARRIER))) + if (code == CODE_LABEL) i++; + else if (GET_RTX_CLASS (code) == 'i') + { + if (prev_code == JUMP_INSN || prev_code == BARRIER) + i++; + else if (prev_code == CALL_INSN) + { + if (nonlocal_label_list != 0 || eh_region) + i++; + else + { + /* Else this call does not force a new block to be + created. However, it may still be the end of a basic + block if it is followed by a CODE_LABEL or a BARRIER. + + To disambiguate calls which force new blocks to be + created from those which just happen to be at the end + of a block we insert nops during find_basic_blocks_1 + after calls which are the last insn in a block by + chance. We must account for such insns in + max_uid_for_flow. */ + + extra_uids_for_flow++; + } + } + } /* We change the code of the CALL_INSN, so that it won't start a new block. */ @@ -360,6 +380,7 @@ find_basic_blocks (f, nregs, file, live_reachable_p) These cases are rare, so we don't need too much space. */ max_uid_for_flow += max_uid_for_flow / 10; #endif + max_uid_for_flow += extra_uids_for_flow; /* Allocate some tables that last till end of compiling this function and some needed only in find_basic_blocks and life_analysis. */ @@ -410,6 +431,7 @@ find_basic_blocks_1 (f, nonlocal_label_list, live_reachable_p) int depth, pass; int in_libcall_block = 0; int deleted_handler = 0; + int call_had_abnormal_edge = 0; pass = 1; active_eh_region = (int *) alloca ((max_uid_for_flow + 1) * sizeof (int)); @@ -456,8 +478,7 @@ find_basic_blocks_1 (f, nonlocal_label_list, live_reachable_p) else if (code == CODE_LABEL || (GET_RTX_CLASS (code) == 'i' && (prev_code == JUMP_INSN - || (prev_code == CALL_INSN - && (nonlocal_label_list != 0 || eh_note)) + || (prev_code == CALL_INSN && call_had_abnormal_edge) || prev_code == BARRIER))) { basic_block_head[++i] = insn; @@ -466,12 +487,26 @@ find_basic_blocks_1 (f, nonlocal_label_list, live_reachable_p) if (code == CODE_LABEL) { - LABEL_REFS (insn) = insn; - /* Any label that cannot be deleted - is considered to start a reachable block. */ - if (LABEL_PRESERVE_P (insn)) - block_live[i] = 1; - } + LABEL_REFS (insn) = insn; + /* Any label that cannot be deleted + is considered to start a reachable block. */ + if (LABEL_PRESERVE_P (insn)) + block_live[i] = 1; + } + + /* If the previous insn was a call that did not create an + abnormal edge, we want to add a nop so that the CALL_INSN + itself is not at basic_block_end. This allows us to easily + distinguish between normal calls and those which create + abnormal edges in the flow graph. */ + + if (i > 0 && !call_had_abnormal_edge + && GET_CODE (basic_block_end[i-1]) == CALL_INSN) + { + rtx nop = gen_rtx_USE (VOIDmode, const0_rtx); + nop = emit_insn_after (nop, basic_block_end[i-1]); + basic_block_end[i-1] = nop; + } } else if (GET_RTX_CLASS (code) == 'i') @@ -524,6 +559,10 @@ find_basic_blocks_1 (f, nonlocal_label_list, live_reachable_p) if (code == CALL_INSN && in_libcall_block) code = INSN; + /* Record whether this call created an edge. */ + if (code == CALL_INSN) + call_had_abnormal_edge = (nonlocal_label_list != 0 || eh_note); + if (code != NOTE) prev_code = code; diff --git a/gcc/gcse.c b/gcc/gcse.c index c77aa33d022..0732cb4cadd 100644 --- a/gcc/gcse.c +++ b/gcc/gcse.c @@ -3888,6 +3888,11 @@ static sbitmap *pre_pavout; static sbitmap *pre_ppin; static sbitmap *pre_ppout; +/* Nonzero for expressions that are transparent at the end of the block. + This is only zero for expressions killed by abnormal critical edge + created by a calls. */ +static sbitmap *pre_transpout; + /* Used while performing PRE to denote which insns are redundant. */ static sbitmap pre_redundant; @@ -3910,6 +3915,8 @@ alloc_pre_mem (n_blocks, n_exprs) pre_pavout = sbitmap_vector_alloc (n_blocks, n_exprs); pre_ppin = sbitmap_vector_alloc (n_blocks, n_exprs); pre_ppout = sbitmap_vector_alloc (n_blocks, n_exprs); + + pre_transpout = sbitmap_vector_alloc (n_blocks, n_exprs); } /* Free vars used for PRE analysis. */ @@ -3920,7 +3927,6 @@ free_pre_mem () free (pre_transp); free (pre_comp); free (pre_antloc); - free (pre_avin); free (pre_avout); free (pre_antin); @@ -3930,6 +3936,7 @@ free_pre_mem () free (pre_pavout); free (pre_ppin); free (pre_ppout); + free (pre_transpout); } /* Dump PRE data. */ @@ -3962,6 +3969,9 @@ dump_pre_data (file) pre_ppin, n_basic_blocks); dump_sbitmap_vector (file, "PRE placement possible on outgoing", "BB", pre_ppout, n_basic_blocks); + + dump_sbitmap_vector (file, "PRE transparent on outgoing", "BB", + pre_transpout, n_basic_blocks); } /* Compute the local properties of each recorded expression. @@ -4129,6 +4139,57 @@ compute_pre_pavinout () fprintf (gcse_file, "partially avail expr computation: %d passes\n", passes); } +/* Compute transparent outgoing information for each block. + + An expression is transparent to an edge unless it is killed by + the edge itself. This can only happen with abnormal control flow, + when the edge is traversed through a call. This happens with + non-local labels and exceptions. + + This would not be necessary if we split the edge. While this is + normally impossible for abnormal critical edges, with some effort + it should be possible with exception handling, since we still have + control over which handler should be invoked. But due to increased + EH table sizes, this may not be worthwhile. */ + +static void +compute_pre_transpout () +{ + int bb; + + sbitmap_vector_ones (pre_transpout, n_basic_blocks); + + for (bb = 0; bb < n_basic_blocks; ++bb) + { + int i; + + /* Note that flow inserted a nop a the end of basic blocks that + end in call instructions for reasons other than abnormal + control flow. */ + if (GET_CODE (BLOCK_END (bb)) != CALL_INSN) + continue; + + for (i = 0; i < expr_hash_table_size; i++) + { + struct expr *expr; + for (expr = expr_hash_table[i]; expr ; expr = expr->next_same_hash) + if (GET_CODE (expr->expr) == MEM) + { + rtx addr = XEXP (expr->expr, 0); + + if (GET_CODE (addr) == SYMBOL_REF + && CONSTANT_POOL_ADDRESS_P (addr)) + continue; + + /* ??? Optimally, we would use interprocedural alias + analysis to determine if this mem is actually killed + by this call. */ + RESET_BIT (pre_transpout[bb], expr->bitmap_index); + } + } + } +} + /* Compute "placement possible" information on entrance and exit of each block. @@ -4209,11 +4270,12 @@ compute_pre_ppinout () for (bb = 0; bb < n_basic_blocks - 1; bb++) { sbitmap_ptr ppout = pre_ppout[bb]->elms; + sbitmap_ptr transpout = pre_transpout[bb]->elms; for (i = 0; i < size; i++) { int_list_ptr succ; - SBITMAP_ELT_TYPE tmp = -1L; + SBITMAP_ELT_TYPE tmp = *transpout; for (succ = s_succs[bb]; succ != NULL; succ = succ->next) { @@ -4226,13 +4288,14 @@ compute_pre_ppinout () ppin = pre_ppin[succ_bb]->elms + i; tmp &= *ppin; } + if (*ppout != tmp) { changed = 1; - *ppout++ = tmp; + *ppout = tmp; } - else - ppout++; + + ppout++; transpout++; } } @@ -4252,6 +4315,7 @@ compute_pre_data () compute_pre_avinout (); compute_pre_antinout (); compute_pre_pavinout (); + compute_pre_transpout (); compute_pre_ppinout (); if (gcse_file) fprintf (gcse_file, "\n"); @@ -4376,10 +4440,7 @@ pre_insert_insn (expr, bb) } /* Likewise if the last insn is a call, as will happen in the presence of exception handling. */ - /* ??? The flag_exceptions test is not exact. We don't know if we are - actually in an eh region. Fix flow to tell us this. */ - else if (GET_CODE (insn) == CALL_INSN - && (current_function_has_nonlocal_label || flag_exceptions)) + else if (GET_CODE (insn) == CALL_INSN) { HARD_REG_SET parm_regs; int nparm_regs; @@ -4409,7 +4470,7 @@ pre_insert_insn (expr, bb) { int regno = REGNO (XEXP (XEXP (p, 0), 0)); if (regno >= FIRST_PSEUDO_REGISTER) - abort(); + abort (); SET_HARD_REG_BIT (parm_regs, regno); nparm_regs++; } -- 2.30.2