From 6c81a49011d7d197a0b291531f109cca4ed298a8 Mon Sep 17 00:00:00 2001 From: Jan Hubicka Date: Sat, 11 May 2002 19:16:28 +0200 Subject: [PATCH] i386.md (testsi to testqi spliters): New. * i386.md (testsi to testqi spliters): New. 2002-01-14 Josef Zlomek cfg.c (dump_edge_info): added dumping of EDGE_CAN_FALLTHRU. Wed Jan 9 2002 Josef Zlomek * basic-block.h: New flag EDGE_CAN_FALLTHRU * cfganal.c (set_edge_can_fallthru_flag): New function; marks the edges that can be made fallthru. Mon Nov 12 16:25:53 CET 2001 Jan Hubicka * cfglayout.c (cleanup_unconditional_jumps): New static function. (cfg_layout_initialize): Use it. Co-Authored-By: Pavel Nejedly From-SVN: r53383 --- gcc/ChangeLog | 114 ++++++++++++++++------------------------ gcc/basic-block.h | 2 + gcc/cfg.c | 2 +- gcc/cfganal.c | 39 ++++++++++++-- gcc/cfglayout.c | 81 ++++++++++++++++++++++++++++ gcc/config/i386/i386.md | 53 ++++++++++++++++++- 6 files changed, 218 insertions(+), 73 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 093d96947e7a..df060b25f278 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,43 +1,21 @@ -2002-05-11 Zack Weinberg - - * config/rs6000/rs6000.c (rs6000_default_long_calls, - rs6000_longcall_switch, rs6000_set_default_type_attributes): New. - (TARGET_SET_DEFAULT_TYPE_ATTRIBUTES): Set it. - (rs6000_override_options): Handle -m(no-)longcall. - (init_cumulative_args, output_mi_thunk): Check for both - longcall and shortcall attributes on the function. - (rs6000_attribute_table): Add "shortcall". - (rs6000_handle_longcall_attribute): Update comment. - (altivec_expand_unop_builtin, altivec_expand_binop_builtin, - altivec_expand_ternop_builtin): Add default clauses to switches - to silence warnings. - - * config/rs6000/rs6000.h: Declare rs6000_longcall_switch and - rs6000_default_long_calls. Define REGISTER_TARGET_PRAGMAS. - (TARGET_OPTIONS): Add longcall and no-longcall. - - * config/rs6000/rs6000.md (call_nonlocal_sysv, - call_value_nonlocal_sysv): Split by alternatives. One pair - accepts only SYMBOL_REFs and rejects if CALL_LONG is set in - the call cookie. The other pair accepts only LR/CTR and has - no restriction. - - * config.gcc (rs6000-*-* | powerpc*-*-* trailer stanza): - Set c_target_objs, cxx_target_objs; add t-rs6000-c-rule to - tmake_file. - * config/rs6000/rs6000-c.c: New file. - * config/rs6000/t-rs6000-c-rule: New file. - * config/rs6000/rs6000-protos.c: Add multiple-include guard. - Prototype rs6000_pragma_longcall. - - * doc/extend.texi: Document shortcall attribute. - * doc/invoke.texi: Document -mlongcall, -mno-longcall. - -2002-05-12 Marek Michalkiewicz - - * config/avr/avr.c (avr_mcu_types): Update supported devices. - * config/avr/avr.h (CPP_SPEC, LINK_SPEC, CRT_BINUTILS_SPECS): Likewise. - * config/avr/t-avr (MULTILIB_MATCHES): Likewise. +Sat May 11 14:34:35 CEST 2002 Jan Hubicka + + * i386.md (testsi to testqi spliters): New. + + 2002-01-14 Josef Zlomek + + cfg.c (dump_edge_info): added dumping of EDGE_CAN_FALLTHRU. + + Wed Jan 9 2002 Josef Zlomek + + * basic-block.h: New flag EDGE_CAN_FALLTHRU + * cfganal.c (set_edge_can_fallthru_flag): New function; marks the edges + that can be made fallthru. + + Mon Nov 12 16:25:53 CET 2001 Jan Hubicka + + * cfglayout.c (cleanup_unconditional_jumps): New static function. + (cfg_layout_initialize): Use it. 2002-05-11 Kazu Hirata @@ -240,38 +218,38 @@ Thu May 9 14:52:45 CEST 2002 Jan Hubicka * final.c (end_final): Use C trees to output data structures for profiling. * Makefile.in (LIBGCC_DEPS): Added missing dependency on gcov-io.h - (profile.o): New dependency profile.h - (final.o): New dependency profile.h - * profile.h: New file. New global structure profile_info. - * final.h (count_edges_instrumented_now): Declare. - (current_function_cfg_checksum): Declare. - (function_list): New structure. - (functions_head, functions_tail): New static variables. - (end_final): Emits more data, removed some -ax stuff. - (final): Stores function names and chcksums. - * gcov-io.h (__write_gcov_string): New function. - (__read_gcov_string): New function. - * gcov.c (read_profile): New function. - (create_program_flow_graph): Uses read_profile instead of reading + (profile.o): New dependency profile.h + (final.o): New dependency profile.h + * profile.h: New file. New global structure profile_info. + * final.h (count_edges_instrumented_now): Declare. + (current_function_cfg_checksum): Declare. + (function_list): New structure. + (functions_head, functions_tail): New static variables. + (end_final): Emits more data, removed some -ax stuff. + (final): Stores function names and chcksums. + * gcov-io.h (__write_gcov_string): New function. + (__read_gcov_string): New function. + * gcov.c (read_profile): New function. + (create_program_flow_graph): Uses read_profile instead of reading da_file. - (read_files): Removed da_file checking, it's done by read_profile now. - * libgcc2.c (bb_function_info): New structure. - (bb): New field in structure, removed some -ax stuff. - (__bb_exit_func): Changed structure of da_file. - * profile.c (count_edges_instrumented_now): New global variable. - (current_function_cfg_checksum): New global variable. - (max_counter_in_program): New global variable. - (get_exec_counts): New function. - (compute_checksum): New function. - (instrument_edges): Sets count_edges_instrumented_now. - (compute_branch_probabilities): Uses get_exec_counts instead of + (read_files): Removed da_file checking, it's done by read_profile now. + * libgcc2.c (bb_function_info): New structure. + (bb): New field in structure, removed some -ax stuff. + (__bb_exit_func): Changed structure of da_file. + * profile.c (count_edges_instrumented_now): New global variable. + (current_function_cfg_checksum): New global variable. + (max_counter_in_program): New global variable. + (get_exec_counts): New function. + (compute_checksum): New function. + (instrument_edges): Sets count_edges_instrumented_now. + (compute_branch_probabilities): Uses get_exec_counts instead of reading da_file. - (branch_prob): Calls compute_checksum and writes extra data to bbg_file. - (init_branch_prob): Removed da_file checking, done in get_exec_counts + (branch_prob): Calls compute_checksum and writes extra data to bbg_file. + (init_branch_prob): Removed da_file checking, done in get_exec_counts now. - (end_branch_prob): Removed da_file checking, done in get_exec_counts + (end_branch_prob): Removed da_file checking, done in get_exec_counts now. - * gcov.texi: Updated information about gcov file format. + * gcov.texi: Updated information about gcov file format. 2002-05-09 Kazu Hirata diff --git a/gcc/basic-block.h b/gcc/basic-block.h index e1c1905827c1..05b4b7c90027 100644 --- a/gcc/basic-block.h +++ b/gcc/basic-block.h @@ -141,6 +141,7 @@ typedef struct edge_def { #define EDGE_EH 8 #define EDGE_FAKE 16 #define EDGE_DFS_BACK 32 +#define EDGE_CAN_FALLTHRU 64 #define EDGE_COMPLEX (EDGE_ABNORMAL | EDGE_ABNORMAL_CALL | EDGE_EH) @@ -699,6 +700,7 @@ extern conflict_graph conflict_graph_compute PARAMS ((regset, partition)); extern bool mark_dfs_back_edges PARAMS ((void)); +extern void set_edge_can_fallthru_flag PARAMS ((void)); extern void update_br_prob_note PARAMS ((basic_block)); extern void fixup_abnormal_edges PARAMS ((void)); diff --git a/gcc/cfg.c b/gcc/cfg.c index 766c1b8ff3d7..47dfb238ea59 100644 --- a/gcc/cfg.c +++ b/gcc/cfg.c @@ -609,7 +609,7 @@ dump_edge_info (file, e, do_succ) if (e->flags) { static const char * const bitnames[] - = {"fallthru", "ab", "abcall", "eh", "fake", "dfs_back"}; + = {"fallthru", "ab", "abcall", "eh", "fake", "dfs_back", "can_fallthru"}; int comma = 0; int i, flags = e->flags; diff --git a/gcc/cfganal.c b/gcc/cfganal.c index f70c6c7b2fc3..a64124cfb79e 100644 --- a/gcc/cfganal.c +++ b/gcc/cfganal.c @@ -189,6 +189,36 @@ mark_dfs_back_edges () return found; } +/* Set the flag EDGE_CAN_FALLTHRU for edges that can be fallthru. */ + +void +set_edge_can_fallthru_flag () +{ + int i; + for (i = 0; i < n_basic_blocks; i++) + { + basic_block bb = BASIC_BLOCK (i); + edge e; + + /* The FALLTHRU edge is also CAN_FALLTHRU edge. */ + for (e = bb->succ; e; e = e->succ_next) + if (e->flags & EDGE_FALLTHRU) + e->flags |= EDGE_CAN_FALLTHRU; + + /* If the BB ends with an invertable condjump all (2) edges are + CAN_FALLTHRU edges. */ + if (!bb->succ || !bb->succ->succ_next || bb->succ->succ_next->succ_next) + continue; + if (!any_condjump_p (bb->end)) + continue; + if (!invert_jump (bb->end, JUMP_LABEL (bb->end), 0)) + continue; + invert_jump (bb->end, JUMP_LABEL (bb->end), 0); + bb->succ->flags |= EDGE_CAN_FALLTHRU; + bb->succ->succ_next->flags |= EDGE_CAN_FALLTHRU; + } +} + /* Return true if we need to add fake edge to exit. Helper function for the flow_call_edges_add. */ @@ -326,9 +356,12 @@ flow_call_edges_add (blocks) /* Note that the following may create a new basic block and renumber the existing basic blocks. */ - e = split_block (bb, split_at_insn); - if (e) - blocks_split++; + if (split_at_insn != bb->end) + { + e = split_block (bb, split_at_insn); + if (e) + blocks_split++; + } make_edge (bb, EXIT_BLOCK_PTR, EDGE_FAKE); } diff --git a/gcc/cfglayout.c b/gcc/cfglayout.c index 632280caa900..2820f0d5d969 100644 --- a/gcc/cfglayout.c +++ b/gcc/cfglayout.c @@ -46,6 +46,7 @@ static void set_block_levels PARAMS ((tree, int)); static void change_scope PARAMS ((rtx, tree, tree)); void verify_insn_chain PARAMS ((void)); +static void cleanup_unconditional_jumps PARAMS ((void)); static void fixup_fallthru_exit_predecessor PARAMS ((void)); static rtx unlink_insn_chain PARAMS ((rtx, rtx)); static rtx duplicate_insn_chain PARAMS ((rtx, rtx)); @@ -578,6 +579,76 @@ verify_insn_chain () abort (); } +/* Remove any unconditional jumps and forwarder block creating fallthru + edges instead. During BB reordering fallthru edges are not required + to target next basic block in the linear CFG layout, so the unconditional + jumps are not needed. If LOOPS is not null, also update loop structure & + dominators. */ + +static void +cleanup_unconditional_jumps () +{ + int i; + for (i = 0; i < n_basic_blocks; i++) + { + basic_block bb = BASIC_BLOCK (i); + + if (!bb->succ) + continue; + if (bb->succ->flags & EDGE_FALLTHRU) + continue; + if (!bb->succ->succ_next) + { + rtx insn; + if (GET_CODE (bb->head) != CODE_LABEL && forwarder_block_p (bb) && i) + { + basic_block prev = BASIC_BLOCK (--i); + + if (rtl_dump_file) + fprintf (rtl_dump_file, "Removing forwarder BB %i\n", + bb->index); + + redirect_edge_succ (bb->pred, bb->succ->dest); + flow_delete_block (bb); + bb = prev; + } + else if (simplejump_p (bb->end)) + { + rtx jump = bb->end; + + if (rtl_dump_file) + fprintf (rtl_dump_file, "Removing jump %i in BB %i\n", + INSN_UID (jump), bb->index); + delete_insn (jump); + bb->succ->flags |= EDGE_FALLTHRU; + } + else + continue; + + /* Cleanup barriers and delete ADDR_VECs in a way as they are belonging + to removed tablejump anyway. */ + insn = NEXT_INSN (bb->end); + while (insn + && (GET_CODE (insn) != NOTE + || NOTE_LINE_NUMBER (insn) != NOTE_INSN_BASIC_BLOCK)) + { + rtx next = NEXT_INSN (insn); + + if (GET_CODE (insn) == BARRIER) + delete_barrier (insn); + else if (GET_CODE (insn) == JUMP_INSN) + delete_insn_chain (PREV_INSN (insn), insn); + else if (GET_CODE (insn) == CODE_LABEL) + ; + else if (GET_CODE (insn) != NOTE) + abort (); + + insn = next; + } + } + } +} + /* The block falling through to exit must be the last one in the reordered chain. Ensure that this condition is met. */ static void @@ -767,6 +838,14 @@ cfg_layout_redirect_edge (e, dest) } else redirect_edge_and_branch (e, dest); + + /* We don't want simplejumps in the insn stream during cfglayout. */ + if (simplejump_p (src->end)) + { + delete_insn (src->end); + delete_barrier (NEXT_INSN (src->end)); + src->succ->flags |= EDGE_FALLTHRU; + } dest->index = old_index; } @@ -868,6 +947,8 @@ cfg_layout_initialize () around the code. */ alloc_aux_for_blocks (sizeof (struct reorder_block_def)); + cleanup_unconditional_jumps (); + scope_to_insns_initialize (); record_effective_endpoints (); diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md index fea9d981c067..54e1305e8ecb 100644 --- a/gcc/config/i386/i386.md +++ b/gcc/config/i386/i386.md @@ -7640,6 +7640,56 @@ operands[3] = gen_rtx_AND (mode, operands[0], gen_int_mode (mask, mode)); }) +;; Convert HImode/SImode test instructions with immediate to QImode ones. +;; i386 does not allow to encode test with 8bit sign extended immediate, so +;; this is relatively important trick. +;; Do the converison only post-reload to avoid limiting of the register class +;; to QI regs. +(define_split + [(set (reg 17) + (compare + (and (match_operand 0 "register_operand" "") + (match_operand 1 "const_int_operand" "")) + (const_int 0)))] + "(!TARGET_PROMOTE_QImode || optimize_size) + && reload_completed + && QI_REG_P (operands[0]) + && ((ix86_match_ccmode (insn, CCZmode) + && !(INTVAL (operands[1]) & ~(255 << 8))) + || (ix86_match_ccmode (insn, CCNOmode) + && !(INTVAL (operands[1]) & ~(127 << 8)))) + && GET_MODE (operands[0]) != QImode" + [(set (reg:CCNO 17) + (compare:CCNO + (and:SI (zero_extract:SI (match_dup 0) (const_int 8) (const_int 8)) + (match_dup 1)) + (const_int 0)))] + "operands[0] = gen_lowpart (SImode, operands[0]); + operands[1] = gen_int_mode (INTVAL (operands[1]) >> 8, QImode);") + +(define_split + [(set (reg 17) + (compare + (and (match_operand 0 "nonimmediate_operand" "") + (match_operand 1 "const_int_operand" "")) + (const_int 0)))] + "(!TARGET_PROMOTE_QImode || optimize_size) + && reload_completed + && (!REG_P (operands[0]) || ANY_QI_REG_P (operands[0])) + && ((ix86_match_ccmode (insn, CCZmode) + && !(INTVAL (operands[1]) & ~255)) + || (ix86_match_ccmode (insn, CCNOmode) + && !(INTVAL (operands[1]) & ~127))) + && GET_MODE (operands[0]) != QImode" + [(set (reg:CCNO 17) + (compare:CCNO + (and:QI (match_dup 0) + (match_dup 1)) + (const_int 0)))] + "operands[0] = gen_lowpart (QImode, operands[0]); + operands[1] = gen_lowpart (QImode, operands[1]);") + + ;; %%% This used to optimize known byte-wide and operations to memory, ;; and sometimes to QImode registers. If this is considered useful, ;; it should be done with splitters. @@ -16494,7 +16544,8 @@ (const_int 0)))] "ix86_match_ccmode (insn, CCNOmode) && (true_regnum (operands[0]) != 0 - || CONST_OK_FOR_LETTER_P (INTVAL (operands[1]), 'K')) + || (GET_CODE (operands[1]) == CONST_INT + && CONST_OK_FOR_LETTER_P (INTVAL (operands[1]), 'K'))) && find_regno_note (insn, REG_DEAD, true_regnum (operands[0]))" [(parallel [(set (reg:CCNO 17) -- 2.43.5