컴파일부터 아카이브까지 - LLVM

Tabber·2026년 2월 1일

Swift

목록 보기
8/15
post-thumbnail

iOS 개발자라면,,한번쯤은 공부하고 싶던 부분인 컴파일 - 아카이빙 까지의 모든 과정을 공부해봐요.

목차는 다음과 같아요.

  • LLVM
  • ABI
  • Static vs Dynamic Linking
  • ODR
  • 아카이빙, 앱 사이닝
  • Bitcode, App Thinning

오늘은 LLVM에 대해 알아볼 예정이에요.

LLVM은 Low Level Virtual Machine 의 약어로, 현대 컴파일러 기술의 심장이자, Apple 생태계의 모든 언어(Swift, Objective-C, C++)를 지탱하는 거대한 인프라에요.

LLVM의 핵심 철학 - “모듈화와 재사용성”

과거의 컴파일러(ex. 초기 GCC)는 특정 언어를 특정 CPU 아키텍처용으로 만드는 ‘통짜’ 구조였어요. 하지만 LLVM은 이를 Frontend- Optimizer - Backend 세 단계로 완전히 분리했어요.

  • Frontend (Swift/Clang) : 소스 코드를 읽어 문법을 검사하고, LLVM이 이해할 수 있는 “중간 표현(IR)”으로 번역해요.
  • Optimizer : 특정 하드웨어에 의존하지 않는 상태에서 코드의 효율성을 극대화해요.
  • Backend(LLVM Code Generator) : 최적화된 IR을 실제 기계어(x86, ARM 등)로 변환해요.

Swift 컴파일 파이프라인 (The Swift Way)

Swift는 LLVM의 표준 흐름을 따르면서도, 언어 특유의 성능 최적화를 위해 SIL(Swift Intermediate Language) 이라는 독특한 단계를 하나 더 가지고 있어요.
전체 과정은 다음과 같아요.

  1. Parsing & Semantic Analysis
  • AST(Abstract Syntax Tree) 생성 : 소스 코드를 트리 구조로 분석해요.
  • Type Checking : 변수와 함수의 타입이 맞는지 확인해요. Swift의 강력한 타입 안정성이 여기서 결정돼요.
  1. SIL Generation (Swift 전용 단계)

Swift는 정적 타입 언어이면서도 제네릭, 프로토콜 등 유연한 기능을 제공해요.
이를 LLVM IR로 바로 보내기엔 정보 손실이 커요.

  • Raw SIL : AST에서 변환된 가공되지 않은 중간 언어에요.
  • Canonical SIL : ‘Definite Initialization’ (모든 변수가 사용 전 초기화되었는지) 확인 등 Swift 특유의 최적화가 수행된 상태에요.
  1. IR Generation (LLVM IR)

이제 Swift의 색을 빼고, LLVM이 이해할 수 있는 범용적인 LLVM IR로 변환돼요. 이 단계부터는 언어에 상관없이 공통적인 최적화가 가능해져요.

LLVM IR (Intermediate Representation)

LLVM IR은 컴파일러의 ‘공용어’에요. 어셈블리어와 비슷하게 생겼지만, 다음과 같은 특징이 있어요.

  • 강력한 타입 시스템 : 단순한 메모리 주소가 아니라 타입을 가지고 있어요.
  • 무한한 레지스터 : 실제 CPU와 달리 레지스터 개수에 제한이 없다고 가정해요.
  • SSA (Static Single Assignment) : 모든 변수는 딱 한 번만 할당돼요. 이 특성 덕분에 컴파일러가 데이터의 흐름을 분석하고 최적화하기가 매우 쉬워져요.

왜 LLVM인가요? (iOS 개발 측면에서)

  1. Bitcode 지원 : Apple이 앱스토어에 앱을 올릴 때 Bitcode 형태로 제출하라고 하는 경우가 있어요. 이 Bitcode가 바로 ‘LLVM IR’의 바이너리 형태에요. 덕분에 Apple은 새로운 CPU가 나오면 개발자가 앱을 다시 출시하지 않아도 서버에서 최적화된 기계어로 재컴파일 해줄 수 있어요.
  2. 도구 체인의 통합 : Xcode 정적 분석기, 디버거(LLDB), Instruments가 모두 LLVM 인프라 위에서 돌아가므로 일관된 개발 경험을 제공해요.
  3. Swift 성능 : Swift가 Obejctive-C보다 빠른 이유는 SIL 단계에서 수행되는 고도의 최적화와 LLVM Backend의 강력한 코드 생성 능력 덕분이에요.

정리

오늘은 LLVM에 대해 알아보았어요.

LLVM은 과거 GCC 컴파일러의 단점인 확장성, 분리를 해결하기 위해 나온 컴파일러에요.

Frontend-Optimizer-Backend 으로 역할을 분리하여 기기의 의존성 CPU, 아키텍처에 대한 의존성을 분리하였고, 각 역할이 나눠져있기에 속도 또한 빨라질 수 있었어요.

Swift는 LLVM IR 단계를 거치기 전에 SIL이라는 단계를 거치는데, 이 단계는 Swift 언어의 특징이에요. Swift의 제네릭, 프로토콜 등의 성능과 구현을 최적화 하기 위해 필요한 단계로 이 단계를 거치게 되면 속도와 안정성이 극대화 됩니다. 이 과정을 거치지 않으면 Swift의 고수준의 의도를 잃어버려 LLVM이 최적화할 기회를 놓치거나 컴파일 자체가 불가능해져요.

LLVM IR은 컴파일러의 공용어 역할을 합니다. 이 덕분에 Apple 생태계에서 아키텍처가 바뀌더라도 혹은 최적화가 필요한 경우 이 공용어로 변경이 가능해요.

profile
iOS 정복중인 Tabber 입니다.

0개의 댓글