GCC6 cross compiler packages, based on the latest pmbootstrap aportgen code. Related: #103
457 lines
16 KiB
Diff
457 lines
16 KiB
Diff
From 771535dec733e4b85924f00a3a94c29683d614e5 Mon Sep 17 00:00:00 2001
|
|
From: hjl <hjl@138bc75d-0d04-0410-961f-82ee72b054a4>
|
|
Date: Mon, 26 Feb 2018 15:29:30 +0000
|
|
Subject: [PATCH 11/13] i386: Update -mfunction-return= for return with pop
|
|
|
|
When -mfunction-return= is used, simple_return_pop_internal should pop
|
|
return address into ECX register, adjust stack by bytes to pop from stack
|
|
and jump to the return thunk via ECX register.
|
|
|
|
Revision 257992 removed the bool argument from ix86_output_indirect_jmp.
|
|
Update comments to reflect it.
|
|
|
|
Tested on i686 and x86-64.
|
|
|
|
gcc/
|
|
|
|
Backport from mainline
|
|
2018-02-26 H.J. Lu <hongjiu.lu@intel.com>
|
|
|
|
* config/i386/i386.c (ix86_output_indirect_jmp): Update comments.
|
|
|
|
2018-02-26 H.J. Lu <hongjiu.lu@intel.com>
|
|
|
|
PR target/84530
|
|
* config/i386/i386-protos.h (ix86_output_indirect_jmp): Remove
|
|
the bool argument.
|
|
(ix86_output_indirect_function_return): New prototype.
|
|
(ix86_split_simple_return_pop_internal): Likewise.
|
|
* config/i386/i386.c (indirect_return_via_cx): New.
|
|
(indirect_return_via_cx_bnd): Likewise.
|
|
(indirect_thunk_name): Handle return va CX_REG.
|
|
(output_indirect_thunk_function): Create alias for
|
|
__x86_return_thunk_[re]cx and __x86_return_thunk_[re]cx_bnd.
|
|
(ix86_output_indirect_jmp): Remove the bool argument.
|
|
(ix86_output_indirect_function_return): New function.
|
|
(ix86_split_simple_return_pop_internal): Likewise.
|
|
* config/i386/i386.md (*indirect_jump): Don't pass false
|
|
to ix86_output_indirect_jmp.
|
|
(*tablejump_1): Likewise.
|
|
(simple_return_pop_internal): Change it to define_insn_and_split.
|
|
Call ix86_split_simple_return_pop_internal to split it for
|
|
-mfunction-return=.
|
|
(simple_return_indirect_internal): Call
|
|
ix86_output_indirect_function_return instead of
|
|
ix86_output_indirect_jmp.
|
|
|
|
gcc/testsuite/
|
|
|
|
Backport from mainline
|
|
2018-02-26 H.J. Lu <hongjiu.lu@intel.com>
|
|
|
|
PR target/84530
|
|
* gcc.target/i386/ret-thunk-22.c: New test.
|
|
* gcc.target/i386/ret-thunk-23.c: Likewise.
|
|
* gcc.target/i386/ret-thunk-24.c: Likewise.
|
|
* gcc.target/i386/ret-thunk-25.c: Likewise.
|
|
* gcc.target/i386/ret-thunk-26.c: Likewise.
|
|
---
|
|
gcc/config/i386/i386-protos.h | 4 +-
|
|
gcc/config/i386/i386.c | 127 +++++++++++++++++++++++----
|
|
gcc/config/i386/i386.md | 11 ++-
|
|
gcc/testsuite/gcc.target/i386/ret-thunk-22.c | 15 ++++
|
|
gcc/testsuite/gcc.target/i386/ret-thunk-23.c | 15 ++++
|
|
gcc/testsuite/gcc.target/i386/ret-thunk-24.c | 15 ++++
|
|
gcc/testsuite/gcc.target/i386/ret-thunk-25.c | 15 ++++
|
|
gcc/testsuite/gcc.target/i386/ret-thunk-26.c | 40 +++++++++
|
|
8 files changed, 222 insertions(+), 20 deletions(-)
|
|
create mode 100644 gcc/testsuite/gcc.target/i386/ret-thunk-22.c
|
|
create mode 100644 gcc/testsuite/gcc.target/i386/ret-thunk-23.c
|
|
create mode 100644 gcc/testsuite/gcc.target/i386/ret-thunk-24.c
|
|
create mode 100644 gcc/testsuite/gcc.target/i386/ret-thunk-25.c
|
|
create mode 100644 gcc/testsuite/gcc.target/i386/ret-thunk-26.c
|
|
|
|
diff --git a/gcc/config/i386/i386-protos.h b/gcc/config/i386/i386-protos.h
|
|
index 620d70ef9f6..c7a0ccb58d3 100644
|
|
--- a/gcc/config/i386/i386-protos.h
|
|
+++ b/gcc/config/i386/i386-protos.h
|
|
@@ -311,8 +311,10 @@ extern enum attr_cpu ix86_schedule;
|
|
#endif
|
|
|
|
extern const char * ix86_output_call_insn (rtx_insn *insn, rtx call_op);
|
|
-extern const char * ix86_output_indirect_jmp (rtx call_op, bool ret_p);
|
|
+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);
|
|
+extern void ix86_split_simple_return_pop_internal (rtx);
|
|
extern bool ix86_operands_ok_for_move_multiple (rtx *operands, bool load,
|
|
enum machine_mode mode);
|
|
|
|
diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
|
|
index 66502ee6da6..21c3c18bd3c 100644
|
|
--- a/gcc/config/i386/i386.c
|
|
+++ b/gcc/config/i386/i386.c
|
|
@@ -11080,6 +11080,12 @@ static int indirect_thunks_used;
|
|
by call and return thunks functions with the BND prefix. */
|
|
static int indirect_thunks_bnd_used;
|
|
|
|
+/* True if return thunk function via CX is needed. */
|
|
+static bool indirect_return_via_cx;
|
|
+/* True if return thunk function via CX with the BND prefix is
|
|
+ needed. */
|
|
+static bool indirect_return_via_cx_bnd;
|
|
+
|
|
#ifndef INDIRECT_LABEL
|
|
# define INDIRECT_LABEL "LIND"
|
|
#endif
|
|
@@ -11090,12 +11096,13 @@ static void
|
|
indirect_thunk_name (char name[32], unsigned int regno,
|
|
bool need_bnd_p, bool ret_p)
|
|
{
|
|
- if (regno != INVALID_REGNUM && ret_p)
|
|
+ if (regno != INVALID_REGNUM && regno != CX_REG && ret_p)
|
|
gcc_unreachable ();
|
|
|
|
if (USE_HIDDEN_LINKONCE)
|
|
{
|
|
const char *bnd = need_bnd_p ? "_bnd" : "";
|
|
+ const char *ret = ret_p ? "return" : "indirect";
|
|
if (regno != INVALID_REGNUM)
|
|
{
|
|
const char *reg_prefix;
|
|
@@ -11103,14 +11110,11 @@ indirect_thunk_name (char name[32], unsigned int regno,
|
|
reg_prefix = TARGET_64BIT ? "r" : "e";
|
|
else
|
|
reg_prefix = "";
|
|
- sprintf (name, "__x86_indirect_thunk%s_%s%s",
|
|
- bnd, reg_prefix, reg_names[regno]);
|
|
+ sprintf (name, "__x86_%s_thunk%s_%s%s",
|
|
+ ret, bnd, reg_prefix, reg_names[regno]);
|
|
}
|
|
else
|
|
- {
|
|
- const char *ret = ret_p ? "return" : "indirect";
|
|
- sprintf (name, "__x86_%s_thunk%s", ret, bnd);
|
|
- }
|
|
+ sprintf (name, "__x86_%s_thunk%s", ret, bnd);
|
|
}
|
|
else
|
|
{
|
|
@@ -11274,9 +11278,23 @@ output_indirect_thunk_function (bool need_bnd_p, unsigned int regno)
|
|
ASM_OUTPUT_LABEL (asm_out_file, name);
|
|
}
|
|
|
|
+ /* Create alias for __x86_return_thunk/__x86_return_thunk_bnd or
|
|
+ __x86_return_thunk_ecx/__x86_return_thunk_ecx_bnd. */
|
|
+ bool need_alias;
|
|
if (regno == INVALID_REGNUM)
|
|
+ need_alias = true;
|
|
+ else if (regno == CX_REG)
|
|
+ {
|
|
+ if (need_bnd_p)
|
|
+ need_alias = indirect_return_via_cx_bnd;
|
|
+ else
|
|
+ need_alias = indirect_return_via_cx;
|
|
+ }
|
|
+ else
|
|
+ need_alias = false;
|
|
+
|
|
+ if (need_alias)
|
|
{
|
|
- /* Create alias for __x86.return_thunk/__x86.return_thunk_bnd. */
|
|
char alias[32];
|
|
|
|
indirect_thunk_name (alias, regno, need_bnd_p, true);
|
|
@@ -28019,18 +28037,17 @@ ix86_output_indirect_branch (rtx call_op, const char *xasm,
|
|
else
|
|
ix86_output_indirect_branch_via_push (call_op, xasm, sibcall_p);
|
|
}
|
|
-/* Output indirect jump. CALL_OP is the jump target. Jump is a
|
|
- function return if RET_P is true. */
|
|
+
|
|
+/* Output indirect jump. CALL_OP is the jump target. */
|
|
|
|
const char *
|
|
-ix86_output_indirect_jmp (rtx call_op, bool ret_p)
|
|
+ix86_output_indirect_jmp (rtx call_op)
|
|
{
|
|
if (cfun->machine->indirect_branch_type != indirect_branch_keep)
|
|
{
|
|
- /* We can't have red-zone if this isn't a function return since
|
|
- "call" in the indirect thunk pushes the return address onto
|
|
- stack, destroying red-zone. */
|
|
- if (!ret_p && ix86_red_zone_size != 0)
|
|
+ /* We can't have red-zone since "call" in the indirect thunk
|
|
+ pushes the return address onto stack, destroying red-zone. */
|
|
+ if (ix86_red_zone_size != 0)
|
|
gcc_unreachable ();
|
|
|
|
ix86_output_indirect_branch (call_op, "%0", true);
|
|
@@ -28081,6 +28098,86 @@ ix86_output_function_return (bool long_p)
|
|
return "rep%; ret";
|
|
}
|
|
|
|
+/* Output indirect function return. RET_OP is the function return
|
|
+ target. */
|
|
+
|
|
+const char *
|
|
+ix86_output_indirect_function_return (rtx ret_op)
|
|
+{
|
|
+ if (cfun->machine->function_return_type != indirect_branch_keep)
|
|
+ {
|
|
+ char thunk_name[32];
|
|
+ bool need_bnd_p = ix86_bnd_prefixed_insn_p (current_output_insn);
|
|
+ unsigned int regno = REGNO (ret_op);
|
|
+ gcc_assert (regno == CX_REG);
|
|
+
|
|
+ if (cfun->machine->function_return_type
|
|
+ != indirect_branch_thunk_inline)
|
|
+ {
|
|
+ bool need_thunk = (cfun->machine->function_return_type
|
|
+ == indirect_branch_thunk);
|
|
+ indirect_thunk_name (thunk_name, regno, need_bnd_p, true);
|
|
+ if (need_bnd_p)
|
|
+ {
|
|
+ if (need_thunk)
|
|
+ {
|
|
+ indirect_return_via_cx_bnd = true;
|
|
+ indirect_thunks_bnd_used |= 1 << CX_REG;
|
|
+ }
|
|
+ fprintf (asm_out_file, "\tbnd jmp\t%s\n", thunk_name);
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ if (need_thunk)
|
|
+ {
|
|
+ indirect_return_via_cx = true;
|
|
+ indirect_thunks_used |= 1 << CX_REG;
|
|
+ }
|
|
+ fprintf (asm_out_file, "\tjmp\t%s\n", thunk_name);
|
|
+ }
|
|
+ }
|
|
+ else
|
|
+ output_indirect_thunk (need_bnd_p, regno);
|
|
+
|
|
+ return "";
|
|
+ }
|
|
+ else
|
|
+ return "%!jmp\t%A0";
|
|
+}
|
|
+
|
|
+/* Split simple return with popping POPC bytes from stack to indirect
|
|
+ branch with stack adjustment . */
|
|
+
|
|
+void
|
|
+ix86_split_simple_return_pop_internal (rtx popc)
|
|
+{
|
|
+ struct machine_function *m = cfun->machine;
|
|
+ rtx ecx = gen_rtx_REG (SImode, CX_REG);
|
|
+ rtx_insn *insn;
|
|
+
|
|
+ /* There is no "pascal" calling convention in any 64bit ABI. */
|
|
+ gcc_assert (!TARGET_64BIT);
|
|
+
|
|
+ insn = emit_insn (gen_pop (ecx));
|
|
+ m->fs.cfa_offset -= UNITS_PER_WORD;
|
|
+ m->fs.sp_offset -= UNITS_PER_WORD;
|
|
+
|
|
+ rtx x = plus_constant (Pmode, stack_pointer_rtx, UNITS_PER_WORD);
|
|
+ x = gen_rtx_SET (stack_pointer_rtx, x);
|
|
+ add_reg_note (insn, REG_CFA_ADJUST_CFA, x);
|
|
+ add_reg_note (insn, REG_CFA_REGISTER, gen_rtx_SET (ecx, pc_rtx));
|
|
+ RTX_FRAME_RELATED_P (insn) = 1;
|
|
+
|
|
+ x = gen_rtx_PLUS (Pmode, stack_pointer_rtx, popc);
|
|
+ x = gen_rtx_SET (stack_pointer_rtx, x);
|
|
+ insn = emit_insn (x);
|
|
+ add_reg_note (insn, REG_CFA_ADJUST_CFA, x);
|
|
+ RTX_FRAME_RELATED_P (insn) = 1;
|
|
+
|
|
+ /* Now return address is in ECX. */
|
|
+ emit_jump_insn (gen_simple_return_indirect_internal (ecx));
|
|
+}
|
|
+
|
|
/* Output the assembly for a call instruction. */
|
|
|
|
const char *
|
|
diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md
|
|
index 05a88fff356..857466a6361 100644
|
|
--- a/gcc/config/i386/i386.md
|
|
+++ b/gcc/config/i386/i386.md
|
|
@@ -11813,7 +11813,7 @@
|
|
(define_insn "*indirect_jump"
|
|
[(set (pc) (match_operand:W 0 "indirect_branch_operand" "rBw"))]
|
|
""
|
|
- "* return ix86_output_indirect_jmp (operands[0], false);"
|
|
+ "* return ix86_output_indirect_jmp (operands[0]);"
|
|
[(set (attr "type")
|
|
(if_then_else (match_test "(cfun->machine->indirect_branch_type
|
|
!= indirect_branch_keep)")
|
|
@@ -11868,7 +11868,7 @@
|
|
[(set (pc) (match_operand:W 0 "indirect_branch_operand" "rBw"))
|
|
(use (label_ref (match_operand 1)))]
|
|
""
|
|
- "* return ix86_output_indirect_jmp (operands[0], false);"
|
|
+ "* return ix86_output_indirect_jmp (operands[0]);"
|
|
[(set (attr "type")
|
|
(if_then_else (match_test "(cfun->machine->indirect_branch_type
|
|
!= indirect_branch_keep)")
|
|
@@ -12520,11 +12520,14 @@
|
|
(set_attr "prefix_rep" "1")
|
|
(set_attr "modrm" "0")])
|
|
|
|
-(define_insn "simple_return_pop_internal"
|
|
+(define_insn_and_split "simple_return_pop_internal"
|
|
[(simple_return)
|
|
(use (match_operand:SI 0 "const_int_operand"))]
|
|
"reload_completed"
|
|
"%!ret\t%0"
|
|
+ "&& cfun->machine->function_return_type != indirect_branch_keep"
|
|
+ [(const_int 0)]
|
|
+ "ix86_split_simple_return_pop_internal (operands[0]); DONE;"
|
|
[(set_attr "length" "3")
|
|
(set_attr "atom_unit" "jeu")
|
|
(set_attr "length_immediate" "2")
|
|
@@ -12535,7 +12538,7 @@
|
|
[(simple_return)
|
|
(use (match_operand:SI 0 "register_operand" "r"))]
|
|
"reload_completed"
|
|
- "* return ix86_output_indirect_jmp (operands[0], true);"
|
|
+ "* return ix86_output_indirect_function_return (operands[0]);"
|
|
[(set (attr "type")
|
|
(if_then_else (match_test "(cfun->machine->indirect_branch_type
|
|
!= indirect_branch_keep)")
|
|
diff --git a/gcc/testsuite/gcc.target/i386/ret-thunk-22.c b/gcc/testsuite/gcc.target/i386/ret-thunk-22.c
|
|
new file mode 100644
|
|
index 00000000000..89e086de97b
|
|
--- /dev/null
|
|
+++ b/gcc/testsuite/gcc.target/i386/ret-thunk-22.c
|
|
@@ -0,0 +1,15 @@
|
|
+/* PR target/r84530 */
|
|
+/* { dg-do compile { target ia32 } } */
|
|
+/* { dg-options "-O2 -mfunction-return=thunk" } */
|
|
+
|
|
+struct s { _Complex unsigned short x; };
|
|
+struct s gs = { 100 + 200i };
|
|
+struct s __attribute__((noinline)) foo (void) { return gs; }
|
|
+
|
|
+/* { dg-final { scan-assembler-times "popl\[\\t \]*%ecx" 1 } } */
|
|
+/* { dg-final { scan-assembler "lea\[l\]?\[\\t \]*4\\(%esp\\), %esp" } } */
|
|
+/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_return_thunk_ecx" } } */
|
|
+/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
|
|
+/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */
|
|
+/* { dg-final { scan-assembler {\tpause} } } */
|
|
+/* { dg-final { scan-assembler {\tlfence} } } */
|
|
diff --git a/gcc/testsuite/gcc.target/i386/ret-thunk-23.c b/gcc/testsuite/gcc.target/i386/ret-thunk-23.c
|
|
new file mode 100644
|
|
index 00000000000..43f0ccaa854
|
|
--- /dev/null
|
|
+++ b/gcc/testsuite/gcc.target/i386/ret-thunk-23.c
|
|
@@ -0,0 +1,15 @@
|
|
+/* PR target/r84530 */
|
|
+/* { dg-do compile { target ia32 } } */
|
|
+/* { dg-options "-O2 -mfunction-return=thunk-extern" } */
|
|
+
|
|
+struct s { _Complex unsigned short x; };
|
|
+struct s gs = { 100 + 200i };
|
|
+struct s __attribute__((noinline)) foo (void) { return gs; }
|
|
+
|
|
+/* { dg-final { scan-assembler-times "popl\[\\t \]*%ecx" 1 } } */
|
|
+/* { dg-final { scan-assembler "lea\[l\]?\[\\t \]*4\\(%esp\\), %esp" } } */
|
|
+/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_return_thunk_ecx" } } */
|
|
+/* { dg-final { scan-assembler-not "jmp\[ \t\]*\.LIND" } } */
|
|
+/* { dg-final { scan-assembler-not "call\[ \t\]*\.LIND" } } */
|
|
+/* { dg-final { scan-assembler-not {\tpause} } } */
|
|
+/* { dg-final { scan-assembler-not {\tlfence} } } */
|
|
diff --git a/gcc/testsuite/gcc.target/i386/ret-thunk-24.c b/gcc/testsuite/gcc.target/i386/ret-thunk-24.c
|
|
new file mode 100644
|
|
index 00000000000..8729e35147e
|
|
--- /dev/null
|
|
+++ b/gcc/testsuite/gcc.target/i386/ret-thunk-24.c
|
|
@@ -0,0 +1,15 @@
|
|
+/* PR target/r84530 */
|
|
+/* { dg-do compile { target ia32 } } */
|
|
+/* { dg-options "-O2 -mfunction-return=thunk-inline" } */
|
|
+
|
|
+struct s { _Complex unsigned short x; };
|
|
+struct s gs = { 100 + 200i };
|
|
+struct s __attribute__((noinline)) foo (void) { return gs; }
|
|
+
|
|
+/* { dg-final { scan-assembler-times "popl\[\\t \]*%ecx" 1 } } */
|
|
+/* { dg-final { scan-assembler "lea\[l\]?\[\\t \]*4\\(%esp\\), %esp" } } */
|
|
+/* { dg-final { scan-assembler-not "jmp\[ \t\]*__x86_return_thunk_ecx" } } */
|
|
+/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
|
|
+/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */
|
|
+/* { dg-final { scan-assembler {\tpause} } } */
|
|
+/* { dg-final { scan-assembler {\tlfence} } } */
|
|
diff --git a/gcc/testsuite/gcc.target/i386/ret-thunk-25.c b/gcc/testsuite/gcc.target/i386/ret-thunk-25.c
|
|
new file mode 100644
|
|
index 00000000000..f73553c9a9f
|
|
--- /dev/null
|
|
+++ b/gcc/testsuite/gcc.target/i386/ret-thunk-25.c
|
|
@@ -0,0 +1,15 @@
|
|
+/* PR target/r84530 */
|
|
+/* { dg-do compile { target ia32 } } */
|
|
+/* { dg-options "-O2 -mfunction-return=thunk -fcheck-pointer-bounds -mmpx -fno-pic" } */
|
|
+
|
|
+struct s { _Complex unsigned short x; };
|
|
+struct s gs = { 100 + 200i };
|
|
+struct s __attribute__((noinline)) foo (void) { return gs; }
|
|
+
|
|
+/* { dg-final { scan-assembler-times "popl\[\\t \]*%ecx" 1 } } */
|
|
+/* { dg-final { scan-assembler "lea\[l\]?\[\\t \]*4\\(%esp\\), %esp" } } */
|
|
+/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_return_thunk_bnd_ecx" } } */
|
|
+/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
|
|
+/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */
|
|
+/* { dg-final { scan-assembler {\tpause} } } */
|
|
+/* { dg-final { scan-assembler {\tlfence} } } */
|
|
diff --git a/gcc/testsuite/gcc.target/i386/ret-thunk-26.c b/gcc/testsuite/gcc.target/i386/ret-thunk-26.c
|
|
new file mode 100644
|
|
index 00000000000..9144e988735
|
|
--- /dev/null
|
|
+++ b/gcc/testsuite/gcc.target/i386/ret-thunk-26.c
|
|
@@ -0,0 +1,40 @@
|
|
+/* PR target/r84530 */
|
|
+/* { dg-do run } */
|
|
+/* { dg-options "-Os -mfunction-return=thunk" } */
|
|
+
|
|
+struct S { int i; };
|
|
+__attribute__((const, noinline, noclone))
|
|
+struct S foo (int x)
|
|
+{
|
|
+ struct S s;
|
|
+ s.i = x;
|
|
+ return s;
|
|
+}
|
|
+
|
|
+int a[2048], b[2048], c[2048], d[2048];
|
|
+struct S e[2048];
|
|
+
|
|
+__attribute__((noinline, noclone)) void
|
|
+bar (void)
|
|
+{
|
|
+ int i;
|
|
+ for (i = 0; i < 1024; i++)
|
|
+ {
|
|
+ e[i] = foo (i);
|
|
+ a[i+2] = a[i] + a[i+1];
|
|
+ b[10] = b[10] + i;
|
|
+ c[i] = c[2047 - i];
|
|
+ d[i] = d[i + 1];
|
|
+ }
|
|
+}
|
|
+
|
|
+int
|
|
+main ()
|
|
+{
|
|
+ int i;
|
|
+ bar ();
|
|
+ for (i = 0; i < 1024; i++)
|
|
+ if (e[i].i != i)
|
|
+ __builtin_abort ();
|
|
+ return 0;
|
|
+}
|
|
--
|
|
2.16.3
|
|
|