Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions Makefile.prebuild
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,10 @@ ifeq ($(TARGET), RISCV64_GENERIC)
TARGET_FLAGS = -march=rv64imafdc -mabi=lp64d
endif

ifeq ($(TARGET), U74)
TARGET_FLAGS = -march=rv64imafdc_zba_zbb -mabi=lp64d
endif

all: getarch_2nd
./getarch_2nd 0 >> $(TARGET_MAKE)
./getarch_2nd 1 >> $(TARGET_CONF)
Expand Down
4 changes: 4 additions & 0 deletions Makefile.riscv64
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,7 @@ ifeq ($(CORE), RISCV64_GENERIC)
CCOMMON_OPT += -march=rv64imafdc -mabi=lp64d
FCOMMON_OPT += -march=rv64imafdc -mabi=lp64d
endif
ifeq ($(CORE), U74)
CCOMMON_OPT += -march=rv64imafdc_zba_zbb -mabi=lp64d -mtune=sifive-u74
FCOMMON_OPT += -march=rv64imafdc_zba_zbb -mabi=lp64d -mtune=sifive-u74
endif
1 change: 1 addition & 0 deletions TargetList.txt
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ RISCV64_ZVL128B
C910V
x280
RISCV64_ZVL256B
U74 (e.g. SiFive U74 / StarFive JH7110 / VisionFive 2)

11.LOONGARCH64:
// LOONGSONGENERIC/LOONGSON2K1000/LOONGSON3R5 are legacy names,
Expand Down
3 changes: 3 additions & 0 deletions cmake/cc.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -428,6 +428,9 @@ endif()
if (${CORE} STREQUAL RISCV64_GENERIC)
set (CCOMMON_OPT "${CCOMMON_OPT} -march=rv64imafdc -mabi=lp64d")
endif()
if (${CORE} STREQUAL U74)
set (CCOMMON_OPT "${CCOMMON_OPT} -march=rv64imafdc_zba_zbb -mabi=lp64d -mtune=sifive-u74")
endif()
if (${CORE} STREQUAL x280)
set (CCOMMON_OPT "${CCOMMON_OPT} -march=rv64imafdcv_zba_zbb_zfh_zvl512b -mabi=lp64d")
endif()
Expand Down
9 changes: 9 additions & 0 deletions cmake/prebuild.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -1504,6 +1504,15 @@ endif ()
"#define DTB_DEFAULT_ENTRIES 128\n"
"#define DTB_SIZE 4096\n"
"#define L2_ASSOCIATIVE 4\n")
elseif ("${TCORE}" STREQUAL "U74")
file(APPEND ${TARGET_CONF_TEMP}
"#define L1_DATA_SIZE 32768\n"
"#define L1_DATA_LINESIZE 64\n"
"#define L2_SIZE 2097152\n"
"#define L2_LINESIZE 64 \n"
"#define DTB_DEFAULT_ENTRIES 128\n"
"#define DTB_SIZE 4096\n"
"#define L2_ASSOCIATIVE 16\n")
elseif ("${TCORE}" STREQUAL "WASM128_GENERIC")
file(APPEND ${TARGET_CONF_TEMP}
"#define L1_DATA_SIZE 32768\n"
Expand Down
3 changes: 3 additions & 0 deletions cmake/system.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -409,6 +409,9 @@ if (${TARGET} STREQUAL NEOVERSEV1)
if (${TARGET} STREQUAL RISCV64_GENERIC)
set (KERNEL_DEFINITIONS "${KERNEL_DEFINITIONS} -march=rv64imafdc -mabi=lp64d")
endif()
if (${TARGET} STREQUAL U74)
set (KERNEL_DEFINITIONS "${KERNEL_DEFINITIONS} -march=rv64imafdc_zba_zbb -mabi=lp64d -mtune=sifive-u74")
endif()
if (${TARGET} STREQUAL x280)
set (KERNEL_DEFINITIONS "${KERNEL_DEFINITIONS} -march=rv64imafdcv_zba_zbb_zfh_zvl512b -mabi=lp64d")
endif()
Expand Down
7 changes: 5 additions & 2 deletions cpuid_riscv64.c
Original file line number Diff line number Diff line change
Expand Up @@ -75,21 +75,24 @@ USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#define CPU_x280 2
#define CPU_RISCV64_ZVL256B 3
#define CPU_RISCV64_ZVL128B 4
#define CPU_U74 5

static char *cpuname[] = {
"RISCV64_GENERIC",
"C910V",
"x280",
"CPU_RISCV64_ZVL256B",
"CPU_RISCV64_ZVL128B"
"CPU_RISCV64_ZVL128B",
"U74"
};

static char *cpuname_lower[] = {
"riscv64_generic",
"c910v",
"x280",
"riscv64_zvl256b",
"riscv64_zvl128b"
"riscv64_zvl128b",
"u74"
};

int detect(void){
Expand Down
14 changes: 14 additions & 0 deletions getarch.c
Original file line number Diff line number Diff line change
Expand Up @@ -1232,6 +1232,20 @@ USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#else
#endif

#ifdef FORCE_U74
#define FORCE
#define ARCHITECTURE "RISCV64"
#define SUBARCHITECTURE "U74"
#define SUBDIRNAME "riscv64"
#define ARCHCONFIG "-DU74 " \
"-DL1_DATA_SIZE=32768 -DL1_DATA_LINESIZE=64 " \
"-DL2_SIZE=2097152 -DL2_LINESIZE=64 " \
"-DDTB_DEFAULT_ENTRIES=128 -DDTB_SIZE=4096 -DL2_ASSOCIATIVE=16 "
#define LIBNAME "u74"
#define CORENAME "U74"
#else
#endif

#ifdef FORCE_WASM128_GENERIC
#define FORCE
#define ARCHITECTURE "WASM"
Expand Down
264 changes: 264 additions & 0 deletions kernel/generic/gemmkernel_4x4.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,264 @@
/***************************************************************************
* Copyright (c) 2026, The OpenBLAS Project
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name of the OpenBLAS project nor the names of
* its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE OPENBLAS PROJECT OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
* *****************************************************************************/

/*
* Portable C GEMM micro-kernel with a 4x4 register tile (16 accumulators).
*
* This is a wider companion to gemmkernel_2x2.c intended for in-order scalar
* cores whose FP FMA has a multi-cycle latency but 1/cycle throughput (e.g.
* SiFive U74: fmadd.d latency 7, repeat rate 1). A 2x2 tile exposes only 4
* independent accumulator chains, which is fewer than the FMA latency and
* leaves the FP pipe stalled on the accumulator dependency. A 4x4 tile keeps
* 16 independent chains -- comfortably above the latency -- and lowers the
* load:FMA ratio from 1:1 to 1:2, so the single load/store pipe stops being
* the bottleneck. RV64G has 32 FP registers, so 16 accumulators + 4 A + 4 B
* fit without spilling.
*
* Packed-data contract (identical to the 2x2 kernel, verified against the
* generic tcopy_4 / ncopy_4 copy routines): the A operand is packed by
* tcopy_<UNROLL_M> into MR-row micro-panels [A(r0,k)..A(r3,k)] per k, and the
* B operand by ncopy_<UNROLL_N> into NR-col micro-panels [B(k,c0)..B(k,c3)]
* per k. Both dimensions are decomposed as 4 / 2 / 1 sub-blocks at the edges.
*/

#include "common.h"

#include "conversion_macros.h"

#ifdef BGEMM
#define C_TO_F32 TO_F32
#else
#define C_TO_F32
#endif

int CNAME(BLASLONG bm,BLASLONG bn,BLASLONG bk,FLOAT alpha,IFLOAT* ba,IFLOAT* bb,FLOAT* C,BLASLONG ldc
#ifdef TRMMKERNEL
,BLASLONG offset
#endif
)
{
BLASLONG i,j,k;
FLOAT *C0,*C1,*C2,*C3;
IFLOAT *ptrba,*ptrbb;
FLOAT r0c0,r1c0,r2c0,r3c0;
FLOAT r0c1,r1c1,r2c1,r3c1;
FLOAT r0c2,r1c2,r2c2,r3c2;
FLOAT r0c3,r1c3,r2c3,r3c3;
IFLOAT a0,a1,a2,a3,b0,b1,b2,b3;

/* ==================== N panels of 4 ==================== */
for (j=0; j<bn/4; j+=1)
{
C0 = C;
C1 = C0+ldc;
C2 = C1+ldc;
C3 = C2+ldc;
ptrba = ba;

/* ---- 4x4 : 4 rows x 4 cols, 16 accumulators ---- */
for (i=0; i<bm/4; i+=1)
{
ptrbb = bb;
r0c0=r1c0=r2c0=r3c0=0;
r0c1=r1c1=r2c1=r3c1=0;
r0c2=r1c2=r2c2=r3c2=0;
r0c3=r1c3=r2c3=r3c3=0;
for (k=0; k<bk; k+=1)
{
b0=ptrbb[0]; b1=ptrbb[1]; b2=ptrbb[2]; b3=ptrbb[3];
a0=ptrba[0]; a1=ptrba[1]; a2=ptrba[2]; a3=ptrba[3];
r0c0+=TO_F32(a0)*TO_F32(b0); r1c0+=TO_F32(a1)*TO_F32(b0); r2c0+=TO_F32(a2)*TO_F32(b0); r3c0+=TO_F32(a3)*TO_F32(b0);
r0c1+=TO_F32(a0)*TO_F32(b1); r1c1+=TO_F32(a1)*TO_F32(b1); r2c1+=TO_F32(a2)*TO_F32(b1); r3c1+=TO_F32(a3)*TO_F32(b1);
r0c2+=TO_F32(a0)*TO_F32(b2); r1c2+=TO_F32(a1)*TO_F32(b2); r2c2+=TO_F32(a2)*TO_F32(b2); r3c2+=TO_F32(a3)*TO_F32(b2);
r0c3+=TO_F32(a0)*TO_F32(b3); r1c3+=TO_F32(a1)*TO_F32(b3); r2c3+=TO_F32(a2)*TO_F32(b3); r3c3+=TO_F32(a3)*TO_F32(b3);
ptrba+=4; ptrbb+=4;
}
C0[0]=TO_OUTPUT(C_TO_F32(C0[0])+r0c0*ALPHA); C0[1]=TO_OUTPUT(C_TO_F32(C0[1])+r1c0*ALPHA); C0[2]=TO_OUTPUT(C_TO_F32(C0[2])+r2c0*ALPHA); C0[3]=TO_OUTPUT(C_TO_F32(C0[3])+r3c0*ALPHA);
C1[0]=TO_OUTPUT(C_TO_F32(C1[0])+r0c1*ALPHA); C1[1]=TO_OUTPUT(C_TO_F32(C1[1])+r1c1*ALPHA); C1[2]=TO_OUTPUT(C_TO_F32(C1[2])+r2c1*ALPHA); C1[3]=TO_OUTPUT(C_TO_F32(C1[3])+r3c1*ALPHA);
C2[0]=TO_OUTPUT(C_TO_F32(C2[0])+r0c2*ALPHA); C2[1]=TO_OUTPUT(C_TO_F32(C2[1])+r1c2*ALPHA); C2[2]=TO_OUTPUT(C_TO_F32(C2[2])+r2c2*ALPHA); C2[3]=TO_OUTPUT(C_TO_F32(C2[3])+r3c2*ALPHA);
C3[0]=TO_OUTPUT(C_TO_F32(C3[0])+r0c3*ALPHA); C3[1]=TO_OUTPUT(C_TO_F32(C3[1])+r1c3*ALPHA); C3[2]=TO_OUTPUT(C_TO_F32(C3[2])+r2c3*ALPHA); C3[3]=TO_OUTPUT(C_TO_F32(C3[3])+r3c3*ALPHA);
C0+=4; C1+=4; C2+=4; C3+=4;
}
/* ---- 2x4 : 2 rows x 4 cols ---- */
if (bm & 2)
{
ptrbb = bb;
r0c0=r1c0=0; r0c1=r1c1=0; r0c2=r1c2=0; r0c3=r1c3=0;
for (k=0; k<bk; k+=1)
{
b0=ptrbb[0]; b1=ptrbb[1]; b2=ptrbb[2]; b3=ptrbb[3];
a0=ptrba[0]; a1=ptrba[1];
r0c0+=TO_F32(a0)*TO_F32(b0); r1c0+=TO_F32(a1)*TO_F32(b0);
r0c1+=TO_F32(a0)*TO_F32(b1); r1c1+=TO_F32(a1)*TO_F32(b1);
r0c2+=TO_F32(a0)*TO_F32(b2); r1c2+=TO_F32(a1)*TO_F32(b2);
r0c3+=TO_F32(a0)*TO_F32(b3); r1c3+=TO_F32(a1)*TO_F32(b3);
ptrba+=2; ptrbb+=4;
}
C0[0]=TO_OUTPUT(C_TO_F32(C0[0])+r0c0*ALPHA); C0[1]=TO_OUTPUT(C_TO_F32(C0[1])+r1c0*ALPHA);
C1[0]=TO_OUTPUT(C_TO_F32(C1[0])+r0c1*ALPHA); C1[1]=TO_OUTPUT(C_TO_F32(C1[1])+r1c1*ALPHA);
C2[0]=TO_OUTPUT(C_TO_F32(C2[0])+r0c2*ALPHA); C2[1]=TO_OUTPUT(C_TO_F32(C2[1])+r1c2*ALPHA);
C3[0]=TO_OUTPUT(C_TO_F32(C3[0])+r0c3*ALPHA); C3[1]=TO_OUTPUT(C_TO_F32(C3[1])+r1c3*ALPHA);
C0+=2; C1+=2; C2+=2; C3+=2;
}
/* ---- 1x4 : 1 row x 4 cols ---- */
if (bm & 1)
{
ptrbb = bb;
r0c0=0; r0c1=0; r0c2=0; r0c3=0;
for (k=0; k<bk; k+=1)
{
b0=ptrbb[0]; b1=ptrbb[1]; b2=ptrbb[2]; b3=ptrbb[3];
a0=ptrba[0];
r0c0+=TO_F32(a0)*TO_F32(b0);
r0c1+=TO_F32(a0)*TO_F32(b1);
r0c2+=TO_F32(a0)*TO_F32(b2);
r0c3+=TO_F32(a0)*TO_F32(b3);
ptrba+=1; ptrbb+=4;
}
C0[0]=TO_OUTPUT(C_TO_F32(C0[0])+r0c0*ALPHA);
C1[0]=TO_OUTPUT(C_TO_F32(C1[0])+r0c1*ALPHA);
C2[0]=TO_OUTPUT(C_TO_F32(C2[0])+r0c2*ALPHA);
C3[0]=TO_OUTPUT(C_TO_F32(C3[0])+r0c3*ALPHA);
C0+=1; C1+=1; C2+=1; C3+=1;
}
bb = bb + bk*4;
C = C + ldc*4;
}

/* ==================== N panel of 2 ==================== */
if (bn & 2)
{
C0 = C;
C1 = C0+ldc;
ptrba = ba;

for (i=0; i<bm/4; i+=1)
{
ptrbb = bb;
r0c0=r1c0=r2c0=r3c0=0;
r0c1=r1c1=r2c1=r3c1=0;
for (k=0; k<bk; k+=1)
{
b0=ptrbb[0]; b1=ptrbb[1];
a0=ptrba[0]; a1=ptrba[1]; a2=ptrba[2]; a3=ptrba[3];
r0c0+=TO_F32(a0)*TO_F32(b0); r1c0+=TO_F32(a1)*TO_F32(b0); r2c0+=TO_F32(a2)*TO_F32(b0); r3c0+=TO_F32(a3)*TO_F32(b0);
r0c1+=TO_F32(a0)*TO_F32(b1); r1c1+=TO_F32(a1)*TO_F32(b1); r2c1+=TO_F32(a2)*TO_F32(b1); r3c1+=TO_F32(a3)*TO_F32(b1);
ptrba+=4; ptrbb+=2;
}
C0[0]=TO_OUTPUT(C_TO_F32(C0[0])+r0c0*ALPHA); C0[1]=TO_OUTPUT(C_TO_F32(C0[1])+r1c0*ALPHA); C0[2]=TO_OUTPUT(C_TO_F32(C0[2])+r2c0*ALPHA); C0[3]=TO_OUTPUT(C_TO_F32(C0[3])+r3c0*ALPHA);
C1[0]=TO_OUTPUT(C_TO_F32(C1[0])+r0c1*ALPHA); C1[1]=TO_OUTPUT(C_TO_F32(C1[1])+r1c1*ALPHA); C1[2]=TO_OUTPUT(C_TO_F32(C1[2])+r2c1*ALPHA); C1[3]=TO_OUTPUT(C_TO_F32(C1[3])+r3c1*ALPHA);
C0+=4; C1+=4;
}
if (bm & 2)
{
ptrbb = bb;
r0c0=r1c0=0; r0c1=r1c1=0;
for (k=0; k<bk; k+=1)
{
b0=ptrbb[0]; b1=ptrbb[1];
a0=ptrba[0]; a1=ptrba[1];
r0c0+=TO_F32(a0)*TO_F32(b0); r1c0+=TO_F32(a1)*TO_F32(b0);
r0c1+=TO_F32(a0)*TO_F32(b1); r1c1+=TO_F32(a1)*TO_F32(b1);
ptrba+=2; ptrbb+=2;
}
C0[0]=TO_OUTPUT(C_TO_F32(C0[0])+r0c0*ALPHA); C0[1]=TO_OUTPUT(C_TO_F32(C0[1])+r1c0*ALPHA);
C1[0]=TO_OUTPUT(C_TO_F32(C1[0])+r0c1*ALPHA); C1[1]=TO_OUTPUT(C_TO_F32(C1[1])+r1c1*ALPHA);
C0+=2; C1+=2;
}
if (bm & 1)
{
ptrbb = bb;
r0c0=0; r0c1=0;
for (k=0; k<bk; k+=1)
{
b0=ptrbb[0]; b1=ptrbb[1];
a0=ptrba[0];
r0c0+=TO_F32(a0)*TO_F32(b0);
r0c1+=TO_F32(a0)*TO_F32(b1);
ptrba+=1; ptrbb+=2;
}
C0[0]=TO_OUTPUT(C_TO_F32(C0[0])+r0c0*ALPHA);
C1[0]=TO_OUTPUT(C_TO_F32(C1[0])+r0c1*ALPHA);
C0+=1; C1+=1;
}
bb = bb + bk*2;
C = C + ldc*2;
}

/* ==================== N panel of 1 ==================== */
if (bn & 1)
{
C0 = C;
ptrba = ba;

for (i=0; i<bm/4; i+=1)
{
ptrbb = bb;
r0c0=r1c0=r2c0=r3c0=0;
for (k=0; k<bk; k+=1)
{
b0=ptrbb[0];
a0=ptrba[0]; a1=ptrba[1]; a2=ptrba[2]; a3=ptrba[3];
r0c0+=TO_F32(a0)*TO_F32(b0); r1c0+=TO_F32(a1)*TO_F32(b0); r2c0+=TO_F32(a2)*TO_F32(b0); r3c0+=TO_F32(a3)*TO_F32(b0);
ptrba+=4; ptrbb+=1;
}
C0[0]=TO_OUTPUT(C_TO_F32(C0[0])+r0c0*ALPHA); C0[1]=TO_OUTPUT(C_TO_F32(C0[1])+r1c0*ALPHA); C0[2]=TO_OUTPUT(C_TO_F32(C0[2])+r2c0*ALPHA); C0[3]=TO_OUTPUT(C_TO_F32(C0[3])+r3c0*ALPHA);
C0+=4;
}
if (bm & 2)
{
ptrbb = bb;
r0c0=r1c0=0;
for (k=0; k<bk; k+=1)
{
b0=ptrbb[0];
a0=ptrba[0]; a1=ptrba[1];
r0c0+=TO_F32(a0)*TO_F32(b0); r1c0+=TO_F32(a1)*TO_F32(b0);
ptrba+=2; ptrbb+=1;
}
C0[0]=TO_OUTPUT(C_TO_F32(C0[0])+r0c0*ALPHA); C0[1]=TO_OUTPUT(C_TO_F32(C0[1])+r1c0*ALPHA);
C0+=2;
}
if (bm & 1)
{
ptrbb = bb;
r0c0=0;
for (k=0; k<bk; k+=1)
{
r0c0+=TO_F32(ptrba[0])*TO_F32(ptrbb[0]);
ptrba+=1; ptrbb+=1;
}
C0[0]=TO_OUTPUT(C_TO_F32(C0[0])+r0c0*ALPHA);
C0+=1;
}
bb = bb + bk;
C = C + ldc;
}

return 0;
}
Loading
Loading