The following testcase produces an ICE in subst_reloads, when compiled
with "-march=z990 -O2 -ftracer":

----------------snip--------------------
extern int memcmp(const void *s1, const void *s2, unsigned long n);
extern int printf (__const char *__restrict __format, ...);
typedef struct
{
   char tmp[4092];
   char msglen[4];
   char msgtype[2];
} TESTSTRUCT;
void test_func(TESTSTRUCT *testtb) {
    if (testtb)
        printf("a");
    if (memcmp(testtb->msgtype, "a", 2))
        printf("a");
    printf("b");
}
------------------snap--------------------

% ./gcc/cc1 -march=z990 -O2 -ftracer test.i
 test_func
Analyzing compilation unitPerforming intraprocedural optimizations
Assembling functions:
 test_func
test.i: In function ‘test_func’:
test.i:19: internal compiler error: in subst_reloads, at reload.c:6108

This already ICEs with the hammer branch, and I think is also still a latent
problem in trunk.  It's a combination of the tracer and CSE working hand in 
hand to produce an invalid MEM address.  It goes like so:

1) Initially the memcmp() call is implemented by the cmpmem_short instruction
   of s390.  Remember that with -march=z990 we have long displacements active.
   The instruction emitted for the memcmp() is:
(insn 69 68 70 1 (parallel [
            (set (reg:CCU 33 %cc)
                (compare:CCU (mem/s:BLK (reg/f:DI 46) [0 S2 A8])
                    (mem/s:BLK (plus:DI (reg/v/f:DI 43 [ testtb ])
                            (const_int 4096 [0x1000]))
                            [0 <variable>.msgtype+0 S2 A8])))
            (use (const_int 1 [0x1]))
            (use (const:BLK (unspec:BLK [
                            (const_int 0 [0x0])
                        ] 213)))
            (clobber (scratch:DI))
        ]) 92 {*cmpmem_short} (nil)
    (expr_list:REG_EQUAL (compare:CCU (mem/s:BLK (symbol_ref/f:DI ("*.LC0")
[flags 0x2] <string_cst 0x20000368b70>) [0 S2 A8])
            (mem/s:BLK (plus:DI (reg/v/f:DI 43 [ testtb ])
                    (const_int 4096 [0x1000]))
                      [0 <variable>.msgtype+0 S2 A8]))
        (nil)))

  So, everything fine, but note the (mem (plus (reg 43) (4096)) operand, which
  we are going to screw up soon.

2) Then -ftracer comes along an duplicates a trace through the whole function
   using the "if (testtb)" predicate.  So we end up with two copies of the
   body, including the above instruction.  One of them under the testtb==0
   branch.

3) Now CSE2 comes into play, with it's path following feature.  In the second
   version of the above insn it knows that testtb (== pseudo 43) is zero.
   Hence it happily changes the insn to read:
(insn 24 23 25 3 (parallel [
            (set (reg:CCU 33 %cc)
                (compare:CCU (mem/s:BLK (reg/f:DI 46) [0 S2 A8])
                    (mem/s:BLK (const_int 4096 [0x1000])
                      [0 <variable>.msgtype+0 S2 A8])))
            (use (const_int 1 [0x1]))
            (use (const:BLK (unspec:BLK [
                            (const_int 0 [0x0])
                        ] 213)))
            (clobber (scratch:DI))
        ]) 92 {*cmpmem_short} (nil)

   Note how the operand in question now is (mem (const_int 4096)).  That is
   fine so far normally, as the compiler can't know that this is going to
   be in invalid address operand.  It can't know that because all predicates
   say that it is valid.

4) reload comes over that insn, looks at the various operands and addresses
   and also determines that (mem (const_int 4096)) is valid because
   strict_memory_address_p returns true for it.

5) But then the constraints are checked too.  And we use 'Q' constraints
   in the cmpmem_short insn:
  (define_insn "*cmpmem_short"
  [(set (reg:CCU CC_REGNUM)
        (compare:CCU (match_operand:BLK 0 "memory_operand" "Q,Q,Q")
                     (match_operand:BLK 1 "memory_operand" "Q,Q,Q")))
   (use (match_operand 2 "nonmemory_operand" "n,a,a"))
   (use (match_operand 3 "immediate_operand" "X,R,X"))
   (clobber (match_scratch 4 "=X,X,&a"))]
   ...
   And the 'Q' constraint forbids long displacements also on long disp
   machines.  So we now have an inconsistent situation.  As the constraints
   don't match we try to reload this address operand (const_int 4096):

Reloads for insn # 24
Reload 0: reload_in (VOID) = (const_int 4096 [0x1000])
        ADDR_REGS, RELOAD_FOR_INPUT (opnum = 1)
        reload_in_reg: (const_int 4096 [0x1000])

   But this operand can't be reloaded easily, because the const_int has no
   mode, hence this whole reload has only VOIDmode, and no register can
   be found for it.  Actually this situation should never happen (i.e. a
   modeless reload), that's why it isn't handled in push_reload and friends.
   All these invalid addresses should have been created a reload for much
   earlier than in the constraint checking.

I unfortunately don't have a good idea how to fix this.  I think these
large displacements much somehow be forbidden already in the predicate,
not only via the constraints, which would mean that one can't use
"memory_operand" as predicate.  Or cmpmem_short needs to accept also the 'S'
constraint.  Or some way would be found for reload to determine a mode for
this reload despite it being only a const_int.  Pmode would be natural.
Alternatively strict_memory_address_p() (via legitimate_address_p() in s390.c)
could reject addresses which only consist of a displacement larger than
4096.  By that long displacement would still be accepted everywhere (when the
machine has them) but only when connected with some register as base or index.
That would ensure that a mode is available for the whole address which makes
reloading possible.


-- 
           Summary: ICE in subst_reloads
           Product: gcc
           Version: 4.1.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: rtl-optimization
        AssignedTo: unassigned at gcc dot gnu dot org
        ReportedBy: matz at gcc dot gnu dot org
  GCC host triplet: s390x-ibm-linux
GCC target triplet: s390x-ibm-linux


http://gcc.gnu.org/bugzilla/show_bug.cgi?id=27661

Reply via email to