On Thu, May 8, 2025 at 11:11 AM H.J. Lu <hjl.to...@gmail.com> wrote: > > Conditional and unconditional branch targets can be either a label or > a symbol. For conditional jump: > > (jump_insn 7 6 14 2 (set (pc) > (if_then_else (eq (reg:CCZ 17 flags) > (const_int 0 [0])) > (label_ref:DI 23) > (pc))) "x.c":8:5 1458 {jcc} > (expr_list:REG_DEAD (reg:CCZ 17 flags) > (int_list:REG_BR_PROB 217325348 (nil))) > ... > (code_label 23 20 8 4 4 (nil) [1 uses]) > (note 8 23 9 4 [bb 4] NOTE_INSN_BASIC_BLOCK) > (call_insn/j 9 8 10 4 (call (mem:QI (symbol_ref:DI ("bar") [flags 0x41] > <function_decl 0x7f4cff3c0b00 bar>) [0 bar S1 A8]) > (const_int 0 [0])) "x.c":8:14 discrim 1 1469 {sibcall_di} > (expr_list:REG_CALL_DECL (symbol_ref:DI ("bar") [flags 0x41] > <function_dec > l 0x7f4cff3c0b00 bar>) > (nil)) > (nil)) > > they can be changed to > > (jump_insn 7 6 14 2 (set (pc) > (if_then_else (eq (reg:CCZ 17 flags) > (const_int 0 [0])) > ((symbol_ref:DI ("bar") [flags 0x41] <function_decl > 0x7fffe99c0c00 foo>) > (pc))) "x.c":8:5 1458 {jcc} > (expr_list:REG_DEAD (reg:CCZ 17 flags) > (int_list:REG_BR_PROB 217325348 (nil))) > > if the call is a sibcall. For jump table: > > (jump_table_data 16 15 17 (addr_vec:DI [ > (label_ref:DI 18) > (label_ref:DI 22) > (label_ref:DI 26) > (label_ref:DI 30) > (label_ref:DI 34) > ])) > ... > (code_label 30 17 31 4 5 (nil) [1 uses]) > (note 31 30 32 4 [bb 4] NOTE_INSN_BASIC_BLOCK) > (call_insn/j 32 31 33 4 (call (mem:QI (symbol_ref:DI ("bar3") [flags 0x41] > <function_decl 0x7f21be3c0e00 bar3>) [0 bar3 S1 A8]) > (const_int 0 [0])) "j.c":15:13 1469 {sibcall_di} > (expr_list:REG_CALL_DECL (symbol_ref:DI ("bar3") [flags 0x41] > <function_decl 0x7f21be3c0e00 bar3>) > (nil)) > (nil)) > > They can be changed to > > (jump_table_data 16 15 17 (addr_vec:DI [ > (symbol_ref:DI ("bar0") [flags 0x41] <function_decl > 0x7f4f1c5c0b00 bar0>) > (symbol_ref:DI ("bar1") [flags 0x41] <function_decl > 0x7f4f1c5c0c00 bar1>) > (symbol_ref:DI ("bar2") [flags 0x41] <function_decl > 0x7f4f1c5c0d00 bar2>) > (symbol_ref:DI ("bar3") [flags 0x41] <function_decl > 0x7f4f1c5c0e00 bar3>) > (symbol_ref:DI ("bar4") [flags 0x41] <function_decl > 0x7f4f1c5c0f00 bar4>) > ])) > > if bar0/bar1/bar2/bar3/bar4 calls are sibcalls. > > Instead of supporting symbol reference in jump label and jump table in > the full RTL optimization pipeline, which requires very invasive changes > to GCC RTL infrastructure, support symbol reference in jump label and > jump table for the pass which turning REG_EH_REGION notes back into > NOTE_INSN_EH_REGION notes and after: > > 1. Add a set_jump_target method to assign symbol reference to jump label. > 2. Add condsibcall_p for conditional sibling call. > 3. Add anycall_p to return true for call and conditional sibcall. > 4. Replace CALL_P with anycall_p in except.cc, final.cc and function-abi.cc > to support conditional sibcall. > 5. Return false for symbol reference in jump table check. > 6. Update create_trace_edges and rtx_writer::print_rtx_operand_code_0 to > handle symbol reference in jump label. > 7. Update to final_scan_insn_1 to handle symbol reference in jump table. > 8. Document limitation of symbol reference support in jump label. > > * dwarf2cfi.c (create_trace_edges): Skip symbol reference in > jump table and in JUMP_LABEL. Short-circuit JUMP for the pure > sibcall. > * except.cc (sjlj_mark_call_sites): Replace CALL_P with > anycall_p. > (finish_eh_generation): Likewise. > (insn_could_throw_p): Likewise. > (can_nonlocal_goto): Likewise. > (set_nothrow_function_flags): Also call condsibcall_p to check > conditional sibcall. > * final.cc (final_scan_insn_1): Support symbol reference in jump > table. > (collect_fn_hard_reg_usage): Replace CALL_P with anycall_p. > * function-abi.cc (insn_callee_abi): Likewise. > * jump.cc (condsibcall_p): New. > * print-rtl.cc (rtx_writer::print_rtx_operand_code_0): Support > symbol reference in JUMP_LABEL. > * rtl.h (rtx_jump_insn::set_jump_target): New, with the rtx > argument. > * rtl.h (condsibcall_p): New. > (anycall_p): Likewise. > * rtlanal.cc (tablejump_p): Return false if JUMP_LABEL is a > symbol reference. > * config/i386/i386-expand.cc (ix86_notrack_prefixed_insn_p): > Likewise. > * doc/rtl.texi (addr_vec): Also allow symbol reference. > (JUMP_LABEL): Likewise. > > Signed-off-by: H.J. Lu <hjl.to...@gmail.com> > --- > gcc/config/i386/i386-expand.cc | 5 ++++- > gcc/doc/rtl.texi | 24 +++++++++++++---------- > gcc/dwarf2cfi.cc | 20 ++++++++++++++++++- > gcc/except.cc | 11 ++++++----- > gcc/final.cc | 26 +++++++++++++++++++++--- > gcc/function-abi.cc | 2 +- > gcc/jump.cc | 36 ++++++++++++++++++++++++++++++++++ > gcc/print-rtl.cc | 2 ++ > gcc/rtl.h | 32 ++++++++++++++++++++++++++++++ > gcc/rtlanal.cc | 5 ++++- > 10 files changed, 141 insertions(+), 22 deletions(-) > > diff --git a/gcc/config/i386/i386-expand.cc b/gcc/config/i386/i386-expand.cc > index 7f0fdb6fa9e..0d0802692d1 100644 > --- a/gcc/config/i386/i386-expand.cc > +++ b/gcc/config/i386/i386-expand.cc > @@ -25501,7 +25501,10 @@ ix86_notrack_prefixed_insn_p (rtx_insn *insn) > if (JUMP_P (insn) && !flag_cet_switch) > { > rtx target = JUMP_LABEL (insn); > - if (target == NULL_RTX || ANY_RETURN_P (target)) > + if (target == NULL_RTX > + || ANY_RETURN_P (target) > + /* Also check for conditional sibcall. */ > + || SYMBOL_REF_P (target)) > return false; > > /* Check the jump is a switch table. */ > diff --git a/gcc/doc/rtl.texi b/gcc/doc/rtl.texi > index 089bb1c4ede..0976c9c82dd 100644 > --- a/gcc/doc/rtl.texi > +++ b/gcc/doc/rtl.texi > @@ -3459,8 +3459,9 @@ insn, inside a @code{parallel}, or inside an expression. > @findex addr_vec > @item (addr_vec:@var{m} [@var{lr0} @var{lr1} @dots{}]) > Represents a table of jump addresses. The vector elements @var{lr0}, > -etc., are @code{label_ref} expressions. The mode @var{m} specifies > -how much space is given to each address; normally @var{m} would be > +etc., are @code{label_ref} or @code{symbol_ref} expressions. The mode > +@var{m} specifies how much space is given to each address; normally > +@var{m} would be > @code{Pmode}. > > @findex addr_diff_vec > @@ -3780,14 +3781,17 @@ instruction to return from the current function, it > is recorded as a > accessed in the same way and in addition contain a field > @code{JUMP_LABEL} which is defined once jump optimization has completed. > > -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; 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. > +For unconditional jumps, this field contains the @code{code_label} to > +which this insn will branch. For simple conditional jumps, this field > +contains the @code{code_label} or @code{symbol_ref} to which this insn > +will branch possibly conditionally. @code{symbol_ref} should only be > +generated immediately before the pass which turning REG_EH_REGION notes > +back into NOTE_INSN_EH_REGION notes. In a more complex jump, > +@code{JUMP_LABEL} records one of the 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 their @code{JUMP_LABEL} is @code{RETURN} > or @code{SIMPLE_RETURN}. > diff --git a/gcc/dwarf2cfi.cc b/gcc/dwarf2cfi.cc > index a5353d39e7e..d8f25123284 100644 > --- a/gcc/dwarf2cfi.cc > +++ b/gcc/dwarf2cfi.cc > @@ -2646,6 +2646,8 @@ create_trace_edges (rtx_insn *insn) > if (JUMP_P (insn)) > { > rtx_jump_table_data *table; > + bool sibcall_p = false; > + bool label_p = false; > > if (find_reg_note (insn, REG_NON_LOCAL_GOTO, NULL_RTX)) > return; > @@ -2657,8 +2659,17 @@ create_trace_edges (rtx_insn *insn) > n = GET_NUM_ELEM (vec); > for (i = 0; i < n; ++i) > { > - rtx_insn *lab = as_a <rtx_insn *> (XEXP (RTVEC_ELT (vec, i), > 0)); > + rtx l = RTVEC_ELT (vec, i); > + if (SYMBOL_REF_P (l)) > + { > + /* A symbol reference must be a sibcall. Skip it. */ > + sibcall_p = true; > + continue; > + } > + l = XEXP (l, 0); > + rtx_insn *lab = as_a <rtx_insn *> (l); > maybe_record_trace_start (lab, insn); > + label_p = true; > } > > /* Handle casesi dispatch insns. */ > @@ -2687,12 +2698,19 @@ create_trace_edges (rtx_insn *insn) > maybe_record_trace_start (lab, insn); > } > } > + /* A symbol reference must be a sibcall. */ > + else if (SYMBOL_REF_P (JUMP_LABEL (insn))) > + sibcall_p = true; > else > { > rtx_insn *lab = JUMP_LABEL_AS_INSN (insn); > gcc_assert (lab != NULL); > maybe_record_trace_start (lab, insn); > } > + > + /* Check for the pure sibcall. */ > + if (sibcall_p && !label_p) > + return; > } > else if (CALL_P (insn)) > { > diff --git a/gcc/except.cc b/gcc/except.cc > index 0fe1e093489..2f37e4652b9 100644 > --- a/gcc/except.cc > +++ b/gcc/except.cc > @@ -1154,7 +1154,7 @@ sjlj_mark_call_sites (void) > > /* Don't separate a call from it's argument loads. */ > before = insn; > - if (CALL_P (insn)) > + if (anycall_p (insn)) > before = find_first_parameter_load (insn, NULL); > > start_sequence (); > @@ -1567,7 +1567,7 @@ finish_eh_generation (void) > gcc_assert (BB_HEAD (e->dest) == label_rtx (lp->post_landing_pad)); > > redirect_edge_succ (e, BLOCK_FOR_INSN (lp->landing_pad)); > - e->flags |= (CALL_P (BB_END (bb)) > + e->flags |= (anycall_p (BB_END (bb)) > ? EDGE_ABNORMAL | EDGE_ABNORMAL_CALL > : EDGE_ABNORMAL); > } > @@ -1763,7 +1763,7 @@ insn_could_throw_p (const_rtx insn) > { > if (!flag_exceptions) > return false; > - if (CALL_P (insn)) > + if (anycall_p (insn)) > return true; > if (INSN_P (insn) && cfun->can_throw_non_call_exceptions) > return may_trap_p (PATTERN (insn)); > @@ -1980,7 +1980,7 @@ insn_nothrow_p (const_rtx insn) > bool > can_nonlocal_goto (const rtx_insn *insn) > { > - if (nonlocal_goto_handler_labels && CALL_P (insn)) > + if (nonlocal_goto_handler_labels && anycall_p (insn)) > { > rtx note = find_reg_note (insn, REG_EH_REGION, NULL_RTX); > if (!note || INTVAL (XEXP (note, 0)) != INT_MIN) > @@ -2020,7 +2020,8 @@ set_nothrow_function_flags (void) > { > crtl->nothrow = 0; > > - if (!CALL_P (insn) || !SIBLING_CALL_P (insn)) > + if ((!CALL_P (insn) || !SIBLING_CALL_P (insn)) > + && !condsibcall_p (insn)) > { > crtl->all_throwers_are_sibcalls = 0; > return 0; > diff --git a/gcc/final.cc b/gcc/final.cc > index 12c6eb0ac09..bff6bf3fd86 100644 > --- a/gcc/final.cc > +++ b/gcc/final.cc > @@ -2524,13 +2524,33 @@ final_scan_insn_1 (rtx_insn *insn, FILE *file, int > optimize_p ATTRIBUTE_UNUSED, > } > #else > vlen = XVECLEN (body, GET_CODE (body) == ADDR_DIFF_VEC); > +#ifdef ASM_OUTPUT_ADDR_VEC_ELT > + const char *asm_op = integer_asm_op (POINTER_SIZE_UNITS, true); > +#endif > for (idx = 0; idx < vlen; idx++) > { > if (GET_CODE (body) == ADDR_VEC) > { > #ifdef ASM_OUTPUT_ADDR_VEC_ELT > - ASM_OUTPUT_ADDR_VEC_ELT > - (file, CODE_LABEL_NUMBER (XEXP (XVECEXP (body, 0, idx), > 0))); > + rtx l = XVECEXP (body, 0, idx); > + if (SYMBOL_REF_P (l)) > + { > + gcc_assert (asm_op != NULL); > + fprintf (file, "%s", asm_op); > + assemble_external (SYMBOL_REF_DECL (l)); > +#ifdef ASM_OUTPUT_SYMBOL_REF > + ASM_OUTPUT_SYMBOL_REF (file, l); > +#else > + assemble_name (file, XSTR (l, 0)); > +#endif > + putc ('\n', file); > + } > + else > + { > + l = XEXP (l, 0); > + ASM_OUTPUT_ADDR_VEC_ELT > + (file, CODE_LABEL_NUMBER (l)); > + } > #else > gcc_unreachable (); > #endif > @@ -4604,7 +4624,7 @@ collect_fn_hard_reg_usage (void) > if (!NONDEBUG_INSN_P (insn)) > continue; > > - if (CALL_P (insn) > + if (anycall_p (insn) > && !self_recursive_call_p (insn)) > function_used_regs > |= insn_callee_abi (insn).full_and_partial_reg_clobbers (); > diff --git a/gcc/function-abi.cc b/gcc/function-abi.cc > index d500657b49e..3cabe67af73 100644 > --- a/gcc/function-abi.cc > +++ b/gcc/function-abi.cc > @@ -218,7 +218,7 @@ fndecl_abi (const_tree fndecl) > function_abi > insn_callee_abi (const rtx_insn *insn) > { > - gcc_assert (insn && CALL_P (insn)); > + gcc_assert (insn && anycall_p (insn)); > > if (flag_ipa_ra) > if (tree fndecl = get_call_fndecl (insn)) > diff --git a/gcc/jump.cc b/gcc/jump.cc > index 02df75ab08e..b7768a8b53f 100644 > --- a/gcc/jump.cc > +++ b/gcc/jump.cc > @@ -1011,6 +1011,42 @@ jump_to_label_p (const rtx_insn *insn) > return (JUMP_P (insn) > && JUMP_LABEL (insn) != NULL && !ANY_RETURN_P (JUMP_LABEL (insn))); > } > + > +/* Return true if INSN has a conditional sibling call. */ > + > +bool > +condsibcall_p (const rtx_insn *insn) > +{ > + if (!JUMP_P (insn)) > + return false; > + > + rtx label = JUMP_LABEL (insn); > + if (label == nullptr || ANY_RETURN_P (label)) > + return false; > + > + /* Check the direct conditional sibling call. */ > + if (SYMBOL_REF_P (label)) > + return true; > + > + /* Check jump table with the indirect conditional sibling call. */ > + rtx_insn *target = as_a<rtx_insn *> (label); > + rtx_insn *table = next_insn (target); > + if (!table > + || !JUMP_TABLE_DATA_P (table) > + || GET_CODE (PATTERN (table)) != ADDR_VEC) > + return false; > + > + rtx body = PATTERN (table); > + unsigned int len = XVECLEN (body, 0); > + for (unsigned int i = 0; i < len; i++) > + { > + rtx target = XVECEXP (body, 0, i); > + if (SYMBOL_REF_P (target)) > + return true; > + } > + > + return false; > +} > > /* 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 > diff --git a/gcc/print-rtl.cc b/gcc/print-rtl.cc > index 033f7e7aab0..3ed7130ee1c 100644 > --- a/gcc/print-rtl.cc > +++ b/gcc/print-rtl.cc > @@ -308,6 +308,8 @@ rtx_writer::print_rtx_operand_code_0 (const_rtx in_rtx > ATTRIBUTE_UNUSED, > fprintf (m_outfile, "return"); > else if (GET_CODE (JUMP_LABEL (in_rtx)) == SIMPLE_RETURN) > fprintf (m_outfile, "simple_return"); > + else if (SYMBOL_REF_P (JUMP_LABEL (in_rtx))) > + print_rtx_operand_code_0 (JUMP_LABEL (in_rtx), idx); > else > fprintf (m_outfile, "%d", INSN_UID (JUMP_LABEL (in_rtx))); > } > diff --git a/gcc/rtl.h b/gcc/rtl.h > index cc25aed1f49..0d665b74c7a 100644 > --- a/gcc/rtl.h > +++ b/gcc/rtl.h > @@ -625,6 +625,7 @@ public: > /* Set jump target. */ > > inline void set_jump_target (rtx_code_label *); > + inline void set_jump_target (rtx); > }; > > struct GTY(()) rtx_call_insn : public rtx_insn > @@ -1895,6 +1896,12 @@ inline void rtx_jump_insn::set_jump_target > (rtx_code_label *target) > JUMP_LABEL (this) = target; > } > > +inline void rtx_jump_insn::set_jump_target (rtx target) > +{ > + gcc_assert (SYMBOL_REF_P (target) || LABEL_P (target)); > + JUMP_LABEL (this) = target; > +} > + > /* Once basic blocks are found, each CODE_LABEL starts a chain that > goes through all the LABEL_REFs that jump to that label. The chain > eventually winds up at the CODE_LABEL: it is circular. */ > @@ -4175,6 +4182,7 @@ extern bool jump_to_label_p (const rtx_insn *); > extern bool condjump_p (const rtx_insn *); > extern bool any_condjump_p (const rtx_insn *); > extern bool any_uncondjump_p (const rtx_insn *); > +extern bool condsibcall_p (const rtx_insn *); > extern rtx pc_set (const rtx_insn *); > extern rtx condjump_label (const rtx_insn *); > extern bool simplejump_p (const rtx_insn *); > @@ -4635,6 +4643,30 @@ word_register_operation_p (const_rtx x) > } > } > > +/* Return true if INSN is a conditional sibcall. */ > + > +inline bool > +condsibcall_p (const_rtx insn) > +{ > + return condsibcall_p (as_a <const rtx_insn *> (insn)); > +} > + > +/* Return true if INSN is a call or a conditional sibcall. */ > + > +inline bool > +anycall_p (const rtx_insn *insn) > +{ > + return CALL_P (insn) || condsibcall_p (insn); > +} > + > +/* Return true if INSN is a call or a conditional sibcall. */ > + > +inline bool > +anycall_p (const_rtx insn) > +{ > + return CALL_P (insn) || condsibcall_p (insn); > +} > + > /* Holds an rtx comparison to simplify passing many parameters pertaining to > a > single comparison. */ > > diff --git a/gcc/rtlanal.cc b/gcc/rtlanal.cc > index 86a5e473308..915a5d4634d 100644 > --- a/gcc/rtlanal.cc > +++ b/gcc/rtlanal.cc > @@ -3539,7 +3539,10 @@ tablejump_p (const rtx_insn *insn, rtx_insn **labelp, > return false; > > rtx target = JUMP_LABEL (insn); > - if (target == NULL_RTX || ANY_RETURN_P (target)) > + if (target == NULL_RTX > + || ANY_RETURN_P (target) > + /* Also check for conditional sibcall. */ > + || SYMBOL_REF_P (target)) > return false; > > rtx_insn *label = as_a<rtx_insn *> (target); > -- > 2.49.0 >
-- H.J.