책 소개
소스 파일은 아래 깃허브 페이지에서 내려 받으실 수 있습니다.
(https://github.com/AcornPublishing/llvm-cookbook)
요약
컴파일러에 익숙하지 않은 독자들을 위해 LLVM 활용 예제로 친절하게 컴파일러 내부 동작 구조 및 관련 도구를 설명한다. GCC 컴파일러를 익숙하게 다루는 독자라면 최신 컴파일러를 이해하기 위해 꼭 보길 권장한다. 코드를 한 줄씩 설명해주기 때문에, 컴파일러 코드를 처음 접하는 독자도 이론이 실제로 적용된 코드를 살펴볼 수 있는 좋은 기회가 될 것이다.
이 책에서 다루는 내용
■ LLVM의 모듈식 디자인과 LLVM 도구 소개
■ 언어에 대한 프론트엔드 작성
■ JIT 기능 추가 및 여러 언어의 프론트엔드 사용
■ LLVM 패스 구조 및 LLVM 패스 매니저 이해
■ 분석 패스 개발 및 최적화 패스 변환
■ TOY 언어로 LLVM 백엔드 구현
■ Selection DAG 단계에서 코드 최적화 및 변수 레지스터 할당
이 책의 대상 독자
컴파일러 개념에 익숙하고 LLVM 기반 구조를 이해하고 탐험하기를 원하며, 업무에 활용하고자 하는 컴파일러 엔지니어를 위한 것이다.
또한 컴파일러와 직접 연관은 없지만 수천 라인의 코드를 작성하는 프로그래머를 위한 책이기도 하다. 컴파일러 동작 방식에 대한 지식을 바탕으로 최적화된 코드를 작성해 고성능의 깔끔한 프로그램을 개발할 수 있다.
이 책의 구성
1장, ‘LLVM 설계와 사용법’에서는 LLVM과 Clang를 다운로드해 설치하는 방법과 LLVM 내부 동작과 관련된 여러 예제를 통해 LLVM의 모듈 구조에 대해 설명한다. 또한 프론트엔드에 관련된 다양한 예제를 다룬다.
2장, ‘프론트엔드 작성 단계’에서는 프로그래밍 언어의 프론트엔드 구현 방법을 설명한다. TOY 언어를 위해 하위 단계부터 간단한 컴파일러 프론트엔드를 만들며, 이를 통해 프론트엔드 언어가 LLVM IR로 변환되는 과정을 눈으로 확인해본다.
3장, ‘프론트엔드 확장과 JIT 컴파일 추가’에서는 TOY 언어의 고급 기능을 살펴보고 프론트엔드에 JIT 컴파일 기능을 추가한다. 대부분의 현대 프로그래밍 언어에서 찾을 수 있는 강력한 기능을 구현한다.
4장, ‘최적화 준비’에서는 LLVM IR의 패스 기반 구조를 다룬다. 다양한 최적화 단계를 탐험하고, 각 단계에서 어떤 최적화 기술이 적용되는지 살펴본다. LLVM 패스를 스스로 작성할 수 있게 단계별로 설명한다.
5장, ‘최적화 구현’에서는 흔히 사용되는 LLVM IR에 대한 다양한 최적화 패스 구현 방법을 설명한다. 또한 아직 LLVM 오픈소스 코드에 공개되지 않은 벡터화 기술 관련 내용도 살펴본다.
6장, ‘타겟 독립적 코드 생성기’에서는 타겟 독립적 코드 생성기의 추상적인 기반 구조에 대해 설명한다. LLVM IR이 최종적으로 기계 코드를 생성하기 위해 사용하는 Selection DAG로 어떻게 변환되는지도 살펴본다.
7장, ‘머신 코드 최적화’에서는 Selection DAG가 어떻게 최적화되고 타겟 레지스터가 어떻게 변수에 할당되는지 살펴본다. 또한 Selection DAG의 최적화와 여타 레지스터 할당 기술에 대해서도 설명한다.
8장, ‘LLVM 백엔드 작성’에서는 레지스터와 명령어 집합, 호출 규약, 인코딩, 보조 타겟 기능 등 타겟 아키텍처를 표현하는 방법을 설명한다.
9장, ‘다양한 프로젝트에서의 LLVM 활용’에서는 LLVM IR 기반 구조를 사용할 수 있는 다양한 프로젝트를 살펴본다. LLVM은 단순한 컴파일러가 아니라 컴파일러 기반 구조다. 코드 조각들에 적용할 수 있는 다양한 프로젝트를 살펴보고 유용한 정보를 얻는 것이 9장의 목표다.
본문에 쓰인 컬러 이미지는 여기에서 내려 받으세요.
목차
목차
- 1장. LLVM 설계와 사용법
- 소개
- 모듈 설계 이해
- Clang/LLVM을 이용한 크로스컴파일링
- C 소스코드를 LLVM 어셈블리로 변환
- IR을 LLVM 비트코드로 변환
- LLVM 비트코드를 타겟 머신 어셈블리로 변환
- LLVM 비트코드를 LLVM 어셈블리로 역변환
- LLVM IR 변환
- LLVM 비트코드 링킹
- LLVM 비트코드 실행
- C 프론트엔드 Clang 사용
- GO 프론트엔드 사용
- 드래곤에그 사용
- 2장. 프론트엔드 작성 단계
- 소개
- TOY 언어 정의
- 렉서 구현 방법
- 추상 구문 트리 정의
- 파서 구현
- 단순 표현식의 파싱
- 이항 표현식의 파싱
- 파싱을 위한 드라이버 적용
- TOY 언어 대상 렉서 실행
- 각 추상 구문 트리 클래스를 위한 IR 코드 생성 기법 정의
- 표현식을 위한 IR코드 생성
- 함수를 위한 IR 코드 생성
- IR 코드 최적화 기능 추가
- 3장. 프론트엔드 확장과 JIT 컴파일 추가
- 소개
- 조건문 코드 생성: if/then/else
- 반복문 코드 생성
- 사용자 정의 연산자: 이항 연산자
- 사용자 정의 연산자: 단항 연산자
- JIT 컴파일 추가
- 4장. 최적화 준비
- 소개
- 최적화의 다양한 레벨
- LLVM 패스 구현
- opt 툴로 구현한 패스 실행
- 새로운 패스에서 다른 패스 사용
- 패스 매니저에 패스 등록
- 분석 패스 구현
- 에일리어스 분석 패스 구현
- 다른 분석 패스 사용
- 5장. 최적화 구현
- 소개
- 죽은 코드 제거 패스
- 인라인 변환 패스 작성
- 메모리 최적화 패스 작성
- LLVM IR 병합
- 반복문 변환과 최적화
- 표현식 재배치
- IR 벡터화
- 기타 최적화 패스
- 6장. 타겟 독립적 코드 생성기
- 소개
- LLVM IR의 생명주기
- GraphViz를 이용한 LLVM IR 제어 흐름 그래프 시각화
- TableGen을 이용한 타겟 지정
- 명령어 집합 정의
- 머신 코드 디스크립터 추가
- MachineInstrBuilder 클래스 구현
- MachineBasicBlock 클래스 구현
- MachineFunction 클래스 구현
- 명령어 선택자 작성
- SelectionDAG 교정
- SelectionDAG 최적화
- DAG에서 명령어 선택
- SelectionDAG에서 명령어 스케줄링
- 7장. 머신 코드 최적화
- 소개
- 머신 코드의 공통부분 표현식 제거
- 유효 구간 분석
- 레지스터 할당
- 프롤로그-에필로그 코드 삽입
- 코드 생성
- 꼬리 호출 최적화
- 형제 호출 최적화
- 8장. LLVM 백엔드 작성
- 소개
- 레지스터와 레지스터 집합 정의
- 호출 규약 정의
- 명령어 집합 정의
- 프레임 저수준화 구현
- 명령어 출력
- 명령어 선택
- 명령어 인코딩 추가
- 보조 타겟 지원
- 다중 명령어로 저수준화
- 타겟 등록
- 9장. 다양한 프로젝트에서의 LLVM 활용
- 소개
- LLVM의 예외 처리
- Sanitizer 사용 방법
- LLVM으로 가비지 컬렉터 작성
- LLVM IR을 자바스크립트로 변환
- Clang 정적 분석기의 사용
- bugpoint 사용
- LLDB 사용