This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

SH bootstrap failure


Hi,

Current mainline does not bootstrap on sh4-unknown-linux-gnu
for miscompiling with the stage1 compiler. It seems the latent
bug related with register allocation. The appended testcase
aborts on 3.2-3.4 sh4 compilers with -O1 and -O2. It's an ugly
deformation of mainline gcc/varasm.c:output_constructor, but
the point would be the need of many DImode registers.

After the postreload pass, the line

	assemble_zeros (pos - total_bytes);

of the testcase is compiled to

--
(insn 225 181 226 13 (nil) (set (reg:DI 4 r4 [195])
	(reg/v:DI 10 r10 [180])) 135 {*movdi_i} (nil)
    (nil))

(insn 226 225 128 13 (nil) (set (reg:DI 3 r3)
	(mem:DI (plus:SI (reg/f:SI 14 r14)
		(const_int 8 [0x8])) [0 total_bytes S8 A32])) 135 {*movdi_i} (nil)
    (nil))

(insn 128 226 209 13 0x84d2d00 (parallel [
	    (set (reg:DI 4 r4 [195])
		(minus:DI (reg:DI 4 r4 [195])
		    (reg:DI 3 r3)))
	    (clobber (reg:SI 147 t))
	]) 25 {subdi3_compact} (nil)
    (nil))

(insn 209 128 131 13 (nil) (set (reg/f:SI 1 r1 [196])
	(symbol_ref:SI ("assemble_zeros"))) 123 {movsi_ie} (nil)
    (expr_list:REG_EQUIV (symbol_ref:SI ("assemble_zeros"))
	(nil)))
...
--

and the final asm code is the following.

--
	mov	r11,r5
	mov.l	@(8,r14),r3
	mov.l	@(12,r14),r4
	clrt
	subc	r3,r4
	mov.l	.L38,r1
	jsr	@r1
	subc	r4,r5
	...
.L38:
	.long	assemble_zeros
--

It looks like that (r4, r5) pair is assigned to the DImode register
195 and (r3, r4) to a scratch register for total_bytes.
Then a bad code for the subtraction is generated because r4 is shared
with these two register pairs.
The appended patch works for me, i.e. bootstrapped on mainline with
no new regressions, though the register allocation part is beyond me
and I don't know the right fix. Thought?

Regards,
	kaz
--
	* config/sh/sh.h (HARD_REGNO_MODE_OK): Don't accept DImode
	Rodd for ! TARGET_SHMEDIA.

diff -u3p ORIG/gcc/gcc/config/sh/sh.h LOCAL/gcc/gcc/config/sh/sh.h
--- ORIG/gcc/gcc/config/sh/sh.h	Sat Jun  7 19:11:01 2003
+++ LOCAL/gcc/gcc/config/sh/sh.h	Tue Jun 10 16:32:02 2003
@@ -979,6 +979,8 @@ extern char sh_additional_register_names
 	  && (((REGNO) - FIRST_FP_REG) & 1) == 0)) \
    : XD_REGISTER_P (REGNO) \
    ? (MODE) == DFmode \
+   : GENERAL_REGISTER_P (REGNO) && (MODE) == DImode \
+   ? (TARGET_SHMEDIA || (((REGNO) - FIRST_GENERAL_REG) & 1) == 0) \
    : TARGET_REGISTER_P (REGNO) \
    ? ((MODE) == DImode || (MODE) == SImode) \
    : (REGNO) == PR_REG ? 0			\

--
#include <stdio.h>
#include <stdlib.h>

struct tstr
{
  struct tstr *type;
  int index;
  int val;
};

typedef struct tstr *tree;

long long tree_low_cst (int index, int flg)
{
  return index + flg;
}

unsigned long long int_size_in_bytes (unsigned long long size)
{
  return size/32;
}

void
assemble_zeros (unsigned long long size)
{
  if (size != 70)
    {
      printf ("%llu\n", size);
      abort ();
    }
}

int int_byte_position (int index)
{
  return index * 8;
}

void
output_constructor (tree exp, unsigned long long size, unsigned int align)
{
  tree field = exp;
  long long total_bytes = 10;
  int val = exp->val;
  tree index = exp->type;

  if (index)
    {
      unsigned long long fieldsize = int_size_in_bytes (size);
      long long lo_index = 0;
      long long hi_index = tree_low_cst (index->index, 0);
      long long index;

      for (index = lo_index; index <= hi_index; index++)
	{

	  if (val == 0)
	    assemble_zeros (fieldsize);

	  total_bytes += fieldsize;
	}
    }
  else if (field == 0 || field->index)
    {
      long long pos;

      pos = (field && field->index) ? int_byte_position (field->index) : 0;
      if ((field != 0 || index != 0) && pos != total_bytes)
	{
	  assemble_zeros (pos - total_bytes);
	  total_bytes = pos;
	}

    }
  else if (val != 0)
    abort ();

  if ((unsigned long long)total_bytes < size)
    assemble_zeros (size - total_bytes);
}

struct tstr tstr = { 0, 10, 20, }; 

int
main ()
{
  output_constructor (&tstr, 23, 47);
  exit (0);
}


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]