├── .gitignore ├── llvm └── lib │ └── Transforms │ ├── MyPass │ ├── Tests │ │ └── Test.ll │ ├── CMakeLists.txt │ ├── README.md │ └── MyPass.cpp │ ├── SimpleLoopPass │ ├── CMakeLists.txt │ ├── Tests │ │ ├── SimpleLoopTest.c.txt │ │ ├── NestedLoopTest.c.txt │ │ ├── SimpleLoopTest.2.ll │ │ ├── SimpleLoopTest.ll │ │ ├── NestedLoopTest.ll │ │ └── NestedLoopTest.2.ll │ ├── SimpleLoopPass.cpp │ └── README.md │ ├── SimpleModulePass │ ├── CMakeLists.txt │ ├── Test.c.txt │ ├── README.md │ ├── SimpleModulePass.cpp │ └── Test.ll │ ├── SimpleFunctionPass │ ├── CMakeLists.txt │ ├── Test.c.txt │ ├── Test.ll │ ├── README.md │ └── SimpleFunctionPass.cpp │ ├── ConstantAdditionCombiner │ ├── CMakeLists.txt │ ├── Test.ll │ ├── README.md │ └── ConstantAdditionCombiner.cpp │ ├── RunTimeFunctionCallCounter │ ├── CMakeLists.txt │ ├── Tests │ │ ├── Test.c.txt │ │ ├── Test.ll │ │ └── TestWithCounter.ll │ ├── README.md │ └── RunTimeFunctionCallCounter.cpp │ ├── CompileTimeFunctionCallCounter │ ├── CMakeLists.txt │ ├── Tests │ │ ├── Test.c.txt │ │ └── Test.ll │ ├── README.md │ └── CompileTimeFunctionCallCounter.cpp │ └── CMakeLists.txt ├── LICENSE ├── README.md └── .clang-format /.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | build-xcode 3 | -------------------------------------------------------------------------------- /llvm/lib/Transforms/MyPass/Tests/Test.ll: -------------------------------------------------------------------------------- 1 | define i32 @foo() { 2 | %a = add i32 2, 3 3 | ret i32 %a 4 | } 5 | 6 | define void @bar() { 7 | ret void 8 | } 9 | -------------------------------------------------------------------------------- /llvm/lib/Transforms/MyPass/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # CMakeLists.txt 2 | 3 | add_llvm_library(MyPass MODULE BUILDTREE_ONLY 4 | MyPass.cpp 5 | 6 | PLUGIN_TOOL 7 | opt 8 | ) 9 | -------------------------------------------------------------------------------- /llvm/lib/Transforms/SimpleLoopPass/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # CMakeLists.txt 2 | 3 | add_llvm_library(SimpleLoopPass MODULE BUILDTREE_ONLY 4 | SimpleLoopPass.cpp 5 | 6 | PLUGIN_TOOL 7 | opt 8 | ) 9 | -------------------------------------------------------------------------------- /llvm/lib/Transforms/SimpleModulePass/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # CMakeLists.txt 2 | 3 | add_llvm_library(SimpleModulePass MODULE BUILDTREE_ONLY 4 | SimpleModulePass.cpp 5 | 6 | PLUGIN_TOOL 7 | opt 8 | ) 9 | -------------------------------------------------------------------------------- /llvm/lib/Transforms/SimpleFunctionPass/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # CMakeLists.txt 2 | 3 | add_llvm_library(SimpleFunctionPass MODULE BUILDTREE_ONLY 4 | SimpleFunctionPass.cpp 5 | 6 | PLUGIN_TOOL 7 | opt 8 | ) 9 | -------------------------------------------------------------------------------- /llvm/lib/Transforms/ConstantAdditionCombiner/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # CMakeLists.txt 2 | 3 | add_llvm_library(ConstantAdditionCombiner MODULE BUILDTREE_ONLY 4 | ConstantAdditionCombiner.cpp 5 | 6 | PLUGIN_TOOL 7 | opt 8 | ) 9 | -------------------------------------------------------------------------------- /llvm/lib/Transforms/RunTimeFunctionCallCounter/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # CMakeLists.txt 2 | 3 | add_llvm_library(RunTimeFunctionCallCounter MODULE BUILDTREE_ONLY 4 | RunTimeFunctionCallCounter.cpp 5 | 6 | PLUGIN_TOOL 7 | opt 8 | ) 9 | -------------------------------------------------------------------------------- /llvm/lib/Transforms/CompileTimeFunctionCallCounter/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # CMakeLists.txt 2 | 3 | add_llvm_library(CompileTimeFunctionCallCounter MODULE BUILDTREE_ONLY 4 | CompileTimeFunctionCallCounter.cpp 5 | 6 | PLUGIN_TOOL 7 | opt 8 | ) 9 | -------------------------------------------------------------------------------- /llvm/lib/Transforms/ConstantAdditionCombiner/Test.ll: -------------------------------------------------------------------------------- 1 | ; ModuleID = 'Test.ll' 2 | source_filename = "Test.ll" 3 | 4 | define i32 @Test(i32 %a, i32 %b) { 5 | %c = add i32 1, 2 6 | %d = add i32 5, 6 7 | %e = add i32 %a, %b 8 | %f = add i32 %c, %d 9 | %g = add i32 %e, %f 10 | ret i32 %g 11 | } 12 | -------------------------------------------------------------------------------- /llvm/lib/Transforms/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | ... 2 | add_subdirectory(MyPass) 3 | add_subdirectory(SimpleModulePass) 4 | add_subdirectory(SimpleFunctionPass) 5 | add_subdirectory(SimpleLoopPass) 6 | add_subdirectory(CompileTimeFunctionCallCounter) 7 | add_subdirectory(RunTimeFunctionCallCounter) 8 | add_subdirectory(ConstantAdditionCombiner) 9 | -------------------------------------------------------------------------------- /llvm/lib/Transforms/SimpleLoopPass/Tests/SimpleLoopTest.c.txt: -------------------------------------------------------------------------------- 1 | // SimpleLoopTest.c 2 | 3 | int array[1024]; 4 | 5 | void SimpleLoopTest() 6 | { 7 | for (int i = 0; i < 100; i++) 8 | { 9 | array[i] = i; 10 | } 11 | 12 | for (int i = 101; i < 200; i++) 13 | { 14 | array[i] = array[i] * i; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /llvm/lib/Transforms/SimpleLoopPass/Tests/NestedLoopTest.c.txt: -------------------------------------------------------------------------------- 1 | // NestedLoopTest.c 2 | 3 | int a[1024][1024]; 4 | int b[1024][1024]; 5 | 6 | void NestedLoopTest() 7 | { 8 | for (int i = 0; i < 100; i++) 9 | { 10 | for (int j = 0; j < 100; j++) 11 | { 12 | a[i][j] = ((i - 3) * (i + 3)) % i; 13 | } 14 | } 15 | } -------------------------------------------------------------------------------- /llvm/lib/Transforms/RunTimeFunctionCallCounter/Tests/Test.c.txt: -------------------------------------------------------------------------------- 1 | // Test.c 2 | 3 | void Foo() 4 | { 5 | } 6 | 7 | void Bar() 8 | { 9 | Foo(); 10 | } 11 | 12 | void Fez() 13 | { 14 | Bar(); 15 | } 16 | 17 | int main() 18 | { 19 | Foo(); 20 | Bar(); 21 | Fez(); 22 | 23 | for (int i = 0; i < 5; i++) 24 | { 25 | Foo(); 26 | } 27 | 28 | return 0; 29 | } 30 | -------------------------------------------------------------------------------- /llvm/lib/Transforms/CompileTimeFunctionCallCounter/Tests/Test.c.txt: -------------------------------------------------------------------------------- 1 | // Test.c 2 | 3 | void Foo() 4 | { 5 | } 6 | 7 | void Bar() 8 | { 9 | Foo(); 10 | } 11 | 12 | void Fez() 13 | { 14 | Bar(); 15 | } 16 | 17 | int main() 18 | { 19 | Foo(); 20 | Bar(); 21 | Fez(); 22 | 23 | for (int i = 0; i < 5; i++) 24 | { 25 | Foo(); 26 | } 27 | 28 | return 0; 29 | } 30 | -------------------------------------------------------------------------------- /llvm/lib/Transforms/SimpleFunctionPass/Test.c.txt: -------------------------------------------------------------------------------- 1 | // Test.c 2 | 3 | int Foo(int a) 4 | { 5 | int b; 6 | 7 | if (a > 33) 8 | { 9 | b = 66; 10 | } 11 | else 12 | { 13 | b = 77; 14 | } 15 | 16 | return b; 17 | } 18 | 19 | int Bar(int a, int b) 20 | { 21 | return a + b; 22 | } 23 | 24 | int Bead(int a, int b) 25 | { 26 | return a * b; 27 | } 28 | -------------------------------------------------------------------------------- /llvm/lib/Transforms/SimpleModulePass/Test.c.txt: -------------------------------------------------------------------------------- 1 | // Test.c 2 | 3 | int globalInt = 0; 4 | short globalShort = 1; 5 | const char* globalString = "This is a global string"; 6 | 7 | int Foo(int a) 8 | { 9 | int b; 10 | 11 | if (a > 33) 12 | { 13 | b = 66; 14 | } 15 | else 16 | { 17 | b = 77; 18 | } 19 | 20 | return b; 21 | } 22 | 23 | int Bar(int a, int b) 24 | { 25 | return a + b; 26 | } 27 | 28 | int Bead(int a, int b) 29 | { 30 | return a * b; 31 | } 32 | -------------------------------------------------------------------------------- /llvm/lib/Transforms/MyPass/README.md: -------------------------------------------------------------------------------- 1 | # Write an LLVM Pass With New PassManager 2 | 3 | ## My Pass 4 | 5 | 1. Create a directory `llvm-project/llvm/lib/Transforms/MyPass` 6 | 2. Add `CMakeLists.txt` file `llvm-project/llvm/lib/Transforms/MyPass` 7 | 3. Add source file `MyPass.cpp` into `llvm-project/llvm/lib/Transforms/MyPass` 8 | 9 | 4. Add the following code into `llvm-project/llvm/lib/Transforms/CMakeLists.txt`: 10 | 11 | ```cmake 12 | add_subdirectory(MyPass) 13 | ``` 14 | 15 | 5. Build 16 | 17 | ```bash 18 | cd /path/to/llvm-project 19 | mkdir -p build 20 | cd build 21 | 22 | cmake -G Ninja -DLLVM_ENABLE_PROJECTS=clang ../llvm 23 | 24 | ninja 25 | ``` 26 | 27 | 6. Run 28 | 29 | Commands: 30 | 31 | ```bash 32 | ./bin/opt -load-pass-plugin=lib/MyPass.dylib -passes="my-pass" -disable-output ../llvm/lib/Transforms/MyPass/Tests/Test.ll 33 | ``` 34 | 35 | Outout: 36 | 37 | ``` 38 | MyPass in function: foo 39 | MyPass in function: bar 40 | ``` 41 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Zhanglin 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # LLVM Pass Examples 2 | 3 | Some simple LLVM Pass examples: 4 | 5 | ```c 6 | llvm-project/llvm 7 | ├── ... 8 | ├── lib 9 | │ └── Transforms 10 | │ │── 1.MyPass 11 | │ │── 2.SimpleModulePass 12 | │ └── 3.SimpleFunctionPass 13 | │ └── 4.SimpleLoopPass 14 | │ └── 5.CompileTimeFunctionCallCounter 15 | │ └── 6.RunTimeFunctionCallCounter 16 | │ └── 7.ConstantAdditionCombiner 17 | │── ... 18 | ``` 19 | 20 | 具体编译及使用步骤,请参考: 21 | 22 | 1. [LLVM系列第十八章:写一个简单的IR处理流程Pass](https://blog.csdn.net/Zhanglin_Wu/article/details/125383746) 23 | 2. [LLVM系列第十九章:写一个简单的Module Pass](https://blog.csdn.net/Zhanglin_Wu/article/details/125466341) 24 | 3. [LLVM系列第二十章:写一个简单的Function Pass](https://blog.csdn.net/Zhanglin_Wu/article/details/125438188) 25 | 4. [LLVM系列第二十一章:写一个简单的Loop Pass](https://blog.csdn.net/Zhanglin_Wu/article/details/125494996) 26 | 5. [LLVM系列第二十二章:写一个简单的编译时函数调用统计器(Pass)](https://blog.csdn.net/Zhanglin_Wu/article/details/125670416) 27 | 6. [LLVM系列第二十三章:写一个简单的运行时函数调用统计器(Pass)](https://blog.csdn.net/Zhanglin_Wu/article/details/125696699) 28 | 7. [LLVM系列第二十九章:写一个简单的常量加法“消除”工具(Pass)](https://blog.csdn.net/Zhanglin_Wu/article/details/126114008) 29 | -------------------------------------------------------------------------------- /llvm/lib/Transforms/SimpleFunctionPass/Test.ll: -------------------------------------------------------------------------------- 1 | ; ModuleID = 'Test.c' 2 | source_filename = "Test.c" 3 | 4 | define i32 @Foo(i32 %a) { 5 | entry: 6 | %a.addr = alloca i32, align 4 7 | %b = alloca i32, align 4 8 | store i32 %a, i32* %a.addr, align 4 9 | %0 = load i32, i32* %a.addr, align 4 10 | %cmp = icmp sgt i32 %0, 33 11 | br i1 %cmp, label %if.then, label %if.else 12 | 13 | if.then: ; preds = %entry 14 | store i32 66, i32* %b, align 4 15 | br label %if.end 16 | 17 | if.else: ; preds = %entry 18 | store i32 77, i32* %b, align 4 19 | br label %if.end 20 | 21 | if.end: ; preds = %if.else, %if.then 22 | %1 = load i32, i32* %b, align 4 23 | ret i32 %1 24 | } 25 | 26 | define i32 @Bar(i32 %a, i32 %b) { 27 | entry: 28 | %a.addr = alloca i32, align 4 29 | %b.addr = alloca i32, align 4 30 | store i32 %a, i32* %a.addr, align 4 31 | store i32 %b, i32* %b.addr, align 4 32 | %0 = load i32, i32* %a.addr, align 4 33 | %1 = load i32, i32* %b.addr, align 4 34 | %add = add nsw i32 %0, %1 35 | ret i32 %add 36 | } 37 | 38 | define i32 @Bead(i32 %a, i32 %b) { 39 | entry: 40 | %a.addr = alloca i32, align 4 41 | %b.addr = alloca i32, align 4 42 | store i32 %a, i32* %a.addr, align 4 43 | store i32 %b, i32* %b.addr, align 4 44 | %0 = load i32, i32* %a.addr, align 4 45 | %1 = load i32, i32* %b.addr, align 4 46 | %mul = mul nsw i32 %0, %1 47 | ret i32 %mul 48 | } 49 | -------------------------------------------------------------------------------- /llvm/lib/Transforms/ConstantAdditionCombiner/README.md: -------------------------------------------------------------------------------- 1 | # A Simple LLVM Transform Pass (With New PassManager) 2 | 3 | ### Simple Module Pass 4 | 5 | 1. Create a directory `llvm-project/llvm/lib/Transforms/ConstantAdditionCombiner` 6 | 2. Add `CMakeLists.txt` file `llvm-project/llvm/lib/Transforms/ConstantAdditionCombiner` 7 | 3. Add source file `ConstantAdditionCombiner.cpp` into `llvm-project/llvm/lib/Transforms/ConstantAdditionCombiner` 8 | 9 | 4. Add the following code into `llvm-project/llvm/lib/Transforms/CMakeLists.txt`: 10 | 11 | ```cmake 12 | add_subdirectory(ConstantAdditionCombiner) 13 | ``` 14 | 15 | ### Build 16 | 17 | ```bash 18 | cd /path/to/llvm-project/llvm 19 | mkdir -p build 20 | cd build 21 | 22 | cmake -G Ninja -DCMAKE_BUILD_TYPE=Debug .. 23 | 24 | ninja 25 | ``` 26 | 27 | Output: 28 | 29 | ``` 30 | [2/2] Linking CXX shared module lib/ConstantAdditionCombiner.dylib 31 | ``` 32 | 33 | ### Run 34 | 35 | #### Find the constant addition instructions 36 | 37 | ```bash 38 | ./bin/opt -load-pass-plugin=lib/ConstantAdditionCombiner.dylib -passes="constant-addition-printer" -disable-output ../lib/Transforms/ConstantAdditionCombiner/Test.ll 39 | ``` 40 | 41 | Output: 42 | 43 | ``` 44 | Function: Test 45 | %c = add i32 1, 2 46 | %d = add i32 5, 6 47 | ``` 48 | 49 | #### Combome the constant addition instructions 50 | 51 | ``` 52 | ./bin/opt -load-pass-plugin=lib/ConstantAdditionCombiner.dylib -passes="constant-addition-combiner" -S ../lib/Transforms/ConstantAdditionCombiner/Test.ll 53 | ``` 54 | 55 | Output: 56 | 57 | ``` 58 | ; ModuleID = '../lib/Transforms/ConstantAdditionCombiner/Test.ll' 59 | source_filename = "Test.ll" 60 | 61 | define i32 @Test(i32 %a, i32 %b) { 62 | %e = add i32 %a, %b 63 | %f = add i32 3, 11 64 | %g = add i32 %e, %f 65 | ret i32 %g 66 | } 67 | ``` 68 | -------------------------------------------------------------------------------- /llvm/lib/Transforms/SimpleModulePass/README.md: -------------------------------------------------------------------------------- 1 | # A Simple LLVM Module Pass (With New PassManager) 2 | 3 | ### Simple Module Pass 4 | 5 | 1. Create a directory `llvm-project/llvm/lib/Transforms/SimpleModulePass` 6 | 2. Add `CMakeLists.txt` file `llvm-project/llvm/lib/Transforms/SimpleModulePass` 7 | 3. Add source file `SimpleModulePass.cpp` into `llvm-project/llvm/lib/Transforms/SimpleModulePass` 8 | 9 | 4. Add the following code into `llvm-project/llvm/lib/Transforms/CMakeLists.txt`: 10 | 11 | ```cmake 12 | add_subdirectory(SimpleModulePass) 13 | ``` 14 | 15 | ### Build 16 | 17 | ```bash 18 | cd /path/to/llvm-project 19 | mkdir -p build 20 | cd build 21 | 22 | cmake -G Ninja -DLLVM_ENABLE_PROJECTS=clang ../llvm 23 | 24 | ninja 25 | ``` 26 | 27 | Output: 28 | 29 | ``` 30 | [4/4] Linking CXX shared module lib/SimpleModulePass.dylib 31 | ``` 32 | 33 | ### Run 34 | 35 | ```bash 36 | mv ../llvm/lib/Transforms/SimpleModulePass/Test.c.txt ../llvm/lib/Transforms/SimpleModulePass/Test.c 37 | clang -S -emit-llvm ../llvm/lib/Transforms/SimpleModulePass/Test.c -o ../llvm/lib/Transforms/SimpleModulePass/Test.ll 38 | 39 | ./bin/opt -load-pass-plugin=lib/SimpleModulePass.dylib -passes="simple-module-pass" -disable-output ../llvm/lib/Transforms/SimpleModulePass/Test.ll 40 | ``` 41 | 42 | Output: 43 | 44 | ``` 45 | Module: ../llvm/lib/Transforms/SimpleModulePass/Test.ll 46 | ID: ../llvm/lib/Transforms/SimpleModulePass/Test.ll 47 | Source File Name: ../llvm/lib/Transforms/SimpleModulePass/Test.c 48 | Instruction Count: 28 49 | 50 | Gloabl Variable Count: 4 51 | Global Variable: globalInt 52 | Global Variable: globalShort 53 | Global Variable: .str 54 | Global Variable: globalString 55 | 56 | Function Count: 3 57 | Function: Foo 58 | Function: Bar 59 | Function: Bead 60 | ``` 61 | -------------------------------------------------------------------------------- /llvm/lib/Transforms/MyPass/MyPass.cpp: -------------------------------------------------------------------------------- 1 | // MyPass.cpp 2 | 3 | #include "llvm/IR/PassManager.h" 4 | #include "llvm/Passes/PassBuilder.h" 5 | #include "llvm/Passes/PassPlugin.h" 6 | #include "llvm/Support/raw_ostream.h" 7 | 8 | // Only needed for printing 9 | #include 10 | 11 | using namespace llvm; 12 | 13 | namespace 14 | { 15 | class MyPass : public PassInfoMixin 16 | { 17 | public: 18 | 19 | // The first argument of the run() function defines on what level 20 | // of granularity your pass will run (e.g. Module, Function). 21 | // The second argument is the corresponding AnalysisManager 22 | // (e.g ModuleAnalysisManager, FunctionAnalysisManager) 23 | PreservedAnalyses run(Function& function, FunctionAnalysisManager& analysisManager) 24 | { 25 | std::cout << "MyPass in function: " << function.getName().str() << std::endl; 26 | 27 | // Here goes what you want to do with a pass 28 | 29 | // Assuming we did not change anything of the IR code 30 | return PreservedAnalyses::all(); 31 | } 32 | }; 33 | } 34 | 35 | // This part is the new way of registering your pass 36 | extern "C" PassPluginLibraryInfo LLVM_ATTRIBUTE_WEAK llvmGetPassPluginInfo() 37 | { 38 | return 39 | { 40 | LLVM_PLUGIN_API_VERSION, 41 | "MyPass", 42 | "v0.1", 43 | [](PassBuilder &passBuilder) { 44 | passBuilder.registerPipelineParsingCallback( 45 | [](StringRef name, FunctionPassManager &passManager, ArrayRef) { 46 | if(name == "my-pass") 47 | { 48 | passManager.addPass(MyPass()); 49 | return true; 50 | } 51 | 52 | return false; 53 | } 54 | ); 55 | } 56 | }; 57 | } 58 | -------------------------------------------------------------------------------- /llvm/lib/Transforms/CompileTimeFunctionCallCounter/README.md: -------------------------------------------------------------------------------- 1 | # LLVM Pass: Compile Time Function Call Counter (With New PassManager) 2 | 3 | ### Compile Time Function Call Counter 4 | 5 | 1. Create a directory `llvm-project/llvm/lib/Transforms/CompileTimeFunctionCallCounter` 6 | 2. Add `CMakeLists.txt` file `llvm-project/llvm/lib/Transforms/CompileTimeFunctionCallCounter` 7 | 3. Add source file `CompileTimeFunctionCallCounter.cpp` into `llvm-project/llvm/lib/Transforms/CompileTimeFunctionCallCounter` 8 | 9 | 4. Add the following code into `llvm-project/llvm/lib/Transforms/CMakeLists.txt`: 10 | 11 | ```cmake 12 | add_subdirectory(CompileTimeFunctionCallCounter) 13 | ``` 14 | 15 | ### Build 16 | 17 | ```bash 18 | cd /path/to/llvm-project 19 | mkdir -p build 20 | cd build 21 | 22 | # Format the source code 23 | clang-format -i ../llvm/lib/Transforms/CompileTimeFunctionCallCounter/*.cpp ../llvm/lib/Transforms/CompileTimeFunctionCallCounter/**/*.c 24 | 25 | # Set up C++ standard library and header path 26 | export SDKROOT=$(xcrun --sdk macosx --show-sdk-path) 27 | 28 | # Generate projects 29 | cmake -G Ninja -DLLVM_ENABLE_PROJECTS=clang ../llvm 30 | 31 | # Compile 32 | ninja 33 | ``` 34 | 35 | Output: 36 | 37 | ``` 38 | [4/4] Linking CXX shared module lib/CompileTimeFunctionCallCounter.dylib 39 | ``` 40 | 41 | ### Run 42 | 43 | Commands: 44 | 45 | ```bash 46 | mv ../llvm/lib/Transforms/CompileTimeFunctionCallCounter/Tests/Test.c.txt ../llvm/lib/Transforms/CompileTimeFunctionCallCounter/Tests/Test.c 47 | 48 | clang -S -emit-llvm ../llvm/lib/Transforms/CompileTimeFunctionCallCounter/Tests/Test.c -o ../llvm/lib/Transforms/CompileTimeFunctionCallCounter/Tests/Test.ll 49 | 50 | ./bin/opt -load-pass-plugin=lib/CompileTimeFunctionCallCounter.dylib -passes="compile-time-function-call-counter" -disable-output ../llvm/lib/Transforms/CompileTimeFunctionCallCounter/Tests/Test.ll 51 | ``` 52 | 53 | Output: 54 | 55 | ``` 56 | Function: Foo, called 3 times 57 | Function: Bar, called 2 times 58 | Function: Fez, called 1 times 59 | ``` 60 | -------------------------------------------------------------------------------- /llvm/lib/Transforms/SimpleFunctionPass/README.md: -------------------------------------------------------------------------------- 1 | # A Simple LLVM Function Pass (With New PassManager) 2 | 3 | ### Simple Function Pass 4 | 5 | 1. Create a directory `llvm-project/llvm/lib/Transforms/SimpleFunctionPass` 6 | 2. Add `CMakeLists.txt` file `llvm-project/llvm/lib/Transforms/SimpleFunctionPass` 7 | 3. Add source file `SimpleFunctionPass.cpp` into `llvm-project/llvm/lib/Transforms/SimpleFunctionPass` 8 | 9 | 4. Add the following code into `llvm-project/llvm/lib/Transforms/CMakeLists.txt`: 10 | 11 | ```cmake 12 | add_subdirectory(SimpleFunctionPass) 13 | ``` 14 | 15 | ### Build 16 | 17 | ```bash 18 | cd /path/to/llvm-project 19 | mkdir -p build 20 | cd build 21 | 22 | cmake -G Ninja -DLLVM_ENABLE_PROJECTS=clang ../llvm 23 | 24 | ninja 25 | ``` 26 | 27 | ### Run 28 | 29 | ```bash 30 | mv ../llvm/lib/Transforms/SimpleFunctionPass/Test.c.txt ../llvm/lib/Transforms/SimpleFunctionPass/Test.c 31 | clang -S -emit-llvm ../llvm/lib/Transforms/SimpleFunctionPass/Test.c -o ../llvm/lib/Transforms/SimpleFunctionPass/Test.ll 32 | 33 | ./bin/opt -load-pass-plugin=lib/SimpleFunctionPass.dylib -passes="simple-function-pass" -disable-output ../llvm/lib/Transforms/SimpleFunctionPass/Test.ll 34 | ``` 35 | 36 | Output: 37 | 38 | ```bash 39 | Function: Foo 40 | Instruction Count: 12 41 | 42 | Basic Block Count: 4 43 | BasicBlock: entry 44 | BasicBlock: if.then 45 | BasicBlock: if.else 46 | BasicBlock: if.end 47 | 48 | Argument Count: 1 49 | Argument: a 50 | 51 | Function Type: 52 | i32 (i32) 53 | 54 | Function: Bar 55 | Instruction Count: 8 56 | 57 | Basic Block Count: 1 58 | BasicBlock: entry 59 | 60 | Argument Count: 2 61 | Argument: a 62 | Argument: b 63 | 64 | Function Type: 65 | i32 (i32, i32) 66 | 67 | Function: Bead 68 | Instruction Count: 8 69 | 70 | Basic Block Count: 1 71 | BasicBlock: entry 72 | 73 | Argument Count: 2 74 | Argument: a 75 | Argument: b 76 | 77 | Function Type: 78 | i32 (i32, i32) 79 | ``` 80 | -------------------------------------------------------------------------------- /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | BasedOnStyle: Microsoft 3 | AccessModifierOffset: '-4' 4 | AlignAfterOpenBracket: Align 5 | AlignEscapedNewlines: Left 6 | AlignOperands: 'true' 7 | AlignTrailingComments: 'true' 8 | AllowAllArgumentsOnNextLine: 'true' 9 | AllowAllConstructorInitializersOnNextLine: 'false' 10 | AllowAllParametersOfDeclarationOnNextLine: 'false' 11 | AllowShortBlocksOnASingleLine: 'false' 12 | AllowShortCaseLabelsOnASingleLine: 'false' 13 | AllowShortFunctionsOnASingleLine: None 14 | AllowShortIfStatementsOnASingleLine: Never 15 | AllowShortLambdasOnASingleLine: None 16 | AllowShortLoopsOnASingleLine: 'false' 17 | BinPackArguments: 'false' 18 | BinPackParameters: 'false' 19 | BreakAfterJavaFieldAnnotations: 'true' 20 | BreakBeforeBinaryOperators: None 21 | BreakBeforeTernaryOperators: 'true' 22 | BreakConstructorInitializers: AfterColon 23 | PackConstructorInitializers: Never 24 | CompactNamespaces: 'true' 25 | ContinuationIndentWidth: '4' 26 | Cpp11BracedListStyle: 'true' 27 | DerivePointerAlignment: 'true' 28 | FixNamespaceComments: 'true' 29 | IncludeBlocks: Regroup 30 | IndentCaseLabels: 'false' 31 | IndentPPDirectives: BeforeHash 32 | IndentWidth: '4' 33 | IndentWrappedFunctionNames: 'false' 34 | JavaScriptQuotes: Double 35 | JavaScriptWrapImports: 'true' 36 | KeepEmptyLinesAtTheStartOfBlocks: 'false' 37 | Language: Cpp 38 | MaxEmptyLinesToKeep: '1' 39 | NamespaceIndentation: All 40 | ObjCBlockIndentWidth: '4' 41 | DerivePointerAlignment: 'false' 42 | PointerAlignment: Left 43 | ReferenceAlignment: Pointer 44 | ReflowComments: 'true' 45 | SortIncludes: 'true' 46 | SortUsingDeclarations: 'true' 47 | SpaceAfterCStyleCast: 'false' 48 | SpaceAfterLogicalNot: 'false' 49 | SpaceAfterTemplateKeyword: 'false' 50 | SpaceBeforeAssignmentOperators: 'true' 51 | SpaceBeforeCpp11BracedList: 'false' 52 | SpaceBeforeCtorInitializerColon: 'true' 53 | SpaceBeforeInheritanceColon: 'true' 54 | SpaceBeforeParens: ControlStatements 55 | SpaceBeforeRangeBasedForLoopColon: 'true' 56 | SpaceInEmptyParentheses: 'false' 57 | SpacesInAngles: 'false' 58 | SpacesInCStyleCastParentheses: 'false' 59 | SpacesInContainerLiterals: 'false' 60 | SpacesInParentheses: 'false' 61 | SpacesInSquareBrackets: 'false' 62 | Standard: Cpp11 63 | TabWidth: '4' 64 | UseTab: Never 65 | SeparateDefinitionBlocks: Always 66 | EmptyLineAfterAccessModifier: Always 67 | 68 | ... 69 | -------------------------------------------------------------------------------- /llvm/lib/Transforms/SimpleLoopPass/SimpleLoopPass.cpp: -------------------------------------------------------------------------------- 1 | // SimpleLoopPass.cpp 2 | 3 | #include "llvm/IR/PassManager.h" 4 | #include "llvm/Passes/PassBuilder.h" 5 | #include "llvm/Passes/PassPlugin.h" 6 | #include "llvm/Support/raw_ostream.h" 7 | 8 | #include 9 | 10 | using namespace llvm; 11 | using std::cout; 12 | using std::endl; 13 | 14 | namespace 15 | { 16 | class SimpleLoopPass : public PassInfoMixin 17 | { 18 | public: 19 | 20 | PreservedAnalyses run(Loop& loop, 21 | LoopAnalysisManager& analysisManager, 22 | LoopStandardAnalysisResults& analysisResults, 23 | LPMUpdater& updater) 24 | { 25 | cout << "Loop: " << loop.getName().str() << endl; 26 | 27 | // Print out all the sub-loops in this loop 28 | cout << endl << " Sub-Loop Count: " << loop.getSubLoops().size() << endl; 29 | for (const auto& subLoop : loop) 30 | { 31 | cout << " Sub-Loop: " << subLoop->getName().str() << endl; 32 | } 33 | 34 | // Print out all the basic blocks in this loop 35 | cout << endl << " Basic Block Count: " << loop.getNumBlocks() << endl; 36 | for (const auto& basicBlock : loop.getBlocks()) 37 | { 38 | cout << " Basic Block: " << basicBlock->getName().str() << endl; 39 | } 40 | 41 | cout << endl << endl; 42 | 43 | // Assuming we did not change anything of the IR code 44 | return PreservedAnalyses::all(); 45 | } 46 | }; 47 | } // namespace 48 | 49 | // This is the new way of registering our pass 50 | extern "C" PassPluginLibraryInfo LLVM_ATTRIBUTE_WEAK llvmGetPassPluginInfo() 51 | { 52 | return {LLVM_PLUGIN_API_VERSION, "SimpleLoopPass", "v0.1", [](PassBuilder& passBuilder) { 53 | passBuilder.registerPipelineParsingCallback( 54 | [](StringRef name, LoopPassManager& passManager, ArrayRef) { 55 | if (name == "simple-loop-pass") 56 | { 57 | passManager.addPass(SimpleLoopPass()); 58 | return true; 59 | } 60 | 61 | return false; 62 | }); 63 | }}; 64 | } 65 | -------------------------------------------------------------------------------- /llvm/lib/Transforms/RunTimeFunctionCallCounter/README.md: -------------------------------------------------------------------------------- 1 | # LLVM Pass: Run-Time Function Call Counter (With New PassManager) 2 | 3 | ### Run-Time Function Call Counter 4 | 5 | 1. Create a directory `llvm-project/llvm/lib/Transforms/RunTimeFunctionCallCounter` 6 | 2. Add `CMakeLists.txt` file `llvm-project/llvm/lib/Transforms/RunTimeFunctionCallCounter` 7 | 3. Add source file `RunTimeFunctionCallCounter.cpp` into `llvm-project/llvm/lib/Transforms/RunTimeFunctionCallCounter` 8 | 9 | 4. Add the following code into `llvm-project/llvm/lib/Transforms/CMakeLists.txt`: 10 | 11 | ```cmake 12 | add_subdirectory(RunTimeFunctionCallCounter) 13 | ``` 14 | 15 | ### Build 16 | 17 | ```bash 18 | cd /path/to/llvm-project 19 | mkdir -p build 20 | cd build 21 | 22 | # Format the source code 23 | clang-format -i ../llvm/lib/Transforms/RunTimeFunctionCallCounter/*.cpp ../llvm/lib/Transforms/RunTimeFunctionCallCounter/**/*.c 24 | 25 | # Set up C++ standard library and header path 26 | export SDKROOT=$(xcrun --sdk macosx --show-sdk-path) 27 | 28 | # Generate projects 29 | cmake -G Ninja -DLLVM_ENABLE_PROJECTS=clang ../llvm 30 | 31 | # Compile 32 | ninja 33 | ``` 34 | 35 | Output: 36 | 37 | ``` 38 | [4/4] Linking CXX shared module lib/RunTimeFunctionCallCounter.dylib 39 | ``` 40 | 41 | ### Run 42 | 43 | Commands: 44 | 45 | ```bash 46 | mv ../llvm/lib/Transforms/RunTimeFunctionCallCounter/Tests/Test.c.txt ../llvm/lib/Transforms/RunTimeFunctionCallCounter/Tests/Test.c 47 | 48 | clang -S -emit-llvm ../llvm/lib/Transforms/RunTimeFunctionCallCounter/Tests/Test.c -o ../llvm/lib/Transforms/RunTimeFunctionCallCounter/Tests/Test.ll 49 | 50 | ./bin/opt -debug -load-pass-plugin=lib/RunTimeFunctionCallCounter.dylib -passes="runtime-function-call-counter" ../llvm/lib/Transforms/RunTimeFunctionCallCounter/Tests/Test.ll -o Test.bin 51 | 52 | ./bin/lli ./Test.bin 53 | ``` 54 | 55 | Output: 56 | 57 | ``` 58 | Args: ./bin/opt -debug -load-pass-plugin=lib/RunTimeFunctionCallCounter.dylib -passes=runtime-function-call-counter ../llvm/lib/Transforms/RunTimeFunctionCallCounter/Tests/Test.ll -o Test.bin 59 | Instrumented: Foo 60 | Instrumented: Bar 61 | Instrumented: Fez 62 | Instrumented: main 63 | Function: Foo, called 8 times 64 | Function: Bar, called 2 times 65 | Function: Fez, called 1 times 66 | Function: main, called 1 times 67 | ``` 68 | 69 | ### Inspect 70 | 71 | Commands: 72 | 73 | ``` 74 | ./bin/llvm-dis Test.bin -o ../llvm/lib/Transforms/RunTimeFunctionCallCounter/Tests/TestWithCounter.ll 75 | ``` 76 | -------------------------------------------------------------------------------- /llvm/lib/Transforms/SimpleLoopPass/Tests/SimpleLoopTest.2.ll: -------------------------------------------------------------------------------- 1 | ; RUN: opt -S -passes=loop-opt-tutorial -debug-only=loop-opt-tutorial < %s 2>&1 | FileCheck %s 2 | ; REQUIRES: asserts 3 | 4 | @B = common global [1024 x i32] zeroinitializer, align 16 5 | 6 | ; CHECK: Entering LoopOptTutorialPass::run 7 | ; CHECK: Entering LoopOptTutorialPass::run 8 | define void @dep_free(i32* noalias %arg) { 9 | bb: 10 | br label %bb5 11 | 12 | bb5: ; preds = %bb14, %bb 13 | %indvars.iv2 = phi i64 [ %indvars.iv.next3, %bb14 ], [ 0, %bb ] 14 | %.01 = phi i32 [ 0, %bb ], [ %tmp15, %bb14 ] 15 | %exitcond4 = icmp ne i64 %indvars.iv2, 100 16 | br i1 %exitcond4, label %bb7, label %bb17 17 | 18 | bb7: ; preds = %bb5 19 | %tmp = add nsw i32 %.01, -3 20 | %tmp8 = add nuw nsw i64 %indvars.iv2, 3 21 | %tmp9 = trunc i64 %tmp8 to i32 22 | %tmp10 = mul nsw i32 %tmp, %tmp9 23 | %tmp11 = trunc i64 %indvars.iv2 to i32 24 | %tmp12 = srem i32 %tmp10, %tmp11 25 | %tmp13 = getelementptr inbounds i32, i32* %arg, i64 %indvars.iv2 26 | store i32 %tmp12, i32* %tmp13, align 4 27 | br label %bb14 28 | 29 | bb14: ; preds = %bb7 30 | %indvars.iv.next3 = add nuw nsw i64 %indvars.iv2, 1 31 | %tmp15 = add nuw nsw i32 %.01, 1 32 | br label %bb5 33 | 34 | bb17: ; preds = %bb27, %bb5 35 | %indvars.iv = phi i64 [ %indvars.iv.next, %bb27 ], [ 0, %bb5 ] 36 | %.0 = phi i32 [ 0, %bb5 ], [ %tmp28, %bb27 ] 37 | %exitcond = icmp ne i64 %indvars.iv, 100 38 | br i1 %exitcond, label %bb19, label %bb18 39 | 40 | bb18: ; preds = %bb17 41 | br label %bb29 42 | 43 | bb19: ; preds = %bb17 44 | %tmp20 = add nsw i32 %.0, -3 45 | %tmp21 = add nuw nsw i64 %indvars.iv, 3 46 | %tmp22 = trunc i64 %tmp21 to i32 47 | %tmp23 = mul nsw i32 %tmp20, %tmp22 48 | %tmp24 = trunc i64 %indvars.iv to i32 49 | %tmp25 = srem i32 %tmp23, %tmp24 50 | %tmp26 = getelementptr inbounds [1024 x i32], [1024 x i32]* @B, i64 0, i64 %indvars.iv 51 | store i32 %tmp25, i32* %tmp26, align 4 52 | br label %bb27 53 | 54 | bb27: ; preds = %bb19 55 | %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1 56 | %tmp28 = add nuw nsw i32 %.0, 1 57 | br label %bb17 58 | 59 | bb29: ; preds = %bb18 60 | ret void 61 | } 62 | -------------------------------------------------------------------------------- /llvm/lib/Transforms/SimpleLoopPass/README.md: -------------------------------------------------------------------------------- 1 | # A Simple LLVM Loop Pass (With New PassManager) 2 | 3 | ### Simple Loop Pass 4 | 5 | 1. Create a directory `llvm-project/llvm/lib/Transforms/SimpleLoopPass` 6 | 2. Add `CMakeLists.txt` file `llvm-project/llvm/lib/Transforms/SimpleLoopPass` 7 | 3. Add source file `SimpleLoopPass.cpp` into `llvm-project/llvm/lib/Transforms/SimpleLoopPass` 8 | 9 | 4. Add the following code into `llvm-project/llvm/lib/Transforms/CMakeLists.txt`: 10 | 11 | ```cmake 12 | add_subdirectory(SimpleLoopPass) 13 | ``` 14 | 15 | ### Build 16 | 17 | ```bash 18 | cd /path/to/llvm-project 19 | mkdir -p build 20 | cd build 21 | 22 | cmake -G Ninja -DLLVM_ENABLE_PROJECTS=clang ../llvm 23 | 24 | ninja 25 | ``` 26 | 27 | Output: 28 | 29 | ``` 30 | [4/4] Linking CXX shared module lib/SimpleLoopPass.dylib 31 | ``` 32 | 33 | ### Run 34 | 35 | Simple loop test: 36 | 37 | ```bash 38 | mv ../llvm/lib/Transforms/SimpleLoopPass/Tests/SimpleLoopTest.c.txt ../llvm/lib/Transforms/SimpleLoopPass/Tests/SimpleLoopTest.c 39 | 40 | clang -S -emit-llvm -O1 ../llvm/lib/Transforms/SimpleLoopPass/Tests/SimpleLoopTest.c -o ../llvm/lib/Transforms/SimpleLoopPass/Tests/SimpleLoopTest.ll 41 | 42 | ./bin/opt -load-pass-plugin=lib/SimpleLoopPass.dylib -passes="simple-loop-pass" -disable-output ../llvm/lib/Transforms/SimpleLoopPass/Tests/SimpleLoopTest.ll 43 | ``` 44 | 45 | Output: 46 | 47 | ``` 48 | Loop: for.body 49 | 50 | Sub-Loop Count: 0 51 | 52 | Basic Block Count: 1 53 | Basic Block: for.body 54 | 55 | 56 | Loop: for.body5 57 | 58 | Sub-Loop Count: 0 59 | 60 | Basic Block Count: 1 61 | Basic Block: for.body5 62 | ``` 63 | 64 | Nested loop test: 65 | 66 | ```bash 67 | mv ../llvm/lib/Transforms/SimpleLoopPass/Tests/NestedLoopTest.c.txt ../llvm/lib/Transforms/SimpleLoopPass/Tests/NestedLoopTest.c 68 | 69 | clang -S -emit-llvm -O1 ../llvm/lib/Transforms/SimpleLoopPass/Tests/NestedLoopTest.c -o ../llvm/lib/Transforms/SimpleLoopPass/Tests/NestedLoopTest.ll 70 | 71 | ./bin/opt -load-pass-plugin=lib/SimpleLoopPass.dylib -passes="simple-loop-pass" -disable-output ../llvm/lib/Transforms/SimpleLoopPass/Tests/NestedLoopTest.ll 72 | ``` 73 | 74 | Output: 75 | 76 | ``` 77 | Loop: for.body4 78 | 79 | Sub-Loop Count: 0 80 | 81 | Basic Block Count: 1 82 | Basic Block: for.body4 83 | 84 | 85 | Loop: for.cond1.preheader 86 | 87 | Sub-Loop Count: 1 88 | Sub-Loop: for.body4 89 | 90 | Basic Block Count: 3 91 | Basic Block: for.cond1.preheader 92 | Basic Block: for.body4 93 | Basic Block: for.cond.cleanup3 94 | ``` 95 | -------------------------------------------------------------------------------- /llvm/lib/Transforms/SimpleFunctionPass/SimpleFunctionPass.cpp: -------------------------------------------------------------------------------- 1 | // SimpleFunctionPass.cpp 2 | 3 | #include "llvm/IR/PassManager.h" 4 | #include "llvm/Passes/PassBuilder.h" 5 | #include "llvm/Passes/PassPlugin.h" 6 | #include "llvm/Support/raw_ostream.h" 7 | 8 | #include 9 | 10 | using namespace llvm; 11 | using std::cout; 12 | using std::endl; 13 | 14 | namespace 15 | { 16 | class SimpleFunctionPass : public PassInfoMixin 17 | { 18 | public: 19 | 20 | PreservedAnalyses run(Function& function, FunctionAnalysisManager& analysisManager) 21 | { 22 | cout << "Function: " << function.getName().str() << endl; 23 | cout << " Instruction Count: " << function.getInstructionCount() << endl; 24 | 25 | // Print out all the basic blocks in this function 26 | cout << endl << " Basic Block Count: " << function.getBasicBlockList().size() << endl; 27 | for (const auto& basicBlock : function) 28 | { 29 | cout << " BasicBlock: " << basicBlock.getName().str() << endl; 30 | } 31 | 32 | // Print out all the arguments of this function 33 | cout << endl << " Argument Count: " << function.arg_size() << endl; 34 | for (const auto& arg : function.args()) 35 | { 36 | cout << " Argument: " << arg.getName().str() << endl; 37 | } 38 | 39 | cout << endl << " Function Type: " << endl; 40 | function.getFunctionType()->print(outs()); 41 | cout << endl << endl; 42 | 43 | // Assuming we did not change anything of the IR code 44 | return PreservedAnalyses::all(); 45 | } 46 | }; 47 | } 48 | 49 | // This part is the new way of registering your pass 50 | extern "C" PassPluginLibraryInfo LLVM_ATTRIBUTE_WEAK llvmGetPassPluginInfo() 51 | { 52 | return 53 | { 54 | LLVM_PLUGIN_API_VERSION, 55 | "SimpleFunctionPass", 56 | "v0.1", 57 | [](PassBuilder& passBuilder) { 58 | passBuilder.registerPipelineParsingCallback( 59 | [](StringRef name, FunctionPassManager& passManager, ArrayRef) { 60 | if(name == "simple-function-pass") 61 | { 62 | passManager.addPass(SimpleFunctionPass()); 63 | return true; 64 | } 65 | 66 | return false; 67 | } 68 | ); 69 | } 70 | }; 71 | } 72 | -------------------------------------------------------------------------------- /llvm/lib/Transforms/SimpleModulePass/SimpleModulePass.cpp: -------------------------------------------------------------------------------- 1 | // SimpleModulePass.cpp 2 | 3 | #include "llvm/IR/PassManager.h" 4 | #include "llvm/Passes/PassBuilder.h" 5 | #include "llvm/Passes/PassPlugin.h" 6 | #include "llvm/Support/raw_ostream.h" 7 | 8 | #include 9 | 10 | using namespace llvm; 11 | using std::cout; 12 | using std::endl; 13 | 14 | namespace 15 | { 16 | class SimpleModulePass : public PassInfoMixin 17 | { 18 | public: 19 | 20 | PreservedAnalyses run(Module& module, ModuleAnalysisManager& analysisManager) 21 | { 22 | cout << "Module: " << module.getName().str() << endl; 23 | cout << " ID: " << module.getModuleIdentifier() << endl; 24 | cout << " Source File Name: " << module.getSourceFileName() << endl; 25 | cout << " Instruction Count: " << module.getInstructionCount() << endl; 26 | 27 | // Print out all the global variables in this module 28 | cout << endl << " Gloabl Variable Count: " << module.getGlobalList().size() << endl; 29 | for (const auto& globalVariable : module.getGlobalList()) 30 | { 31 | cout << " Global Variable: " << globalVariable.getName().str() << endl; 32 | } 33 | 34 | // Print out all the functions in this module 35 | cout << endl << " Function Count: " << module.getFunctionList().size() << endl; 36 | for (const auto& function : module) 37 | { 38 | cout << " Function: " << function.getName().str() << endl; 39 | } 40 | 41 | // Assuming we did not change anything of the IR code 42 | return PreservedAnalyses::all(); 43 | } 44 | }; 45 | } 46 | 47 | // This is the new way of registering our pass 48 | extern "C" PassPluginLibraryInfo LLVM_ATTRIBUTE_WEAK llvmGetPassPluginInfo() 49 | { 50 | return 51 | { 52 | LLVM_PLUGIN_API_VERSION, 53 | "SimpleModulePass", 54 | "v0.1", 55 | [](PassBuilder& passBuilder) { 56 | passBuilder.registerPipelineParsingCallback( 57 | [](StringRef name, ModulePassManager& passManager, ArrayRef) { 58 | if(name == "simple-module-pass") 59 | { 60 | passManager.addPass(SimpleModulePass()); 61 | return true; 62 | } 63 | 64 | return false; 65 | } 66 | ); 67 | } 68 | }; 69 | } 70 | -------------------------------------------------------------------------------- /llvm/lib/Transforms/RunTimeFunctionCallCounter/Tests/Test.ll: -------------------------------------------------------------------------------- 1 | ; ModuleID = '../llvm/lib/Transforms/CompileTimeFunctionCallCounter/Tests/Test.c' 2 | source_filename = "../llvm/lib/Transforms/CompileTimeFunctionCallCounter/Tests/Test.c" 3 | target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" 4 | target triple = "x86_64-apple-macosx11.0.0" 5 | 6 | ; Function Attrs: noinline nounwind optnone ssp uwtable 7 | define dso_local void @Foo() #0 { 8 | entry: 9 | ret void 10 | } 11 | 12 | ; Function Attrs: noinline nounwind optnone ssp uwtable 13 | define dso_local void @Bar() #0 { 14 | entry: 15 | call void @Foo() 16 | ret void 17 | } 18 | 19 | ; Function Attrs: noinline nounwind optnone ssp uwtable 20 | define dso_local void @Fez() #0 { 21 | entry: 22 | call void @Bar() 23 | ret void 24 | } 25 | 26 | ; Function Attrs: noinline nounwind optnone ssp uwtable 27 | define dso_local i32 @main() #0 { 28 | entry: 29 | %retval = alloca i32, align 4 30 | %i = alloca i32, align 4 31 | store i32 0, i32* %retval, align 4 32 | call void @Foo() 33 | call void @Bar() 34 | call void @Fez() 35 | store i32 0, i32* %i, align 4 36 | br label %for.cond 37 | 38 | for.cond: ; preds = %for.inc, %entry 39 | %0 = load i32, i32* %i, align 4 40 | %cmp = icmp slt i32 %0, 5 41 | br i1 %cmp, label %for.body, label %for.end 42 | 43 | for.body: ; preds = %for.cond 44 | call void @Foo() 45 | br label %for.inc 46 | 47 | for.inc: ; preds = %for.body 48 | %1 = load i32, i32* %i, align 4 49 | %inc = add nsw i32 %1, 1 50 | store i32 %inc, i32* %i, align 4 51 | br label %for.cond, !llvm.loop !3 52 | 53 | for.end: ; preds = %for.cond 54 | ret i32 0 55 | } 56 | 57 | attributes #0 = { noinline nounwind optnone ssp uwtable "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "tune-cpu"="generic" "unsafe-fp-math"="false" "use-soft-float"="false" } 58 | 59 | !llvm.module.flags = !{!0, !1} 60 | !llvm.ident = !{!2} 61 | 62 | !0 = !{i32 1, !"wchar_size", i32 4} 63 | !1 = !{i32 7, !"PIC Level", i32 2} 64 | !2 = !{!"clang version 12.0.1 (https://github.com/llvm/llvm-project fed41342a82f5a3a9201819a82bf7a48313e296b)"} 65 | !3 = distinct !{!3, !4} 66 | !4 = !{!"llvm.loop.mustprogress"} 67 | -------------------------------------------------------------------------------- /llvm/lib/Transforms/CompileTimeFunctionCallCounter/Tests/Test.ll: -------------------------------------------------------------------------------- 1 | ; ModuleID = '../llvm/lib/Transforms/CompileTimeFunctionCallCounter/Tests/Test.c' 2 | source_filename = "../llvm/lib/Transforms/CompileTimeFunctionCallCounter/Tests/Test.c" 3 | target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" 4 | target triple = "x86_64-apple-macosx11.0.0" 5 | 6 | ; Function Attrs: noinline nounwind optnone ssp uwtable 7 | define dso_local void @Foo() #0 { 8 | entry: 9 | ret void 10 | } 11 | 12 | ; Function Attrs: noinline nounwind optnone ssp uwtable 13 | define dso_local void @Bar() #0 { 14 | entry: 15 | call void @Foo() 16 | ret void 17 | } 18 | 19 | ; Function Attrs: noinline nounwind optnone ssp uwtable 20 | define dso_local void @Fez() #0 { 21 | entry: 22 | call void @Bar() 23 | ret void 24 | } 25 | 26 | ; Function Attrs: noinline nounwind optnone ssp uwtable 27 | define dso_local i32 @main() #0 { 28 | entry: 29 | %retval = alloca i32, align 4 30 | %i = alloca i32, align 4 31 | store i32 0, i32* %retval, align 4 32 | call void @Foo() 33 | call void @Bar() 34 | call void @Fez() 35 | store i32 0, i32* %i, align 4 36 | br label %for.cond 37 | 38 | for.cond: ; preds = %for.inc, %entry 39 | %0 = load i32, i32* %i, align 4 40 | %cmp = icmp slt i32 %0, 5 41 | br i1 %cmp, label %for.body, label %for.end 42 | 43 | for.body: ; preds = %for.cond 44 | call void @Foo() 45 | br label %for.inc 46 | 47 | for.inc: ; preds = %for.body 48 | %1 = load i32, i32* %i, align 4 49 | %inc = add nsw i32 %1, 1 50 | store i32 %inc, i32* %i, align 4 51 | br label %for.cond, !llvm.loop !3 52 | 53 | for.end: ; preds = %for.cond 54 | ret i32 0 55 | } 56 | 57 | attributes #0 = { noinline nounwind optnone ssp uwtable "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "tune-cpu"="generic" "unsafe-fp-math"="false" "use-soft-float"="false" } 58 | 59 | !llvm.module.flags = !{!0, !1} 60 | !llvm.ident = !{!2} 61 | 62 | !0 = !{i32 1, !"wchar_size", i32 4} 63 | !1 = !{i32 7, !"PIC Level", i32 2} 64 | !2 = !{!"clang version 12.0.1 (https://github.com/llvm/llvm-project fed41342a82f5a3a9201819a82bf7a48313e296b)"} 65 | !3 = distinct !{!3, !4} 66 | !4 = !{!"llvm.loop.mustprogress"} 67 | -------------------------------------------------------------------------------- /llvm/lib/Transforms/SimpleLoopPass/Tests/SimpleLoopTest.ll: -------------------------------------------------------------------------------- 1 | ; ModuleID = '../llvm/lib/Transforms/SimpleLoopPass/Tests/SimpleLoopTest.c' 2 | source_filename = "../llvm/lib/Transforms/SimpleLoopPass/Tests/SimpleLoopTest.c" 3 | target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" 4 | target triple = "x86_64-apple-macosx11.0.0" 5 | 6 | @array = dso_local local_unnamed_addr global [1024 x i32] zeroinitializer, align 16 7 | 8 | ; Function Attrs: nofree norecurse nounwind ssp uwtable 9 | define dso_local void @SimpleLoopTest() local_unnamed_addr #0 { 10 | entry: 11 | br label %for.body 12 | 13 | for.body: ; preds = %entry, %for.body 14 | %indvars.iv24 = phi i64 [ 0, %entry ], [ %indvars.iv.next25, %for.body ] 15 | %arrayidx = getelementptr inbounds [1024 x i32], [1024 x i32]* @array, i64 0, i64 %indvars.iv24 16 | %0 = trunc i64 %indvars.iv24 to i32 17 | store i32 %0, i32* %arrayidx, align 4, !tbaa !3 18 | %indvars.iv.next25 = add nuw nsw i64 %indvars.iv24, 1 19 | %exitcond26.not = icmp eq i64 %indvars.iv.next25, 100 20 | br i1 %exitcond26.not, label %for.body5, label %for.body, !llvm.loop !7 21 | 22 | for.cond.cleanup4: ; preds = %for.body5 23 | ret void 24 | 25 | for.body5: ; preds = %for.body, %for.body5 26 | %indvars.iv = phi i64 [ %indvars.iv.next, %for.body5 ], [ 101, %for.body ] 27 | %arrayidx7 = getelementptr inbounds [1024 x i32], [1024 x i32]* @array, i64 0, i64 %indvars.iv 28 | %1 = load i32, i32* %arrayidx7, align 4, !tbaa !3 29 | %2 = trunc i64 %indvars.iv to i32 30 | %mul = mul nsw i32 %1, %2 31 | store i32 %mul, i32* %arrayidx7, align 4, !tbaa !3 32 | %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1 33 | %exitcond.not = icmp eq i64 %indvars.iv.next, 200 34 | br i1 %exitcond.not, label %for.cond.cleanup4, label %for.body5, !llvm.loop !10 35 | } 36 | 37 | attributes #0 = { nofree norecurse nounwind ssp uwtable "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "tune-cpu"="generic" "unsafe-fp-math"="false" "use-soft-float"="false" } 38 | 39 | !llvm.module.flags = !{!0, !1} 40 | !llvm.ident = !{!2} 41 | 42 | !0 = !{i32 1, !"wchar_size", i32 4} 43 | !1 = !{i32 7, !"PIC Level", i32 2} 44 | !2 = !{!"clang version 12.0.1 (https://github.com/llvm/llvm-project fed41342a82f5a3a9201819a82bf7a48313e296b)"} 45 | !3 = !{!4, !4, i64 0} 46 | !4 = !{!"int", !5, i64 0} 47 | !5 = !{!"omnipotent char", !6, i64 0} 48 | !6 = !{!"Simple C/C++ TBAA"} 49 | !7 = distinct !{!7, !8, !9} 50 | !8 = !{!"llvm.loop.mustprogress"} 51 | !9 = !{!"llvm.loop.unroll.disable"} 52 | !10 = distinct !{!10, !8, !9} 53 | -------------------------------------------------------------------------------- /llvm/lib/Transforms/SimpleModulePass/Test.ll: -------------------------------------------------------------------------------- 1 | ; ModuleID = '../llvm/lib/Transforms/SimpleModulePass/Test.c' 2 | source_filename = "../llvm/lib/Transforms/SimpleModulePass/Test.c" 3 | target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" 4 | target triple = "x86_64-apple-macosx11.0.0" 5 | 6 | @globalInt = dso_local global i32 0, align 4 7 | @globalShort = dso_local global i16 1, align 2 8 | @.str = private unnamed_addr constant [24 x i8] c"This is a global string\00", align 1 9 | @globalString = dso_local global i8* getelementptr inbounds ([24 x i8], [24 x i8]* @.str, i32 0, i32 0), align 8 10 | 11 | ; Function Attrs: noinline nounwind optnone ssp uwtable 12 | define dso_local i32 @Foo(i32 %a) #0 { 13 | entry: 14 | %a.addr = alloca i32, align 4 15 | %b = alloca i32, align 4 16 | store i32 %a, i32* %a.addr, align 4 17 | %0 = load i32, i32* %a.addr, align 4 18 | %cmp = icmp sgt i32 %0, 33 19 | br i1 %cmp, label %if.then, label %if.else 20 | 21 | if.then: ; preds = %entry 22 | store i32 66, i32* %b, align 4 23 | br label %if.end 24 | 25 | if.else: ; preds = %entry 26 | store i32 77, i32* %b, align 4 27 | br label %if.end 28 | 29 | if.end: ; preds = %if.else, %if.then 30 | %1 = load i32, i32* %b, align 4 31 | ret i32 %1 32 | } 33 | 34 | ; Function Attrs: noinline nounwind optnone ssp uwtable 35 | define dso_local i32 @Bar(i32 %a, i32 %b) #0 { 36 | entry: 37 | %a.addr = alloca i32, align 4 38 | %b.addr = alloca i32, align 4 39 | store i32 %a, i32* %a.addr, align 4 40 | store i32 %b, i32* %b.addr, align 4 41 | %0 = load i32, i32* %a.addr, align 4 42 | %1 = load i32, i32* %b.addr, align 4 43 | %add = add nsw i32 %0, %1 44 | ret i32 %add 45 | } 46 | 47 | ; Function Attrs: noinline nounwind optnone ssp uwtable 48 | define dso_local i32 @Bead(i32 %a, i32 %b) #0 { 49 | entry: 50 | %a.addr = alloca i32, align 4 51 | %b.addr = alloca i32, align 4 52 | store i32 %a, i32* %a.addr, align 4 53 | store i32 %b, i32* %b.addr, align 4 54 | %0 = load i32, i32* %a.addr, align 4 55 | %1 = load i32, i32* %b.addr, align 4 56 | %mul = mul nsw i32 %0, %1 57 | ret i32 %mul 58 | } 59 | 60 | attributes #0 = { noinline nounwind optnone ssp uwtable "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "tune-cpu"="generic" "unsafe-fp-math"="false" "use-soft-float"="false" } 61 | 62 | !llvm.module.flags = !{!0, !1} 63 | !llvm.ident = !{!2} 64 | 65 | !0 = !{i32 1, !"wchar_size", i32 4} 66 | !1 = !{i32 7, !"PIC Level", i32 2} 67 | !2 = !{!"clang version 12.0.1 (https://github.com/llvm/llvm-project fed41342a82f5a3a9201819a82bf7a48313e296b)"} 68 | -------------------------------------------------------------------------------- /llvm/lib/Transforms/SimpleLoopPass/Tests/NestedLoopTest.ll: -------------------------------------------------------------------------------- 1 | ; ModuleID = '../llvm/lib/Transforms/SimpleLoopPass/Tests/NestedLoopTest.c' 2 | source_filename = "../llvm/lib/Transforms/SimpleLoopPass/Tests/NestedLoopTest.c" 3 | target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" 4 | target triple = "x86_64-apple-macosx11.0.0" 5 | 6 | @a = dso_local local_unnamed_addr global [1024 x [1024 x i32]] zeroinitializer, align 16 7 | @b = dso_local local_unnamed_addr global [1024 x [1024 x i32]] zeroinitializer, align 16 8 | 9 | ; Function Attrs: nofree norecurse nounwind ssp uwtable writeonly 10 | define dso_local void @NestedLoopTest() local_unnamed_addr #0 { 11 | entry: 12 | br label %for.cond1.preheader 13 | 14 | for.cond1.preheader: ; preds = %entry, %for.cond.cleanup3 15 | %indvars.iv21 = phi i64 [ 0, %entry ], [ %indvars.iv.next22, %for.cond.cleanup3 ] 16 | %i.020 = phi i32 [ 0, %entry ], [ %inc8, %for.cond.cleanup3 ] 17 | %sub = add nsw i32 %i.020, -3 18 | %add = add nuw nsw i32 %i.020, 3 19 | %mul = mul nsw i32 %sub, %add 20 | %0 = trunc i64 %indvars.iv21 to i32 21 | %rem = srem i32 %mul, %0 22 | br label %for.body4 23 | 24 | for.cond.cleanup: ; preds = %for.cond.cleanup3 25 | ret void 26 | 27 | for.cond.cleanup3: ; preds = %for.body4 28 | %indvars.iv.next22 = add nuw nsw i64 %indvars.iv21, 1 29 | %inc8 = add nuw nsw i32 %i.020, 1 30 | %exitcond26.not = icmp eq i64 %indvars.iv.next22, 100 31 | br i1 %exitcond26.not, label %for.cond.cleanup, label %for.cond1.preheader, !llvm.loop !3 32 | 33 | for.body4: ; preds = %for.cond1.preheader, %for.body4 34 | %indvars.iv = phi i64 [ 0, %for.cond1.preheader ], [ %indvars.iv.next, %for.body4 ] 35 | %arrayidx6 = getelementptr inbounds [1024 x [1024 x i32]], [1024 x [1024 x i32]]* @a, i64 0, i64 %indvars.iv21, i64 %indvars.iv 36 | store i32 %rem, i32* %arrayidx6, align 4, !tbaa !6 37 | %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1 38 | %exitcond.not = icmp eq i64 %indvars.iv.next, 100 39 | br i1 %exitcond.not, label %for.cond.cleanup3, label %for.body4, !llvm.loop !10 40 | } 41 | 42 | attributes #0 = { nofree norecurse nounwind ssp uwtable writeonly "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "tune-cpu"="generic" "unsafe-fp-math"="false" "use-soft-float"="false" } 43 | 44 | !llvm.module.flags = !{!0, !1} 45 | !llvm.ident = !{!2} 46 | 47 | !0 = !{i32 1, !"wchar_size", i32 4} 48 | !1 = !{i32 7, !"PIC Level", i32 2} 49 | !2 = !{!"clang version 12.0.1 (https://github.com/llvm/llvm-project fed41342a82f5a3a9201819a82bf7a48313e296b)"} 50 | !3 = distinct !{!3, !4, !5} 51 | !4 = !{!"llvm.loop.mustprogress"} 52 | !5 = !{!"llvm.loop.unroll.disable"} 53 | !6 = !{!7, !7, i64 0} 54 | !7 = !{!"int", !8, i64 0} 55 | !8 = !{!"omnipotent char", !9, i64 0} 56 | !9 = !{!"Simple C/C++ TBAA"} 57 | !10 = distinct !{!10, !4, !5} 58 | -------------------------------------------------------------------------------- /llvm/lib/Transforms/SimpleLoopPass/Tests/NestedLoopTest.2.ll: -------------------------------------------------------------------------------- 1 | ; RUN: opt -S -passes=loop-opt-tutorial -debug-only=loop-opt-tutorial < %s 2>&1 | FileCheck %s 2 | ; REQUIRES: asserts 3 | ; 4 | ; Opts: -correlated-propagation -mem2reg -instcombine -loop-simplify -indvars -instnamer 5 | ; 6 | ; Source: 7 | ; int A[1024][1024]; 8 | ; int B[1024][1024]; 9 | ; 10 | ; #define EXPENSIVE_PURE_COMPUTATION(i) ((i - 3) * (i + 3) % i) 11 | ; 12 | ; void dep_free() { 13 | ; for (int i = 0; i < 100; i++) 14 | ; for (int j = 0; j < 100; j++) 15 | ; A[i][j] = EXPENSIVE_PURE_COMPUTATION(i); 16 | ; } 17 | ; 18 | @A = common dso_local global [1024 x [1024 x i32]] zeroinitializer, align 4 19 | @B = common dso_local global [1024 x [1024 x i32]] zeroinitializer, align 4 20 | 21 | ; CHECK: Entering LoopOptTutorialPass::run 22 | ; CHECK: Loop at depth 2 23 | ; CHECK: Entering LoopOptTutorialPass::run 24 | ; CHECK: Loop at depth 1 25 | ; CHECK: Loop at depth 2 26 | define dso_local void @dep_free() { 27 | entry: 28 | br label %for.cond 29 | 30 | for.cond: ; preds = %for.inc7, %entry 31 | %indvars.iv1 = phi i64 [ %indvars.iv.next2, %for.inc7 ], [ 0, %entry ] 32 | %i.0 = phi i32 [ 0, %entry ], [ %inc8, %for.inc7 ] 33 | %exitcond5 = icmp ne i64 %indvars.iv1, 100 34 | br i1 %exitcond5, label %for.body, label %for.cond.cleanup 35 | 36 | for.cond.cleanup: ; preds = %for.cond 37 | br label %for.end9 38 | 39 | for.body: ; preds = %for.cond 40 | br label %for.cond1 41 | 42 | for.cond1: ; preds = %for.inc, %for.body 43 | %indvars.iv = phi i64 [ %indvars.iv.next, %for.inc ], [ 0, %for.body ] 44 | %exitcond = icmp ne i64 %indvars.iv, 100 45 | br i1 %exitcond, label %for.body4, label %for.cond.cleanup3 46 | 47 | for.cond.cleanup3: ; preds = %for.cond1 48 | br label %for.end 49 | 50 | for.body4: ; preds = %for.cond1 51 | %sub = add nsw i32 %i.0, -3 52 | %tmp = add nuw nsw i64 %indvars.iv1, 3 53 | %tmp6 = trunc i64 %tmp to i32 54 | %mul = mul nsw i32 %sub, %tmp6 55 | %tmp7 = trunc i64 %indvars.iv1 to i32 56 | %rem = srem i32 %mul, %tmp7 57 | %arrayidx6 = getelementptr inbounds [1024 x [1024 x i32]], [1024 x [1024 x i32]]* @A, i64 0, i64 %indvars.iv1, i64 %indvars.iv 58 | store i32 %rem, i32* %arrayidx6, align 4, !tbaa !2 59 | br label %for.inc 60 | 61 | for.inc: ; preds = %for.body4 62 | %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1 63 | br label %for.cond1 64 | 65 | for.end: ; preds = %for.cond.cleanup3 66 | br label %for.inc7 67 | 68 | for.inc7: ; preds = %for.end 69 | %indvars.iv.next2 = add nuw nsw i64 %indvars.iv1, 1 70 | %inc8 = add nuw nsw i32 %i.0, 1 71 | br label %for.cond 72 | 73 | for.end9: ; preds = %for.cond.cleanup 74 | ret void 75 | } 76 | 77 | declare void @llvm.lifetime.start.p0i8(i64 immarg, i8* nocapture) 78 | 79 | declare void @llvm.lifetime.end.p0i8(i64 immarg, i8* nocapture) 80 | 81 | 82 | !llvm.module.flags = !{!0} 83 | !llvm.ident = !{!1} 84 | 85 | !0 = !{i32 1, !"wchar_size", i32 4} 86 | !1 = !{!"clang version 10.0.0 (https://github.com/kitbarton/llvm-project.git 8ec1040ded5afb786efc933363420571aa6ec5ea)"} 87 | !2 = !{!3, !3, i64 0} 88 | !3 = !{!"int", !4, i64 0} 89 | !4 = !{!"omnipotent char", !5, i64 0} 90 | !5 = !{!"Simple C/C++ TBAA"} -------------------------------------------------------------------------------- /llvm/lib/Transforms/CompileTimeFunctionCallCounter/CompileTimeFunctionCallCounter.cpp: -------------------------------------------------------------------------------- 1 | // CompileTimeFunctionCallCounter.cpp 2 | 3 | #include "llvm/IR/PassManager.h" 4 | #include "llvm/Passes/PassBuilder.h" 5 | #include "llvm/Passes/PassPlugin.h" 6 | 7 | #include 8 | #include 9 | 10 | using namespace llvm; 11 | using FunctionCalls = std::map; 12 | 13 | // A LLVM Pass to analyse the function calls 14 | class CompileTimeFunctionCallCounter : public AnalysisInfoMixin 15 | { 16 | public: 17 | 18 | using Result = FunctionCalls; 19 | 20 | Result run(Module& module, ModuleAnalysisManager&); 21 | 22 | private: 23 | 24 | friend struct AnalysisInfoMixin; 25 | 26 | // A special key to identify a particular analysis pass type 27 | static AnalysisKey Key; 28 | }; 29 | 30 | // A LLVM Pass to print the function call statistics 31 | class CompileTimeFunctionCallPrinter : public PassInfoMixin 32 | { 33 | public: 34 | 35 | PreservedAnalyses run(Module& module, ModuleAnalysisManager& analysisManager); 36 | }; 37 | 38 | AnalysisKey CompileTimeFunctionCallCounter::Key; 39 | 40 | CompileTimeFunctionCallCounter::Result CompileTimeFunctionCallCounter::run(Module& module, ModuleAnalysisManager&) 41 | { 42 | Result functionCalls; 43 | 44 | for (const Function& function : module) 45 | { 46 | for (const BasicBlock& basicBlock : function) 47 | { 48 | for (const Instruction& instruction : basicBlock) 49 | { 50 | const CallBase* functionCallInstruction = dyn_cast(&instruction); 51 | if (nullptr == functionCallInstruction) 52 | { 53 | // Ignore instructions that are not function calls 54 | continue; 55 | } 56 | 57 | // We can get the called function if this is a direct function call 58 | const Function* calledFunction = functionCallInstruction->getCalledFunction(); 59 | if (nullptr == calledFunction) 60 | { 61 | continue; 62 | } 63 | 64 | auto functionCallIterator = functionCalls.find(calledFunction); 65 | if (functionCalls.end() == functionCallIterator) 66 | { 67 | functionCallIterator = functionCalls.insert(std::make_pair(calledFunction, 0)).first; 68 | } 69 | 70 | ++functionCallIterator->second; 71 | } 72 | } 73 | } 74 | 75 | return functionCalls; 76 | } 77 | 78 | PreservedAnalyses CompileTimeFunctionCallPrinter::run(Module& module, ModuleAnalysisManager& analysisManager) 79 | { 80 | auto functionCalls = analysisManager.getResult(module); 81 | for (auto& functionCall : functionCalls) 82 | { 83 | std::cout << "Function: " << functionCall.first->getName().str() << ", " 84 | << "called " << functionCall.second << " times" << std::endl; 85 | } 86 | 87 | // Assuming we did not change anything of the IR code 88 | return PreservedAnalyses::all(); 89 | } 90 | 91 | // Pass registration 92 | extern "C" LLVM_ATTRIBUTE_WEAK ::PassPluginLibraryInfo llvmGetPassPluginInfo() 93 | { 94 | return { 95 | LLVM_PLUGIN_API_VERSION, "CompileTimeFunctionCallPrinter", LLVM_VERSION_STRING, [](PassBuilder& passBuilder) { 96 | // 1. Registration for "opt -passes="compile-time-function-call-counter"" 97 | passBuilder.registerPipelineParsingCallback( 98 | [&](StringRef name, ModulePassManager& passManager, ArrayRef) { 99 | if (name == "compile-time-function-call-counter") 100 | { 101 | passManager.addPass(CompileTimeFunctionCallPrinter()); 102 | return true; 103 | } 104 | 105 | return false; 106 | }); 107 | 108 | // 2. Registration for "analysisManager.getResult(module)" 109 | passBuilder.registerAnalysisRegistrationCallback([](ModuleAnalysisManager& analysisManager) { 110 | analysisManager.registerPass([&]() { 111 | return CompileTimeFunctionCallCounter(); 112 | }); 113 | }); 114 | }}; 115 | } 116 | -------------------------------------------------------------------------------- /llvm/lib/Transforms/RunTimeFunctionCallCounter/Tests/TestWithCounter.ll: -------------------------------------------------------------------------------- 1 | ; ModuleID = 'Test.bin' 2 | source_filename = "../llvm/lib/Transforms/CompileTimeFunctionCallCounter/Tests/Test.c" 3 | target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" 4 | target triple = "x86_64-apple-macosx11.0.0" 5 | 6 | @counter_Foo = common global i32 0, align 4 7 | @name_Foo = private unnamed_addr constant [4 x i8] c"Foo\00", align 1 8 | @counter_Bar = common global i32 0, align 4 9 | @name_Bar = private unnamed_addr constant [4 x i8] c"Bar\00", align 1 10 | @counter_Fez = common global i32 0, align 4 11 | @name_Fez = private unnamed_addr constant [4 x i8] c"Fez\00", align 1 12 | @counter_main = common global i32 0, align 4 13 | @name_main = private unnamed_addr constant [5 x i8] c"main\00", align 1 14 | @0 = global [31 x i8] c"Function: %s, called %d times\0A\00" 15 | @llvm.global_dtors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 0, void ()* @PrintfWrapper, i8* null }] 16 | 17 | ; Function Attrs: noinline nounwind optnone ssp uwtable 18 | define dso_local void @Foo() #0 { 19 | entry: 20 | %0 = load i32, i32* @counter_Foo, align 4 21 | %1 = add i32 1, %0 22 | store i32 %1, i32* @counter_Foo, align 4 23 | ret void 24 | } 25 | 26 | ; Function Attrs: noinline nounwind optnone ssp uwtable 27 | define dso_local void @Bar() #0 { 28 | entry: 29 | %0 = load i32, i32* @counter_Bar, align 4 30 | %1 = add i32 1, %0 31 | store i32 %1, i32* @counter_Bar, align 4 32 | call void @Foo() 33 | ret void 34 | } 35 | 36 | ; Function Attrs: noinline nounwind optnone ssp uwtable 37 | define dso_local void @Fez() #0 { 38 | entry: 39 | %0 = load i32, i32* @counter_Fez, align 4 40 | %1 = add i32 1, %0 41 | store i32 %1, i32* @counter_Fez, align 4 42 | call void @Bar() 43 | ret void 44 | } 45 | 46 | ; Function Attrs: noinline nounwind optnone ssp uwtable 47 | define dso_local i32 @main() #0 { 48 | entry: 49 | %0 = load i32, i32* @counter_main, align 4 50 | %1 = add i32 1, %0 51 | store i32 %1, i32* @counter_main, align 4 52 | %retval = alloca i32, align 4 53 | %i = alloca i32, align 4 54 | store i32 0, i32* %retval, align 4 55 | call void @Foo() 56 | call void @Bar() 57 | call void @Fez() 58 | store i32 0, i32* %i, align 4 59 | br label %for.cond 60 | 61 | for.cond: ; preds = %for.inc, %entry 62 | %2 = load i32, i32* %i, align 4 63 | %cmp = icmp slt i32 %2, 5 64 | br i1 %cmp, label %for.body, label %for.end 65 | 66 | for.body: ; preds = %for.cond 67 | call void @Foo() 68 | br label %for.inc 69 | 70 | for.inc: ; preds = %for.body 71 | %3 = load i32, i32* %i, align 4 72 | %inc = add nsw i32 %3, 1 73 | store i32 %inc, i32* %i, align 4 74 | br label %for.cond, !llvm.loop !3 75 | 76 | for.end: ; preds = %for.cond 77 | ret i32 0 78 | } 79 | 80 | declare i32 @printf(i8*, ...) 81 | 82 | define void @PrintfWrapper() { 83 | enter: 84 | %0 = load i32, i32* @counter_Foo, align 4 85 | %1 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([31 x i8], [31 x i8]* @0, i32 0, i32 0), i8* getelementptr inbounds ([4 x i8], [4 x i8]* @name_Foo, i32 0, i32 0), i32 %0) 86 | %2 = load i32, i32* @counter_Bar, align 4 87 | %3 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([31 x i8], [31 x i8]* @0, i32 0, i32 0), i8* getelementptr inbounds ([4 x i8], [4 x i8]* @name_Bar, i32 0, i32 0), i32 %2) 88 | %4 = load i32, i32* @counter_Fez, align 4 89 | %5 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([31 x i8], [31 x i8]* @0, i32 0, i32 0), i8* getelementptr inbounds ([4 x i8], [4 x i8]* @name_Fez, i32 0, i32 0), i32 %4) 90 | %6 = load i32, i32* @counter_main, align 4 91 | %7 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([31 x i8], [31 x i8]* @0, i32 0, i32 0), i8* getelementptr inbounds ([5 x i8], [5 x i8]* @name_main, i32 0, i32 0), i32 %6) 92 | ret void 93 | } 94 | 95 | attributes #0 = { noinline nounwind optnone ssp uwtable "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "tune-cpu"="generic" "unsafe-fp-math"="false" "use-soft-float"="false" } 96 | 97 | !llvm.module.flags = !{!0, !1} 98 | !llvm.ident = !{!2} 99 | 100 | !0 = !{i32 1, !"wchar_size", i32 4} 101 | !1 = !{i32 7, !"PIC Level", i32 2} 102 | !2 = !{!"clang version 12.0.1 (https://github.com/llvm/llvm-project fed41342a82f5a3a9201819a82bf7a48313e296b)"} 103 | !3 = distinct !{!3, !4} 104 | !4 = !{!"llvm.loop.mustprogress"} 105 | -------------------------------------------------------------------------------- /llvm/lib/Transforms/ConstantAdditionCombiner/ConstantAdditionCombiner.cpp: -------------------------------------------------------------------------------- 1 | // ConstantAdditionCombiner.cpp 2 | 3 | #include "llvm/IR/PassManager.h" 4 | #include "llvm/Passes/PassBuilder.h" 5 | #include "llvm/Passes/PassPlugin.h" 6 | #include "llvm/Support/raw_ostream.h" 7 | 8 | #include 9 | 10 | using namespace llvm; 11 | using std::cout; 12 | using std::endl; 13 | 14 | namespace 15 | { 16 | /** 17 | * An analysis to collect all the "add" instructions with constant operands from a function 18 | */ 19 | struct ConstantAdditionAnalysis : public llvm::AnalysisInfoMixin 20 | { 21 | using Result = llvm::SmallVector; 22 | 23 | Result run(llvm::Function& function, llvm::FunctionAnalysisManager& analysisManager); 24 | 25 | // A special type used by analysis passes to provide an address that 26 | // identifies that particular analysis pass type 27 | static llvm::AnalysisKey Key; 28 | }; 29 | 30 | AnalysisKey ConstantAdditionAnalysis::Key; 31 | 32 | bool IsConstantIntOnly(Instruction& instruction) 33 | { 34 | for (Use& operand : instruction.operands()) 35 | { 36 | if (!isa(operand)) 37 | return false; 38 | } 39 | 40 | return true; 41 | } 42 | 43 | ConstantAdditionAnalysis::Result ConstantAdditionAnalysis::run(Function& function, 44 | FunctionAnalysisManager& analysisManager) 45 | { 46 | SmallVector addInstructions; 47 | for (BasicBlock& block : function) 48 | { 49 | for (Instruction& instruction : block) 50 | { 51 | if (!instruction.isBinaryOp()) 52 | continue; 53 | 54 | if (instruction.getOpcode() != Instruction::BinaryOps::Add) 55 | continue; 56 | 57 | if (!IsConstantIntOnly(instruction)) 58 | continue; 59 | 60 | addInstructions.push_back(&cast(instruction)); 61 | } 62 | } 63 | 64 | return addInstructions; 65 | } 66 | 67 | /** 68 | * An pass to print all the "add" instructions with constant operands from a function 69 | */ 70 | struct ConstantAdditionPrinterPass : public llvm::PassInfoMixin 71 | { 72 | explicit ConstantAdditionPrinterPass(llvm::raw_ostream& outStream) : 73 | out(outStream) 74 | { 75 | } 76 | 77 | llvm::PreservedAnalyses run(llvm::Function& function, llvm::FunctionAnalysisManager& analysisManager) 78 | { 79 | auto& addInstructions = analysisManager.getResult(function); 80 | 81 | out << "Function: " << function.getName() << "\n"; 82 | for (auto& instruction : addInstructions) 83 | { 84 | out << *instruction << "\n"; 85 | } 86 | 87 | return PreservedAnalyses::all(); 88 | } 89 | 90 | private: 91 | 92 | llvm::raw_ostream& out; 93 | }; 94 | 95 | struct ConstantAdditionCombinerPass : public llvm::PassInfoMixin 96 | { 97 | llvm::PreservedAnalyses run(llvm::Function& function, llvm::FunctionAnalysisManager& analysisManager); 98 | }; 99 | 100 | void ReplaceAddInstructionWithConstant(BinaryOperator* binaryOperator) 101 | { 102 | auto first = cast(binaryOperator->getOperand(0)); 103 | auto second = cast(binaryOperator->getOperand(1)); 104 | 105 | // Get the final value from the "add" instruction 106 | auto sum = ConstantExpr::getAdd(first, second); 107 | 108 | binaryOperator->replaceAllUsesWith(sum); 109 | binaryOperator->eraseFromParent(); 110 | } 111 | 112 | PreservedAnalyses ConstantAdditionCombinerPass::run(Function& function, FunctionAnalysisManager& analysisManager) 113 | { 114 | auto& addInstructions = analysisManager.getResult(function); 115 | for (auto binaryOperator : addInstructions) 116 | { 117 | ReplaceAddInstructionWithConstant(binaryOperator); 118 | } 119 | 120 | auto preservedAnalyses = PreservedAnalyses::all(); 121 | preservedAnalyses.abandon(); 122 | return preservedAnalyses; 123 | } 124 | } // namespace 125 | 126 | // Register the passes 127 | extern "C" PassPluginLibraryInfo LLVM_ATTRIBUTE_WEAK llvmGetPassPluginInfo() 128 | { 129 | return {LLVM_PLUGIN_API_VERSION, "ConstantAdditionCombiner", "v0.1", [](PassBuilder& passBuilder) { 130 | passBuilder.registerAnalysisRegistrationCallback([](FunctionAnalysisManager& analysisManager) { 131 | analysisManager.registerPass([] { 132 | return ConstantAdditionAnalysis(); 133 | }); 134 | }); 135 | 136 | passBuilder.registerPipelineParsingCallback( 137 | [](StringRef name, FunctionPassManager& passManager, ArrayRef) { 138 | if (name == "constant-addition-printer") 139 | { 140 | passManager.addPass(ConstantAdditionPrinterPass(outs())); 141 | return true; 142 | } 143 | 144 | if (name == "constant-addition-combiner") 145 | { 146 | passManager.addPass(ConstantAdditionCombinerPass()); 147 | return true; 148 | } 149 | 150 | return false; 151 | }); 152 | }}; 153 | } 154 | -------------------------------------------------------------------------------- /llvm/lib/Transforms/RunTimeFunctionCallCounter/RunTimeFunctionCallCounter.cpp: -------------------------------------------------------------------------------- 1 | // RunTimeFunctionCallCounter.cpp 2 | 3 | #include "llvm/IR/IRBuilder.h" 4 | #include "llvm/IR/PassManager.h" 5 | #include "llvm/Passes/PassBuilder.h" 6 | #include "llvm/Passes/PassPlugin.h" 7 | #include "llvm/Transforms/Utils/ModuleUtils.h" 8 | 9 | #include 10 | #include 11 | 12 | using namespace llvm; 13 | 14 | #define DEBUG_TYPE "runtime-function-call-counter" 15 | 16 | namespace helper 17 | { 18 | Constant* CreateGlobalVariable(Module& module, StringRef globalVariableName); 19 | bool CountFunctionCallsInModule(Module& module); 20 | } // namespace helper 21 | 22 | // A LLVM Pass to count the function calls at runtime 23 | class RunTimeFunctionCallCounter : public PassInfoMixin 24 | { 25 | public: 26 | 27 | PreservedAnalyses run(Module& module, ModuleAnalysisManager&) 28 | { 29 | bool changed = helper::CountFunctionCallsInModule(module); 30 | return changed ? PreservedAnalyses::none() : PreservedAnalyses::all(); 31 | } 32 | }; 33 | 34 | // Pass registration 35 | extern "C" LLVM_ATTRIBUTE_WEAK ::PassPluginLibraryInfo llvmGetPassPluginInfo() 36 | { 37 | return { 38 | LLVM_PLUGIN_API_VERSION, "Run-Time Function Call Counter", LLVM_VERSION_STRING, [](PassBuilder& passBuilder) { 39 | passBuilder.registerPipelineParsingCallback( 40 | [](StringRef name, ModulePassManager& passManager, ArrayRef) { 41 | if (name == "runtime-function-call-counter") 42 | { 43 | passManager.addPass(RunTimeFunctionCallCounter()); 44 | return true; 45 | } 46 | 47 | return false; 48 | }); 49 | }}; 50 | } 51 | 52 | Constant* helper::CreateGlobalVariable(Module& module, StringRef globalVariableName) 53 | { 54 | auto& context = module.getContext(); 55 | 56 | // This will insert a declaration into module 57 | Constant* newGlobalVariable = module.getOrInsertGlobal(globalVariableName, IntegerType::getInt32Ty(context)); 58 | 59 | // This will change the declaration into definition (and initialize to 0) 60 | GlobalVariable* initializedGlobalVariable = module.getNamedGlobal(globalVariableName); 61 | initializedGlobalVariable->setLinkage(GlobalValue::CommonLinkage); 62 | initializedGlobalVariable->setAlignment(MaybeAlign(4)); 63 | initializedGlobalVariable->setInitializer(ConstantInt::get(context, APInt(32, 0))); 64 | 65 | return newGlobalVariable; 66 | } 67 | 68 | bool helper::CountFunctionCallsInModule(Module& module) 69 | { 70 | auto& context = module.getContext(); 71 | 72 | // Function name to IR variable map that holds the call counters 73 | StringMap callCounterMap; 74 | 75 | // Function name to IR variable map that holds the function names 76 | StringMap functionNameMap; 77 | 78 | // Step 1. For each function in the module, inject the code for call-counting 79 | for (Function& function : module) 80 | { 81 | if (function.isDeclaration()) 82 | { 83 | continue; 84 | } 85 | 86 | // Get an IR builder and set the insertion point to the top of the function 87 | IRBuilder<> counterBuilder(&*function.getEntryBlock().getFirstInsertionPt()); 88 | 89 | // Create a global variable to count the calls to this function 90 | std::string counterName = "counter_" + function.getName().str(); 91 | Constant* counterVariable = helper::CreateGlobalVariable(module, counterName); 92 | callCounterMap[function.getName()] = counterVariable; 93 | 94 | // Create a global variable to hold the name of this function 95 | Constant* functionName = counterBuilder.CreateGlobalStringPtr(function.getName(), "name_" + function.getName()); 96 | functionNameMap[function.getName()] = functionName; 97 | 98 | // Inject instruction to increment the call count each time this function executes 99 | LoadInst* counteCurrentValue = counterBuilder.CreateLoad(counterVariable); 100 | Value* counterNextValue = counterBuilder.CreateAdd(counterBuilder.getInt32(1), counteCurrentValue); 101 | counterBuilder.CreateStore(counterNextValue, counterVariable); 102 | 103 | // Let the opt tool print out some debug information 104 | // (Visible only if we pass "-debug" to the command and have an assert build.) 105 | LLVM_DEBUG(dbgs() << "Instrumented: " << function.getName() << "\n"); 106 | } 107 | 108 | // Stop here if there is no function definition in this module 109 | if (callCounterMap.size() == 0) 110 | { 111 | return false; 112 | } 113 | 114 | // Step 2. Inject the declaration of "printf()" 115 | // 116 | // Create (or get) the following declaration in the IR module: 117 | // declare i32 @printf(i8*, ...) 118 | // 119 | // It corresponds to the following C declaration: 120 | // int printf(char*, ...) 121 | PointerType* printfArgType = PointerType::getUnqual(Type::getInt8Ty(context)); 122 | FunctionType* printfFunctionType = FunctionType::get(IntegerType::getInt32Ty(context), 123 | printfArgType, 124 | /*IsVarArgs=*/true); 125 | FunctionCallee printfCallee = module.getOrInsertFunction("printf", printfFunctionType); 126 | 127 | // Step 3. Inject a global variable that will hold the printf format string 128 | Constant* formatString = ConstantDataArray::getString(context, "Function: %s, called %d times\n"); 129 | Constant* formatStringVariable = module.getOrInsertGlobal("", formatString->getType()); 130 | dyn_cast(formatStringVariable)->setInitializer(formatString); 131 | 132 | // Step 4. Define a printf wrapper that will print the results 133 | // 134 | // Define `PrintfWrapper` that will print the results stored in functionNameMap 135 | // and callCounterMap. It is equivalent to the following C++ function: 136 | // ``` 137 | // void PrintfWrapper() 138 | // { 139 | // for (auto &item : functions) 140 | // { 141 | // printf("Function: %s, called %d times\n", item.name, item.count); 142 | // } 143 | // } 144 | // ``` 145 | // ("item.name" comes from functionNameMap, "item.count" comes from callCounterMap.) 146 | FunctionType* printfWrapperType = FunctionType::get(Type::getVoidTy(context), 147 | {}, 148 | /*IsVarArgs=*/false); 149 | Function* printfWrapperFunction = 150 | dyn_cast(module.getOrInsertFunction("PrintfWrapper", printfWrapperType).getCallee()); 151 | BasicBlock* enterBlock = BasicBlock::Create(context, "enter", printfWrapperFunction); 152 | IRBuilder<> printfWrapperBuilder(enterBlock); 153 | 154 | Value* formatStringPtr = printfWrapperBuilder.CreatePointerCast(formatStringVariable, printfArgType); 155 | for (auto& item : callCounterMap) 156 | { 157 | Constant* functionName = functionNameMap[item.first()]; 158 | LoadInst* counterValue = printfWrapperBuilder.CreateLoad(item.second); 159 | printfWrapperBuilder.CreateCall(printfCallee, {formatStringPtr, functionName, counterValue}); 160 | } 161 | 162 | printfWrapperBuilder.CreateRetVoid(); 163 | 164 | // Step 5. Call `PrintfWrapper` at the very end of this module 165 | appendToGlobalDtors(module, printfWrapperFunction, /*Priority=*/0); 166 | 167 | return true; 168 | } 169 | --------------------------------------------------------------------------------