On Thu, Jun 26, 2025 at 3:32 PM H.J. Lu <hjl.to...@gmail.com> wrote:
>
> 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>

PING^2.

> > ---
> >  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.



--
H.J.

Reply via email to