Compiling clisp with gcc 4 CVS fails with the following ICE. This is a regression from GCC 3.3. $ gcc -fPIC -D_GNU_SOURCE -W -Wswitch -Wcomment -Wpointer-arith -Wimplicit -Wreturn-type -O -DUNICODE -DDYNAMIC_FFI -DDYNAMIC_MODULES -DNO_SIGSEGV -I. -c spvw.c -save-temps -v Using built-in specs. Target: x86_64-suse-linux Configured with: ../configure --enable-threads=posix --prefix=/usr --with-local-prefix=/usr/local --infodir=/usr/share/info --mandir=/usr/share/man --libdir=/usr/lib64 --libexecdir=/usr/lib64 --enable-languages=c,c++,objc,f95,java,ada --enable-checking --with-gxx-include-dir=/usr/include/c++/4.0.0 --with-slibdir=/lib64 --with-system-zlib --enable-shared --enable-__cxa_atexit --without-system-libunwind --host=x86_64-suse-linux Thread model: posix gcc version 4.0.0 20050410 (prerelease) (SUSE Linux) /usr/lib64/gcc/x86_64-suse-linux/4.0.0/cc1 -E -quiet -v -I. -D_GNU_SOURCE -DUNICODE -DDYNAMIC_FFI -DDYNAMIC_MODULES -DNO_SIGSEGV spvw.c -mtune=k8 -W -Wswitch -Wcomment -Wpointer-arith -Wimplicit -Wreturn-type -fPIC -O -fpch-preprocess -o spvw.i #include "..." search starts here: #include <...> search starts here: . /usr/local/include /usr/lib64/gcc/x86_64-suse-linux/4.0.0/include /usr/lib64/gcc/x86_64-suse-linux/4.0.0/../../../../x86_64-suse-linux/include /usr/include End of search list. /usr/lib64/gcc/x86_64-suse-linux/4.0.0/cc1 -fpreprocessed spvw.i -quiet -dumpbase spvw.c -mtune=k8 -auxbase spvw -O -W -Wswitch -Wcomment -Wpointer-arith -Wimplicit -Wreturn-type -version -fPIC -o spvw.s GNU C version 4.0.0 20050410 (prerelease) (SUSE Linux) (x86_64-suse-linux) compiled by GNU C version 4.0.0 20050410 (prerelease) (SUSE Linux). GGC heuristics: --param ggc-min-expand=30 --param ggc-min-heapsize=4096 In file included from spvw.d:25: lispbibl.d:7430: warning: volatile register variables don’t work as you might wish In file included from spvw.d:563: spvw_typealloc.d: In function ‘allocate_vector’: spvw_typealloc.d:94: error: unrecognizable insn: (insn 93 92 88 4 (set (reg/f:DI 87) (plus:DI (reg:DI 91) (const_int 1125899906842624 [0x4000000000000]))) -1 (insn_list:REG_DEP_TRUE 92 (nil)) (expr_list:REG_DEAD (reg:DI 91) (expr_list:REG_EQUAL (const:DI (plus:DI (symbol_ref:DI ("symbol_tab_data") [flags 0x40] <var_decl 0x2aaaab1cc750 symbol_tab_data>) (const_int 1125899906842624 [0x4000000000000]))) (nil)))) spvw_typealloc.d:94: internal compiler error: in extract_insn, at recog.c:2060 Please submit a full bug report, with preprocessed source if appropriate.
Created attachment 8579 [details] Preprocessed source file
Also happens with mainline. extern struct symbol_tab_ { void *S_nil; } symbol_tab_data; typedef struct { unsigned int length; void *data[0]; } s; void * allocate_vector (unsigned int len) { unsigned int need; s *ptr; void *obj; ptr->length = len; void **p = &ptr->data[0]; do { *p++ = ((((unsigned char *) ((&symbol_tab_data.S_nil)) + ((unsigned long int) (((1L << (2)))) << 48)))); } while (!(--len == 0)); return obj; } t.c: In function 'allocate_vector': t.c:25: error: unrecognizable insn: (insn 56 55 51 0 (set (reg/f:DI 70) (plus:DI (reg:DI 73) (const_int 1125899906842624 [0x4000000000000]))) -1 (insn_list:REG_DEP_TRUE 55 (nil)) (expr_list:REG_DEAD (reg:DI 73) (expr_list:REG_EQUAL (const:DI (plus:DI (symbol_ref:DI ("symbol_tab_data") [flags 0x40] <var_decl 0x2a95a36270 symbol_tab_data>) (const_int 1125899906842624 [0x4000000000000]))) (nil)))) t.c:25: internal compiler error: in extract_insn, at recog.c:2082
Needs "-O -mtune=k8 -fPIC" of course. -fPIC seems to cause the problem.
Double *sigh*. The old loop optimizer introduces the offending insn. From the .loop dump: Insn 26: regno 70 (life 1), move-insn forces 25 savings 1 moved to 56 Hoisted regno 74 r/o from (mem/u/c:DI (const:DI (unspec:DI [ (symbol_ref:DI ("symbol_tab_data") [flags 0x40] <var_decl 0x2a95a36270 symbol_tab_data>) ] 2)) [0 S8 A8]) ... (insn 56 55 51 0 (set (reg/f:DI 70) (plus:DI (reg:DI 73) (const_int 1125899906842624 [0x4000000000000]))) -1 (nil) (expr_list:REG_EQUAL (const:DI (plus:DI (symbol_ref:DI ("symbol_tab_data") [flags 0x40] <var_decl 0x2a95a36270 symbol_tab_data>) (const_int 1125899906842624 [0x4000000000000]))) (nil)))
After CSE1 (t.c.04.cse) we have: (insn 20 18 22 1 (set (reg:DI 66) (mem/u/c:DI (const:DI (unspec:DI [ (symbol_ref:DI ("bar") [flags 0x40] <var_decl 0x2a95a2f000 bar>) ] 2)) [0 S8 A8])) 81 {*movdi_1_rex64} (nil) (nil)) (insn 22 20 23 1 (set (reg:DI 68) (const_int 2147483648 [0x80000000])) 81 {*movdi_1_rex64} (nil) (nil)) (insn 23 22 24 1 (parallel [ (set (reg:DI 67) (plus:DI (reg:DI 66) (reg:DI 68))) (clobber (reg:CC 17 flags)) ]) 193 {*adddi_1_rex64} (nil) (expr_list:REG_EQUAL (const:DI (plus:DI (symbol_ref:DI ("bar") [flags 0x40] <var_decl 0x2a95a2f000 bar>) (const_int 2147483648 [0x80000000]))) (nil))) but old loop (t.c.06.loop) somehow turns this into: (insn 45 48 46 0 (set (reg:DI 69) (mem/u/c:DI (const:DI (unspec:DI [ (symbol_ref:DI ("bar") [flags 0x40] <var_decl 0x2a95a2f000 bar>) ] 2)) [0 S8 A8])) -1 (nil) (nil)) (insn 46 45 41 0 (set (reg/f:DI 67) (plus:DI (reg:DI 69) (const_int 2147483648 [0x80000000]))) -1 (nil) (expr_list:REG_EQUAL (const:DI (plus:DI (symbol_ref:DI ("bar") [flags 0x40] <var_decl 0x2a95a2f000 bar>) (const_int 2147483648 [0x80000000]))) (nil))) Note how we have lost a clobber and turned a reg+reg addition into a reg+imm; from: (set (reg:DI 66) (mem:DI (const:DI (unspec:DI [(symbol_ref:DI ("bar"))])))) (set (reg:DI 68) (const_int 2147483648 [0x80000000])) (parallel [ (set (reg:DI 67) (plus:DI (reg:DI 66) (reg:DI 68))) (clobber (reg:CC 17 flags))]) to: (set (reg:DI 69) (mem:DI (const:DI (unspec:DI [(symbol_ref:DI ("bar"))])))) (set (reg/f:DI 67) (plus:DI (reg:DI 69) (const_int 2147483648 [0x80000000])))
The offending insn is created by emit_move_insn in loop.c, here: 2354 start_sequence (); 2355 emit_move_insn (m->insert_temp ? newreg : m->set_dest, 2356 m->set_src); 2357 seq = get_insns (); 2358 end_sequence (); (gdb) p debug_rtx_list (seq, 10) (insn 45 0 46 (set (reg:DI 69) (mem/u/c:DI (const:DI (unspec:DI [ (symbol_ref:DI ("bar") [flags 0x40] <var_decl 0x2a95a2f000 bar>) ] 2)) [0 S8 A8])) -1 (nil) (nil)) (insn 46 45 0 (set (reg/f:DI 67) (plus:DI (reg:DI 69) (const_int 2147483648 [0x80000000]))) -1 (nil) (expr_list:REG_EQUAL (const:DI (plus:DI (symbol_ref:DI ("bar") [flags 0x40] <var_decl 0x2a95a2f000 bar>) (const_int 2147483648 [0x80000000]))) (nil)))
My RTL-fu is way below par, so perhaps this doesn't make sense at all, but... It seems that emit_move_insn must always produce valid move insns. So it should check that an immediate is a valid PIC operand if -fPIC. In this case I'd say LEGITIMATE_CONSTANT_P is the wrong target macro to use. So you would have this instead: Index: expr.c =================================================================== RCS file: /cvs/gcc/gcc/gcc/expr.c,v retrieving revision 1.783 diff -u -3 -p -r1.783 expr.c --- expr.c 30 Mar 2005 21:34:23 -0000 1.783 +++ expr.c 10 Apr 2005 17:51:01 -0000 @@ -3093,7 +3093,8 @@ emit_move_insn (rtx x, rtx y) y_cst = y; - if (!LEGITIMATE_CONSTANT_P (y)) + if ((!flag_pic && !LEGITIMATE_CONSTANT_P (y)) + || (flag_pic && !LEGITIMATE_PIC_OPERAND_P (y))) { y = force_const_mem (mode, y);
FWIW, smallest test case I could find: extern struct bar_t bar; void foo (void) { void **p; do { *p++ = ((unsigned char *) &bar + ((unsigned long int) 1L << 31)); } while (p); }
Alexandre Oliva pointed out to me that it was probably the expander who should produce a proper legitimate insn. I looked at this some more and found that in legitimize_pic_address we do not check if a displacement is a valid PIC displacement: Index: config/i386/i386.c =================================================================== RCS file: /cvs/gcc/gcc/gcc/config/i386/i386.c,v retrieving revision 1.807 diff -u -3 -p -r1.807 i386.c --- config/i386/i386.c 9 Apr 2005 17:19:48 -0000 1.807 +++ config/i386/i386.c 10 Apr 2005 21:01:26 -0000 @@ -5612,7 +5612,13 @@ legitimize_pic_address (rtx orig, rtx re base == reg ? NULL_RTX : reg); if (GET_CODE (new) == CONST_INT) - new = plus_constant (base, INTVAL (new)); + { + if (legitimate_pic_address_disp_p (new)) + new = plus_constant (base, INTVAL (new)); + else + new = gen_rtx_PLUS (Pmode, base, + copy_to_mode_reg (Pmode, new)); + } else { if (GET_CODE (new) == PLUS && CONSTANT_P (XEXP (new, 1))) This looks to me like much better hack (maybe even a proper fix!) so I'll test this to see what happens...
Steven, any update on this one? Would you like to get it assigned to?
This patch trivially "fixes" the problem because the argument to legitimate_pic_address_disp_p is incorrect, and it will always return false.
Postponed until 4.0.2.
The testcase in comment #8 still triggers an ICE if run with -O -mtune=k8 -fPIC.
(In reply to comment #13) > The testcase in comment #8 still triggers an ICE if run with -O -mtune=k8 > -fPIC. > it works with my patched gcc41: (...) .section .data.rel.ro,"aw",@progbits .align 8 .LC1: .quad bar+2147483648 (...) .text foo: movq .LC1(%rip), %rdx .L3: movq %rdx, (%rax) addq $8, %rax jne .L3 rep ; ret (...)
*** Bug 24443 has been marked as a duplicate of this bug. ***
testing fix that should make legitimize_pic_address correctly decompose the address. Similar to Steven's but I think it actually works ;) Index: config/i386/i386.c =================================================================== --- config/i386/i386.c (revision 106026) +++ config/i386/i386.c (working copy) @@ -6016,7 +6016,18 @@ legitimize_pic_address (rtx orig, rtx re } else { - if (GET_CODE (addr) == CONST) + if (GET_CODE (addr) == CONST_INT + && !x86_64_immediate_operand (addr, VOIDmode)) + { + if (reg) + { + emit_move_insn (reg, addr); + new = reg; + } + else + new = force_reg (DImode, addr); + } + else if (GET_CODE (addr) == CONST) { addr = XEXP (addr, 0);
This prevents compiling a reasonably popular program; it's a showstopper.
See comment #16 for a patch.
(In reply to comment #18) > See comment #16 for a patch. More than that, it has been posted: http://gcc.gnu.org/ml/gcc-patches/2005-10/msg01792.html
Patch comitted. For some reason don't seem to appear in logs?