├── .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 |
--------------------------------------------------------------------------------