1 From 3f2a4b8f8ceef1a2095e1611e9c7b20590efcf23 Mon Sep 17 00:00:00 2001
2 From: Richard Lowe <richlowe@richlowe.net>
3 Date: Sat, 23 Jan 2016 22:14:56 -0500
4 Subject: i386: Save integer-passed arguments to the stack, to
7 Originally implemented in:
8 commit 023cc9a4c9c698bed1f51d38eac850d327fc1146
9 Author: jsm28 <jsm28@138bc75d-0d04-0410-961f-82ee72b054a4>
10 Date: Wed Jun 29 23:51:34 2005 +0000
12 * gcc/dwarf2.h (DW_AT_SUN_amd64_parmdump): New.
13 * gcc/dwarf2out.c (gen_subprogram_die): Add this attribute.
14 * gcc/doc/invoke.texi (-msave-args): New x86-64 option.
15 * gcc/config/i386/i386.h (MASK_SAVE_ARGS, TARGET_SAVE_ARGS): New.
16 (TARGET_SWITCHES): Add -msave-args.
17 * gcc/config/i386/i386.c (struct ix86_frame): Add nmsave_args and
19 (pro_epilogue_adjust_stack): Declare.
20 (ix86_nsaved_args): New.
21 (override_options, ix86_can_use_return_insn_p,
22 ix86_frame_pointer_required, ix86_compute_frame_layout,
23 ix86_emit_save_regs, ix86_emit_save_regs_using_mov,
24 ix86_expand_prologue, ix86_expand_epilogue): Handle -msave-args.
26 git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/branches/csl-sol210-3_4-branch@101443 138bc75d-0d04-0410-961f-82ee72b054a4
28 gcc/config/i386/i386-options.cc | 3 +
29 gcc/config/i386/i386.cc | 130 +++++++++++++++++-
30 gcc/config/i386/i386.h | 7 +
31 gcc/config/i386/i386.opt | 10 ++
32 gcc/doc/invoke.texi | 4 +
33 gcc/dwarf2out.cc | 5 +
34 .../gcc.target/i386/msave-args-mov.c | 26 ++++
35 .../gcc.target/i386/msave-args-push.c | 26 ++++
36 include/dwarf2.def | 2 +
37 9 files changed, 206 insertions(+), 7 deletions(-)
38 create mode 100644 gcc/testsuite/gcc.target/i386/msave-args-mov.c
39 create mode 100644 gcc/testsuite/gcc.target/i386/msave-args-push.c
41 diff --git a/gcc/config/i386/i386-options.cc b/gcc/config/i386/i386-options.cc
42 index 6c212a8edeb9..8f330973f028 100644
43 --- a/gcc/config/i386/i386-options.cc
44 +++ b/gcc/config/i386/i386-options.cc
45 @@ -2788,6 +2788,9 @@ ix86_option_override_internal (bool main_args_p,
46 &= ~(OPTION_MASK_ISA2_AVX5124FMAPS | OPTION_MASK_ISA2_AVX5124VNNIW);
49 + if (!TARGET_64BIT_P (opts->x_ix86_isa_flags) && TARGET_SAVE_ARGS)
50 + error ("-msave-args makes no sense in the 32-bit mode");
52 /* Validate -mpreferred-stack-boundary= value or default it to
53 PREFERRED_STACK_BOUNDARY_DEFAULT. */
54 ix86_preferred_stack_boundary = PREFERRED_STACK_BOUNDARY_DEFAULT;
55 diff --git a/gcc/config/i386/i386.cc b/gcc/config/i386/i386.cc
56 index 92b8fa7b7329..b18ac72dbc9a 100644
57 --- a/gcc/config/i386/i386.cc
58 +++ b/gcc/config/i386/i386.cc
59 @@ -433,6 +433,9 @@ static bool i386_asm_output_addr_const_extra (FILE *, rtx);
60 static bool ix86_can_inline_p (tree, tree);
61 static unsigned int ix86_minimum_incoming_stack_boundary (bool);
63 +static int ix86_nsaved_args (void);
64 +static rtx_def* pro_epilogue_adjust_stack (rtx, rtx, rtx, int, bool);
67 /* Whether -mtune= or -march= were specified */
68 int ix86_tune_defaulted;
69 @@ -5908,7 +5911,7 @@ ix86_can_use_return_insn_p (void)
71 struct ix86_frame &frame = cfun->machine->frame;
72 return (frame.stack_pointer_offset == UNITS_PER_WORD
73 - && (frame.nregs + frame.nsseregs) == 0);
74 + && (frame.nmsave_args + frame.nregs + frame.nsseregs) == 0);
77 /* Return stack frame size. get_frame_size () returns used stack slots
78 @@ -5945,6 +5948,9 @@ ix86_frame_pointer_required (void)
79 if (TARGET_32BIT_MS_ABI && cfun->calls_setjmp)
82 + if (TARGET_SAVE_ARGS)
85 /* Win64 SEH, very large frames need a frame-pointer as maximum stack
87 if (TARGET_64BIT_MS_ABI && ix86_get_frame_size () > SEH_MAX_FRAME_SIZE)
88 @@ -6888,6 +6894,7 @@ ix86_compute_frame_layout (void)
90 frame->nregs = ix86_nsaved_regs ();
91 frame->nsseregs = ix86_nsaved_sseregs ();
92 + frame->nmsave_args = ix86_nsaved_args ();
94 /* 64-bit MS ABI seem to require stack alignment to be always 16,
95 except for function prologues, leaf functions and when the defult
96 @@ -6973,7 +6980,8 @@ ix86_compute_frame_layout (void)
99 frame->save_regs_using_mov
100 - = TARGET_PROLOGUE_USING_MOVE && m->use_fast_prologue_epilogue;
101 + = TARGET_FORCE_SAVE_REGS_USING_MOV ||
102 + (TARGET_PROLOGUE_USING_MOVE && m->use_fast_prologue_epilogue);
104 /* Skip return address and error code in exception handler. */
105 offset = INCOMING_FRAME_SP_OFFSET;
106 @@ -6990,6 +6998,13 @@ ix86_compute_frame_layout (void)
107 /* The traditional frame pointer location is at the top of the frame. */
108 frame->hard_frame_pointer_offset = offset;
110 + if (TARGET_SAVE_ARGS)
112 + offset += frame->nmsave_args * UNITS_PER_WORD;
113 + offset += (frame->nmsave_args % 2) * UNITS_PER_WORD;
115 + frame->arg_save_offset = offset;
117 /* Register save area */
118 offset += frame->nregs * UNITS_PER_WORD;
119 frame->reg_save_offset = offset;
120 @@ -7123,7 +7138,7 @@ ix86_compute_frame_layout (void)
121 /* Size prologue needs to allocate. */
122 to_allocate = offset - frame->sse_reg_save_offset;
124 - if ((!to_allocate && frame->nregs <= 1)
125 + if ((!TARGET_SAVE_ARGS && !to_allocate && frame->nregs <= 1)
126 || (TARGET_64BIT && to_allocate >= HOST_WIDE_INT_C (0x80000000))
127 /* If static stack checking is enabled and done with probes,
128 the registers need to be saved before allocating the frame. */
129 @@ -7147,7 +7162,11 @@ ix86_compute_frame_layout (void)
131 frame->red_zone_size = to_allocate;
132 if (frame->save_regs_using_mov)
134 frame->red_zone_size += frame->nregs * UNITS_PER_WORD;
135 + frame->red_zone_size += frame->nmsave_args * UNITS_PER_WORD;
136 + frame->red_zone_size += (frame->nmsave_args % 2) * UNITS_PER_WORD;
138 if (frame->red_zone_size > RED_ZONE_SIZE - RED_ZONE_RESERVE)
139 frame->red_zone_size = RED_ZONE_SIZE - RED_ZONE_RESERVE;
141 @@ -7205,6 +7224,22 @@ ix86_compute_frame_layout (void)
143 frame->hard_frame_pointer_offset = frame->hfp_save_offset;
146 + if (getenv("DEBUG_FRAME_STUFF") != NULL)
148 + printf("nmsave_args: %d\n", frame->nmsave_args);
149 + printf("nsseregs: %d\n", frame->nsseregs);
150 + printf("nregs: %d\n", frame->nregs);
152 + printf("frame_pointer_offset: %llx\n", frame->frame_pointer_offset);
153 + printf("hard_frame_pointer_offset: %llx\n", frame->hard_frame_pointer_offset);
154 + printf("stack_pointer_offset: %llx\n", frame->stack_pointer_offset);
155 + printf("hfp_save_offset: %llx\n", frame->hfp_save_offset);
156 + printf("arg_save_offset: %llx\n", frame->arg_save_offset);
157 + printf("reg_save_offset: %llx\n", frame->reg_save_offset);
158 + printf("sse_reg_save_offset: %llx\n", frame->sse_reg_save_offset);
163 /* This is semi-inlined memory_address_length, but simplified
164 @@ -7420,6 +7455,23 @@ ix86_emit_save_regs (void)
168 + if (TARGET_SAVE_ARGS)
171 + int nsaved = ix86_nsaved_args ();
172 + int start = cfun->returns_struct;
174 + for (i = start; i < start + nsaved; i++)
176 + regno = x86_64_int_parameter_registers[i];
177 + insn = emit_insn (gen_push (gen_rtx_REG (word_mode, regno)));
178 + RTX_FRAME_RELATED_P (insn) = 1;
180 + if (nsaved % 2 != 0)
181 + pro_epilogue_adjust_stack (stack_pointer_rtx, stack_pointer_rtx,
182 + GEN_INT (-UNITS_PER_WORD), -1, false);
185 if (!TARGET_APX_PUSH2POP2
186 || !ix86_can_use_push2pop2 ()
187 || cfun->machine->func_type != TYPE_NORMAL)
188 @@ -7585,9 +7637,30 @@ ix86_emit_save_reg_using_mov (machine_mode mode, unsigned int regno,
189 /* Emit code to save registers using MOV insns.
190 First register is stored at CFA - CFA_OFFSET. */
192 -ix86_emit_save_regs_using_mov (HOST_WIDE_INT cfa_offset)
193 +ix86_emit_save_regs_using_mov (const struct ix86_frame *frame)
196 + HOST_WIDE_INT cfa_offset = frame->arg_save_offset;
198 + if (TARGET_SAVE_ARGS)
201 + int nsaved = ix86_nsaved_args ();
202 + int start = cfun->returns_struct;
204 + /* We deal with this twice? */
205 + if (nsaved % 2 != 0)
206 + cfa_offset -= UNITS_PER_WORD;
208 + for (i = start + nsaved - 1; i >= start; i--)
210 + regno = x86_64_int_parameter_registers[i];
211 + ix86_emit_save_reg_using_mov(word_mode, regno, cfa_offset);
212 + cfa_offset -= UNITS_PER_WORD;
216 + cfa_offset = frame->reg_save_offset;
218 for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
219 if (GENERAL_REGNO_P (regno) && ix86_save_reg (regno, true, true))
220 @@ -8945,7 +9018,7 @@ ix86_expand_prologue (void)
224 - int_registers_saved = (frame.nregs == 0);
225 + int_registers_saved = (frame.nregs == 0 && frame.nmsave_args == 0);
226 sse_registers_saved = (frame.nsseregs == 0);
227 save_stub_call_needed = (m->call_ms2sysv);
228 gcc_assert (sse_registers_saved || !save_stub_call_needed);
229 @@ -8987,7 +9060,7 @@ ix86_expand_prologue (void)
230 && (! TARGET_STACK_PROBE
231 || frame.stack_pointer_offset < CHECK_STACK_LIMIT))
233 - ix86_emit_save_regs_using_mov (frame.reg_save_offset);
234 + ix86_emit_save_regs_using_mov (&frame);
235 cfun->machine->red_zone_used = true;
236 int_registers_saved = true;
238 @@ -9287,7 +9360,7 @@ ix86_expand_prologue (void)
241 if (!int_registers_saved)
242 - ix86_emit_save_regs_using_mov (frame.reg_save_offset);
243 + ix86_emit_save_regs_using_mov (&frame);
244 if (!sse_registers_saved)
245 ix86_emit_save_sse_regs_using_mov (frame.sse_reg_save_offset);
246 else if (save_stub_call_needed)
247 @@ -9322,6 +9395,7 @@ ix86_expand_prologue (void)
248 relative to the value of the stack pointer at the end of the function
249 prologue, and moving instructions that access redzone area via frame
250 pointer inside push sequence violates this assumption. */
251 + /* XXX: We may wish to do this when SAVE_ARGS in general */
252 if (frame_pointer_needed && frame.red_zone_size)
253 emit_insn (gen_memory_blockage ());
255 @@ -9824,6 +9898,7 @@ ix86_expand_epilogue (int style)
257 /* See the comment about red zone and frame
258 pointer usage in ix86_expand_prologue. */
259 + /* XXX: We may wish to do this when SAVE_ARGS in general */
260 if (frame_pointer_needed && frame.red_zone_size)
261 emit_insn (gen_memory_blockage ());
263 @@ -10068,6 +10143,35 @@ ix86_expand_epilogue (int style)
264 ix86_emit_restore_regs_using_pop (TARGET_APX_PPX);
267 + if (TARGET_SAVE_ARGS) {
269 + * For each saved argument, emit a restore note, to make sure it happens
270 + * correctly within the shrink wrapping (I think).
272 + * Note that 'restore' in this case merely means the rule is the same as
273 + * it was on function entry, not that we have actually done a register
274 + * restore (which of course, we haven't).
276 + * If we do not do this, the DWARF code will emit sufficient restores to
277 + * provide balance on its own initiative, which in the presence of
278 + * -fshrink-wrap may actually _introduce_ unbalance (whereby we only
279 + * .cfi_offset a register sometimes, but will always .cfi_restore it.
280 + * This will trip an assert.)
282 + int start = cfun->returns_struct;
283 + int nsaved = ix86_nsaved_args();
286 + for (i = start + nsaved - 1; i >= start; i--)
287 + queued_cfa_restores
288 + = alloc_reg_note (REG_CFA_RESTORE,
290 + x86_64_int_parameter_registers[i]),
291 + queued_cfa_restores);
293 + gcc_assert(m->fs.fp_valid);
296 /* If we used a stack pointer and haven't already got rid of it,
299 @@ -11232,6 +11336,18 @@ ix86_cannot_force_const_mem (machine_mode mode, rtx x)
300 return !ix86_legitimate_constant_p (mode, x);
303 +/* Return number of arguments to be saved on the stack with
307 +ix86_nsaved_args (void)
309 + if (TARGET_SAVE_ARGS)
310 + return crtl->args.info.regno - cfun->returns_struct;
315 /* Nonzero if the symbol is marked as dllimport, or as stub-variable,
318 diff --git a/gcc/config/i386/i386.h b/gcc/config/i386/i386.h
319 index 26e15d2677fb..4b00a785562b 100644
320 --- a/gcc/config/i386/i386.h
321 +++ b/gcc/config/i386/i386.h
322 @@ -2597,6 +2597,11 @@ enum avx_u128_state
324 saved frame pointer if frame_pointer_needed
325 <- HARD_FRAME_POINTER
327 + [-msave-args] <- arg_save_offset
334 @@ -2630,6 +2635,7 @@ enum avx_u128_state
336 struct GTY(()) ix86_frame
342 @@ -2641,6 +2647,7 @@ struct GTY(()) ix86_frame
343 HOST_WIDE_INT hard_frame_pointer_offset;
344 HOST_WIDE_INT stack_pointer_offset;
345 HOST_WIDE_INT hfp_save_offset;
346 + HOST_WIDE_INT arg_save_offset;
347 HOST_WIDE_INT reg_save_offset;
348 HOST_WIDE_INT stack_realign_allocate;
349 HOST_WIDE_INT stack_realign_offset;
350 diff --git a/gcc/config/i386/i386.opt b/gcc/config/i386/i386.opt
351 index d5f793a9e8b0..c0305bd79703 100644
352 --- a/gcc/config/i386/i386.opt
353 +++ b/gcc/config/i386/i386.opt
354 @@ -537,6 +537,16 @@ mtls-direct-seg-refs
355 Target Mask(TLS_DIRECT_SEG_REFS)
356 Use direct references against %gs when accessing tls data.
359 +Target Mask(SAVE_ARGS) Var(ix86_target_flags)
360 +Save integer arguments on the stack at function entry.
362 +mforce-save-regs-using-mov
363 +Target Mask(FORCE_SAVE_REGS_USING_MOV) Var(ix86_target_flags)
364 +Save registers using push in function prologues. This is intentionally
365 +undocumented and used for msave-args testing.
369 Target RejectNegative Negative(mtune=) Joined Var(ix86_tune_string)
370 Schedule code for given CPU.
371 diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
372 index 2f2f3700057b..36ea22d6ccf0 100644
373 --- a/gcc/doc/invoke.texi
374 +++ b/gcc/doc/invoke.texi
375 @@ -21168,6 +21168,10 @@ The default setting is @samp{tpidr_el0}. It is recommended to compile all
376 code intended to interoperate with the same value of this option to avoid
377 accessing a different thread pointer from the wrong exception level.
381 +Save integer-sized arguments on the stack on function entry.
383 @opindex mstrict-align
384 @opindex mno-strict-align
386 diff --git a/gcc/dwarf2out.cc b/gcc/dwarf2out.cc
387 index 1b0e8b5a5b29..b1c19db5ce48 100644
388 --- a/gcc/dwarf2out.cc
389 +++ b/gcc/dwarf2out.cc
390 @@ -24152,6 +24152,11 @@ gen_subprogram_die (tree decl, dw_die_ref context_die)
391 /* Add the calling convention attribute if requested. */
392 add_calling_convention_attribute (subr_die, decl);
394 +#ifdef TARGET_SAVE_ARGS
395 + if (declaration && TARGET_SAVE_ARGS)
396 + add_AT_flag (subr_die, DW_AT_SUN_amd64_parmdump, 1);
399 /* Output Dwarf info for all of the stuff within the body of the function
400 (if it has one - it may be just a declaration).
402 diff --git a/gcc/testsuite/gcc.target/i386/msave-args-mov.c b/gcc/testsuite/gcc.target/i386/msave-args-mov.c
404 index 000000000000..a2ca76752a96
406 +++ b/gcc/testsuite/gcc.target/i386/msave-args-mov.c
408 +/* { dg-do run { target { { i?86-*-solaris2.* } && lp64 } } } */
409 +/* { dg-options "-msave-args -mforce-save-regs-using-mov -save-temps" } */
413 +void t(int, int, int, int, int) __attribute__ ((noinline));
416 +main(int argc, char **argv)
423 +t(int a, int b, int c, int d, int e)
425 + printf("%d %d %d %d %d", a, b, c, d, e);
428 +/* { dg-final { scan-assembler "movq\t%rdi, -8\\(%rbp\\)" } } */
429 +/* { dg-final { scan-assembler "movq\t%rsi, -16\\(%rbp\\)" } } */
430 +/* { dg-final { scan-assembler "movq\t%rdx, -24\\(%rbp\\)" } } */
431 +/* { dg-final { scan-assembler "movq\t%rcx, -32\\(%rbp\\)" } } */
432 +/* { dg-final { scan-assembler "movq\t%r8, -40\\(%rbp\\)" } } */
433 +/* { dg-final { cleanup-saved-temps } } */
434 diff --git a/gcc/testsuite/gcc.target/i386/msave-args-push.c b/gcc/testsuite/gcc.target/i386/msave-args-push.c
436 index 000000000000..fbe053dadc8b
438 +++ b/gcc/testsuite/gcc.target/i386/msave-args-push.c
440 +/* { dg-do run { target { { i?86-*-solaris2.* } && lp64 } } } */
441 +/* { dg-options "-msave-args -save-temps " } */
445 +void t(int, int, int, int, int) __attribute__ ((noinline));
448 +main(int argc, char **argv)
455 +t(int a, int b, int c, int d, int e)
457 + printf("%d %d %d %d %d", a, b, c, d, e);
460 +/* { dg-final { scan-assembler "pushq\t%rdi" } } */
461 +/* { dg-final { scan-assembler "pushq\t%rsi" } } */
462 +/* { dg-final { scan-assembler "pushq\t%rdx" } } */
463 +/* { dg-final { scan-assembler "pushq\t%rcx" } } */
464 +/* { dg-final { scan-assembler "pushq\t%r8" } } */
465 +/* { dg-final { cleanup-saved-temps } } */
466 diff --git a/include/dwarf2.def b/include/dwarf2.def
467 index 66c7fa1220f8..9284f3d59c54 100644
468 --- a/include/dwarf2.def
469 +++ b/include/dwarf2.def
470 @@ -467,6 +467,8 @@ DW_TAG (DW_AT_GNU_denominator, 0x2304)
471 /* Biased integer extension.
472 See https://gcc.gnu.org/wiki/DW_AT_GNU_bias . */
473 DW_TAG (DW_AT_GNU_bias, 0x2305)
474 +/* Sun extension. */
475 +DW_AT (DW_AT_SUN_amd64_parmdump, 0x2224)
477 DW_AT (DW_AT_upc_threads_scaled, 0x3210)
478 /* PGI (STMicroelectronics) extensions. */