1 From 9115575f021bc853091b1528fbae30b8b1abb821 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 Content-Type: text/plain; charset=UTF-8
8 Content-Transfer-Encoding: 8bit
10 Merged from 5.3 to 7.2 by: Aurélien Larcher
12 Originally implemented in:
13 commit 023cc9a4c9c698bed1f51d38eac850d327fc1146
14 Author: jsm28 <jsm28@138bc75d-0d04-0410-961f-82ee72b054a4>
15 Date: Wed Jun 29 23:51:34 2005 +0000
17 * gcc/dwarf2.h (DW_AT_SUN_amd64_parmdump): New.
18 * gcc/dwarf2out.c (gen_subprogram_die): Add this attribute.
19 * gcc/doc/invoke.texi (-msave-args): New x86-64 option.
20 * gcc/config/i386/i386.h (MASK_SAVE_ARGS, TARGET_SAVE_ARGS): New.
21 (TARGET_SWITCHES): Add -msave-args.
22 * gcc/config/i386/i386.c (struct ix86_frame): Add nmsave_args and
24 (pro_epilogue_adjust_stack): Declare.
25 (ix86_nsaved_args): New.
26 (override_options, ix86_can_use_return_insn_p,
27 ix86_frame_pointer_required, ix86_compute_frame_layout,
28 ix86_emit_save_regs, ix86_emit_save_regs_using_mov,
29 ix86_expand_prologue, ix86_expand_epilogue): Handle -msave-args.
31 git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/branches/csl-sol210-3_4-branch@101443 138bc75d-0d04-0410-961f-82ee72b054a4
33 gcc/config/i386/i386-options.c | 3 +
34 gcc/config/i386/i386.c | 130 +++++++++++++++++-
35 gcc/config/i386/i386.h | 7 +
36 gcc/config/i386/i386.opt | 10 ++
37 gcc/doc/invoke.texi | 4 +
39 .../gcc.target/i386/msave-args-mov.c | 26 ++++
40 .../gcc.target/i386/msave-args-push.c | 26 ++++
41 include/dwarf2.def | 2 +
42 9 files changed, 206 insertions(+), 7 deletions(-)
43 create mode 100644 gcc/testsuite/gcc.target/i386/msave-args-mov.c
44 create mode 100644 gcc/testsuite/gcc.target/i386/msave-args-push.c
46 diff --git a/gcc/config/i386/i386-options.c b/gcc/config/i386/i386-options.c
47 index 18d2c0b9f99..9f9d1028eb7 100644
48 --- a/gcc/config/i386/i386-options.c
49 +++ b/gcc/config/i386/i386-options.c
51 &= ~((OPTION_MASK_ISA_BMI | OPTION_MASK_ISA_BMI2 | OPTION_MASK_ISA_TBM)
52 & ~opts->x_ix86_isa_flags_explicit);
54 + if (!TARGET_64BIT_P (opts->x_ix86_isa_flags) && TARGET_SAVE_ARGS)
55 + error ("-msave-args makes no sense in the 32-bit mode");
57 /* Validate -mpreferred-stack-boundary= value or default it to
58 PREFERRED_STACK_BOUNDARY_DEFAULT. */
59 ix86_preferred_stack_boundary = PREFERRED_STACK_BOUNDARY_DEFAULT;
60 diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
61 index 9d02aad9e13..cdd5633cb57 100644
62 --- a/gcc/config/i386/i386.c
63 +++ b/gcc/config/i386/i386.c
65 static bool ix86_can_inline_p (tree, tree);
66 static unsigned int ix86_minimum_incoming_stack_boundary (bool);
68 +static int ix86_nsaved_args (void);
69 +static rtx_def* pro_epilogue_adjust_stack (rtx, rtx, rtx, int, bool);
72 /* Whether -mtune= or -march= were specified */
73 int ix86_tune_defaulted;
76 struct ix86_frame &frame = cfun->machine->frame;
77 return (frame.stack_pointer_offset == UNITS_PER_WORD
78 - && (frame.nregs + frame.nsseregs) == 0);
79 + && (frame.nmsave_args + frame.nregs + frame.nsseregs) == 0);
82 /* Return stack frame size. get_frame_size () returns used stack slots
84 if (TARGET_32BIT_MS_ABI && cfun->calls_setjmp)
87 + if (TARGET_SAVE_ARGS)
90 /* Win64 SEH, very large frames need a frame-pointer as maximum stack
92 if (TARGET_64BIT_MS_ABI && ix86_get_frame_size () > SEH_MAX_FRAME_SIZE)
95 frame->nregs = ix86_nsaved_regs ();
96 frame->nsseregs = ix86_nsaved_sseregs ();
97 + frame->nmsave_args = ix86_nsaved_args ();
99 /* 64-bit MS ABI seem to require stack alignment to be always 16,
100 except for function prologues, leaf functions and when the defult
101 @@ -6494,7 +6501,8 @@
104 frame->save_regs_using_mov
105 - = TARGET_PROLOGUE_USING_MOVE && m->use_fast_prologue_epilogue;
106 + = TARGET_FORCE_SAVE_REGS_USING_MOV ||
107 + (TARGET_PROLOGUE_USING_MOVE && m->use_fast_prologue_epilogue);
109 /* Skip return address and error code in exception handler. */
110 offset = INCOMING_FRAME_SP_OFFSET;
111 @@ -6511,6 +6519,13 @@
112 /* The traditional frame pointer location is at the top of the frame. */
113 frame->hard_frame_pointer_offset = offset;
115 + if (TARGET_SAVE_ARGS)
117 + offset += frame->nmsave_args * UNITS_PER_WORD;
118 + offset += (frame->nmsave_args % 2) * UNITS_PER_WORD;
120 + frame->arg_save_offset = offset;
122 /* Register save area */
123 offset += frame->nregs * UNITS_PER_WORD;
124 frame->reg_save_offset = offset;
125 @@ -6644,7 +6659,7 @@
126 /* Size prologue needs to allocate. */
127 to_allocate = offset - frame->sse_reg_save_offset;
129 - if ((!to_allocate && frame->nregs <= 1)
130 + if ((!TARGET_SAVE_ARGS && !to_allocate && frame->nregs <= 1)
131 || (TARGET_64BIT && to_allocate >= HOST_WIDE_INT_C (0x80000000))
132 /* If static stack checking is enabled and done with probes,
133 the registers need to be saved before allocating the frame. */
134 @@ -6666,7 +6681,11 @@
136 frame->red_zone_size = to_allocate;
137 if (frame->save_regs_using_mov)
139 frame->red_zone_size += frame->nregs * UNITS_PER_WORD;
140 + frame->red_zone_size += frame->nmsave_args * UNITS_PER_WORD;
141 + frame->red_zone_size += (frame->nmsave_args % 2) * UNITS_PER_WORD;
143 if (frame->red_zone_size > RED_ZONE_SIZE - RED_ZONE_RESERVE)
144 frame->red_zone_size = RED_ZONE_SIZE - RED_ZONE_RESERVE;
146 @@ -6724,6 +6743,22 @@
148 frame->hard_frame_pointer_offset = frame->hfp_save_offset;
151 + if (getenv("DEBUG_FRAME_STUFF") != NULL)
153 + printf("nmsave_args: %d\n", frame->nmsave_args);
154 + printf("nsseregs: %d\n", frame->nsseregs);
155 + printf("nregs: %d\n", frame->nregs);
157 + printf("frame_pointer_offset: %llx\n", frame->frame_pointer_offset);
158 + printf("hard_frame_pointer_offset: %llx\n", frame->hard_frame_pointer_offset);
159 + printf("stack_pointer_offset: %llx\n", frame->stack_pointer_offset);
160 + printf("hfp_save_offset: %llx\n", frame->hfp_save_offset);
161 + printf("arg_save_offset: %llx\n", frame->arg_save_offset);
162 + printf("reg_save_offset: %llx\n", frame->reg_save_offset);
163 + printf("sse_reg_save_offset: %llx\n", frame->sse_reg_save_offset);
168 /* This is semi-inlined memory_address_length, but simplified
169 @@ -6939,6 +6974,23 @@
173 + if (TARGET_SAVE_ARGS)
176 + int nsaved = ix86_nsaved_args ();
177 + int start = cfun->returns_struct;
179 + for (i = start; i < start + nsaved; i++)
181 + regno = x86_64_int_parameter_registers[i];
182 + insn = emit_insn (gen_push (gen_rtx_REG (word_mode, regno)));
183 + RTX_FRAME_RELATED_P (insn) = 1;
185 + if (nsaved % 2 != 0)
186 + pro_epilogue_adjust_stack (stack_pointer_rtx, stack_pointer_rtx,
187 + GEN_INT (-UNITS_PER_WORD), -1, false);
190 for (regno = FIRST_PSEUDO_REGISTER - 1; regno-- > 0; )
191 if (GENERAL_REGNO_P (regno) && ix86_save_reg (regno, true, true))
193 @@ -7025,9 +7077,30 @@
194 /* Emit code to save registers using MOV insns.
195 First register is stored at CFA - CFA_OFFSET. */
197 -ix86_emit_save_regs_using_mov (HOST_WIDE_INT cfa_offset)
198 +ix86_emit_save_regs_using_mov (const struct ix86_frame *frame)
201 + HOST_WIDE_INT cfa_offset = frame->arg_save_offset;
203 + if (TARGET_SAVE_ARGS)
206 + int nsaved = ix86_nsaved_args ();
207 + int start = cfun->returns_struct;
209 + /* We deal with this twice? */
210 + if (nsaved % 2 != 0)
211 + cfa_offset -= UNITS_PER_WORD;
213 + for (i = start + nsaved - 1; i >= start; i--)
215 + regno = x86_64_int_parameter_registers[i];
216 + ix86_emit_save_reg_using_mov(word_mode, regno, cfa_offset);
217 + cfa_offset -= UNITS_PER_WORD;
221 + cfa_offset = frame->reg_save_offset;
223 for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
224 if (GENERAL_REGNO_P (regno) && ix86_save_reg (regno, true, true))
225 @@ -8372,7 +8445,7 @@
229 - int_registers_saved = (frame.nregs == 0);
230 + int_registers_saved = (frame.nregs == 0 && frame.nmsave_args == 0);
231 sse_registers_saved = (frame.nsseregs == 0);
232 save_stub_call_needed = (m->call_ms2sysv);
233 gcc_assert (sse_registers_saved || !save_stub_call_needed);
234 @@ -8414,7 +8487,7 @@
235 && (! TARGET_STACK_PROBE
236 || frame.stack_pointer_offset < CHECK_STACK_LIMIT))
238 - ix86_emit_save_regs_using_mov (frame.reg_save_offset);
239 + ix86_emit_save_regs_using_mov (&frame);
240 cfun->machine->red_zone_used = true;
241 int_registers_saved = true;
243 @@ -8711,7 +8784,7 @@
246 if (!int_registers_saved)
247 - ix86_emit_save_regs_using_mov (frame.reg_save_offset);
248 + ix86_emit_save_regs_using_mov (&frame);
249 if (!sse_registers_saved)
250 ix86_emit_save_sse_regs_using_mov (frame.sse_reg_save_offset);
251 else if (save_stub_call_needed)
252 @@ -8746,6 +8819,7 @@
253 relative to the value of the stack pointer at the end of the function
254 prologue, and moving instructions that access redzone area via frame
255 pointer inside push sequence violates this assumption. */
256 + /* XXX: We may wish to do this when SAVE_ARGS in general */
257 if (frame_pointer_needed && frame.red_zone_size)
258 emit_insn (gen_memory_blockage ());
260 @@ -9130,6 +9204,7 @@
262 /* See the comment about red zone and frame
263 pointer usage in ix86_expand_prologue. */
264 + /* XXX: We may wish to do this when SAVE_ARGS in general */
265 if (frame_pointer_needed && frame.red_zone_size)
266 emit_insn (gen_memory_blockage ());
268 @@ -9366,6 +9441,35 @@
269 ix86_emit_restore_regs_using_pop ();
272 + if (TARGET_SAVE_ARGS) {
274 + * For each saved argument, emit a restore note, to make sure it happens
275 + * correctly within the shrink wrapping (I think).
277 + * Note that 'restore' in this case merely means the rule is the same as
278 + * it was on function entry, not that we have actually done a register
279 + * restore (which of course, we haven't).
281 + * If we do not do this, the DWARF code will emit sufficient restores to
282 + * provide balance on its own initiative, which in the presence of
283 + * -fshrink-wrap may actually _introduce_ unbalance (whereby we only
284 + * .cfi_offset a register sometimes, but will always .cfi_restore it.
285 + * This will trip an assert.)
287 + int start = cfun->returns_struct;
288 + int nsaved = ix86_nsaved_args();
291 + for (i = start + nsaved - 1; i >= start; i--)
292 + queued_cfa_restores
293 + = alloc_reg_note (REG_CFA_RESTORE,
295 + x86_64_int_parameter_registers[i]),
296 + queued_cfa_restores);
298 + gcc_assert(m->fs.fp_valid);
301 /* If we used a stack pointer and haven't already got rid of it,
304 @@ -10458,6 +10562,18 @@
305 return !ix86_legitimate_constant_p (mode, x);
308 +/* Return number of arguments to be saved on the stack with
312 +ix86_nsaved_args (void)
314 + if (TARGET_SAVE_ARGS)
315 + return crtl->args.info.regno - cfun->returns_struct;
320 /* Nonzero if the symbol is marked as dllimport, or as stub-variable,
323 diff --git a/gcc/config/i386/i386.h b/gcc/config/i386/i386.h
324 index 5583ec6881a..eebf9b9670d 100644
325 --- a/gcc/config/i386/i386.h
326 +++ b/gcc/config/i386/i386.h
327 --- i386.h.~1~ 2022-04-21 10:59:17.000000000 +0000
328 +++ i386.h 2022-05-19 11:15:00.066584226 +0000
329 @@ -2726,6 +2726,11 @@
331 saved frame pointer if frame_pointer_needed
332 <- HARD_FRAME_POINTER
334 + [-msave-args] <- arg_save_offset
341 @@ -2759,6 +2764,7 @@
343 struct GTY(()) ix86_frame
349 @@ -2770,6 +2776,7 @@
350 HOST_WIDE_INT hard_frame_pointer_offset;
351 HOST_WIDE_INT stack_pointer_offset;
352 HOST_WIDE_INT hfp_save_offset;
353 + HOST_WIDE_INT arg_save_offset;
354 HOST_WIDE_INT reg_save_offset;
355 HOST_WIDE_INT stack_realign_allocate;
356 HOST_WIDE_INT stack_realign_offset;
357 diff --git a/gcc/config/i386/i386.opt b/gcc/config/i386/i386.opt
358 index c781fdc8278..af7e920a67c 100644
359 --- a/gcc/config/i386/i386.opt
360 +++ b/gcc/config/i386/i386.opt
361 @@ -514,6 +514,16 @@ mtls-direct-seg-refs
362 Target Mask(TLS_DIRECT_SEG_REFS)
363 Use direct references against %gs when accessing tls data.
366 +Target Mask(SAVE_ARGS)
367 +Save integer arguments on the stack at function entry.
369 +mforce-save-regs-using-mov
370 +Target Mask(FORCE_SAVE_REGS_USING_MOV)
371 +Save registers using push in function prologues. This is intentionally
372 +undocumented and used for msave-args testing.
376 Target RejectNegative Negative(mtune=) Joined Var(ix86_tune_string)
377 Schedule code for given CPU.
378 diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
379 index 4f265aeead0..33facd6e594 100644
380 --- a/gcc/doc/invoke.texi
381 +++ b/gcc/doc/invoke.texi
382 @@ -18083,6 +18083,10 @@
383 @option{-mcmodel=large} option is incompatible with @option{-mabi=ilp32},
384 @option{-fpic} and @option{-fPIC}.
388 +Save integer-sized arguments on the stack on function entry.
391 @itemx -mno-strict-align
392 @opindex mstrict-align
393 diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c
394 index 7606371296e..de12e492bb3 100644
395 --- a/gcc/dwarf2out.c
396 +++ b/gcc/dwarf2out.c
397 @@ -23648,6 +23648,11 @@
398 /* Add the calling convention attribute if requested. */
399 add_calling_convention_attribute (subr_die, decl);
401 +#ifdef TARGET_SAVE_ARGS
402 + if (declaration && TARGET_SAVE_ARGS)
403 + add_AT_flag (subr_die, DW_AT_SUN_amd64_parmdump, 1);
406 /* Output Dwarf info for all of the stuff within the body of the function
407 (if it has one - it may be just a declaration).
409 diff --git a/gcc/testsuite/gcc.target/i386/msave-args-mov.c b/gcc/testsuite/gcc.target/i386/msave-args-mov.c
411 index 00000000000..a2ca76752a9
413 +++ b/gcc/testsuite/gcc.target/i386/msave-args-mov.c
415 +/* { dg-do run { target { { i?86-*-solaris2.* } && lp64 } } } */
416 +/* { dg-options "-msave-args -mforce-save-regs-using-mov -save-temps" } */
420 +void t(int, int, int, int, int) __attribute__ ((noinline));
423 +main(int argc, char **argv)
430 +t(int a, int b, int c, int d, int e)
432 + printf("%d %d %d %d %d", a, b, c, d, e);
435 +/* { dg-final { scan-assembler "movq\t%rdi, -8\\(%rbp\\)" } } */
436 +/* { dg-final { scan-assembler "movq\t%rsi, -16\\(%rbp\\)" } } */
437 +/* { dg-final { scan-assembler "movq\t%rdx, -24\\(%rbp\\)" } } */
438 +/* { dg-final { scan-assembler "movq\t%rcx, -32\\(%rbp\\)" } } */
439 +/* { dg-final { scan-assembler "movq\t%r8, -40\\(%rbp\\)" } } */
440 +/* { dg-final { cleanup-saved-temps } } */
441 diff --git a/gcc/testsuite/gcc.target/i386/msave-args-push.c b/gcc/testsuite/gcc.target/i386/msave-args-push.c
443 index 00000000000..fbe053dadc8
445 +++ b/gcc/testsuite/gcc.target/i386/msave-args-push.c
447 +/* { dg-do run { target { { i?86-*-solaris2.* } && lp64 } } } */
448 +/* { dg-options "-msave-args -save-temps " } */
452 +void t(int, int, int, int, int) __attribute__ ((noinline));
455 +main(int argc, char **argv)
462 +t(int a, int b, int c, int d, int e)
464 + printf("%d %d %d %d %d", a, b, c, d, e);
467 +/* { dg-final { scan-assembler "pushq\t%rdi" } } */
468 +/* { dg-final { scan-assembler "pushq\t%rsi" } } */
469 +/* { dg-final { scan-assembler "pushq\t%rdx" } } */
470 +/* { dg-final { scan-assembler "pushq\t%rcx" } } */
471 +/* { dg-final { scan-assembler "pushq\t%r8" } } */
472 +/* { dg-final { cleanup-saved-temps } } */
473 diff --git a/include/dwarf2.def b/include/dwarf2.def
474 index 1ae6e1df298..17e32b3400a 100644
475 --- a/include/dwarf2.def
476 +++ b/include/dwarf2.def
477 @@ -467,6 +467,8 @@ DW_TAG (DW_AT_GNU_denominator, 0x2304)
478 /* Biased integer extension.
479 See https://gcc.gnu.org/wiki/DW_AT_GNU_bias . */
480 DW_TAG (DW_AT_GNU_bias, 0x2305)
481 +/* Sun extension. */
482 +DW_AT (DW_AT_SUN_amd64_parmdump, 0x2224)
484 DW_AT (DW_AT_upc_threads_scaled, 0x3210)
485 /* PGI (STMicroelectronics) extensions. */