1  /* Verify that simple indirect calls are inlined even without early
       2     inlining..  */
       3  /* { dg-do run } */
       4  /* { dg-options "-O3 -fdump-ipa-inline -fno-early-inlining -fno-ipa-icf"  } */
       5  
       6  extern void abort (void);
       7  
       8  struct S
       9  {
      10    int i;
      11    void (*f)(struct S *);
      12    int j,k,l;
      13  };
      14  
      15  struct U
      16  {
      17    struct U *next;
      18    struct S s;
      19    short a[8];
      20  };
      21  
      22  struct Z
      23  {
      24    unsigned u;
      25    void (*f)(struct Z *, int);
      26    struct Z *next;
      27  };
      28  
      29  static struct Z *gz;
      30  static struct U *gu;
      31  static int gr = 111;
      32  char gc[1024];
      33  
      34  static __attribute__ ((noinline, noclone)) struct U *
      35  get_u (void)
      36  {
      37    return (struct U *) &gc;
      38  }
      39  
      40  static void wrong_target_1 (struct S *s)
      41  {
      42    abort ();
      43  }
      44  
      45  static void wrong_target_2 (struct S *s)
      46  {
      47    abort ();
      48  }
      49  
      50  static void wrong_target_3 (struct S *s)
      51  {
      52    abort ();
      53  }
      54  
      55  static void wrong_target_4 (struct S *s)
      56  {
      57    abort ();
      58  }
      59  
      60  static void good_target (struct Z *z, int i)
      61  {
      62    gr = 0;
      63  }
      64  
      65  static void good_target_4 (struct S *s)
      66  {
      67    gr = 0;
      68  }
      69  
      70  static void g1 (struct S *s)
      71  {
      72    struct Z *z = (struct Z*) s;
      73    z->f (z, 8);
      74  }
      75  
      76  static void f1 (struct U *u)
      77  {
      78    gz->f = good_target;
      79    g1 (&u->s);
      80  }
      81  
      82  static void g2 (struct Z *z)
      83  {
      84    z->f (z, 8);
      85  }
      86  
      87  static void f2 (struct U *u)
      88  {
      89    gz->f = good_target;
      90    g2 ((struct Z*) &u->s);
      91  }
      92  
      93  static void h3 (struct Z *z)
      94  {
      95    z->f (z, 8);
      96  }
      97  
      98  static void g3 (struct S *s)
      99  {
     100    h3 ((struct Z*) s);
     101  }
     102  
     103  static void f3 (struct U *u)
     104  {
     105    gz->f = good_target;
     106    g3 (&u->s);
     107  }
     108  
     109  static void h4 (struct S *s)
     110  {
     111    s->f (s);
     112  }
     113  
     114  static void g4 (struct U *u)
     115  {
     116    h4 (&u->s);
     117  }
     118  
     119  static inline __attribute__ ((flatten)) void f4 (struct Z *z)
     120  {
     121    gu->s.f = good_target_4;
     122    g4 ((struct U *) z);
     123  }
     124  
     125  int main (int argc, char **argv)
     126  {
     127    struct U *u = get_u ();
     128    u->next = u;
     129    u->s.i = 5678;
     130    u->s.f = wrong_target_1;
     131    u->s.j = 1234;
     132    gz = (struct Z *) &u->s;
     133    f1 (u);
     134  
     135    u = get_u();
     136    u->s.i = 9999;
     137    u->s.f = wrong_target_2;
     138    gz = (struct Z *) &u->s;
     139    f2 (u);
     140  
     141    u = get_u();
     142    u->s.i = 9998;
     143    u->s.f = wrong_target_3;
     144    gz = (struct Z *) &u->s;
     145    f3 (u);
     146  
     147    u = get_u();
     148    u->s.i = 9998;
     149    u->s.f = wrong_target_4;
     150    gu = u;
     151    f4 ((struct Z *) u);
     152    return gr;
     153  }
     154  
     155  
     156  /* { dg-final { scan-ipa-dump-not "wrong_target\[^\\n\]*inline copy in" "inline"  } } */