ff4ff35918
Red Bear OS is a full fork. All sources must be available from git clone with zero network access. Removed gitignore rules that excluded fetched source trees under recipes/*/source/, local/recipes/kde/*/source/, local/recipes/qt/*/source/, and vendor source trees. Build artifacts (target/, build/, source.tar, *.o, *.so) remain excluded. 127291 files added — kernel, relibc, base, bootloader, pkgar, all KDE/Qt frameworks, mesa, wayland, DRM drivers, and every other recipe source.
195 lines
5.1 KiB
NASM
195 lines
5.1 KiB
NASM
dnl ARM Neon mpn_hamdist -- mpn bit hamming distance.
|
|
|
|
dnl Copyright 2013 Free Software Foundation, Inc.
|
|
|
|
dnl This file is part of the GNU MP Library.
|
|
dnl
|
|
dnl The GNU MP Library is free software; you can redistribute it and/or modify
|
|
dnl it under the terms of either:
|
|
dnl
|
|
dnl * the GNU Lesser General Public License as published by the Free
|
|
dnl Software Foundation; either version 3 of the License, or (at your
|
|
dnl option) any later version.
|
|
dnl
|
|
dnl or
|
|
dnl
|
|
dnl * the GNU General Public License as published by the Free Software
|
|
dnl Foundation; either version 2 of the License, or (at your option) any
|
|
dnl later version.
|
|
dnl
|
|
dnl or both in parallel, as here.
|
|
dnl
|
|
dnl The GNU MP Library is distributed in the hope that it will be useful, but
|
|
dnl WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
dnl or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
dnl for more details.
|
|
dnl
|
|
dnl You should have received copies of the GNU General Public License and the
|
|
dnl GNU Lesser General Public License along with the GNU MP Library. If not,
|
|
dnl see https://www.gnu.org/licenses/.
|
|
|
|
include(`../config.m4')
|
|
|
|
C cycles/limb
|
|
C StrongARM: -
|
|
C XScale -
|
|
C Cortex-A7 ?
|
|
C Cortex-A8 ?
|
|
C Cortex-A9 1.89
|
|
C Cortex-A15 0.95
|
|
|
|
C TODO
|
|
C * Explore using vldr and vldm. Does it help on A9? (These loads do
|
|
C 64-bits-at-a-time, which will mess up in big-endian mode. Except not for
|
|
C popcount. Except perhaps also for popcount for the edge loads.)
|
|
C * Arrange to align the pointer, if that helps performance. Use the same
|
|
C read-and-mask trick we use on PCs, for simplicity and performance. (Sorry
|
|
C valgrind!)
|
|
C * Explore if explicit align directives, e.g., "[ptr:128]" help.
|
|
C * See rth's gmp-devel 2013-02/03 messages about final summation tricks.
|
|
|
|
C INPUT PARAMETERS
|
|
define(`ap', r0)
|
|
define(`bp', r1)
|
|
define(`n', r2)
|
|
|
|
C We sum into 16 16-bit counters in q8,q9, but at the end we sum them and end
|
|
C up with 8 16-bit counters. Therefore, we can sum to 8(2^16-1) bits, or
|
|
C (8*2^16-1)/32 = 0x3fff limbs. We use a chunksize close to that, but which
|
|
C can be represented as a 8-bit ARM constant.
|
|
C
|
|
define(`chunksize',0x3f80)
|
|
|
|
ASM_START()
|
|
PROLOGUE(mpn_hamdist)
|
|
|
|
cmp n, #chunksize
|
|
bhi L(gt16k)
|
|
|
|
L(lt16k):
|
|
vmov.i64 q8, #0 C clear summation register
|
|
vmov.i64 q9, #0 C clear summation register
|
|
|
|
tst n, #1
|
|
beq L(xxx0)
|
|
vmov.i64 d0, #0
|
|
vmov.i64 d20, #0
|
|
sub n, n, #1
|
|
vld1.32 {d0[0]}, [ap]! C load 1 limb
|
|
vld1.32 {d20[0]}, [bp]! C load 1 limb
|
|
veor d0, d0, d20
|
|
vcnt.8 d24, d0
|
|
vpadal.u8 d16, d24 C d16/q8 = 0; could just splat
|
|
|
|
L(xxx0):tst n, #2
|
|
beq L(xx00)
|
|
sub n, n, #2
|
|
vld1.32 {d0}, [ap]! C load 2 limbs
|
|
vld1.32 {d20}, [bp]! C load 2 limbs
|
|
veor d0, d0, d20
|
|
vcnt.8 d24, d0
|
|
vpadal.u8 d16, d24
|
|
|
|
L(xx00):tst n, #4
|
|
beq L(x000)
|
|
sub n, n, #4
|
|
vld1.32 {q0}, [ap]! C load 4 limbs
|
|
vld1.32 {q10}, [bp]! C load 4 limbs
|
|
veor q0, q0, q10
|
|
vcnt.8 q12, q0
|
|
vpadal.u8 q8, q12
|
|
|
|
L(x000):tst n, #8
|
|
beq L(0000)
|
|
|
|
subs n, n, #8
|
|
vld1.32 {q0,q1}, [ap]! C load 8 limbs
|
|
vld1.32 {q10,q11}, [bp]! C load 8 limbs
|
|
bls L(sum)
|
|
|
|
L(gt8): vld1.32 {q2,q3}, [ap]! C load 8 limbs
|
|
vld1.32 {q14,q15}, [bp]! C load 8 limbs
|
|
veor q0, q0, q10
|
|
veor q1, q1, q11
|
|
sub n, n, #8
|
|
vcnt.8 q12, q0
|
|
vcnt.8 q13, q1
|
|
b L(mid)
|
|
|
|
L(0000):subs n, n, #16
|
|
blo L(e0)
|
|
|
|
vld1.32 {q2,q3}, [ap]! C load 8 limbs
|
|
vld1.32 {q0,q1}, [ap]! C load 8 limbs
|
|
vld1.32 {q14,q15}, [bp]! C load 8 limbs
|
|
vld1.32 {q10,q11}, [bp]! C load 8 limbs
|
|
veor q2, q2, q14
|
|
veor q3, q3, q15
|
|
vcnt.8 q12, q2
|
|
vcnt.8 q13, q3
|
|
subs n, n, #16
|
|
blo L(end)
|
|
|
|
L(top): vld1.32 {q2,q3}, [ap]! C load 8 limbs
|
|
vld1.32 {q14,q15}, [bp]! C load 8 limbs
|
|
veor q0, q0, q10
|
|
veor q1, q1, q11
|
|
vpadal.u8 q8, q12
|
|
vcnt.8 q12, q0
|
|
vpadal.u8 q9, q13
|
|
vcnt.8 q13, q1
|
|
L(mid): vld1.32 {q0,q1}, [ap]! C load 8 limbs
|
|
vld1.32 {q10,q11}, [bp]! C load 8 limbs
|
|
veor q2, q2, q14
|
|
veor q3, q3, q15
|
|
subs n, n, #16
|
|
vpadal.u8 q8, q12
|
|
vcnt.8 q12, q2
|
|
vpadal.u8 q9, q13
|
|
vcnt.8 q13, q3
|
|
bhs L(top)
|
|
|
|
L(end): vpadal.u8 q8, q12
|
|
vpadal.u8 q9, q13
|
|
L(sum): veor q0, q0, q10
|
|
veor q1, q1, q11
|
|
vcnt.8 q12, q0
|
|
vcnt.8 q13, q1
|
|
vpadal.u8 q8, q12
|
|
vpadal.u8 q9, q13
|
|
vadd.i16 q8, q8, q9
|
|
C we have 8 16-bit counts
|
|
L(e0): vpaddl.u16 q8, q8 C we have 4 32-bit counts
|
|
vpaddl.u32 q8, q8 C we have 2 64-bit counts
|
|
vmov.32 r0, d16[0]
|
|
vmov.32 r1, d17[0]
|
|
add r0, r0, r1
|
|
bx lr
|
|
|
|
C Code for large count. Splits operand and calls above code.
|
|
define(`ap2', r5)
|
|
define(`bp2', r6)
|
|
L(gt16k):
|
|
push {r4,r5,r6,r14}
|
|
mov ap2, ap
|
|
mov bp2, bp
|
|
mov r3, n C full count
|
|
mov r4, #0 C total sum
|
|
|
|
1: mov n, #chunksize C count for this invocation
|
|
bl L(lt16k) C could jump deep inside code
|
|
add ap2, ap2, #chunksize*4 C point at next chunk
|
|
add bp2, bp2, #chunksize*4 C point at next chunk
|
|
add r4, r4, r0
|
|
mov ap, ap2 C put chunk pointer in place for call
|
|
mov bp, bp2 C put chunk pointer in place for call
|
|
sub r3, r3, #chunksize
|
|
cmp r3, #chunksize
|
|
bhi 1b
|
|
|
|
mov n, r3 C count for final invocation
|
|
bl L(lt16k)
|
|
add r0, r4, r0
|
|
pop {r4,r5,r6,pc}
|
|
EPILOGUE()
|