1  /* This testcase derives from gnu obstack.c/obstack.h and failed with
       2     -O3 -funroll-all-loops, or -O1 -frename-registers -funroll-loops on
       3     sparc-sun-solaris2.7.
       4  
       5     Copyright (C) 2001  Free Software Foundation.  */
       6  
       7  /* { dg-require-effective-target indirect_calls } */
       8  
       9  # define PTR_INT_TYPE __PTRDIFF_TYPE__
      10  
      11  struct _obstack_chunk
      12  {
      13    char  *limit;
      14    struct _obstack_chunk *prev;
      15    char	contents[4];
      16  };
      17  
      18  struct obstack
      19  {
      20    long	chunk_size;
      21    struct _obstack_chunk *chunk;
      22    char	*object_base;
      23    char	*next_free;
      24    char	*chunk_limit;
      25    PTR_INT_TYPE temp;
      26    int   alignment_mask;
      27    struct _obstack_chunk *(*chunkfun) (void *, long);
      28    void (*freefun) (void *, struct _obstack_chunk *);
      29    void *extra_arg;
      30    unsigned use_extra_arg:1;
      31    unsigned maybe_empty_object:1;
      32    unsigned alloc_failed:1;
      33  };
      34  
      35  extern void _obstack_newchunk (struct obstack *, int);
      36  
      37  struct fooalign {char x; double d;};
      38  #define DEFAULT_ALIGNMENT  \
      39    ((PTR_INT_TYPE) ((char *) &((struct fooalign *) 0)->d - (char *) 0))
      40  union fooround {long x; double d;};
      41  #define DEFAULT_ROUNDING (sizeof (union fooround))
      42  
      43  #ifndef COPYING_UNIT
      44  #define COPYING_UNIT int
      45  #endif
      46  
      47  #define CALL_CHUNKFUN(h, size) \
      48    (((h) -> use_extra_arg) \
      49     ? (*(h)->chunkfun) ((h)->extra_arg, (size)) \
      50     : (*(struct _obstack_chunk *(*) (long)) (h)->chunkfun) ((size)))
      51  
      52  #define CALL_FREEFUN(h, old_chunk) \
      53    do { \
      54      if ((h) -> use_extra_arg) \
      55        (*(h)->freefun) ((h)->extra_arg, (old_chunk)); \
      56      else \
      57        (*(void (*) (void *)) (h)->freefun) ((old_chunk)); \
      58    } while (0)
      59  
      60  void
      61  _obstack_newchunk (h, length)
      62       struct obstack *h;
      63       int length;
      64  {
      65    register struct _obstack_chunk *old_chunk = h->chunk;
      66    register struct _obstack_chunk *new_chunk;
      67    register long	new_size;
      68    register long obj_size = h->next_free - h->object_base;
      69    register long i;
      70    long already;
      71  
      72    new_size = (obj_size + length) + (obj_size >> 3) + 100;
      73    if (new_size < h->chunk_size)
      74      new_size = h->chunk_size;
      75  
      76    new_chunk = CALL_CHUNKFUN (h, new_size);
      77    h->chunk = new_chunk;
      78    new_chunk->prev = old_chunk;
      79    new_chunk->limit = h->chunk_limit = (char *) new_chunk + new_size;
      80  
      81    if (h->alignment_mask + 1 >= DEFAULT_ALIGNMENT)
      82      {
      83        for (i = obj_size / sizeof (COPYING_UNIT) - 1;
      84  	   i >= 0; i--)
      85  	((COPYING_UNIT *)new_chunk->contents)[i]
      86  	  = ((COPYING_UNIT *)h->object_base)[i];
      87        already = obj_size / sizeof (COPYING_UNIT) * sizeof (COPYING_UNIT);
      88      }
      89    else
      90      already = 0;
      91    for (i = already; i < obj_size; i++)
      92      new_chunk->contents[i] = h->object_base[i];
      93  
      94    if (h->object_base == old_chunk->contents && ! h->maybe_empty_object)
      95      {
      96        new_chunk->prev = old_chunk->prev;
      97        CALL_FREEFUN (h, old_chunk);
      98      }
      99  
     100    h->object_base = new_chunk->contents;
     101    h->next_free = h->object_base + obj_size;
     102    h->maybe_empty_object = 0;
     103  }