| /* Verify that simple indirect calls are inlined even without early |
| inlining.. */ |
| /* { dg-do run } */ |
| /* { dg-options "-O3 -fdump-ipa-inline -fno-early-inlining" } */ |
| |
| extern void abort (void); |
| |
| struct S |
| { |
| int i; |
| void (*f)(struct S *); |
| int j,k,l; |
| }; |
| |
| struct U |
| { |
| struct U *next; |
| struct S s; |
| short a[8]; |
| }; |
| |
| struct Z |
| { |
| unsigned u; |
| void (*f)(struct Z *, int); |
| struct Z *next; |
| }; |
| |
| static struct Z *gz; |
| static struct U *gu; |
| static int gr = 111; |
| char gc[1024]; |
| |
| static __attribute__ ((noinline, noclone)) struct U * |
| get_u (void) |
| { |
| return (struct U *) &gc; |
| } |
| |
| static void wrong_target_1 (struct S *s) |
| { |
| abort (); |
| } |
| |
| static void wrong_target_2 (struct S *s) |
| { |
| abort (); |
| } |
| |
| static void wrong_target_3 (struct S *s) |
| { |
| abort (); |
| } |
| |
| static void wrong_target_4 (struct S *s) |
| { |
| abort (); |
| } |
| |
| static void good_target (struct Z *z, int i) |
| { |
| gr = 0; |
| } |
| |
| static void good_target_4 (struct S *s) |
| { |
| gr = 0; |
| } |
| |
| static void g1 (struct S *s) |
| { |
| struct Z *z = (struct Z*) s; |
| z->f (z, 8); |
| } |
| |
| static void f1 (struct U *u) |
| { |
| gz->f = good_target; |
| g1 (&u->s); |
| } |
| |
| static void g2 (struct Z *z) |
| { |
| z->f (z, 8); |
| } |
| |
| static void f2 (struct U *u) |
| { |
| gz->f = good_target; |
| g2 ((struct Z*) &u->s); |
| } |
| |
| static void h3 (struct Z *z) |
| { |
| z->f (z, 8); |
| } |
| |
| static void g3 (struct S *s) |
| { |
| h3 ((struct Z*) s); |
| } |
| |
| static void f3 (struct U *u) |
| { |
| gz->f = good_target; |
| g3 (&u->s); |
| } |
| |
| static void h4 (struct S *s) |
| { |
| s->f (s); |
| } |
| |
| static void g4 (struct U *u) |
| { |
| h4 (&u->s); |
| } |
| |
| static inline __attribute__ ((flatten)) void f4 (struct Z *z) |
| { |
| gu->s.f = good_target_4; |
| g4 ((struct U *) z); |
| } |
| |
| int main (int argc, char **argv) |
| { |
| struct U *u = get_u (); |
| u->next = u; |
| u->s.i = 5678; |
| u->s.f = wrong_target_1; |
| u->s.j = 1234; |
| gz = (struct Z *) &u->s; |
| f1 (u); |
| |
| u = get_u(); |
| u->s.i = 9999; |
| u->s.f = wrong_target_2; |
| gz = (struct Z *) &u->s; |
| f2 (u); |
| |
| u = get_u(); |
| u->s.i = 9998; |
| u->s.f = wrong_target_3; |
| gz = (struct Z *) &u->s; |
| f3 (u); |
| |
| u = get_u(); |
| u->s.i = 9998; |
| u->s.f = wrong_target_4; |
| gu = u; |
| f4 ((struct Z *) u); |
| return gr; |
| } |
| |
| |
| /* { dg-final { scan-ipa-dump-not "wrong_target\[^\\n\]*inline copy in" "inline" } } */ |
| /* { dg-final { cleanup-ipa-dump "inline" } } */ |