| /* This testcase derives from gnu obstack.c/obstack.h and failed with |
| -O3 -funroll-all-loops, or -O1 -frename-registers -funroll-loops on |
| sparc-sun-solaris2.7. |
| |
| Copyright (C) 2001 Free Software Foundation. */ |
| |
| # define PTR_INT_TYPE __PTRDIFF_TYPE__ |
| |
| struct _obstack_chunk |
| { |
| char *limit; |
| struct _obstack_chunk *prev; |
| char contents[4]; |
| }; |
| |
| struct obstack |
| { |
| long chunk_size; |
| struct _obstack_chunk *chunk; |
| char *object_base; |
| char *next_free; |
| char *chunk_limit; |
| PTR_INT_TYPE temp; |
| int alignment_mask; |
| struct _obstack_chunk *(*chunkfun) (void *, long); |
| void (*freefun) (void *, struct _obstack_chunk *); |
| void *extra_arg; |
| unsigned use_extra_arg:1; |
| unsigned maybe_empty_object:1; |
| unsigned alloc_failed:1; |
| }; |
| |
| extern void _obstack_newchunk (struct obstack *, int); |
| |
| struct fooalign {char x; double d;}; |
| #define DEFAULT_ALIGNMENT \ |
| ((PTR_INT_TYPE) ((char *) &((struct fooalign *) 0)->d - (char *) 0)) |
| union fooround {long x; double d;}; |
| #define DEFAULT_ROUNDING (sizeof (union fooround)) |
| |
| #ifndef COPYING_UNIT |
| #define COPYING_UNIT int |
| #endif |
| |
| #define CALL_CHUNKFUN(h, size) \ |
| (((h) -> use_extra_arg) \ |
| ? (*(h)->chunkfun) ((h)->extra_arg, (size)) \ |
| : (*(struct _obstack_chunk *(*) (long)) (h)->chunkfun) ((size))) |
| |
| #define CALL_FREEFUN(h, old_chunk) \ |
| do { \ |
| if ((h) -> use_extra_arg) \ |
| (*(h)->freefun) ((h)->extra_arg, (old_chunk)); \ |
| else \ |
| (*(void (*) (void *)) (h)->freefun) ((old_chunk)); \ |
| } while (0) |
| |
| void |
| _obstack_newchunk (h, length) |
| struct obstack *h; |
| int length; |
| { |
| register struct _obstack_chunk *old_chunk = h->chunk; |
| register struct _obstack_chunk *new_chunk; |
| register long new_size; |
| register long obj_size = h->next_free - h->object_base; |
| register long i; |
| long already; |
| |
| new_size = (obj_size + length) + (obj_size >> 3) + 100; |
| if (new_size < h->chunk_size) |
| new_size = h->chunk_size; |
| |
| new_chunk = CALL_CHUNKFUN (h, new_size); |
| h->chunk = new_chunk; |
| new_chunk->prev = old_chunk; |
| new_chunk->limit = h->chunk_limit = (char *) new_chunk + new_size; |
| |
| if (h->alignment_mask + 1 >= DEFAULT_ALIGNMENT) |
| { |
| for (i = obj_size / sizeof (COPYING_UNIT) - 1; |
| i >= 0; i--) |
| ((COPYING_UNIT *)new_chunk->contents)[i] |
| = ((COPYING_UNIT *)h->object_base)[i]; |
| already = obj_size / sizeof (COPYING_UNIT) * sizeof (COPYING_UNIT); |
| } |
| else |
| already = 0; |
| for (i = already; i < obj_size; i++) |
| new_chunk->contents[i] = h->object_base[i]; |
| |
| if (h->object_base == old_chunk->contents && ! h->maybe_empty_object) |
| { |
| new_chunk->prev = old_chunk->prev; |
| CALL_FREEFUN (h, old_chunk); |
| } |
| |
| h->object_base = new_chunk->contents; |
| h->next_free = h->object_base + obj_size; |
| h->maybe_empty_object = 0; |
| } |