This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: improve unaligned loads with no special insns
- From: Eric Botcazou <ebotcazou at libertysurf dot fr>
- To: Richard Henderson <rth at redhat dot com>
- Cc: gcc-patches at gcc dot gnu dot org
- Date: Sun, 7 Nov 2004 10:33:36 +0100
- Subject: Re: improve unaligned loads with no special insns
- References: <20041106001345.GA23308@redhat.com>
> The object here is to forcably align a memory (with AND), load two
> words, and shift them into place. The mechanism that we currently use
> is loading N aligned units (usually bytes) and shifting them into place
> one at a time. The new scheme is more efficient for more than two
> loads, and is *sigificantly* better for 8 byte unaligned loads.
It apparently pessimizes on 32-bit targets for 4-byte unaligned loads:
before at -O2 on SPARC:
f:
ldub [%o0+4], %o4
ldub [%o0+1], %o5
ldub [%o0+2], %g1
ldub [%o0+3], %o0
sll %o5, 24, %o5
sll %g1, 16, %g1
sll %o0, 8, %o0
or %g1, %o5, %g1
or %o0, %g1, %o0
jmp %o7+8
or %o4, %o0, %o0
after:
f:
add %o0, 1, %o0
and %o0, -4, %g1
ld [%g1+4], %o3
ld [%g1], %o2
and %o0, 3, %o0
sll %o0, 3, %o0
sll %o2, 1, %g1
xnor %g0, %o0, %o1
srl %o3, %o0, %o5
sll %g1, %o1, %g1
or %g1, %o5, %o5
jmp %o7+8
mov %o5, %o0
2 more insns.
> For instance,
>
> struct S { char c; long x __attribute__((packed)); };
> long f(struct S *s) { return s->x; }
>
> .text size/ old new
> ia64 208 96
> sparc64 92 48
Right, 6 less insns on SPARC 64-bit at -O2.
> Tested on ia64, alpha and x86 linux.
It could have been nice to test on big-endian, because the new function emits
wrong code there. Testcase attached.
> + /* Shift down the double-word such that the requested value is at bit
> 0. */ + if (shift != const0_rtx)
> + comb = expand_simple_binop (dmode, unsignedp ? LSHIFTRT : ASHIFTRT,
> + comb, shift, NULL, unsignedp, OPTAB_LIB_WIDEN);
> + if (comb == NULL)
> + goto fail;
Probably wrong on big-endian. Something like:
shift = BITS_PER_WORD - shift;
might be needed.
--
Eric Botcazou
struct S { char c; long x __attribute__((packed)); };
long f(struct S *s) { return s->x; }
int main(void)
{
struct S s = { 0, -1 };
if (f(&s) != -1)
abort ();
return 0;
}