Blame SOURCES/gcc48-rh1537828-7.patch

5ed81e
commit 4361c221ff4b53f585a2e8c0ba38956c8132609f
5ed81e
Author: hjl <hjl@138bc75d-0d04-0410-961f-82ee72b054a4>
5ed81e
Date:   Mon Feb 26 15:29:30 2018 +0000
5ed81e
5ed81e
    i386: Update -mfunction-return= for return with pop
5ed81e
    
5ed81e
    When -mfunction-return= is used, simple_return_pop_internal should pop
5ed81e
    return address into ECX register, adjust stack by bytes to pop from stack
5ed81e
    and jump to the return thunk via ECX register.
5ed81e
    
5ed81e
    Tested on i686 and x86-64.
5ed81e
    
5ed81e
            PR target/84530
5ed81e
            * config/i386/i386-protos.h (ix86_output_indirect_jmp): Remove
5ed81e
            the bool argument.
5ed81e
            (ix86_output_indirect_function_return): New prototype.
5ed81e
            (ix86_split_simple_return_pop_internal): Likewise.
5ed81e
            * config/i386/i386.c (indirect_return_via_cx): New.
5ed81e
            (indirect_return_via_cx_bnd): Likewise.
5ed81e
            (indirect_thunk_name): Handle return va CX_REG.
5ed81e
            (output_indirect_thunk_function): Create alias for
5ed81e
            __x86_return_thunk_[re]cx and __x86_return_thunk_[re]cx_bnd.
5ed81e
            (ix86_output_indirect_jmp): Remove the bool argument.
5ed81e
            (ix86_output_indirect_function_return): New function.
5ed81e
            (ix86_split_simple_return_pop_internal): Likewise.
5ed81e
            * config/i386/i386.md (*indirect_jump): Don't pass false
5ed81e
            to ix86_output_indirect_jmp.
5ed81e
            (*tablejump_1): Likewise.
5ed81e
            (simple_return_pop_internal): Change it to define_insn_and_split.
5ed81e
            Call ix86_split_simple_return_pop_internal to split it for
5ed81e
            -mfunction-return=.
5ed81e
            (simple_return_indirect_internal): Call
5ed81e
            ix86_output_indirect_function_return instead of
5ed81e
            ix86_output_indirect_jmp.
5ed81e
    
5ed81e
    gcc/testsuite/
5ed81e
    
5ed81e
            PR target/84530
5ed81e
            * gcc.target/i386/ret-thunk-22.c: New test.
5ed81e
            * gcc.target/i386/ret-thunk-23.c: Likewise.
5ed81e
            * gcc.target/i386/ret-thunk-24.c: Likewise.
5ed81e
            * gcc.target/i386/ret-thunk-25.c: Likewise.
5ed81e
            * gcc.target/i386/ret-thunk-26.c: Likewise.
5ed81e
    
5ed81e
    git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@257992 138bc75d-0d04-0410-961f-82ee72b054a4
5ed81e
5ed81e
diff --git a/gcc/config/i386/i386-protos.h b/gcc/config/i386/i386-protos.h
5ed81e
index 4e4b2100f79..394d4aebf96 100644
5ed81e
--- a/gcc/config/i386/i386-protos.h
5ed81e
+++ b/gcc/config/i386/i386-protos.h
5ed81e
@@ -306,8 +306,10 @@ extern enum attr_cpu ix86_schedule;
5ed81e
 #endif
5ed81e
 
5ed81e
 extern const char * ix86_output_call_insn (rtx insn, rtx call_op);
5ed81e
-extern const char * ix86_output_indirect_jmp (rtx call_op, bool ret_p);
5ed81e
+extern const char * ix86_output_indirect_jmp (rtx call_op);
5ed81e
 extern const char * ix86_output_function_return (bool long_p);
5ed81e
+extern const char * ix86_output_indirect_function_return (rtx ret_op);
5ed81e
+extern void ix86_split_simple_return_pop_internal (rtx);
5ed81e
 
5ed81e
 #ifdef RTX_CODE
5ed81e
 /* Target data for multipass lookahead scheduling.
5ed81e
diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
5ed81e
index c25d26ca826..a8238a001ee 100644
5ed81e
--- a/gcc/config/i386/i386.c
5ed81e
+++ b/gcc/config/i386/i386.c
5ed81e
@@ -8777,6 +8777,9 @@ static bool indirect_thunk_needed = false;
5ed81e
    by call and return thunks functions.  */
5ed81e
 static int indirect_thunks_used;
5ed81e
 
5ed81e
+/* True if return thunk function via CX is needed.  */
5ed81e
+static bool indirect_return_via_cx;
5ed81e
+
5ed81e
 #ifndef INDIRECT_LABEL
5ed81e
 # define INDIRECT_LABEL "LIND"
5ed81e
 #endif
5ed81e
@@ -8786,26 +8789,29 @@ static int indirect_thunks_used;
5ed81e
 static void
5ed81e
 indirect_thunk_name (char name[32], int regno, bool ret_p)
5ed81e
 {
5ed81e
-  if (regno >= 0 && ret_p)
5ed81e
+  if (regno != INVALID_REGNUM && regno != CX_REG && ret_p)
5ed81e
     gcc_unreachable ();
5ed81e
 
5ed81e
   if (USE_HIDDEN_LINKONCE)
5ed81e
     {
5ed81e
-      if (regno >= 0)
5ed81e
+      const char *prefix;
5ed81e
+
5ed81e
+      prefix = "";
5ed81e
+
5ed81e
+      const char *ret = ret_p ? "return" : "indirect";
5ed81e
+
5ed81e
+      if (regno != INVALID_REGNUM)
5ed81e
 	{
5ed81e
 	  const char *reg_prefix;
5ed81e
 	  if (LEGACY_INT_REGNO_P (regno))
5ed81e
 	    reg_prefix = TARGET_64BIT ? "r" : "e";
5ed81e
 	  else
5ed81e
 	    reg_prefix = "";
5ed81e
-	  sprintf (name, "__x86_indirect_thunk_%s%s",
5ed81e
-		   reg_prefix, reg_names[regno]);
5ed81e
+	  sprintf (name, "__x86_%s_thunk%s_%s%s",
5ed81e
+		   ret, prefix, reg_prefix, reg_names[regno]);
5ed81e
 	}
5ed81e
       else
5ed81e
-	{
5ed81e
-	  const char *ret = ret_p ? "return" : "indirect";
5ed81e
-	  sprintf (name, "__x86_%s_thunk", ret);
5ed81e
-	}
5ed81e
+	sprintf (name, "__x86_%s_thunk%s", ret, prefix);
5ed81e
     }
5ed81e
   else
5ed81e
     {
5ed81e
@@ -8947,9 +8953,18 @@ output_indirect_thunk_function (int regno)
5ed81e
 	ASM_OUTPUT_LABEL (asm_out_file, name);
5ed81e
       }
5ed81e
 
5ed81e
-  if (regno < 0)
5ed81e
+  /* Create alias for __x86_return_thunk or
5ed81e
+     __x86_return_thunk_ecx.  */
5ed81e
+  bool need_alias;
5ed81e
+  if (regno == INVALID_REGNUM)
5ed81e
+    need_alias = true;
5ed81e
+  else if (regno == CX_REG)
5ed81e
+    need_alias = indirect_return_via_cx;
5ed81e
+  else
5ed81e
+    need_alias = false;
5ed81e
+
5ed81e
+  if (need_alias)
5ed81e
     {
5ed81e
-      /* Create alias for __x86.return_thunk/__x86.return_thunk_bnd.  */
5ed81e
       char alias[32];
5ed81e
 
5ed81e
       indirect_thunk_name (alias, regno, true);
5ed81e
@@ -24704,21 +24719,21 @@ ix86_output_indirect_branch (rtx call_op, const char *xasm,
5ed81e
   else
5ed81e
     ix86_output_indirect_branch_via_push (call_op, xasm, sibcall_p);
5ed81e
 }
5ed81e
+
5ed81e
 /* Output indirect jump.  CALL_OP is the jump target.  Jump is a
5ed81e
    function return if RET_P is true.  */
5ed81e
 
5ed81e
 const char *
5ed81e
-ix86_output_indirect_jmp (rtx call_op, bool ret_p)
5ed81e
+ix86_output_indirect_jmp (rtx call_op)
5ed81e
 {
5ed81e
   if (cfun->machine->indirect_branch_type != indirect_branch_keep)
5ed81e
     {
5ed81e
       struct ix86_frame frame;
5ed81e
       ix86_compute_frame_layout (&frame);
5ed81e
 
5ed81e
-      /* We can't have red-zone if this isn't a function return since
5ed81e
-	 "call" in the indirect thunk pushes the return address onto
5ed81e
-	 stack, destroying red-zone.  */
5ed81e
-      if (!ret_p && frame.red_zone_size != 0)
5ed81e
+      /* We can't have red-zone since "call" in the indirect thunk
5ed81e
+	 pushes the return address onto the stack, destroying the red-zone.  */
5ed81e
+      if (frame.red_zone_size != 0)
5ed81e
 	gcc_unreachable ();
5ed81e
 
5ed81e
       ix86_output_indirect_branch (call_op, "%0", true);
5ed81e
@@ -24759,6 +24774,75 @@ ix86_output_function_return (bool long_p)
5ed81e
   return "rep%; ret";
5ed81e
 }
5ed81e
 
5ed81e
+/* Output indirect function return.  RET_OP is the function return
5ed81e
+   target.  */
5ed81e
+
5ed81e
+const char *
5ed81e
+ix86_output_indirect_function_return (rtx ret_op)
5ed81e
+{
5ed81e
+  if (cfun->machine->function_return_type != indirect_branch_keep)
5ed81e
+    {
5ed81e
+      char thunk_name[32];
5ed81e
+      enum indirect_thunk_prefix need_prefix
5ed81e
+	= indirect_thunk_need_prefix (current_output_insn);
5ed81e
+      unsigned int regno = REGNO (ret_op);
5ed81e
+      gcc_assert (regno == CX_REG);
5ed81e
+
5ed81e
+      if (cfun->machine->function_return_type
5ed81e
+	  != indirect_branch_thunk_inline)
5ed81e
+	{
5ed81e
+	  bool need_thunk = (cfun->machine->function_return_type
5ed81e
+			     == indirect_branch_thunk);
5ed81e
+	  indirect_thunk_name (thunk_name, regno, need_prefix, true);
5ed81e
+	  if (need_thunk)
5ed81e
+	    {
5ed81e
+	      indirect_return_via_cx = true;
5ed81e
+	      indirect_thunks_used |= 1 << CX_REG;
5ed81e
+	    }
5ed81e
+	  fprintf (asm_out_file, "\tjmp\t%s\n", thunk_name);
5ed81e
+	}
5ed81e
+      else
5ed81e
+	output_indirect_thunk (need_prefix, regno);
5ed81e
+
5ed81e
+      return "";
5ed81e
+    }
5ed81e
+  else
5ed81e
+    return "jmp\t%A0";
5ed81e
+}
5ed81e
+
5ed81e
+/* Split simple return with popping POPC bytes from stack to indirect
5ed81e
+   branch with stack adjustment .  */
5ed81e
+
5ed81e
+void
5ed81e
+ix86_split_simple_return_pop_internal (rtx popc)
5ed81e
+{
5ed81e
+  struct machine_function *m = cfun->machine;
5ed81e
+  rtx ecx = gen_rtx_REG (SImode, CX_REG);
5ed81e
+  rtx insn;
5ed81e
+
5ed81e
+  /* There is no "pascal" calling convention in any 64bit ABI.  */
5ed81e
+  gcc_assert (!TARGET_64BIT);
5ed81e
+
5ed81e
+  insn = emit_insn (gen_pop (ecx));
5ed81e
+  m->fs.cfa_offset -= UNITS_PER_WORD;
5ed81e
+  m->fs.sp_offset -= UNITS_PER_WORD;
5ed81e
+
5ed81e
+  rtx x = plus_constant (Pmode, stack_pointer_rtx, UNITS_PER_WORD);
5ed81e
+  x = gen_rtx_SET (VOIDmode, stack_pointer_rtx, x);
5ed81e
+  add_reg_note (insn, REG_CFA_ADJUST_CFA, x);
5ed81e
+  add_reg_note (insn, REG_CFA_REGISTER, gen_rtx_SET (VOIDmode, ecx, pc_rtx));
5ed81e
+  RTX_FRAME_RELATED_P (insn) = 1;
5ed81e
+
5ed81e
+  x = gen_rtx_PLUS (Pmode, stack_pointer_rtx, popc);
5ed81e
+  x = gen_rtx_SET (VOIDmode, stack_pointer_rtx, x);
5ed81e
+  insn = emit_insn (x);
5ed81e
+  add_reg_note (insn, REG_CFA_ADJUST_CFA, x);
5ed81e
+  RTX_FRAME_RELATED_P (insn) = 1;
5ed81e
+
5ed81e
+  /* Now return address is in ECX.  */
5ed81e
+  emit_jump_insn (gen_simple_return_indirect_internal (ecx));
5ed81e
+}
5ed81e
+
5ed81e
 /* Output the assembly for a call instruction.  */
5ed81e
 
5ed81e
 const char *
5ed81e
diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md
5ed81e
index 228f8f6d77a..3320ec233d2 100644
5ed81e
--- a/gcc/config/i386/i386.md
5ed81e
+++ b/gcc/config/i386/i386.md
5ed81e
@@ -11282,7 +11282,7 @@
5ed81e
 (define_insn "*indirect_jump"
5ed81e
   [(set (pc) (match_operand:W 0 "indirect_branch_operand" "rw"))]
5ed81e
   ""
5ed81e
-  "* return ix86_output_indirect_jmp (operands[0], false);"
5ed81e
+  "* return ix86_output_indirect_jmp (operands[0]);"
5ed81e
   [(set (attr "type")
5ed81e
      (if_then_else (match_test "(cfun->machine->indirect_branch_type
5ed81e
 				 != indirect_branch_keep)")
5ed81e
@@ -11336,7 +11336,7 @@
5ed81e
   [(set (pc) (match_operand:W 0 "indirect_branch_operand" "rw"))
5ed81e
    (use (label_ref (match_operand 1)))]
5ed81e
   ""
5ed81e
-  "* return ix86_output_indirect_jmp (operands[0], false);"
5ed81e
+  "* return ix86_output_indirect_jmp (operands[0]);"
5ed81e
   [(set (attr "type")
5ed81e
      (if_then_else (match_test "(cfun->machine->indirect_branch_type
5ed81e
 				 != indirect_branch_keep)")
5ed81e
@@ -11769,11 +11769,14 @@
5ed81e
    (set_attr "prefix_rep" "1")
5ed81e
    (set_attr "modrm" "0")])
5ed81e
 
5ed81e
-(define_insn "simple_return_pop_internal"
5ed81e
+(define_insn_and_split "simple_return_pop_internal"
5ed81e
   [(simple_return)
5ed81e
    (use (match_operand:SI 0 "const_int_operand"))]
5ed81e
   "reload_completed"
5ed81e
   "ret\t%0"
5ed81e
+  "&& cfun->machine->function_return_type != indirect_branch_keep"
5ed81e
+  [(const_int 0)]
5ed81e
+  "ix86_split_simple_return_pop_internal (operands[0]); DONE;"
5ed81e
   [(set_attr "length" "3")
5ed81e
    (set_attr "atom_unit" "jeu")
5ed81e
    (set_attr "length_immediate" "2")
5ed81e
@@ -11783,7 +11786,7 @@
5ed81e
   [(simple_return)
5ed81e
    (use (match_operand:SI 0 "register_operand" "r"))]
5ed81e
   "reload_completed"
5ed81e
-  "* return ix86_output_indirect_jmp (operands[0], true);"
5ed81e
+  "* return ix86_output_indirect_function_return (operands[0]);"
5ed81e
   [(set (attr "type")
5ed81e
      (if_then_else (match_test "(cfun->machine->indirect_branch_type
5ed81e
 				 != indirect_branch_keep)")
5ed81e
diff --git a/gcc/testsuite/gcc.target/i386/ret-thunk-22.c b/gcc/testsuite/gcc.target/i386/ret-thunk-22.c
5ed81e
new file mode 100644
5ed81e
index 00000000000..89e086de97b
5ed81e
--- /dev/null
5ed81e
+++ b/gcc/testsuite/gcc.target/i386/ret-thunk-22.c
5ed81e
@@ -0,0 +1,15 @@
5ed81e
+/* PR target/r84530 */
5ed81e
+/* { dg-do compile { target ia32 } } */
5ed81e
+/* { dg-options "-O2 -mfunction-return=thunk" } */
5ed81e
+
5ed81e
+struct s { _Complex unsigned short x; };
5ed81e
+struct s gs = { 100 + 200i };
5ed81e
+struct s __attribute__((noinline)) foo (void) { return gs; }
5ed81e
+
5ed81e
+/* { dg-final { scan-assembler-times "popl\[\\t \]*%ecx" 1 } } */
5ed81e
+/* { dg-final { scan-assembler "lea\[l\]?\[\\t \]*4\\(%esp\\), %esp" } } */
5ed81e
+/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_return_thunk_ecx" } } */
5ed81e
+/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
5ed81e
+/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */
5ed81e
+/* { dg-final { scan-assembler {\tpause} } } */
5ed81e
+/* { dg-final { scan-assembler {\tlfence} } } */
5ed81e
diff --git a/gcc/testsuite/gcc.target/i386/ret-thunk-23.c b/gcc/testsuite/gcc.target/i386/ret-thunk-23.c
5ed81e
new file mode 100644
5ed81e
index 00000000000..43f0ccaa854
5ed81e
--- /dev/null
5ed81e
+++ b/gcc/testsuite/gcc.target/i386/ret-thunk-23.c
5ed81e
@@ -0,0 +1,15 @@
5ed81e
+/* PR target/r84530 */
5ed81e
+/* { dg-do compile { target ia32 } } */
5ed81e
+/* { dg-options "-O2 -mfunction-return=thunk-extern" } */
5ed81e
+
5ed81e
+struct s { _Complex unsigned short x; };
5ed81e
+struct s gs = { 100 + 200i };
5ed81e
+struct s __attribute__((noinline)) foo (void) { return gs; }
5ed81e
+
5ed81e
+/* { dg-final { scan-assembler-times "popl\[\\t \]*%ecx" 1 } } */
5ed81e
+/* { dg-final { scan-assembler "lea\[l\]?\[\\t \]*4\\(%esp\\), %esp" } } */
5ed81e
+/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_return_thunk_ecx" } } */
5ed81e
+/* { dg-final { scan-assembler-not "jmp\[ \t\]*\.LIND" } } */
5ed81e
+/* { dg-final { scan-assembler-not "call\[ \t\]*\.LIND" } } */
5ed81e
+/* { dg-final { scan-assembler-not {\tpause} } } */
5ed81e
+/* { dg-final { scan-assembler-not {\tlfence} } } */
5ed81e
diff --git a/gcc/testsuite/gcc.target/i386/ret-thunk-24.c b/gcc/testsuite/gcc.target/i386/ret-thunk-24.c
5ed81e
new file mode 100644
5ed81e
index 00000000000..8729e35147e
5ed81e
--- /dev/null
5ed81e
+++ b/gcc/testsuite/gcc.target/i386/ret-thunk-24.c
5ed81e
@@ -0,0 +1,15 @@
5ed81e
+/* PR target/r84530 */
5ed81e
+/* { dg-do compile { target ia32 } } */
5ed81e
+/* { dg-options "-O2 -mfunction-return=thunk-inline" } */
5ed81e
+
5ed81e
+struct s { _Complex unsigned short x; };
5ed81e
+struct s gs = { 100 + 200i };
5ed81e
+struct s __attribute__((noinline)) foo (void) { return gs; }
5ed81e
+
5ed81e
+/* { dg-final { scan-assembler-times "popl\[\\t \]*%ecx" 1 } } */
5ed81e
+/* { dg-final { scan-assembler "lea\[l\]?\[\\t \]*4\\(%esp\\), %esp" } } */
5ed81e
+/* { dg-final { scan-assembler-not "jmp\[ \t\]*__x86_return_thunk_ecx" } } */
5ed81e
+/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
5ed81e
+/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */
5ed81e
+/* { dg-final { scan-assembler {\tpause} } } */
5ed81e
+/* { dg-final { scan-assembler {\tlfence} } } */
5ed81e
diff --git a/gcc/testsuite/gcc.target/i386/ret-thunk-25.c b/gcc/testsuite/gcc.target/i386/ret-thunk-25.c
5ed81e
new file mode 100644
5ed81e
index 00000000000..f73553c9a9f
5ed81e
--- /dev/null
5ed81e
+++ b/gcc/testsuite/gcc.target/i386/ret-thunk-25.c
5ed81e
@@ -0,0 +1,14 @@
5ed81e
+/* PR target/r84530 */
5ed81e
+/* { dg-do compile { target ia32 } } */
5ed81e
+/* { dg-options "-O2 -mfunction-return=thunk -fno-pic" } */
5ed81e
+
5ed81e
+struct s { _Complex unsigned short x; };
5ed81e
+struct s gs = { 100 + 200i };
5ed81e
+struct s __attribute__((noinline)) foo (void) { return gs; }
5ed81e
+
5ed81e
+/* { dg-final { scan-assembler-times "popl\[\\t \]*%ecx" 1 } } */
5ed81e
+/* { dg-final { scan-assembler "lea\[l\]?\[\\t \]*4\\(%esp\\), %esp" } } */
5ed81e
+/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
5ed81e
+/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */
5ed81e
+/* { dg-final { scan-assembler {\tpause} } } */
5ed81e
+/* { dg-final { scan-assembler {\tlfence} } } */
5ed81e
diff --git a/gcc/testsuite/gcc.target/i386/ret-thunk-26.c b/gcc/testsuite/gcc.target/i386/ret-thunk-26.c
5ed81e
new file mode 100644
5ed81e
index 00000000000..9144e988735
5ed81e
--- /dev/null
5ed81e
+++ b/gcc/testsuite/gcc.target/i386/ret-thunk-26.c
5ed81e
@@ -0,0 +1,40 @@
5ed81e
+/* PR target/r84530 */
5ed81e
+/* { dg-do run } */
5ed81e
+/* { dg-options "-Os -mfunction-return=thunk" } */
5ed81e
+
5ed81e
+struct S { int i; };
5ed81e
+__attribute__((const, noinline, noclone))
5ed81e
+struct S foo (int x)
5ed81e
+{
5ed81e
+  struct S s;
5ed81e
+  s.i = x;
5ed81e
+  return s;
5ed81e
+}
5ed81e
+
5ed81e
+int a[2048], b[2048], c[2048], d[2048];
5ed81e
+struct S e[2048];
5ed81e
+
5ed81e
+__attribute__((noinline, noclone)) void
5ed81e
+bar (void)
5ed81e
+{
5ed81e
+  int i;
5ed81e
+  for (i = 0; i < 1024; i++)
5ed81e
+    {
5ed81e
+      e[i] = foo (i);
5ed81e
+      a[i+2] = a[i] + a[i+1];
5ed81e
+      b[10] = b[10] + i;
5ed81e
+      c[i] = c[2047 - i];
5ed81e
+      d[i] = d[i + 1];
5ed81e
+    }
5ed81e
+}
5ed81e
+
5ed81e
+int
5ed81e
+main ()
5ed81e
+{
5ed81e
+  int i;
5ed81e
+  bar ();
5ed81e
+  for (i = 0; i < 1024; i++)
5ed81e
+    if (e[i].i != i)
5ed81e
+      __builtin_abort ();
5ed81e
+  return 0;
5ed81e
+}