Compiling the test case at the end with -O2 causes: $ ./cc1plus -O2 -quiet a.cc a.cc: In function 'void E(uint64*, uint64*, const void*, int64)': a.cc:18:15: internal compiler error: in memory_address_addr_space, at explow.c:504 Please submit a full bug report, with preprocessed source if appropriate. See <http://gcc.gnu.org/bugs.html> for instructions. The ICE occurs during RTL expansion for the statement: $G =$5 = 0x7ffff7124410 # VUSE <.MEM_58(D)> D.2207_9 = *lo_8(D); Both sides are uint64, but in expand_expr_real_1, when we call memory_address_addr_space on *lo_8, we get: #3 0x00000000010e6c3d in expand_expr_real_1 (exp=0x7ffff7ff88c0, target=0x7ffff6f0fcc0, tmode=DImode, modifier=EXPAND_NORMAL, alt_rtl=0x7fffffffd7f8) at /home/dnovillo/gcc/src/gcc/expr.c:8735 8735 op0 = memory_address_addr_space (address_mode, op0, as); (gdb) ptu exp $NODE =$10 = 0x7ffff7ff88c0 *lo_8(D); (gdb) p address_mode $11 = DImode (gdb) pr op0 (reg/v/f:DI 8 st [ lo ]) void(gdb) down #2 0x00000000010720f0 in memory_address_addr_space (mode=DImode, x=0x7ffff6f16100, as=0 '\000') at /home/dnovillo/gcc/src/gcc/explow.c:504 504 gcc_assert (memory_address_addr_space_p (mode, x, as)); (gdb) pr x (reg:DI 12 st(4)) and X fails the memory_address_addr_space_p() test. Test case: ========================================================================= typedef unsigned long long uint64; typedef long long int64; typedef unsigned char uint8; static const int PT = 8 * 1024; typedef unsigned int uint32; static inline uint64 L(const uint8 *p) { return 1; } void E(uint64 *, uint64 *, const void *, int64) __attribute__ ((__target__ ("sse4"))); void E (uint64 * lo, uint64 * hi, const void *bytes, int64 length) { const uint8 *p = static_cast < const uint8 * >(bytes); const uint8 *e = p + length; uint32 l = *lo; uint64 l64 = l; if ((e - p) >= PT) { while ((e - p) >= 128) { l64 = __builtin_ia32_crc32di (l64, L (p)); l64 = __builtin_ia32_crc32di (l64, L (p)); l64 = __builtin_ia32_crc32di (l64, L (p)); l64 = __builtin_ia32_crc32di (l64, L (p)); l64 = __builtin_ia32_crc32di (l64, L (p)); l64 = __builtin_ia32_crc32di (l64, L (p)); l64 = __builtin_ia32_crc32di (l64, L (p)); l64 = __builtin_ia32_crc32di (l64, L (p)); l64 = __builtin_ia32_crc32di (l64, L (p)); } } while ((e - p) >= 16) { l64 = __builtin_ia32_crc32di (l64, L (p)); l64 = __builtin_ia32_crc32di (l64, L (p)); } l = l64; *lo = l; }
Jeff, this is the ICE I was referring to earlier on IRC. It seems to happen earlier than what you were working on, so it may not be related to your changes.
st4 definitely isn't a valid memory address... But that routine should be copying the value into a pseudo... If the target legitmize_address made a change but didn't give us back something useful, then this routine could ICE in the way you described. I don't see how this is related to anything I've been working on. Jeff
target attribute is a never ending source of problems.
Sounds similar to other reports that build on i?86 without -msse and a target attribute that enables some more SSE features. Try with -msse, if that works this is invalid (and a dup of PRxxx).
I get the ICE on x86_64-linux -m64 -O2 too, so that's not it. Started failing with http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=167964
Created attachment 23198 [details] gcc46-pr47564.patch Ugh, this is ugly. The problem is that tree_rest_of_compilation calls init_emit and lots of other init* functions and assumes x_rtl will stay initialized until expansion. But if during any of the following optimization passes set_cfun is called to some other function which has different target options, target_reinit is called, which calls free_after_compilation which will clear x_rtl. Among other things it clears reg_rtx_no, which means when expanding E pseudo allocation starts from 0 instead of first pseudo (i.e. allocates various hard/virtual registers first, which of course can't lead to anything sane). Most of the set_cfun calls actually came from cgraph verification, where it is not really needed - IMHO we can set_cfun there just when we are about to diagnose an issue and when we do that, we will internal_error at the end of function anyway and thus don't have to worry about restoring it at all. The attached patch fixes that. On the testcase there is another set_cfun call after tree_rest_of_compilation has been called though, in particular from cgraph_release_function_body during inlining (called from cgraph_release_node). I guess in such a case we don't actually need target reinit, perhaps we could just change cfun after saving the previous value, instead of using push_cfun/pop_cfun. Or perhaps target_reinit could save x_rtl copy before it and restore it afterwards, so that it doesn't clear it if it wasn't all 0's before.
Following works by not doing target_reinit once tree_rest_of_compilation calls init_function_start, until final. --- function.c.jj 2011-01-25 18:40:08.000000000 +0100 +++ function.c 2011-02-01 16:33:48.000000000 +0100 @@ -4294,7 +4294,10 @@ invoke_set_current_function_hook (tree f cl_optimization_restore (&global_options, TREE_OPTIMIZATION (opts)); } - targetm.set_current_function (fndecl); + /* Don't call targetm.set_current_function in between + prepare_function_start and following free_after_compilation. */ + if (regno_reg_rtx == NULL) + targetm.set_current_function (fndecl); } }
Created attachment 23211 [details] gcc46-pr47564.patch Updated fix. For 4.7 I'd say we want to split this reinitialization up, into reinitializations that matter for tree optimizations (ideally those could be saved into (and restored from) some save area pointed to from TARGET_OPTION_NODE, e.g. init_set_costs can be saved into target_cfgloop structure), and initializations that only matter from expand_gimple_cfg entry till free_after_compilation (there we could remember the last TARGET_OPTION_NODE (or global) and if current TARGET_OPTION_NODE (or global) is different from it, call the init_* calls at the beginning of expand_gimple_cfg.
Author: jakub Date: Thu Feb 3 08:29:03 2011 New Revision: 169784 URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=169784 Log: PR target/47564 * toplev.c (target_reinit): Save and restore *crtl and regno_reg_rtx around backend_init_target and lang_dependent_init_target calls. * cgraphunit.c (cgraph_debug_gimple_stmt): New function. (verify_cgraph_node): Don't call set_cfun here. Use cgraph_debug_gimple_stmt instead of debug_gimple_stmt. Set error_found for incorrectly represented calls to thunks. * gcc.target/i386/pr47564.c: New test. Added: trunk/gcc/testsuite/gcc.target/i386/pr47564.c Modified: trunk/gcc/ChangeLog trunk/gcc/cgraphunit.c trunk/gcc/testsuite/ChangeLog trunk/gcc/toplev.c
Fixed.