The Arm prologue of a variadic function pushes the anonymous argument
registers, up to 16 bytes for r0-r3, and releases them on exit, so that
area is part of the frame. Both prologue expanders however reported the
static stack size as offsets->outgoing_args - offsets->saved_args, and
arm_get_frame_offsets sets offsets->saved_args to
crtl->args.pretend_args_size, so the subtraction discarded exactly the
save area. Report offsets->outgoing_args instead. aarch64 already
counts its varargs save area in frame.frame_size.
The local "size" is left alone: it also drives the stack-checking probe
sequence, which must continue to exclude the pretend area. Non-variadic
functions have pretend_args_size == 0 and are unaffected.
int vf (int a, ...) { char buf[100]; ... }
-O2 -fstack-usage: vf 120 static -> vf 136 static
current_function_static_stack_size has one consumer outside the back
ends, toplev.cc:output_stack_usage_1, so this cannot change code
generation.
Bootstrapped on x86_64-pc-linux-gnu, and tested on arm-none-eabi with a
cross compiler: no regressions in gcc.target/arm, gcc.target/arm/mve,
gcc.target/arm/simd or gcc.dg/tree-ssa against the same tree without the
patch.
Assisted-by: Claude Opus 5 (Anthropic)
gcc/ChangeLog:
PR target/106554
* config/arm/arm.cc (arm_expand_prologue): Report
offsets->outgoing_args as the static stack size, so that the
anonymous argument save area is included.
(thumb1_expand_prologue): Likewise.
gcc/testsuite/ChangeLog:
PR target/106554
* gcc.target/arm/pr106554.c: New test.
Signed-off-by: Dominic P <[email protected]>
---
Changes in v2: the test limit is -Wstack-usage=124 instead of 128. With
fewer callee-saved registers pushed, vf can use exactly 128 bytes and
the expected warning is lost; 124 leaves 4 bytes either side on the
configurations tried. The code change is unchanged.
OK for trunk?
gcc/config/arm/arm.cc | 4 ++--
gcc/testsuite/gcc.target/arm/pr106554.c | 31 +++++++++++++++++++++++++
2 files changed, 33 insertions(+), 2 deletions(-)
create mode 100644 gcc/testsuite/gcc.target/arm/pr106554.c
diff --git a/gcc/config/arm/arm.cc b/gcc/config/arm/arm.cc
index 33b64995442..c02b34c0fae 100644
--- a/gcc/config/arm/arm.cc
+++ b/gcc/config/arm/arm.cc
@@ -24186,7 +24186,7 @@ arm_expand_prologue (void)
size = offsets->outgoing_args - offsets->saved_args;
if (flag_stack_usage_info)
- current_function_static_stack_size = size;
+ current_function_static_stack_size = offsets->outgoing_args;
/* If this isn't an interrupt service routine and we have a frame, then do
stack checking. We use IP as the first scratch register, except for the
@@ -27674,7 +27674,7 @@ thumb1_expand_prologue (void)
size = offsets->outgoing_args - offsets->saved_args;
if (flag_stack_usage_info)
- current_function_static_stack_size = size;
+ current_function_static_stack_size = offsets->outgoing_args;
/* If we have a frame, then do stack checking. FIXME: not implemented. */
if ((flag_stack_check == STATIC_BUILTIN_STACK_CHECK
diff --git a/gcc/testsuite/gcc.target/arm/pr106554.c
b/gcc/testsuite/gcc.target/arm/pr106554.c
new file mode 100644
index 00000000000..2d88996bb13
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/pr106554.c
@@ -0,0 +1,31 @@
+/* PR target/106554: -fstack-usage and -Wstack-usage= must account for
+ the anonymous argument save area that the prologue of a variadic
+ function pushes. Only vf, whose frame includes the 16-byte save area,
+ exceeds the limit. */
+
+/* { dg-do compile } */
+/* { dg-options "-O2 -Wstack-usage=124" } */
+
+extern void sink (char *, int);
+
+int
+nf (int a) /* { dg-bogus "stack usage" } */
+{
+ char buf[100];
+ sink (buf, a);
+ return buf[0] + a;
+}
+
+int
+vf (int a, ...) /* { dg-warning "stack usage is \[0-9\]* bytes" } */
+{
+ char buf[100];
+ __builtin_va_list ap;
+ int r;
+
+ __builtin_va_start (ap, a);
+ r = __builtin_va_arg (ap, int);
+ __builtin_va_end (ap);
+ sink (buf, r);
+ return buf[0] + a + r;
+}
--
2.55.0