Blame sysdeps/ia64/memcpy.S

Packit 6c4009
/* Optimized version of the standard memcpy() function.
Packit 6c4009
   This file is part of the GNU C Library.
Packit 6c4009
   Copyright (C) 2000-2018 Free Software Foundation, Inc.
Packit 6c4009
   Contributed by Dan Pop for Itanium <Dan.Pop@cern.ch>.
Packit 6c4009
   Rewritten for McKinley by Sverre Jarp, HP Labs/CERN <Sverre.Jarp@cern.ch>
Packit 6c4009
Packit 6c4009
   The GNU C Library is free software; you can redistribute it and/or
Packit 6c4009
   modify it under the terms of the GNU Lesser General Public
Packit 6c4009
   License as published by the Free Software Foundation; either
Packit 6c4009
   version 2.1 of the License, or (at your option) any later version.
Packit 6c4009
Packit 6c4009
   The GNU C Library is distributed in the hope that it will be useful,
Packit 6c4009
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 6c4009
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 6c4009
   Lesser General Public License for more details.
Packit 6c4009
Packit 6c4009
   You should have received a copy of the GNU Lesser General Public
Packit 6c4009
   License along with the GNU C Library; if not, see
Packit 6c4009
   <http://www.gnu.org/licenses/>.  */
Packit 6c4009
Packit 6c4009
/* Return: dest
Packit 6c4009
Packit 6c4009
   Inputs:
Packit 6c4009
        in0:    dest
Packit 6c4009
        in1:    src
Packit 6c4009
        in2:    byte count
Packit 6c4009
Packit 6c4009
   An assembly implementation of the algorithm used by the generic C
Packit 6c4009
   version from glibc.  The case when source and sest are aligned is
Packit 6c4009
   treated separately, for extra performance.
Packit 6c4009
Packit 6c4009
   In this form, memcpy assumes little endian mode.  For big endian mode,
Packit 6c4009
   sh1 must be computed using an extra instruction: sub sh1 = 64, sh1
Packit 6c4009
   and the order of r[MEMLAT] and r[MEMLAT+1] must be reverted in the
Packit 6c4009
   shrp instruction.  */
Packit 6c4009
Packit 6c4009
#define USE_LFETCH
Packit 6c4009
#define USE_FLP
Packit 6c4009
#include <sysdep.h>
Packit 6c4009
#undef ret
Packit 6c4009
Packit 6c4009
#define LFETCH_DIST     500
Packit 6c4009
Packit 6c4009
#define ALIGN_UNROLL_no   4 // no. of elements
Packit 6c4009
#define ALIGN_UNROLL_sh	  2 // (shift amount)
Packit 6c4009
Packit 6c4009
#define MEMLAT	8
Packit 6c4009
#define Nrot	((4*(MEMLAT+2) + 7) & ~7)
Packit 6c4009
Packit 6c4009
#define OP_T_THRES 	16
Packit 6c4009
#define OPSIZ 		8
Packit 6c4009
Packit 6c4009
#define loopcnt		r14
Packit 6c4009
#define elemcnt		r15
Packit 6c4009
#define saved_pr	r16
Packit 6c4009
#define saved_lc	r17
Packit 6c4009
#define adest		r18
Packit 6c4009
#define dest		r19
Packit 6c4009
#define asrc		r20
Packit 6c4009
#define src		r21
Packit 6c4009
#define len		r22
Packit 6c4009
#define tmp2		r23
Packit 6c4009
#define tmp3		r24
Packit 6c4009
#define	tmp4		r25
Packit 6c4009
#define ptable		r26
Packit 6c4009
#define ploop56		r27
Packit 6c4009
#define	loopaddr	r28
Packit 6c4009
#define	sh1		r29
Packit 6c4009
#define ptr1		r30
Packit 6c4009
#define ptr2		r31
Packit 6c4009
Packit 6c4009
#define movi0 		mov
Packit 6c4009
Packit 6c4009
#define p_scr		p6
Packit 6c4009
#define p_xtr		p7
Packit 6c4009
#define p_nxtr		p8
Packit 6c4009
#define p_few		p9
Packit 6c4009
Packit 6c4009
#if defined(USE_FLP)
Packit 6c4009
#define load		ldf8
Packit 6c4009
#define store		stf8
Packit 6c4009
#define tempreg		f6
Packit 6c4009
#define the_r		fr
Packit 6c4009
#define the_s		fs
Packit 6c4009
#define the_t		ft
Packit 6c4009
#define the_q		fq
Packit 6c4009
#define the_w		fw
Packit 6c4009
#define the_x		fx
Packit 6c4009
#define the_y		fy
Packit 6c4009
#define the_z		fz
Packit 6c4009
#elif defined(USE_INT)
Packit 6c4009
#define load		ld8
Packit 6c4009
#define store		st8
Packit 6c4009
#define tempreg		tmp2
Packit 6c4009
#define the_r		r
Packit 6c4009
#define the_s		s
Packit 6c4009
#define the_t		t
Packit 6c4009
#define the_q		q
Packit 6c4009
#define the_w		w
Packit 6c4009
#define the_x		x
Packit 6c4009
#define the_y		y
Packit 6c4009
#define the_z		z
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
#ifdef GAS_ALIGN_BREAKS_UNWIND_INFO
Packit 6c4009
/* Manually force proper loop-alignment.  Note: be sure to
Packit 6c4009
   double-check the code-layout after making any changes to
Packit 6c4009
   this routine! */
Packit 6c4009
# define ALIGN(n)	{ nop 0 }
Packit 6c4009
#else
Packit 6c4009
# define ALIGN(n)	.align n
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
#if defined(USE_LFETCH)
Packit 6c4009
#define LOOP(shift)						\
Packit 6c4009
		ALIGN(32);					\
Packit 6c4009
.loop##shift##:							\
Packit 6c4009
{ .mmb								\
Packit 6c4009
(p[0])	ld8.nt1	r[0] = [asrc], 8 ;				\
Packit 6c4009
(p[0])	lfetch.nt1 [ptr1], 16 ;					\
Packit 6c4009
	nop.b 0 ;						\
Packit 6c4009
} { .mib							\
Packit 6c4009
(p[MEMLAT+1]) st8 [dest] = tmp3, 8 ;				\
Packit 6c4009
(p[MEMLAT]) shrp tmp3 = r[MEMLAT], s[MEMLAT+1], shift ;		\
Packit 6c4009
	nop.b 0 ;;						\
Packit 6c4009
 } { .mmb							\
Packit 6c4009
(p[0])	ld8.nt1	s[0] = [asrc], 8 ;				\
Packit 6c4009
(p[0])	lfetch.nt1	[ptr2], 16 ;				\
Packit 6c4009
	nop.b 0 ;						\
Packit 6c4009
} { .mib							\
Packit 6c4009
(p[MEMLAT+1]) st8 [dest] = tmp4, 8 ;				\
Packit 6c4009
(p[MEMLAT]) shrp tmp4 = s[MEMLAT], r[MEMLAT], shift ;		\
Packit 6c4009
	br.ctop.sptk.many .loop##shift 				\
Packit 6c4009
;; }								\
Packit 6c4009
{ .mib								\
Packit 6c4009
	br.cond.sptk.many .copy_bytes ; /* deal with the remaining bytes */  \
Packit 6c4009
}
Packit 6c4009
#else
Packit 6c4009
#define LOOP(shift)						\
Packit 6c4009
		ALIGN(32);					\
Packit 6c4009
.loop##shift##:							\
Packit 6c4009
{ .mmb								\
Packit 6c4009
(p[0])	ld8.nt1	r[0] = [asrc], 8 ;				\
Packit 6c4009
	nop.b 0 ;						\
Packit 6c4009
} { .mib							\
Packit 6c4009
(p[MEMLAT+1]) st8 [dest] = tmp3, 8 ;				\
Packit 6c4009
(p[MEMLAT]) shrp tmp3 = r[MEMLAT], s[MEMLAT+1], shift ;		\
Packit 6c4009
	nop.b 0 ;;						\
Packit 6c4009
 } { .mmb							\
Packit 6c4009
(p[0])	ld8.nt1	s[0] = [asrc], 8 ;				\
Packit 6c4009
	nop.b 0 ;						\
Packit 6c4009
} { .mib							\
Packit 6c4009
(p[MEMLAT+1]) st8 [dest] = tmp4, 8 ;				\
Packit 6c4009
(p[MEMLAT]) shrp tmp4 = s[MEMLAT], r[MEMLAT], shift ;		\
Packit 6c4009
	br.ctop.sptk.many .loop##shift 				\
Packit 6c4009
;; }								\
Packit 6c4009
{ .mib								\
Packit 6c4009
	br.cond.sptk.many .copy_bytes ; /* deal with the remaining bytes */  \
Packit 6c4009
}
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
Packit 6c4009
ENTRY(memcpy)
Packit 6c4009
{ .mmi
Packit 6c4009
	.prologue
Packit 6c4009
	alloc 	r2 = ar.pfs, 3, Nrot - 3, 0, Nrot
Packit 6c4009
	.rotr	r[MEMLAT+1], s[MEMLAT+2], q[MEMLAT+1], t[MEMLAT+1]
Packit 6c4009
	.rotp	p[MEMLAT+2]
Packit 6c4009
	.rotf	fr[MEMLAT+1], fq[MEMLAT+1], fs[MEMLAT+1], ft[MEMLAT+1]
Packit 6c4009
	mov	ret0 = in0		// return tmp2 = dest
Packit 6c4009
	.save   pr, saved_pr
Packit 6c4009
	movi0	saved_pr = pr		// save the predicate registers
Packit 6c4009
} { .mmi
Packit 6c4009
	and	tmp4 = 7, in0 		// check if destination is aligned
Packit 6c4009
	mov 	dest = in0		// dest
Packit 6c4009
	mov 	src = in1		// src
Packit 6c4009
;; }
Packit 6c4009
{ .mii
Packit 6c4009
	cmp.eq	p_scr, p0 = in2, r0	// if (len == 0)
Packit 6c4009
	.save   ar.lc, saved_lc
Packit 6c4009
        movi0 	saved_lc = ar.lc	// save the loop counter
Packit 6c4009
	.body
Packit 6c4009
	cmp.ge	p_few, p0 = OP_T_THRES, in2 // is len <= OP_T_THRESH
Packit 6c4009
} { .mbb
Packit 6c4009
	mov	len = in2		// len
Packit 6c4009
(p_scr)	br.cond.dpnt.few .restore_and_exit // 	Branch no. 1: return dest
Packit 6c4009
(p_few) br.cond.dpnt.many .copy_bytes	// Branch no. 2: copy byte by byte
Packit 6c4009
;; }
Packit 6c4009
{ .mmi
Packit 6c4009
#if defined(USE_LFETCH)
Packit 6c4009
	lfetch.nt1 [dest]		//
Packit 6c4009
	lfetch.nt1 [src]		//
Packit 6c4009
#endif
Packit 6c4009
	shr.u	elemcnt = len, 3	// elemcnt = len / 8
Packit 6c4009
} { .mib
Packit 6c4009
	cmp.eq	p_scr, p0 = tmp4, r0	// is destination aligned?
Packit 6c4009
	sub	loopcnt = 7, tmp4	//
Packit 6c4009
(p_scr) br.cond.dptk.many .dest_aligned
Packit 6c4009
;; }
Packit 6c4009
{ .mmi
Packit 6c4009
	ld1	tmp2 = [src], 1		//
Packit 6c4009
	sub	len = len, loopcnt, 1	// reduce len
Packit 6c4009
	movi0	ar.lc = loopcnt		//
Packit 6c4009
} { .mib
Packit 6c4009
	cmp.ne  p_scr, p0 = 0, loopcnt	// avoid loading beyond end-point
Packit 6c4009
;; }
Packit 6c4009
Packit 6c4009
.l0:	// ---------------------------- // L0: Align src on 8-byte boundary
Packit 6c4009
{ .mmi
Packit 6c4009
	st1	[dest] = tmp2, 1	//
Packit 6c4009
(p_scr)	ld1	tmp2 = [src], 1		//
Packit 6c4009
} { .mib
Packit 6c4009
	cmp.lt	p_scr, p0 = 1, loopcnt	// avoid load beyond end-point
Packit 6c4009
	add	loopcnt = -1, loopcnt
Packit 6c4009
	br.cloop.dptk.few .l0		//
Packit 6c4009
;; }
Packit 6c4009
Packit 6c4009
.dest_aligned:
Packit 6c4009
{ .mmi
Packit 6c4009
	and	tmp4 = 7, src		// ready for alignment check
Packit 6c4009
	shr.u	elemcnt = len, 3	// elemcnt = len / 8
Packit 6c4009
;; }
Packit 6c4009
{ .mib
Packit 6c4009
	cmp.ne	p_scr, p0 = tmp4, r0	// is source also aligned
Packit 6c4009
	tbit.nz p_xtr, p_nxtr = src, 3	// prepare a separate move if src
Packit 6c4009
} { .mib				// is not 16B aligned
Packit 6c4009
	add	ptr2 = LFETCH_DIST, dest	// prefetch address
Packit 6c4009
	add	ptr1 = LFETCH_DIST, src
Packit 6c4009
(p_scr) br.cond.dptk.many .src_not_aligned
Packit 6c4009
;; }
Packit 6c4009
Packit 6c4009
// The optimal case, when dest, and src are aligned
Packit 6c4009
Packit 6c4009
.both_aligned:
Packit 6c4009
{ .mmi
Packit 6c4009
	.pred.rel "mutex",p_xtr,p_nxtr
Packit 6c4009
(p_xtr)	cmp.gt  p_scr, p0 = ALIGN_UNROLL_no+1, elemcnt // Need N + 1 to qualify
Packit 6c4009
(p_nxtr) cmp.gt p_scr, p0 = ALIGN_UNROLL_no, elemcnt  // Need only N to qualify
Packit 6c4009
	movi0	pr.rot = 1 << 16	// set rotating predicates
Packit 6c4009
} { .mib
Packit 6c4009
(p_scr) br.cond.dpnt.many .copy_full_words
Packit 6c4009
;; }
Packit 6c4009
Packit 6c4009
{ .mmi
Packit 6c4009
(p_xtr)	load	tempreg = [src], 8
Packit 6c4009
(p_xtr) add 	elemcnt = -1, elemcnt
Packit 6c4009
	movi0	ar.ec = MEMLAT + 1	// set the epilog counter
Packit 6c4009
;; }
Packit 6c4009
{ .mmi
Packit 6c4009
(p_xtr) add	len = -8, len		//
Packit 6c4009
	add 	asrc = 16, src 		// one bank apart (for USE_INT)
Packit 6c4009
	shr.u	loopcnt = elemcnt, ALIGN_UNROLL_sh  // cater for unrolling
Packit 6c4009
;;}
Packit 6c4009
{ .mmi
Packit 6c4009
	add	loopcnt = -1, loopcnt
Packit 6c4009
(p_xtr)	store	[dest] = tempreg, 8	// copy the "extra" word
Packit 6c4009
	nop.i	0
Packit 6c4009
;; }
Packit 6c4009
{ .mib
Packit 6c4009
	add	adest = 16, dest
Packit 6c4009
	movi0	ar.lc = loopcnt 	// set the loop counter
Packit 6c4009
;; }
Packit 6c4009
Packit 6c4009
#ifdef  GAS_ALIGN_BREAKS_UNWIND_INFO
Packit 6c4009
	{ nop 0 }
Packit 6c4009
#else
Packit 6c4009
	.align	32
Packit 6c4009
#endif
Packit 6c4009
#if defined(USE_FLP)
Packit 6c4009
.l1: // ------------------------------- // L1: Everything a multiple of 8
Packit 6c4009
{ .mmi
Packit 6c4009
#if defined(USE_LFETCH)
Packit 6c4009
(p[0])	lfetch.nt1 [ptr2],32
Packit 6c4009
#endif
Packit 6c4009
(p[0])	ldfp8	the_r[0],the_q[0] = [src], 16
Packit 6c4009
(p[0])	add	len = -32, len
Packit 6c4009
} {.mmb
Packit 6c4009
(p[MEMLAT]) store [dest] = the_r[MEMLAT], 8
Packit 6c4009
(p[MEMLAT]) store [adest] = the_s[MEMLAT], 8
Packit 6c4009
;; }
Packit 6c4009
{ .mmi
Packit 6c4009
#if defined(USE_LFETCH)
Packit 6c4009
(p[0])	lfetch.nt1 [ptr1],32
Packit 6c4009
#endif
Packit 6c4009
(p[0])	ldfp8	the_s[0], the_t[0] = [src], 16
Packit 6c4009
} {.mmb
Packit 6c4009
(p[MEMLAT]) store [dest] = the_q[MEMLAT], 24
Packit 6c4009
(p[MEMLAT]) store [adest] = the_t[MEMLAT], 24
Packit 6c4009
	br.ctop.dptk.many .l1
Packit 6c4009
;; }
Packit 6c4009
#elif defined(USE_INT)
Packit 6c4009
.l1: // ------------------------------- // L1: Everything a multiple of 8
Packit 6c4009
{ .mmi
Packit 6c4009
(p[0])	load	the_r[0] = [src], 8
Packit 6c4009
(p[0])	load	the_q[0] = [asrc], 8
Packit 6c4009
(p[0])	add	len = -32, len
Packit 6c4009
} {.mmb
Packit 6c4009
(p[MEMLAT]) store [dest] = the_r[MEMLAT], 8
Packit 6c4009
(p[MEMLAT]) store [adest] = the_q[MEMLAT], 8
Packit 6c4009
;; }
Packit 6c4009
{ .mmi
Packit 6c4009
(p[0])	load	the_s[0]  = [src], 24
Packit 6c4009
(p[0])	load	the_t[0] = [asrc], 24
Packit 6c4009
} {.mmb
Packit 6c4009
(p[MEMLAT]) store [dest] = the_s[MEMLAT], 24
Packit 6c4009
(p[MEMLAT]) store [adest] = the_t[MEMLAT], 24
Packit 6c4009
#if defined(USE_LFETCH)
Packit 6c4009
;; }
Packit 6c4009
{ .mmb
Packit 6c4009
(p[0])	lfetch.nt1 [ptr2],32
Packit 6c4009
(p[0])	lfetch.nt1 [ptr1],32
Packit 6c4009
#endif
Packit 6c4009
	br.ctop.dptk.many .l1
Packit 6c4009
;; }
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
.copy_full_words:
Packit 6c4009
{ .mib
Packit 6c4009
	cmp.gt	p_scr, p0 = 8, len	//
Packit 6c4009
	shr.u	elemcnt = len, 3	//
Packit 6c4009
(p_scr) br.cond.dpnt.many .copy_bytes
Packit 6c4009
;; }
Packit 6c4009
{ .mii
Packit 6c4009
	load	tempreg = [src], 8
Packit 6c4009
	add	loopcnt = -1, elemcnt	//
Packit 6c4009
;; }
Packit 6c4009
{ .mii
Packit 6c4009
	cmp.ne	p_scr, p0 = 0, loopcnt	//
Packit 6c4009
	mov	ar.lc = loopcnt		//
Packit 6c4009
;; }
Packit 6c4009
Packit 6c4009
.l2: // ------------------------------- // L2: Max 4 words copied separately
Packit 6c4009
{ .mmi
Packit 6c4009
	store	[dest] = tempreg, 8
Packit 6c4009
(p_scr)	load	tempreg = [src], 8	//
Packit 6c4009
	add	len = -8, len
Packit 6c4009
} { .mib
Packit 6c4009
	cmp.lt	p_scr, p0 = 1, loopcnt	// avoid load beyond end-point
Packit 6c4009
	add	loopcnt = -1, loopcnt
Packit 6c4009
	br.cloop.dptk.few  .l2
Packit 6c4009
;; }
Packit 6c4009
Packit 6c4009
.copy_bytes:
Packit 6c4009
{ .mib
Packit 6c4009
	cmp.eq	p_scr, p0 = len, r0	// is len == 0 ?
Packit 6c4009
	add	loopcnt = -1, len	// len--;
Packit 6c4009
(p_scr)	br.cond.spnt	.restore_and_exit
Packit 6c4009
;; }
Packit 6c4009
{ .mii
Packit 6c4009
	ld1	tmp2 = [src], 1
Packit 6c4009
	movi0	ar.lc = loopcnt
Packit 6c4009
	cmp.ne	p_scr, p0 = 0, loopcnt	// avoid load beyond end-point
Packit 6c4009
;; }
Packit 6c4009
Packit 6c4009
.l3: // ------------------------------- // L3: Final byte move
Packit 6c4009
{ .mmi
Packit 6c4009
	st1	[dest] = tmp2, 1
Packit 6c4009
(p_scr)	ld1	tmp2 = [src], 1
Packit 6c4009
} { .mib
Packit 6c4009
	cmp.lt	p_scr, p0 = 1, loopcnt	// avoid load beyond end-point
Packit 6c4009
	add	loopcnt = -1, loopcnt
Packit 6c4009
	br.cloop.dptk.few  .l3
Packit 6c4009
;; }
Packit 6c4009
Packit 6c4009
.restore_and_exit:
Packit 6c4009
{ .mmi
Packit 6c4009
	movi0	pr = saved_pr, -1	// restore the predicate registers
Packit 6c4009
;; }
Packit 6c4009
{ .mib
Packit 6c4009
	movi0	ar.lc = saved_lc	// restore the loop counter
Packit 6c4009
	br.ret.sptk.many b0
Packit 6c4009
;; }
Packit 6c4009
Packit 6c4009
Packit 6c4009
.src_not_aligned:
Packit 6c4009
{ .mmi
Packit 6c4009
	cmp.gt	p_scr, p0 = 16, len
Packit 6c4009
	and	sh1 = 7, src 		// sh1 = src % 8
Packit 6c4009
	shr.u	loopcnt = len, 4	// element-cnt = len / 16
Packit 6c4009
} { .mib
Packit 6c4009
	add	tmp4 = @ltoff(.table), gp
Packit 6c4009
	add 	tmp3 = @ltoff(.loop56), gp
Packit 6c4009
(p_scr)	br.cond.dpnt.many .copy_bytes	// do byte by byte if too few
Packit 6c4009
;; }
Packit 6c4009
{ .mmi
Packit 6c4009
	and	asrc = -8, src		// asrc = (-8) -- align src for loop
Packit 6c4009
	add 	loopcnt = -1, loopcnt	// loopcnt--
Packit 6c4009
	shl	sh1 = sh1, 3		// sh1 = 8 * (src % 8)
Packit 6c4009
} { .mmi
Packit 6c4009
	ld8	ptable = [tmp4]		// ptable = &table
Packit 6c4009
	ld8	ploop56 = [tmp3]	// ploop56 = &loop56
Packit 6c4009
	and	tmp2 = -16, len		// tmp2 = len & -OPSIZ
Packit 6c4009
;; }
Packit 6c4009
{ .mmi
Packit 6c4009
	add	tmp3 = ptable, sh1	// tmp3 = &table + sh1
Packit 6c4009
	add	src = src, tmp2		// src += len & (-16)
Packit 6c4009
	movi0	ar.lc = loopcnt		// set LC
Packit 6c4009
;; }
Packit 6c4009
{ .mmi
Packit 6c4009
	ld8	tmp4 = [tmp3]		// tmp4 = loop offset
Packit 6c4009
	sub	len = len, tmp2		// len -= len & (-16)
Packit 6c4009
	movi0	ar.ec = MEMLAT + 2 	// one more pass needed
Packit 6c4009
;; }
Packit 6c4009
{ .mmi
Packit 6c4009
	ld8	s[1] = [asrc], 8	// preload
Packit 6c4009
	sub	loopaddr = ploop56,tmp4	// loopadd = &loop56 - loop offset
Packit 6c4009
	movi0   pr.rot = 1 << 16	// set rotating predicates
Packit 6c4009
;; }
Packit 6c4009
{ .mib
Packit 6c4009
	nop.m	0
Packit 6c4009
	movi0	b6 = loopaddr
Packit 6c4009
	br	b6			// jump to the appropriate loop
Packit 6c4009
;; }
Packit 6c4009
Packit 6c4009
	LOOP(8)
Packit 6c4009
	LOOP(16)
Packit 6c4009
	LOOP(24)
Packit 6c4009
	LOOP(32)
Packit 6c4009
	LOOP(40)
Packit 6c4009
	LOOP(48)
Packit 6c4009
	LOOP(56)
Packit 6c4009
END(memcpy)
Packit 6c4009
libc_hidden_builtin_def (memcpy)
Packit 6c4009
Packit 6c4009
	.rodata
Packit 6c4009
	.align 8
Packit 6c4009
.table:
Packit 6c4009
	data8	0			// dummy entry
Packit 6c4009
	data8 	.loop56 - .loop8
Packit 6c4009
	data8 	.loop56 - .loop16
Packit 6c4009
	data8 	.loop56 - .loop24
Packit 6c4009
	data8	.loop56 - .loop32
Packit 6c4009
	data8	.loop56 - .loop40
Packit 6c4009
	data8	.loop56 - .loop48
Packit 6c4009
	data8	.loop56 - .loop56