blob: 7843a7c2d1d98111e0ceb8aeed1ca44c25581f87 [file]
// Copyright 2026 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build loong64 && gc && !purego
#include "textflag.h"
// HALF_ROUND applies one BlaMka half-round (mul-add-xor-rotate) to two
// groups of 4 columns, each packed 2-wide into V registers (v0/v2/v4/v6
// hold one pair of columns in lane0/lane1, v1/v3/v5/v7 hold the other).
// t0, t1 are scratch registers, one per independent column group.
#define HALF_ROUND(v0, v1, v2, v3, v4, v5, v6, v7, t0, t1) \
VMULWEVVWU v0, v2, t0; \
VADDV t0, t0, t0; \
VADDV v0, v2, v0; \
VADDV v0, t0, v0; \
VXORV v6, v0, v6; \
VROTRV $32, v6, v6; \
VMULWEVVWU v1, v3, t1; \
VADDV t1, t1, t1; \
VADDV v1, v3, v1; \
VADDV v1, t1, v1; \
VXORV v7, v1, v7; \
VROTRV $32, v7, v7; \
VMULWEVVWU v4, v6, t0; \
VADDV t0, t0, t0; \
VADDV v4, v6, v4; \
VADDV v4, t0, v4; \
VXORV v2, v4, v2; \
VROTRV $24, v2, v2; \
VMULWEVVWU v5, v7, t1; \
VADDV t1, t1, t1; \
VADDV v5, v7, v5; \
VADDV v5, t1, v5; \
VXORV v3, v5, v3; \
VROTRV $24, v3, v3; \
VMULWEVVWU v0, v2, t0; \
VADDV t0, t0, t0; \
VADDV v0, v2, v0; \
VADDV v0, t0, v0; \
VXORV v6, v0, v6; \
VROTRV $16, v6, v6; \
VMULWEVVWU v1, v3, t1; \
VADDV t1, t1, t1; \
VADDV v1, v3, v1; \
VADDV v1, t1, v1; \
VXORV v7, v1, v7; \
VROTRV $16, v7, v7; \
VMULWEVVWU v4, v6, t0; \
VADDV t0, t0, t0; \
VADDV v4, v6, v4; \
VADDV v4, t0, v4; \
VXORV v2, v4, v2; \
VROTRV $63, v2, v2; \
VMULWEVVWU v5, v7, t1; \
VADDV t1, t1, t1; \
VADDV v5, v7, v5; \
VADDV v5, t1, v5; \
VXORV v3, v5, v3; \
VROTRV $63, v3, v3
// SHUFFLE / SHUFFLE_INV: reused verbatim from blake2b_loong64.s -- amd64
// avo source confirms argon2's SHUFFLE/SHUFFLE_INV and blake2b's SHUFFLE
// are byte-for-byte identical macros (diagonalize / undiagonalize),
// operating only on V2..V7 (V0/V1 untouched), with V13 held at zero.
#define SHUFFLE \
VADDV V2, V13, V12; \
VADDV V6, V13, V16; \
VADDV V4, V13, V14; \
VADDV V5, V13, V4; \
VADDV V14, V13, V5; \
VSHUF4IV $9, V3, V2; \
VSHUF4IV $9, V12, V3; \
VSHUF4IV $3, V7, V6; \
VSHUF4IV $3, V16, V7
#define SHUFFLE_INV \
VADDV V2, V13, V12; \
VADDV V6, V13, V16; \
VADDV V4, V13, V14; \
VADDV V5, V13, V4; \
VADDV V14, V13, V5; \
VSHUF4IV $3, V3, V2; \
VSHUF4IV $3, V12, V3; \
VSHUF4IV $9, V7, V6; \
VSHUF4IV $9, V16, V7
// LOAD_MSG_0 / STORE_MSG_0: row pass. `off` is the byte offset of the
// 128-byte (16-uint64) row group; within the macro the 8 loads step by
// 16B (2 uint64 per V register). Called from blamkaLOONG64 with off
// stepping by 128B across the 8 row groups -- do not confuse the two
// strides.
#define LOAD_MSG_0(off) \
VMOVQ (off+0)(R4), V0; \
VMOVQ (off+16)(R4), V1; \
VMOVQ (off+32)(R4), V2; \
VMOVQ (off+48)(R4), V3; \
VMOVQ (off+64)(R4), V4; \
VMOVQ (off+80)(R4), V5; \
VMOVQ (off+96)(R4), V6; \
VMOVQ (off+112)(R4), V7
#define STORE_MSG_0(off) \
VMOVQ V0, (off+0)(R4); \
VMOVQ V1, (off+16)(R4); \
VMOVQ V2, (off+32)(R4); \
VMOVQ V3, (off+48)(R4); \
VMOVQ V4, (off+64)(R4); \
VMOVQ V5, (off+80)(R4); \
VMOVQ V6, (off+96)(R4); \
VMOVQ V7, (off+112)(R4)
// LOAD_MSG_1 / STORE_MSG_1: diagonal pass. `off` is the byte offset within
// a 128-byte row group; within the macro the 8 loads step by 128B (one
// element from each of the 8 row groups, mirroring blamka_generic.go's
// t[off], t[128+off], t[256+off], ...). Called from blamkaLOONG64 with
// off stepping by 16B (2 uint64) across the 8 diagonal groups -- the
// inner/outer strides are swapped relative to LOAD_MSG_0/STORE_MSG_0.
#define LOAD_MSG_1(off) \
VMOVQ (off+0)(R4), V0; \
VMOVQ (off+128)(R4), V1; \
VMOVQ (off+256)(R4), V2; \
VMOVQ (off+384)(R4), V3; \
VMOVQ (off+512)(R4), V4; \
VMOVQ (off+640)(R4), V5; \
VMOVQ (off+768)(R4), V6; \
VMOVQ (off+896)(R4), V7
#define STORE_MSG_1(off) \
VMOVQ V0, (off+0)(R4); \
VMOVQ V1, (off+128)(R4); \
VMOVQ V2, (off+256)(R4); \
VMOVQ V3, (off+384)(R4); \
VMOVQ V4, (off+512)(R4); \
VMOVQ V5, (off+640)(R4); \
VMOVQ V6, (off+768)(R4); \
VMOVQ V7, (off+896)(R4)
// BLAMKA_ROUND_0(off): one full row pass over the 16-uint64 group at
// byte offset off -- corresponds to a single call to blamkaGeneric
// with the "row" argument order (t[off]..t[off+15]).
#define BLAMKA_ROUND_0(off) \
LOAD_MSG_0(off); \
HALF_ROUND(V0, V1, V2, V3, V4, V5, V6, V7, V8, V9); \
SHUFFLE; \
HALF_ROUND(V0, V1, V2, V3, V4, V5, V6, V7, V8, V9); \
SHUFFLE_INV; \
STORE_MSG_0(off)
// BLAMKA_ROUND_1(off): one full diagonal pass over the 16 uint64s at
// diagonal offset off -- corresponds to a single call to blamkaGeneric
// with the "diagonal" argument order (t[off], t[off+1], t[16+off], ...).
#define BLAMKA_ROUND_1(off) \
LOAD_MSG_1(off); \
HALF_ROUND(V0, V1, V2, V3, V4, V5, V6, V7, V8, V9); \
SHUFFLE; \
HALF_ROUND(V0, V1, V2, V3, V4, V5, V6, V7, V8, V9); \
SHUFFLE_INV; \
STORE_MSG_1(off)
// func blamkaLOONG64(b *block)
TEXT ·blamkaLOONG64(SB), NOSPLIT, $0-8
MOVV b+0(FP), R4
VXORV V13, V13, V13 // V13 = 0, used by SHUFFLE/SHUFFLE_INV
// Round 0: 8 row passes, stride 128 bytes (16 uint64s).
BLAMKA_ROUND_0(0)
BLAMKA_ROUND_0(128)
BLAMKA_ROUND_0(256)
BLAMKA_ROUND_0(384)
BLAMKA_ROUND_0(512)
BLAMKA_ROUND_0(640)
BLAMKA_ROUND_0(768)
BLAMKA_ROUND_0(896)
// Round 1: 8 diagonal passes, stride 16 bytes (2 uint64s).
BLAMKA_ROUND_1(0)
BLAMKA_ROUND_1(16)
BLAMKA_ROUND_1(32)
BLAMKA_ROUND_1(48)
BLAMKA_ROUND_1(64)
BLAMKA_ROUND_1(80)
BLAMKA_ROUND_1(96)
BLAMKA_ROUND_1(112)
RET
// func mixBlocksVX(out, a, b, c *block)
TEXT ·mixBlocksVX(SB), NOSPLIT, $0-32
MOVV out+0(FP), R4
MOVV a+8(FP), R5
MOVV b+16(FP), R6
MOVV c+24(FP), R7
MOVV $1024, R8
PCALIGN $16
mixloop:
VMOVQ (R5), V0
VMOVQ (R6), V1
VMOVQ (R7), V2
VXORV V0, V1, V0
VXORV V0, V2, V0
VMOVQ V0, (R4)
ADDV $16, R4
ADDV $16, R5
ADDV $16, R6
ADDV $16, R7
SUBV $16, R8
BNE R8, R0, mixloop
RET
// func xorBlocksVX(out, a, b, c *block)
TEXT ·xorBlocksVX(SB), NOSPLIT, $0-32
MOVV out+0(FP), R4
MOVV a+8(FP), R5
MOVV b+16(FP), R6
MOVV c+24(FP), R7
MOVV $1024, R8
PCALIGN $16
xorloop:
VMOVQ (R5), V0
VMOVQ (R6), V1
VMOVQ (R7), V2
VMOVQ (R4), V3
VXORV V0, V1, V0
VXORV V0, V2, V0
VXORV V0, V3, V0
VMOVQ V0, (R4)
ADDV $16, R4
ADDV $16, R5
ADDV $16, R6
ADDV $16, R7
SUBV $16, R8
BNE R8, R0, xorloop
RET