84 lines
2.7 KiB
Diff
84 lines
2.7 KiB
Diff
From 4075f299ca6a5d15fdb46f877cbe11b7166a19ff Mon Sep 17 00:00:00 2001
|
|
From: Xi Ruoyao <xry111@xry111.site>
|
|
Date: Wed, 29 Mar 2023 01:36:09 +0800
|
|
Subject: [PATCH 042/124] LoongArch: Improve GAR store for va_list
|
|
|
|
LoongArch backend used to save all GARs for a function with variable
|
|
arguments. But sometimes a function only accepts variable arguments for
|
|
a purpose like C++ function overloading. For example, POSIX defines
|
|
open() as:
|
|
|
|
int open(const char *path, int oflag, ...);
|
|
|
|
But only two forms are actually used:
|
|
|
|
int open(const char *pathname, int flags);
|
|
int open(const char *pathname, int flags, mode_t mode);
|
|
|
|
So it's obviously a waste to save all 8 GARs in open(). We can use the
|
|
cfun->va_list_gpr_size field set by the stdarg pass to only save the
|
|
GARs necessary to be saved.
|
|
|
|
If the va_list escapes (for example, in fprintf() we pass it to
|
|
vfprintf()), stdarg would set cfun->va_list_gpr_size to 255 so we
|
|
don't need a special case.
|
|
|
|
With this patch, only one GAR ($a2/$r6) is saved in open(). Ideally
|
|
even this stack store should be omitted too, but doing so is not trivial
|
|
and AFAIK there are no compilers (for any target) performing the "ideal"
|
|
optimization here, see https://godbolt.org/z/n1YqWq9c9.
|
|
|
|
Bootstrapped and regtested on loongarch64-linux-gnu. Ok for trunk
|
|
(GCC 14 or now)?
|
|
|
|
gcc/ChangeLog:
|
|
|
|
* config/loongarch/loongarch.cc
|
|
(loongarch_setup_incoming_varargs): Don't save more GARs than
|
|
cfun->va_list_gpr_size / UNITS_PER_WORD.
|
|
|
|
gcc/testsuite/ChangeLog:
|
|
|
|
* gcc.target/loongarch/va_arg.c: New test.
|
|
|
|
Signed-off-by: Peng Fan <fanpeng@loongson.cn>
|
|
Signed-off-by: ticat_fp <fanpeng@loongson.cn>
|
|
---
|
|
gcc/testsuite/gcc.target/loongarch/va_arg.c | 24 +++++++++++++++++++++
|
|
1 file changed, 24 insertions(+)
|
|
create mode 100644 gcc/testsuite/gcc.target/loongarch/va_arg.c
|
|
|
|
diff --git a/gcc/testsuite/gcc.target/loongarch/va_arg.c b/gcc/testsuite/gcc.target/loongarch/va_arg.c
|
|
new file mode 100644
|
|
index 000000000..980c96d0e
|
|
--- /dev/null
|
|
+++ b/gcc/testsuite/gcc.target/loongarch/va_arg.c
|
|
@@ -0,0 +1,24 @@
|
|
+/* { dg-do compile } */
|
|
+/* { dg-options "-O2" } */
|
|
+
|
|
+/* Technically we shouldn't save any register for this function: it should be
|
|
+ compiled as if it accepts 3 named arguments. But AFAIK no compilers can
|
|
+ achieve this "perfect" optimization now, so just ensure we are using the
|
|
+ knowledge provided by stdarg pass and we won't save GARs impossible to be
|
|
+ accessed with __builtin_va_arg () when the va_list does not escape. */
|
|
+
|
|
+/* { dg-final { scan-assembler-not "st.*r7" } } */
|
|
+
|
|
+int
|
|
+test (int a0, ...)
|
|
+{
|
|
+ void *arg;
|
|
+ int a1, a2;
|
|
+
|
|
+ __builtin_va_start (arg, a0);
|
|
+ a1 = __builtin_va_arg (arg, int);
|
|
+ a2 = __builtin_va_arg (arg, int);
|
|
+ __builtin_va_end (arg);
|
|
+
|
|
+ return a0 + a1 + a2;
|
|
+}
|
|
--
|
|
2.33.0
|
|
|