summaryrefslogtreecommitdiffstats
path: root/meta/recipes-devtools/gcc/gcc-6.4/backport/0011-i386-Update-mfunction-return-for-return-with-pop.patch
diff options
context:
space:
mode:
Diffstat (limited to 'meta/recipes-devtools/gcc/gcc-6.4/backport/0011-i386-Update-mfunction-return-for-return-with-pop.patch')
-rw-r--r--meta/recipes-devtools/gcc/gcc-6.4/backport/0011-i386-Update-mfunction-return-for-return-with-pop.patch453
1 files changed, 453 insertions, 0 deletions
diff --git a/meta/recipes-devtools/gcc/gcc-6.4/backport/0011-i386-Update-mfunction-return-for-return-with-pop.patch b/meta/recipes-devtools/gcc/gcc-6.4/backport/0011-i386-Update-mfunction-return-for-return-with-pop.patch
new file mode 100644
index 0000000000..3b036fbe18
--- /dev/null
+++ b/meta/recipes-devtools/gcc/gcc-6.4/backport/0011-i386-Update-mfunction-return-for-return-with-pop.patch
@@ -0,0 +1,453 @@
1From b3a2269c7884378a9afd394ac7e669aab0443b57 Mon Sep 17 00:00:00 2001
2From: hjl <hjl@138bc75d-0d04-0410-961f-82ee72b054a4>
3Date: Mon, 26 Feb 2018 15:29:30 +0000
4Subject: [PATCH 11/12] i386: Update -mfunction-return= for return with pop
5
6When -mfunction-return= is used, simple_return_pop_internal should pop
7return address into ECX register, adjust stack by bytes to pop from stack
8and jump to the return thunk via ECX register.
9
10Revision 257992 removed the bool argument from ix86_output_indirect_jmp.
11Update comments to reflect it.
12
13Tested on i686 and x86-64.
14
15 Backport from mainline
16 * config/i386/i386.c (ix86_output_indirect_jmp): Update comments.
17
18 PR target/84530
19 * config/i386/i386-protos.h (ix86_output_indirect_jmp): Remove
20 the bool argument.
21 (ix86_output_indirect_function_return): New prototype.
22 (ix86_split_simple_return_pop_internal): Likewise.
23 * config/i386/i386.c (indirect_return_via_cx): New.
24 (indirect_return_via_cx_bnd): Likewise.
25 (indirect_thunk_name): Handle return va CX_REG.
26 (output_indirect_thunk_function): Create alias for
27 __x86_return_thunk_[re]cx and __x86_return_thunk_[re]cx_bnd.
28 (ix86_output_indirect_jmp): Remove the bool argument.
29 (ix86_output_indirect_function_return): New function.
30 (ix86_split_simple_return_pop_internal): Likewise.
31 * config/i386/i386.md (*indirect_jump): Don't pass false
32 to ix86_output_indirect_jmp.
33 (*tablejump_1): Likewise.
34 (simple_return_pop_internal): Change it to define_insn_and_split.
35 Call ix86_split_simple_return_pop_internal to split it for
36 -mfunction-return=.
37 (simple_return_indirect_internal): Call
38 ix86_output_indirect_function_return instead of
39 ix86_output_indirect_jmp.
40
41gcc/testsuite/
42
43 Backport from mainline
44 PR target/84530
45 * gcc.target/i386/ret-thunk-22.c: New test.
46 * gcc.target/i386/ret-thunk-23.c: Likewise.
47 * gcc.target/i386/ret-thunk-24.c: Likewise.
48 * gcc.target/i386/ret-thunk-25.c: Likewise.
49 * gcc.target/i386/ret-thunk-26.c: Likewise.
50
51Upstream-Status: Pending
52
53Signed-off-by: Juro Bystricky <juro.bystricky@intel.com>
54
55---
56 gcc/config/i386/i386-protos.h | 4 +-
57 gcc/config/i386/i386.c | 127 +++++++++++++++++++++++----
58 gcc/config/i386/i386.md | 11 ++-
59 gcc/testsuite/gcc.target/i386/ret-thunk-22.c | 15 ++++
60 gcc/testsuite/gcc.target/i386/ret-thunk-23.c | 15 ++++
61 gcc/testsuite/gcc.target/i386/ret-thunk-24.c | 15 ++++
62 gcc/testsuite/gcc.target/i386/ret-thunk-25.c | 15 ++++
63 gcc/testsuite/gcc.target/i386/ret-thunk-26.c | 40 +++++++++
64 8 files changed, 222 insertions(+), 20 deletions(-)
65 create mode 100644 gcc/testsuite/gcc.target/i386/ret-thunk-22.c
66 create mode 100644 gcc/testsuite/gcc.target/i386/ret-thunk-23.c
67 create mode 100644 gcc/testsuite/gcc.target/i386/ret-thunk-24.c
68 create mode 100644 gcc/testsuite/gcc.target/i386/ret-thunk-25.c
69 create mode 100644 gcc/testsuite/gcc.target/i386/ret-thunk-26.c
70
71diff --git a/gcc/config/i386/i386-protos.h b/gcc/config/i386/i386-protos.h
72index 620d70e..c7a0ccb5 100644
73--- a/gcc/config/i386/i386-protos.h
74+++ b/gcc/config/i386/i386-protos.h
75@@ -311,8 +311,10 @@ extern enum attr_cpu ix86_schedule;
76 #endif
77
78 extern const char * ix86_output_call_insn (rtx_insn *insn, rtx call_op);
79-extern const char * ix86_output_indirect_jmp (rtx call_op, bool ret_p);
80+extern const char * ix86_output_indirect_jmp (rtx call_op);
81 extern const char * ix86_output_function_return (bool long_p);
82+extern const char * ix86_output_indirect_function_return (rtx ret_op);
83+extern void ix86_split_simple_return_pop_internal (rtx);
84 extern bool ix86_operands_ok_for_move_multiple (rtx *operands, bool load,
85 enum machine_mode mode);
86
87diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
88index 66502ee..21c3c18 100644
89--- a/gcc/config/i386/i386.c
90+++ b/gcc/config/i386/i386.c
91@@ -11080,6 +11080,12 @@ static int indirect_thunks_used;
92 by call and return thunks functions with the BND prefix. */
93 static int indirect_thunks_bnd_used;
94
95+/* True if return thunk function via CX is needed. */
96+static bool indirect_return_via_cx;
97+/* True if return thunk function via CX with the BND prefix is
98+ needed. */
99+static bool indirect_return_via_cx_bnd;
100+
101 #ifndef INDIRECT_LABEL
102 # define INDIRECT_LABEL "LIND"
103 #endif
104@@ -11090,12 +11096,13 @@ static void
105 indirect_thunk_name (char name[32], unsigned int regno,
106 bool need_bnd_p, bool ret_p)
107 {
108- if (regno != INVALID_REGNUM && ret_p)
109+ if (regno != INVALID_REGNUM && regno != CX_REG && ret_p)
110 gcc_unreachable ();
111
112 if (USE_HIDDEN_LINKONCE)
113 {
114 const char *bnd = need_bnd_p ? "_bnd" : "";
115+ const char *ret = ret_p ? "return" : "indirect";
116 if (regno != INVALID_REGNUM)
117 {
118 const char *reg_prefix;
119@@ -11103,14 +11110,11 @@ indirect_thunk_name (char name[32], unsigned int regno,
120 reg_prefix = TARGET_64BIT ? "r" : "e";
121 else
122 reg_prefix = "";
123- sprintf (name, "__x86_indirect_thunk%s_%s%s",
124- bnd, reg_prefix, reg_names[regno]);
125+ sprintf (name, "__x86_%s_thunk%s_%s%s",
126+ ret, bnd, reg_prefix, reg_names[regno]);
127 }
128 else
129- {
130- const char *ret = ret_p ? "return" : "indirect";
131- sprintf (name, "__x86_%s_thunk%s", ret, bnd);
132- }
133+ sprintf (name, "__x86_%s_thunk%s", ret, bnd);
134 }
135 else
136 {
137@@ -11274,9 +11278,23 @@ output_indirect_thunk_function (bool need_bnd_p, unsigned int regno)
138 ASM_OUTPUT_LABEL (asm_out_file, name);
139 }
140
141+ /* Create alias for __x86_return_thunk/__x86_return_thunk_bnd or
142+ __x86_return_thunk_ecx/__x86_return_thunk_ecx_bnd. */
143+ bool need_alias;
144 if (regno == INVALID_REGNUM)
145+ need_alias = true;
146+ else if (regno == CX_REG)
147+ {
148+ if (need_bnd_p)
149+ need_alias = indirect_return_via_cx_bnd;
150+ else
151+ need_alias = indirect_return_via_cx;
152+ }
153+ else
154+ need_alias = false;
155+
156+ if (need_alias)
157 {
158- /* Create alias for __x86.return_thunk/__x86.return_thunk_bnd. */
159 char alias[32];
160
161 indirect_thunk_name (alias, regno, need_bnd_p, true);
162@@ -28019,18 +28037,17 @@ ix86_output_indirect_branch (rtx call_op, const char *xasm,
163 else
164 ix86_output_indirect_branch_via_push (call_op, xasm, sibcall_p);
165 }
166-/* Output indirect jump. CALL_OP is the jump target. Jump is a
167- function return if RET_P is true. */
168+
169+/* Output indirect jump. CALL_OP is the jump target. */
170
171 const char *
172-ix86_output_indirect_jmp (rtx call_op, bool ret_p)
173+ix86_output_indirect_jmp (rtx call_op)
174 {
175 if (cfun->machine->indirect_branch_type != indirect_branch_keep)
176 {
177- /* We can't have red-zone if this isn't a function return since
178- "call" in the indirect thunk pushes the return address onto
179- stack, destroying red-zone. */
180- if (!ret_p && ix86_red_zone_size != 0)
181+ /* We can't have red-zone since "call" in the indirect thunk
182+ pushes the return address onto stack, destroying red-zone. */
183+ if (ix86_red_zone_size != 0)
184 gcc_unreachable ();
185
186 ix86_output_indirect_branch (call_op, "%0", true);
187@@ -28081,6 +28098,86 @@ ix86_output_function_return (bool long_p)
188 return "rep%; ret";
189 }
190
191+/* Output indirect function return. RET_OP is the function return
192+ target. */
193+
194+const char *
195+ix86_output_indirect_function_return (rtx ret_op)
196+{
197+ if (cfun->machine->function_return_type != indirect_branch_keep)
198+ {
199+ char thunk_name[32];
200+ bool need_bnd_p = ix86_bnd_prefixed_insn_p (current_output_insn);
201+ unsigned int regno = REGNO (ret_op);
202+ gcc_assert (regno == CX_REG);
203+
204+ if (cfun->machine->function_return_type
205+ != indirect_branch_thunk_inline)
206+ {
207+ bool need_thunk = (cfun->machine->function_return_type
208+ == indirect_branch_thunk);
209+ indirect_thunk_name (thunk_name, regno, need_bnd_p, true);
210+ if (need_bnd_p)
211+ {
212+ if (need_thunk)
213+ {
214+ indirect_return_via_cx_bnd = true;
215+ indirect_thunks_bnd_used |= 1 << CX_REG;
216+ }
217+ fprintf (asm_out_file, "\tbnd jmp\t%s\n", thunk_name);
218+ }
219+ else
220+ {
221+ if (need_thunk)
222+ {
223+ indirect_return_via_cx = true;
224+ indirect_thunks_used |= 1 << CX_REG;
225+ }
226+ fprintf (asm_out_file, "\tjmp\t%s\n", thunk_name);
227+ }
228+ }
229+ else
230+ output_indirect_thunk (need_bnd_p, regno);
231+
232+ return "";
233+ }
234+ else
235+ return "%!jmp\t%A0";
236+}
237+
238+/* Split simple return with popping POPC bytes from stack to indirect
239+ branch with stack adjustment . */
240+
241+void
242+ix86_split_simple_return_pop_internal (rtx popc)
243+{
244+ struct machine_function *m = cfun->machine;
245+ rtx ecx = gen_rtx_REG (SImode, CX_REG);
246+ rtx_insn *insn;
247+
248+ /* There is no "pascal" calling convention in any 64bit ABI. */
249+ gcc_assert (!TARGET_64BIT);
250+
251+ insn = emit_insn (gen_pop (ecx));
252+ m->fs.cfa_offset -= UNITS_PER_WORD;
253+ m->fs.sp_offset -= UNITS_PER_WORD;
254+
255+ rtx x = plus_constant (Pmode, stack_pointer_rtx, UNITS_PER_WORD);
256+ x = gen_rtx_SET (stack_pointer_rtx, x);
257+ add_reg_note (insn, REG_CFA_ADJUST_CFA, x);
258+ add_reg_note (insn, REG_CFA_REGISTER, gen_rtx_SET (ecx, pc_rtx));
259+ RTX_FRAME_RELATED_P (insn) = 1;
260+
261+ x = gen_rtx_PLUS (Pmode, stack_pointer_rtx, popc);
262+ x = gen_rtx_SET (stack_pointer_rtx, x);
263+ insn = emit_insn (x);
264+ add_reg_note (insn, REG_CFA_ADJUST_CFA, x);
265+ RTX_FRAME_RELATED_P (insn) = 1;
266+
267+ /* Now return address is in ECX. */
268+ emit_jump_insn (gen_simple_return_indirect_internal (ecx));
269+}
270+
271 /* Output the assembly for a call instruction. */
272
273 const char *
274diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md
275index 05a88ff..857466a 100644
276--- a/gcc/config/i386/i386.md
277+++ b/gcc/config/i386/i386.md
278@@ -11813,7 +11813,7 @@
279 (define_insn "*indirect_jump"
280 [(set (pc) (match_operand:W 0 "indirect_branch_operand" "rBw"))]
281 ""
282- "* return ix86_output_indirect_jmp (operands[0], false);"
283+ "* return ix86_output_indirect_jmp (operands[0]);"
284 [(set (attr "type")
285 (if_then_else (match_test "(cfun->machine->indirect_branch_type
286 != indirect_branch_keep)")
287@@ -11868,7 +11868,7 @@
288 [(set (pc) (match_operand:W 0 "indirect_branch_operand" "rBw"))
289 (use (label_ref (match_operand 1)))]
290 ""
291- "* return ix86_output_indirect_jmp (operands[0], false);"
292+ "* return ix86_output_indirect_jmp (operands[0]);"
293 [(set (attr "type")
294 (if_then_else (match_test "(cfun->machine->indirect_branch_type
295 != indirect_branch_keep)")
296@@ -12520,11 +12520,14 @@
297 (set_attr "prefix_rep" "1")
298 (set_attr "modrm" "0")])
299
300-(define_insn "simple_return_pop_internal"
301+(define_insn_and_split "simple_return_pop_internal"
302 [(simple_return)
303 (use (match_operand:SI 0 "const_int_operand"))]
304 "reload_completed"
305 "%!ret\t%0"
306+ "&& cfun->machine->function_return_type != indirect_branch_keep"
307+ [(const_int 0)]
308+ "ix86_split_simple_return_pop_internal (operands[0]); DONE;"
309 [(set_attr "length" "3")
310 (set_attr "atom_unit" "jeu")
311 (set_attr "length_immediate" "2")
312@@ -12535,7 +12538,7 @@
313 [(simple_return)
314 (use (match_operand:SI 0 "register_operand" "r"))]
315 "reload_completed"
316- "* return ix86_output_indirect_jmp (operands[0], true);"
317+ "* return ix86_output_indirect_function_return (operands[0]);"
318 [(set (attr "type")
319 (if_then_else (match_test "(cfun->machine->indirect_branch_type
320 != indirect_branch_keep)")
321diff --git a/gcc/testsuite/gcc.target/i386/ret-thunk-22.c b/gcc/testsuite/gcc.target/i386/ret-thunk-22.c
322new file mode 100644
323index 0000000..89e086d
324--- /dev/null
325+++ b/gcc/testsuite/gcc.target/i386/ret-thunk-22.c
326@@ -0,0 +1,15 @@
327+/* PR target/r84530 */
328+/* { dg-do compile { target ia32 } } */
329+/* { dg-options "-O2 -mfunction-return=thunk" } */
330+
331+struct s { _Complex unsigned short x; };
332+struct s gs = { 100 + 200i };
333+struct s __attribute__((noinline)) foo (void) { return gs; }
334+
335+/* { dg-final { scan-assembler-times "popl\[\\t \]*%ecx" 1 } } */
336+/* { dg-final { scan-assembler "lea\[l\]?\[\\t \]*4\\(%esp\\), %esp" } } */
337+/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_return_thunk_ecx" } } */
338+/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
339+/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */
340+/* { dg-final { scan-assembler {\tpause} } } */
341+/* { dg-final { scan-assembler {\tlfence} } } */
342diff --git a/gcc/testsuite/gcc.target/i386/ret-thunk-23.c b/gcc/testsuite/gcc.target/i386/ret-thunk-23.c
343new file mode 100644
344index 0000000..43f0cca
345--- /dev/null
346+++ b/gcc/testsuite/gcc.target/i386/ret-thunk-23.c
347@@ -0,0 +1,15 @@
348+/* PR target/r84530 */
349+/* { dg-do compile { target ia32 } } */
350+/* { dg-options "-O2 -mfunction-return=thunk-extern" } */
351+
352+struct s { _Complex unsigned short x; };
353+struct s gs = { 100 + 200i };
354+struct s __attribute__((noinline)) foo (void) { return gs; }
355+
356+/* { dg-final { scan-assembler-times "popl\[\\t \]*%ecx" 1 } } */
357+/* { dg-final { scan-assembler "lea\[l\]?\[\\t \]*4\\(%esp\\), %esp" } } */
358+/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_return_thunk_ecx" } } */
359+/* { dg-final { scan-assembler-not "jmp\[ \t\]*\.LIND" } } */
360+/* { dg-final { scan-assembler-not "call\[ \t\]*\.LIND" } } */
361+/* { dg-final { scan-assembler-not {\tpause} } } */
362+/* { dg-final { scan-assembler-not {\tlfence} } } */
363diff --git a/gcc/testsuite/gcc.target/i386/ret-thunk-24.c b/gcc/testsuite/gcc.target/i386/ret-thunk-24.c
364new file mode 100644
365index 0000000..8729e35
366--- /dev/null
367+++ b/gcc/testsuite/gcc.target/i386/ret-thunk-24.c
368@@ -0,0 +1,15 @@
369+/* PR target/r84530 */
370+/* { dg-do compile { target ia32 } } */
371+/* { dg-options "-O2 -mfunction-return=thunk-inline" } */
372+
373+struct s { _Complex unsigned short x; };
374+struct s gs = { 100 + 200i };
375+struct s __attribute__((noinline)) foo (void) { return gs; }
376+
377+/* { dg-final { scan-assembler-times "popl\[\\t \]*%ecx" 1 } } */
378+/* { dg-final { scan-assembler "lea\[l\]?\[\\t \]*4\\(%esp\\), %esp" } } */
379+/* { dg-final { scan-assembler-not "jmp\[ \t\]*__x86_return_thunk_ecx" } } */
380+/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
381+/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */
382+/* { dg-final { scan-assembler {\tpause} } } */
383+/* { dg-final { scan-assembler {\tlfence} } } */
384diff --git a/gcc/testsuite/gcc.target/i386/ret-thunk-25.c b/gcc/testsuite/gcc.target/i386/ret-thunk-25.c
385new file mode 100644
386index 0000000..f73553c
387--- /dev/null
388+++ b/gcc/testsuite/gcc.target/i386/ret-thunk-25.c
389@@ -0,0 +1,15 @@
390+/* PR target/r84530 */
391+/* { dg-do compile { target ia32 } } */
392+/* { dg-options "-O2 -mfunction-return=thunk -fcheck-pointer-bounds -mmpx -fno-pic" } */
393+
394+struct s { _Complex unsigned short x; };
395+struct s gs = { 100 + 200i };
396+struct s __attribute__((noinline)) foo (void) { return gs; }
397+
398+/* { dg-final { scan-assembler-times "popl\[\\t \]*%ecx" 1 } } */
399+/* { dg-final { scan-assembler "lea\[l\]?\[\\t \]*4\\(%esp\\), %esp" } } */
400+/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_return_thunk_bnd_ecx" } } */
401+/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
402+/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */
403+/* { dg-final { scan-assembler {\tpause} } } */
404+/* { dg-final { scan-assembler {\tlfence} } } */
405diff --git a/gcc/testsuite/gcc.target/i386/ret-thunk-26.c b/gcc/testsuite/gcc.target/i386/ret-thunk-26.c
406new file mode 100644
407index 0000000..9144e98
408--- /dev/null
409+++ b/gcc/testsuite/gcc.target/i386/ret-thunk-26.c
410@@ -0,0 +1,40 @@
411+/* PR target/r84530 */
412+/* { dg-do run } */
413+/* { dg-options "-Os -mfunction-return=thunk" } */
414+
415+struct S { int i; };
416+__attribute__((const, noinline, noclone))
417+struct S foo (int x)
418+{
419+ struct S s;
420+ s.i = x;
421+ return s;
422+}
423+
424+int a[2048], b[2048], c[2048], d[2048];
425+struct S e[2048];
426+
427+__attribute__((noinline, noclone)) void
428+bar (void)
429+{
430+ int i;
431+ for (i = 0; i < 1024; i++)
432+ {
433+ e[i] = foo (i);
434+ a[i+2] = a[i] + a[i+1];
435+ b[10] = b[10] + i;
436+ c[i] = c[2047 - i];
437+ d[i] = d[i + 1];
438+ }
439+}
440+
441+int
442+main ()
443+{
444+ int i;
445+ bar ();
446+ for (i = 0; i < 1024; i++)
447+ if (e[i].i != i)
448+ __builtin_abort ();
449+ return 0;
450+}
451--
4522.7.4
453