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]

Re: improve unaligned loads with no special insns


> 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;
}

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