x86 conditional branch (jcc) target can be either a label or a symbol.
Add a pass to fold tail call with jcc by turning:

        jcc     .L6
...
.L6:
        jmp     tailcall

into:

        jcc     tailcall

After basic block reordering pass, conditional branches look like

(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]  <functi
on_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))

If the branch edge destination is a basic block with only a direct
sibcall, change the jcc target to the sibcall target and decrement
the destination basic block entry label use count.  Even though the
destination basic block is unused, it must be kept since it is required
by RTL control flow check and JUMP_LABEL of the conditional jump can
only point to a code label, not a code symbol.  Dummy sibcall patterns
are added so that sibcalls in basic blocks, whose entry label use count
is 0, won't be generated.

Update final_scan_insn_1 to skip a label if its use count is 0.

gcc/

        PR target/47253
        * final.cc (final_scan_insn_1): Skip the unused label.
        * config/i386/i386-features.cc (sibcall_only_bb): New.
        (fold_sibcall): Likewise.
        (pass_data_fold_sibcall): Likewise.
        (pass_fold_sibcall): Likewise.
        (make_pass_fold_sibcall): Likewise.
        * config/i386/i386-passes.def: Add pass_fold_sibcall after
        pass_reorder_blocks.
        * config/i386/i386-protos.h (ix86_output_jcc_insn): New.
        (make_pass_fold_sibcall): Likewise.
        * config/i386/i386.cc (ix86_output_jcc_insn): Likewise.
        * config/i386/i386.md (*jcc): Renamed to ...
        (jcc): This.  Replace label_ref with symbol_label_operand.  Use
        ix86_output_jcc_insn.  Set length to 6 if the branch target
        isn't a label.
        (*sibcall): Renamed to ...
        (sibcall_<mode>): This.
        (sibcall_dummy_<mode>): New.
        (*sibcall_pop): Renamed to ...
        (sibcall_pop): This.
        (sibcall_pop_dummy): New.
        (*sibcall_value): Renamed to ...
        (sibcall_value_<mode>): This.
        (sibcall_value_dummy_<mode>): New.
        (*sibcall_value_pop): Renamed to ...
        (sibcall_value_pop): This.
        (sibcall_value_pop_dummy): New.
        * config/i386/predicates.md (symbol_label_operand): Likewise.

gcc/testsuite/

        PR target/47253
        * gcc.target/i386/pr47253-1a.c: New file.
        * gcc.target/i386/pr47253-1b.c: Likewise.
        * gcc.target/i386/pr47253-2a.c: Likewise.
        * gcc.target/i386/pr47253-2b.c: Likewise.
        * gcc.target/i386/pr47253-3a.c: Likewise.
        * gcc.target/i386/pr47253-3b.c: Likewise.
        * gcc.target/i386/pr47253-3c.c: Likewise.
        * gcc.target/i386/pr47253-4a.c: Likewise.
        * gcc.target/i386/pr47253-4b.c: Likewise.
        * gcc.target/i386/pr47253-5.c: Likewise.
        * gcc.target/i386/pr47253-6.c: Likewise.
        * gcc.target/i386/pr47253-7a.c: Likewise.
        * gcc.target/i386/pr47253-7b.c: Likewise.

Signed-off-by: H.J. Lu <hjl.to...@gmail.com>
---
 gcc/config/i386/i386-features.cc           | 208 +++++++++++++++++++++
 gcc/config/i386/i386-passes.def            |   1 +
 gcc/config/i386/i386-protos.h              |   3 +
 gcc/config/i386/i386.cc                    |  12 ++
 gcc/config/i386/i386.md                    |  57 +++++-
 gcc/config/i386/predicates.md              |   4 +
 gcc/final.cc                               |   4 +
 gcc/testsuite/gcc.target/i386/pr47253-1a.c |  24 +++
 gcc/testsuite/gcc.target/i386/pr47253-1b.c |  17 ++
 gcc/testsuite/gcc.target/i386/pr47253-2a.c |  27 +++
 gcc/testsuite/gcc.target/i386/pr47253-2b.c |  17 ++
 gcc/testsuite/gcc.target/i386/pr47253-3a.c |  32 ++++
 gcc/testsuite/gcc.target/i386/pr47253-3b.c |  20 ++
 gcc/testsuite/gcc.target/i386/pr47253-3c.c |  20 ++
 gcc/testsuite/gcc.target/i386/pr47253-4a.c |  26 +++
 gcc/testsuite/gcc.target/i386/pr47253-4b.c |  18 ++
 gcc/testsuite/gcc.target/i386/pr47253-5.c  |  15 ++
 gcc/testsuite/gcc.target/i386/pr47253-6.c  |  15 ++
 gcc/testsuite/gcc.target/i386/pr47253-7a.c |  52 ++++++
 gcc/testsuite/gcc.target/i386/pr47253-7b.c |  36 ++++
 20 files changed, 600 insertions(+), 8 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/i386/pr47253-1a.c
 create mode 100644 gcc/testsuite/gcc.target/i386/pr47253-1b.c
 create mode 100644 gcc/testsuite/gcc.target/i386/pr47253-2a.c
 create mode 100644 gcc/testsuite/gcc.target/i386/pr47253-2b.c
 create mode 100644 gcc/testsuite/gcc.target/i386/pr47253-3a.c
 create mode 100644 gcc/testsuite/gcc.target/i386/pr47253-3b.c
 create mode 100644 gcc/testsuite/gcc.target/i386/pr47253-3c.c
 create mode 100644 gcc/testsuite/gcc.target/i386/pr47253-4a.c
 create mode 100644 gcc/testsuite/gcc.target/i386/pr47253-4b.c
 create mode 100644 gcc/testsuite/gcc.target/i386/pr47253-5.c
 create mode 100644 gcc/testsuite/gcc.target/i386/pr47253-6.c
 create mode 100644 gcc/testsuite/gcc.target/i386/pr47253-7a.c
 create mode 100644 gcc/testsuite/gcc.target/i386/pr47253-7b.c

diff --git a/gcc/config/i386/i386-features.cc b/gcc/config/i386/i386-features.cc
index c35ac24fd8a..bb1e428bb1b 100644
--- a/gcc/config/i386/i386-features.cc
+++ b/gcc/config/i386/i386-features.cc
@@ -3288,6 +3288,214 @@ make_pass_remove_partial_avx_dependency (gcc::context 
*ctxt)
   return new pass_remove_partial_avx_dependency (ctxt);
 }
 
+/* Return the sibcall target if BB only has a direct sibcall.  */
+
+static rtx
+sibcall_only_bb (basic_block bb, bitmap sibcall_bbs)
+{
+  if (!single_succ_p (bb)
+      || single_succ (bb) != EXIT_BLOCK_PTR_FOR_FN (cfun))
+    return nullptr;
+
+  rtx_insn *insn, *sibcall = nullptr;
+
+  FOR_BB_INSNS (bb, insn)
+    {
+      if (!NONDEBUG_INSN_P (insn))
+       continue;
+      if (sibcall
+         || !CALL_P (insn)
+         || !SIBLING_CALL_P (insn)
+         || can_throw_external (insn))
+       return nullptr;
+      sibcall = insn;
+    }
+
+  rtx call = PATTERN (sibcall);
+  if (GET_CODE (call) == SET)
+    call = SET_SRC (call);
+  if (GET_CODE (call) != CALL)
+    return nullptr;
+  rtx fnaddr = XEXP (call, 0);
+  fnaddr = XEXP (fnaddr, 0);
+  if (GET_CODE (fnaddr) == SYMBOL_REF
+      && !ix86_nopic_noplt_attribute_p (fnaddr))
+    {
+      /* Record basic block only with a direct sibcall.  */
+      bitmap_set_bit (sibcall_bbs, bb->index);
+      return fnaddr;
+    }
+  return nullptr;
+}
+
+/* Fold direct sibcall.  */
+
+static unsigned int
+fold_sibcall (void)
+{
+  timevar_push (TV_MACH_DEP);
+
+  bitmap_obstack_initialize (NULL);
+  bitmap jcc_sibcall_bbs = BITMAP_ALLOC (NULL);
+
+  unsigned int todo = 0;
+  basic_block bb;
+  rtx_insn *insn;
+  bool jcc_sibcall = false;
+
+  FOR_EACH_BB_FN (bb, cfun)
+    {
+      FOR_BB_INSNS (bb, insn)
+       {
+         if (!JUMP_P (insn))
+           continue;
+
+         if (INSN_CODE (insn) == CODE_FOR_jcc)
+           {
+             rtx label = JUMP_LABEL (insn);
+             rtx sibcall_target;
+             edge branch_edge = BRANCH_EDGE (bb);
+             basic_block branch_bb = branch_edge->dest;
+             sibcall_target = sibcall_only_bb (branch_bb,
+                                               jcc_sibcall_bbs);
+             if (sibcall_target)
+               {
+                 /* Decrement the label use count.  */
+                 LABEL_NUSES (label) -= 1;
+                 rtx set = pc_set (insn);
+                 rtx src = SET_SRC (set);
+                 /* Change the jcc code label to the sibcall target.
+                    Keep JUMP_LABEL points to the unused code label
+                    since it can only point to a code label, not a
+                    code symbol.  */
+                 XEXP (src, 1) = sibcall_target;
+                 branch_edge->flags &= ~EDGE_CAN_FALLTHRU;
+                 jcc_sibcall = true;
+               }
+           }
+       }
+    }
+
+  if (jcc_sibcall)
+    {
+      bitmap_iterator bi;
+      unsigned id;
+      EXECUTE_IF_SET_IN_BITMAP (jcc_sibcall_bbs, 0, id, bi)
+       {
+         bb = BASIC_BLOCK_FOR_FN (cfun, id);
+
+         bool reachable = false;
+         edge e;
+         edge_iterator ei;
+         FOR_EACH_EDGE (e, ei, bb->preds)
+           {
+             if (e->flags & EDGE_CAN_FALLTHRU)
+               {
+                 reachable = true;
+                 break;
+               }
+           }
+
+         if (!reachable)
+           {
+             /* Keep the basic block even if it isn't used since it is
+                required by RTL control flow check and the entry label
+                is still pointed to by JUMP_LABEL of the conditional
+                tailcall.  Instead, change the sibcall to the dummy
+                sibcall.  */
+             FOR_BB_INSNS (bb, insn)
+               {
+                 if (NONDEBUG_INSN_P (insn))
+                   break;
+               }
+
+             gcc_assert (insn
+                         && CALL_P (insn)
+                         && SIBLING_CALL_P (insn));
+
+             switch (INSN_CODE (insn))
+               {
+               case CODE_FOR_sibcall_di:
+                 INSN_CODE (insn) = CODE_FOR_sibcall_dummy_di;
+                 break;
+               case CODE_FOR_sibcall_si:
+                 INSN_CODE (insn) = CODE_FOR_sibcall_dummy_si;
+                 break;
+               case CODE_FOR_sibcall_value_di:
+                 INSN_CODE (insn) = CODE_FOR_sibcall_value_dummy_di;
+                 break;
+               case CODE_FOR_sibcall_value_si:
+                 INSN_CODE (insn) = CODE_FOR_sibcall_value_dummy_si;
+                 break;
+               case CODE_FOR_sibcall_pop:
+                 INSN_CODE (insn) = CODE_FOR_sibcall_pop_dummy;
+                 break;
+               case CODE_FOR_sibcall_value_pop:
+                 INSN_CODE (insn) = CODE_FOR_sibcall_value_pop_dummy;
+                 break;
+               default:
+                 gcc_unreachable ();
+               }
+           }
+       }
+    }
+
+  BITMAP_FREE (jcc_sibcall_bbs);
+  bitmap_obstack_release (NULL);
+
+  timevar_pop (TV_MACH_DEP);
+
+  return todo;
+}
+
+namespace {
+
+const pass_data pass_data_fold_sibcall =
+{
+  RTL_PASS, /* type */
+  "fold_tail", /* name */
+  OPTGROUP_NONE, /* optinfo_flags */
+  TV_MACH_DEP, /* tv_id */
+  0, /* properties_required */
+  0, /* properties_provided */
+  0, /* properties_destroyed */
+  0, /* todo_flags_start */
+  0, /* todo_flags_finish */
+};
+
+class pass_fold_sibcall : public rtl_opt_pass
+{
+public:
+  pass_fold_sibcall (gcc::context *ctxt)
+    : rtl_opt_pass (pass_data_fold_sibcall, ctxt)
+  {}
+
+  /* opt_pass methods: */
+  bool gate (function *) final override
+    {
+      return optimize;
+    }
+
+  unsigned int execute (function *) final override
+    {
+      return fold_sibcall ();
+    }
+
+  opt_pass *clone () final override
+    {
+      return new pass_fold_sibcall (m_ctxt);
+    }
+
+}; // class pass_remove_redundant_vector_load
+
+} // anon namespace
+
+rtl_opt_pass *
+make_pass_fold_sibcall (gcc::context *ctxt)
+{
+  return new pass_fold_sibcall (ctxt);
+}
+
 /* Convert legacy instructions that clobbers EFLAGS to APX_NF
    instructions when there are no flag set between a flag
    producer and user.  */
diff --git a/gcc/config/i386/i386-passes.def b/gcc/config/i386/i386-passes.def
index 39f8bc65ddc..5df0f3333ae 100644
--- a/gcc/config/i386/i386-passes.def
+++ b/gcc/config/i386/i386-passes.def
@@ -37,3 +37,4 @@ along with GCC; see the file COPYING3.  If not see
 
   INSERT_PASS_AFTER (pass_late_combine, 1, pass_remove_partial_avx_dependency);
   INSERT_PASS_AFTER (pass_rtl_ifcvt, 1, pass_apx_nf_convert);
+  INSERT_PASS_AFTER (pass_reorder_blocks, 1, pass_fold_sibcall);
diff --git a/gcc/config/i386/i386-protos.h b/gcc/config/i386/i386-protos.h
index bea3fd4b2e2..f578f05fcc4 100644
--- a/gcc/config/i386/i386-protos.h
+++ b/gcc/config/i386/i386-protos.h
@@ -373,6 +373,7 @@ extern enum attr_cpu ix86_schedule;
 
 extern bool ix86_nopic_noplt_attribute_p (rtx call_op);
 extern const char * ix86_output_call_insn (rtx_insn *insn, rtx call_op);
+extern const char * ix86_output_jcc_insn (rtx call_op);
 extern const char * ix86_output_indirect_jmp (rtx call_op);
 extern const char * ix86_output_function_return (bool long_p);
 extern const char * ix86_output_indirect_function_return (rtx ret_op);
@@ -427,6 +428,8 @@ extern rtl_opt_pass 
*make_pass_insert_endbr_and_patchable_area
   (gcc::context *);
 extern rtl_opt_pass *make_pass_remove_partial_avx_dependency
   (gcc::context *);
+extern rtl_opt_pass *make_pass_fold_sibcall
+  (gcc::context *);
 extern rtl_opt_pass *make_pass_apx_nf_convert (gcc::context *);
 extern rtl_opt_pass *make_pass_align_tight_loops (gcc::context *);
 
diff --git a/gcc/config/i386/i386.cc b/gcc/config/i386/i386.cc
index 3128973ba79..609fbe4bdb9 100644
--- a/gcc/config/i386/i386.cc
+++ b/gcc/config/i386/i386.cc
@@ -17238,6 +17238,18 @@ ix86_output_call_insn (rtx_insn *insn, rtx call_op)
 
   return "";
 }
+
+/* Output the assembly for a conditional jump instruction.  */
+
+const char *
+ix86_output_jcc_insn (rtx call_op)
+{
+  if (LABEL_P (call_op))
+    return "%!%+j%C1\t%l0";
+  else
+    return "%!%+j%C1\t%P0";
+}
+
 
 /* Return a MEM corresponding to a stack slot with mode MODE.
    Allocate a new slot if necessary.
diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md
index 8575fbf40fe..24498256c0c 100644
--- a/gcc/config/i386/i386.md
+++ b/gcc/config/i386/i386.md
@@ -19753,19 +19753,20 @@ (define_split
 
 ;; We ignore the overflow flag for signed branch instructions.
 
-(define_insn "*jcc"
+(define_insn "jcc"
   [(set (pc)
        (if_then_else (match_operator 1 "ix86_comparison_operator"
                                      [(reg FLAGS_REG) (const_int 0)])
-                     (label_ref (match_operand 0))
+              (match_operand 0 "symbol_label_operand")
                      (pc)))]
   ""
-  "%!%+j%C1\t%l0"
+  "* return ix86_output_jcc_insn (operands[0]);"
   [(set_attr "type" "ibr")
    (set_attr "modrm" "0")
    (set (attr "length")
        (if_then_else
-         (and (ge (minus (match_dup 0) (pc))
+         (and (match_test ("LABEL_P (operands[0])"))
+           (ge (minus (match_dup 0) (pc))
                   (const_int -126))
               (lt (minus (match_dup 0) (pc))
                   (const_int 128)))
@@ -20158,13 +20159,21 @@ (define_insn "*sibcall_GOT_32"
 }
   [(set_attr "type" "call")])
 
-(define_insn "*sibcall"
+(define_insn "sibcall_<mode>"
   [(call (mem:QI (match_operand:W 0 "sibcall_insn_operand" "UBsBz"))
         (match_operand 1))]
   "SIBLING_CALL_P (insn)"
   "* return ix86_output_call_insn (insn, operands[0]);"
   [(set_attr "type" "call")])
 
+;; A dummy sibcal used in an unreachable basic block.
+(define_insn "sibcall_dummy_<mode>"
+  [(call (mem:QI (match_operand:W 0 "sibcall_insn_operand" "UBsBz"))
+        (match_operand 1))]
+  "SIBLING_CALL_P (insn)"
+  ""
+  [(set_attr "length" "0")])
+
 (define_insn "*sibcall_memory"
   [(call (mem:QI (match_operand:W 0 "memory_operand" "m"))
         (match_operand 1))
@@ -20224,7 +20233,7 @@ (define_insn "*call_pop"
   "* return ix86_output_call_insn (insn, operands[0]);"
   [(set_attr "type" "call")])
 
-(define_insn "*sibcall_pop"
+(define_insn "sibcall_pop"
   [(call (mem:QI (match_operand:SI 0 "sibcall_insn_operand" "UBsBz"))
         (match_operand 1))
    (set (reg:SI SP_REG)
@@ -20234,6 +20243,17 @@ (define_insn "*sibcall_pop"
   "* return ix86_output_call_insn (insn, operands[0]);"
   [(set_attr "type" "call")])
 
+;; A dummy sibcal used in an unreachable basic block.
+(define_insn "sibcall_pop_dummy"
+  [(call (mem:QI (match_operand:SI 0 "sibcall_insn_operand" "UBsBz"))
+        (match_operand 1))
+   (set (reg:SI SP_REG)
+       (plus:SI (reg:SI SP_REG)
+                (match_operand:SI 2 "immediate_operand" "i")))]
+  "!TARGET_64BIT && SIBLING_CALL_P (insn)"
+  ""
+  [(set_attr "length" "0")])
+
 (define_insn "*sibcall_pop_memory"
   [(call (mem:QI (match_operand:SI 0 "memory_operand" "Bs"))
         (match_operand 1))
@@ -20360,7 +20380,7 @@ (define_insn "*sibcall_value_GOT_32"
 }
   [(set_attr "type" "callv")])
 
-(define_insn "*sibcall_value"
+(define_insn "sibcall_value_<mode>"
   [(set (match_operand 0)
        (call (mem:QI (match_operand:W 1 "sibcall_insn_operand" "UBsBz"))
              (match_operand 2)))]
@@ -20368,6 +20388,15 @@ (define_insn "*sibcall_value"
   "* return ix86_output_call_insn (insn, operands[1]);"
   [(set_attr "type" "callv")])
 
+;; A dummy sibcal used in an unreachable basic block.
+(define_insn "sibcall_value_dummy_<mode>"
+  [(set (match_operand 0)
+       (call (mem:QI (match_operand:W 1 "sibcall_insn_operand" "UBsBz"))
+             (match_operand 2)))]
+  "SIBLING_CALL_P (insn)"
+  ""
+  [(set_attr "length" "0")])
+
 (define_insn "*sibcall_value_memory"
   [(set (match_operand 0)
        (call (mem:QI (match_operand:W 1 "memory_operand" "m"))
@@ -20434,7 +20463,7 @@ (define_insn "*call_value_pop"
   "* return ix86_output_call_insn (insn, operands[1]);"
   [(set_attr "type" "callv")])
 
-(define_insn "*sibcall_value_pop"
+(define_insn "sibcall_value_pop"
   [(set (match_operand 0)
        (call (mem:QI (match_operand:SI 1 "sibcall_insn_operand" "UBsBz"))
              (match_operand 2)))
@@ -20445,6 +20474,18 @@ (define_insn "*sibcall_value_pop"
   "* return ix86_output_call_insn (insn, operands[1]);"
   [(set_attr "type" "callv")])
 
+;; A dummy sibcal used in an unreachable basic block.
+(define_insn "sibcall_value_pop_dummy"
+  [(set (match_operand 0)
+       (call (mem:QI (match_operand:SI 1 "sibcall_insn_operand" "UBsBz"))
+             (match_operand 2)))
+   (set (reg:SI SP_REG)
+       (plus:SI (reg:SI SP_REG)
+                (match_operand:SI 3 "immediate_operand" "i")))]
+  "!TARGET_64BIT && SIBLING_CALL_P (insn)"
+  ""
+  [(set_attr "length" "0")])
+
 (define_insn "*sibcall_value_pop_memory"
   [(set (match_operand 0)
        (call (mem:QI (match_operand:SI 1 "memory_operand" "m"))
diff --git a/gcc/config/i386/predicates.md b/gcc/config/i386/predicates.md
index 8631588f78e..4607e2172c7 100644
--- a/gcc/config/i386/predicates.md
+++ b/gcc/config/i386/predicates.md
@@ -768,6 +768,10 @@ (define_predicate "sibcall_memory_operand"
   return false;
 })
 
+;; Return true when operand is a symbol or label reference.
+(define_predicate "symbol_label_operand"
+  (match_code "symbol_ref,label_ref"))
+
 ;; Return true if OP is a GOT memory operand.
 (define_predicate "GOT_memory_operand"
   (and (match_operand 0 "memory_operand")
diff --git a/gcc/final.cc b/gcc/final.cc
index 12c6eb0ac09..5fb44433fb8 100644
--- a/gcc/final.cc
+++ b/gcc/final.cc
@@ -2390,6 +2390,10 @@ final_scan_insn_1 (rtx_insn *insn, FILE *file, int 
optimize_p ATTRIBUTE_UNUSED,
       break;
 
     case CODE_LABEL:
+      /* Skip the unused label.  */
+      if (LABEL_NUSES (insn) == 0)
+       break;
+
       /* The target port might emit labels in the output function for
         some insn, e.g. sh.cc output_branchy_insn.  */
       if (CODE_LABEL_NUMBER (insn) <= max_labelno)
diff --git a/gcc/testsuite/gcc.target/i386/pr47253-1a.c 
b/gcc/testsuite/gcc.target/i386/pr47253-1a.c
new file mode 100644
index 00000000000..7983f27f116
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr47253-1a.c
@@ -0,0 +1,24 @@
+/* { dg-do compile { target { *-*-linux* && { ! ia32 } } } } */
+/* { dg-options "-O2 -fpic -fplt" } */
+/* Keep labels and directives ('.cfi_startproc', '.cfi_endproc').  */
+/* { dg-final { check-function-bodies "**" "" "" { target "*-*-*" } {^\t?\.}  
} } */
+
+/*
+**func:
+**.LFB0:
+**     .cfi_startproc
+**     cmpl    \$1, %edi
+**     je      bar@PLT
+**     ret
+**     .cfi_endproc
+**...
+*/
+
+extern void bar (void);
+
+void
+func (int c)
+{
+  if (c == 1)
+    bar();
+}
diff --git a/gcc/testsuite/gcc.target/i386/pr47253-1b.c 
b/gcc/testsuite/gcc.target/i386/pr47253-1b.c
new file mode 100644
index 00000000000..c2198e06fd6
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr47253-1b.c
@@ -0,0 +1,17 @@
+/* { dg-do compile { target { *-*-linux* && ia32 } } } */
+/* { dg-options "-O2 -fno-pic -fplt" } */
+/* Keep labels and directives ('.cfi_startproc', '.cfi_endproc').  */
+/* { dg-final { check-function-bodies "**" "" "" { target "*-*-*" } {^\t?\.}  
} } */
+
+/*
+**func:
+**.LFB0:
+**     .cfi_startproc
+**     cmpl    \$1, 4\(%esp\)
+**     je      bar
+**     ret
+**     .cfi_endproc
+**...
+*/
+
+#include "pr47253-1a.c"
diff --git a/gcc/testsuite/gcc.target/i386/pr47253-2a.c 
b/gcc/testsuite/gcc.target/i386/pr47253-2a.c
new file mode 100644
index 00000000000..67162592186
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr47253-2a.c
@@ -0,0 +1,27 @@
+/* { dg-do compile { target { *-*-linux* && { ! ia32 } } } } */
+/* { dg-options "-O2 -fno-pic -fplt" } */
+/* Keep labels and directives ('.cfi_startproc', '.cfi_endproc').  */
+/* { dg-final { check-function-bodies "**" "" "" { target "*-*-*" } {^\t?\.}  
} } */
+
+/*
+**func:
+**.LFB0:
+**     .cfi_startproc
+**     testb   %dil, %dil
+**     je      f
+**     jmp     t
+**     .cfi_endproc
+**...
+*/
+
+extern void t(void);
+extern void f(void);
+ 
+void
+func(bool ok)
+{
+  if (ok)
+    t();
+  else
+    f();
+}
diff --git a/gcc/testsuite/gcc.target/i386/pr47253-2b.c 
b/gcc/testsuite/gcc.target/i386/pr47253-2b.c
new file mode 100644
index 00000000000..0096b0266fb
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr47253-2b.c
@@ -0,0 +1,17 @@
+/* { dg-do compile { target { *-*-linux* && ia32 } } } */
+/* { dg-options "-O2 -fno-pic -fplt" } */
+/* Keep labels and directives ('.cfi_startproc', '.cfi_endproc').  */
+/* { dg-final { check-function-bodies "**" "" "" { target "*-*-*" } {^\t?\.}  
} } */
+
+/*
+**func:
+**.LFB0:
+**     .cfi_startproc
+**     cmpb    \$0, 4\(%esp\)
+**     je      f
+**     jmp     t
+**     .cfi_endproc
+**...
+*/
+
+#include "pr47253-2a.c"
diff --git a/gcc/testsuite/gcc.target/i386/pr47253-3a.c 
b/gcc/testsuite/gcc.target/i386/pr47253-3a.c
new file mode 100644
index 00000000000..f920c95fb45
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr47253-3a.c
@@ -0,0 +1,32 @@
+/* { dg-do compile { target { *-*-linux* && lp64 } } } */
+/* { dg-options "-O2 -fno-pic -fplt" } */
+/* Keep labels and directives ('.cfi_startproc', '.cfi_endproc').  */
+/* { dg-final { check-function-bodies "**" "" "" { target "*-*-*" } {^\t?\.}  
} } */
+
+/*
+**func:
+**.LFB0:
+**     .cfi_startproc
+**     cmpl    \$1, %edi
+**     je      bar
+**     cmpl    \$2, %edi
+**     je      foo
+**     jmp     \*func_p\(%rip\)
+**     .cfi_endproc
+**...
+*/
+
+extern void bar(void);
+extern void foo(void);
+extern void (*func_p) (void);
+
+void
+func (int c)
+{
+  if (c == 1)
+    bar();
+  else if (c == 2)
+    foo();
+  else
+    func_p ();
+}
diff --git a/gcc/testsuite/gcc.target/i386/pr47253-3b.c 
b/gcc/testsuite/gcc.target/i386/pr47253-3b.c
new file mode 100644
index 00000000000..254b0c9145d
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr47253-3b.c
@@ -0,0 +1,20 @@
+/* { dg-do compile { target { *-*-linux* && ia32 } } } */
+/* { dg-options "-O2 -fno-pic -fplt" } */
+/* Keep labels and directives ('.cfi_startproc', '.cfi_endproc').  */
+/* { dg-final { check-function-bodies "**" "" "" { target "*-*-*" } {^\t?\.}  
} } */
+
+/*
+**func:
+**.LFB0:
+**     .cfi_startproc
+**     movl    4\(%esp\), %eax
+**     cmpl    \$1, %eax
+**     je      bar
+**     cmpl    \$2, %eax
+**     je      foo
+**     jmp     \*func_p
+**     .cfi_endproc
+**...
+*/
+
+#include "pr47253-3a.c"
diff --git a/gcc/testsuite/gcc.target/i386/pr47253-3c.c 
b/gcc/testsuite/gcc.target/i386/pr47253-3c.c
new file mode 100644
index 00000000000..4b67b19dbd5
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr47253-3c.c
@@ -0,0 +1,20 @@
+/* { dg-do compile { target { *-*-linux* && maybe_x32 } } } */
+/* { dg-options "-O2 -fno-pic -fplt -mx32" } */
+/* Keep labels and directives ('.cfi_startproc', '.cfi_endproc').  */
+/* { dg-final { check-function-bodies "**" "" "" { target "*-*-*" } {^\t?\.}  
} } */
+
+/*
+**func:
+**.LFB0:
+**     .cfi_startproc
+**     cmpl    \$1, %edi
+**     je      bar
+**     cmpl    \$2, %edi
+**     je      foo
+**     movl    func_p\(%rip\), %eax
+**     jmp     \*%rax
+**     .cfi_endproc
+**...
+*/
+
+#include "pr47253-3a.c"
diff --git a/gcc/testsuite/gcc.target/i386/pr47253-4a.c 
b/gcc/testsuite/gcc.target/i386/pr47253-4a.c
new file mode 100644
index 00000000000..1862d6297ac
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr47253-4a.c
@@ -0,0 +1,26 @@
+/* { dg-do compile { target { *-*-linux* && { ! ia32 } } } } */
+/* { dg-options "-O2 -fno-pic -fplt" } */
+/* Keep labels and directives ('.cfi_startproc', '.cfi_endproc').  */
+/* { dg-final { check-function-bodies "**" "" "" { target "*-*-*" } {^\t?\.}  
} } */
+
+/*
+**func:
+**.LFB0:
+**     .cfi_startproc
+**     cmpl    \$1, %edi
+**     je      bar
+**     movl    \$2, %eax
+**     ret
+**     .cfi_endproc
+**...
+*/
+
+extern int bar(void);
+
+int
+func (int c)
+{
+  if (c == 1)
+    return bar();
+  return 2;
+}
diff --git a/gcc/testsuite/gcc.target/i386/pr47253-4b.c 
b/gcc/testsuite/gcc.target/i386/pr47253-4b.c
new file mode 100644
index 00000000000..c489a77b15e
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr47253-4b.c
@@ -0,0 +1,18 @@
+/* { dg-do compile { target { *-*-linux* && ia32 } } } */
+/* { dg-options "-O2 -fno-pic -fplt" } */
+/* Keep labels and directives ('.cfi_startproc', '.cfi_endproc').  */
+/* { dg-final { check-function-bodies "**" "" "" { target "*-*-*" } {^\t?\.}  
} } */
+
+/*
+**func:
+**.LFB0:
+**     .cfi_startproc
+**     cmpl    \$1, 4\(%esp\)
+**     je      bar
+**     movl    \$2, %eax
+**     ret
+**     .cfi_endproc
+**...
+*/
+
+#include "pr47253-4a.c"
diff --git a/gcc/testsuite/gcc.target/i386/pr47253-5.c 
b/gcc/testsuite/gcc.target/i386/pr47253-5.c
new file mode 100644
index 00000000000..cf284d0659d
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr47253-5.c
@@ -0,0 +1,15 @@
+/* { dg-do compile { target *-*-linux* } } */
+/* { dg-options "-O2 -fpic -fno-plt" } */
+
+extern void bar (void);
+
+void
+func (int c)
+{
+  if (c == 1)
+    bar();
+}
+
+/* { dg-final { scan-assembler-not "jmp\[ \t\]bar" } } */
+/* { dg-final { scan-assembler "jmp\[ \t\]*.bar@GOTPCREL" { target { ! ia32 } 
} } } */
+/* { dg-final { scan-assembler "jmp\[ \t\]*.bar@GOT\\(" { target ia32 } } } */
diff --git a/gcc/testsuite/gcc.target/i386/pr47253-6.c 
b/gcc/testsuite/gcc.target/i386/pr47253-6.c
new file mode 100644
index 00000000000..e7aa9f25249
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr47253-6.c
@@ -0,0 +1,15 @@
+/* { dg-do compile { target *-*-linux* } } */
+/* { dg-options "-O2 -fno-pic -fno-plt" } */
+
+extern void bar (void);
+
+void
+func (int c)
+{
+  if (c == 1)
+    bar();
+}
+
+/* { dg-final { scan-assembler-not "jmp\[ \t\]bar" } } */
+/* { dg-final { scan-assembler "jmp\[ \t\]*.bar@GOTPCREL" { target { ! ia32 } 
} } } */
+/* { dg-final { scan-assembler "jmp\[ \t\]*.bar@GOT" { target ia32 } } } */
diff --git a/gcc/testsuite/gcc.target/i386/pr47253-7a.c 
b/gcc/testsuite/gcc.target/i386/pr47253-7a.c
new file mode 100644
index 00000000000..6e05ad3ec46
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr47253-7a.c
@@ -0,0 +1,52 @@
+/* { dg-do compile { target { *-*-linux* && lp64 } } } */
+/* { dg-options "-O2 -fno-pic -fplt" } */
+/* Keep labels and directives ('.cfi_startproc', '.cfi_endproc').  */
+/* { dg-final { check-function-bodies "**" "" "" { target "*-*-*" } {^\t?\.}  
} } */
+
+/*
+**func:
+**.LFB0:
+**     .cfi_startproc
+**     cmpl    \$1, %edi
+**     je      bar
+**     cmpl    \$2, %edi
+**     je      foo
+**     cmpl    \$3, %edi
+**     je      .L12
+**     cmpl    \$5, %edi
+**     je      .L13
+**     ret
+**...
+**.L12:
+**     jmp     \*func_p\(%rip\)
+**...
+**.L13:
+**     subq    \$8, %rsp
+**     .cfi_def_cfa_offset 16
+**     call    \*func_p\(%rip\)
+**     addq    \$8, %rsp
+**     .cfi_def_cfa_offset 8
+**     jmp     foo
+**     .cfi_endproc
+**...
+*/
+
+extern void bar(void);
+extern void foo(void);
+extern void (*func_p) (void);
+
+void
+func (int c)
+{
+  if (c == 1)
+    bar();
+  else if (c == 2)
+    foo();
+  else if (c == 3)
+    func_p ();
+  else if (c == 5)
+    {
+      func_p ();
+      foo ();
+    }
+}
diff --git a/gcc/testsuite/gcc.target/i386/pr47253-7b.c 
b/gcc/testsuite/gcc.target/i386/pr47253-7b.c
new file mode 100644
index 00000000000..fa58b5e5016
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr47253-7b.c
@@ -0,0 +1,36 @@
+/* { dg-do compile { target { *-*-linux* && maybe_x32 } } } */
+/* { dg-options "-O2 -fno-pic -fplt -mx32" } */
+/* Keep labels and directives ('.cfi_startproc', '.cfi_endproc').  */
+/* { dg-final { check-function-bodies "**" "" "" { target "*-*-*" } {^\t?\.}  
} } */
+
+/*
+**func:
+**.LFB0:
+**     .cfi_startproc
+**     cmpl    \$1, %edi
+**     je      bar
+**     cmpl    \$2, %edi
+**     je      foo
+**     cmpl    \$3, %edi
+**     je      .L12
+**     cmpl    \$5, %edi
+**     je      .L13
+**     ret
+**...
+**.L12:
+**     movl    func_p\(%rip\), %eax
+**     jmp     \*%rax
+**...
+**.L13:
+**     subl    \$8, %esp
+**     .cfi_def_cfa_offset 16
+**     movl    func_p\(%rip\), %eax
+**     call    \*%rax
+**     addl    \$8, %esp
+**     .cfi_def_cfa_offset 8
+**     jmp     foo
+**     .cfi_endproc
+**...
+*/
+
+#include "pr47253-7a.c"
-- 
2.48.1

Reply via email to