331 lines
6.6 KiB
ArmAsm
331 lines
6.6 KiB
ArmAsm
.text
|
|
.asciz "@(#)misalign.s 1.1 94/10/31 Copyr 1987 Sun Micro"
|
|
.align 4
|
|
|
|
! Copyright (c) 1987 by Sun Microsystems,Inc.
|
|
|
|
!
|
|
! C library routines for compiler support of misaligned memory
|
|
! references. These are called when an in-line test reveals a
|
|
! misaligned address.
|
|
!
|
|
|
|
#include <machine/asm_linkage.h>
|
|
|
|
!- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
!
|
|
! int ld_int(p)
|
|
! char *p;
|
|
! {
|
|
! /*
|
|
! * load 32-bit int from misaligned address
|
|
! * cost(16-bit aligned case): 9 cycles
|
|
! * cost(8-bit aligned case): 18 cycles
|
|
! */
|
|
! }
|
|
!
|
|
RTENTRY(ld_int)
|
|
andcc %o0,1,%g0 ! test 16-bit alignment
|
|
be,a 1f ! fast case: two loads;
|
|
lduh [%o0+2],%o1 ! do first one in delay slot
|
|
!
|
|
ldub [%o0+3],%o3 ! slow case: load 4 bytes in <o0,o1,o2,o3>
|
|
ldub [%o0+2],%o2
|
|
ldub [%o0+1],%o1
|
|
ldub [%o0],%o0 ! note this has to be done last.
|
|
sll %o2,8,%o2
|
|
sll %o1,16,%o1
|
|
sll %o0,24,%o0
|
|
or %o1,%o0,%o0 ! put the pieces together.
|
|
or %o2,%o0,%o0
|
|
retl
|
|
or %o3,%o0,%o0
|
|
1:
|
|
lduh [%o0],%o0 ! 2nd half of fast case
|
|
sll %o0,16,%o0 ! shift, concat, done.
|
|
retl
|
|
or %o0,%o1,%o0
|
|
|
|
!- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
!
|
|
! float ld_float(p)
|
|
! char *p;
|
|
! {
|
|
! /* load 32-bit float (not double!) from misaligned address */
|
|
! }
|
|
!
|
|
RTENTRY(ld_float)
|
|
save %sp,-SA(MINFRAME+8),%sp
|
|
andcc %i0,1,%g0 ! test for short alignment
|
|
be,a 1f
|
|
lduh [%i0],%o0 ! short aligned case: 2 loads, 2 stores
|
|
!
|
|
ldub [%i0],%o0 ! byte aligned case: 4 loads, 4 stores
|
|
ldub [%i0+1],%o1
|
|
ldub [%i0+2],%o2
|
|
ldub [%i0+3],%o3
|
|
stb %o0,[%fp-4]
|
|
stb %o1,[%fp-3]
|
|
stb %o2,[%fp-2]
|
|
b 2f
|
|
stb %o3,[%fp-1]
|
|
1:
|
|
lduh [%i0+2],%o1 ! rest of short aligned case
|
|
sth %o0,[%fp-4]
|
|
sth %o1,[%fp-2]
|
|
2:
|
|
ld [%fp-4],%f0 ! load FPU reg, done
|
|
ret
|
|
restore
|
|
|
|
!- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
!
|
|
! double ld_double(p)
|
|
! char *p;
|
|
! {
|
|
! /* load 64-bit float from misaligned address */
|
|
! }
|
|
!
|
|
RTENTRY(ld_double)
|
|
save %sp,-SA(MINFRAME+8),%sp
|
|
andcc %i0,3,%g0 ! test for long alignment
|
|
be,a 1f ! long aligned case: 2 loads, no stores
|
|
ld [%i0],%f0
|
|
!
|
|
andcc %i0,1,%g0 ! test for short alignment
|
|
be,a 2f ! short aligned case: 4 loads, 4 stores
|
|
lduh [%i0],%o0
|
|
!
|
|
ldub [%i0],%o0 ! worst case: byte alignment
|
|
ldub [%i0+1],%o1 ! 8 loads, 8 stores
|
|
ldub [%i0+2],%o2
|
|
ldub [%i0+3],%o3
|
|
stb %o0,[%fp-8]
|
|
stb %o1,[%fp-7]
|
|
stb %o2,[%fp-6]
|
|
stb %o3,[%fp-5]
|
|
ldub [%i0+4],%o0
|
|
ldub [%i0+5],%o1
|
|
ldub [%i0+6],%o2
|
|
ldub [%i0+7],%o3
|
|
stb %o0,[%fp-4]
|
|
stb %o1,[%fp-3]
|
|
stb %o2,[%fp-2]
|
|
stb %o3,[%fp-1]
|
|
ldd [%fp-8],%f0 ! load f0-f1, done
|
|
ret
|
|
restore
|
|
2:
|
|
lduh [%i0+2],%o1 ! rest of short aligned case
|
|
lduh [%i0+4],%o2
|
|
lduh [%i0+6],%o3
|
|
sth %o0,[%fp-8]
|
|
sth %o1,[%fp-6]
|
|
sth %o2,[%fp-4]
|
|
sth %o3,[%fp-2]
|
|
ldd [%fp-8],%f0 ! load f0-f1, done
|
|
ret
|
|
restore
|
|
1:
|
|
ld [%i0+4],%f1 ! rest of long aligned case
|
|
ret
|
|
restore
|
|
|
|
!- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
!
|
|
! int st_int(x,p)
|
|
! int x;
|
|
! char *p;
|
|
! {
|
|
! /* store 32-bit int from misaligned address;
|
|
! return stored value */
|
|
! }
|
|
!
|
|
RTENTRY(st_int)
|
|
andcc %o1,1,%g0 ! test for short alignment
|
|
be,a 1f
|
|
srl %o0,16,%o4
|
|
!
|
|
srl %o0,24,%o5 ! byte aligned case
|
|
stb %o5,[%o1]
|
|
srl %o0,16,%o2
|
|
stb %o2,[%o1+1]
|
|
srl %o0,8,%o3
|
|
stb %o3,[%o1+2]
|
|
retl
|
|
stb %o0,[%o1+3]
|
|
1:
|
|
sth %o4,[%o1] ! rest of short aligned case
|
|
retl
|
|
sth %o0,[%o1+2]
|
|
|
|
!- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
!
|
|
! float st_float(x,p)
|
|
! float x;
|
|
! char *p;
|
|
! {
|
|
! /* store 32-bit float from misaligned address;
|
|
! return stored value */
|
|
! }
|
|
!
|
|
RTENTRY(st_float)
|
|
save %sp,-SA(MINFRAME+8),%sp
|
|
andcc %i1,1,%g0 ! test for short alignment
|
|
be,a 1f ! short aligned case
|
|
srl %i0,16,%o0
|
|
!
|
|
srl %i0,24,%o0 ! byte aligned case
|
|
srl %i0,16,%o1
|
|
srl %i0,8,%o2
|
|
stb %o0,[%i1]
|
|
stb %o1,[%i1+1]
|
|
stb %o2,[%i1+2]
|
|
stb %i0,[%i1+3]
|
|
st %i0,[%fp-4] ! store temp, load f0, done
|
|
ld [%fp-4],%f0
|
|
ret
|
|
restore
|
|
1:
|
|
sth %o0,[%i1] ! rest of short aligned case
|
|
sth %i0,[%i1+2]
|
|
st %i0,[%fp-4]
|
|
ld [%fp-4],%f0
|
|
ret
|
|
restore
|
|
|
|
!- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
!
|
|
! double st_double(x,p)
|
|
! double x;
|
|
! char *p;
|
|
! {
|
|
! /* store 64-bit float from misaligned address;
|
|
! return stored value */
|
|
! }
|
|
!
|
|
RTENTRY(st_double)
|
|
save %sp,-SA(MINFRAME+8),%sp
|
|
andcc %i2,3,%g0 ! test for long alignment
|
|
be,a 1f ! long aligned case: 2 stores, 2 loads
|
|
st %i0,[%i2]
|
|
!
|
|
andcc %i2,1,%g0 ! test for short alignment
|
|
be,a 2f ! short aligned case: 4 stores, 4 loads
|
|
srl %i0,16,%o0
|
|
! ! byte aligned case: the pits
|
|
srl %i0,24,%o0
|
|
srl %i0,16,%o1
|
|
srl %i0,8,%o2
|
|
stb %o0,[%i2] ! store first word, a byte at a time
|
|
stb %o1,[%i2+1]
|
|
stb %o2,[%i2+2]
|
|
stb %i0,[%i2+3]
|
|
srl %i1,24,%o0
|
|
srl %i1,16,%o1
|
|
srl %i1,8,%o2
|
|
stb %o0,[%i2+4] ! store second word, a byte at a time
|
|
stb %o1,[%i2+5]
|
|
stb %o2,[%i2+6]
|
|
stb %i1,[%i2+7]
|
|
std %i0,[%fp-8] ! since dest is misaligned, must use temp
|
|
ldd [%fp-8],%f0 ! load f0,f1 from double-aligned temp, done
|
|
ret
|
|
restore
|
|
2: ! rest of short aligned case
|
|
srl %i1,16,%o1
|
|
sth %o0,[%i2] ! store two words, a half word at a time
|
|
sth %i0,[%i2+2]
|
|
sth %o1,[%i2+4]
|
|
sth %i1,[%i2+6]
|
|
std %i0,[%fp-8] ! since dest is misaligned, must use temp
|
|
ldd [%fp-8],%f0 ! load f0,f1 from double-aligned temp, done
|
|
ret
|
|
restore
|
|
1: ! rest of long aligned case
|
|
st %i1,[%i2+4]
|
|
ld [%i2],%f0 ! load f0,f1 from long-aligned memory, done
|
|
ld [%i2+4],%f1
|
|
ret
|
|
restore
|
|
|
|
!- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
!
|
|
! void st_float_foreff(x,p)
|
|
! float x;
|
|
! char *p;
|
|
! {
|
|
! /* store 32-bit float from misaligned address */
|
|
! }
|
|
!
|
|
RTENTRY(st_float_foreff)
|
|
andcc %o1,1,%g0 ! test for short alignment
|
|
be,a 1f
|
|
srl %o0,16,%o2
|
|
!
|
|
srl %o0,24,%o2 ! byte aligned case
|
|
srl %o0,16,%o3
|
|
srl %o0,8,%o4
|
|
stb %o2,[%o1]
|
|
stb %o3,[%o1+1]
|
|
stb %o4,[%o1+2]
|
|
retl
|
|
stb %o0,[%o1+3]
|
|
1: ! rest of short aligned case
|
|
sth %o2,[%o1]
|
|
retl
|
|
sth %o0,[%o1+2]
|
|
|
|
!- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
!
|
|
! void st_double_foreff(x,p)
|
|
! double x;
|
|
! char *p;
|
|
! {
|
|
! /* store 64-bit float from misaligned address;
|
|
! return stored value */
|
|
! }
|
|
!
|
|
RTENTRY(st_double_foreff)
|
|
andcc %o2,3,%g0 ! test for long alignment
|
|
be,a 1f ! long aligned case: 2 stores
|
|
st %o0,[%o2]
|
|
!
|
|
andcc %o2,1,%g0 ! test for short alignment
|
|
be,a 2f ! short aligned case: 4 stores
|
|
srl %o0,16,%o3
|
|
!
|
|
srl %o0,24,%o3 ! byte aligned case: 8 stores
|
|
srl %o0,16,%o4
|
|
srl %o0,8,%o5
|
|
stb %o3,[%o2]
|
|
stb %o4,[%o2+1]
|
|
stb %o5,[%o2+2]
|
|
stb %o0,[%o2+3]
|
|
srl %o1,24,%o3
|
|
srl %o1,16,%o4
|
|
srl %o1,8,%o5
|
|
stb %o3,[%o2+4]
|
|
stb %o4,[%o2+5]
|
|
stb %o5,[%o2+6]
|
|
retl
|
|
stb %o1,[%o2+7]
|
|
2: ! rest of short aligned case
|
|
srl %o1,16,%o4
|
|
sth %o3,[%o2]
|
|
sth %o0,[%o2+2]
|
|
sth %o4,[%o2+4]
|
|
retl
|
|
sth %o1,[%o2+6]
|
|
1: ! rest of long aligned case
|
|
retl
|
|
st %o1,[%o2+4]
|