Go 1.26·1.27, 어셈블리 없이 SIMD 쓰는 실험적 API 선보여
- Go 1.26이 amd64용 SIMD API를, Go 1.27이 arm64(NEON)와 wasm용 API를 추가함. 기전에는 이 기능을 쓰려면 Go 어셈블리를 직접 작성해야 했음.
- Go 1.27은 플랫폼과 벡터 크기를 가리지 않는 실험적 simd 패키지를 도입, C++의 Highway를 느슨히 참고해 한 번 작성하면 아셈 수준 성능을 목표로 함.
- simd 패키지는 고정 크기 벡터를 타입 체계에서 빼고 모든 플랫폼 연산의 교집합만 제공, 빈 자리는 다른 SIMD 명령어로 에뮬레이션해 메꿈.
- 지원 범위는 amd64의 AVX, AVX2, AVX512, arm64의 NEON, wasm의 SIMD 명령어이며 GOEXPERIMENT=simd로 켤 수 있음. SIMD가 없는 플랫폼은 전부 에뮬레이션으로 동작함.
- 컴파일러는 AST 재작성으로 simd 타입을 쓰는 함수를 @simdNNN(128/256/512, 0은 에뮬레이션) 복사본으로 만들고, 프로그램 시작 시 확인한 SIMD 레벨로 분기해 특화 함수끼리는 오버헤드 없이 직접 호출함.
Hacker News opinions
이 브랜치 성격 참 잘 잡은 것 같아. 멀티코어 도는 Go 프로젝트 저수준 최적화 문이 열리는 건데, 표준 라이브러리에 SIMD 변형까지 넣는 언어가 별로 없었지.
벡터 연산은 MATLAB이 원래 밑천으로 삼던 거임.
C/C++은 그렇다치고 Java, .NET, D, Zig, Julia, Swift, Rust에도 있었잖아. 다만 이런 언어가 SIMD 쓰는 법을 직접 안 넣는 이유는, 대다수가 SIMD 코드를 어떻게 잘 짜는지 모르기 때문이더라. 나부터도 그렇고.
내 Go 최대 불만이 이거였는데 거의 항상 성능 내려면 C/C++ 링크해야 했거든. 자동 벡터화가 '대충 충분한' 경우가 많다는 점은 이번에도 못 메운 게 아쉽다.
숫자 루프를 SIMD로 고쳐 써주는 린터 룰로 1차 버전 만들 수 있을 듯. 이미 여러 종류 루프 고치는 룰이 있으니까 되잖아.
어셈블리랑 unsafe 패키지는 구석에서 잊히네. CGO가 더 쉬운 길일 뿐 Go에 선택지가 없던 건 아니었어.
참고로 Go 컴파일러에 자동 벡터화 작업이 이미 진행 중임. CL 791740에 쌓여 있고 결과도 나쁘지 않아서 어느 정도는 들어갈 것 같아.