o Compile command $ h8300-elf-gcc -O1 -mh -mint32 -Os -S gcc-bug.c o Result message gcc-bug.c: In function `add_to_page_cache': gcc-bug.c:86: internal compiler error: in change_address_1, at emit-rtl.c:2017 o problem source code struct list_head { struct list_head *next, *prev; }; static inline void __list_add(struct list_head *new, struct list_head *prev, struct list_head *next) { next->prev = new; new->next = next; new->prev = prev; prev->next = new; } static inline void list_add(struct list_head *new, struct list_head *head) { __list_add(new, head, head->next); } typedef struct { int counter; } atomic_t; static __inline__ int atomic_inc_return(atomic_t *v) { int ret,flags; do { asm volatile ("sub.l er0,er0\n\tstc ccr,r0l\n\tmov.l er0,%0":"=r" (flags) : : "er0"); asm volatile ("orc #0x80,ccr"); } while(0); v->counter++; ret = v->counter; asm volatile ("mov.l %0,er0\n\tldc r0l,ccr": :"r" (flags) : "er0"); return ret; } struct address_space { struct list_head clean_pages; unsigned long nrpages; }; struct inode { unsigned long dummy; }; typedef struct page { struct list_head list; struct address_space *mapping; unsigned long index; atomic_t count; unsigned long flags; } mem_map_t; extern unsigned int page_hash_bits; static inline unsigned long _page_hashfn(struct address_space * mapping, unsigned long index) { return (((((unsigned long) mapping)/(sizeof(struct inode) & ~ (sizeof(struct inode) - 1)))+index)+(((((unsigned long) mapping) /(sizeof(struct inode) & ~ (sizeof(struct inode) - 1)))+index)>>(page_hash_bits))) & ((1 << (page_hash_bits))-1); } atomic_t page_cache_size = { (0) }; unsigned int page_hash_bits; struct page **page_hash_table; static void add_page_to_hash_queue(struct page * page, struct page **p) { } static inline void add_page_to_inode_queue(struct address_space *mapping, struct page * page) { struct list_head *head = &mapping->clean_pages; mapping->nrpages++; list_add(&page->list, head); page->mapping = mapping; } static inline void __add_to_page_cache(struct page * page, struct address_space *mapping, unsigned long offset, struct page **hash) { unsigned long flags; flags = page->flags & ~(1 << 3 | 1 << 1 | 1 << 4 | 1 << 2 | 1 << 13 | 1 << 12); page->flags = flags | (1 << 0); atomic_inc_return(&(page)->count); page->index = offset; add_page_to_inode_queue(mapping, page); add_page_to_hash_queue(page, hash); } static void lru_cache_add(struct page *page) { } void add_to_page_cache(struct page * page, struct address_space * mapping, unsigned long offset) { __add_to_page_cache(page, mapping, offset, (page_hash_table+_page_hashfn(mapping,offset))); lru_cache_add(page); }
On the mainline (20030718), I cannot reproduce this so this looks like it only effects 3.3, I will try 3.3.1 (the latest snapshot) unless someone beats me to it.
I can reproduce this on 3.3.1 (20030714).
It also happens in 3.2.3.
It also happens in 3.1.
3.1.1 and 3.2.3 is no problem
This is a regression from 3.0.4 where gcc did not ICE.
testing snapshot ... gcc version 3.3.1 20030714 (prerelease) Result gcc-bug.c: In function `add_to_page_cache': gcc-bug.c:92: internal compiler error: in change_address_1, at emit-rtl.c:2020
Only -mint32 -mh -Os needed to reproduce it. Workaround is to change -Os to -O1 or remove one of the other two options.
I simplified the testcase a little bit. struct list_head { struct list_head *next, *prev; }; struct atomic { int counter; }; struct address_space { struct list_head clean_pages; }; struct page { struct list_head list; struct address_space *mapping; unsigned long index; struct atomic count; unsigned long flags; }; extern unsigned int page_hash_bits; unsigned int page_hash_bits; struct page **page_hash_table; void add_page_to_hash_queue (struct page *page, struct page **p); void lru_cache_add (struct page *page); void add_to_page_cache (struct page *page, struct address_space *mapping, unsigned long offset) { unsigned long m = ((unsigned long) mapping) / 4 + offset; unsigned long hash_value = (m + (m >> page_hash_bits)) & ((1 << page_hash_bits) - 1); struct page **hash = page_hash_table + hash_value; struct list_head *head; page->flags |= 1; { struct atomic *v = &page->count; int flags; asm volatile ("" : "=r" (flags) : : "er0"); v->counter++; asm volatile ("" : : "r" (flags) : "er0"); } page->index = offset; head = &mapping->clean_pages; { struct list_head *new = &page->list; struct list_head *prev = head; struct list_head *next = head->next; next->prev = new; new->next = next; new->prev = prev; prev->next = new; } add_page_to_hash_queue (page, hash); lru_cache_add (page); }
Backporting the following patch solves the problem. http://gcc.gnu.org/ml/gcc-cvs/2002-12/msg00640.html I will talk to the author of the patch to see if it would make sense to have it on 3.3 branch.
Slightly more reduced: struct list { struct list *next, *prev; }; struct page { struct list list; int index; int counter; }; int bits, table; int foo (struct page *page, struct list *head, int offset) { int value = (offset >> bits) & (1 << bits); int hash = table + value; page->index |= 1; { int *v = &page->counter; int flags; asm volatile ("" : "=r" (flags) : : "er0"); (*v)++; asm volatile ("" : : "r" (flags) : "er0"); } page->index = offset; { struct list *new = &page->list; struct list *prev = head; struct list *next = head->next; next->prev = new; new->next = next; new->prev = prev; prev->next = new; } return (int) page + hash; }
Slightly more reduced: struct page { struct page *next, *prev; int index; int counter; }; int bits, table; int foo (struct page *new, struct page *head, int offset) { int value = (offset + bits) & (1 << bits); int hash = table + value; new->index++; { int *v = &new->counter; int flags; asm volatile ("" : "=r" (flags) : : "er0"); (*v)++; asm volatile ("" : : "r" (flags) : "er0"); } new->index = offset; { struct page *prev = head; struct page *next = head->next; next->prev = new; new->next = next; new->prev = prev; prev->next = new; } return (int) new + hash; }
Postponed until GCC 3.3.3.
since this is a case of "backport this from 3.4 to fix" we should get Gabriel's opinion.
Subject: Re: [3.3 regression] internal error at emit-rtl.c:2017 "zack at gcc dot gnu dot org" <gcc-bugzilla@gcc.gnu.org> writes: | since this is a case of "backport this from 3.4 to fix" we should | get Gabriel's opinion. It is OK. I missed the proposed fix for this PR. Thanks for bringing it to my attention. -- Gaby
Kazu, would you please do the backport, re-test, and commit?
Kazu -- Do you think you have plan for this in time for 3.3.x? -- Gaby
I was about to put a comment. Mid-air comflict! Whee, the proposed backport does not fix the problem anymore! I still get the same ICE. Would you mind giving me a day or two to analyze this? If it's beyond my capability, I'll give up with WONTFIX.
Subject: Re: [3.3 regression] internal error at emit-rtl.c:2017 "kazu at cs dot umass dot edu" <gcc-bugzilla@gcc.gnu.org> writes: | Would you mind giving me a day or two to analyze this? Sure. You've till the end of the year :-) | If it's beyond my capability, I'll give up with WONTFIX. Thanks! -- Gaby
Subject: Bug 11576 CVSROOT: /cvs/gcc Module name: gcc Branch: gcc-3_3-branch Changes by: kazu@gcc.gnu.org 2003-12-23 15:10:26 Modified files: gcc : ChangeLog gcc/config/h8300: h8300.h Log message: PR target/11576 * config/h8300/h8300.h (CONSTANT_ADDRESS_P): Allow CONST and HIGH on all variants. Patches: http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/ChangeLog.diff?cvsroot=gcc&only_with_tag=gcc-3_3-branch&r1=1.16114.2.858&r2=1.16114.2.859 http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/config/h8300/h8300.h.diff?cvsroot=gcc&only_with_tag=gcc-3_3-branch&r1=1.123.2.2&r2=1.123.2.3
Just committed a patch.