작년에 LLVM에 대하여 맛보기를 한적이 있었다. 요번에는 LLVM을 이용하여 프로젝트를 하나 진행해 볼까 한다.
우선 처음으로 cpp코드를 LLVM IR로 변환을 해볼것이다.

여기 Hello, World!를 출력하는 cpp코드가 있다.
% clang++ -S -emit-llvm cpp.cpp -o cpp.ll
터미널에서 현재 파일 위치로 이동한 후 위 명령어를 실행하면
cpp.cpp 파일이 변환되어 cpp.ll이라는 파일이 생긴다.

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

엄청 코드가 긴 것을 확인할 수 있다.
🧐왜 코드가 길어졌을까?
사실 이것에 대한 정답은 cpp.cpp파일에 있다.
바로
using namespace std;
가 문제였던 것이다.
복잡한 C++ 표준 라이브러리가 포함이 되어있어서 길었던 것이였다...

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가 존재하기 때문에 직접 IR을 만들고 실행이 가능하다.
IR생성 코드를 작성해보자.

include를 통해 llvm/IR을 불러온다.
⚠️만약 이부분에서
에러가 난다면
c_cpp_properties.json파일에 들어간다"includePath": [ "${workspaceFolder}/**" ],부분에
"includePath": [ "${workspaceFolder}/**", "/opt/homebrew/opt/llvm/include" ],"/opt/homebrew/opt/llvm/include"를 추가하시면
수정이 되는걸 확인하실수 있습니다.

밑에는 코드에 대하여 주석입니다.
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을 파일로 생성하여 저장하고, 실행하는 부분을 공부해볼 것이다.