diff options
Diffstat (limited to 'gcc/testsuite/gcc.dg/tree-prof')
19 files changed, 770 insertions, 11 deletions
diff --git a/gcc/testsuite/gcc.dg/tree-prof/20041218-1.c b/gcc/testsuite/gcc.dg/tree-prof/20041218-1.c new file mode 100644 index 0000000000..cbd1c7c80e --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-prof/20041218-1.c @@ -0,0 +1,119 @@ +/* PR rtl-optimization/16968 */ +/* Testcase by Jakub Jelinek <jakub@redhat.com> */ +/* { dg-require-effective-target freorder } */ +/* { dg-options "-O2 -freorder-blocks-and-partition" } */ + +struct T +{ + unsigned int b, c, *d; + unsigned char e; +}; +struct S +{ + unsigned int a; + struct T f; +}; +struct U +{ + struct S g, h; +}; +struct V +{ + unsigned int i; + struct U j; +}; + +extern void exit (int); +extern void abort (void); + +void * +dummy1 (void *x) +{ + return ""; +} + +void * +dummy2 (void *x, void *y) +{ + exit (0); +} + +struct V * +baz (unsigned int x) +{ + static struct V v; + __builtin_memset (&v, 0x55, sizeof (v)); + return &v; +} + +int +check (void *x, struct S *y) +{ + if (y->a || y->f.b || y->f.c || y->f.d || y->f.e) + abort (); + return 1; +} + +static struct V * +bar (unsigned int x, void *y) +{ + const struct T t = { 0, 0, (void *) 0, 0 }; + struct V *u; + void *v; + v = dummy1 (y); + if (!v) + return (void *) 0; + + u = baz (sizeof (struct V)); + u->i = x; + u->j.g.a = 0; + u->j.g.f = t; + u->j.h.a = 0; + u->j.h.f = t; + + if (!check (v, &u->j.g) || !check (v, &u->j.h)) + return (void *) 0; + return u; +} + +int +foo (unsigned int *x, unsigned int y, void **z) +{ + void *v; + unsigned int i, j; + + *z = v = (void *) 0; + + for (i = 0; i < y; i++) + { + struct V *c; + + j = *x; + + switch (j) + { + case 1: + c = bar (j, x); + break; + default: + c = 0; + break; + } + if (c) + v = dummy2 (v, c); + else + return 1; + } + + *z = v; + return 0; +} + +int +main (void) +{ + unsigned int one = 1; + void *p; + foo (&one, 1, &p); + abort (); +} diff --git a/gcc/testsuite/gcc.dg/tree-prof/cold_partition_label.c b/gcc/testsuite/gcc.dg/tree-prof/cold_partition_label.c new file mode 100644 index 0000000000..a03aad7f6d --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-prof/cold_partition_label.c @@ -0,0 +1,38 @@ +/* Test case to check if function foo gets split and the cold function + gets a label. */ +/* { dg-require-effective-target freorder } */ +/* { dg-options "-O2 -freorder-blocks-and-partition -save-temps" } */ + +#define SIZE 10000 + +const char *sarr[SIZE]; +const char *buf_hot; +const char *buf_cold; + +__attribute__((noinline)) +void +foo (int path) +{ + int i; + if (path) + { + for (i = 0; i < SIZE; i++) + sarr[i] = buf_hot; + } + else + { + for (i = 0; i < SIZE; i++) + sarr[i] = buf_cold; + } +} + +int +main (int argc, char *argv[]) +{ + buf_hot = "hello"; + buf_cold = "world"; + foo (argc); + return 0; +} + +/* { dg-final-use { cleanup-saved-temps } } */ diff --git a/gcc/testsuite/gcc.dg/tree-prof/comp-goto-1.c b/gcc/testsuite/gcc.dg/tree-prof/comp-goto-1.c new file mode 100644 index 0000000000..bbfe1f4728 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-prof/comp-goto-1.c @@ -0,0 +1,166 @@ +/* { dg-require-effective-target freorder } */ +/* { dg-options "-O2 -freorder-blocks-and-partition" } */ +#include <stdlib.h> + +#if !defined(NO_LABEL_VALUES) && (!defined(STACK_SIZE) || STACK_SIZE >= 4000) && __INT_MAX__ >= 2147483647 +typedef unsigned int uint32; +typedef signed int sint32; + +typedef uint32 reg_t; + +typedef unsigned long int host_addr_t; +typedef uint32 target_addr_t; +typedef sint32 target_saddr_t; + +typedef union +{ + struct + { + unsigned int offset:18; + unsigned int ignore:4; + unsigned int s1:8; + int :2; + signed int simm:14; + unsigned int s3:8; + unsigned int s2:8; + int pad2:2; + } f1; + long long ll; + double d; +} insn_t; + +typedef struct +{ + target_addr_t vaddr_tag; + unsigned long int rigged_paddr; +} tlb_entry_t; + +typedef struct +{ + insn_t *pc; + reg_t registers[256]; + insn_t *program; + tlb_entry_t tlb_tab[0x100]; +} environment_t; + +enum operations +{ + LOAD32_RR, + METAOP_DONE +}; + +host_addr_t +f () +{ + abort (); +} + +reg_t +simulator_kernel (int what, environment_t *env) +{ + register insn_t *pc = env->pc; + register reg_t *regs = env->registers; + register insn_t insn; + register int s1; + register reg_t r2; + register void *base_addr = &&sim_base_addr; + register tlb_entry_t *tlb = env->tlb_tab; + + if (what != 0) + { + int i; + static void *op_map[] = + { + &&L_LOAD32_RR, + &&L_METAOP_DONE, + }; + insn_t *program = env->program; + for (i = 0; i < what; i++) + program[i].f1.offset = op_map[program[i].f1.offset] - base_addr; + } + + sim_base_addr:; + + insn = *pc++; + r2 = (*(reg_t *) (((char *) regs) + (insn.f1.s2 << 2))); + s1 = (insn.f1.s1 << 2); + goto *(base_addr + insn.f1.offset); + + L_LOAD32_RR: + { + target_addr_t vaddr_page = r2 / 4096; + unsigned int x = vaddr_page % 0x100; + insn = *pc++; + + for (;;) + { + target_addr_t tag = tlb[x].vaddr_tag; + host_addr_t rigged_paddr = tlb[x].rigged_paddr; + + if (tag == vaddr_page) + { + *(reg_t *) (((char *) regs) + s1) = *(uint32 *) (rigged_paddr + r2); + r2 = *(reg_t *) (((char *) regs) + (insn.f1.s2 << 2)); + s1 = insn.f1.s1 << 2; + goto *(base_addr + insn.f1.offset); + } + + if (((target_saddr_t) tag < 0)) + { + *(reg_t *) (((char *) regs) + s1) = *(uint32 *) f (); + r2 = *(reg_t *) (((char *) regs) + (insn.f1.s2 << 2)); + s1 = insn.f1.s1 << 2; + goto *(base_addr + insn.f1.offset); + } + + x = (x - 1) % 0x100; + } + + L_METAOP_DONE: + return (*(reg_t *) (((char *) regs) + s1)); + } +} + +insn_t program[2 + 1]; + +void *malloc (); + +int +main () +{ + environment_t env; + insn_t insn; + int i, res; + host_addr_t a_page = (host_addr_t) malloc (2 * 4096); + target_addr_t a_vaddr = 0x123450; + target_addr_t vaddr_page = a_vaddr / 4096; + a_page = (a_page + 4096 - 1) & -4096; + + env.tlb_tab[((vaddr_page) % 0x100)].vaddr_tag = vaddr_page; + env.tlb_tab[((vaddr_page) % 0x100)].rigged_paddr = a_page - vaddr_page * 4096; + insn.f1.offset = LOAD32_RR; + env.registers[0] = 0; + env.registers[2] = a_vaddr; + *(sint32 *) (a_page + a_vaddr % 4096) = 88; + insn.f1.s1 = 0; + insn.f1.s2 = 2; + + for (i = 0; i < 2; i++) + program[i] = insn; + + insn.f1.offset = METAOP_DONE; + insn.f1.s1 = 0; + program[2] = insn; + + env.pc = program; + env.program = program; + + res = simulator_kernel (2 + 1, &env); + + if (res != 88) + abort (); + exit (0); +} +#else +main(){ exit (0); } +#endif diff --git a/gcc/testsuite/gcc.dg/tree-prof/crossmodule-indircall-1.c b/gcc/testsuite/gcc.dg/tree-prof/crossmodule-indircall-1.c new file mode 100644 index 0000000000..67a76c9f1e --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-prof/crossmodule-indircall-1.c @@ -0,0 +1,21 @@ +/* { dg-require-effective-target lto } */ +/* { dg-additional-sources "crossmodule-indircall-1a.c" } */ +/* { dg-options "-O3 -flto -DDOJOB=1" } */ + +int a; +extern void (*p[2])(int n); +void abort (void); +main() +{ int i; + + /* This call shall be converted. */ + for (i = 0;i<1000;i++) + p[0](1); + /* This call shall not be converted. */ + for (i = 0;i<1000;i++) + p[i%2](2); + if (a != 1000) + abort (); + + return 0; +} diff --git a/gcc/testsuite/gcc.dg/tree-prof/crossmodule-indircall-1a.c b/gcc/testsuite/gcc.dg/tree-prof/crossmodule-indircall-1a.c new file mode 100644 index 0000000000..a94195cd95 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-prof/crossmodule-indircall-1a.c @@ -0,0 +1,40 @@ +/* It seems there is no way to avoid the other source of mulitple + source testcase from being compiled independently. Just avoid + error. */ +#ifdef DOJOB +extern int a; +void abort (void); + +#ifdef _PROFILE_USE +__attribute__ ((externally_visible)) +int constval=1,constval2=2; +#else +__attribute__ ((externally_visible)) +int constval=3,constval2=2; +#endif + + +void +add(int i) +{ + /* Verify that inlining happens for first case. */ + if (i==constval && !__builtin_constant_p (i)) + abort (); + /* Second case has no dominating target; it should not inline. */ + if (i==constval2 && __builtin_constant_p (i)) + abort (); + a += i; +} +void +sub(int i) +{ + a -= i; +} +__attribute__ ((externally_visible)) +void (*p[2])(int)={add, sub}; +#else +main() +{ + return 0; +} +#endif diff --git a/gcc/testsuite/gcc.dg/tree-prof/inliner-1.c b/gcc/testsuite/gcc.dg/tree-prof/inliner-1.c index b5340b56d7..e44887b529 100644 --- a/gcc/testsuite/gcc.dg/tree-prof/inliner-1.c +++ b/gcc/testsuite/gcc.dg/tree-prof/inliner-1.c @@ -36,7 +36,7 @@ main () /* cold function should be inlined, while hot function should not. Look for "cold_function () [tail call];" call statement not for the - declaration or other apperances of the string in dump. */ + declaration or other appearances of the string in dump. */ /* { dg-final-use { scan-tree-dump "cold_function ..;" "optimized"} } */ /* { dg-final-use { scan-tree-dump-not "hot_function ..;" "optimized"} } */ /* { dg-final-use { cleanup-tree-dump "optimized" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-prof/peel-1.c b/gcc/testsuite/gcc.dg/tree-prof/peel-1.c new file mode 100644 index 0000000000..65f0c562cd --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-prof/peel-1.c @@ -0,0 +1,25 @@ +/* { dg-options "-O3 -fdump-rtl-loop2_unroll -fno-unroll-loops -fpeel-loops" } */ +void abort(); + +int a[1000]; +int +__attribute__ ((noinline)) +t() +{ + int i; + for (i=0;i<1000;i++) + if (!a[i]) + return 1; + abort (); +} +main() +{ + int i; + for (i=0;i<1000;i++) + t(); + return 0; +} +/* { dg-final-use { scan-rtl-dump "Considering simply peeling loop" "loop2_unroll" } } */ +/* In fact one peeling is enough; we however mispredict number of iterations of the loop + at least until loop_ch is schedule ahead of profiling pass. */ +/* { dg-final-use { cleanup-rtl-dump "loop2_unroll" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-prof/pr45354.c b/gcc/testsuite/gcc.dg/tree-prof/pr45354.c index b30ad77694..849e786bb2 100644 --- a/gcc/testsuite/gcc.dg/tree-prof/pr45354.c +++ b/gcc/testsuite/gcc.dg/tree-prof/pr45354.c @@ -1,5 +1,5 @@ /* { dg-require-effective-target freorder } */ -/* { dg-options "-O -freorder-blocks-and-partition -fschedule-insns -fselective-scheduling" { target powerpc*-*-* ia64-*-* x86_64-*-* } } */ +/* { dg-options "-O2 -freorder-blocks-and-partition -fschedule-insns -fselective-scheduling" { target powerpc*-*-* ia64-*-* x86_64-*-* } } */ extern void abort (void); diff --git a/gcc/testsuite/gcc.dg/tree-prof/pr50907.c b/gcc/testsuite/gcc.dg/tree-prof/pr50907.c index 2ba26e392c..b850513a13 100644 --- a/gcc/testsuite/gcc.dg/tree-prof/pr50907.c +++ b/gcc/testsuite/gcc.dg/tree-prof/pr50907.c @@ -1,5 +1,5 @@ /* PR middle-end/50907 */ /* { dg-require-effective-target freorder } */ -/* { dg-options "-O -freorder-blocks-and-partition -fschedule-insns -fselective-scheduling -fpic" { target { { powerpc*-*-* ia64-*-* x86_64-*-* } && fpic } } } */ +/* { dg-options "-O2 -freorder-blocks-and-partition -fschedule-insns -fselective-scheduling -fpic" { target { { powerpc*-*-* ia64-*-* x86_64-*-* } && fpic } } } */ #include "pr45354.c" diff --git a/gcc/testsuite/gcc.dg/tree-prof/pr52027.c b/gcc/testsuite/gcc.dg/tree-prof/pr52027.c index c12f8b484e..c46a14b2e8 100644 --- a/gcc/testsuite/gcc.dg/tree-prof/pr52027.c +++ b/gcc/testsuite/gcc.dg/tree-prof/pr52027.c @@ -1,6 +1,6 @@ /* PR debug/52027 */ /* { dg-require-effective-target freorder } */ -/* { dg-options "-O -freorder-blocks-and-partition -fno-reorder-functions" } */ +/* { dg-options "-O2 -freorder-blocks-and-partition -fno-reorder-functions" } */ void foo (int len) diff --git a/gcc/testsuite/gcc.dg/tree-prof/pr59003.c b/gcc/testsuite/gcc.dg/tree-prof/pr59003.c new file mode 100644 index 0000000000..1c7d5e07fb --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-prof/pr59003.c @@ -0,0 +1,30 @@ +/* PR target/59003 */ +/* { dg-options "-O2" } */ +/* { dg-options "-O2 -mtune=amdfam10" { target i?86-*-* x86_64-*-* } } */ +/* { dg-options "-O2 -fno-common" { target hppa*-*-hpux* } } */ + +__attribute__((noinline, noclone)) void * +foo (void *p, unsigned int q) +{ + return __builtin_memset (p, 0, q * 4UL); +} + +char buf[128] __attribute__((aligned (32))); + +int +main () +{ + int i; + for (i = 0; i < 100000; i++) + foo (buf + 4, 1 + (i & 1)); + for (i = 0; i < 128; i++) + { + buf[i] = 'X'; + asm volatile ("" : : : "memory"); + } + foo (buf + 32, 7); + for (i = 0; i < 128; i++) + if (buf[i] != ((i < 32 || i >= 32 + 28) ? 'X' : 0)) + __builtin_abort (); + return 0; +} diff --git a/gcc/testsuite/gcc.dg/tree-prof/switch-case-1.c b/gcc/testsuite/gcc.dg/tree-prof/switch-case-1.c new file mode 100644 index 0000000000..50ee9e44fd --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-prof/switch-case-1.c @@ -0,0 +1,40 @@ +/* { dg-options "-O2 -fdump-rtl-expand-all" } */ +int g; + +__attribute__((noinline)) void foo (int n) +{ + switch (n) + { + case 1: + g++; break; + case 2: + g += 2; break; + case 3: + g += 1; break; + case 4: + g += 3; break; + case 5: + g += 4; break; + case 6: + g += 5; break; + case 7: + g += 6; break; + case 8: + g += 7; break; + case 9: + g += 8; break; + default: + g += 8; break; + } +} + +int main () +{ + int i; + for (i = 0; i < 10000; i++) + foo ((i * i) % 5); + return 0; +} +/* { dg-final-use { scan-rtl-dump-times ";; basic block\[^\\n\]*count 4000" 2 "expand"} } */ +/* { dg-final-use { scan-rtl-dump-times ";; basic block\[^\\n\]*count 2000" 1 "expand"} } */ +/* { dg-final-use { cleanup-rtl-dump "expand" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-prof/switch-case-2.c b/gcc/testsuite/gcc.dg/tree-prof/switch-case-2.c new file mode 100644 index 0000000000..07d4363d39 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-prof/switch-case-2.c @@ -0,0 +1,40 @@ +/* { dg-options "-O2 -fdump-rtl-expand-all" } */ +int g; + +__attribute__((noinline)) void foo (int n) +{ + switch (n) + { + case 99: + g += 2; break; + case 1: + g++; break; + case 100: + g += 1; break; + case 4: + g += 3; break; + case 5: + g += 4; break; + case 6: + g += 5; break; + case 7: + g += 6; break; + case 8: + g += 7; break; + case 9: + g += 8; break; + default: + g += 8; break; + } +} + +int main () +{ + int i; + for (i = 0; i < 10000; i++) + foo ((i * i) % 5); + return 0; +} +/* { dg-final-use { scan-rtl-dump-times ";; basic block\[^\\n\]*count 4000" 2 "expand"} } */ +/* { dg-final-use { scan-rtl-dump-times ";; basic block\[^\\n\]*count 2000" 1 "expand"} } */ +/* { dg-final-use { cleanup-rtl-dump "expand" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-prof/time-profiler-1.c b/gcc/testsuite/gcc.dg/tree-prof/time-profiler-1.c new file mode 100644 index 0000000000..c61b534a25 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-prof/time-profiler-1.c @@ -0,0 +1,22 @@ +/* { dg-options "-O2 -fdump-ipa-profile" } */ + +__attribute__ ((noinline)) +int foo() +{ + return 0; +} + +__attribute__ ((noinline)) +int bar() +{ + return 1; +} + +int main () +{ + return foo (); +} +/* { dg-final-use { scan-ipa-dump-times "Read tp_first_run: 0" 1 "profile"} } */ +/* { dg-final-use { scan-ipa-dump-times "Read tp_first_run: 1" 1 "profile"} } */ +/* { dg-final-use { scan-ipa-dump-times "Read tp_first_run: 2" 1 "profile"} } */ +/* { dg-final-use { cleanup-ipa-dump "profile" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-prof/time-profiler-2.c b/gcc/testsuite/gcc.dg/tree-prof/time-profiler-2.c new file mode 100644 index 0000000000..0411341975 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-prof/time-profiler-2.c @@ -0,0 +1,50 @@ +/* { dg-options "-O2 -fdump-ipa-profile" } */ + +#include <unistd.h> + +__attribute__ ((noinline)) +int foo() +{ + return 1; +} + +__attribute__ ((noinline)) +int bar() +{ + return 1; +} + +__attribute__ ((noinline)) +int baz() +{ + return 1; +} + +__attribute__ ((noinline)) +int baz1() +{ + return 1; +} + +int main () +{ + int f = fork(); + int r = 0; + + foo (); + + if (f < 0) + return 1; /* Fork failed. */ + + if(f == 0) /* Child process. */ + r = bar() - foo(); + else /* Parent process. */ + r = foo() - foo(); + + return r; +} +/* { dg-final-use { scan-ipa-dump-times "Read tp_first_run: 0" 2 "profile"} } */ +/* { dg-final-use { scan-ipa-dump-times "Read tp_first_run: 1" 1 "profile"} } */ +/* { dg-final-use { scan-ipa-dump-times "Read tp_first_run: 2" 1 "profile"} } */ +/* { dg-final-use { scan-ipa-dump-times "Read tp_first_run: 3" 1 "profile"} } */ +/* { dg-final-use { cleanup-ipa-dump "profile" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-prof/tree-prof.exp b/gcc/testsuite/gcc.dg/tree-prof/tree-prof.exp index e3c5e3d048..454dfaeed2 100644 --- a/gcc/testsuite/gcc.dg/tree-prof/tree-prof.exp +++ b/gcc/testsuite/gcc.dg/tree-prof/tree-prof.exp @@ -1,5 +1,4 @@ -# Copyright (C) 2001, 2002, 2004, 2005, 2007, 2008, 2011 -# Free Software Foundation, Inc. +# Copyright (C) 2001-2014 Free Software Foundation, Inc. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -16,7 +15,7 @@ # <http://www.gnu.org/licenses/>. # Test the functionality of programs compiled with profile-directed block -# ordering using -fprofile-generate followed by -fbranch-use. +# ordering using -fprofile-generate followed by -fprofile-use. load_lib target-supports.exp diff --git a/gcc/testsuite/gcc.dg/tree-prof/unroll-1.c b/gcc/testsuite/gcc.dg/tree-prof/unroll-1.c new file mode 100644 index 0000000000..0663b1286d --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-prof/unroll-1.c @@ -0,0 +1,23 @@ +/* { dg-options "-O3 -fdump-rtl-loop2_unroll -funroll-loops -fno-peel-loops" } */ +void abort (); + +int a[1000]; +int +__attribute__ ((noinline)) +t() +{ + int i; + for (i=0;i<1000;i++) + if (!a[i]) + return 1; + abort (); +} +main() +{ + int i; + for (i=0;i<1000;i++) + t(); + return 0; +} +/* { dg-final-use { scan-rtl-dump "Considering unrolling loop with constant number of iterations" "loop2_unroll" } } */ +/* { dg-final-use { cleanup-rtl-dump "loop2_unroll" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-prof/update-loopch.c b/gcc/testsuite/gcc.dg/tree-prof/update-loopch.c index 2bce8a2e5f..5297098fc9 100644 --- a/gcc/testsuite/gcc.dg/tree-prof/update-loopch.c +++ b/gcc/testsuite/gcc.dg/tree-prof/update-loopch.c @@ -1,4 +1,4 @@ -/* { dg-options "-O2 -fdump-ipa-profile-blocks -fdump-tree-optimized-blocks" } */ +/* { dg-options "-O2 -fdump-ipa-profile-blocks-details -fdump-tree-optimized-blocks-details" } */ int max = 33333; int a[8]; int @@ -14,8 +14,9 @@ main () /* Loop header copying will peel away the initial conditional, so the loop body is once reached directly from entry point of function, rest via loopback edge. */ -/* { dg-final-use { scan-ipa-dump "count:33333" "profile"} } */ -/* { dg-final-use { scan-tree-dump "count:33332" "optimized"} } */ -/* { dg-final-use { scan-tree-dump-not "Invalid sum" "optimized"} } */ +/* { dg-final-use { scan-ipa-dump "loop depth 1, count 33334" "profile"} } */ +/* { dg-final-use { scan-tree-dump "loop depth 1, count 33332" "optimized"} } */ +/* { dg-final-use { scan-tree-dump-times "Removing basic block \[^\r\n\]*\[\\r\\n\]+\[^\r\n\]*\[\\r\\n\]+Invalid sum of\[^\r\n\]*\[\\r\\n\]+Invalid sum of" 1 "optimized"} } */ +/* { dg-final-use { scan-tree-dump-times "Invalid sum of" 2 "optimized"} } */ /* { dg-final-use { cleanup-ipa-dump "profile" } } */ /* { dg-final-use { cleanup-tree-dump "optimized" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-prof/va-arg-pack-1.c b/gcc/testsuite/gcc.dg/tree-prof/va-arg-pack-1.c new file mode 100644 index 0000000000..8d17dbfef8 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-prof/va-arg-pack-1.c @@ -0,0 +1,145 @@ +/* __builtin_va_arg_pack () builtin tests. */ +/* { dg-require-effective-target freorder } */ +/* { dg-options "-O2 -freorder-blocks-and-partition" } */ + +#include <stdarg.h> + +extern void abort (void); + +int v1 = 8; +long int v2 = 3; +void *v3 = (void *) &v2; +struct A { char c[16]; } v4 = { "foo" }; +long double v5 = 40; +char seen[20]; +int cnt; + +__attribute__ ((noinline)) int +foo1 (int x, int y, ...) +{ + int i; + long int l; + void *v; + struct A a; + long double ld; + va_list ap; + + va_start (ap, y); + if (x < 0 || x >= 20 || seen[x]) + abort (); + seen[x] = ++cnt; + if (y != 6) + abort (); + i = va_arg (ap, int); + if (i != 5) + abort (); + switch (x) + { + case 0: + i = va_arg (ap, int); + if (i != 9 || v1 != 9) + abort (); + a = va_arg (ap, struct A); + if (__builtin_memcmp (a.c, v4.c, sizeof (a.c)) != 0) + abort (); + v = (void *) va_arg (ap, struct A *); + if (v != (void *) &v4) + abort (); + l = va_arg (ap, long int); + if (l != 3 || v2 != 4) + abort (); + break; + case 1: + ld = va_arg (ap, long double); + if (ld != 41 || v5 != ld) + abort (); + i = va_arg (ap, int); + if (i != 8) + abort (); + v = va_arg (ap, void *); + if (v != &v2) + abort (); + break; + case 2: + break; + default: + abort (); + } + va_end (ap); + return x; +} + +__attribute__ ((noinline)) int +foo2 (int x, int y, ...) +{ + long long int ll; + void *v; + struct A a, b; + long double ld; + va_list ap; + + va_start (ap, y); + if (x < 0 || x >= 20 || seen[x]) + abort (); + seen[x] = ++cnt | 64; + if (y != 10) + abort (); + switch (x) + { + case 11: + break; + case 12: + ld = va_arg (ap, long double); + if (ld != 41 || v5 != 40) + abort (); + a = va_arg (ap, struct A); + if (__builtin_memcmp (a.c, v4.c, sizeof (a.c)) != 0) + abort (); + b = va_arg (ap, struct A); + if (__builtin_memcmp (b.c, v4.c, sizeof (b.c)) != 0) + abort (); + v = va_arg (ap, void *); + if (v != &v2) + abort (); + ll = va_arg (ap, long long int); + if (ll != 16LL) + abort (); + break; + case 2: + break; + default: + abort (); + } + va_end (ap); + return x + 8; +} + +__attribute__ ((noinline)) int +foo3 (void) +{ + return 6; +} + +extern inline __attribute__ ((always_inline, gnu_inline)) int +bar (int x, ...) +{ + if (x < 10) + return foo1 (x, foo3 (), 5, __builtin_va_arg_pack ()); + return foo2 (x, foo3 () + 4, __builtin_va_arg_pack ()); +} + +int +main (void) +{ + if (bar (0, ++v1, v4, &v4, v2++) != 0) + abort (); + if (bar (1, ++v5, 8, v3) != 1) + abort (); + if (bar (2) != 2) + abort (); + if (bar (v1 + 2) != 19) + abort (); + if (bar (v1 + 3, v5--, v4, v4, v3, 16LL) != 20) + abort (); + return 0; +} |