reload bug

Jeffrey A Law law@cygnus.com
Mon Nov 30 17:59:00 GMT 1998


Joern, Bernd, if one of you could dive into this I'm sure everyone would
appreciate it.  This is causing the x86 port to mis-compile itself in some
circumstances.

It's another case were we incorrectly delete an output reload.  Compile the
attached testcase on an x86 with -O -funroll-all-loops -fomit-frame-pointer

This causes the compiler to mis-compile itself in some circumstances.

--

When reload starts we have the following insns:

[ ... ]
(insn 27 25 30 (set (reg/v:SI 23)
        (minus:SI (reg:SI 32)
            (reg:SI 33))) 160 {subsi3+1} (insn_list 24 (insn_list 25 (nil)))
    (expr_list:REG_DEAD (reg:SI 32)
        (expr_list:REG_DEAD (reg:SI 33)
            (expr_list:REG_EQUAL (div:SI (reg:SI 28)
                    (const_int 1009))
                (nil)))))

(insn 30 27 32 (set (reg:SI 35)
        (ashift:SI (reg/v:SI 23)
            (const_int 6))) 235 {ashlsi3} (insn_list 27 (nil))
    (expr_list:REG_EQUAL (mult:SI (reg/v:SI 23)
            (const_int 64))
        (nil)))

(insn 32 30 33 (set (reg:SI 35)
        (minus:SI (reg:SI 35)
            (reg/v:SI 23))) 160 {subsi3+1} (insn_list 30 (nil))
    (expr_list:REG_EQUAL (mult:SI (reg/v:SI 23)
            (const_int 63))
        (nil)))



We continue and start processing reloads for insn 27:

Reload 0: reload_in (SI) = (reg:SI 0 %eax)
        reload_out (SI) = (mem:SI (plus:SI (reg:SI 7 %esp)
                                                        (const_int 28)) 0)
        GENERAL_REGS, RELOAD_OTHER (opnum = 0)
        reload_in_reg: (reg:SI 0 %eax)
        reload_out_reg: (reg/v:SI 23)
        reload_reg_rtx: (reg:SI 0 %eax)


Note that reload_out references a stack slot.


After completion of emit_reload_insns and subst_reloads for insn 27 we have:

(insn 27 25 222 (set (reg:SI 0 %eax)
        (minus:SI (reg:SI 0 %eax)
            (reg:SI 1 %edx))) 160 {subsi3+1} (insn_list 24 (insn_list 25 (nil)))
    (expr_list:REG_DEAD (reg:SI 0 %eax)
        (expr_list:REG_DEAD (reg:SI 1 %edx)
            (expr_list:REG_EQUAL (div:SI (reg:SI 2 %ecx)
                    (const_int 1009))
                (nil)))))

(insn 222 27 30 (set (mem:SI (plus:SI (reg:SI 7 %esp)
                (const_int 28)) 0)
        (reg:SI 0 %eax)) -1 (nil)
    (nil))

(insn 30 222 32 (set (reg:SI 0 %eax)
        (ashift:SI (reg/v:SI 23)
            (const_int 6))) 235 {ashlsi3} (insn_list 27 (nil))
    (expr_list:REG_EQUAL (mult:SI (reg/v:SI 23)
            (const_int 64))
        (nil)))

(insn 32 30 33 (set (reg:SI 0 %eax)
        (minus:SI (reg:SI 0 %eax)
            (reg/v:SI 23))) 160 {subsi3+1} (insn_list 30 (nil))
    (expr_list:REG_EQUAL (mult:SI (reg/v:SI 23)
            (const_int 63))
        (nil)))


insn 30 has reloads too:
Reload 0: reload_in (SI) = (reg:SI 0 %eax)
        reload_out (SI) = (reg:SI 0 %eax)
        GENERAL_REGS, RELOAD_OTHER (opnum = 0), can't combine
        reload_in_reg: (reg/v:SI 23)
        reload_out_reg: (reg:SI 0 %eax)
        reload_reg_rtx: (reg:SI 0 %eax)

After completion of emit_reload_insns and subst_reload for insn 30 we have:

(insn 27 25 222 (set (reg:SI 0 %eax)
        (minus:SI (reg:SI 0 %eax)
            (reg:SI 1 %edx))) 160 {subsi3+1} (insn_list 24 (insn_list 25 (nil)))
    (expr_list:REG_DEAD (reg:SI 0 %eax)
        (expr_list:REG_DEAD (reg:SI 1 %edx)
            (expr_list:REG_EQUAL (div:SI (reg:SI 2 %ecx)
                    (const_int 1009))
                (nil)))))

(insn 222 27 30 (set (mem:SI (plus:SI (reg:SI 7 %esp)
                (const_int 28)) 0)
        (reg:SI 0 %eax)) -1 (nil)
    (nil))

(insn 30 222 32 (set (reg:SI 0 %eax)
        (ashift:SI (reg:SI 0 %eax)
            (const_int 6))) 235 {ashlsi3} (insn_list 27 (nil))
    (expr_list:REG_EQUAL (mult:SI (reg/v:SI 23)
            (const_int 64))
        (nil)))

(insn 32 30 33 (set (reg:SI 0 %eax)
        (minus:SI (reg:SI 0 %eax)
            (reg/v:SI 23))) 160 {subsi3+1} (insn_list 30 (nil))
    (expr_list:REG_EQUAL (mult:SI (reg/v:SI 23)
            (const_int 63))
        (nil)))


Note that we've replaced the reg23 in insn 30 with our reload register %eax
which holds the value for reg23.  Also note that the value in the stack slot
no longer corresponds to the current value in %eax after the execution of
insn 30.  Similarly %eax is no longer equivalent to reg23. after insn 30.





Then we proceed to insn 32 with the following reloads:

Reload 0: reload_in (SI) = (mem:SI (plus:SI (reg:SI 7 %esp)
                                                        (const_int 28)) 0)
        GENERAL_REGS, RELOAD_FOR_INPUT (opnum = 2), optional, can't combine
        reload_in_reg: (reg/v:SI 23)

After finishing emit_reload_insns & subst_reloads for insn 32 we have:

(insn 27 25 222 (set (reg:SI 0 %eax)
        (minus:SI (reg:SI 0 %eax)
            (reg:SI 1 %edx))) 160 {subsi3+1} (insn_list 24 (insn_list 25 (nil)))
    (expr_list:REG_DEAD (reg:SI 0 %eax)
        (expr_list:REG_DEAD (reg:SI 1 %edx)
            (expr_list:REG_EQUAL (div:SI (reg:SI 2 %ecx)
                    (const_int 1009))
                (nil)))))

(insn 222 27 30 (set (mem:SI (plus:SI (reg:SI 7 %esp)
                (const_int 28)) 0)
        (reg:SI 0 %eax)) -1 (nil)
    (nil))

(insn 30 222 32 (set (reg:SI 0 %eax)
        (ashift:SI (reg:SI 0 %eax)
            (const_int 6))) 235 {ashlsi3} (insn_list 27 (nil))
    (expr_list:REG_EQUAL (mult:SI (reg/v:SI 23)
            (const_int 64))
        (nil)))

(insn 32 30 33 (set (reg:SI 0 %eax)
        (minus:SI (reg:SI 0 %eax)
            (mem:SI (plus:SI (reg:SI 7 %esp)
                    (const_int 28)) 0))) 160 {subsi3+1} (insn_list 30 (nil))
    (expr_list:REG_EQUAL (mult:SI (reg/v:SI 23)
            (const_int 63))
        (nil)))




We're still OK at this point.  Note that we now have a read from the memory
location stored in insn 222.

We continue processing reloads for a few more uninteresting instrutions until
we come along this insn:

(insn 37 35 39 (set (mem:SI (plus:SI (reg:SI 7 %esp)
                (const_int 28)) 0)
        (minus:SI (reg:SI 2 %ecx)
            (reg:SI 0 %eax))) 160 {subsi3+1} (insn_list 35 (nil))
    (expr_list:REG_DEAD (reg:SI 2 %ecx)
        (expr_list:REG_DEAD (reg:SI 0 %eax)
            (nil))))
$41 = void
Reload 0: reload_in (SI) = (reg:SI 2 %ecx)
        reload_out (SI) = (mem:SI (plus:SI (reg:SI 7 %esp)
                                                        (const_int 28)) 0)
        GENERAL_REGS, RELOAD_OTHER (opnum = 0)
        reload_in_reg: (reg:SI 2 %ecx)
        reload_out_reg: (reg/v:SI 23)
        reload_reg_rtx: (reg:SI 2 %ecx)


Note that reload_out_reg is reg23.

reg_last_reload_reg[23] = %eax

reg_reloaded_contents[%eax] = 23

spill_reg_store[%eax] = insn 222.

spill_reg_stored_to[%eax] = reg23

We get into this code in emit_reload_insns:


      /* If this is an output reload that stores something that is
         not loaded in this same reload, see if we can eliminate a previous
         store.  */
      {
        rtx pseudo = reload_out_reg[j];

        if (pseudo
            && GET_CODE (pseudo) == REG
            && ! rtx_equal_p (reload_in_reg[j], pseudo)
            && REGNO (pseudo) >= FIRST_PSEUDO_REGISTER
            && reg_last_reload_reg[REGNO (pseudo)])
          {
            int pseudo_no = REGNO (pseudo);
            int last_regno = REGNO (reg_last_reload_reg[pseudo_no]);

            /* We don't need to test full validity of last_regno for
               inherit here; we only want to know if the store actually
               matches the pseudo.  */
            if (reg_reloaded_contents[last_regno] == pseudo_no
                && spill_reg_store[last_regno]
                && rtx_equal_p (pseudo, spill_reg_stored_to[last_regno]))
              delete_output_reload (insn, j, last_regno);
          }
      }

Note the call to delete_output_reload -- it will delete insn 222, which in
turn causes insn 32 to read from an uninitialized memory location.



The testcase:









struct _IO_FILE {
};
typedef struct _IO_FILE _IO_FILE;
struct _IO_FILE_plus;
extern struct _IO_FILE_plus _IO_stdin_, _IO_stdout_, _IO_stderr_;
typedef union rtunion_def
{
  struct rtx_def *rtx;
} rtunion;
typedef struct rtx_def
{
  unsigned int volatil : 1;
  rtunion fld[1];
} *rtx;
enum tree_code {
  LAST_AND_UNUSED_TREE_CODE	 
};
extern char tree_code_type[256 ];
typedef union tree_node *tree;
struct tree_common
{
  enum tree_code code : 8;
  unsigned public_flag : 1;
};
typedef struct {
  int  r[(11 + sizeof (int ))/(sizeof (int ))];
} realvaluetype;
struct tree_real_cst
{
  struct rtx_def *rtl;	 
};
struct tree_identifier
{
  char *pointer;
};
struct tree_decl
{
  struct rtx_def *rtl;	 
  union tree_node *name;
};

union tree_node
{
  struct tree_common common;
  struct tree_real_cst real_cst;
  struct tree_decl decl;
  struct tree_identifier identifier;
 };
struct _obstack_chunk		 
{
  char  *limit;			 
  struct _obstack_chunk *prev;	 
  char	contents[4];		 
};
struct obstack		 
{
  long	chunk_size;		 
  struct _obstack_chunk *chunk;	 
  char	*object_base;		 
  char	*next_free;		 
  char	*chunk_limit;		 
  int  temp;		 
  int   alignment_mask;		 
  struct _obstack_chunk *(*chunkfun) (void *, long);
  void (*freefun) (void *, struct _obstack_chunk *);
  void *extra_arg;		 
  unsigned use_extra_arg:1;	 
  unsigned maybe_empty_object:1; 
  unsigned alloc_failed:1;	 
};
extern struct obstack permanent_obstack;
int const_labelno;
struct addr_const
{
  rtx base;
  int  offset;
};

struct constant_descriptor
{
  struct constant_descriptor *next;
  char *label;
  char contents[1];
};
static struct constant_descriptor *const_hash_table[1009 ];
struct deferred_constant
{
  struct deferred_constant *next;
  tree exp;
  int reloc;
  int labelno;
};
static struct deferred_constant *after_function_constants;
static struct deferred_constant *deferred_constants;
static int defer_addressed_constants_flag;
rtx
output_constant_def (exp)
     tree exp;
{
  register int hash;
  register struct constant_descriptor *desc;
  char label[256];
  char *found = 0;
  int reloc;
  register rtx def;
  hash = const_hash (exp) % 1009 ;
    {
      do {	sprintf ( label , "*.%s%d",   "LC" , (unsigned) (  const_labelno ));	} while (0) ;
      desc->label
	= (char *) __extension__	({ struct obstack *__h = ( &permanent_obstack );
	__extension__	({ struct obstack *__o = ( __h );
		int __len = (  (  strlen (label) ) );
		if (__o->next_free + __len + 1 > __o->chunk_limit)	_obstack_newchunk (__o, __len + 1);
 	}) ;	
	__extension__	({ struct obstack *__o1 = ( __h );
	void *value;
	if (__o1->next_free == value)	__o1->maybe_empty_object = 1;
	value;
        }) ;
 }) ;
      const_hash_table[hash] = desc;
    }
  do	{	
	rtx rtl = (tree_code_type[(int) ( ((enum tree_code) (  exp  )->common.code)  )]  != 'd'	? ((    exp    )  ->real_cst.rtl)  : ((     exp    )  ->decl.rtl) );
	fprintf (((_IO_FILE*)(&_IO_stderr_))  , "Encode %s, public = %d\n",	((     ((     exp    )  ->decl.name)     )   ->identifier.pointer) ,	((  exp  )->common.public_flag) );
	(( (( rtl )->fld[  0 ].rtx)  )->volatil) 	= (tree_code_type[(int) ( ((enum tree_code) (  exp  )->common.code)  )]  != 'd'	|| ! ((  exp  )->common.public_flag)  );
	}	while (0) ;
}



More information about the Gcc-bugs mailing list