[v3,4/5] Add tests for C/C++ musttail attributes
Checks
Commit Message
Mostly adopted from the existing C musttail plugin tests.
---
gcc/testsuite/c-c++-common/musttail1.c | 17 ++++++++++++
gcc/testsuite/c-c++-common/musttail2.c | 36 +++++++++++++++++++++++++
gcc/testsuite/c-c++-common/musttail3.c | 31 +++++++++++++++++++++
gcc/testsuite/c-c++-common/musttail4.c | 19 +++++++++++++
gcc/testsuite/gcc.dg/musttail-invalid.c | 17 ++++++++++++
5 files changed, 120 insertions(+)
create mode 100644 gcc/testsuite/c-c++-common/musttail1.c
create mode 100644 gcc/testsuite/c-c++-common/musttail2.c
create mode 100644 gcc/testsuite/c-c++-common/musttail3.c
create mode 100644 gcc/testsuite/c-c++-common/musttail4.c
create mode 100644 gcc/testsuite/gcc.dg/musttail-invalid.c
Comments
On Wed, 31 Jan 2024 at 07:49, Andi Kleen <ak@linux.intel.com> wrote:
>
> Mostly adopted from the existing C musttail plugin tests.
> ---
> gcc/testsuite/c-c++-common/musttail1.c | 17 ++++++++++++
> gcc/testsuite/c-c++-common/musttail2.c | 36 +++++++++++++++++++++++++
> gcc/testsuite/c-c++-common/musttail3.c | 31 +++++++++++++++++++++
> gcc/testsuite/c-c++-common/musttail4.c | 19 +++++++++++++
> gcc/testsuite/gcc.dg/musttail-invalid.c | 17 ++++++++++++
> 5 files changed, 120 insertions(+)
> create mode 100644 gcc/testsuite/c-c++-common/musttail1.c
> create mode 100644 gcc/testsuite/c-c++-common/musttail2.c
> create mode 100644 gcc/testsuite/c-c++-common/musttail3.c
> create mode 100644 gcc/testsuite/c-c++-common/musttail4.c
> create mode 100644 gcc/testsuite/gcc.dg/musttail-invalid.c
>
> diff --git a/gcc/testsuite/c-c++-common/musttail1.c b/gcc/testsuite/c-c++-common/musttail1.c
> new file mode 100644
> index 000000000000..476185e3ed4b
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/musttail1.c
> @@ -0,0 +1,17 @@
> +/* { dg-do compile { target tail_call } } */
> +/* { dg-options "-O2" } */
> +/* { dg-additional-options "-std=c++11" { target c++ } } */
> +/* { dg-additional-options "-std=c23" { target c } } */
> +/* { dg-additional-options "-fdelayed-branch" { target sparc*-*-* } } */
> +
> +int __attribute__((noinline,noclone))
Hi,
Sorry to nitpick -- Just wondering if it'd be slightly better to use
noipa attribute instead, assuming the intent is to disable IPA opts ?
Thanks,
Prathamesh
> +callee (int i)
> +{
> + return i * i;
> +}
> +
> +int __attribute__((noinline,noclone))
> +caller (int i)
> +{
> + [[gnu::musttail]] return callee (i + 1);
> +}
> diff --git a/gcc/testsuite/c-c++-common/musttail2.c b/gcc/testsuite/c-c++-common/musttail2.c
> new file mode 100644
> index 000000000000..28f2f68ef13d
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/musttail2.c
> @@ -0,0 +1,36 @@
> +/* { dg-do compile { target tail_call } } */
> +/* { dg-additional-options "-std=c++11" { target c++ } } */
> +/* { dg-additional-options "-std=c23" { target c } } */
> +
> +struct box { char field[256]; int i; };
> +
> +int __attribute__((noinline,noclone))
> +test_2_callee (int i, struct box b)
> +{
> + if (b.field[0])
> + return 5;
> + return i * i;
> +}
> +
> +int __attribute__((noinline,noclone))
> +test_2_caller (int i)
> +{
> + struct box b;
> + [[gnu::musttail]] return test_2_callee (i + 1, b); /* { dg-error "cannot tail-call: " } */
> +}
> +
> +extern void setjmp (void);
> +void
> +test_3 (void)
> +{
> + [[gnu::musttail]] return setjmp (); /* { dg-error "cannot tail-call: " } */
> +}
> +
> +typedef void (fn_ptr_t) (void);
> +volatile fn_ptr_t fn_ptr;
> +
> +void
> +test_5 (void)
> +{
> + [[gnu::musttail]] return fn_ptr (); /* { dg-error "cannot tail-call: " } */
> +}
> diff --git a/gcc/testsuite/c-c++-common/musttail3.c b/gcc/testsuite/c-c++-common/musttail3.c
> new file mode 100644
> index 000000000000..fdbb292944ad
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/musttail3.c
> @@ -0,0 +1,31 @@
> +/* { dg-do compile { target tail_call } } */
> +/* { dg-additional-options "-std=c++11" { target c++ } } */
> +/* { dg-additional-options "-std=c23" { target c } } */
> +
> +extern int foo2 (int x, ...);
> +
> +struct str
> +{
> + int a, b;
> +};
> +
> +struct str
> +cstruct (int x)
> +{
> + if (x < 10)
> + [[clang::musttail]] return cstruct (x + 1);
> + return ((struct str){ x, 0 });
> +}
> +
> +int
> +foo (int x)
> +{
> + if (x < 10)
> + [[clang::musttail]] return foo2 (x, 29);
> + if (x < 100)
> + {
> + int k = foo (x + 1);
> + [[clang::musttail]] return k; /* { dg-error "cannot tail-call: " } */
> + }
> + return x;
> +}
> diff --git a/gcc/testsuite/c-c++-common/musttail4.c b/gcc/testsuite/c-c++-common/musttail4.c
> new file mode 100644
> index 000000000000..7bf44816f14a
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/musttail4.c
> @@ -0,0 +1,19 @@
> +/* { dg-do compile { target tail_call } } */
> +/* { dg-additional-options "-std=c++11" { target c++ } } */
> +/* { dg-additional-options "-std=c23" { target c } } */
> +
> +struct box { char field[64]; int i; };
> +
> +struct box __attribute__((noinline,noclone))
> +returns_struct (int i)
> +{
> + struct box b;
> + b.i = i * i;
> + return b;
> +}
> +
> +int __attribute__((noinline,noclone))
> +test_1 (int i)
> +{
> + [[gnu::musttail]] return returns_struct (i * 5).i; /* { dg-error "cannot tail-call: " } */
> +}
> diff --git a/gcc/testsuite/gcc.dg/musttail-invalid.c b/gcc/testsuite/gcc.dg/musttail-invalid.c
> new file mode 100644
> index 000000000000..c4725b4b8226
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/musttail-invalid.c
> @@ -0,0 +1,17 @@
> +/* { dg-do compile } */
> +/* { dg-options "-std=c23" } */
> +
> +[[musttail]] int j; /* { dg-warning "attribute ignored" } */
> +__attribute__((musttail)) int k; /* { dg-warning "attribute directive ignored" } */
> +
> +void foo(void)
> +{
> + [[musttail]] j++; /* { dg-warning "attribute ignored" } */
> + [[musttail]] if (k > 0) /* { dg-warning "attribute ignored" } */
> + [[musttail]] k++; /* { dg-warning "attribute ignored" } */
> +}
> +
> +int foo2(int p)
> +{
> + [[gnu::musttail(1)]] return foo2(p + 1); /* { dg-error "has arguments" } */
> +}
> --
> 2.43.0
>
On Tue, Jan 30, 2024 at 06:17:17PM -0800, Andi Kleen wrote:
> Mostly adopted from the existing C musttail plugin tests.
Please add a ChangeLog entry.
> ---
> gcc/testsuite/c-c++-common/musttail1.c | 17 ++++++++++++
> gcc/testsuite/c-c++-common/musttail2.c | 36 +++++++++++++++++++++++++
> gcc/testsuite/c-c++-common/musttail3.c | 31 +++++++++++++++++++++
> gcc/testsuite/c-c++-common/musttail4.c | 19 +++++++++++++
> gcc/testsuite/gcc.dg/musttail-invalid.c | 17 ++++++++++++
> 5 files changed, 120 insertions(+)
> create mode 100644 gcc/testsuite/c-c++-common/musttail1.c
> create mode 100644 gcc/testsuite/c-c++-common/musttail2.c
> create mode 100644 gcc/testsuite/c-c++-common/musttail3.c
> create mode 100644 gcc/testsuite/c-c++-common/musttail4.c
> create mode 100644 gcc/testsuite/gcc.dg/musttail-invalid.c
>
> diff --git a/gcc/testsuite/c-c++-common/musttail1.c b/gcc/testsuite/c-c++-common/musttail1.c
> new file mode 100644
> index 000000000000..476185e3ed4b
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/musttail1.c
> @@ -0,0 +1,17 @@
> +/* { dg-do compile { target tail_call } } */
> +/* { dg-options "-O2" } */
> +/* { dg-additional-options "-std=c++11" { target c++ } } */
This will run the test only once with -std=c++11. We'll get better coverage
with dropping the line above and using
/* { dg-do compile { target { tail_call && { c || c++11 } } } } */
but here it may not matter.
> +/* { dg-additional-options "-std=c23" { target c } } */
> +/* { dg-additional-options "-fdelayed-branch" { target sparc*-*-* } } */
> +
> +int __attribute__((noinline,noclone))
> +callee (int i)
> +{
> + return i * i;
> +}
> +
> +int __attribute__((noinline,noclone))
> +caller (int i)
> +{
> + [[gnu::musttail]] return callee (i + 1);
> +}
> diff --git a/gcc/testsuite/c-c++-common/musttail2.c b/gcc/testsuite/c-c++-common/musttail2.c
> new file mode 100644
> index 000000000000..28f2f68ef13d
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/musttail2.c
> @@ -0,0 +1,36 @@
> +/* { dg-do compile { target tail_call } } */
> +/* { dg-additional-options "-std=c++11" { target c++ } } */
> +/* { dg-additional-options "-std=c23" { target c } } */
> +
> +struct box { char field[256]; int i; };
> +
> +int __attribute__((noinline,noclone))
> +test_2_callee (int i, struct box b)
> +{
> + if (b.field[0])
> + return 5;
> + return i * i;
> +}
> +
> +int __attribute__((noinline,noclone))
> +test_2_caller (int i)
> +{
> + struct box b;
> + [[gnu::musttail]] return test_2_callee (i + 1, b); /* { dg-error "cannot tail-call: " } */
> +}
> +
> +extern void setjmp (void);
> +void
> +test_3 (void)
> +{
> + [[gnu::musttail]] return setjmp (); /* { dg-error "cannot tail-call: " } */
> +}
> +
> +typedef void (fn_ptr_t) (void);
> +volatile fn_ptr_t fn_ptr;
> +
> +void
> +test_5 (void)
> +{
> + [[gnu::musttail]] return fn_ptr (); /* { dg-error "cannot tail-call: " } */
> +}
> diff --git a/gcc/testsuite/c-c++-common/musttail3.c b/gcc/testsuite/c-c++-common/musttail3.c
> new file mode 100644
> index 000000000000..fdbb292944ad
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/musttail3.c
> @@ -0,0 +1,31 @@
> +/* { dg-do compile { target tail_call } } */
> +/* { dg-additional-options "-std=c++11" { target c++ } } */
> +/* { dg-additional-options "-std=c23" { target c } } */
> +
> +extern int foo2 (int x, ...);
> +
> +struct str
> +{
> + int a, b;
> +};
> +
> +struct str
> +cstruct (int x)
> +{
> + if (x < 10)
> + [[clang::musttail]] return cstruct (x + 1);
> + return ((struct str){ x, 0 });
> +}
> +
> +int
> +foo (int x)
> +{
> + if (x < 10)
> + [[clang::musttail]] return foo2 (x, 29);
> + if (x < 100)
> + {
> + int k = foo (x + 1);
> + [[clang::musttail]] return k; /* { dg-error "cannot tail-call: " } */
> + }
> + return x;
> +}
> diff --git a/gcc/testsuite/c-c++-common/musttail4.c b/gcc/testsuite/c-c++-common/musttail4.c
> new file mode 100644
> index 000000000000..7bf44816f14a
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/musttail4.c
> @@ -0,0 +1,19 @@
> +/* { dg-do compile { target tail_call } } */
> +/* { dg-additional-options "-std=c++11" { target c++ } } */
> +/* { dg-additional-options "-std=c23" { target c } } */
> +
> +struct box { char field[64]; int i; };
> +
> +struct box __attribute__((noinline,noclone))
> +returns_struct (int i)
> +{
> + struct box b;
> + b.i = i * i;
> + return b;
> +}
> +
> +int __attribute__((noinline,noclone))
> +test_1 (int i)
> +{
> + [[gnu::musttail]] return returns_struct (i * 5).i; /* { dg-error "cannot tail-call: " } */
> +}
> diff --git a/gcc/testsuite/gcc.dg/musttail-invalid.c b/gcc/testsuite/gcc.dg/musttail-invalid.c
> new file mode 100644
> index 000000000000..c4725b4b8226
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/musttail-invalid.c
Is there a C++ test for the invalid cases?
> @@ -0,0 +1,17 @@
> +/* { dg-do compile } */
> +/* { dg-options "-std=c23" } */
> +
> +[[musttail]] int j; /* { dg-warning "attribute ignored" } */
> +__attribute__((musttail)) int k; /* { dg-warning "attribute directive ignored" } */
> +
> +void foo(void)
> +{
> + [[musttail]] j++; /* { dg-warning "attribute ignored" } */
> + [[musttail]] if (k > 0) /* { dg-warning "attribute ignored" } */
> + [[musttail]] k++; /* { dg-warning "attribute ignored" } */
> +}
> +
> +int foo2(int p)
> +{
> + [[gnu::musttail(1)]] return foo2(p + 1); /* { dg-error "has arguments" } */
> +}
> --
> 2.43.0
>
Marek
> This will run the test only once with -std=c++11. We'll get better coverage
> with dropping the line above and using
>
> /* { dg-do compile { target { tail_call && { c || c++11 } } } } */
>
> but here it may not matter.
The problem is that older C/C++ standards don't support [[]] attributes.
It would make sense to say >= gnu++11 || >= c23 but I don't know how to
express that.
On Wed, Jan 31, 2024 at 11:39:56PM -0800, Andi Kleen wrote:
> > This will run the test only once with -std=c++11. We'll get better coverage
> > with dropping the line above and using
> >
> > /* { dg-do compile { target { tail_call && { c || c++11 } } } } */
> >
> > but here it may not matter.
>
> The problem is that older C/C++ standards don't support [[]] attributes.
> It would make sense to say >= gnu++11 || >= c23 but I don't know how to
> express that.
That's what the c++11 target does. Unfortunately for C we don't have
anything like that, hence the additional-options adding c23.
Marek
On Thu, 1 Feb 2024, Marek Polacek wrote:
> On Wed, Jan 31, 2024 at 11:39:56PM -0800, Andi Kleen wrote:
> > > This will run the test only once with -std=c++11. We'll get better coverage
> > > with dropping the line above and using
> > >
> > > /* { dg-do compile { target { tail_call && { c || c++11 } } } } */
> > >
> > > but here it may not matter.
> >
> > The problem is that older C/C++ standards don't support [[]] attributes.
> > It would make sense to say >= gnu++11 || >= c23 but I don't know how to
> > express that.
>
> That's what the c++11 target does. Unfortunately for C we don't have
> anything like that, hence the additional-options adding c23.
For C we don't loop over the testsuite building with different standard
options - such a conditional only makes sense for C++ in the context of
building the same tests several times for different standards, when some
tests need to be conditional on the standard for which they are built.
new file mode 100644
@@ -0,0 +1,17 @@
+/* { dg-do compile { target tail_call } } */
+/* { dg-options "-O2" } */
+/* { dg-additional-options "-std=c++11" { target c++ } } */
+/* { dg-additional-options "-std=c23" { target c } } */
+/* { dg-additional-options "-fdelayed-branch" { target sparc*-*-* } } */
+
+int __attribute__((noinline,noclone))
+callee (int i)
+{
+ return i * i;
+}
+
+int __attribute__((noinline,noclone))
+caller (int i)
+{
+ [[gnu::musttail]] return callee (i + 1);
+}
new file mode 100644
@@ -0,0 +1,36 @@
+/* { dg-do compile { target tail_call } } */
+/* { dg-additional-options "-std=c++11" { target c++ } } */
+/* { dg-additional-options "-std=c23" { target c } } */
+
+struct box { char field[256]; int i; };
+
+int __attribute__((noinline,noclone))
+test_2_callee (int i, struct box b)
+{
+ if (b.field[0])
+ return 5;
+ return i * i;
+}
+
+int __attribute__((noinline,noclone))
+test_2_caller (int i)
+{
+ struct box b;
+ [[gnu::musttail]] return test_2_callee (i + 1, b); /* { dg-error "cannot tail-call: " } */
+}
+
+extern void setjmp (void);
+void
+test_3 (void)
+{
+ [[gnu::musttail]] return setjmp (); /* { dg-error "cannot tail-call: " } */
+}
+
+typedef void (fn_ptr_t) (void);
+volatile fn_ptr_t fn_ptr;
+
+void
+test_5 (void)
+{
+ [[gnu::musttail]] return fn_ptr (); /* { dg-error "cannot tail-call: " } */
+}
new file mode 100644
@@ -0,0 +1,31 @@
+/* { dg-do compile { target tail_call } } */
+/* { dg-additional-options "-std=c++11" { target c++ } } */
+/* { dg-additional-options "-std=c23" { target c } } */
+
+extern int foo2 (int x, ...);
+
+struct str
+{
+ int a, b;
+};
+
+struct str
+cstruct (int x)
+{
+ if (x < 10)
+ [[clang::musttail]] return cstruct (x + 1);
+ return ((struct str){ x, 0 });
+}
+
+int
+foo (int x)
+{
+ if (x < 10)
+ [[clang::musttail]] return foo2 (x, 29);
+ if (x < 100)
+ {
+ int k = foo (x + 1);
+ [[clang::musttail]] return k; /* { dg-error "cannot tail-call: " } */
+ }
+ return x;
+}
new file mode 100644
@@ -0,0 +1,19 @@
+/* { dg-do compile { target tail_call } } */
+/* { dg-additional-options "-std=c++11" { target c++ } } */
+/* { dg-additional-options "-std=c23" { target c } } */
+
+struct box { char field[64]; int i; };
+
+struct box __attribute__((noinline,noclone))
+returns_struct (int i)
+{
+ struct box b;
+ b.i = i * i;
+ return b;
+}
+
+int __attribute__((noinline,noclone))
+test_1 (int i)
+{
+ [[gnu::musttail]] return returns_struct (i * 5).i; /* { dg-error "cannot tail-call: " } */
+}
new file mode 100644
@@ -0,0 +1,17 @@
+/* { dg-do compile } */
+/* { dg-options "-std=c23" } */
+
+[[musttail]] int j; /* { dg-warning "attribute ignored" } */
+__attribute__((musttail)) int k; /* { dg-warning "attribute directive ignored" } */
+
+void foo(void)
+{
+ [[musttail]] j++; /* { dg-warning "attribute ignored" } */
+ [[musttail]] if (k > 0) /* { dg-warning "attribute ignored" } */
+ [[musttail]] k++; /* { dg-warning "attribute ignored" } */
+}
+
+int foo2(int p)
+{
+ [[gnu::musttail(1)]] return foo2(p + 1); /* { dg-error "has arguments" } */
+}