├── .gitignore ├── README.md ├── part_1 ├── Dockerfile ├── README.md ├── func_lister.cpp ├── run.sh └── test.c ├── part_2 ├── CfgDfs │ ├── Dockerfile │ ├── main.cpp │ ├── run.sh │ └── test.c ├── CountBasicBlocks │ ├── Dockerfile │ ├── main.cpp │ ├── run.sh │ └── test.c ├── DetectRecursion │ ├── Dockerfile │ ├── main.cpp │ ├── run.sh │ └── test.c ├── GlobalVariables │ ├── Dockerfile │ ├── main.cpp │ ├── run.sh │ └── test.c ├── README.md └── UnusedGlobalVariables │ ├── Dockerfile │ ├── main.cpp │ ├── run.sh │ └── test.c └── part_3 ├── CMakeLists.txt ├── code.txt ├── main └── main.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode 2 | *.so 3 | *.ll 4 | *.dot 5 | *.png 6 | part_4 -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Part1: https://sh4dy.com/2024/06/29/learning_llvm_01/ 2 |
3 | 4 | Part2: https://sh4dy.com/2024/07/06/learning_llvm_02/ 5 |
6 | 7 | Part3: https://sh4dy.com/2024/11/24/learning_llvm_03/ 8 | -------------------------------------------------------------------------------- /part_1/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:22.04 2 | WORKDIR /home/learning_llvm 3 | RUN apt update -y 4 | RUN apt install clang lsb-release wget software-properties-common gnupg -y 5 | RUN wget https://apt.llvm.org/llvm.sh 6 | RUN chmod +x llvm.sh 7 | RUN ./llvm.sh 16 8 | RUN mv /usr/include/llvm-16/llvm /usr/include/llvm 9 | RUN mv /usr/include/llvm-c-16/llvm-c /usr/include/llvm-c 10 | COPY ./ ./ 11 | RUN chmod +x ./run.sh 12 | CMD ["./run.sh"] -------------------------------------------------------------------------------- /part_1/README.md: -------------------------------------------------------------------------------- 1 | ```bash 2 | docker build -t learning_llvm . 3 | docker run --rm -it learning_llvm 4 | ``` 5 | -------------------------------------------------------------------------------- /part_1/func_lister.cpp: -------------------------------------------------------------------------------- 1 | #include "llvm/IR/PassManager.h" 2 | #include "llvm/Passes/PassBuilder.h" 3 | #include "llvm/Passes/PassPlugin.h" 4 | #include "llvm/Support/raw_ostream.h" 5 | using namespace llvm; 6 | 7 | namespace 8 | { 9 | // All LLVM passes must inherit from the CRTP mixin PassInfoMixin 10 | struct FunctionListerPass : public PassInfoMixin 11 | { 12 | // A pass should have a run method 13 | PreservedAnalyses run(Function &F, FunctionAnalysisManager &FAM) 14 | { 15 | // outs() returns a reference to a raw_fd_ostream for standard output. 16 | outs() << F.getName() << '\n'; 17 | return PreservedAnalyses::all(); 18 | } 19 | }; 20 | 21 | } 22 | 23 | PassPluginLibraryInfo getPassPluginInfo() 24 | { 25 | const auto callback = [](PassBuilder &PB) 26 | { 27 | PB.registerPipelineStartEPCallback( 28 | [&](ModulePassManager &MPM, auto) 29 | { 30 | MPM.addPass(createModuleToFunctionPassAdaptor(FunctionListerPass())); 31 | return true; 32 | }); 33 | }; 34 | 35 | return {LLVM_PLUGIN_API_VERSION, "name", "0.0.1", callback}; 36 | }; 37 | 38 | /* When a plugin is loaded by the driver, it will call this entry point to 39 | obtain information about this plugin and about how to register its passes. 40 | */ 41 | extern "C" LLVM_ATTRIBUTE_WEAK PassPluginLibraryInfo llvmGetPassPluginInfo() 42 | { 43 | return getPassPluginInfo(); 44 | } -------------------------------------------------------------------------------- /part_1/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | clang-16 -shared -o func_lister.so func_lister.cpp -fPIC 3 | clang-16 -O1 -fpass-plugin=./func_lister.so test.c -o test -------------------------------------------------------------------------------- /part_1/test.c: -------------------------------------------------------------------------------- 1 | // test.c 2 | void testFunctionOne() 3 | { 4 | } 5 | 6 | void testFunctionTwo() 7 | { 8 | } 9 | 10 | int main() 11 | { 12 | return 0; 13 | } -------------------------------------------------------------------------------- /part_2/CfgDfs/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:22.04 2 | WORKDIR /home/learning_llvm 3 | RUN apt update -y 4 | RUN apt install clang lsb-release wget software-properties-common gnupg -y 5 | RUN wget https://apt.llvm.org/llvm.sh 6 | RUN chmod +x llvm.sh 7 | RUN ./llvm.sh 16 8 | RUN mv /usr/include/llvm-16/llvm /usr/include/llvm 9 | RUN mv /usr/include/llvm-c-16/llvm-c /usr/include/llvm-c 10 | COPY ./ ./ 11 | RUN chmod +x ./run.sh 12 | CMD ["./run.sh"] -------------------------------------------------------------------------------- /part_2/CfgDfs/main.cpp: -------------------------------------------------------------------------------- 1 | #include "llvm/IR/PassManager.h" 2 | #include "llvm/Passes/PassBuilder.h" 3 | #include "llvm/Passes/PassPlugin.h" 4 | #include "llvm/Support/raw_ostream.h" 5 | #include 6 | 7 | using namespace llvm; 8 | 9 | namespace 10 | { 11 | void Dfs(BasicBlock *currentBlock) 12 | { 13 | static std::unordered_map visited; 14 | visited[currentBlock] = true; 15 | currentBlock->print(outs()); 16 | for (BasicBlock *bb : successors(currentBlock)) 17 | { 18 | if (!visited[bb]) 19 | { 20 | Dfs(bb); 21 | } 22 | } 23 | } 24 | struct CfgDfs : public PassInfoMixin 25 | { 26 | PreservedAnalyses run(Module &M, ModuleAnalysisManager &MPM) 27 | { 28 | for (Function &F : M) 29 | { 30 | if (!F.isDeclaration()) 31 | { 32 | outs() << "----------------------------------------------------------------\n"; 33 | outs() << "Running DFS for the function " << F.getName() << "\n"; 34 | BasicBlock &entryBlock = F.getEntryBlock(); 35 | Dfs(&entryBlock); 36 | } 37 | } 38 | return PreservedAnalyses::all(); 39 | } 40 | 41 | static bool isRequired() 42 | { 43 | return true; 44 | } 45 | }; 46 | 47 | } 48 | 49 | PassPluginLibraryInfo getPassPluginInfo() 50 | { 51 | const auto callback = [](PassBuilder &PB) 52 | { 53 | PB.registerPipelineParsingCallback( 54 | [&](StringRef name, ModulePassManager &MPM, ArrayRef) 55 | { 56 | if (name == "run-pass") 57 | { 58 | MPM.addPass(CfgDfs()); 59 | return true; 60 | } 61 | return false; 62 | }); 63 | }; 64 | 65 | return {LLVM_PLUGIN_API_VERSION, "CfgDfs", LLVM_VERSION_STRING, callback}; 66 | }; 67 | 68 | extern "C" LLVM_ATTRIBUTE_WEAK PassPluginLibraryInfo llvmGetPassPluginInfo() 69 | { 70 | return getPassPluginInfo(); 71 | } -------------------------------------------------------------------------------- /part_2/CfgDfs/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | clang-16 -shared -o lib.so main.cpp -fPIC 3 | clang-16 -S -emit-llvm test.c -o test.ll 4 | opt-16 -load-pass-plugin ./lib.so -passes=run-pass -disable-output test.ll -------------------------------------------------------------------------------- /part_2/CfgDfs/test.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int testFunction() 4 | { 5 | for (int i = 0; i < 10; i++) 6 | { 7 | printf("%d\n", i); 8 | } 9 | return 1337; 10 | } 11 | 12 | int main() 13 | { 14 | int x = testFunction(); 15 | if (x > 1000) 16 | { 17 | puts("Yay"); 18 | } 19 | else 20 | { 21 | puts("Ne"); 22 | } 23 | return 0; 24 | } -------------------------------------------------------------------------------- /part_2/CountBasicBlocks/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:22.04 2 | WORKDIR /home/learning_llvm 3 | RUN apt update -y 4 | RUN apt install clang lsb-release wget software-properties-common gnupg -y 5 | RUN wget https://apt.llvm.org/llvm.sh 6 | RUN chmod +x llvm.sh 7 | RUN ./llvm.sh 16 8 | RUN mv /usr/include/llvm-16/llvm /usr/include/llvm 9 | RUN mv /usr/include/llvm-c-16/llvm-c /usr/include/llvm-c 10 | COPY ./ ./ 11 | RUN chmod +x ./run.sh 12 | CMD ["./run.sh"] -------------------------------------------------------------------------------- /part_2/CountBasicBlocks/main.cpp: -------------------------------------------------------------------------------- 1 | #include "llvm/IR/PassManager.h" 2 | #include "llvm/Passes/PassBuilder.h" 3 | #include "llvm/Passes/PassPlugin.h" 4 | #include "llvm/Support/raw_ostream.h" 5 | using namespace llvm; 6 | 7 | namespace 8 | { 9 | struct CountBasicBlocks : public PassInfoMixin 10 | { 11 | PreservedAnalyses run(Module &M, ModuleAnalysisManager &MPM) 12 | { 13 | for (Function &F : M) 14 | { 15 | if (!F.isDeclaration()) 16 | { 17 | int nBlocks = 0; 18 | outs() << "----------------------------------------------------------------------\n"; 19 | outs() << "Counting and printing basic blocks in the function " << F.getName() << "\n"; 20 | for (BasicBlock &BB : F) 21 | { 22 | BB.print(outs()); 23 | outs() << "\n"; 24 | nBlocks++; 25 | } 26 | outs() << "Number of basic blocks: " << nBlocks << "\n"; 27 | } 28 | } 29 | return PreservedAnalyses::all(); 30 | } 31 | 32 | static bool isRequired() 33 | { 34 | return true; 35 | } 36 | }; 37 | 38 | } 39 | 40 | PassPluginLibraryInfo getPassPluginInfo() 41 | { 42 | const auto callback = [](PassBuilder &PB) 43 | { 44 | PB.registerPipelineParsingCallback( 45 | [&](StringRef name, ModulePassManager &MPM, ArrayRef) 46 | { 47 | if (name == "run-pass") 48 | { 49 | MPM.addPass(CountBasicBlocks()); 50 | return true; 51 | } 52 | return false; 53 | }); 54 | }; 55 | 56 | return {LLVM_PLUGIN_API_VERSION, "CountBasicBlocks", LLVM_VERSION_STRING, callback}; 57 | }; 58 | 59 | extern "C" LLVM_ATTRIBUTE_WEAK PassPluginLibraryInfo llvmGetPassPluginInfo() 60 | { 61 | return getPassPluginInfo(); 62 | } -------------------------------------------------------------------------------- /part_2/CountBasicBlocks/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | clang-16 -shared -o lib.so main.cpp -fPIC 3 | clang-16 -S -emit-llvm test.c -o test.ll 4 | opt-16 -load-pass-plugin ./lib.so -passes=run-pass -disable-output test.ll -------------------------------------------------------------------------------- /part_2/CountBasicBlocks/test.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void testFunction(int x) 4 | { 5 | if (x == 1337) 6 | { 7 | puts("nice one"); 8 | } 9 | else 10 | { 11 | puts("sad"); 12 | } 13 | } 14 | 15 | void someFunction() 16 | { 17 | for (int i = 0; i < 10; i++) 18 | { 19 | printf("%d\n", i); 20 | } 21 | } 22 | 23 | void anotherFunction() 24 | { 25 | while (1) 26 | { 27 | puts("abcd"); 28 | } 29 | } 30 | 31 | int main() 32 | { 33 | return 0; 34 | } -------------------------------------------------------------------------------- /part_2/DetectRecursion/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:22.04 2 | WORKDIR /home/learning_llvm 3 | RUN apt update -y 4 | RUN apt install clang lsb-release wget software-properties-common gnupg -y 5 | RUN wget https://apt.llvm.org/llvm.sh 6 | RUN chmod +x llvm.sh 7 | RUN ./llvm.sh 16 8 | RUN mv /usr/include/llvm-16/llvm /usr/include/llvm 9 | RUN mv /usr/include/llvm-c-16/llvm-c /usr/include/llvm-c 10 | COPY ./ ./ 11 | RUN chmod +x ./run.sh 12 | CMD ["./run.sh"] -------------------------------------------------------------------------------- /part_2/DetectRecursion/main.cpp: -------------------------------------------------------------------------------- 1 | #include "llvm/IR/PassManager.h" 2 | #include "llvm/Passes/PassBuilder.h" 3 | #include "llvm/Passes/PassPlugin.h" 4 | #include "llvm/Support/raw_ostream.h" 5 | using namespace llvm; 6 | 7 | namespace 8 | { 9 | struct DetectRecursion : public PassInfoMixin 10 | { 11 | PreservedAnalyses run(Module &M, ModuleAnalysisManager &MPM) 12 | { 13 | for (Function &F : M) 14 | { 15 | bool recursionDetected = false; 16 | 17 | for (BasicBlock &BB : F) 18 | { 19 | for (Instruction &instr : BB) 20 | { 21 | if (instr.getOpcode() == Instruction::Call) 22 | { 23 | CallInst *callInstr = dyn_cast(&instr); 24 | if (callInstr) 25 | { 26 | Function *calledFunction = callInstr->getCalledFunction(); 27 | if (calledFunction && calledFunction->getName() == F.getName()) 28 | { 29 | outs() << "Recursion detected: " << calledFunction->getName() << "\n"; 30 | recursionDetected = true; 31 | break; 32 | } 33 | } 34 | } 35 | } 36 | if (recursionDetected) 37 | break; 38 | } 39 | } 40 | return PreservedAnalyses::all(); 41 | } 42 | 43 | static bool isRequired() 44 | { 45 | return true; 46 | } 47 | }; 48 | 49 | } 50 | 51 | PassPluginLibraryInfo getPassPluginInfo() 52 | { 53 | const auto callback = [](PassBuilder &PB) 54 | { 55 | PB.registerPipelineParsingCallback( 56 | [&](StringRef name, ModulePassManager &MPM, ArrayRef) 57 | { 58 | if (name == "run-pass") 59 | { 60 | MPM.addPass(DetectRecursion()); 61 | return true; 62 | } 63 | return false; 64 | }); 65 | }; 66 | 67 | return {LLVM_PLUGIN_API_VERSION, "DetectRecursion", LLVM_VERSION_STRING, callback}; 68 | }; 69 | 70 | extern "C" LLVM_ATTRIBUTE_WEAK PassPluginLibraryInfo llvmGetPassPluginInfo() 71 | { 72 | return getPassPluginInfo(); 73 | } -------------------------------------------------------------------------------- /part_2/DetectRecursion/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | clang-16 -shared -o lib.so main.cpp -fPIC 3 | clang-16 -S -emit-llvm test.c -o test.ll 4 | opt-16 -load-pass-plugin ./lib.so -passes=run-pass -disable-output test.ll -------------------------------------------------------------------------------- /part_2/DetectRecursion/test.c: -------------------------------------------------------------------------------- 1 | int fib(int n) 2 | { 3 | if (n <= 1) 4 | return n; 5 | return fib(n - 1) + fib(n - 2); 6 | } 7 | 8 | int testFunction() 9 | { 10 | return 1000; 11 | } 12 | 13 | void anotherFunction() 14 | { 15 | while (1) 16 | ; 17 | } 18 | 19 | int main() 20 | { 21 | fib(10); 22 | return 0; 23 | } -------------------------------------------------------------------------------- /part_2/GlobalVariables/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:22.04 2 | WORKDIR /home/learning_llvm 3 | RUN apt update -y 4 | RUN apt install clang lsb-release wget software-properties-common gnupg -y 5 | RUN wget https://apt.llvm.org/llvm.sh 6 | RUN chmod +x llvm.sh 7 | RUN ./llvm.sh 16 8 | RUN mv /usr/include/llvm-16/llvm /usr/include/llvm 9 | RUN mv /usr/include/llvm-c-16/llvm-c /usr/include/llvm-c 10 | COPY ./ ./ 11 | RUN chmod +x ./run.sh 12 | CMD ["./run.sh"] -------------------------------------------------------------------------------- /part_2/GlobalVariables/main.cpp: -------------------------------------------------------------------------------- 1 | #include "llvm/IR/PassManager.h" 2 | #include "llvm/Passes/PassBuilder.h" 3 | #include "llvm/Passes/PassPlugin.h" 4 | #include "llvm/Support/raw_ostream.h" 5 | using namespace llvm; 6 | 7 | namespace 8 | { 9 | struct GlobalVarsPass : public PassInfoMixin 10 | { 11 | PreservedAnalyses run(Module &M, ModuleAnalysisManager &MPM) 12 | { 13 | auto globals = M.globals(); 14 | for(auto itr = globals.begin();itr!=globals.end();itr++){ 15 | StringRef varName = itr->getName(); 16 | Type* ty = itr->getType(); 17 | outs()<<"Variable Name: "<print(outs()); 20 | outs()<<"\n"; 21 | } 22 | return PreservedAnalyses::all(); 23 | } 24 | 25 | static bool isRequired() 26 | { 27 | return true; 28 | } 29 | }; 30 | 31 | } 32 | 33 | PassPluginLibraryInfo getPassPluginInfo() 34 | { 35 | const auto callback = [](PassBuilder &PB) 36 | { 37 | PB.registerPipelineParsingCallback( 38 | [&](StringRef name, ModulePassManager &MPM, ArrayRef) 39 | { 40 | if (name == "run-pass") 41 | { 42 | MPM.addPass(GlobalVarsPass()); 43 | return true; 44 | } 45 | return false; 46 | }); 47 | }; 48 | 49 | return {LLVM_PLUGIN_API_VERSION, "GlobalVarsPass", LLVM_VERSION_STRING, callback}; 50 | }; 51 | 52 | extern "C" LLVM_ATTRIBUTE_WEAK PassPluginLibraryInfo llvmGetPassPluginInfo() 53 | { 54 | return getPassPluginInfo(); 55 | } -------------------------------------------------------------------------------- /part_2/GlobalVariables/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | clang-16 -shared -o lib.so main.cpp -fPIC 3 | clang-16 -S -emit-llvm test.c -o test.ll 4 | opt-16 -load-pass-plugin ./lib.so -passes=run-pass -disable-output test.ll -------------------------------------------------------------------------------- /part_2/GlobalVariables/test.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int varOne = 1337; 4 | char* name = "sh4dy"; 5 | char chr; 6 | float num; 7 | 8 | void testFunction(int x){ 9 | if(x==1337){ 10 | puts("nice one"); 11 | }else{ 12 | puts("sad"); 13 | } 14 | } 15 | 16 | int main(){ 17 | return 0; 18 | } -------------------------------------------------------------------------------- /part_2/README.md: -------------------------------------------------------------------------------- 1 | Blog: https://sh4dy.com/2024/07/06/learning_llvm_02/ 2 | -------------------------------------------------------------------------------- /part_2/UnusedGlobalVariables/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:22.04 2 | WORKDIR /home/learning_llvm 3 | RUN apt update -y 4 | RUN apt install clang lsb-release wget software-properties-common gnupg -y 5 | RUN wget https://apt.llvm.org/llvm.sh 6 | RUN chmod +x llvm.sh 7 | RUN ./llvm.sh 16 8 | RUN mv /usr/include/llvm-16/llvm /usr/include/llvm 9 | RUN mv /usr/include/llvm-c-16/llvm-c /usr/include/llvm-c 10 | COPY ./ ./ 11 | RUN chmod +x ./run.sh 12 | CMD ["./run.sh"] -------------------------------------------------------------------------------- /part_2/UnusedGlobalVariables/main.cpp: -------------------------------------------------------------------------------- 1 | #include "llvm/IR/PassManager.h" 2 | #include "llvm/Passes/PassBuilder.h" 3 | #include "llvm/Passes/PassPlugin.h" 4 | #include "llvm/Support/raw_ostream.h" 5 | using namespace llvm; 6 | 7 | namespace 8 | { 9 | struct UnusedGlobalVarsPass : public PassInfoMixin 10 | { 11 | PreservedAnalyses run(Module &M, ModuleAnalysisManager &MPM) 12 | { 13 | auto globalVars = M.globals(); 14 | for(GlobalVariable &gvar: globalVars){ 15 | if(gvar.use_empty()){ 16 | outs()<<"Unused global variable: "<) 36 | { 37 | if (name == "run-pass") 38 | { 39 | MPM.addPass(UnusedGlobalVarsPass()); 40 | return true; 41 | } 42 | return false; 43 | }); 44 | }; 45 | 46 | return {LLVM_PLUGIN_API_VERSION, "UnusedGlobalVarsPass", LLVM_VERSION_STRING, callback}; 47 | }; 48 | 49 | extern "C" LLVM_ATTRIBUTE_WEAK PassPluginLibraryInfo llvmGetPassPluginInfo() 50 | { 51 | return getPassPluginInfo(); 52 | } -------------------------------------------------------------------------------- /part_2/UnusedGlobalVariables/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | clang-16 -shared -o lib.so main.cpp -fPIC 3 | clang-16 -S -emit-llvm test.c -o test.ll 4 | opt-16 -load-pass-plugin ./lib.so -passes=run-pass -disable-output test.ll -------------------------------------------------------------------------------- /part_2/UnusedGlobalVariables/test.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int varOne = 1337; 4 | char* name = "sh4dy"; 5 | char chr; 6 | float num; 7 | 8 | void testFunction(int x){ 9 | if(x==1337){ 10 | puts("nice one"); 11 | }else{ 12 | puts("sad"); 13 | } 14 | } 15 | 16 | int main(){ 17 | return 0; 18 | } -------------------------------------------------------------------------------- /part_3/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.13) 2 | project(main) 3 | 4 | set(CMAKE_CXX_STANDARD 17) 5 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 6 | 7 | find_program(LLVM_CONFIG_EXECUTABLE llvm-config-16 REQUIRED) 8 | 9 | if(NOT LLVM_CONFIG_EXECUTABLE) 10 | message(FATAL_ERROR "llvm-config not found") 11 | endif() 12 | 13 | execute_process( 14 | COMMAND ${LLVM_CONFIG_EXECUTABLE} --cxxflags 15 | OUTPUT_VARIABLE LLVM_CXXFLAGS 16 | OUTPUT_STRIP_TRAILING_WHITESPACE 17 | ) 18 | execute_process( 19 | COMMAND ${LLVM_CONFIG_EXECUTABLE} --ldflags 20 | OUTPUT_VARIABLE LLVM_LDFLAGS 21 | OUTPUT_STRIP_TRAILING_WHITESPACE 22 | ) 23 | execute_process( 24 | COMMAND ${LLVM_CONFIG_EXECUTABLE} --libs core orcjit native 25 | OUTPUT_VARIABLE LLVM_LIBS 26 | OUTPUT_STRIP_TRAILING_WHITESPACE 27 | ) 28 | 29 | add_executable(${PROJECT_NAME} main.cpp) 30 | 31 | target_compile_options(${PROJECT_NAME} PRIVATE ${LLVM_CXXFLAGS}) 32 | target_link_libraries(${PROJECT_NAME} PRIVATE ${LLVM_LIBS} ${LLVM_LDFLAGS}) 33 | -------------------------------------------------------------------------------- /part_3/code.txt: -------------------------------------------------------------------------------- 1 | add 1,2 2 | sub 10,5 3 | mul 10,20 4 | xor 5,5 5 | add 5,10 6 | xor 10,5 -------------------------------------------------------------------------------- /part_3/main: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xSh4dy/learning_llvm/1695f1bec7aa62ac550f35a100327ede6241e172/part_3/main -------------------------------------------------------------------------------- /part_3/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | struct Instruction { 19 | std::string name; 20 | int64_t val1; 21 | int64_t val2; 22 | 23 | Instruction(const std::string &name, int64_t val1, int64_t val2) 24 | : name(name), val1(val1), val2(val2) {} 25 | }; 26 | 27 | void fatal_error(const std::string &message) { 28 | std::cerr << message << std::endl; 29 | std::exit(1); 30 | } 31 | 32 | std::vector> GetInstructions(const std::string &file_name) { 33 | std::ifstream ifile(file_name); 34 | std::string instruction_line; 35 | std::vector> instructions; 36 | 37 | if (!ifile.is_open()) { 38 | fatal_error("Failed to open file: " + file_name); 39 | } 40 | 41 | while (std::getline(ifile, instruction_line)) { 42 | std::istringstream stream(instruction_line); 43 | std::string instruction_type; 44 | int64_t val1, val2; 45 | char comma; 46 | 47 | if (stream >> instruction_type >> val1 >> comma >> val2) { 48 | instructions.push_back(std::make_unique(instruction_type, val1, val2)); 49 | } else { 50 | fatal_error("Invalid instruction format: " + instruction_line); 51 | } 52 | } 53 | return instructions; 54 | } 55 | 56 | void AddFunctionsToIR(llvm::LLVMContext &ctx, llvm::Module *module, const std::string &function_name) { 57 | auto int64_type = llvm::Type::getInt64Ty(ctx); 58 | std::vector params(2, int64_type); 59 | llvm::IRBuilder<> ir_builder(ctx); 60 | 61 | llvm::FunctionType *function_type = llvm::FunctionType::get(int64_type, params, false); 62 | llvm::Function *func = llvm::Function::Create(function_type, llvm::Function::ExternalLinkage, function_name, module); 63 | 64 | llvm::BasicBlock *basic_block = llvm::BasicBlock::Create(ctx, "entry", func); 65 | ir_builder.SetInsertPoint(basic_block); 66 | 67 | auto args = func->args(); 68 | auto arg_iter = args.begin(); 69 | llvm::Argument *arg1 = arg_iter++; 70 | llvm::Argument *arg2 = arg_iter; 71 | 72 | llvm::Value *result = nullptr; 73 | 74 | if (function_name == "add") { 75 | result = ir_builder.CreateAdd(arg1, arg2); 76 | } else if (function_name == "sub") { 77 | result = ir_builder.CreateSub(arg1, arg2); 78 | } else if (function_name == "mul") { 79 | result = ir_builder.CreateMul(arg1, arg2); 80 | } else if (function_name == "xor") { 81 | result = ir_builder.CreateXor(arg1, arg2); 82 | } else { 83 | fatal_error("Invalid function name: " + function_name); 84 | } 85 | 86 | ir_builder.CreateRet(result); 87 | } 88 | 89 | llvm::orc::ExecutorAddr GetExecutorAddr(llvm::orc::LLJIT &jit, const std::string &function_name) { 90 | auto sym = jit.lookup(function_name).get(); 91 | if (!sym) { 92 | fatal_error("Function not found in JIT: " + function_name); 93 | } 94 | return sym; 95 | } 96 | 97 | int main() { 98 | llvm::LLVMContext ctx; 99 | llvm::InitializeNativeTarget(); 100 | llvm::InitializeNativeTargetAsmPrinter(); 101 | 102 | auto module = std::make_unique("neko_module", ctx); 103 | 104 | AddFunctionsToIR(ctx, module.get(), "add"); 105 | AddFunctionsToIR(ctx, module.get(), "sub"); 106 | AddFunctionsToIR(ctx, module.get(), "mul"); 107 | AddFunctionsToIR(ctx, module.get(), "xor"); 108 | 109 | auto jit_builder = llvm::orc::LLJITBuilder(); 110 | auto jit = jit_builder.create(); 111 | if (!jit) { 112 | fatal_error("Failed to create JIT: " + llvm::toString(jit.takeError())); 113 | } 114 | 115 | if (auto err = jit->get()->addIRModule(llvm::orc::ThreadSafeModule(std::move(module), std::make_unique()))) { 116 | fatal_error("Failed to add IR module for JIT compilation: " + llvm::toString(std::move(err))); 117 | } 118 | 119 | auto instructions = GetInstructions("code.txt"); 120 | std::unordered_map fn_symbols; 121 | 122 | for (const auto &instruction : instructions) { 123 | if (fn_symbols.find(instruction->name) == fn_symbols.end()) { 124 | fn_symbols[instruction->name] = GetExecutorAddr(*jit->get(), instruction->name); 125 | } 126 | 127 | auto *fn = reinterpret_cast(fn_symbols[instruction->name].getValue()); 128 | int64_t value = fn(instruction->val1, instruction->val2); 129 | std::cout << value << std::endl; 130 | } 131 | 132 | return 0; 133 | } 134 | --------------------------------------------------------------------------------