Skip to content

Commit 910d7df

Browse files
authored
Add AArch64 NEON implementation for Adler32 (#83)
1 parent c698884 commit 910d7df

2 files changed

Lines changed: 117 additions & 4 deletions

File tree

HashLib/src/Checksum/HlpAdler32Dispatch.pas

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ procedure Adler32_Update_Scalar(AData: PByte; ALength: UInt32; ASums: Pointer);
6868
// SIMD implementations: SSE2 / SSSE3 (IA-32); SSE2 / SSSE3 / AVX2 (x86-64)
6969
// =============================================================================
7070

71-
{$IFDEF HASHLIB_X86_SIMD}
71+
{$IF DEFINED(HASHLIB_X86_SIMD) OR DEFINED(HASHLIB_ARM_SIMD)}
7272

7373
type
7474
TProcessBlocksProc = procedure(AData: PByte; ANumBlocks: UInt32;
@@ -113,7 +113,9 @@ procedure Adler32_Update_Simd(AData: PByte; ALength: UInt32; ASums: Pointer;
113113
end;
114114
end;
115115

116-
{$ENDIF HASHLIB_X86_SIMD}
116+
{$ENDIF}
117+
118+
{$IFDEF HASHLIB_X86_SIMD}
117119

118120
{$IFDEF HASHLIB_I386_ASM}
119121

@@ -163,8 +165,6 @@ procedure Adler32_Update_Avx2(AData: PByte; ALength: UInt32; ASums: Pointer);
163165

164166
{$ENDIF HASHLIB_X86_64_ASM}
165167

166-
{$IFDEF HASHLIB_X86_SIMD}
167-
168168
procedure Adler32_Update_Sse2(AData: PByte; ALength: UInt32; ASums: Pointer);
169169
begin
170170
Adler32_Update_Simd(AData, ALength, ASums, @Adler32_ProcessBlocks_Sse2);
@@ -181,6 +181,25 @@ procedure Adler32_Update_Ssse3(AData: PByte; ALength: UInt32; ASums: Pointer);
181181

182182
{$ENDIF HASHLIB_X86_SIMD}
183183

184+
{$IFDEF HASHLIB_AARCH64_ASM}
185+
186+
procedure Adler32_ProcessBlocks_Neon(AData: PByte; ANumBlocks: UInt32;
187+
ASums, AConstants: Pointer);
188+
{$I ..\Include\Simd\Common\SimdProc4Begin_aarch64.inc}
189+
{$I ..\Include\Simd\Adler32\Adler32BlocksNeon_aarch64.inc}
190+
end;
191+
192+
{$IFDEF HASHLIB_ARM_SIMD}
193+
194+
procedure Adler32_Update_Neon(AData: PByte; ALength: UInt32; ASums: Pointer);
195+
begin
196+
Adler32_Update_Simd(AData, ALength, ASums, @Adler32_ProcessBlocks_Neon);
197+
end;
198+
199+
{$ENDIF HASHLIB_ARM_SIMD}
200+
201+
{$ENDIF HASHLIB_AARCH64_ASM}
202+
184203
// =============================================================================
185204
// Dispatch initialization
186205
// =============================================================================
@@ -216,6 +235,14 @@ procedure InitDispatch();
216235
end;
217236
end;
218237
{$ENDIF}
238+
{$IFDEF HASHLIB_AARCH64_ASM}
239+
case TCpuFeatures.Arm.SelectSlot([TArmSimdLevel.NEON]) of
240+
TArmSimdLevel.NEON:
241+
begin
242+
Adler32_Update := @Adler32_Update_Neon;
243+
end;
244+
end;
245+
{$ENDIF}
219246
end;
220247

221248
initialization
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
// Adler-32 ProcessBlocks AArch64 NEON implementation (32-byte blocks).
2+
// Expects AAPCS64: x0 = AData, w1 = ANumBlocks, x2 = ASums, x3 = AConstants.
3+
// ASums layout: [SumA: UInt32, SumB: UInt32]. Does NOT apply mod 65521.
4+
// Constants layout matches Adler32Constants: bytes [32..1] at offset 0..31
5+
// (two 16-byte halves; only the weight bytes are read here).
6+
// Reference (golden): HashLib Adler32BlocksSsse3_x86_64.inc;
7+
// Chromium zlib adler32_simd.c ADLER32_SIMD_NEON column-sum + vmlal path.
8+
//
9+
// Instruction encodings (for assembler compatibility):
10+
// FPC 3.2.2's inline assembler cannot encode AArch64 vector mnemonics
11+
// (subscripted vector regs require FPC 3.3+, and ldr/str/ldp with qN crash the
12+
// 3.2.2 assembler). Each such instruction is therefore emitted as its raw 32-bit
13+
// '.long' opcode, with the equivalent mnemonic in the trailing comment; only
14+
// neg/ret stay as text.
15+
//
16+
// Register map:
17+
// w9 = block counter (from w1)
18+
// w10 = SumA in / SumA out
19+
// w11 = SumB in / SumB out
20+
// w12 = SumA * num_blocks (v_ps lane 0 seed)
21+
// w13 = horizontal-reduce scratch
22+
// v0 = v_s1 (uint32x4 byte-sum accumulators)
23+
// v1 = v_s2 (uint32x4 s2 partial, SumB seeded in lane 0)
24+
// v4-v5 = 32 input bytes per block
25+
// v6-v8 = uaddlp / horizontal-reduce temps
26+
// v16-v19 = column sums (uint16x8)
27+
// v20 = v_ps (SumA*blocks + per-block v_s1), lane 0 used before <<5 add
28+
// v24-v27 = widened weight vectors for vmlal
29+
// v28-v29 = weight byte loads from AConstants
30+
// v30 = ext scratch for weight / reduce halves
31+
.long 0xb940004a // ldr w10, [x2]
32+
.long 0xb940044b // ldr w11, [x2, #4]
33+
.long 0x1b017d4c // mul w12, w10, w1
34+
.long 0x2a0103e9 // mov w9, w1
35+
.long 0x6e341e94 // eor v20.16b, v20.16b, v20.16b
36+
.long 0x4e041d94 // ins v20.s[0], w12
37+
.long 0x6e211c21 // eor v1.16b, v1.16b, v1.16b
38+
.long 0x4e041d61 // ins v1.s[0], w11
39+
.long 0x6e201c00 // eor v0.16b, v0.16b, v0.16b
40+
.long 0x6e301e10 // eor v16.16b, v16.16b, v16.16b
41+
.long 0x6e311e31 // eor v17.16b, v17.16b, v17.16b
42+
.long 0x6e321e52 // eor v18.16b, v18.16b, v18.16b
43+
.long 0x6e331e73 // eor v19.16b, v19.16b, v19.16b
44+
.long 0x3dc0007c // ldr q28, [x3, #0x0]
45+
.long 0x3dc0047d // ldr q29, [x3, #0x10]
46+
.Ladler_blocks_loop:
47+
.long 0x4ea08694 // add v20.4s, v20.4s, v0.4s
48+
.long 0x3dc00004 // ldr q4, [x0, #0x0]
49+
.long 0x3dc00405 // ldr q5, [x0, #0x10]
50+
.long 0x6e202886 // uaddlp v6.8h, v4.16b
51+
.long 0x6e6068c0 // uadalp v0.4s, v6.8h
52+
.long 0x6e2028a7 // uaddlp v7.8h, v5.16b
53+
.long 0x6e6068e0 // uadalp v0.4s, v7.8h
54+
.long 0x2e241210 // uaddw v16.8h, v16.8h, v4.8b
55+
.long 0x6e241231 // uaddw2 v17.8h, v17.8h, v4.16b
56+
.long 0x2e251252 // uaddw v18.8h, v18.8h, v5.8b
57+
.long 0x6e251273 // uaddw2 v19.8h, v19.8h, v5.16b
58+
.long 0x91008000 // add x0, x0, #32
59+
.long 0x71000529 // subs w9, w9, #1
60+
b.ne .Ladler_blocks_loop
61+
.long 0x4f255694 // shl v20.4s, v20.4s, #5
62+
.long 0x4eb48421 // add v1.4s, v1.4s, v20.4s
63+
.long 0x2f08a798 // ushll v24.8h, v28.8b, #0
64+
.long 0x6e1c439e // ext v30.16b, v28.16b, v28.16b, #8
65+
.long 0x2f08a7d9 // ushll v25.8h, v30.8b, #0
66+
.long 0x2f08a7ba // ushll v26.8h, v29.8b, #0
67+
.long 0x6e1d43be // ext v30.16b, v29.16b, v29.16b, #8
68+
.long 0x2f08a7db // ushll v27.8h, v30.8b, #0
69+
.long 0x2e788201 // umlal v1.4s, v16.4h, v24.4h
70+
.long 0x6e788201 // umlal2 v1.4s, v16.8h, v24.8h
71+
.long 0x2e798221 // umlal v1.4s, v17.4h, v25.4h
72+
.long 0x6e798221 // umlal2 v1.4s, v17.8h, v25.8h
73+
.long 0x2e7a8241 // umlal v1.4s, v18.4h, v26.4h
74+
.long 0x6e7a8241 // umlal2 v1.4s, v18.8h, v26.8h
75+
.long 0x2e7b8261 // umlal v1.4s, v19.4h, v27.4h
76+
.long 0x6e7b8261 // umlal2 v1.4s, v19.8h, v27.8h
77+
.long 0x4ea0bc06 // addp v6.4s, v0.4s, v0.4s
78+
.long 0x0ea6bcc6 // addp v6.2s, v6.2s, v6.2s
79+
.long 0x0e043ccd // umov w13, v6.s[0]
80+
.long 0x0b0d014a // add w10, w10, w13
81+
.long 0x4ea1bc26 // addp v6.4s, v1.4s, v1.4s
82+
.long 0x0ea6bcc6 // addp v6.2s, v6.2s, v6.2s
83+
.long 0x0e043ccb // umov w11, v6.s[0]
84+
.long 0xb900004a // str w10, [x2]
85+
.long 0xb900044b // str w11, [x2, #4]
86+
ret

0 commit comments

Comments
 (0)