From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 10472 invoked by alias); 30 Jan 2006 20:31:23 -0000 Received: (qmail 10458 invoked by uid 22791); 30 Jan 2006 20:31:19 -0000 X-Spam-Check-By: sourceware.org Received: from miranda.se.axis.com (HELO miranda.se.axis.com) (193.13.178.8) by sourceware.org (qpsmtpd/0.31) with ESMTP; Mon, 30 Jan 2006 20:31:14 +0000 Received: from ignucius.se.axis.com (ignucius.se.axis.com [10.83.5.18]) by miranda.se.axis.com (8.12.9/8.12.9/Debian-5local0.1) with ESMTP id k0UKVAVJ027996; Mon, 30 Jan 2006 21:31:10 +0100 Received: from ignucius.se.axis.com (localhost [127.0.0.1]) by ignucius.se.axis.com (8.12.8p1/8.12.8/Debian-2woody1) with ESMTP id k0UKVAmC020414; Mon, 30 Jan 2006 21:31:10 +0100 Received: (from hp@localhost) by ignucius.se.axis.com (8.12.8p1/8.12.8/Debian-2woody1) id k0UKVAba020410; Mon, 30 Jan 2006 21:31:10 +0100 Date: Mon, 30 Jan 2006 20:54:00 -0000 Message-Id: <200601302031.k0UKVAba020410@ignucius.se.axis.com> From: Hans-Peter Nilsson To: gcc-patches@gcc.gnu.org Subject: [RFA:] Split REG_LABEL into REG_LABEL_TARGET and REG_LABEL_OPERAND Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org X-SW-Source: 2006-01/txt/msg02145.txt.bz2 :ADDPATCH middle-end: So, here's the patch to split REG_LABEL into REG_LABEL_TARGET and REG_LABEL_OPERAND. See for why this is necessary. (BTW, it's s/JUMP_TARGET/JUMP_LABEL/ in one place, not the other way round as the followup says). This patch has been bootstrapped and regression-tested on i686-pc-linux-gnu (FC2) and regression-tested cross to cris-axis-elf, cris-axis-linux-gnu, mmix-knuth-mmixware, sh-elf, sh64-elf and mips-elf. The documentation changes have been "make info dvi" and those parts of gccint.dvi visually inspected. An earlier version with equivalent function but with the code in propagate_block_delete_insn arranged a little differently (the if-body split out into a helper function because I initially thought I'd need to refer to it twice and then forgot to change it back) and with an extra assert for absence of REG_LABEL_OPERAND notes on insns where a case-table was deleted (instead of just ignoring them), was also bootstrapped on x86_64-unknown-linux-gnu (FC4) and powerpc-unknown-linux-gnu (FC4). I was a bit worried that for some reason this patch would cause performance regressions or other issues for branch-target targets, so (with the earlier version of the patch) I compared assembly for sh64-elf in a tree where I also compiled csibe-2.1.1 with patches similar to those posted at (but additional changes to work around the -DSTACK_SIZE=N option for sh64-sim) at -O0, -O1, -O2, -Os and -O3 for "time". I think that'd be enough to expose any important regressions. I found no regressions, but saw (only) these code changes which may warrant some comments: diff -upr asm-sh64.nonjmp7/as-15329 asm-sh64/as-15329 --- asm-sh64.nonjmp7/as-15329 2006-01-27 12:11:09.000000000 +0100 +++ asm-sh64/as-15329 2006-01-27 15:42:28.000000000 +0100 @@ -21,13 +21,6 @@ _x: .L3: pt .L3, tr0 blink tr0, r63 - .align 2 .L2: - add.l r14, r63, r15 - ld.l r15, 0, r14 - ld.l r15, 4, r18 - addi.l r15, 8, r15 - ptabs r18, tr0 - blink tr0, r63 .size _x, .-_x .ident "GCC: (GNU) 4.2.0 20060126 (experimental)" as-15329 is the -O0 compilation of gcc.c-torture/compile/920501-7.c. The (removed) code after L2 would be dead. The change seems benevolent but unimportant. I didn't debug it, but it's probably that the code is removed due to the first "blink tr0, r63" now getting its JUMP_LABEL field set sticky and the dead-code-removal-at-O0 pass seeing this where previously the field was being cleared. diff -upr asm-sh64.nonjmp7/as-30060 asm-sh64/as-30060 --- asm-sh64.nonjmp7/as-30060 2006-01-27 13:09:05.000000000 +0100 +++ asm-sh64/as-30060 2006-01-27 16:40:23.000000000 +0100 @@ -1043,7 +1043,7 @@ _jpeg_gen_optimal_table: blink tr0, r18 pt .L167, tr4 pt .L169, tr3 - pt .L168, tr0 + pt .L168, tr1 movi 0, r6 movi 1, r5 blink tr4, r63 @@ -1059,7 +1059,7 @@ _jpeg_gen_optimal_table: .L169: addi.l r2, 1, r2 movi 256, r1 - bne r2, r1, tr0 + bne r2, r1, tr1 addi.l r5, 1, r5 movi 33, r1 bne r5, r1, tr4 @@ -1090,7 +1090,7 @@ _jpeg_gen_optimal_table: .L167: movi 0, r2 add.l r11, r63, r3 - blink tr0, r63 + blink tr1, r63 .size _jpeg_gen_optimal_table, .-_jpeg_gen_optimal_table .align 2 .align 5 as-30060 is CSiBE/src/jpeg-6b/jchuff.c compiled at -O2. The difference in register allocation seems as unimportant as the plain renumbering; it's not shown in the diff, but tr0..tr7 are all used in this function. diff -upr asm-sh64.nonjmp7/as-31718 asm-sh64/as-31718 --- asm-sh64.nonjmp7/as-31718 2006-01-27 13:22:54.000000000 +0100 +++ asm-sh64/as-31718 2006-01-27 16:53:25.000000000 +0100 @@ -1747,18 +1747,16 @@ _debug_log_proc: .global _SetCryptKeys .type _SetCryptKeys, @function _SetCryptKeys: - gettr tr5, r1 + gettr tr5, r0 pt _strlen, tr5 addi.l r15, -296, r15 - gettr tr6, r0 - st.l r15, 272, r14 - st.l r15, 256, r10 + st.l r15, 276, r14 + st.l r15, 260, r10 st.l r15, 284, r0 - st.l r15, 280, r1 - st.l r15, 276, r18 - st.l r15, 268, r13 - st.l r15, 264, r12 - st.l r15, 260, r11 + st.l r15, 280, r18 + st.l r15, 272, r13 + st.l r15, 268, r12 + st.l r15, 264, r11 add.l r15, r63, r14 add.l r2, r63, r10 blink tr5, r18 @@ -1861,7 +1859,6 @@ _SetCryptKeys: shori 41525, r1 shori 61731, r2 st.l r11, 12, r2 - pt .L196, tr6 add.l r14, r63, r13 st.l r11, 8, r1 movi 256, r4 @@ -1887,6 +1884,7 @@ _SetCryptKeys: pt .L193, tr2 pt .L194, tr3 pt .L198, tr4 + pt .L196, tr0 pt .L206, tr1 movi 0, r8 movi 0, r9 @@ -1931,7 +1929,7 @@ _SetCryptKeys: st.b r7, 0, r3 addi.l r4, 1, r4 st.b r2, 0, r6 - bne r5, r0, tr6 + bne r5, r0, tr0 .L194: addi.l r8, 2, r8 .L216: @@ -2134,17 +2132,15 @@ _SetCryptKeys: .L206: addi.l r14, 256, r14 add.l r14, r63, r15 - ld.l r15, 20, r18 - ld.l r15, 24, r0 - ld.l r15, 28, r1 + ld.l r15, 24, r18 + ld.l r15, 28, r0 + ld.l r15, 4, r10 ptabs r18, tr0 ptabs r0, tr5 - ptabs r1, tr6 - ld.l r15, 0, r10 - ld.l r15, 4, r11 - ld.l r15, 8, r12 - ld.l r15, 12, r13 - ld.l r15, 16, r14 + ld.l r15, 8, r11 + ld.l r15, 12, r12 + ld.l r15, 16, r13 + ld.l r15, 20, r14 addi.l r15, 40, r15 blink tr0, r63 .size _SetCryptKeys, .-_SetCryptKeys as-31718 is CSiBE/src/unrarlib-0.4.0/unrarlib/unrarlib.c compiled at -O3. This looks like a change for the better: in the first and last chunk we see that tr6 isn't needed and thus not saved and restored. Yay. In the other chunks, we see tr0 used where tr6 was used before the patch. The set of tr0 is elsewhere than for tr6, because GCC can't move the tr0 set all the way up to the earlier tr6 init because of other local allocations of tr0. Ok to commit? gcc: Divide REG_LABEL notes into REG_LABEL_OPERAND and REG_LABEL_TARGET. * reload.c (find_reloads): Generate REG_LABEL_OPERAND, not REG_LABEL when replacing an operand with a LABEL_REF for a non-jump insn. (subst_reloads): When replacing a LABEL_REG with a register, instead of generating a REG_LABEL note, assert that there already is one or that the label is a known target for the insn. * loop.c (add_label_notes): Generate REG_LABEL_OPERAND notes. Adjust head comment accordingly. (find_and_verify_loops): Test for REG_LABEL_OPERAND notes instead of testing insn type and REG_LABEL presence. * rtlanal.c (computed_jump_p): Instead of looking for a REG_LABEL note, check the JUMP_LABEL field. Remove "else" after return. * reorg.c (emit_delay_sequence): Replace case for REG_LABEL with cases for REG_LABEL_OPERAND and REG_LABEL_TARGET. (fill_slots_from_thread): Handle both REG_LABEL_OPERAND and REG_LABEL_TARGET notes, including the JUMP_TARGET field on JUMP_P insns. Iterate over all notes; don't assume there's only one. * flow.c (propagate_block_delete_insn): Check for a REG_LABEL_TARGET note referring to a case-table; ignore REG_LABEL_OPERAND notes. * cse.c (recorded_label_ref): Adjust comment to refer to REG_LABEL_OPERAND. (cse_basic_block): Do LABEL_REF check for all INSN_P insns, not just NONJUMP_INSN_P. (check_for_label_ref): For JUMP_P insns, check that the LABEL_REF isn't a jump target. (rebuild_jump_labels): Adjust head comment. (init_label_info): Ditto. Remove REG_LABEL_OPERAND notes only; don't reset REG_LABEL_TARGET notes, including the JUMP_LABEL field. (mark_all_labels): For JUMP_P insns without a target, check if the the target is noted on the previous nonjump insn. (mark_jump_label_1): New function, guts from mark_jump_label. : Handle first operand as a non-target when marking jump target labels. : Adjust for whether to generate a REG_LABEL_TARGET or a REG_LABEL_OPERAND note. For 'E' format rtl, iterate in descending element order. (delete_related_insns): Handle both REG_LABEL_TARGET and REG_LABEL_OPERAND notes. For JUMP_P insns with labels with zero reference count, delete and fallthrough. Move finding-next- non-deleted insn last in the function. Look at all INSN_P insns for REG_LABEL_OPERAND notes. (redirect_jump_2): Assert that OLABEL equals the old JUMP_LABEL of JUMP. * print-rtl.c (print_rtx): For JUMP_P insns and a non-NULL JUMP_LABEL, output the INSN_UID of it. * gcse.c: Adjust comments as appropriate to say REG_LABEL_OPERAND and/or REG_LABEL_TARGET. (add_label_notes): Only add REG_LABEL_OPERAND notes. Put in line with jump.c copy by only adding notes for labels actually referenced in the insn. * emit-rtl.c (try_split): Don't assume only NONJUMP_INSN_P need usage count increment; handle all INSN_P trial insns. (emit_copy_of_insn_after): Change to not copy REG_LABEL_OPERAND notes. * rtl.h (struct rtx_def) : Adjust to mention REG_LABEL_TARGET and REG_LABEL_OPERAND. (LABEL_REF_NONLOCAL_P): Allow REG_LABEL_TARGET and REG_LABEL_OPERAND. * combine.c (distribute_notes): Adjust for REG_LABEL_TARGET on JUMP_P insns and REG_LABEL_OPERAND everywhere. * sched-rgn.c (is_cfg_nonregular): Check for REG_LABEL_OPERANDS on all INSN_P insns. * reg-notes.def (LABEL_TARGET, LABEL_OPERAND): Split from LABEL. * cfgrtl.c (delete_insn): Adjust to handle REG_LABEL_TARGET and REG_LABEL_OPERAND notes. * reload1.c (calculate_needs_all_insns): Adjust comments. (set_label_offsets): Adjust to look for REG_LABEL_OPERAND notes. * config/alpha/alpha.md (split for load of an address into a four-insn sequence on Unicos/Mk): Adjust to use REG_LABEL_OPERAND. * config/sh/sh.md (sh_reorg, final_prescan_insn): Ditto. * doc/rtl.texi (Insns): Specify when a label_ref makes a jump_insn. Similar for what label_refs can go in the JUMP_TARGET field. Split REG_LABEL documentation into REG_LABEL_TARGET and REG_LABEL_OPERAND. Index: gcc/reload.c =================================================================== --- gcc/reload.c (revision 108225) +++ gcc/reload.c (working copy) @@ -4036,13 +4036,18 @@ find_reloads (rtx insn, int replace, int *recog_data.operand_loc[i] = substitution; - /* If we're replacing an operand with a LABEL_REF, we need - to make sure that there's a REG_LABEL note attached to + /* If we're replacing an operand with a LABEL_REF, we need to + make sure that there's a REG_LABEL_OPERAND note attached to this instruction. */ - if (!JUMP_P (insn) - && GET_CODE (substitution) == LABEL_REF - && !find_reg_note (insn, REG_LABEL, XEXP (substitution, 0))) - REG_NOTES (insn) = gen_rtx_INSN_LIST (REG_LABEL, + if (GET_CODE (substitution) == LABEL_REF + && !find_reg_note (insn, REG_LABEL_OPERAND, + XEXP (substitution, 0)) + /* For a JUMP_P, if it was a branch target it must have + already been recorded as such. */ + && (!JUMP_P (insn) + || !label_is_jump_target_p (XEXP (substitution, 0), + insn))) + REG_NOTES (insn) = gen_rtx_INSN_LIST (REG_LABEL_OPERAND, XEXP (substitution, 0), REG_NOTES (insn)); } @@ -5993,17 +5998,15 @@ subst_reloads (rtx insn) } #endif /* ENABLE_CHECKING */ - /* If we're replacing a LABEL_REF with a register, add a - REG_LABEL note to indicate to flow which label this + /* If we're replacing a LABEL_REF with a register, there must + already be an indication (to e.g. flow) which label this register refers to. */ - if (GET_CODE (*r->where) == LABEL_REF - && JUMP_P (insn)) - { - REG_NOTES (insn) = gen_rtx_INSN_LIST (REG_LABEL, - XEXP (*r->where, 0), - REG_NOTES (insn)); - JUMP_LABEL (insn) = XEXP (*r->where, 0); - } + gcc_assert (GET_CODE (*r->where) != LABEL_REF + || !JUMP_P (insn) + || find_reg_note (insn, + REG_LABEL_OPERAND, + XEXP (*r->where, 0)) + || label_is_jump_target_p (XEXP (*r->where, 0), insn)); /* Encapsulate RELOADREG so its machine mode matches what used to be there. Note that gen_lowpart_common will Index: gcc/loop.c =================================================================== --- gcc/loop.c (revision 108225) +++ gcc/loop.c (working copy) @@ -2130,9 +2130,9 @@ rtx_equal_for_loop_p (rtx x, rtx y, stru return 1; } -/* If X contains any LABEL_REF's, add REG_LABEL notes for them to all - insns in INSNS which use the reference. LABEL_NUSES for CODE_LABEL - references is incremented once for each added note. */ +/* If X contains any LABEL_REF's, add REG_LABEL_OPERAND notes for them + to all insns in INSNS which use the reference. LABEL_NUSES for + CODE_LABEL references is incremented once for each added note. */ static void add_label_notes (rtx x, rtx insns) @@ -2152,8 +2152,12 @@ add_label_notes (rtx x, rtx insns) for (insn = insns; insn; insn = NEXT_INSN (insn)) if (reg_mentioned_p (XEXP (x, 0), insn)) { - REG_NOTES (insn) = gen_rtx_INSN_LIST (REG_LABEL, XEXP (x, 0), - REG_NOTES (insn)); + /* There's no reason for current users to emit jump-insns + with such a LABEL_REF. */ + gcc_assert (!JUMP_P (insn)); + REG_NOTES (insn) + = gen_rtx_INSN_LIST (REG_LABEL_OPERAND, XEXP (x, 0), + REG_NOTES (insn)); if (LABEL_P (XEXP (x, 0))) LABEL_NUSES (XEXP (x, 0))++; } @@ -3124,11 +3128,11 @@ find_and_verify_loops (rtx f, struct loo invalidated, because it can be jumped into from anywhere. */ for_each_eh_label (invalidate_loops_containing_label); - /* Now scan all insn's in the function. If any JUMP_INSN branches into a - loop that it is not contained within, that loop is marked invalid. - If any INSN or CALL_INSN uses a label's address, then the loop containing - that label is marked invalid, because it could be jumped into from - anywhere. + /* Now scan all insn's in the function. If any JUMP_INSN branches into + a loop that it is not contained within, that loop is marked invalid. + If any insn uses a label's address as an operand, then the loop + containing that label is marked invalid, because it could be jumped + into from anywhere. Also look for blocks of code ending in an unconditional branch that exits the loop. If such a block is surrounded by a conditional @@ -3142,11 +3146,15 @@ find_and_verify_loops (rtx f, struct loo { struct loop *this_loop = uid_loop[INSN_UID (insn)]; - if (NONJUMP_INSN_P (insn) || CALL_P (insn)) + if (INSN_P (insn)) { - rtx note = find_reg_note (insn, REG_LABEL, NULL_RTX); - if (note) - invalidate_loops_containing_label (XEXP (note, 0)); + rtx note; + + for (note = find_reg_note (insn, REG_LABEL_OPERAND, NULL_RTX); + note != NULL; + note = XEXP (note, 1)) + if (REG_NOTE_KIND (note) == REG_LABEL_OPERAND) + invalidate_loops_containing_label (XEXP (note, 0)); } if (!JUMP_P (insn)) Index: gcc/rtlanal.c =================================================================== --- gcc/rtlanal.c (revision 108225) +++ gcc/rtlanal.c (working copy) @@ -2703,9 +2703,11 @@ computed_jump_p (rtx insn) { rtx pat = PATTERN (insn); - if (find_reg_note (insn, REG_LABEL, NULL_RTX)) + /* If we have a JUMP_LABEL set, we're not a computed jump. */ + if (JUMP_LABEL (insn) != NULL) return 0; - else if (GET_CODE (pat) == PARALLEL) + + if (GET_CODE (pat) == PARALLEL) { int len = XVECLEN (pat, 0); int has_use_labelref = 0; Index: gcc/reorg.c =================================================================== --- gcc/reorg.c (revision 108225) +++ gcc/reorg.c (working copy) @@ -540,7 +540,8 @@ emit_delay_sequence (rtx insn, rtx list, remove_note (tem, note); break; - case REG_LABEL: + case REG_LABEL_OPERAND: + case REG_LABEL_TARGET: /* Keep the label reference count up to date. */ if (LABEL_P (XEXP (note, 0))) LABEL_NUSES (XEXP (note, 0)) ++; @@ -2719,14 +2720,40 @@ fill_slots_from_thread (rtx insn, rtx co /* We are moving this insn, not deleting it. We must temporarily increment the use count on any referenced label lest it be deleted by delete_related_insns. */ - note = find_reg_note (trial, REG_LABEL, 0); - /* REG_LABEL could be NOTE_INSN_DELETED_LABEL too. */ - if (note && LABEL_P (XEXP (note, 0))) + for (note = REG_NOTES (trial); + note != NULL; + note = XEXP (note, 1)) + if (REG_NOTE_KIND (note) == REG_LABEL_OPERAND + || REG_NOTE_KIND (note) == REG_LABEL_TARGET) + { + /* REG_LABEL_OPERAND could be + NOTE_INSN_DELETED_LABEL too. */ + if (LABEL_P (XEXP (note, 0))) + LABEL_NUSES (XEXP (note, 0))++; + else + gcc_assert (REG_NOTE_KIND (note) + == REG_LABEL_OPERAND); + } + if (JUMP_P (trial) && JUMP_LABEL (trial)) LABEL_NUSES (XEXP (note, 0))++; delete_related_insns (trial); - if (note && LABEL_P (XEXP (note, 0))) + for (note = REG_NOTES (trial); + note != NULL; + note = XEXP (note, 1)) + if (REG_NOTE_KIND (note) == REG_LABEL_OPERAND + || REG_NOTE_KIND (note) == REG_LABEL_TARGET) + { + /* REG_LABEL_OPERAND could be + NOTE_INSN_DELETED_LABEL too. */ + if (LABEL_P (XEXP (note, 0))) + LABEL_NUSES (XEXP (note, 0))--; + else + gcc_assert (REG_NOTE_KIND (note) + == REG_LABEL_OPERAND); + } + if (JUMP_P (trial) && JUMP_LABEL (trial)) LABEL_NUSES (XEXP (note, 0))--; } else Index: gcc/flow.c =================================================================== --- gcc/flow.c (revision 108225) +++ gcc/flow.c (working copy) @@ -293,6 +293,7 @@ static void notice_stack_pointer_modific static void mark_reg (rtx, void *); static void mark_regs_live_at_end (regset); static void calculate_global_regs_live (sbitmap, sbitmap, int); +static bool propagate_block_delete_insn_label_note (rtx); static void propagate_block_delete_insn (rtx); static rtx propagate_block_delete_libcall (rtx, rtx); static int insn_dead_p (struct propagate_block_info *, rtx, int, rtx); @@ -1598,8 +1599,24 @@ allocate_reg_life_data (void) static void propagate_block_delete_insn (rtx insn) { - rtx inote = find_reg_note (insn, REG_LABEL, NULL_RTX); + rtx inote = find_reg_note (insn, REG_LABEL_TARGET, NULL_RTX); + if (inote != NULL + && !propagate_block_delete_insn_label_note (XEXP (inote, 0))) + /* ADDR_VECs must be referred to as targets, not operands. */ + gcc_assert (find_reg_note (insn, REG_LABEL_OPERAND, NULL_RTX) == NULL); + + delete_insn_and_edges (insn); + ndead++; +} + +/* Worker function for propagate_block_delete_insn. Checks whether + LABEL refers to a case-table and if so, deletes it. + Returns TRUE if a case-table was deleted, FALSE otherwise. */ + +static bool +propagate_block_delete_insn_label_note (rtx label) +{ /* If the insn referred to a label, and that label was attached to an ADDR_VEC, it's safe to delete the ADDR_VEC. In fact, it's pretty much mandatory to delete it, because the ADDR_VEC may be @@ -1610,9 +1627,8 @@ propagate_block_delete_insn (rtx insn) real good way to fix up the reference to the deleted label when the label is deleted, so we just allow it here. */ - if (inote && LABEL_P (inote)) + if (LABEL_P (label)) { - rtx label = XEXP (inote, 0); rtx next; /* The label may be forced if it has been put in the constant @@ -1634,11 +1650,12 @@ propagate_block_delete_insn (rtx insn) delete_insn_and_edges (next); ndead++; + + return true; } } - delete_insn_and_edges (insn); - ndead++; + return false; } /* Delete dead libcalls for propagate_block. Return the insn Index: gcc/cse.c =================================================================== --- gcc/cse.c (revision 108225) +++ gcc/cse.c (working copy) @@ -381,8 +381,9 @@ static int cse_altered; static int cse_jumps_altered; -/* Nonzero if we put a LABEL_REF into the hash table for an INSN without a - REG_LABEL, we have to rerun jump after CSE to put in the note. */ +/* Nonzero if we put a LABEL_REF into the hash table for an INSN + without a REG_LABEL_OPERAND, we have to rerun jump after CSE to put + in the note. */ static int recorded_label_ref; /* canon_hash stores 1 in do_not_record @@ -6970,7 +6971,7 @@ cse_basic_block (rtx from, rtx to, struc /* If we haven't already found an insn where we added a LABEL_REF, check this one. */ - if (NONJUMP_INSN_P (insn) && ! recorded_label_ref + if (INSN_P (insn) && ! recorded_label_ref && for_each_rtx (&PATTERN (insn), check_for_label_ref, (void *) insn)) recorded_label_ref = 1; @@ -7069,23 +7070,26 @@ cse_basic_block (rtx from, rtx to, struc return to ? NEXT_INSN (to) : 0; } -/* Called via for_each_rtx to see if an insn is using a LABEL_REF for which - there isn't a REG_LABEL note. Return one if so. DATA is the insn. */ +/* Called via for_each_rtx to see if an insn is using a LABEL_REF for + which there isn't a REG_LABEL_OPERAND note. + Return one if so. DATA is the insn. */ static int check_for_label_ref (rtx *rtl, void *data) { rtx insn = (rtx) data; - /* If this insn uses a LABEL_REF and there isn't a REG_LABEL note for it, - we must rerun jump since it needs to place the note. If this is a - LABEL_REF for a CODE_LABEL that isn't in the insn chain, don't do this - since no REG_LABEL will be added. */ + /* If this insn uses a LABEL_REF and there isn't a REG_LABEL_OPERAND + note for it, we must rerun jump since it needs to place the note. If + this is a LABEL_REF for a CODE_LABEL that isn't in the insn chain, + don't do this since no REG_LABEL_OPERAND will be added. */ return (GET_CODE (*rtl) == LABEL_REF && ! LABEL_REF_NONLOCAL_P (*rtl) + && (!JUMP_P (insn) + || !label_is_jump_target_p (XEXP (*rtl, 0), insn)) && LABEL_P (XEXP (*rtl, 0)) && INSN_UID (XEXP (*rtl, 0)) != 0 - && ! find_reg_note (insn, REG_LABEL, XEXP (*rtl, 0))); + && ! find_reg_note (insn, REG_LABEL_OPERAND, XEXP (*rtl, 0))); } /* Count the number of times registers are used (not set) in X. Index: gcc/jump.c =================================================================== --- gcc/jump.c (revision 108225) +++ gcc/jump.c (working copy) @@ -68,15 +68,17 @@ Software Foundation, 51 Franklin Street, static void init_label_info (rtx); static void mark_all_labels (rtx); +static void mark_jump_label_1 (rtx, rtx, bool, bool); static void delete_computation (rtx); static void redirect_exp_1 (rtx *, rtx, rtx, rtx); static int invert_exp_1 (rtx, rtx); static int returnjump_p_1 (rtx *, void *); static void delete_prior_computation (rtx, rtx); -/* Alternate entry into the jump optimizer. This entry point only rebuilds - the JUMP_LABEL field in jumping insns and REG_LABEL notes in non-jumping - instructions. */ +/* This function rebuilds the JUMP_LABEL field and REG_LABEL_TARGET + notes in jumping insns and REG_LABEL_OPERAND notes in non-jumping + instructions and jumping insns that have labels as operands + (e.g. cbranchsi4). */ void rebuild_jump_labels (rtx f) { @@ -195,31 +197,43 @@ struct tree_opt_pass pass_purge_lineno_n }; -/* Initialize LABEL_NUSES and JUMP_LABEL fields. Delete any REG_LABEL - notes whose labels don't occur in the insn any more. Returns the - largest INSN_UID found. */ +/* Initialize LABEL_NUSES and JUMP_LABEL fields, add REG_LABEL_TARGET + for remaining targets for JUMP_P. Delete any REG_LABEL_OPERAND + notes whose labels don't occur in the insn any more. */ + static void init_label_info (rtx f) { rtx insn; for (insn = f; insn; insn = NEXT_INSN (insn)) - if (LABEL_P (insn)) - LABEL_NUSES (insn) = (LABEL_PRESERVE_P (insn) != 0); - else if (JUMP_P (insn)) - JUMP_LABEL (insn) = 0; - else if (NONJUMP_INSN_P (insn) || CALL_P (insn)) - { - rtx note, next; + { + if (LABEL_P (insn)) + LABEL_NUSES (insn) = (LABEL_PRESERVE_P (insn) != 0); - for (note = REG_NOTES (insn); note; note = next) - { - next = XEXP (note, 1); - if (REG_NOTE_KIND (note) == REG_LABEL - && ! reg_mentioned_p (XEXP (note, 0), PATTERN (insn))) - remove_note (insn, note); - } - } + /* REG_LABEL_TARGET notes (including the JUMP_LABEL field) are + sticky and not reset here; that way we won't lose association + with a label when e.g. the source for a target register + disappears out of reach for targets that may use jump-target + registers. Jump transformations are supposed to transform + any REG_LABEL_TARGET notes. The target label reference in a + branch may disappear from the branch (and from the + instruction before it) for other reasons, like register + allocation. */ + + if (INSN_P (insn)) + { + rtx note, next; + + for (note = REG_NOTES (insn); note; note = next) + { + next = XEXP (note, 1); + if (REG_NOTE_KIND (note) == REG_LABEL_OPERAND + && ! reg_mentioned_p (XEXP (note, 0), PATTERN (insn))) + remove_note (insn, note); + } + } + } } /* Mark the label each jump jumps to. @@ -229,33 +243,68 @@ static void mark_all_labels (rtx f) { rtx insn; + rtx prev_nonjump_insn = NULL; for (insn = f; insn; insn = NEXT_INSN (insn)) if (INSN_P (insn)) { mark_jump_label (PATTERN (insn), insn, 0); - if (! INSN_DELETED_P (insn) && JUMP_P (insn)) + + /* If the previous non-jump insn sets something to a label, + something that this jump insn uses, make that label the primary + target of this insn if we don't yet have any. That previous + insn must be a single_set and not refer to more than one label. + The jump insn must not refer to other labels as jump targets + and must be a plain (set (pc) ...), maybe in a parallel, and + may refer to the item being set only directly or as one of the + arms in an IF_THEN_ELSE. */ + if (! INSN_DELETED_P (insn) + && JUMP_P (insn) + && JUMP_LABEL (insn) == NULL) { - /* When we know the LABEL_REF contained in a REG used in - an indirect jump, we'll have a REG_LABEL note so that - flow can tell where it's going. */ - if (JUMP_LABEL (insn) == 0) + rtx label_note = NULL; + rtx pc = pc_set (insn); + rtx pc_src = pc != NULL ? SET_SRC (pc) : NULL; + + if (prev_nonjump_insn != NULL) + label_note + = find_reg_note (prev_nonjump_insn, REG_LABEL_OPERAND, NULL); + + if (label_note != NULL && pc_src != NULL) { - rtx label_note = find_reg_note (insn, REG_LABEL, NULL_RTX); - if (label_note) + rtx label_set = single_set (prev_nonjump_insn); + rtx label_dest + = label_set != NULL ? SET_DEST (label_set) : NULL; + + if (label_set != NULL + /* The source must be the direct LABEL_REF, not a + PLUS, UNSPEC, IF_THEN_ELSE etc. */ + && GET_CODE (SET_SRC (label_set)) == LABEL_REF + && (rtx_equal_p (label_dest, pc_src) + || (GET_CODE (pc_src) == IF_THEN_ELSE + && (rtx_equal_p (label_dest, XEXP (pc_src, 1)) + || rtx_equal_p (label_dest, + XEXP (pc_src, 2)))))) + { - /* But a LABEL_REF around the REG_LABEL note, so - that we can canonicalize it. */ - rtx label_ref = gen_rtx_LABEL_REF (Pmode, - XEXP (label_note, 0)); - - mark_jump_label (label_ref, insn, 0); - XEXP (label_note, 0) = XEXP (label_ref, 0); - JUMP_LABEL (insn) = XEXP (label_note, 0); + /* The CODE_LABEL referred to in the note must be the + CODE_LABEL in the LABEL_REF of the "set". We can + conveniently use it for the marker function, which + requires a LABEL_REF wrapping. */ + gcc_assert (XEXP (label_note, 0) + == XEXP (SET_SRC (label_set), 0)); + + mark_jump_label_1 (label_set, insn, false, true); + gcc_assert (JUMP_LABEL (insn) + == XEXP (SET_SRC (label_set), 0)); } } } + else if (! INSN_DELETED_P (insn)) + prev_nonjump_insn = insn; } + else if (LABEL_P (insn)) + prev_nonjump_insn = NULL; } /* Move all block-beg, block-end, loop-beg, loop-cont, loop-vtop, loop-end, @@ -1092,12 +1141,14 @@ follow_jumps (rtx label) } -/* Find all CODE_LABELs referred to in X, and increment their use counts. - If INSN is a JUMP_INSN and there is at least one CODE_LABEL referenced - in INSN, then store one of them in JUMP_LABEL (INSN). - If INSN is an INSN or a CALL_INSN and there is at least one CODE_LABEL - referenced in INSN, add a REG_LABEL note containing that label to INSN. - Also, when there are consecutive labels, canonicalize on the last of them. +/* Find all CODE_LABELs referred to in X, and increment their use + counts. If INSN is a JUMP_INSN and there is at least one + CODE_LABEL referenced in INSN as a jump target, then store the last + one in JUMP_LABEL (INSN). For a tablejump, this must be the label + for the ADDR_VEC. Store any other jump targets as REG_LABEL_TARGET + notes. If INSN is an INSN or a CALL_INSN or non-target operands of + a JUMP_INSN, and there is at least one CODE_LABEL referenced in + INSN, add a REG_LABEL_OPERAND note containing that label to INSN. Note that two labels separated by a loop-beginning note must be kept distinct if we have not yet done loop-optimization, @@ -1108,6 +1159,19 @@ follow_jumps (rtx label) void mark_jump_label (rtx x, rtx insn, int in_mem) { + mark_jump_label_1 (x, insn, in_mem != 0, + (insn != NULL && x == PATTERN (insn) && JUMP_P (insn))); +} + +/* Worker function for mark_jump_label. IN_MEM is TRUE when X occurrs + within a (MEM ...). IS_TARGET is TRUE when X is to be treated as a + jump-target; when the JUMP_LABEL field of INSN should be set or a + REG_LABEL_TARGET note should be added, not a REG_LABEL_OPERAND + note. */ + +static void +mark_jump_label_1 (rtx x, rtx insn, bool in_mem, bool is_target) +{ RTX_CODE code = GET_CODE (x); int i; const char *fmt; @@ -1124,7 +1188,7 @@ mark_jump_label (rtx x, rtx insn, int in return; case MEM: - in_mem = 1; + in_mem = true; break; case SYMBOL_REF: @@ -1133,9 +1197,19 @@ mark_jump_label (rtx x, rtx insn, int in /* If this is a constant-pool reference, see if it is a label. */ if (CONSTANT_POOL_ADDRESS_P (x)) - mark_jump_label (get_pool_constant (x), insn, in_mem); + mark_jump_label_1 (get_pool_constant (x), insn, in_mem, is_target); break; + /* Handle operands in the condition of an if-then-else as for a + non-jump insn. */ + case IF_THEN_ELSE: + if (!is_target) + break; + mark_jump_label_1 (XEXP (x, 0), insn, in_mem, false); + mark_jump_label_1 (XEXP (x, 1), insn, in_mem, true); + mark_jump_label_1 (XEXP (x, 2), insn, in_mem, true); + return; + case LABEL_REF: { rtx label = XEXP (x, 0); @@ -1158,17 +1232,21 @@ mark_jump_label (rtx x, rtx insn, int in if (insn) { - if (JUMP_P (insn)) + if (is_target + && (JUMP_LABEL (insn) == NULL || JUMP_LABEL (insn) == label)) JUMP_LABEL (insn) = label; else { - /* Add a REG_LABEL note for LABEL unless there already - is one. All uses of a label, except for labels - that are the targets of jumps, must have a - REG_LABEL note. */ - if (! find_reg_note (insn, REG_LABEL, label)) - REG_NOTES (insn) = gen_rtx_INSN_LIST (REG_LABEL, label, - REG_NOTES (insn)); + enum reg_note kind + = is_target ? REG_LABEL_TARGET : REG_LABEL_OPERAND; + + /* Add a REG_LABEL_OPERAND or REG_LABEL_TARGET note + for LABEL unless there already is one. All uses of + a label, except for the primary target of a jump, + must have such a note. */ + if (! find_reg_note (insn, kind, label)) + REG_NOTES (insn) + = gen_rtx_INSN_LIST (kind, label, REG_NOTES (insn)); } } return; @@ -1183,7 +1261,8 @@ mark_jump_label (rtx x, rtx insn, int in int eltnum = code == ADDR_DIFF_VEC ? 1 : 0; for (i = 0; i < XVECLEN (x, eltnum); i++) - mark_jump_label (XVECEXP (x, eltnum, i), NULL_RTX, in_mem); + mark_jump_label_1 (XVECEXP (x, eltnum, i), NULL_RTX, in_mem, + is_target); } return; @@ -1192,15 +1271,21 @@ mark_jump_label (rtx x, rtx insn, int in } fmt = GET_RTX_FORMAT (code); + + /* The primary target of a tablejump is the label of the ADDR_VEC, + which is canonically mentioned *last* in the insn. To get it + marked as JUMP_LABEL, we iterate over items in reverse order. */ for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) { if (fmt[i] == 'e') - mark_jump_label (XEXP (x, i), insn, in_mem); + mark_jump_label_1 (XEXP (x, i), insn, in_mem, is_target); else if (fmt[i] == 'E') { int j; - for (j = 0; j < XVECLEN (x, i); j++) - mark_jump_label (XVECEXP (x, i, j), insn, in_mem); + + for (j = XVECLEN (x, i) - 1; j >= 0; j--) + mark_jump_label_1 (XVECEXP (x, i, j), insn, in_mem, + is_target); } } } @@ -1430,20 +1515,10 @@ delete_related_insns (rtx insn) rtx lab = JUMP_LABEL (insn), lab_next; if (LABEL_NUSES (lab) == 0) - { - /* This can delete NEXT or PREV, - either directly if NEXT is JUMP_LABEL (INSN), - or indirectly through more levels of jumps. */ - delete_related_insns (lab); - - /* I feel a little doubtful about this loop, - but I see no clean and sure alternative way - to find the first insn after INSN that is not now deleted. - I hope this works. */ - while (next && INSN_DELETED_P (next)) - next = NEXT_INSN (next); - return next; - } + /* This can delete NEXT or PREV, + either directly if NEXT is JUMP_LABEL (INSN), + or indirectly through more levels of jumps. */ + delete_related_insns (lab); else if (tablejump_p (insn, NULL, &lab_next)) { /* If we're deleting the tablejump, delete the dispatch table. @@ -1472,10 +1547,12 @@ delete_related_insns (rtx insn) return next; } - /* Likewise for an ordinary INSN / CALL_INSN with a REG_LABEL note. */ - if (NONJUMP_INSN_P (insn) || CALL_P (insn)) + /* Likewise for any JUMP_P / INSN / CALL_INSN with a + REG_LABEL_OPERAND or REG_LABEL_TARGET note. */ + if (INSN_P (insn)) for (note = REG_NOTES (insn); note; note = XEXP (note, 1)) - if (REG_NOTE_KIND (note) == REG_LABEL + if ((REG_NOTE_KIND (note) == REG_LABEL_OPERAND + || REG_NOTE_KIND (note) == REG_LABEL_TARGET) /* This could also be a NOTE_INSN_DELETED_LABEL note. */ && LABEL_P (XEXP (note, 0))) if (LABEL_NUSES (XEXP (note, 0)) == 0) @@ -1520,6 +1597,12 @@ delete_related_insns (rtx insn) } } + /* I feel a little doubtful about this loop, + but I see no clean and sure alternative way + to find the first insn after INSN that is not now deleted. + I hope this works. */ + while (next && INSN_DELETED_P (next)) + next = NEXT_INSN (next); return next; } @@ -1677,6 +1760,8 @@ redirect_jump_2 (rtx jump, rtx olabel, r { rtx note; + gcc_assert (JUMP_LABEL (jump) == olabel); + JUMP_LABEL (jump) = nlabel; if (nlabel) ++LABEL_NUSES (nlabel); Index: gcc/print-rtl.c =================================================================== --- gcc/print-rtl.c (revision 108225) +++ gcc/print-rtl.c (working copy) @@ -359,6 +359,9 @@ print_rtx (rtx in_rtx) } } } + else if (i == 9 && JUMP_P (in_rtx) && XEXP (in_rtx, i) != NULL) + /* Output the JUMP_LABEL reference. */ + fprintf (outfile, "\n -> %d", INSN_UID (XEXP (in_rtx, i))); break; case 'e': Index: gcc/gcse.c =================================================================== --- gcc/gcse.c (revision 108225) +++ gcc/gcse.c (working copy) @@ -4564,17 +4575,18 @@ one_pre_gcse_pass (int pass) return changed; } -/* If X contains any LABEL_REF's, add REG_LABEL notes for them to INSN. - If notes are added to an insn which references a CODE_LABEL, the - LABEL_NUSES count is incremented. We have to add REG_LABEL notes, - because the following loop optimization pass requires them. */ +/* If X contains any LABEL_REF's, add REG_LABEL_OPERAND notes for them + to INSN. If such notes are added to an insn which references a + CODE_LABEL, the LABEL_NUSES count is incremented. We have to add + that note, because the following loop optimization pass requires + them. */ /* ??? This is very similar to the loop.c add_label_notes function. We could probably share code here. */ /* ??? If there was a jump optimization pass after gcse and before loop, then we would not need to do this here, because jump would add the - necessary REG_LABEL notes. */ + necessary REG_LABEL_OPERAND and REG_LABEL_TARGET notes. */ static void add_label_notes (rtx x, rtx insn) @@ -4591,10 +4603,18 @@ add_label_notes (rtx x, rtx insn) We no longer ignore such label references (see LABEL_REF handling in mark_jump_label for additional information). */ - REG_NOTES (insn) = gen_rtx_INSN_LIST (REG_LABEL, XEXP (x, 0), - REG_NOTES (insn)); - if (LABEL_P (XEXP (x, 0))) - LABEL_NUSES (XEXP (x, 0))++; + if (reg_mentioned_p (XEXP (x, 0), insn)) + { + /* There's no reason for current users to emit jump-insns + with such a LABEL_REF, so we don't have to handle + REG_LABEL_TARGET notes. */ + gcc_assert (!JUMP_P (insn)); + REG_NOTES (insn) + = gen_rtx_INSN_LIST (REG_LABEL_OPERAND, XEXP (x, 0), + REG_NOTES (insn)); + if (LABEL_P (XEXP (x, 0))) + LABEL_NUSES (XEXP (x, 0))++; + } return; } Index: gcc/emit-rtl.c =================================================================== --- gcc/emit-rtl.c (revision 108225) +++ gcc/emit-rtl.c (working copy) @@ -3272,11 +3272,12 @@ try_split (rtx pat, rtx trial, int last) /* If there are LABELS inside the split insns increment the usage count so we don't delete the label. */ - if (NONJUMP_INSN_P (trial)) + if (INSN_P (trial)) { insn = insn_last; while (insn != NULL_RTX) { + /* JUMP_P insns have already been "marked" above. */ if (NONJUMP_INSN_P (insn)) mark_label_nuses (PATTERN (insn)); @@ -5438,10 +5439,11 @@ emit_copy_of_insn_after (rtx insn, rtx a which may be duplicated by the basic block reordering code. */ RTX_FRAME_RELATED_P (new) = RTX_FRAME_RELATED_P (insn); - /* Copy all REG_NOTES except REG_LABEL since mark_jump_label will - make them. */ + /* Copy all REG_NOTES except REG_LABEL_OPERAND since mark_jump_label + will make them. REG_LABEL_TARGETs are created there too, but are + supposed to be sticky, so we copy them. */ for (link = REG_NOTES (insn); link; link = XEXP (link, 1)) - if (REG_NOTE_KIND (link) != REG_LABEL) + if (REG_NOTE_KIND (link) != REG_LABEL_OPERAND) { if (GET_CODE (link) == EXPR_LIST) REG_NOTES (new) Index: gcc/rtl.h =================================================================== --- gcc/rtl.h (revision 108225) +++ gcc/rtl.h (working copy) @@ -208,7 +208,8 @@ struct rtx_def GTY((chain_next ("RTX_NEX 1 in a REG expression if corresponds to a variable declared by the user, 0 for an internally generated temporary. 1 in a SUBREG with a negative value. - 1 in a LABEL_REF or in a REG_LABEL note for a non-local label. + 1 in a LABEL_REF, REG_LABEL_TARGET or REG_LABEL_OPERAND note for a + non-local label. In a SYMBOL_REF, this flag is used for machine-specific purposes. */ unsigned int volatil : 1; /* 1 in a MEM referring to a field of an aggregate. @@ -1137,10 +1138,11 @@ do { \ (RTL_FLAG_CHECK1("LABEL_OUTSIDE_LOOP_P", (RTX), LABEL_REF)->in_struct) /* 1 if RTX is a label_ref for a nonlocal label. */ -/* Likewise in an expr_list for a reg_label note. */ +/* Likewise in an expr_list for a REG_LABEL_OPERAND or + REG_LABEL_TARGET note. */ #define LABEL_REF_NONLOCAL_P(RTX) \ - (RTL_FLAG_CHECK2("LABEL_REF_NONLOCAL_P", (RTX), LABEL_REF, \ - REG_LABEL)->volatil) + (RTL_FLAG_CHECK3("LABEL_REF_NONLOCAL_P", (RTX), LABEL_REF, \ + REG_LABEL_OPERAND, REG_LABEL_TARGET)->volatil) /* 1 if RTX is a code_label that should always be considered to be needed. */ #define LABEL_PRESERVE_P(RTX) \ Index: gcc/combine.c =================================================================== --- gcc/combine.c (revision 108225) +++ gcc/combine.c (working copy) @@ -12142,7 +12142,8 @@ distribute_notes (rtx notes, rtx from_in } break; - case REG_LABEL: + case REG_LABEL_TARGET: + case REG_LABEL_OPERAND: /* This can show up in several ways -- either directly in the pattern, or hidden off in the constant pool with (or without?) a REG_EQUAL note. */ @@ -12165,34 +12166,33 @@ distribute_notes (rtx notes, rtx from_in place = i2; } - /* Don't attach REG_LABEL note to a JUMP_INSN. Add - a JUMP_LABEL instead or decrement LABEL_NUSES. */ - if (place && JUMP_P (place)) + /* For REG_LABEL_TARGET on a JUMP_P, we prefer to put the note + as a JUMP_LABEL or decrement LABEL_NUSES if it's already + there. */ + if (place && JUMP_P (place) + && REG_NOTE_KIND (note) == REG_LABEL_TARGET + && (JUMP_LABEL (place) == NULL + || JUMP_LABEL (place) == XEXP (note, 0))) { rtx label = JUMP_LABEL (place); if (!label) JUMP_LABEL (place) = XEXP (note, 0); - else - { - gcc_assert (label == XEXP (note, 0)); - if (LABEL_P (label)) - LABEL_NUSES (label)--; - } + else if (LABEL_P (label)) + LABEL_NUSES (label)--; place = 0; } - if (place2 && JUMP_P (place2)) + if (place2 && JUMP_P (place2) + && REG_NOTE_KIND (note) == REG_LABEL_TARGET + && (JUMP_LABEL (place2) == NULL + || JUMP_LABEL (place2) == XEXP (note, 0))) { rtx label = JUMP_LABEL (place2); if (!label) JUMP_LABEL (place2) = XEXP (note, 0); - else - { - gcc_assert (label == XEXP (note, 0)); - if (LABEL_P (label)) - LABEL_NUSES (label)--; - } + else if (LABEL_P (label)) + LABEL_NUSES (label)--; place2 = 0; } break; Index: gcc/sched-rgn.c =================================================================== --- gcc/sched-rgn.c (revision 108225) +++ gcc/sched-rgn.c (working copy) @@ -305,24 +305,20 @@ is_cfg_nonregular (void) if (current_function_has_exception_handlers ()) return 1; - /* If we have non-jumping insns which refer to labels, then we consider - the cfg not well structured. */ + /* If we have insns which refer to labels as non-jumped-to operands, + then we consider the cfg not well structured. */ FOR_EACH_BB (b) FOR_BB_INSNS (b, insn) { - /* Check for labels referred by non-jump insns. */ - if (NONJUMP_INSN_P (insn) || CALL_P (insn)) - { - rtx note = find_reg_note (insn, REG_LABEL, NULL_RTX); - if (note - && ! (JUMP_P (NEXT_INSN (insn)) - && find_reg_note (NEXT_INSN (insn), REG_LABEL, - XEXP (note, 0)))) - return 1; - } + /* Check for labels referred to but (at least not directly) as + jump targets. */ + if (INSN_P (insn) + && find_reg_note (insn, REG_LABEL_OPERAND, NULL_RTX)) + return 1; + /* If this function has a computed jump, then we consider the cfg not well structured. */ - else if (JUMP_P (insn) && computed_jump_p (insn)) + if (JUMP_P (insn) && computed_jump_p (insn)) return 1; } Index: gcc/reg-notes.def =================================================================== --- gcc/reg-notes.def (revision 108225) +++ gcc/reg-notes.def (working copy) @@ -92,10 +92,16 @@ REG_NOTE (UNUSED) REG_NOTE (CC_SETTER) REG_NOTE (CC_USER) -/* Points to a CODE_LABEL. Used by non-JUMP_INSNs to say that the - CODE_LABEL contained in the REG_LABEL note is used by the insn. - This note is an INSN_LIST. */ -REG_NOTE (LABEL) +/* Points to a CODE_LABEL. Used by JUMP_INSNs to say that the CODE_LABEL + contained in the REG_LABEL_TARGET note is a possible jump target of + this insn. This note is an INSN_LIST. */ +REG_NOTE (LABEL_TARGET) + +/* Points to a CODE_LABEL. Used by any insn to say that the CODE_LABEL + contained in the REG_LABEL_OPERAND note is used by the insn, but as an + operand, not as a jump target (though it may indirectly be a jump + target for a later jump insn). This note is an INSN_LIST. */ +REG_NOTE (LABEL_OPERAND) /* REG_DEP_ANTI and REG_DEP_OUTPUT are used in LOG_LINKS to represent write-after-read and write-after-write dependencies respectively. */ Index: gcc/cfgrtl.c =================================================================== --- gcc/cfgrtl.c (revision 108225) +++ gcc/cfgrtl.c (working copy) @@ -140,15 +140,15 @@ delete_insn (rtx insn) /* If deleting a jump, decrement the use count of the label. Deleting the label itself should happen in the normal course of block merging. */ - if (JUMP_P (insn) - && JUMP_LABEL (insn) - && LABEL_P (JUMP_LABEL (insn))) - LABEL_NUSES (JUMP_LABEL (insn))--; - - /* Also if deleting an insn that references a label. */ - else + if (JUMP_P (insn)) { - while ((note = find_reg_note (insn, REG_LABEL, NULL_RTX)) != NULL_RTX + if (JUMP_LABEL (insn) + && LABEL_P (JUMP_LABEL (insn))) + LABEL_NUSES (JUMP_LABEL (insn))--; + + /* If there are more targets, remove them too. */ + while ((note + = find_reg_note (insn, REG_LABEL_TARGET, NULL_RTX)) != NULL_RTX && LABEL_P (XEXP (note, 0))) { LABEL_NUSES (XEXP (note, 0))--; @@ -156,6 +156,14 @@ delete_insn (rtx insn) } } + /* Also if deleting any insn that references a label as an operand. */ + while ((note = find_reg_note (insn, REG_LABEL_OPERAND, NULL_RTX)) != NULL_RTX + && LABEL_P (XEXP (note, 0))) + { + LABEL_NUSES (XEXP (note, 0))--; + remove_note (insn, note); + } + if (JUMP_P (insn) && (GET_CODE (PATTERN (insn)) == ADDR_VEC || GET_CODE (PATTERN (insn)) == ADDR_DIFF_VEC)) Index: gcc/reload1.c =================================================================== --- gcc/reload1.c (revision 108225) +++ gcc/reload1.c (working copy) @@ -1445,8 +1445,8 @@ calculate_needs_all_insns (int global) chain->need_operand_change = 0; /* If this is a label, a JUMP_INSN, or has REG_NOTES (which might - include REG_LABEL), we need to see what effects this has on the - known offsets at labels. */ + include REG_LABEL_OPERAND and REG_LABEL_TARGET), we need to see + what effects this has on the known offsets at labels. */ if (LABEL_P (insn) || JUMP_P (insn) || (INSN_P (insn) && REG_NOTES (insn) != 0)) @@ -2165,10 +2165,11 @@ set_label_offsets (rtx x, rtx insn, int case INSN: case CALL_INSN: - /* Any labels mentioned in REG_LABEL notes can be branched to indirectly - and hence must have all eliminations at their initial offsets. */ + /* Any labels mentioned in REG_LABEL_OPERAND notes can be branched + to indirectly and hence must have all eliminations at their + initial offsets. */ for (tem = REG_NOTES (x); tem; tem = XEXP (tem, 1)) - if (REG_NOTE_KIND (tem) == REG_LABEL) + if (REG_NOTE_KIND (tem) == REG_LABEL_OPERAND) set_label_offsets (XEXP (tem, 0), insn, 1); return; Index: gcc/config/alpha/alpha.md =================================================================== --- gcc/config/alpha/alpha.md (revision 108426) +++ gcc/config/alpha/alpha.md (working copy) @@ -5323,9 +5323,9 @@ (define_split ;; Split the load of an address into a four-insn sequence on Unicos/Mk. ;; Always generate a REG_EQUAL note for the last instruction to facilitate -;; optimizations. If the symbolic operand is a label_ref, generate REG_LABEL -;; notes and update LABEL_NUSES because this is not done automatically. -;; Labels may be incorrectly deleted if we don't do this. +;; optimizations. If the symbolic operand is a label_ref, generate +;; REG_LABEL_OPERAND notes and update LABEL_NUSES because this is not done +;; automatically. Labels may be incorrectly deleted if we don't do this. ;; ;; Describing what the individual instructions do correctly is too complicated ;; so use UNSPECs for each of the three parts of an address. @@ -5349,11 +5349,11 @@ (define_split rtx label; label = XEXP (operands[1], 0); - REG_NOTES (insn1) = gen_rtx_EXPR_LIST (REG_LABEL, label, + REG_NOTES (insn1) = gen_rtx_EXPR_LIST (REG_LABEL_OPERAND, label, REG_NOTES (insn1)); - REG_NOTES (insn2) = gen_rtx_EXPR_LIST (REG_LABEL, label, + REG_NOTES (insn2) = gen_rtx_EXPR_LIST (REG_LABEL_OPERAND, label, REG_NOTES (insn2)); - REG_NOTES (insn3) = gen_rtx_EXPR_LIST (REG_LABEL, label, + REG_NOTES (insn3) = gen_rtx_EXPR_LIST (REG_LABEL_OPERAND, label, REG_NOTES (insn3)); LABEL_NUSES (label) += 3; } Index: gcc/config/sh/sh.c =================================================================== --- gcc/config/sh/sh.c (revision 108426) +++ gcc/config/sh/sh.c (working copy) @@ -4309,8 +4309,8 @@ sh_reorg (void) mdep_reorg_phase = SH_INSERT_USES_LABELS; if (TARGET_RELAX) { - /* Remove all REG_LABEL notes. We want to use them for our own - purposes. This works because none of the remaining passes + /* Remove all REG_LABEL_OPERAND notes. We want to use them for our + own purposes. This works because none of the remaining passes need to look at them. ??? But it may break in the future. We should use a machine @@ -4321,7 +4321,8 @@ sh_reorg (void) { rtx note; - while ((note = find_reg_note (insn, REG_LABEL, NULL_RTX)) != 0) + while ((note = find_reg_note (insn, REG_LABEL_OPERAND, + NULL_RTX)) != 0) remove_note (insn, note); } } @@ -4496,16 +4497,16 @@ sh_reorg (void) continue; } - /* Create a code label, and put it in a REG_LABEL note on - the insn which sets the register, and on each call insn - which uses the register. In final_prescan_insn we look - for the REG_LABEL notes, and output the appropriate label + /* Create a code label, and put it in a REG_LABEL_OPERAND note + on the insn which sets the register, and on each call insn + which uses the register. In final_prescan_insn we look for + the REG_LABEL_OPERAND notes, and output the appropriate label or pseudo-op. */ label = gen_label_rtx (); - REG_NOTES (link) = gen_rtx_INSN_LIST (REG_LABEL, label, + REG_NOTES (link) = gen_rtx_INSN_LIST (REG_LABEL_OPERAND, label, REG_NOTES (link)); - REG_NOTES (insn) = gen_rtx_INSN_LIST (REG_LABEL, label, + REG_NOTES (insn) = gen_rtx_INSN_LIST (REG_LABEL_OPERAND, label, REG_NOTES (insn)); if (rescan) { @@ -4521,7 +4522,8 @@ sh_reorg (void) || ((reg2 = sfunc_uses_reg (scan)) && REGNO (reg2) == REGNO (reg)))) REG_NOTES (scan) - = gen_rtx_INSN_LIST (REG_LABEL, label, REG_NOTES (scan)); + = gen_rtx_INSN_LIST (REG_LABEL_OPERAND, label, + REG_NOTES (scan)); } while (scan != dies); } @@ -5016,7 +5018,7 @@ final_prescan_insn (rtx insn, rtx *opvec { rtx note; - note = find_reg_note (insn, REG_LABEL, NULL_RTX); + note = find_reg_note (insn, REG_LABEL_OPERAND, NULL_RTX); if (note) { rtx pattern; Index: doc/rtl.texi =================================================================== --- doc/rtl.texi (revision 110246) +++ doc/rtl.texi (working copy) @@ -2961,9 +2961,10 @@ mandatory ones listed above. These four @findex jump_insn @item jump_insn The expression code @code{jump_insn} is used for instructions that may -jump (or, more generally, may contain @code{label_ref} expressions). If -there is an instruction to return from the current function, it is -recorded as a @code{jump_insn}. +jump (or, more generally, may contain @code{label_ref} expressions to +which @code{pc} can be set in that instruction). If there is an +instruction to return from the current function, it is recorded as a +@code{jump_insn}. @findex JUMP_LABEL @code{jump_insn} insns have the same extra fields as @code{insn} insns, @@ -2973,9 +2974,11 @@ accessed in the same way and in addition For simple conditional and unconditional jumps, this field contains the @code{code_label} to which this insn will (possibly conditionally) branch. In a more complex jump, @code{JUMP_LABEL} records one of the -labels that the insn refers to; the only way to find the others is to -scan the entire body of the insn. In an @code{addr_vec}, -@code{JUMP_LABEL} is @code{NULL_RTX}. +labels that the insn refers to; other jump target labels are recorded +as @code{REG_LABEL_TARGET} notes. The exception is @code{addr_vec} +and @code{addr_diff_vec}, where @code{JUMP_LABEL} is @code{NULL_RTX} +and the only way to find the labels is to scan the entire body of the +insn. Return insns count as jumps, but since they do not refer to any labels, their @code{JUMP_LABEL} is @code{NULL_RTX}. @@ -3302,14 +3305,25 @@ note giving the expression being compute with @code{REG_LIBCALL} and @code{REG_RETVAL} notes on the first and last insns, respectively. -@findex REG_LABEL -@item REG_LABEL +@findex REG_LABEL_OPERAND +@item REG_LABEL_OPERAND This insn uses @var{op}, a @code{code_label} or a @code{note} of type -@code{NOTE_INSN_DELETED_LABEL}, but is not a -@code{jump_insn}, or it is a @code{jump_insn} that required the label to -be held in a register. The presence of this note allows jump -optimization to be aware that @var{op} is, in fact, being used, and flow -optimization to build an accurate flow graph. +@code{NOTE_INSN_DELETED_LABEL}, but is not a @code{jump_insn}, or it +is a @code{jump_insn} that refers to the operand as an ordinary +operand. The label may still eventually be a jump target, but if so +in an indirect jump in a subsequent insn. The presence of this note +allows jump optimization to be aware that @var{op} is, in fact, being +used, and flow optimization to build an accurate flow graph. + +@findex REG_LABEL_TARGET +@item REG_LABEL_TARGET +This insn is a @code{jump_insn} but not a @code{addr_vec} or +@code{addr_diff_vec}. It uses @var{op}, a @code{code_label} as a +direct or indirect jump target. Its purpose is similar to that of +@code{REG_LABEL_OPERAND}. This note is only present if the insn has +multiple targets; the last label in the insn (in the highest numbered +insn-field) goes into the @code{JUMP_LABEL} field and does not have a +@code{REG_LABEL_TARGET} note. @xref{Insns, JUMP_LABEL}. @findex REG_CROSSING_JUMP @item REG_CROSSING_JUMP brgds, H-P