Blame SOURCES/gcc48-rh1537828-7.patch

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