LLVM을 공부하며 CPP compiler만들기(1)

2ho·2025년 3월 25일

LLVM

목록 보기
1/2
post-thumbnail

LLVM에 공부를 시작하기 전에..

작년에 LLVM에 대하여 맛보기를 한적이 있었다. 요번에는 LLVM을 이용하여 프로젝트를 하나 진행해 볼까 한다.

개발 시작

🌎hello World!

우선 처음으로 cpp코드를 LLVM IR로 변환을 해볼것이다.

여기 Hello, World!를 출력하는 cpp코드가 있다.

% clang++ -S -emit-llvm cpp.cpp -o cpp.ll  

터미널에서 현재 파일 위치로 이동한 후 위 명령어를 실행하면
cpp.cpp 파일이 변환되어 cpp.ll이라는 파일이 생긴다.

굿
다음으로 cpp.ll파일을 열어볼까?

🧐cpp.ll


엄청 코드가 긴 것을 확인할 수 있다.
🧐왜 코드가 길어졌을까?
사실 이것에 대한 정답은 cpp.cpp파일에 있다.
바로

using namespace std;

가 문제였던 것이다.
복잡한 C++ 표준 라이브러리가 포함이 되어있어서 길었던 것이였다...

✍️cpp.cpp수정


c 스타일로 코드를 작성하였다.

무려 28줄까지 줄어들었다..
500줄이 넘던 파일이...
수정을 완료하였으니 다음단계로 넘어가자

😎최적화

이제 cpp.ll 파일을 최적화 할 것이다.

% opt -O2 cpp.ll -o  cpp-clean.ll

이 코드를 입력하면 cpp-clean.ll이라는 파일이 생성된다.

🤔그런데 opt가 뭐지?

😲opt는 LLVM 자체 최적화 툴이다

이제 최적화를 완료 하였으니 실행을 시켜볼까?

👨‍💻코드 실행

실행을 하려면 JIT컴파일러를 이용해야한다.

우선 파일을 실행 가능한 바이너리 파일로 만들자.

% clang++ -o cpp-clean cpp-clean.ll


cpp-clean.ll위에 cpp-clean이 나왔다!
이제 저 파일을 실행하면 된다.

% ./cpp-clean


실행이 되는 것을 확인하였다.

이제 직접 IR을 만들고 실행해보자.

💻LLVM CPP API

LLVM은 CPP API가 존재하기 때문에 직접 IR을 만들고 실행이 가능하다.
IR생성 코드를 작성해보자.

include


include를 통해 llvm/IR을 불러온다.

⚠️만약 이부분에서

에러가 난다면
c_cpp_properties.json파일에 들어간다

"includePath": [
                "${workspaceFolder}/**"
            ],

부분에

"includePath": [
                "${workspaceFolder}/**",
                "/opt/homebrew/opt/llvm/include"
            ],

"/opt/homebrew/opt/llvm/include"를 추가하시면

수정이 되는걸 확인하실수 있습니다.

main


밑에는 코드에 대하여 주석입니다.

LLVMContext Context; // LLVM Context 생성
Module *ModuleOb = new Module("MyModule", Context); // LLVM 모듈 생성
IRBuilder<> Builder(Context); // IR생성을 위한 빌더 객체 생성

// Main함수 부분타입 정의 - 타입 int32, 매개변수 false
FunctionType *funcType = FunctionType::get(Type::getInt32Ty(context), false);
Function *mainFunc = Function::Create(funcType, Function::ExternalLinkage, "main", ModuleOb); // main 함수 생성 (외부 호출 가능)

BasicBlock *entry = BasicBlock::Create(Context, "entry", mainFunc); // main함수 entry 생성 - 코드가 실행될 시작부분
Builder.SetInsertPoint(entry); // 빌더 insert위치 entry로 설정

Value *returnValue = ConstantInt::get(Type::getInt32Ty(Context), 0); // 정수 0 생성 - int32
Builder.CreateRet(returnValue); // return 생성

ModuleOb->print(outs(), nullptr); // 만들어진 IR을 출력
delete ModuleOb; // 메모리 누수 방지!
return 0 // 종료

✅이제 코드를 완성하였으니 실행을 해봅시다.

컴파일 && 실행

이제 실행을 위해 LLVM라이브러리 링크를하자
cmd창에

clang++ generate_ir.cpp -o generate_ir `llvm-config --cxxflags --ldflags --libs core` -std=c++17

를 입력하면

정상작동 하는 경우

generate_ir파일이 생성된 것을 확인할 수 있다.

👍생성되었다면 컴파일은 완료된 것이다!

이제 실행을 해보자

./generate_ir

커맨드에 입력하면 된다.


🎉LLVM IR을 생성하는 프로그램을 완성하였다!🎉

다음시간에는 IR을 파일로 생성하여 저장하고, 실행하는 부분을 공부해볼 것이다.

profile
!developer

0개의 댓글