BookinglyTech News
Software

Go 1.27 estrena una API SIMD portable y experimental para amd64, arm64 y wasm

Go 1.27 suma a las APIs experimentales de SIMD un paquete portable y agnóstico al tamaño de vector, con emulación en plataformas sin soporte.

3 min de lecturaHacker News (top)0 vistas

Go 1.27 incluye una API experimental de SIMD portable, independiente de la plataforma y del tamaño de vector. Llega después de que Go 1.26 introdujera una API para amd64 y de que la propia 1.27 añadiera soporte para arm64, en concreto NEON, y wasm. El paquete se activa en tiempo de compilación con GOEXPERIMENT=simd, igual que el paquete archsimd.

Antes de estas APIs, la única forma de usar SIMD desde Go era escribir ensamblador. Solo compensaba en kernels de cómputo muy críticos, así que mucho software que podría aprovechar las instrucciones vectoriales dejaba la CPU sin usar. El recolector de basura Green Tea, por ejemplo, emplea SIMD para acelerar el escaneo de memoria en busca de objetos vivos.

Del archsimd al simd portable

Go 1.26 trajo archsimd, un paquete dependiente de la arquitectura. Go 1.27 va más allá con simd, una interfaz experimental, portable y agnóstica al tamaño, inspirada libremente en Highway para C++. La idea es escribir una vez código SIMD con rendimiento cercano al ensamblador en plataformas con soporte y una emulación competente en las que no lo tienen.

El paquete simd soporta AVX, AVX2 y AVX512 en amd64, NEON en arm64 y las instrucciones SIMD de wasm. Los tipos de vector son primitivos en plural y con mayúscula inicial, como simd.Uint8s o simd.Float32s. Se cargan y almacenan desde slices. Un ejemplo de la API es una función innerProduct que usa LoadFloat32s, MulAdd y sum para calcular el producto interno de dos arrays de float32.

El problema de fondo

Las arquitecturas SIMD varían en casi todo. Unas tienen un tamaño de vector fijo: wasm, PowerPC y s390x, 128 bits. Otras ofrecen varios tamaños fijos: amd64 con 128, 256 y 512; loong64 con 128 y 256. riscv64 admite vectores de tamaño no especificado entre 128 y 65536 bits, siempre potencias de dos. arm64 combina NEON, de 128 bits, con SVE, de 128 a 2048 bits y también potencias de dos. Saber qué soporta una máquina concreta exige comprobar características: en amd64, si hay AVX, AVX2 o AVX512; en arm64, si hay NEON o SVE, y qué variante de SVE.

También cambia el enmascaramiento. wasm, AVX, AVX2 y NEON no tienen máscaras y usan bitmasks vectoriales y operaciones booleanas. AVX512 y RVV emplean registros de máscara especiales. SVE asigna un bit por byte del vector, pero el bit menos significativo de cada elemento gobierna la operación. Las operaciones disponibles tampoco son iguales: wasm, por ejemplo, carece de comparaciones para vectores de enteros de 64 bits.

El paquete simd tapa esas diferencias quitando los vectores de tamaño fijo del sistema de tipos y exponiendo solo las operaciones que están en la intersección de todas las plataformas. Los huecos los rellena con emulación eficiente a partir de otras instrucciones SIMD. En plataformas sin SIMD o sin soporte en archsimd, todas las operaciones se emulan, de modo que el código escrito con simd siempre se ejecuta.

Para quien mantiene kernels de criptografía, procesamiento de datos o IA en Go, la propuesta reduce la dependencia del ensamblador y facilita llevar el mismo código entre amd64, arm64 y wasm. Queda por ver si la emulación aguanta cargas reales y cuándo el paquete dejará de ser experimental.