This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
ADDRESSOF still broken
- To: egcs-patches at cygnus dot com
- Subject: ADDRESSOF still broken
- From: Andreas Schwab <schwab at issan dot informatik dot uni-dortmund dot de>
- Date: 19 Oct 1998 10:42:44 +0200
The latest changes to the ADDRESSOF optimisation are still not enough to
make it work again. There can be other insns beside CALL that require
operands to be in memory. For example, the extv/insv patterns normally
require that the first operand is either a memory operand in QImode or a
register operand in SImode (this is the case on m68k). In the example
below, the following insn is triggering the abort:
(insn 22 21 24 (set (reg:SI 35)
(zero_extract:SI (mem/s:QI (addressof:SI (reg/v:SI 33) 32) 0)
(const_int 1)
(const_int 0))) 342 {extzv+1} (nil)
(nil))
The (mem:QI (addressof (reg:SI))) is tried be replaced by (reg:QI) which
is not a valid operand for zero_extract (but a (reg:SI) would be).
Another problem is that doing the purging inside the REG_NOTES of an insn
cannot generate any new insns, and the register that is replaced for the
(mem (addressof)) must be exactly the same as in the insn. For example,
consider the following insn that is generated after cse for the example
below:
(insn 23 22 24 (set (strict_low_part (subreg:QI (reg:SI 33) 0))
(mem/s:QI (addressof:SI (reg/v:SI 32) 31) 0)) 54 {movstrictqi+1} (nil)
(expr_list:REG_EQUAL (zero_extend:SI (mem/s:QI (addressof:SI (reg/v:SI 32) 31) 0))
(nil)))
In the first pass the (mem (addressof)) is replaced by some register after
emitting an appropriate insn to set it, and when processing the note list
exactly the same replacement must be made without emitting any insns this
time.
The compiler was configured for the target m68k-linux.
$ cat ecofflink.i
typedef struct {
unsigned fBitfield : 1;
unsigned continued : 1;
unsigned bt : 6;
unsigned tq4 : 4;
unsigned tq5 : 4;
unsigned tq0 : 4;
unsigned tq1 : 4;
unsigned tq2 : 4;
unsigned tq3 : 4;
} TIR, *pTIR;
typedef struct {
unsigned rfd : 12;
unsigned index : 20;
} RNDXR, *pRNDXR;
struct tir_ext {
unsigned char t_bits1[1];
unsigned char t_tq45[1];
unsigned char t_tq01[1];
unsigned char t_tq23[1];
};
struct rndx_ext {
unsigned char r_bits[4];
};
void
_bfd_ecoff_swap_tir_in (bigend, ext_copy, intern)
int bigend;
const struct tir_ext *ext_copy;
TIR *intern;
{
struct tir_ext ext[1];
*ext = *ext_copy;
if (bigend) {
intern->fBitfield = 0 != (ext->t_bits1[0] & ((unsigned int) 0x80) );
intern->continued = 0 != (ext->t_bits1[0] & ((unsigned int) 0x40) );
intern->bt = (ext->t_bits1[0] & ((unsigned int) 0x3F) )
>> 0 ;
intern->tq4 = (ext->t_tq45[0] & ((unsigned int) 0xF0) )
>> 4 ;
intern->tq5 = (ext->t_tq45[0] & ((unsigned int) 0x0F) )
>> 0 ;
intern->tq0 = (ext->t_tq01[0] & ((unsigned int) 0xF0) )
>> 4 ;
intern->tq1 = (ext->t_tq01[0] & ((unsigned int) 0x0F) )
>> 0 ;
intern->tq2 = (ext->t_tq23[0] & ((unsigned int) 0xF0) )
>> 4 ;
intern->tq3 = (ext->t_tq23[0] & ((unsigned int) 0x0F) )
>> 0 ;
} else {
intern->fBitfield = 0 != (ext->t_bits1[0] & ((unsigned int) 0x01) );
intern->continued = 0 != (ext->t_bits1[0] & ((unsigned int) 0x02) );
intern->bt = (ext->t_bits1[0] & ((unsigned int) 0xFC) )
>> 2 ;
intern->tq4 = (ext->t_tq45[0] & ((unsigned int) 0x0F) )
>> 0 ;
intern->tq5 = (ext->t_tq45[0] & ((unsigned int) 0xF0) )
>> 4 ;
intern->tq0 = (ext->t_tq01[0] & ((unsigned int) 0x0F) )
>> 0 ;
intern->tq1 = (ext->t_tq01[0] & ((unsigned int) 0xF0) )
>> 4 ;
intern->tq2 = (ext->t_tq23[0] & ((unsigned int) 0x0F) )
>> 0 ;
intern->tq3 = (ext->t_tq23[0] & ((unsigned int) 0xF0) )
>> 4 ;
}
}
void
_bfd_ecoff_swap_tir_out (bigend, intern_copy, ext)
int bigend;
const TIR *intern_copy;
struct tir_ext *ext;
{
TIR intern[1];
*intern = *intern_copy;
if (bigend) {
ext->t_bits1[0] = ((intern->fBitfield ? ((unsigned int) 0x80) : 0)
| (intern->continued ? ((unsigned int) 0x40) : 0)
| ((intern->bt << 0 )
& ((unsigned int) 0x3F) ));
ext->t_tq45[0] = (((intern->tq4 << 4 )
& ((unsigned int) 0xF0) )
| ((intern->tq5 << 0 )
& ((unsigned int) 0x0F) ));
ext->t_tq01[0] = (((intern->tq0 << 4 )
& ((unsigned int) 0xF0) )
| ((intern->tq1 << 0 )
& ((unsigned int) 0x0F) ));
ext->t_tq23[0] = (((intern->tq2 << 4 )
& ((unsigned int) 0xF0) )
| ((intern->tq3 << 0 )
& ((unsigned int) 0x0F) ));
} else {
ext->t_bits1[0] = ((intern->fBitfield ? ((unsigned int) 0x01) : 0)
| (intern->continued ? ((unsigned int) 0x02) : 0)
| ((intern->bt << 2 )
& ((unsigned int) 0xFC) ));
ext->t_tq45[0] = (((intern->tq4 << 0 )
& ((unsigned int) 0x0F) )
| ((intern->tq5 << 4 )
& ((unsigned int) 0xF0) ));
ext->t_tq01[0] = (((intern->tq0 << 0 )
& ((unsigned int) 0x0F) )
| ((intern->tq1 << 4 )
& ((unsigned int) 0xF0) ));
ext->t_tq23[0] = (((intern->tq2 << 0 )
& ((unsigned int) 0x0F) )
| ((intern->tq3 << 4 )
& ((unsigned int) 0xF0) ));
}
}
void
_bfd_ecoff_swap_rndx_in (bigend, ext_copy, intern)
int bigend;
const struct rndx_ext *ext_copy;
RNDXR *intern;
{
struct rndx_ext ext[1];
*ext = *ext_copy;
if (bigend) {
intern->rfd = (ext->r_bits[0] << 4 )
| ((ext->r_bits[1] & ((unsigned int) 0xF0) )
>> 4 );
intern->index = ((ext->r_bits[1] & ((unsigned int) 0x0F) )
<< 16 )
| (ext->r_bits[2] << 8 )
| (ext->r_bits[3] << 0 );
} else {
intern->rfd = (ext->r_bits[0] << 0 )
| ((ext->r_bits[1] & ((unsigned int) 0x0F) )
<< 8 );
intern->index = ((ext->r_bits[1] & ((unsigned int) 0xF0) )
>> 4 )
| (ext->r_bits[2] << 4 )
| ((unsigned int) ext->r_bits[3]
<< 12 );
}
}
void
_bfd_ecoff_swap_rndx_out (bigend, intern_copy, ext)
int bigend;
const RNDXR *intern_copy;
struct rndx_ext *ext;
{
RNDXR intern[1];
*intern = *intern_copy;
if (bigend) {
ext->r_bits[0] = intern->rfd >> 4 ;
ext->r_bits[1] = (((intern->rfd << 4 )
& ((unsigned int) 0xF0) )
| ((intern->index >> 16 )
& ((unsigned int) 0x0F) ));
ext->r_bits[2] = intern->index >> 8 ;
ext->r_bits[3] = intern->index >> 0 ;
} else {
ext->r_bits[0] = intern->rfd >> 0 ;
ext->r_bits[1] = (((intern->rfd >> 8 )
& ((unsigned int) 0x0F) )
| ((intern->index << 4 )
& ((unsigned int) 0xF0) ));
ext->r_bits[2] = intern->index >> 4 ;
ext->r_bits[3] = intern->index >> 12 ;
}
}
$ /usr/local/egcs/bin/gcc -O2 -S ecofflink.i
../../gcc/function.c:2921: Internal compiler error in function purge_addressof_1
This is the insn the compiler is choking on:
1998-10-18 Andreas Schwab <schwab@issan.cs.uni-dortmund.de>
* function.c (purge_addressof_1): Instead of aborting when a
bitfield insertion as a replacement for (MEM (ADDRESSOF)) does not
work just put the ADDRESSOF on stack. Otherwise remember all such
successfull replacements, so that exactly the same replacements
can be made on the REG_NOTEs. Remove the special case for CALL
insns again.
(purge_addressof_replacements): New variable.
(purge_addressof): Clear it at end.
--- egcs-2.92/gcc/function.c.~2~ Thu Oct 15 00:31:50 1998
+++ egcs-2.92/gcc/function.c Sun Oct 18 20:21:55 1998
@@ -2812,6 +2812,10 @@
TREE_USED (decl) || DECL_INITIAL (decl) != 0);
}
+/* List of replacements made below in purge_addressof_1 when creating
+ bitfield insertions. */
+static rtx purge_addressof_replacements;
+
/* Helper function for purge_addressof. See if the rtx expression at *LOC
in INSN needs to be changed. If FORCE, always put any ADDRESSOFs into
the stack. */
@@ -2874,6 +2878,25 @@
{
int size_x, size_sub;
+ if (!insn)
+ {
+ /* When processing REG_NOTES look at the list of
+ replacements done on the insn to find the register that X
+ was replaced by. */
+ rtx tem;
+
+ for (tem = purge_addressof_replacements; tem != NULL_RTX;
+ tem = XEXP (XEXP (tem, 1), 1))
+ if (rtx_equal_p (x, XEXP (tem, 0)))
+ {
+ *loc = XEXP (XEXP (tem, 1), 0);
+ return;
+ }
+
+ /* There should always be such a replacement. */
+ abort ();
+ }
+
size_x = GET_MODE_BITSIZE (GET_MODE (x));
size_sub = GET_MODE_BITSIZE (GET_MODE (sub));
@@ -2889,12 +2912,15 @@
if (store)
{
- /* If we can't replace with a register, be afraid. */
-
start_sequence ();
val = gen_reg_rtx (GET_MODE (x));
if (! validate_change (insn, loc, val, 0))
- abort ();
+ {
+ /* Discard the current sequence and put the
+ ADDRESSOF on stack. */
+ end_sequence ();
+ goto give_up;
+ }
seq = gen_sequence ();
end_sequence ();
emit_insn_before (seq, insn);
@@ -2916,21 +2942,33 @@
GET_MODE_SIZE (GET_MODE (sub)),
GET_MODE_SIZE (GET_MODE (sub)));
- /* If we can't replace with a register, be afraid. */
if (! validate_change (insn, loc, val, 0))
- abort ();
+ {
+ /* Discard the current sequence and put the
+ ADDRESSOF on stack. */
+ end_sequence ();
+ goto give_up;
+ }
seq = gen_sequence ();
end_sequence ();
emit_insn_before (seq, insn);
}
+ /* Remember the replacement so that the same one can be done
+ on the REG_NOTES. */
+ purge_addressof_replacements
+ = gen_rtx_EXPR_LIST (VOIDmode, x,
+ gen_rtx_EXPR_LIST (VOIDmode, val,
+ purge_addressof_replacements));
+
/* We replaced with a reg -- all done. */
return;
}
}
else if (validate_change (insn, loc, sub, 0))
goto restart;
+ give_up:;
/* else give up and put it into the stack */
}
else if (code == ADDRESSOF)
@@ -2944,12 +2982,6 @@
purge_addressof_1 (&SET_SRC (x), insn, force, 0);
return;
}
- else if (code == CALL)
- {
- purge_addressof_1 (&XEXP (x, 0), insn, 1, 0);
- purge_addressof_1 (&XEXP (x, 1), insn, force, 0);
- return;
- }
/* Scan all subexpressions. */
fmt = GET_RTX_FORMAT (code);
@@ -2980,6 +3012,7 @@
asm_noperands (PATTERN (insn)) > 0, 0);
purge_addressof_1 (®_NOTES (insn), NULL_RTX, 0, 0);
}
+ purge_addressof_replacements = 0;
}
/* Pass through the INSNS of function FNDECL and convert virtual register
--
Andreas Schwab "And now for something
schwab@issan.cs.uni-dortmund.de completely different"
schwab@gnu.org