Blame SOURCES/gcc48-rh1537828-7.patch

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