mirror of
https://github.com/hanzoai/wasm2go.git
synced 2026-10-30 15:06:48 +00:00
Assembly overrides can now declare an arm64 body for FEAT_FHM, the f16-product / f32-accumulate multiply-adds (FMLAL, FMLAL2 and their by-element forms). The base package detects it (hw.optional.arm.FEAT_FHM on darwin, HWCAP_ASIMDFHM on linux) as CPUFHM, and the dispatch ladder checks it first: the arm64 levels are independent features rather than a ladder, so the order only decides which of several present bodies runs. Co-authored-by: Claude Fable 5.1 <[email protected]>
55 lines
1.4 KiB
Go
55 lines
1.4 KiB
Go
//go:build arm64 && linux
|
|
|
|
package helpers
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"os"
|
|
)
|
|
|
|
// CPUDotProd reports FEAT_DotProd (the SDOT/UDOT instructions).
|
|
// Feature-gated splice bodies dispatch on it at runtime; the
|
|
// portable twin body runs when it is false.
|
|
var CPUDotProd = detectDotProd()
|
|
|
|
// CPUI8MM reports FEAT_I8MM (the SMMLA/UMMLA int8 matrix
|
|
// instructions). The tile kernels branch on it at entry and fall
|
|
// back to their dotprod bodies when it is false — FEAT_DotProd
|
|
// without FEAT_I8MM is common (Neoverse N1, Cortex-A76..X1, Apple
|
|
// M1), so the two are detected separately.
|
|
var CPUI8MM = detectI8MM()
|
|
|
|
// CPUFHM reports FEAT_FHM (FMLAL/FMLSL: f16 products accumulated in
|
|
// f32). Bodies that keep f16 operands unwidened dispatch on it.
|
|
var CPUFHM = detectFHM()
|
|
|
|
func detectDotProd() bool {
|
|
// AT_HWCAP (16), HWCAP_ASIMDDP (bit 20).
|
|
return auxvBit(16, 20)
|
|
}
|
|
|
|
func detectI8MM() bool {
|
|
// AT_HWCAP2 (26), HWCAP2_I8MM (bit 13).
|
|
return auxvBit(26, 13)
|
|
}
|
|
|
|
func detectFHM() bool {
|
|
// AT_HWCAP (16), HWCAP_ASIMDFHM (bit 23).
|
|
return auxvBit(16, 23)
|
|
}
|
|
|
|
// auxvBit reports bit `bit` of the auxiliary-vector entry `key`:
|
|
// unswappable 8-byte key/value pairs.
|
|
func auxvBit(key uint64, bit uint) bool {
|
|
auxv, err := os.ReadFile("/proc/self/auxv")
|
|
if err != nil {
|
|
return false
|
|
}
|
|
for i := 0; i+16 <= len(auxv); i += 16 {
|
|
if binary.LittleEndian.Uint64(auxv[i:]) == key {
|
|
return binary.LittleEndian.Uint64(auxv[i+8:])&(1<<bit) != 0
|
|
}
|
|
}
|
|
return false
|
|
}
|