------- Comment #6 from falk at debian dot org 2005-10-15 15:04 -------
OK, let's have a look at this somewhat minimal example:
struct S {
long l;
unsigned char c;
};
unsigned long f(unsigned char *p10) {
struct S *p = (struct S *) (p10 + 10);
return p->c;
}
What we want is of course:
ldl v0,18(a0)
and v0,0xff,v0
but we get:
ldl v0,16(a0)
extbl v0,0x2,v0
The problem comes from get_aligned_mem being passed
(mem/s:QI (plus:DI (reg/v/f:DI 70 [ p10 ]
(const_int 18 [0x12])) [0 S1 A64])
However, get_aligned_mem assumes the *base* without offset is
aligned, so it generates bogus code.
get_aligned_mem is being called from alpha_expand_mov_nobwx because
aligned_memory_operand says "yeah" to the above rtx.
aligned_memory_operand is supposed to do:
;; Return 1 if this memory address is a known aligned register plus
;; a constant.
which is in fact what get_aligned_mem needs. However, the first thing
aligned_memory_operand checks is
if (MEM_ALIGN (op) >= 32)
return 1;
which happens to be true, since the base *with* offset is aligned.
This check seems bogus, since the base is still unaligned. However,
given the scary comments surrounding it I don't really dare touching
it. Richard, can you give a hint?
--
falk at debian dot org changed:
What |Removed |Added
----------------------------------------------------------------------------
CC| |rth at gcc dot gnu dot org
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=24178