Bug 47564 - [4.6 Regression] internal compiler error in memory_address_addr_space, at explow.c:504
Summary: [4.6 Regression] internal compiler error in memory_address_addr_space, at exp...
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: target (show other bugs)
Version: 4.6.0
: P3 normal
Target Milestone: 4.6.0
Assignee: Jakub Jelinek
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2011-02-01 03:09 UTC by Diego Novillo
Modified: 2011-02-03 08:32 UTC (History)
4 users (show)

See Also:
Host:
Target: i?86-linux-gnu
Build:
Known to work:
Known to fail:
Last reconfirmed: 2011-02-01 14:18:55


Attachments
gcc46-pr47564.patch (1.22 KB, patch)
2011-02-01 14:40 UTC, Jakub Jelinek
Details | Diff
gcc46-pr47564.patch (1.99 KB, patch)
2011-02-02 10:00 UTC, Jakub Jelinek
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Diego Novillo 2011-02-01 03:09:18 UTC
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;
}
Comment 1 Diego Novillo 2011-02-01 03:10:41 UTC
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.
Comment 2 Jeffrey A. Law 2011-02-01 03:48:43 UTC
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
Comment 3 Jakub Jelinek 2011-02-01 08:20:20 UTC
target attribute is a never ending source of problems.
Comment 4 Richard Biener 2011-02-01 11:50:39 UTC
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).
Comment 5 Jakub Jelinek 2011-02-01 12:32:51 UTC
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
Comment 6 Jakub Jelinek 2011-02-01 14:40:50 UTC
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.
Comment 7 Jakub Jelinek 2011-02-01 15:47:07 UTC
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);
     }
 }
Comment 8 Jakub Jelinek 2011-02-02 10:00:11 UTC
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.
Comment 9 Jakub Jelinek 2011-02-03 08:29:07 UTC
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
Comment 10 Jakub Jelinek 2011-02-03 08:32:44 UTC
Fixed.