From b932f770f70d60b1d6c89d6ef1fe8dc88bdecda1 Mon Sep 17 00:00:00 2001 From: Jan Hubicka Date: Sat, 20 Oct 2001 12:04:00 +0200 Subject: basic-block.h (find_sub_basic_blocks): Use sbitmap parameter. * basic-block.h (find_sub_basic_blocks): Use sbitmap parameter. * cfgbuild.c (find_bb_boundaries, compute_outgoing_frequencies): Break out from ... (find_sub_basic_blocks): ... here; (find_many_sub_basic_blocks): New. * recog.c (split_all_insns): Update find_sub_basic_blocks call. * i386.h (ASM_PREFERRED_EH_DATA_FORMAT): Define sdata4. * i386.c (ix86_va_arg): Kill indirect_p handling; fix aliasing issues.: * i386.c (split_di, split_ti): Revamp to use simplify_subreg. * timevar.def (TV_LIFE, TV_LIFE_UPDATE, TV_MODE_SWITCH): new. * flow.c (update_life_info): Measure time. * c-decl.c: Include timevar.h (c_expand_body): Measure time. * toplev.c (rest_of_compilation): Measure time of mode switching separately. * Makefile.in (c-decl.o, cfgcleanup.o): Add dependancy. * toplev.c (flag_asynchronous_unwind_tables): New global variable. (lang_independent_options): Add asynchronous-unwind-tables (toplev_main): flag_asynchronous_unwind_tables implies flag_unwind_tables. * flags.h (flag_asynchronous_unwind_tables): Declare. * dwarf2out.c (dwarf2out_stack_adjust): Take into account flag_asynchronous_unwind_tables. (output_call_frame_info): Likewise. * invoke.texi (-fasynchronous-unwind-tables): Document. * i386.c (optimization_options): Enable flag_asynchronous_unwind_tables. * i386.c (ix86_expand_setcc): Always expect target to be QImode. * i386.md (s* expanders): Destination is QImode. * toplev.c (rest_of_compilation): Do not call clear_log_links. * rtl.h (clear_log_links): Kill. * flow.c (clear_log_links): Make static; accept blocks parameter; do no clear life info. (update_life_info): Call clear_log_links. * cfganal.c (forwarder_block_p): Avoid active_insn_p calls. From-SVN: r46374 --- gcc/ChangeLog | 46 +++++++++++++ gcc/Makefile.in | 4 +- gcc/basic-block.h | 1 + gcc/c-decl.c | 4 ++ gcc/cfganal.c | 7 +- gcc/cfgbuild.c | 170 ++++++++++++++++++++++++++++++++++++++---------- gcc/config/i386/i386.c | 133 ++++++++----------------------------- gcc/config/i386/i386.h | 3 +- gcc/config/i386/i386.md | 72 ++++++++++---------- gcc/doc/invoke.texi | 8 ++- gcc/dwarf2out.c | 7 +- gcc/flags.h | 4 ++ gcc/flow.c | 52 +++++++++------ gcc/recog.c | 3 +- gcc/rtl.h | 1 - gcc/timevar.def | 4 ++ gcc/toplev.c | 19 ++++-- 17 files changed, 322 insertions(+), 216 deletions(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 834268d..8b6793b 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,49 @@ +Sat Oct 20 12:01:07 CEST 2001 Jan Hubicka + + * basic-block.h (find_sub_basic_blocks): Use sbitmap parameter. + * cfgbuild.c (find_bb_boundaries, compute_outgoing_frequencies): + Break out from ... + (find_sub_basic_blocks): ... here; + (find_many_sub_basic_blocks): New. + * recog.c (split_all_insns): Update find_sub_basic_blocks call. + + * i386.h (ASM_PREFERRED_EH_DATA_FORMAT): Define sdata4. + + * i386.c (ix86_va_arg): Kill indirect_p handling; fix aliasing issues.: + + * i386.c (split_di, split_ti): Revamp to use simplify_subreg. + + * timevar.def (TV_LIFE, TV_LIFE_UPDATE, TV_MODE_SWITCH): new. + * flow.c (update_life_info): Measure time. + * c-decl.c: Include timevar.h + (c_expand_body): Measure time. + * toplev.c (rest_of_compilation): Measure time of mode switching + separately. + * Makefile.in (c-decl.o, cfgcleanup.o): Add dependancy. + + * toplev.c (flag_asynchronous_unwind_tables): New global variable. + (lang_independent_options): Add asynchronous-unwind-tables + (toplev_main): flag_asynchronous_unwind_tables implies + flag_unwind_tables. + * flags.h (flag_asynchronous_unwind_tables): Declare. + * dwarf2out.c (dwarf2out_stack_adjust): Take into account + flag_asynchronous_unwind_tables. + (output_call_frame_info): Likewise. + * invoke.texi (-fasynchronous-unwind-tables): Document. + * i386.c (optimization_options): Enable + flag_asynchronous_unwind_tables. + + * i386.c (ix86_expand_setcc): Always expect target to be QImode. + * i386.md (s* expanders): Destination is QImode. + + * toplev.c (rest_of_compilation): Do not call clear_log_links. + * rtl.h (clear_log_links): Kill. + * flow.c (clear_log_links): Make static; accept blocks parameter; + do no clear life info. + (update_life_info): Call clear_log_links. + + * cfganal.c (forwarder_block_p): Avoid active_insn_p calls. + 2001-10-20 Neil Booth * cpplex.c (handle_newline, skip_escaped_newlines, diff --git a/gcc/Makefile.in b/gcc/Makefile.in index c930972..00577e1 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -1168,7 +1168,7 @@ $(srcdir)/c-parse.y: c-parse.in c-decl.o : c-decl.c $(CONFIG_H) $(SYSTEM_H) $(TREE_H) $(RTL_H) $(C_TREE_H) \ $(GGC_H) $(TARGET_H) c-lex.h flags.h function.h output.h $(EXPR_H) \ - debug.h toplev.h intl.h $(TM_P_H) tree-inline.h + debug.h toplev.h intl.h $(TM_P_H) tree-inline.h $(TIMEVAR_H) c-typeck.o : c-typeck.c $(CONFIG_H) $(SYSTEM_H) $(TREE_H) $(C_TREE_H) \ $(TARGET_H) flags.h intl.h output.h $(EXPR_H) $(RTL_H) toplev.h $(TM_P_H) c-lang.o : c-lang.c $(CONFIG_H) $(SYSTEM_H) $(TREE_H) $(C_TREE_H) \ @@ -1512,7 +1512,7 @@ cfganal.o : cfganal.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) \ cfgbuild.o : cfgbuild.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) flags.h insn-config.h \ $(BASIC_BLOCK_H) $(REGS_H) hard-reg-set.h output.h toplev.h $(RECOG_H) \ function.h except.h $(GGC_H) -cfgcleanup.o : cfgcleanup.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) \ +cfgcleanup.o : cfgcleanup.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) $(TIMEVAR_H)\ $(BASIC_BLOCK_H) hard-reg-set.h output.h flags.h $(RECOG_H) toplev.h $(GGC_H) cfgloop.o : cfgloop.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) \ $(BASIC_BLOCK_H) hard-reg-set.h diff --git a/gcc/basic-block.h b/gcc/basic-block.h index c56ea77..1a0cab6 100644 --- a/gcc/basic-block.h +++ b/gcc/basic-block.h @@ -640,6 +640,7 @@ extern bool forwarder_block_p PARAMS ((basic_block)); extern bool purge_all_dead_edges PARAMS ((void)); extern bool purge_dead_edges PARAMS ((basic_block)); extern void find_sub_basic_blocks PARAMS ((basic_block)); +extern void find_many_sub_basic_blocks PARAMS ((sbitmap)); extern bool can_fallthru PARAMS ((basic_block, basic_block)); extern void flow_nodes_print PARAMS ((const char *, const sbitmap, FILE *)); diff --git a/gcc/c-decl.c b/gcc/c-decl.c index de553b1..45b923a 100644 --- a/gcc/c-decl.c +++ b/gcc/c-decl.c @@ -44,6 +44,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #include "cpplib.h" #include "target.h" #include "debug.h" +#include "timevar.h" /* In grokdeclarator, distinguish syntactic contexts of declarators. */ enum decl_context @@ -6802,6 +6803,8 @@ c_expand_body (fndecl, nested_p) if (flag_syntax_only) return; + timevar_push (TV_EXPAND); + if (flag_inline_trees) { /* First, cache whether the current function is inlinable. Some @@ -6952,6 +6955,7 @@ c_expand_body (fndecl, nested_p) if (nested_p) /* Return to the enclosing function. */ pop_function_context (); + timevar_pop (TV_EXPAND); } /* Check the declarations given in a for-loop for satisfying the C99 diff --git a/gcc/cfganal.c b/gcc/cfganal.c index 5ad1a10..8615a14 100644 --- a/gcc/cfganal.c +++ b/gcc/cfganal.c @@ -67,12 +67,13 @@ forwarder_block_p (bb) while (insn != bb->end) { - if (active_insn_p (insn)) + if (INSN_P (insn) && active_insn_p (insn)) return false; insn = NEXT_INSN (insn); } - return (!active_insn_p (insn) - || (GET_CODE (insn) == JUMP_INSN && onlyjump_p (insn))); + return (!INSN_P (insn) + || (GET_CODE (insn) == JUMP_INSN && simplejump_p (insn)) + || !active_insn_p (insn)); } /* Return nonzero if we can reach target from src by falling trought. */ diff --git a/gcc/cfgbuild.c b/gcc/cfgbuild.c index b27c239..ef86939 100644 --- a/gcc/cfgbuild.c +++ b/gcc/cfgbuild.c @@ -55,6 +55,8 @@ static void make_edges PARAMS ((rtx, int, int, int)); static void make_label_edge PARAMS ((sbitmap *, basic_block, rtx, int)); static void make_eh_edge PARAMS ((sbitmap *, basic_block, rtx)); +static void find_bb_boundaries PARAMS ((basic_block)); +static void compute_outgoing_frequencies PARAMS ((basic_block)); /* Count the basic blocks of the function. */ @@ -246,7 +248,8 @@ make_edges (label_value_list, min, max, update_p) } /* By nature of the way these get numbered, block 0 is always the entry. */ - cached_make_edge (edge_cache, ENTRY_BLOCK_PTR, BASIC_BLOCK (0), EDGE_FALLTHRU); + if (min == 0) + cached_make_edge (edge_cache, ENTRY_BLOCK_PTR, BASIC_BLOCK (0), EDGE_FALLTHRU); for (i = min; i <= max; ++i) { @@ -663,18 +666,27 @@ find_basic_blocks (f, nregs, file) timevar_pop (TV_CFG); } -/* Assume that someone emitted code with control flow instructions to the - basic block. Update the data structure. */ -void -find_sub_basic_blocks (bb) +/* State of basic block as seen by find_sub_basic_blocks. */ +enum state + { + BLOCK_NEW = 0, + BLOCK_ORIGINAL, + BLOCK_TO_SPLIT + }; +#define STATE(bb) (enum state)(size_t)(bb)->aux +#define SET_STATE(bb, state) (bb)->aux = (void *)(state) + +/* Scan basic block BB for possible BB boundaries inside the block + and create new basic blocks in the progress. */ + +static void +find_bb_boundaries (bb) basic_block bb; { rtx insn = bb->head; rtx end = bb->end; rtx flow_transfer_insn = NULL_RTX; edge fallthru = NULL; - basic_block first_bb = bb; - int i; if (insn == bb->end) return; @@ -694,7 +706,7 @@ find_sub_basic_blocks (bb) abort (); break; - /* On code label, split current basic block. */ + /* On code label, split current basic block. */ case CODE_LABEL: fallthru = split_block (bb, PREV_INSN (insn)); if (flow_transfer_insn) @@ -725,7 +737,7 @@ find_sub_basic_blocks (bb) { if (GET_CODE (PATTERN (insn)) == ADDR_VEC || GET_CODE (PATTERN (insn)) == ADDR_DIFF_VEC) - abort(); + abort (); flow_transfer_insn = insn; } else if (code == CALL_INSN) @@ -764,18 +776,87 @@ find_sub_basic_blocks (bb) followed by cleanup at fallthru edge, so the outgoing edges may be dead. */ purge_dead_edges (bb); +} + +/* Assume that frequency of basic block B is known. Compute frequencies + and probabilities of outgoing edges. */ + +static void +compute_outgoing_frequencies (b) + basic_block b; +{ + edge e, f; + if (b->succ && b->succ->succ_next && !b->succ->succ_next->succ_next) + { + rtx note = find_reg_note (b->end, REG_BR_PROB, NULL); + int probability; + + if (!note) + return; + probability = INTVAL (XEXP (find_reg_note (b->end, + REG_BR_PROB, NULL), 0)); + e = BRANCH_EDGE (b); + e->probability = probability; + e->count = ((b->count * probability + REG_BR_PROB_BASE / 2) + / REG_BR_PROB_BASE); + f = FALLTHRU_EDGE (b); + f->probability = REG_BR_PROB_BASE - probability; + f->count = b->count - e->count; + } + if (b->succ && !b->succ->succ_next) + { + e = b->succ; + e->probability = REG_BR_PROB_BASE; + e->count = b->count; + } +} + +/* Assume that someone emitted code with control flow instructions to the + basic block. Update the data structure. */ + +void +find_many_sub_basic_blocks (blocks) + sbitmap blocks; +{ + int i; + int min, max; + + for (i = 0; i < n_basic_blocks; i++) + { + SET_STATE (BASIC_BLOCK (i), + TEST_BIT (blocks, i) + ? BLOCK_TO_SPLIT : BLOCK_ORIGINAL); + } + + for (i = 0; i < n_basic_blocks; i++) + { + basic_block bb = BASIC_BLOCK (i); + if (STATE (bb) == BLOCK_TO_SPLIT) + find_bb_boundaries (bb); + } + + for (i = 0; i < n_basic_blocks; i++) + if (STATE (BASIC_BLOCK (i)) != BLOCK_ORIGINAL) + break; + min = max = i; + for (; i < n_basic_blocks; i++) + if (STATE (BASIC_BLOCK (i)) != BLOCK_ORIGINAL) + max = i; /* Now re-scan and wire in all edges. This expect simple (conditional) jumps at the end of each new basic blocks. */ - make_edges (NULL, first_bb->index, bb->index, 1); + make_edges (NULL, min, max, 1); /* Update branch probabilities. Expect only (un)conditional jumps to be created with only the forward edges. */ - for (i = first_bb->index; i <= bb->index; i++) + for (i = min; i <= max; i++) { - edge e,f; + edge e; basic_block b = BASIC_BLOCK (i); - if (b != first_bb) + + if (STATE (b) == BLOCK_ORIGINAL) + continue; + if (STATE (b) == BLOCK_NEW) { b->count = 0; b->frequency = 0; @@ -785,29 +866,48 @@ find_sub_basic_blocks (bb) b->frequency += EDGE_FREQUENCY (e); } } - if (b->succ && b->succ->succ_next && !b->succ->succ_next->succ_next) - { - rtx note = find_reg_note (b->end, REG_BR_PROB, NULL); - int probability; - - if (!note) - continue; - probability = INTVAL (XEXP (find_reg_note (b->end, - REG_BR_PROB, - NULL), 0)); - e = BRANCH_EDGE (b); - e->probability = probability; - e->count = ((b->count * probability + REG_BR_PROB_BASE / 2) - / REG_BR_PROB_BASE); - f = FALLTHRU_EDGE (b); - f->probability = REG_BR_PROB_BASE - probability; - f->count = b->count - e->count; - } - if (b->succ && !b->succ->succ_next) + compute_outgoing_frequencies (b); + } + for (i = 0; i < n_basic_blocks; i++) + SET_STATE (BASIC_BLOCK (i), 0); +} + +/* Like above but for single basic block only. */ + +void +find_sub_basic_blocks (bb) + basic_block bb; +{ + int i; + int min, max; + basic_block next = (bb->index == n_basic_blocks - 1 + ? NULL : BASIC_BLOCK (bb->index + 1)); + + min = bb->index; + find_bb_boundaries (bb); + max = (next ? next->index : n_basic_blocks) - 1; + + /* Now re-scan and wire in all edges. This expect simple (conditional) + jumps at the end of each new basic blocks. */ + make_edges (NULL, min, max, 1); + + /* Update branch probabilities. Expect only (un)conditional jumps + to be created with only the forward edges. */ + for (i = min; i <= max; i++) + { + edge e; + basic_block b = BASIC_BLOCK (i); + + if (i != min) { - e = b->succ; - e->probability = REG_BR_PROB_BASE; - e->count = b->count; + b->count = 0; + b->frequency = 0; + for (e = b->pred; e; e=e->pred_next) + { + b->count += e->count; + b->frequency += EDGE_FREQUENCY (e); + } } + compute_outgoing_frequencies (b); } } diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c index 6be389c..b9f1470 100644 --- a/gcc/config/i386/i386.c +++ b/gcc/config/i386/i386.c @@ -1061,7 +1061,10 @@ optimization_options (level, size) if (TARGET_64BIT && optimize >= 1) flag_omit_frame_pointer = 1; if (TARGET_64BIT) - flag_pcc_struct_return = 0; + { + flag_pcc_struct_return = 0; + flag_asynchronous_unwind_tables = 1; + } } /* Table of valid machine attributes. */ @@ -2331,7 +2334,7 @@ ix86_va_arg (valist, type) static int intreg[6] = { 0, 1, 2, 3, 4, 5 }; tree f_gpr, f_fpr, f_ovf, f_sav; tree gpr, fpr, ovf, sav, t; - int indirect_p = 0, size, rsize; + int size, rsize; rtx lab_false, lab_over = NULL_RTX; rtx addr_rtx, r; rtx container; @@ -2459,9 +2462,11 @@ ix86_va_arg (valist, type) int i; rtx mem; - mem = assign_temp (type, 0, 1, 0); + /* Never use the memory itself, as it has the alias set. */ + addr_rtx = XEXP (assign_temp (type, 0, 1, 0), 0); + mem = gen_rtx_MEM (BLKmode, addr_rtx); set_mem_alias_set (mem, get_varargs_alias_set ()); - addr_rtx = XEXP (mem, 0); + for (i = 0; i < XVECLEN (container, 0); i++) { rtx slot = XVECEXP (container, 0, i); @@ -2487,7 +2492,6 @@ ix86_va_arg (valist, type) src_mem = adjust_address (src_mem, mode, src_offset); dest_mem = adjust_address (mem, mode, INTVAL (XEXP (slot, 1))); PUT_MODE (dest_mem, mode); - /* ??? Break out TImode moves from integer registers? */ emit_move_insn (dest_mem, src_mem); } } @@ -2543,14 +2547,6 @@ ix86_va_arg (valist, type) if (container) emit_label (lab_over); - if (indirect_p) - { - abort (); - r = gen_rtx_MEM (Pmode, addr_rtx); - set_mem_alias_set (r, get_varargs_alias_set ()); - emit_move_insn (addr_rtx, r); - } - return addr_rtx; } @@ -5931,27 +5927,19 @@ split_di (operands, num, lo_half, hi_half) while (num--) { rtx op = operands[num]; - if (CONSTANT_P (op)) - split_double (op, &lo_half[num], &hi_half[num]); - else if (! reload_completed) - { - lo_half[num] = gen_lowpart (SImode, op); - hi_half[num] = gen_highpart (SImode, op); - } - else if (GET_CODE (op) == REG) - { - if (TARGET_64BIT) - abort(); - lo_half[num] = gen_rtx_REG (SImode, REGNO (op)); - hi_half[num] = gen_rtx_REG (SImode, REGNO (op) + 1); - } - else if (offsettable_memref_p (op)) + + /* simplify_subreg refuse to split volatile memory addresses, + but we still have to handle it. */ + if (GET_CODE (op) == MEM) { lo_half[num] = adjust_address (op, SImode, 0); hi_half[num] = adjust_address (op, SImode, 4); } else - abort (); + { + lo_half[num] = simplify_gen_subreg (SImode, op, DImode, 0); + hi_half[num] = simplify_gen_subreg (SImode, op, DImode, 4); + } } } /* Split one or more TImode RTL references into pairs of SImode @@ -5969,40 +5957,19 @@ split_ti (operands, num, lo_half, hi_half) while (num--) { rtx op = operands[num]; - if (CONSTANT_P (op)) - { - if (GET_CODE (op) == CONST_INT) - { - lo_half[num] = GEN_INT (trunc_int_for_mode (INTVAL (op), SImode)); - hi_half[num] = (1 << (HOST_BITS_PER_WIDE_INT -1)) != 0 ? constm1_rtx : const0_rtx; - } - else if (GET_CODE (op) == CONST_DOUBLE && HOST_BITS_PER_WIDE_INT == 64) - { - lo_half[num] = GEN_INT (trunc_int_for_mode (CONST_DOUBLE_LOW (op), SImode)); - hi_half[num] = GEN_INT (trunc_int_for_mode (CONST_DOUBLE_HIGH (op), SImode)); - } - else - abort (); - } - else if (! reload_completed) - { - lo_half[num] = gen_lowpart (DImode, op); - hi_half[num] = gen_highpart (DImode, op); - } - else if (GET_CODE (op) == REG) - { - if (TARGET_64BIT) - abort(); - lo_half[num] = gen_rtx_REG (DImode, REGNO (op)); - hi_half[num] = gen_rtx_REG (DImode, REGNO (op) + 1); - } - else if (offsettable_memref_p (op)) + + /* simplify_subreg refuse to split volatile memory addresses, but we + still have to handle it. */ + if (GET_CODE (op) == MEM) { lo_half[num] = adjust_address (op, DImode, 0); hi_half[num] = adjust_address (op, DImode, 8); } else - abort (); + { + lo_half[num] = simplify_gen_subreg (DImode, op, TImode, 0); + hi_half[num] = simplify_gen_subreg (DImode, op, TImode, 8); + } } } @@ -7860,54 +7827,19 @@ ix86_expand_setcc (code, dest) { rtx ret, tmp, tmpreg; rtx second_test, bypass_test; - int type; if (GET_MODE (ix86_compare_op0) == DImode && !TARGET_64BIT) return 0; /* FAIL */ - /* Three modes of generation: - 0 -- destination does not overlap compare sources: - clear dest first, emit strict_low_part setcc. - 1 -- destination does overlap compare sources: - emit subreg setcc, zero extend. - 2 -- destination is in QImode: - emit setcc only. - - We don't use mode 0 early in compilation because it confuses CSE. - There are peepholes to turn mode 1 into mode 0 if things work out - nicely after reload. */ - - type = cse_not_expected ? 0 : 1; - - if (GET_MODE (dest) == QImode) - type = 2; - else if (reg_overlap_mentioned_p (dest, ix86_compare_op0) - || reg_overlap_mentioned_p (dest, ix86_compare_op1)) - type = 1; - - if (type == 0) - emit_move_insn (dest, const0_rtx); + if (GET_MODE (dest) != QImode) + abort (); ret = ix86_expand_compare (code, &second_test, &bypass_test); PUT_MODE (ret, QImode); tmp = dest; tmpreg = dest; - if (type == 0) - { - tmp = gen_lowpart (QImode, dest); - tmpreg = tmp; - tmp = gen_rtx_STRICT_LOW_PART (VOIDmode, tmp); - } - else if (type == 1) - { - if (!cse_not_expected) - tmp = gen_reg_rtx (QImode); - else - tmp = gen_lowpart (QImode, dest); - tmpreg = tmp; - } emit_insn (gen_rtx_SET (VOIDmode, tmp, ret)); if (bypass_test || second_test) @@ -7932,17 +7864,6 @@ ix86_expand_setcc (code, dest) emit_insn (gen_iorqi3 (tmp, tmpreg, tmp2)); } - if (type == 1) - { - rtx clob; - - tmp = gen_rtx_ZERO_EXTEND (GET_MODE (dest), tmp); - tmp = gen_rtx_SET (VOIDmode, dest, tmp); - clob = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (CCmode, FLAGS_REG)); - tmp = gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, tmp, clob)); - emit_insn (tmp); - } - return 1; /* DONE */ } diff --git a/gcc/config/i386/i386.h b/gcc/config/i386/i386.h index 49c1b27..da093be 100644 --- a/gcc/config/i386/i386.h +++ b/gcc/config/i386/i386.h @@ -2885,7 +2885,8 @@ extern int const svr4_dbx_register_map[FIRST_PSEUDO_REGISTER]; Whether or not a particular assembler allows us to enter such, I guess we'll have to see. */ #define ASM_PREFERRED_EH_DATA_FORMAT(CODE,GLOBAL) \ - (flag_pic ? (GLOBAL ? DW_EH_PE_indirect : 0) | DW_EH_PE_pcrel \ + (flag_pic \ + ? (GLOBAL ? DW_EH_PE_indirect : 0) | DW_EH_PE_pcrel | DW_EH_PE_sdata4\ : DW_EH_PE_absptr) /* This is how to output the definition of a user-level label named NAME, diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md index e12c4bd..efede44 100644 --- a/gcc/config/i386/i386.md +++ b/gcc/config/i386/i386.md @@ -12423,110 +12423,110 @@ ;; way, which can later delete the movzx if only QImode is needed. (define_expand "seq" - [(set (match_operand:SI 0 "register_operand" "") - (eq:SI (reg:CC 17) (const_int 0)))] + [(set (match_operand:QI 0 "register_operand" "") + (eq:QI (reg:CC 17) (const_int 0)))] "" "if (ix86_expand_setcc (EQ, operands[0])) DONE; else FAIL;") (define_expand "sne" - [(set (match_operand:SI 0 "register_operand" "") - (ne:SI (reg:CC 17) (const_int 0)))] + [(set (match_operand:QI 0 "register_operand" "") + (ne:QI (reg:CC 17) (const_int 0)))] "" "if (ix86_expand_setcc (NE, operands[0])) DONE; else FAIL;") (define_expand "sgt" - [(set (match_operand:SI 0 "register_operand" "") - (gt:SI (reg:CC 17) (const_int 0)))] + [(set (match_operand:QI 0 "register_operand" "") + (gt:QI (reg:CC 17) (const_int 0)))] "" "if (ix86_expand_setcc (GT, operands[0])) DONE; else FAIL;") (define_expand "sgtu" - [(set (match_operand:SI 0 "register_operand" "") - (gtu:SI (reg:CC 17) (const_int 0)))] + [(set (match_operand:QI 0 "register_operand" "") + (gtu:QI (reg:CC 17) (const_int 0)))] "" "if (ix86_expand_setcc (GTU, operands[0])) DONE; else FAIL;") (define_expand "slt" - [(set (match_operand:SI 0 "register_operand" "") - (lt:SI (reg:CC 17) (const_int 0)))] + [(set (match_operand:QI 0 "register_operand" "") + (lt:QI (reg:CC 17) (const_int 0)))] "" "if (ix86_expand_setcc (LT, operands[0])) DONE; else FAIL;") (define_expand "sltu" - [(set (match_operand:SI 0 "register_operand" "") - (ltu:SI (reg:CC 17) (const_int 0)))] + [(set (match_operand:QI 0 "register_operand" "") + (ltu:QI (reg:CC 17) (const_int 0)))] "" "if (ix86_expand_setcc (LTU, operands[0])) DONE; else FAIL;") (define_expand "sge" - [(set (match_operand:SI 0 "register_operand" "") - (ge:SI (reg:CC 17) (const_int 0)))] + [(set (match_operand:QI 0 "register_operand" "") + (ge:QI (reg:CC 17) (const_int 0)))] "" "if (ix86_expand_setcc (GE, operands[0])) DONE; else FAIL;") (define_expand "sgeu" - [(set (match_operand:SI 0 "register_operand" "") - (geu:SI (reg:CC 17) (const_int 0)))] + [(set (match_operand:QI 0 "register_operand" "") + (geu:QI (reg:CC 17) (const_int 0)))] "" "if (ix86_expand_setcc (GEU, operands[0])) DONE; else FAIL;") (define_expand "sle" - [(set (match_operand:SI 0 "register_operand" "") - (le:SI (reg:CC 17) (const_int 0)))] + [(set (match_operand:QI 0 "register_operand" "") + (le:QI (reg:CC 17) (const_int 0)))] "" "if (ix86_expand_setcc (LE, operands[0])) DONE; else FAIL;") (define_expand "sleu" - [(set (match_operand:SI 0 "register_operand" "") - (leu:SI (reg:CC 17) (const_int 0)))] + [(set (match_operand:QI 0 "register_operand" "") + (leu:QI (reg:CC 17) (const_int 0)))] "" "if (ix86_expand_setcc (LEU, operands[0])) DONE; else FAIL;") (define_expand "sunordered" - [(set (match_operand:SI 0 "register_operand" "") - (unordered:SI (reg:CC 17) (const_int 0)))] + [(set (match_operand:QI 0 "register_operand" "") + (unordered:QI (reg:CC 17) (const_int 0)))] "TARGET_80387 || TARGET_SSE" "if (ix86_expand_setcc (UNORDERED, operands[0])) DONE; else FAIL;") (define_expand "sordered" - [(set (match_operand:SI 0 "register_operand" "") - (ordered:SI (reg:CC 17) (const_int 0)))] + [(set (match_operand:QI 0 "register_operand" "") + (ordered:QI (reg:CC 17) (const_int 0)))] "TARGET_80387" "if (ix86_expand_setcc (ORDERED, operands[0])) DONE; else FAIL;") (define_expand "suneq" - [(set (match_operand:SI 0 "register_operand" "") - (uneq:SI (reg:CC 17) (const_int 0)))] + [(set (match_operand:QI 0 "register_operand" "") + (uneq:QI (reg:CC 17) (const_int 0)))] "TARGET_80387 || TARGET_SSE" "if (ix86_expand_setcc (UNEQ, operands[0])) DONE; else FAIL;") (define_expand "sunge" - [(set (match_operand:SI 0 "register_operand" "") - (unge:SI (reg:CC 17) (const_int 0)))] + [(set (match_operand:QI 0 "register_operand" "") + (unge:QI (reg:CC 17) (const_int 0)))] "TARGET_80387 || TARGET_SSE" "if (ix86_expand_setcc (UNGE, operands[0])) DONE; else FAIL;") (define_expand "sungt" - [(set (match_operand:SI 0 "register_operand" "") - (ungt:SI (reg:CC 17) (const_int 0)))] + [(set (match_operand:QI 0 "register_operand" "") + (ungt:QI (reg:CC 17) (const_int 0)))] "TARGET_80387 || TARGET_SSE" "if (ix86_expand_setcc (UNGT, operands[0])) DONE; else FAIL;") (define_expand "sunle" - [(set (match_operand:SI 0 "register_operand" "") - (unle:SI (reg:CC 17) (const_int 0)))] + [(set (match_operand:QI 0 "register_operand" "") + (unle:QI (reg:CC 17) (const_int 0)))] "TARGET_80387 || TARGET_SSE" "if (ix86_expand_setcc (UNLE, operands[0])) DONE; else FAIL;") (define_expand "sunlt" - [(set (match_operand:SI 0 "register_operand" "") - (unlt:SI (reg:CC 17) (const_int 0)))] + [(set (match_operand:QI 0 "register_operand" "") + (unlt:QI (reg:CC 17) (const_int 0)))] "TARGET_80387 || TARGET_SSE" "if (ix86_expand_setcc (UNLT, operands[0])) DONE; else FAIL;") (define_expand "sltgt" - [(set (match_operand:SI 0 "register_operand" "") - (ltgt:SI (reg:CC 17) (const_int 0)))] + [(set (match_operand:QI 0 "register_operand" "") + (ltgt:QI (reg:CC 17) (const_int 0)))] "TARGET_80387 || TARGET_SSE" "if (ix86_expand_setcc (LTGT, operands[0])) DONE; else FAIL;") diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 89ee913..d8887d8 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -602,7 +602,7 @@ in the following sections. @gccoptlist{ -fcall-saved-@var{reg} -fcall-used-@var{reg} @gol -ffixed-@var{reg} -fexceptions @gol --fnon-call-exceptions -funwind-tables @gol +-fnon-call-exceptions -funwind-tables -fasynchronous-unwind-tables @gol -finhibit-size-directive -finstrument-functions @gol -fcheck-memory-usage -fprefix-function-name @gol -fno-common -fno-ident -fno-gnu-linker @gol @@ -9658,6 +9658,12 @@ static data, but will not affect the generated code in any other way. You will normally not enable this option; instead, a language processor that needs this handling would enable it on your behalf. +@item -fasynchronous-unwind-tables +@opindex funwind-tables +Generate unwind table in dwarf2 format, if supported by target machine. The +table is exact at each instruction boundary, so it can be used for stack +unwinding from asynchronous events (such as debugger or garbage collector). + @item -fpcc-struct-return @opindex fpcc-struct-return Return ``short'' @code{struct} and @code{union} values in memory like diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c index 1d245b7..486c7a2 100644 --- a/gcc/dwarf2out.c +++ b/gcc/dwarf2out.c @@ -943,7 +943,8 @@ dwarf2out_stack_adjust (insn) long offset; const char *label; - if (! flag_non_call_exceptions && GET_CODE (insn) == CALL_INSN) + if (!flag_asynchronous_unwind_tables + && GET_CODE (insn) == CALL_INSN) { /* Extract the size of the args from the CALL rtx itself. */ @@ -960,7 +961,7 @@ dwarf2out_stack_adjust (insn) /* If only calls can throw, and we have a frame pointer, save up adjustments until we see the CALL_INSN. */ - else if (! flag_non_call_exceptions + else if (!flag_asynchronous_unwind_tables && cfa.reg != STACK_POINTER_REGNUM) return; @@ -1721,7 +1722,7 @@ output_call_frame_info (for_eh) emit any EH unwind information. */ if (for_eh) { - int any_eh_needed = 0; + int any_eh_needed = flag_asynchronous_unwind_tables; for (i = 0; i < fde_table_in_use; ++i) if (fde_table[i].uses_eh_lsda) any_eh_needed = any_lsda_needed = 1; diff --git a/gcc/flags.h b/gcc/flags.h index bf9e2af..04c3ed9 100644 --- a/gcc/flags.h +++ b/gcc/flags.h @@ -451,6 +451,10 @@ extern int flag_exceptions; extern int flag_unwind_tables; +/* Nonzero means generate frame unwind info table exact at each insn boundary */ + +extern int flag_asynchronous_unwind_tables; + /* Nonzero means don't place uninitialized global data in common storage by default. */ diff --git a/gcc/flow.c b/gcc/flow.c index 030a233..58bf257 100644 --- a/gcc/flow.c +++ b/gcc/flow.c @@ -344,6 +344,7 @@ static void invalidate_mems_from_autoinc PARAMS ((struct propagate_block_info *, static void invalidate_mems_from_set PARAMS ((struct propagate_block_info *, rtx)); static void delete_dead_jumptables PARAMS ((void)); +static void clear_log_links PARAMS ((sbitmap)); void @@ -628,12 +629,19 @@ update_life_info (blocks, extent, prop_flags) tmp = INITIALIZE_REG_SET (tmp_head); + timevar_push ((extent == UPDATE_LIFE_LOCAL || blocks) + ? TV_LIFE_UPDATE : TV_LIFE); + /* Changes to the CFG are only allowed when doing a global update for the entire CFG. */ if ((prop_flags & PROP_ALLOW_CFG_CHANGES) && (extent == UPDATE_LIFE_LOCAL || blocks)) abort (); + /* Clear log links in case we are asked to (re)compute them. */ + if (prop_flags & PROP_LOG_LINKS) + clear_log_links (blocks); + /* For a global update, we go through the relaxation process again. */ if (extent != UPDATE_LIFE_LOCAL) { @@ -727,6 +735,8 @@ update_life_info (blocks, extent, prop_flags) } }); } + timevar_pop ((extent == UPDATE_LIFE_LOCAL || blocks) + ? TV_LIFE_UPDATE : TV_LIFE); } /* Free the variables allocated by find_basic_blocks. @@ -4088,31 +4098,33 @@ count_or_remove_death_notes (blocks, kill) return count; } -/* Clear LOG_LINKS fields of insns in a chain. - Also clear the global_live_at_{start,end} fields of the basic block - structures. */ +/* Clear LOG_LINKS fields of insns in a selected blocks or whole chain + if blocks is NULL. */ -void -clear_log_links (insns) - rtx insns; +static void +clear_log_links (blocks) + sbitmap blocks; { - rtx i; - int b; - - for (i = insns; i; i = NEXT_INSN (i)) - if (INSN_P (i)) - LOG_LINKS (i) = 0; + rtx insn; + int i; - for (b = 0; b < n_basic_blocks; b++) + if (!blocks) { - basic_block bb = BASIC_BLOCK (b); - - bb->global_live_at_start = NULL; - bb->global_live_at_end = NULL; + rtx insn; + for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) + if (INSN_P (insn)) + free_EXPR_LIST_list (&LOG_LINKS (insn)); } - - ENTRY_BLOCK_PTR->global_live_at_end = NULL; - EXIT_BLOCK_PTR->global_live_at_start = NULL; + else + EXECUTE_IF_SET_IN_SBITMAP (blocks, 0, i, + { + basic_block bb = BASIC_BLOCK (i); + rtx insn; + for (insn = bb->head; insn != NEXT_INSN (bb->end); + insn = NEXT_INSN (insn)) + if (INSN_P (insn)) + free_EXPR_LIST_list (&LOG_LINKS (insn)); + }); } /* Given a register bitmap, turn on the bits in a HARD_REG_SET that diff --git a/gcc/recog.c b/gcc/recog.c index 6c3ecd4..874d567 100644 --- a/gcc/recog.c +++ b/gcc/recog.c @@ -2778,8 +2778,7 @@ split_all_insns (upd_life) if (changed) { - for (i = 0; i < n_basic_blocks; i++) - find_sub_basic_blocks (BASIC_BLOCK (i)); + find_many_sub_basic_blocks (blocks); } if (changed && upd_life) diff --git a/gcc/rtl.h b/gcc/rtl.h index 4c0eb2c..d6908e9 100644 --- a/gcc/rtl.h +++ b/gcc/rtl.h @@ -1481,7 +1481,6 @@ void free_EXPR_LIST_node PARAMS ((rtx)); void free_INSN_LIST_node PARAMS ((rtx)); rtx alloc_INSN_LIST PARAMS ((rtx, rtx)); rtx alloc_EXPR_LIST PARAMS ((int, rtx, rtx)); -void clear_log_links PARAMS ((rtx)); /* regclass.c */ diff --git a/gcc/timevar.def b/gcc/timevar.def index 7f62497..353a942 100644 --- a/gcc/timevar.def +++ b/gcc/timevar.def @@ -43,6 +43,9 @@ DEFTIMEVAR (TV_DUMP , "dump files") DEFTIMEVAR (TV_CFG , "cfg construction") /* Time spent by cleaning up CFG. */ DEFTIMEVAR (TV_CLEANUP_CFG , "cfg cleanup") +/* Time spent by life analysis. */ +DEFTIMEVAR (TV_LIFE , "life analysis") +DEFTIMEVAR (TV_LIFE_UPDATE , "life info update") /* Timing in various stages of the compiler. */ DEFTIMEVAR (TV_CPP , "preprocessing") DEFTIMEVAR (TV_LEX , "lexical analysis") @@ -60,6 +63,7 @@ DEFTIMEVAR (TV_FLOW , "flow analysis") DEFTIMEVAR (TV_COMBINE , "combiner") DEFTIMEVAR (TV_IFCVT , "if-conversion") DEFTIMEVAR (TV_REGMOVE , "regmove") +DEFTIMEVAR (TV_MODE_SWITCH , "mode switching") DEFTIMEVAR (TV_SCHED , "scheduling") DEFTIMEVAR (TV_LOCAL_ALLOC , "local alloc") DEFTIMEVAR (TV_GLOBAL_ALLOC , "global alloc") diff --git a/gcc/toplev.c b/gcc/toplev.c index 2df15e7..3bc9dac 100644 --- a/gcc/toplev.c +++ b/gcc/toplev.c @@ -737,6 +737,10 @@ int flag_exceptions; int flag_unwind_tables = 0; +/* Nonzero means generate frame unwind info table exact at each insn boundary */ + +int flag_asynchronous_unwind_tables = 0; + /* Nonzero means don't place uninitialized global data in common storage by default. */ @@ -1096,6 +1100,8 @@ lang_independent_options f_options[] = N_("Enable exception handling") }, {"unwind-tables", &flag_unwind_tables, 1, N_("Just generate unwind tables for exception handling") }, + {"asynchronous-unwind-tables", &flag_asynchronous_unwind_tables, 1, + N_("Generate unwind tables exact at each instruction boundary") }, {"non-call-exceptions", &flag_non_call_exceptions, 1, N_("Support synchronous non-call exceptions") }, {"profile-arcs", &profile_arc_flag, 1, @@ -2933,10 +2939,6 @@ rest_of_compilation (decl) convert_from_ssa (); /* New registers have been created. Rescan their usage. */ reg_scan (insns, max_reg_num (), 1); - /* Life analysis used in SSA adds log_links but these - shouldn't be there until the flow stage, so clear - them away. */ - clear_log_links (insns); close_dump_file (DFI_ussa, print_rtl_with_bb, insns); timevar_pop (TV_FROM_SSA); @@ -3370,7 +3372,7 @@ rest_of_compilation (decl) register_life_up_to_date = 0; #ifdef OPTIMIZE_MODE_SWITCHING - timevar_push (TV_GCSE); + timevar_push (TV_MODE_SWITCH); no_new_pseudos = 0; if (optimize_mode_switching (NULL)) @@ -3382,7 +3384,7 @@ rest_of_compilation (decl) } no_new_pseudos = 1; - timevar_pop (TV_GCSE); + timevar_pop (TV_MODE_SWITCH); #endif timevar_push (TV_SCHED); @@ -4911,6 +4913,11 @@ toplev_main (argc, argv) flag_rerun_cse_after_loop = 1; } + if (flag_non_call_exceptions) + flag_asynchronous_unwind_tables = 1; + if (flag_asynchronous_unwind_tables) + flag_unwind_tables = 1; + /* Warn about options that are not supported on this machine. */ #ifndef INSN_SCHEDULING if (flag_schedule_insns || flag_schedule_insns_after_reload) -- cgit v1.1