AI가 써주는데 왜 어셈블리어로 개발하지 않나
한 번쯤 떠오르는 질문입니다. 고급 언어는 사람이 기계어를 직접 다루기 어려워서 만든 도구입니다. 그렇다면 AI가 코드를 대신 써주는 지금, 굳이 파이썬이나 러스트를 거칠 이유가 있을까요. 모델에게 바로 어셈블리를 뽑게 하면 중간 단계를 걷어내고 최고 성능을 얻을 수 있어야 합니다.
이 추론에는 전제가 하나 깔려 있습니다. 추상화가 사람의 인지 한계를 메우려고 생겼다는 전제입니다. 이 전제가 틀렸습니다.
통과율 51.5%
SuperCoder 연구팀이 어셈블리 슈퍼옵티마이제이션 벤치마크를 만들었습니다. 평균 130줄짜리 어셈블리 프로그램 8,072개로, 이전 데이터셋보다 훨씬 큽니다. 여기에 23개 모델을 붙였습니다.
가장 잘한 모델이 Claude Opus 4였고, 테스트 통과율 51.5%에 gcc -O3 대비 평균 1.43배 속도였습니다.
두 숫자를 나눠 읽어야 합니다. 1.43배는 컴파일러 최고 최적화 옵션을 이겼다는 뜻이라 인상적입니다. 51.5%는 나머지 절반이 틀린 코드였다는 뜻입니다. 절반이 틀린 1.43배는 쓸 수 없습니다.
강화학습으로 파인튜닝하면 달라집니다. Qwen2.5-Coder-7B-Instruct가 61.4% 정확도에 1.10배였는데, 정확도와 속도를 함께 보상으로 넣어 학습한 SuperCoder는 95.0% 정확도에 1.46배가 됐습니다. 7B 모델이 최상위 상용 모델을 크게 앞섭니다.
여기서 읽을 것은 "LLM이 어셈블리를 잘 쓴다"가 아닙니다. 범용 모델은 어셈블리를 못 쓰고, 이 좁은 과제에 맞춰 따로 학습시킨 작은 모델은 잘 쓴다는 것입니다. 어셈블리 생성은 일반 코딩 능력의 연장선이 아니라 별개 기술입니다.
GPU에서는 2.4%
PerfCodeBench는 범위를 넓혀서 시스템 레벨 성능 최적화를 측정합니다. 6개 언어, 1,854개 태스크입니다.
최고 성적을 낸 GPT-5.4 기준으로 정확하고 실행되는 비율이 71.25%, 기준선보다 빠른 비율이 66.72%, 사람이 쓴 참조 구현 이상인 비율이 51.82%였습니다.
여기까지는 나쁘지 않습니다. 문제는 쪼개 보면 나옵니다.
구분 |
정확·실행 비율 |
|---|---|
CPU 태스크 |
82% |
GPU(CUDA) 태스크 |
2.4% |
C++ |
74.73% |
C |
45.16% |
CPU 82%와 GPU 2.4%는 같은 모델의 성적입니다. 저자들 표현대로 CPU 시스템 코드를 푼다고 해서 가속기 커널로 전이되지 않습니다.
C++가 C보다 잘 나오는 것도 뒤집힌 결과처럼 보입니다. C가 더 단순한 언어인데 성적이 30%p 낮습니다. 학습 데이터에 최신 최적화 논의가 C++ 쪽에 훨씬 많기 때문으로 보는 게 자연스럽습니다. 모델의 성능은 문제의 난이도가 아니라 데이터의 두께를 따릅니다.
아키텍처가 바뀌면 무너집니다
CodegenBench는 이 데이터 의존성을 정면으로 겨눕니다. x86_64와 중국의 선웨이(Sunway), 화웨이 쿤펑(Kunpeng) 세 아키텍처에서 BLAS 루틴 106개와 아키텍처별 특화 커널 20개를 생성시켰습니다.
결과는 예상 가능한 방향으로 극단적이었습니다. x86_64에서는 최상위 모델이 잘합니다. 공개 문서와 학습 데이터가 적은 도메인 특화 아키텍처에서는 성능이 크게 떨어집니다.
이게 어셈블리 개발론의 급소입니다. 어셈블리는 빠른 언어가 아니라 이식성을 포기한 언어입니다. C 코드 한 벌은 x86-64, ARM64, RISC-V에서 모두 컴파일됩니다. 어셈블리는 세 벌을 따로 써야 합니다. 그리고 모델은 그중 데이터가 많은 한 벌만 잘 씁니다.
애플이 인텔에서 자체 실리콘으로 넘어갈 때, 고급 언어로 짠 코드는 재컴파일로 넘어갔습니다. 손으로 쓴 어셈블리는 다시 썼습니다. AI가 그 재작성을 대신해 준다 해도, 세 아키텍처 중 두 개는 성적이 낮은 쪽입니다.
병목은 생성이 아니라 검증입니다
소스코드는 실행되기 위해서만 존재하는 게 아닙니다. 리뷰하고, diff를 보고, 테스트를 붙이고, 몇 년 뒤에 왜 이렇게 짰는지 되짚는 매체입니다. 함수 이름, 타입 시그니처, 주석은 기계에게 아무 의미가 없고 사람과 도구에게만 의미가 있습니다.
어셈블리에는 그 층이 없습니다. 레지스터 이름은 의미를 담지 않고, 두 버전을 diff하면 명령어 순서가 전부 밀려서 무엇이 바뀌었는지 읽히지 않습니다. 정적 분석기, 타입 체커, 새니타이저 대부분이 작동하지 않습니다.
AI가 코드를 더 많이 쓸수록 이 층은 덜 중요해지는 게 아니라 더 중요해집니다. 사람이 직접 쓴 코드는 쓰면서 이미 한 번 검증됩니다. 생성된 코드는 그 과정이 없으니 읽고 확인하는 부담이 통째로 뒤로 넘어옵니다. 검토해야 할 코드량이 늘어나는 상황에서 검토가 불가능한 표현으로 내려갈 이유가 없습니다.
추상화의 방향은 AI 때문에 바뀐다면 위로 바뀝니다. 실제로 그렇게 가고 있습니다. 사람들은 어셈블리로 내려가는 대신 타입 시스템이 강한 언어, 명세와 테스트, 형식 검증 쪽으로 올라가고 있습니다. 생성이 싸질수록 값이 붙는 건 검증입니다.
컴파일러는 이미 그 일을 합니다
한 가지 더. gcc -O3는 사람이 손으로 하기 힘든 일을 이미 합니다. 레지스터 할당, 명령어 스케줄링, 자동 벡터화, 인라이닝, 루프 언롤링을 대상 CPU 모델에 맞춰 수행합니다. 수십 년치 최적화가 누적된 공유 자산이고, 그 결과는 재현 가능하며, 버그가 나오면 모두가 같이 고칩니다.
SuperCoder의 1.46배는 이 기준선 위에서 나온 수치입니다. 평균 130줄짜리 프로그램에서요. 수만 줄짜리 실제 시스템 전체에 같은 배수가 적용된다는 뜻이 아닙니다.
그리고 그 1.46배가 진짜 가치가 있다면, 갈 자리는 개발자의 편집기가 아니라 컴파일러 백엔드 안입니다. 슈퍼옵티마이저는 원래 그런 도구입니다. 후보를 탐색하고 등가성 검증기로 정합성을 보장한 뒤 통과한 것만 내놓습니다. LLM은 그 탐색 단계를 맡기에 적합합니다. 51.5%라는 통과율도 검증기가 뒤를 받치면 문제가 되지 않습니다. 틀린 절반은 버려지면 그만이니까요.
정리
"AI가 써주니 어셈블리로 개발하자"는 제안은 추상화가 사람의 한계를 메우는 장치라는 전제 위에 서 있습니다. 추상화가 하는 일은 세 가지입니다. 사람의 인지 부담을 줄이고, 하나의 코드가 여러 아키텍처에서 돌게 하고, 코드를 검증 가능한 형태로 유지합니다.
AI는 첫 번째만 해결합니다. 두 번째와 세 번째는 그대로 남고, 벤치마크 세 개는 오히려 두 번째가 AI에게 더 어렵다는 것을 보여줍니다. 어셈블리를 AI가 쓰는 미래는 올 것 같습니다. 다만 우리가 편집기에서 보는 자리가 아니라 툴체인 안에서, 검증기 뒤에서 옵니다. 그건 새 개발 방식이 아니라 더 좋은 컴파일러입니다.
참고: SuperCoder: Assembly Program Superoptimization with Large Language Models · PerfCodeBench: Benchmarking LLMs for System-Level High-Performance Code Optimization · CodegenBench: Can LLMs Write Efficient Code Across Architectures? · Superoptimization, Wikipedia