diff options
author | Roger Sayle <roger@eyesopen.com> | 2003-12-02 01:43:58 +0000 |
---|---|---|
committer | Roger Sayle <sayle@gcc.gnu.org> | 2003-12-02 01:43:58 +0000 |
commit | d9e7c8e3c35b45d40660abe038d4379eb4f770a3 (patch) | |
tree | a53fd78aee8f68647d8de3b2cf423c36acf60972 | |
parent | b58b21d521f8ee8dd0f53708d937db75262ae65e (diff) | |
download | gcc-d9e7c8e3c35b45d40660abe038d4379eb4f770a3.zip gcc-d9e7c8e3c35b45d40660abe038d4379eb4f770a3.tar.gz gcc-d9e7c8e3c35b45d40660abe038d4379eb4f770a3.tar.bz2 |
re PR rtl-optimization/11634 ([hppa] ICE in verify_local_live_at_start, at flow.c:555)
PR optimization/11634
* recog.c (split_insn): Factor test of INSN_P and handling of
set_noop_p out of here into the two callers.
(split_all_insns): Add INSN_P test and set_noop_p handling here.
If deleting a no-op set after reload that has a REG_UNUSED note,
mark the basic block as changed and recalculate life information.
(split_all_insns_noflow): Add INSN_P test and set_noop_p handling
here.
* gcc.dg/20031201-2.c: New test case.
From-SVN: r74145
-rw-r--r-- | gcc/ChangeLog | 11 | ||||
-rw-r--r-- | gcc/recog.c | 150 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 5 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/20031201-2.c | 41 |
4 files changed, 146 insertions, 61 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 3f755a6..d11d4f0 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,16 @@ 2003-12-01 Roger Sayle <roger@eyesopen.com> + PR optimization/11634 + * recog.c (split_insn): Factor test of INSN_P and handling of + set_noop_p out of here into the two callers. + (split_all_insns): Add INSN_P test and set_noop_p handling here. + If deleting a no-op set after reload that has a REG_UNUSED note, + mark the basic block as changed and recalculate life information. + (split_all_insns_noflow): Add INSN_P test and set_noop_p handling + here. + +2003-12-01 Roger Sayle <roger@eyesopen.com> + PR optimization/12322 * gcse.c (struct ls_expr): Change type of hash_index from int to unsigned int. diff --git a/gcc/recog.c b/gcc/recog.c index f0e75c2..3257fac 100644 --- a/gcc/recog.c +++ b/gcc/recog.c @@ -2642,61 +2642,42 @@ reg_fits_class_p (rtx operand, enum reg_class class, int offset, return 0; } -/* Split single instruction. Helper function for split_all_insns. - Return last insn in the sequence if successful, or NULL if unsuccessful. */ +/* Split single instruction. Helper function for split_all_insns and + split_all_insns_noflow. Return last insn in the sequence if successful, + or NULL if unsuccessful. */ + static rtx split_insn (rtx insn) { - rtx set; - if (!INSN_P (insn)) - ; - /* Don't split no-op move insns. These should silently - disappear later in final. Splitting such insns would - break the code that handles REG_NO_CONFLICT blocks. */ + /* Split insns here to get max fine-grain parallelism. */ + rtx first = PREV_INSN (insn); + rtx last = try_split (PATTERN (insn), insn, 1); - else if ((set = single_set (insn)) != NULL && set_noop_p (set)) - { - /* Nops get in the way while scheduling, so delete them - now if register allocation has already been done. It - is too risky to try to do this before register - allocation, and there are unlikely to be very many - nops then anyways. */ - if (reload_completed) - delete_insn_and_edges (insn); - } - else - { - /* Split insns here to get max fine-grain parallelism. */ - rtx first = PREV_INSN (insn); - rtx last = try_split (PATTERN (insn), insn, 1); + if (last == insn) + return NULL_RTX; + + /* try_split returns the NOTE that INSN became. */ + PUT_CODE (insn, NOTE); + NOTE_SOURCE_FILE (insn) = 0; + NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED; - if (last != insn) + /* ??? Coddle to md files that generate subregs in post-reload + splitters instead of computing the proper hard register. */ + if (reload_completed && first != last) + { + first = NEXT_INSN (first); + for (;;) { - /* try_split returns the NOTE that INSN became. */ - PUT_CODE (insn, NOTE); - NOTE_SOURCE_FILE (insn) = 0; - NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED; - - /* ??? Coddle to md files that generate subregs in post- - reload splitters instead of computing the proper - hard register. */ - if (reload_completed && first != last) - { - first = NEXT_INSN (first); - while (1) - { - if (INSN_P (first)) - cleanup_subreg_operands (first); - if (first == last) - break; - first = NEXT_INSN (first); - } - } - return last; + if (INSN_P (first)) + cleanup_subreg_operands (first); + if (first == last) + break; + first = NEXT_INSN (first); } } - return NULL_RTX; + return last; } + /* Split all insns in the function. If UPD_LIFE, update life info after. */ void @@ -2717,24 +2698,52 @@ split_all_insns (int upd_life) for (insn = bb->head; !finish ; insn = next) { - rtx last; - /* Can't use `next_real_insn' because that might go across CODE_LABELS and short-out basic blocks. */ next = NEXT_INSN (insn); finish = (insn == bb->end); - last = split_insn (insn); - if (last) + if (INSN_P (insn)) { - /* The split sequence may include barrier, but the - BB boundary we are interested in will be set to previous - one. */ - - while (GET_CODE (last) == BARRIER) - last = PREV_INSN (last); - SET_BIT (blocks, bb->index); - changed = true; - insn = last; + rtx set = single_set (insn); + + /* Don't split no-op move insns. These should silently + disappear later in final. Splitting such insns would + break the code that handles REG_NO_CONFLICT blocks. */ + if (set && set_noop_p (set)) + { + /* Nops get in the way while scheduling, so delete them + now if register allocation has already been done. It + is too risky to try to do this before register + allocation, and there are unlikely to be very many + nops then anyways. */ + if (reload_completed) + { + /* If the no-op set has a REG_UNUSED note, we need + to update liveness information. */ + if (find_reg_note (insn, REG_UNUSED, NULL_RTX)) + { + SET_BIT (blocks, bb->index); + changed = true; + } + /* ??? Is life info affected by deleting edges? */ + delete_insn_and_edges (insn); + } + } + else + { + rtx last = split_insn (insn); + if (last) + { + /* The split sequence may include barrier, but the + BB boundary we are interested in will be set to + previous one. */ + + while (GET_CODE (last) == BARRIER) + last = PREV_INSN (last); + SET_BIT (blocks, bb->index); + changed = true; + } + } } } } @@ -2771,9 +2780,28 @@ split_all_insns_noflow (void) for (insn = get_insns (); insn; insn = next) { next = NEXT_INSN (insn); - split_insn (insn); + if (INSN_P (insn)) + { + /* Don't split no-op move insns. These should silently + disappear later in final. Splitting such insns would + break the code that handles REG_NO_CONFLICT blocks. */ + rtx set = single_set (insn); + if (set && set_noop_p (set)) + { + /* Nops get in the way while scheduling, so delete them + now if register allocation has already been done. It + is too risky to try to do this before register + allocation, and there are unlikely to be very many + nops then anyways. + + ??? Should we use delete_insn when the CFG isn't valid? */ + if (reload_completed) + delete_insn_and_edges (insn); + } + else + split_insn (insn); + } } - return; } #ifdef HAVE_peephole2 diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index a880222..d9bc74b 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2003-12-01 Roger Sayle <roger@eyesopen.com> + + PR optimization/11634 + * gcc.dg/20031201-2.c: New test case. + 2003-12-01 Zack Weinberg <zack@codesourcery.com> PR 11433 diff --git a/gcc/testsuite/gcc.dg/20031201-2.c b/gcc/testsuite/gcc.dg/20031201-2.c new file mode 100644 index 0000000..c32b5eb --- /dev/null +++ b/gcc/testsuite/gcc.dg/20031201-2.c @@ -0,0 +1,41 @@ +/* PR optimization/11634 */ + +/* The following code used to ICE in verify_local_live_at_start on + PA when compiled with -O2. The cause was that split_all_insns was + not updating liveness information when deleting no-op moves that + had REG_UNUSED notes. */ + +/* { dg-do compile { target hppa*-*-* } } */ +/* { dg-options "-O2" } */ + +void *f(void *s); +void H5T_conv_vlen (unsigned long long nelmts, unsigned char *bg_ptr) +{ + long long seq_len; + unsigned long long bg_seq_len = 0; + unsigned src_base_size, dst_base_size; + void *tmp_buf = 0; + unsigned tmp_buf_size = 0; + unsigned long long elmtno; + for (elmtno = 0; elmtno < nelmts; elmtno++) + { + unsigned char *tmp = bg_ptr; + bg_seq_len = *tmp; + if (bg_seq_len > 0 + && tmp_buf_size < + (unsigned) (bg_seq_len * + (src_base_size > dst_base_size + ? src_base_size + : dst_base_size))) + { + tmp_buf_size = + (unsigned) (bg_seq_len * + (src_base_size > dst_base_size + ? src_base_size + : dst_base_size)); + } + if (bg_seq_len < seq_len) + f ((unsigned char *) tmp_buf + dst_base_size * bg_seq_len); + } +} + |