From 0dc8bb88d2ea4a56475e2c7e35dc6bbd58f9e7c5 Mon Sep 17 00:00:00 2001 From: Aaron Estrada Date: Sun, 6 Sep 2026 13:43:37 -0600 Subject: [PATCH] feat(sb-simd): add modular AVX-512_FP16 vector support (f16.32, f16.16, f16.8) - cpu-identification.lisp: add avx512fp16-supported-p detection via CPUID leaf 7 subleaf 0 EDX bit 23. - packages.lisp: export avx512fp16-supported-p and define sb-simd-avx512fp16 package extending sb-simd-avx512dq. - instruction-sets/avx512fp16.lisp: define :avx512fp16 instruction set introducing half-precision float vectors: * f16.32 (512-bit ZMM, 32 lanes) * f16.16 (256-bit YMM, 16 lanes) * f16.8 (128-bit XMM, 8 lanes) * Vector arithmetic (vaddph, vsubph, vmulph, vdivph, vsqrtph, vminph, vmaxph, vrcpph, vrsqrtph, vscalefph) * FMA with :encoding :fma (vfmadd213ph, vfmsub213ph, vfnmadd213ph, vfnmsub213ph) * Conversions (f32.16 <-> f16.16, s32.16 <-> f16.16) * Bitwise logic and casts - define-custom-vops.lisp: add f16.32-not to def-not macrolet. - x86-64-fake-vops.lisp: add f16.8-broadcast, f16.16-broadcast, and f16.32-broadcast fake VOPs. - record.lisp & test-suite/utilities.lisp: replace deprecated :sb-simd-pack-256 and :sb-simd-pack-512 feature guards with :x86-64. - test-packages.lisp: validate sb-simd-avx512fp16 symbol bindings. --- contrib/sb-simd/code/cpu-identification.lisp | 10 +- contrib/sb-simd/code/define-custom-vops.lisp | 3 +- .../code/instruction-sets/avx512fp16.lisp | 121 ++++++++++++++++++ contrib/sb-simd/code/packages.lisp | 78 +++++++++++ contrib/sb-simd/code/record.lisp | 8 +- contrib/sb-simd/code/x86-64-fake-vops.lisp | 9 ++ contrib/sb-simd/sb-simd.asd | 1 + contrib/sb-simd/test-suite/test-packages.lisp | 3 +- contrib/sb-simd/test-suite/utilities.lisp | 6 +- 9 files changed, 229 insertions(+), 10 deletions(-) create mode 100644 contrib/sb-simd/code/instruction-sets/avx512fp16.lisp diff --git a/contrib/sb-simd/code/cpu-identification.lisp b/contrib/sb-simd/code/cpu-identification.lisp index 684a6e620..812622f91 100644 --- a/contrib/sb-simd/code/cpu-identification.lisp +++ b/contrib/sb-simd/code/cpu-identification.lisp @@ -60,7 +60,12 @@ (defun avx512vl-supported-p () (and (>= (cpuid 0) 7) - (logbitp 31 (nth-value 1 (cpuid 7 0)))))) + (logbitp 31 (nth-value 1 (cpuid 7 0))))) + + (defun avx512fp16-supported-p () + (and (>= (cpuid 0) 7) + (avx512f-supported-p) + (logbitp 23 (nth-value 3 (cpuid 7 0)))))) #-x86-64 (progn @@ -104,6 +109,9 @@ nil) (defun avx512vl-supported-p () + nil) + + (defun avx512fp16-supported-p () nil)) (defun neon-supported-p () diff --git a/contrib/sb-simd/code/define-custom-vops.lisp b/contrib/sb-simd/code/define-custom-vops.lisp index a4c41904b..e02379a8a 100644 --- a/contrib/sb-simd/code/define-custom-vops.lisp +++ b/contrib/sb-simd/code/define-custom-vops.lisp @@ -365,7 +365,8 @@ (def-not sb-simd-avx512bw::u8.64-not) (def-not sb-simd-avx512bw::u16.32-not) (def-not sb-simd-avx512bw::s8.64-not) - (def-not sb-simd-avx512bw::s16.32-not))) + (def-not sb-simd-avx512bw::s16.32-not) + (def-not sb-simd-avx512fp16::f16.32-not))) ;; Neon #+arm64 (progn diff --git a/contrib/sb-simd/code/instruction-sets/avx512fp16.lisp b/contrib/sb-simd/code/instruction-sets/avx512fp16.lisp new file mode 100644 index 000000000..9987ad300 --- /dev/null +++ b/contrib/sb-simd/code/instruction-sets/avx512fp16.lisp @@ -0,0 +1,121 @@ +(in-package #:sb-simd-avx512fp16) + +(define-instruction-set :avx512fp16 + (:test (avx512fp16-supported-p)) + (:include :avx512dq) + (:scalars + (f16 16 (unsigned-byte 16) #:unsigned-num (#:unsigned-reg))) + (:simd-packs + (f16.32 f16 512 #:simd-pack-512-ub16 (#:int-avx512-reg)) + (f16.16 f16 256 #:simd-pack-256-ub16 (#:int-avx2-reg)) + (f16.8 f16 128 #:simd-pack-ub16 (#:int-sse-reg))) + (:simd-casts + (f16.32 f16.32-broadcast) + (f16.16 f16.16-broadcast) + (f16.8 f16.8-broadcast)) + (:reinterpret-casts + (f16.32! f16.32!-from-p128 f16.32!-from-p256 f16.32!-from-p512) + (f16.16! f16.16!-from-p128 f16.16!-from-p256 f16.16!-from-p512) + (f16.8! f16.8!-from-p128 f16.8!-from-p256 f16.8!-from-p512)) + (:instructions + ;; Reinterprets + (f16.32!-from-p128 #:vmovdqu64 (f16.32) (p128) :cost 1 :encoding :move :always-translatable nil) + (f16.32!-from-p256 #:vmovdqu64 (f16.32) (p256) :cost 1 :encoding :move :always-translatable nil) + (f16.32!-from-p512 #:vmovdqu64 (f16.32) (p512) :cost 1 :encoding :move :always-translatable nil) + + (f16.16!-from-p128 #:vmovdqu (f16.16) (p128) :cost 1 :encoding :move :always-translatable nil) + (f16.16!-from-p256 #:vmovdqu (f16.16) (p256) :cost 1 :encoding :move :always-translatable nil) + (f16.16!-from-p512 #:vextracti32x8 (f16.16) (p512) :cost 1 :suffix '(0) :always-translatable nil) + + (f16.8!-from-p128 #:movdqu (f16.8) (p128) :cost 1 :encoding :move :always-translatable nil) + (f16.8!-from-p256 #:vextracti128 (f16.8) (p256) :cost 1 :suffix '(0) :always-translatable nil) + (f16.8!-from-p512 #:vextracti32x4 (f16.8) (p512) :cost 1 :suffix '(0) :always-translatable nil) + + ;; f16.32 + (f16.32-broadcast nil (f16.32) (f16) :cost 1 :encoding :fake-vop) + (two-arg-f16.32+ #:vaddph (f16.32) (f16.32 f16.32) :cost 1 :associative t) + (two-arg-f16.32- #:vsubph (f16.32) (f16.32 f16.32) :cost 1) + (two-arg-f16.32* #:vmulph (f16.32) (f16.32 f16.32) :cost 1 :associative t) + (two-arg-f16.32/ #:vdivph (f16.32) (f16.32 f16.32) :cost 1) + (f16.32-sqrt #:vsqrtph (f16.32) (f16.32) :cost 1) + (two-arg-f16.32-min #:vminph (f16.32) (f16.32 f16.32) :cost 1 :associative t) + (two-arg-f16.32-max #:vmaxph (f16.32) (f16.32 f16.32) :cost 1 :associative t) + (f16.32-rcp #:vrcpph (f16.32) (f16.32) :cost 1) + (f16.32-rsqrt #:vrsqrtph (f16.32) (f16.32) :cost 1) + (f16.32-scalef #:vscalefph (f16.32) (f16.32 f16.32) :cost 1) + + (f16.32-fmadd #:vfmadd213ph (f16.32) (f16.32 f16.32 f16.32) :cost 1 :encoding :fma) + (f16.32-fmsub #:vfmsub213ph (f16.32) (f16.32 f16.32 f16.32) :cost 1 :encoding :fma) + (f16.32-fnmadd #:vfnmadd213ph (f16.32) (f16.32 f16.32 f16.32) :cost 1 :encoding :fma) + (f16.32-fnmsub #:vfnmsub213ph (f16.32) (f16.32 f16.32 f16.32) :cost 1 :encoding :fma) + + (two-arg-f16.32-and #:vpandd (f16.32) (f16.32 f16.32) :cost 1 :associative t) + (two-arg-f16.32-or #:vpord (f16.32) (f16.32 f16.32) :cost 1 :associative t) + (two-arg-f16.32-xor #:vpxord (f16.32) (f16.32 f16.32) :cost 1 :associative t) + (f16.32-andc1 #:vpandnd (f16.32) (f16.32 f16.32) :cost 1) + (f16.32-not nil (f16.32) (f16.32) :cost 1 :encoding :custom) + + ;; f16.16 + (f16.16-broadcast nil (f16.16) (f16) :cost 1 :encoding :fake-vop) + (two-arg-f16.16+ #:vaddph (f16.16) (f16.16 f16.16) :cost 1 :associative t) + (two-arg-f16.16- #:vsubph (f16.16) (f16.16 f16.16) :cost 1) + (two-arg-f16.16* #:vmulph (f16.16) (f16.16 f16.16) :cost 1 :associative t) + (two-arg-f16.16/ #:vdivph (f16.16) (f16.16 f16.16) :cost 1) + (f16.16-sqrt #:vsqrtph (f16.16) (f16.16) :cost 1) + (two-arg-f16.16-min #:vminph (f16.16) (f16.16 f16.16) :cost 1 :associative t) + (two-arg-f16.16-max #:vmaxph (f16.16) (f16.16 f16.16) :cost 1 :associative t) + (f16.16-rcp #:vrcpph (f16.16) (f16.16) :cost 1) + (f16.16-rsqrt #:vrsqrtph (f16.16) (f16.16) :cost 1) + + (f16.16-fmadd #:vfmadd213ph (f16.16) (f16.16 f16.16 f16.16) :cost 1 :encoding :fma) + (f16.16-fmsub #:vfmsub213ph (f16.16) (f16.16 f16.16 f16.16) :cost 1 :encoding :fma) + (f16.16-fnmadd #:vfnmadd213ph (f16.16) (f16.16 f16.16 f16.16) :cost 1 :encoding :fma) + (f16.16-fnmsub #:vfnmsub213ph (f16.16) (f16.16 f16.16 f16.16) :cost 1 :encoding :fma) + + ;; f16.8 + (f16.8-broadcast nil (f16.8) (f16) :cost 1 :encoding :fake-vop) + (two-arg-f16.8+ #:vaddph (f16.8) (f16.8 f16.8) :cost 1 :associative t) + (two-arg-f16.8- #:vsubph (f16.8) (f16.8 f16.8) :cost 1) + (two-arg-f16.8* #:vmulph (f16.8) (f16.8 f16.8) :cost 1 :associative t) + (two-arg-f16.8/ #:vdivph (f16.8) (f16.8 f16.8) :cost 1) + (f16.8-sqrt #:vsqrtph (f16.8) (f16.8) :cost 1) + (two-arg-f16.8-min #:vminph (f16.8) (f16.8 f16.8) :cost 1 :associative t) + (two-arg-f16.8-max #:vmaxph (f16.8) (f16.8 f16.8) :cost 1 :associative t) + (f16.8-rcp #:vrcpph (f16.8) (f16.8) :cost 1) + (f16.8-rsqrt #:vrsqrtph (f16.8) (f16.8) :cost 1) + + (f16.8-fmadd #:vfmadd213ph (f16.8) (f16.8 f16.8 f16.8) :cost 1 :encoding :fma) + (f16.8-fmsub #:vfmsub213ph (f16.8) (f16.8 f16.8 f16.8) :cost 1 :encoding :fma) + (f16.8-fnmadd #:vfnmadd213ph (f16.8) (f16.8 f16.8 f16.8) :cost 1 :encoding :fma) + (f16.8-fnmsub #:vfnmsub213ph (f16.8) (f16.8 f16.8 f16.8) :cost 1 :encoding :fma) + + ;; Conversions + (f32.16-from-f16.16 #:vcvtph2psx (f32.16) (f16.16) :cost 3) + (f16.16-from-f32.16 #:vcvtps2phx (f16.16) (f32.16) :cost 3) + (f16.16-from-s32.16 #:vcvtdq2ph (f16.16) (s32.16) :cost 3) + (s32.16-from-f16.16 #:vcvtph2dq (s32.16) (f16.16) :cost 3)) + (:associatives + (f16.32+ two-arg-f16.32+ 0) + (f16.32* two-arg-f16.32* 1) + (f16.32-min two-arg-f16.32-min nil) + (f16.32-max two-arg-f16.32-max nil) + (f16.32-and two-arg-f16.32-and +u16-true+) + (f16.32-or two-arg-f16.32-or +u16-false+) + (f16.32-xor two-arg-f16.32-xor +u16-false+) + + (f16.16+ two-arg-f16.16+ 0) + (f16.16* two-arg-f16.16* 1) + (f16.16-min two-arg-f16.16-min nil) + (f16.16-max two-arg-f16.16-max nil) + + (f16.8+ two-arg-f16.8+ 0) + (f16.8* two-arg-f16.8* 1) + (f16.8-min two-arg-f16.8-min nil) + (f16.8-max two-arg-f16.8-max nil)) + (:reducers + (f16.32- two-arg-f16.32- 0) + (f16.32/ two-arg-f16.32/ 1) + (f16.16- two-arg-f16.16- 0) + (f16.16/ two-arg-f16.16/ 1) + (f16.8- two-arg-f16.8- 0) + (f16.8/ two-arg-f16.8/ 1))) diff --git a/contrib/sb-simd/code/packages.lisp b/contrib/sb-simd/code/packages.lisp index 9fcf43bf0..814d96ebf 100644 --- a/contrib/sb-simd/code/packages.lisp +++ b/contrib/sb-simd/code/packages.lisp @@ -257,6 +257,7 @@ #:avx512cd-supported-p #:avx512bw-supported-p #:avx512vl-supported-p + #:avx512fp16-supported-p #:neon-supported-p)) (progn @@ -2513,6 +2514,83 @@ #:u64.8* #:s64.8*)) + #+x86-64 + (defpackage #:sb-simd-avx512fp16 + (:use #:common-lisp #:sb-simd-internals #:sb-simd-avx512dq) + #0# + #1# + #8# + #9# + #10# + #12# + #13# + #14# + #15= + (:export + #:f16 + ;; f16.32 + #:f16.32 + #:f16.32! + #:f16.32-broadcast + #:f16.32+ + #:f16.32- + #:f16.32* + #:f16.32/ + #:f16.32-sqrt + #:f16.32-min + #:f16.32-max + #:f16.32-rcp + #:f16.32-rsqrt + #:f16.32-scalef + #:f16.32-fmadd + #:f16.32-fmsub + #:f16.32-fnmadd + #:f16.32-fnmsub + #:f16.32-and + #:f16.32-or + #:f16.32-xor + #:f16.32-andc1 + #:f16.32-not + ;; f16.16 + #:f16.16 + #:f16.16! + #:f16.16-broadcast + #:f16.16+ + #:f16.16- + #:f16.16* + #:f16.16/ + #:f16.16-sqrt + #:f16.16-min + #:f16.16-max + #:f16.16-rcp + #:f16.16-rsqrt + #:f16.16-fmadd + #:f16.16-fmsub + #:f16.16-fnmadd + #:f16.16-fnmsub + ;; f16.8 + #:f16.8 + #:f16.8! + #:f16.8-broadcast + #:f16.8+ + #:f16.8- + #:f16.8* + #:f16.8/ + #:f16.8-sqrt + #:f16.8-min + #:f16.8-max + #:f16.8-rcp + #:f16.8-rsqrt + #:f16.8-fmadd + #:f16.8-fmsub + #:f16.8-fnmadd + #:f16.8-fnmsub + ;; conversions + #:f32.16-from-f16.16 + #:f16.16-from-f32.16 + #:f16.16-from-s32.16 + #:s32.16-from-f16.16)) + #+arm64 (defpackage #:sb-simd-arm64 (:use #:common-lisp #:sb-simd-internals #:sb-simd) diff --git a/contrib/sb-simd/code/record.lisp b/contrib/sb-simd/code/record.lisp index 381e24da3..2e452aaa3 100644 --- a/contrib/sb-simd/code/record.lisp +++ b/contrib/sb-simd/code/record.lisp @@ -181,14 +181,14 @@ (defun scalar-record-p (x) (typep x '(and value-record (not simd-record)))) -#-sb-simd-pack-256 +#-(or x86-64 sb-simd-pack-256) (progn (defstruct phony-simd-pack-256) (deftype simd-pack-256 (&optional element-type) (declare (ignore element-type)) 'phony-simd-pack-256)) -#-sb-simd-pack-512 +#-(or x86-64 sb-simd-pack-512) (progn (defstruct phony-simd-pack-512) (deftype simd-pack-512 (&optional element-type) @@ -202,10 +202,10 @@ (ecase bits (128 (find-symbol "SIMD-PACK" "SB-EXT")) (256 (or (find-symbol "SIMD-PACK-256" "SB-EXT") - #-sb-simd-pack-256 + #-(or x86-64 sb-simd-pack-256) 'simd-pack-256)) (512 (or (find-symbol "SIMD-PACK-512" "SB-EXT") - #-sb-simd-pack-512 + #-(or x86-64 sb-simd-pack-512) 'simd-pack-512))))) (cond ((not base-type) 't) ((not scalar-record-name) base-type) diff --git a/contrib/sb-simd/code/x86-64-fake-vops.lisp b/contrib/sb-simd/code/x86-64-fake-vops.lisp index d88826b05..13965b4d2 100644 --- a/contrib/sb-simd/code/x86-64-fake-vops.lisp +++ b/contrib/sb-simd/code/x86-64-fake-vops.lisp @@ -1545,3 +1545,12 @@ (define-fake-vop s16.32!-from-s16 (x) (%s16.32-broadcast x)) +(define-fake-vop sb-simd-avx512fp16:f16.8-broadcast (x) + (sb-simd-avx512fp16::%f16.8!-from-p128 (sb-simd-sse2::%u16.8-broadcast x))) + +(define-fake-vop sb-simd-avx512fp16:f16.16-broadcast (x) + (sb-simd-avx512fp16::%f16.16!-from-p256 (sb-simd-avx::%u16.16-broadcast x))) + +(define-fake-vop sb-simd-avx512fp16:f16.32-broadcast (x) + (sb-simd-avx512fp16::%f16.32!-from-p512 (sb-simd-avx512bw::%u16.32-broadcast x))) + diff --git a/contrib/sb-simd/sb-simd.asd b/contrib/sb-simd/sb-simd.asd index deadf4987..3dafef2e0 100644 --- a/contrib/sb-simd/sb-simd.asd +++ b/contrib/sb-simd/sb-simd.asd @@ -34,6 +34,7 @@ (:file "avx512f" :if-feature :x86-64) (:file "avx512bw" :if-feature :x86-64) (:file "avx512dq" :if-feature :x86-64) + (:file "avx512fp16" :if-feature :x86-64) (:file "arm64" :if-feature :arm64) (:file "neon" :if-feature :arm64))) (:file "define-types") diff --git a/contrib/sb-simd/test-suite/test-packages.lisp b/contrib/sb-simd/test-suite/test-packages.lisp index 502d00858..10b23b488 100644 --- a/contrib/sb-simd/test-suite/test-packages.lisp +++ b/contrib/sb-simd/test-suite/test-packages.lisp @@ -18,7 +18,8 @@ (check-package '#:sb-simd-avx2) (check-package '#:sb-simd-avx512f :skip '(f32-fmaddsub f32-fmsubadd f64-fmaddsub f64-fmsubadd)) (check-package '#:sb-simd-avx512bw :skip '(f32-fmaddsub f32-fmsubadd f64-fmaddsub f64-fmsubadd)) - (check-package '#:sb-simd-avx512dq :skip '(f32-fmaddsub f32-fmsubadd f64-fmaddsub f64-fmsubadd))) + (check-package '#:sb-simd-avx512dq :skip '(f32-fmaddsub f32-fmsubadd f64-fmaddsub f64-fmsubadd)) + (check-package '#:sb-simd-avx512fp16 :skip '(f32-fmaddsub f32-fmsubadd f64-fmaddsub f64-fmsubadd))) #+arm64 (check-package '#:sb-simd-neon) ;; Ensure that every instruction has a corresponding VOP. diff --git a/contrib/sb-simd/test-suite/utilities.lisp b/contrib/sb-simd/test-suite/utilities.lisp index 4974a4fb5..1b7886cbb 100644 --- a/contrib/sb-simd/test-suite/utilities.lisp +++ b/contrib/sb-simd/test-suite/utilities.lisp @@ -43,7 +43,7 @@ (sb-vm::%simd-pack-ref-64 pack 2) (sb-vm::%simd-pack-ref-64 pack 3))) -#+sb-simd-pack-512 +#+(or x86-64 sb-simd-pack-512) (defun %simd-pack-512-ub64s (pack) (values (sb-vm::%simd-pack-ref-64 pack 0) (sb-vm::%simd-pack-ref-64 pack 1) @@ -61,13 +61,13 @@ (multiple-value-bind (a0 a1) (%simd-pack-ub64s a) (multiple-value-bind (b0 b1) (%simd-pack-ub64s b) (and (= a0 b0) (= a1 b1)))))) - #+sb-simd-pack-256 + #+(or x86-64 sb-simd-pack-256) (sb-ext:simd-pack-256 (when (sb-ext:simd-pack-256-p b) (multiple-value-bind (a0 a1 a2 a3) (%simd-pack-256-ub64s a) (multiple-value-bind (b0 b1 b2 b3) (%simd-pack-256-ub64s b) (and (= a0 b0) (= a1 b1) (= a2 b2) (= a3 b3)))))) - #+sb-simd-pack-512 + #+(or x86-64 sb-simd-pack-512) (sb-ext:simd-pack-512 (when (sb-ext:simd-pack-512-p b) (multiple-value-bind (a0 a1 a2 a3 a4 a5 a6 a7) (%simd-pack-512-ub64s a)