This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
SH bootstrap failure
- From: kaz Kojima <kkojima at rr dot iij4u dot or dot jp>
- To: gcc-patches at gcc dot gnu dot org
- Cc: joern dot rennecke at superh dot com, aoliva at redhat dot com
- Date: Wed, 11 Jun 2003 13:23:10 +0900
- Subject: 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);
}