├── .clang-format ├── .clang-tidy ├── .github └── workflows │ ├── build.yml │ └── website.yml ├── .gitignore ├── Assignment0-Introduction_to_Docker ├── Dockerfile └── README.md ├── Assignment1-Introduction_to_LLVM ├── FunctionInfo │ ├── .gitignore │ ├── CMakeLists.txt │ ├── Makefile │ ├── lib │ │ ├── CMakeLists.txt │ │ └── FunctionInfo.cpp │ └── test │ │ ├── CMakeLists.txt │ │ ├── Fibonacci.c │ │ ├── Loop.c │ │ └── lit.cfg.in.py ├── LocalOpts │ ├── CMakeLists.txt │ ├── lib │ │ ├── 1-AlgebraicIdentity.cpp │ │ ├── 2-StrengthReduction.cpp │ │ ├── 3-MultiInstOpt.cpp │ │ ├── CMakeLists.txt │ │ ├── LocalOpts.cpp │ │ └── LocalOpts.h │ └── test │ │ ├── CMakeLists.txt │ │ ├── TestCase1.ll │ │ ├── TestCase2.ll │ │ ├── TestCaseBasic.ll │ │ └── lit.cfg.in.py └── README.md ├── Assignment2-Dataflow_Analysis ├── CMakeLists.txt ├── README.md ├── include │ ├── DFA │ │ ├── Domain │ │ │ ├── Base.h │ │ │ ├── Expression.h │ │ │ └── Variable.h │ │ ├── Flow │ │ │ ├── BackwardAnalysis.h │ │ │ ├── ForwardAnalysis.h │ │ │ └── Framework.h │ │ └── MeetOp.h │ └── Utility.h ├── lib │ ├── 1-AvailExprs.cpp │ ├── 2-Liveness.cpp │ ├── 3-SCCP.cpp │ ├── 4-LCM │ │ ├── 1-AnticipatedExprs.cpp │ │ ├── 2-WBAvailExprs.cpp │ │ ├── 3-EarliestPlacement.cpp │ │ ├── 4-PostponableExprs.cpp │ │ ├── 5-LatestPlacement.cpp │ │ ├── 6-UsedExprs.cpp │ │ └── LCM.h │ ├── CMakeLists.txt │ ├── DFA.cpp │ ├── DFA.h │ └── DFA │ │ └── Domain │ │ ├── Expression.cpp │ │ └── Variable.cpp └── test │ ├── 1-AvailExpr.ll │ ├── 2-Liveness.ll │ ├── 3-SCCP.ll │ ├── 4-LCM.ll │ ├── CMakeLists.txt │ └── lit.cfg.in.py ├── Assignment3-Loop_Invariant_Code_Motion ├── CMakeLists.txt ├── README.md ├── lib │ ├── CMakeLists.txt │ ├── LICM.cpp │ └── RegAllocIntfGraph.cpp └── test │ ├── CMakeLists.txt │ ├── LICM.ll │ ├── RegAlloc.c │ └── lit.cfg.in.py ├── README.md ├── Tools ├── C_to_LLVM_IR │ ├── .gitignore │ ├── C_to_LLVM_IR.sh │ └── main.c └── README.md ├── Tutorial01-Introduction_to_LLVM ├── Example1-Cpp_Fundamentals │ ├── .gitignore │ ├── 1-VarReference.cpp │ ├── 2-PublicInheritance.cpp │ ├── 3-STL.cpp │ └── Makefile └── README.md ├── Tutorial02-Introduction_to_LLVM_ii ├── Example1-Transform_Pass_Example │ ├── CMakeLists.txt │ ├── lib │ │ ├── CMakeLists.txt │ │ └── Transform.cpp │ └── test │ │ ├── CMakeLists.txt │ │ ├── Foo.ll │ │ └── lit.cfg.in.py ├── Example2-Pass_Manager │ ├── CMakeLists.txt │ ├── lib │ │ ├── CMakeLists.txt │ │ └── PassManager.cpp │ └── test │ │ ├── CMakeLists.txt │ │ ├── Foo.c │ │ └── lit.cfg.in.py └── README.md ├── Tutorial03-Dataflow_Analysis └── README.md ├── Tutorial04-Dataflow_Analysis_ii └── README.md ├── Tutorial05-Lazy_Code_Motion └── README.md ├── Tutorial06-Scalar_Evolution ├── CMakeLists.txt ├── README.md ├── lib │ ├── CMakeLists.txt │ └── SCEV.cpp └── test │ ├── CMakeLists.txt │ ├── Foo.c │ └── lit.cfg.in.py ├── Tutorial07-Register_Allocation ├── CMakeLists.txt ├── RAGreedy.png ├── RAMinimal.png ├── README.md ├── lib │ ├── CMakeLists.txt │ ├── Logging.h │ └── RegAllocMinimal.cpp └── test │ ├── CMakeLists.txt │ ├── Foo.c │ └── lit.cfg.in.py ├── Tutorial10-Data_Dependency_Analysis └── README.md ├── Website ├── Assignments │ ├── 0.md │ ├── 1.md │ ├── 2.md │ ├── 3.md │ └── index.rst ├── Doxygen │ ├── CMakeLists.txt │ └── doxygen.cfg.in ├── Lecture_Slides │ ├── CSCD70-Machine_Learning_Compilers-20230320.pdf │ ├── CSCD70-Machine_Learning_Compilers-20230320.pptx │ ├── Lecture 1 [Intro] 01.09.2023.pptx │ ├── Lecture 10 [Parallelization] 04.03.2023.pptx │ ├── Lecture 2 [Dataflow] 01.16.2023.pptx │ ├── Lecture 3 [Dataflow-2 and Loops] 01.23.2023.pptx │ ├── Lecture 4 [SSA] 01.30.2023.pptx │ ├── Lecture 5 [LICM and Strength Reduction] 02.06.2023.pptx │ ├── Lecture 6 [Register Allocation] 02.13.2023.pptx │ ├── Lecture 7 [Pointer Analysis] 02.27.2023.pptx │ └── Lecture 8 [Memory Optimizations] 03.13.2023.pptx ├── Makefile ├── Slides.rst ├── Tutorial_Slide_Hdr.tex ├── _templates │ ├── indexsidebar.html │ └── layout.html ├── conf.py └── index.rst └── docker-compose.yml /.clang-format: -------------------------------------------------------------------------------- 1 | BasedOnStyle: LLVM 2 | -------------------------------------------------------------------------------- /.clang-tidy: -------------------------------------------------------------------------------- 1 | Checks: '-*,clang-diagnostic-*,llvm-*,misc-*,-misc-const-correctness,-misc-unused-parameters,-misc-non-private-member-variables-in-classes,-misc-no-recursion,readability-identifier-naming' 2 | CheckOptions: 3 | - key: readability-identifier-naming.ClassCase 4 | value: CamelCase 5 | - key: readability-identifier-naming.EnumCase 6 | value: CamelCase 7 | - key: readability-identifier-naming.FunctionCase 8 | value: camelBack 9 | # Exclude from scanning as this is an exported symbol used for fuzzing 10 | # throughout the code base. 11 | - key: readability-identifier-naming.FunctionIgnoredRegexp 12 | value: "LLVMFuzzerTestOneInput" 13 | - key: readability-identifier-naming.MemberCase 14 | value: CamelCase 15 | - key: readability-identifier-naming.ParameterCase 16 | value: CamelCase 17 | - key: readability-identifier-naming.UnionCase 18 | value: CamelCase 19 | - key: readability-identifier-naming.VariableCase 20 | value: CamelCase 21 | - key: readability-identifier-naming.IgnoreMainLikeFunctions 22 | value: 1 23 | - key: readability-redundant-member-init.IgnoreBaseInCopyConstructors 24 | value: 1 25 | - key: modernize-use-default-member-init.UseAssignment 26 | value: 1 27 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: build 2 | 3 | on: [push] 4 | 5 | jobs: 6 | build: 7 | runs-on: ubuntu-latest 8 | env: 9 | CMAKE_BUILD_AND_TEST: "mkdir -p build && cd build; cmake ..; make; ctest -V" 10 | steps: 11 | - uses: actions/checkout@master 12 | - name: Assignment 0 Introduction to Docker 13 | run: docker-compose build dev 14 | - name: Assignment 1 Introduction to LLVM 15 | run: | 16 | docker-compose run --rm \ 17 | -w /mnt/Assignment1-Introduction_to_LLVM/FunctionInfo \ 18 | dev bash -ce "${CMAKE_BUILD_AND_TEST}" 19 | docker-compose run --rm \ 20 | -w /mnt/Assignment1-Introduction_to_LLVM/LocalOpts \ 21 | dev bash -ce "${CMAKE_BUILD_AND_TEST}" 22 | - name: Assignment 2 Dataflow Analysis 23 | run: | 24 | docker-compose run --rm \ 25 | -w /mnt/Assignment2-Dataflow_Analysis \ 26 | dev bash -ce "${CMAKE_BUILD_AND_TEST}" 27 | - name: C to LLVM IR 28 | run: docker-compose run --rm -w /mnt/Tools/C_to_LLVM_IR dev bash -ce "./C_to_LLVM_IR.sh -p=mem2reg" 29 | - name: Tutorial 1 Introduction to LLVM 30 | run: | 31 | docker-compose run --rm \ 32 | -w /mnt/Tutorial01-Introduction_to_LLVM/Example1-Cpp_Fundamentals \ 33 | dev bash -ce "make && ./1-VarReference && ./2-PublicInheritance && ./3-STL" 34 | - name: Tutorial 2 Introduction to LLVM ii 35 | run: | 36 | docker-compose run --rm \ 37 | -w /mnt/Tutorial02-Introduction_to_LLVM_ii/Example1-Transform_Pass_Example \ 38 | dev bash -ce "${CMAKE_BUILD_AND_TEST}" 39 | docker-compose run --rm \ 40 | -w /mnt/Tutorial02-Introduction_to_LLVM_ii/Example2-Pass_Manager \ 41 | dev bash -ce "${CMAKE_BUILD_AND_TEST}" 42 | - name: Tutorial 6 Scalar Evolution 43 | run: | 44 | docker-compose run --rm \ 45 | -w /mnt/Tutorial06-Scalar_Evolution \ 46 | dev bash -ce "${CMAKE_BUILD_AND_TEST}" 47 | - name: Tutorial 7 Register Allocation 48 | run: | 49 | docker-compose run --rm \ 50 | -w /mnt/Tutorial07-Register_Allocation \ 51 | dev bash -ce "${CMAKE_BUILD_AND_TEST}" 52 | -------------------------------------------------------------------------------- /.github/workflows/website.yml: -------------------------------------------------------------------------------- 1 | name: website 2 | 3 | on: [push] 4 | 5 | jobs: 6 | build: 7 | runs-on: ubuntu-latest 8 | steps: 9 | - uses: actions/checkout@master 10 | with: 11 | persist-credentials: false 12 | - name: Sphinx 13 | run: | 14 | sudo apt-get install -y python3-setuptools \ 15 | doxygen graphviz 16 | sudo -H pip3 install sphinx sphinxemoji recommonmark 17 | - name: Build 18 | run: | 19 | cd Website 20 | make html 21 | cd build/html 22 | mkdir -p Doxygen_build && cd Doxygen_build 23 | cmake ../../../Doxygen && make && mv html ../Doxygen 24 | cd .. 25 | touch .nojekyll 26 | - name: Publish 27 | uses: JamesIves/github-pages-deploy-action@v4.4.1 28 | with: 29 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 30 | BRANCH: gh-pages 31 | FOLDER: Website/build/html 32 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | 3 | # Build Artifacts 4 | build 5 | *.o 6 | *.bc 7 | *.so 8 | 9 | # IDE 10 | .vscode 11 | -------------------------------------------------------------------------------- /Assignment0-Introduction_to_Docker/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:22.04 2 | 3 | ENV LLVM_VERSION=16 4 | 5 | RUN sed -i 's/#force_color_prompt=yes/force_color_prompt=yes/' ~/.bashrc 6 | 7 | RUN apt-get update && \ 8 | env DEBIAN_FRONTEND=noninteractive \ 9 | apt-get install -y vim \ 10 | git \ 11 | build-essential \ 12 | python3-dev \ 13 | python-is-python3 \ 14 | wget \ 15 | ca-certificates \ 16 | lsb-release \ 17 | software-properties-common \ 18 | gpg-agent \ 19 | doxygen \ 20 | graphviz && \ 21 | rm -rf /var/lib/apt/lists/* 22 | 23 | RUN git config --global user.name "ubuntu" && \ 24 | git config --global user.email "ubuntu@cs.toronto.edu" && \ 25 | git config --global --add safe.directory "*" 26 | 27 | RUN wget https://apt.llvm.org/llvm.sh && \ 28 | chmod +x llvm.sh && \ 29 | ./llvm.sh ${LLVM_VERSION} all && \ 30 | rm llvm.sh && \ 31 | rm -rf /var/lib/apt/lists/* 32 | 33 | RUN wget https://bootstrap.pypa.io/get-pip.py && \ 34 | python3 get-pip.py && rm -f get-pip.py 35 | 36 | RUN pip3 install lit==15.0.6 cmake 37 | -------------------------------------------------------------------------------- /Assignment0-Introduction_to_Docker/README.md: -------------------------------------------------------------------------------- 1 | # Assignment 0 Introduction to Docker 2 | 3 | Please feel free to skip this section if you are working on the MathLab machines 4 | @`mathlab.utsc.utoronto.ca` as they already have all the necessary software 5 | components installed. 6 | 7 | ## Introduction 8 | 9 | Docker runs our applications in a *lightweight* **container** by using the 10 | **image** that has all the necessary software components installed. Think of it 11 | as `conda` or `virtualenv` (both are used to as an containerized Python 12 | environment), but at a broader scope for almost all software libraries. Compared 13 | with the virtual machines, Docker has negligible performance overhead, making 14 | itself an ideal solution for software development. 15 | 16 | ## Instructions 17 | 18 | ### Docker 19 | 20 | - **Download and Install Docker**: 21 | [Windows](https://hub.docker.com/editions/community/docker-ce-desktop-windows), 22 | [Mac](https://hub.docker.com/editions/community/docker-ce-desktop-mac), 23 | [Ubuntu](https://docs.docker.com/install/linux/docker-ce/ubuntu/) 24 | - **Build the Docker image**: 25 | - An **image** is an isolated environment that includes all necessary software 26 | components. 27 | ```Bash 28 | # Build the docker image from file Dockerfile and tag (-t) it with name `cscd70:2023S`. 29 | cd Assignment0-Introduction_to_Docker 30 | docker build . -t cscd70:2023S 31 | ``` 32 | - **Create a Docker container**: 33 | - A **container** is an instantiation of an image. Multiple containers can be 34 | created out of the same image. 35 | ```Bash 36 | # Create a container for the first assignment. 37 | cd Assignment1-Introduction_to_LLVM/FunctionInfo 38 | docker run -it -v $(pwd):/mnt --rm --name cscd70_a1 cscd70:2023S 39 | ``` 40 | - `-t`: Allocate a pseudo terminal; `-i`: Connect to STDIN (i.e., keyboard). 41 | `-it` must be used jointly for an interactive bash shell. 42 | - `-v`: Mount the current working directory (i.e., `FunctionInfo`) to `/mnt` 43 | in the container. Any changes made to the mounted directory outside the 44 | container will be reflected in the container as well (and vice versa). The 45 | mounted directory must be in **absolute path**. 46 | - `--rm`: \[Optional\] Automatically clean the container when we exit. 47 | - `--name`: \[Optional\] Name of the container 48 | - The image name (i.e., `cscd70:2023S`) should always come last. 49 | 50 | - **Run the experiments**: 51 | ```Bash 52 | cd /mnt 53 | mkdir build && cd build 54 | cmake .. && make 55 | ``` 56 | 57 | ### Docker-Compose 58 | 59 | Docker-Compose is a simple wrapper on top of the docker commands. There is a 60 | docker-compose file provided in the root folder of this repository. We can do 61 | the same things as we have previously described, but much simpler: 62 | 63 | ```Bash 64 | # Install docker-compose via python-pip. 65 | pip3 install docker-compose 66 | 67 | docker-compose build dev # Build the image. 68 | docker-compose run --rm dev # Create a container. 69 | ``` 70 | -------------------------------------------------------------------------------- /Assignment1-Introduction_to_LLVM/FunctionInfo/.gitignore: -------------------------------------------------------------------------------- 1 | test/Loop.ll 2 | -------------------------------------------------------------------------------- /Assignment1-Introduction_to_LLVM/FunctionInfo/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.18.4) 2 | project(FunctionInfo) 3 | set(CMAKE_EXPORT_COMPILE_COMMANDS ON) 4 | 5 | set(LLVM_VERSION 6 | "16" 7 | CACHE STRING "LLVM Version") 8 | 9 | # Obtain the build flags from `llvm-config --cxxflags` and forward them to 10 | # variable CMAKE_CXX_FLAGS. 11 | execute_process( 12 | COMMAND llvm-config-${LLVM_VERSION} --cxxflags 13 | OUTPUT_VARIABLE LLVM_CXXFLAGS 14 | OUTPUT_STRIP_TRAILING_WHITESPACE) 15 | set(CMAKE_CXX_FLAGS "${LLVM_CXXFLAGS}") 16 | if(NOT CMAKE_BUILD_TYPE OR CMAKE_BUILD_TYPE STREQUAL "Debug") 17 | set(CMAKE_CXX_CLANG_TIDY 18 | "clang-tidy-${LLVM_VERSION};--extra-arg-before=-stdlib=libc++") 19 | message(STATUS "Enabling clang-tidy") 20 | 21 | execute_process( 22 | COMMAND llvm-config-${LLVM_VERSION} --includedir 23 | OUTPUT_VARIABLE LLVM_INCLUDEDIR 24 | OUTPUT_STRIP_TRAILING_WHITESPACE) 25 | set(CMAKE_CXX_FLAGS 26 | "${CMAKE_CXX_FLAGS} -isystem ${LLVM_INCLUDEDIR} -Wall -Wextra -Werror") 27 | endif() 28 | 29 | add_subdirectory(lib) 30 | 31 | include(CTest) 32 | enable_testing() 33 | add_subdirectory(test) 34 | -------------------------------------------------------------------------------- /Assignment1-Introduction_to_LLVM/FunctionInfo/Makefile: -------------------------------------------------------------------------------- 1 | OPTIMIZER := libFunctionInfo.so 2 | OBJs := $(subst .cpp,.o,$(wildcard lib/*.cpp)) 3 | 4 | LLVM_VERSION ?= 16 5 | 6 | CXXFLAGS := $(shell llvm-config-$(LLVM_VERSION) --cxxflags) -fPIC 7 | 8 | all: $(OPTIMIZER) 9 | 10 | $(OPTIMIZER): $(OBJs) 11 | $(CXX) -dylib -shared $^ -o $@ 12 | 13 | .PHONY: clean 14 | clean: 15 | $(RM) $(OPTIMIZER) $(OBJs) 16 | -------------------------------------------------------------------------------- /Assignment1-Introduction_to_LLVM/FunctionInfo/lib/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_library(FunctionInfo SHARED FunctionInfo.cpp) 2 | -------------------------------------------------------------------------------- /Assignment1-Introduction_to_LLVM/FunctionInfo/lib/FunctionInfo.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace llvm; 6 | 7 | namespace { 8 | 9 | class FunctionInfoPass final : public PassInfoMixin { 10 | public: 11 | PreservedAnalyses run([[maybe_unused]] Module &M, ModuleAnalysisManager &) { 12 | outs() << "CSCD70 Function Information Pass" 13 | << "\n"; 14 | 15 | /// @todo(CSCD70) Please complete this method. 16 | 17 | return PreservedAnalyses::all(); 18 | } 19 | }; // class FunctionInfoPass 20 | 21 | } // anonymous namespace 22 | 23 | extern "C" PassPluginLibraryInfo llvmGetPassPluginInfo() { 24 | return { 25 | .APIVersion = LLVM_PLUGIN_API_VERSION, 26 | .PluginName = "FunctionInfo", 27 | .PluginVersion = LLVM_VERSION_STRING, 28 | .RegisterPassBuilderCallbacks = 29 | [](PassBuilder &PB) { 30 | PB.registerPipelineParsingCallback( 31 | [](StringRef Name, ModulePassManager &MPM, 32 | ArrayRef) -> bool { 33 | if (Name == "function-info") { 34 | MPM.addPass(FunctionInfoPass()); 35 | return true; 36 | } 37 | return false; 38 | }); 39 | } // RegisterPassBuilderCallbacks 40 | }; // struct PassPluginLibraryInfo 41 | } 42 | -------------------------------------------------------------------------------- /Assignment1-Introduction_to_LLVM/FunctionInfo/test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | execute_process( 2 | COMMAND llvm-config-${LLVM_VERSION} --bindir 3 | OUTPUT_VARIABLE LLVM_BINDIR 4 | OUTPUT_STRIP_TRAILING_WHITESPACE) 5 | set(CMAKE_LIBRARY_OUTPUT_DIR "${CMAKE_BINARY_DIR}/lib") 6 | 7 | # Configure file lit.cfg.in.py and output to lit.cfg.py. When configuring, all 8 | # variables in the form of @var@ will be replaced by their respective value. 9 | configure_file(lit.cfg.in.py lit.cfg.py @ONLY) 10 | 11 | add_test(NAME FunctionInfoTest COMMAND lit -a ${CMAKE_CURRENT_BINARY_DIR}) 12 | -------------------------------------------------------------------------------- /Assignment1-Introduction_to_LLVM/FunctionInfo/test/Fibonacci.c: -------------------------------------------------------------------------------- 1 | // clang-format off 2 | // RUN: clang -O2 -S -emit-llvm -c %s -o %basename_t.ll 3 | // RUN: opt -load-pass-plugin=%dylibdir/libFunctionInfo.so -passes=function-info -disable-output %basename_t.ll 2>&1 | \ 4 | // RUN: FileCheck --match-full-lines --check-prefix=SAMPLE %s 5 | // clang-format on 6 | /// @todo(CSCD70) Please Remove the `--check-prefix=SAMPLE` option and add the 7 | /// CHECK directives similar to those in Loop.c. 8 | // SAMPLE: CSCD70 Function Information Pass 9 | #include 10 | #include 11 | 12 | int printf(const char *format, ...) { 13 | int ret; 14 | va_list args; 15 | va_start(args, format); 16 | ret = vfprintf(stdout, format, args); 17 | va_end(args); 18 | 19 | return ret; 20 | } 21 | 22 | int Fibonacci(const int n) { 23 | if (n == 0) { 24 | printf("f(0) = 0"); 25 | return 0; 26 | } 27 | if (n == 1) { 28 | printf("f(1) = 1"); 29 | return 1; 30 | } 31 | printf("f(%d) = f(%d) + f(%d)", n, n - 1, n - 2); 32 | return Fibonacci(n - 1) + Fibonacci(n - 2); 33 | } 34 | -------------------------------------------------------------------------------- /Assignment1-Introduction_to_LLVM/FunctionInfo/test/Loop.c: -------------------------------------------------------------------------------- 1 | // clang-format off 2 | // Compile the test case into assembly. 3 | // RUN: clang -O2 -S -emit-llvm -c %s -o %basename_t.ll 4 | // Run the FunctionInfo pass. The `-disable-output` option disables 5 | // outputting the bytecode because we are only checking the pass outputs 6 | // here. 7 | // RUN: opt -load-pass-plugin=%dylibdir/libFunctionInfo.so -passes=function-info -disable-output %basename_t.ll 2>&1 | \ 8 | // Check the output "CSCD70 Function Information Pass". 9 | // RUN: FileCheck --match-full-lines --check-prefix=SAMPLE %s 10 | // clang-format on 11 | /// @todo(CSCD70) Please remove the `--check-prefix=SAMPLE` option. 12 | // SAMPLE: CSCD70 Function Information Pass 13 | 14 | int g; 15 | 16 | // CHECK-LABEL: Function Name: g_incr 17 | // CHECK-NEXT: Number of Arguments: 1 18 | // CHECK-NEXT: Number of Calls: 0 19 | // CHECK-NEXT: Number OF BBs: 1 20 | // CHECK-NEXT: Number of Instructions: 4 21 | int g_incr(int c) { 22 | g += c; 23 | return g; 24 | } 25 | 26 | // CHECK-LABEL: Function Name: loop 27 | // CHECK-NEXT: Number of Arguments: 3 28 | // CHECK-NEXT: Number of Calls: 0 29 | // CHECK-NEXT: Number OF BBs: 3 30 | // CHECK-NEXT: Number of Instructions: 10 31 | int loop(int a, int b, int c) { 32 | int i, ret = 0; 33 | 34 | for (i = a; i < b; i++) { 35 | g_incr(c); 36 | } 37 | 38 | return ret + g; 39 | } 40 | -------------------------------------------------------------------------------- /Assignment1-Introduction_to_LLVM/FunctionInfo/test/lit.cfg.in.py: -------------------------------------------------------------------------------- 1 | # *lit* is the LLVM integrated tester. Please visit 2 | # 3 | # https://llvm.org/docs/CommandGuide/lit.html 4 | # 5 | # for its documentation. 6 | import lit 7 | import lit.llvm 8 | 9 | lit.llvm.initialize(lit_config, config) 10 | 11 | from lit.llvm import llvm_config 12 | 13 | 14 | config.name = "@CMAKE_PROJECT_NAME@" 15 | # The ShTest files contain some number of shell-like command pipelines, along 16 | # with assertions about what should be in the output. 17 | config.test_format = lit.formats.ShTest() 18 | config.test_source_root = "@CMAKE_CURRENT_SOURCE_DIR@" 19 | config.test_exec_root = "@CMAKE_CURRENT_BINARY_DIR@" 20 | config.suffixes = [".c", ".ll"] 21 | 22 | config.substitutions.append((r"%dylibdir", "@CMAKE_LIBRARY_OUTPUT_DIR@")) 23 | 24 | # Extra config attributes for the tool substitution. 25 | config.llvm_config_bindir = "@LLVM_BINDIR@" 26 | llvm_config.add_tool_substitutions( 27 | ["clang", "opt", "FileCheck"], config.llvm_config_bindir 28 | ) 29 | -------------------------------------------------------------------------------- /Assignment1-Introduction_to_LLVM/LocalOpts/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.18.4) 2 | project(LocalOpts) 3 | set(CMAKE_EXPORT_COMPILE_COMMANDS ON) 4 | 5 | set(LLVM_VERSION 6 | "16" 7 | CACHE STRING "LLVM Version") 8 | 9 | execute_process( 10 | COMMAND llvm-config-${LLVM_VERSION} --cxxflags 11 | OUTPUT_VARIABLE LLVM_CXXFLAGS 12 | OUTPUT_STRIP_TRAILING_WHITESPACE) 13 | set(CMAKE_CXX_FLAGS "${LLVM_CXXFLAGS}") 14 | if(NOT CMAKE_BUILD_TYPE OR CMAKE_BUILD_TYPE STREQUAL "Debug") 15 | set(CMAKE_CXX_CLANG_TIDY 16 | "clang-tidy-${LLVM_VERSION};--extra-arg-before=-stdlib=libc++") 17 | message(STATUS "Enabling clang-tidy") 18 | 19 | execute_process( 20 | COMMAND llvm-config-${LLVM_VERSION} --includedir 21 | OUTPUT_VARIABLE LLVM_INCLUDEDIR 22 | OUTPUT_STRIP_TRAILING_WHITESPACE) 23 | set(CMAKE_CXX_FLAGS 24 | "${CMAKE_CXX_FLAGS} -isystem ${LLVM_INCLUDEDIR} -Wall -Wextra -Werror") 25 | endif() 26 | 27 | add_subdirectory(lib) 28 | 29 | include(CTest) 30 | enable_testing() 31 | add_subdirectory(test) 32 | -------------------------------------------------------------------------------- /Assignment1-Introduction_to_LLVM/LocalOpts/lib/1-AlgebraicIdentity.cpp: -------------------------------------------------------------------------------- 1 | #include "LocalOpts.h" 2 | 3 | using namespace llvm; 4 | 5 | PreservedAnalyses AlgebraicIdentityPass::run([[maybe_unused]] Function &F, 6 | FunctionAnalysisManager &) { 7 | 8 | /// @todo(CSCD70) Please complete this method. 9 | 10 | return PreservedAnalyses::none(); 11 | } 12 | -------------------------------------------------------------------------------- /Assignment1-Introduction_to_LLVM/LocalOpts/lib/2-StrengthReduction.cpp: -------------------------------------------------------------------------------- 1 | #include "LocalOpts.h" 2 | 3 | using namespace llvm; 4 | 5 | PreservedAnalyses StrengthReductionPass::run([[maybe_unused]] Function &F, 6 | FunctionAnalysisManager &) { 7 | 8 | /// @todo(CSCD70) Please complete this method. 9 | 10 | return PreservedAnalyses::none(); 11 | } 12 | -------------------------------------------------------------------------------- /Assignment1-Introduction_to_LLVM/LocalOpts/lib/3-MultiInstOpt.cpp: -------------------------------------------------------------------------------- 1 | #include "LocalOpts.h" 2 | 3 | using namespace llvm; 4 | 5 | PreservedAnalyses MultiInstOptPass::run([[maybe_unused]] Function &F, 6 | FunctionAnalysisManager &) { 7 | 8 | /// @todo(CSCD70) Please complete this method. 9 | 10 | return PreservedAnalyses::none(); 11 | } 12 | -------------------------------------------------------------------------------- /Assignment1-Introduction_to_LLVM/LocalOpts/lib/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_library(LocalOpts SHARED 1-AlgebraicIdentity.cpp 2-StrengthReduction.cpp 2 | 3-MultiInstOpt.cpp LocalOpts.cpp) 3 | -------------------------------------------------------------------------------- /Assignment1-Introduction_to_LLVM/LocalOpts/lib/LocalOpts.cpp: -------------------------------------------------------------------------------- 1 | #include "LocalOpts.h" 2 | 3 | #include 4 | #include 5 | 6 | using namespace llvm; 7 | 8 | extern "C" PassPluginLibraryInfo llvmGetPassPluginInfo() { 9 | return { 10 | .APIVersion = LLVM_PLUGIN_API_VERSION, 11 | .PluginName = "LocalOpts", 12 | .PluginVersion = LLVM_VERSION_STRING, 13 | .RegisterPassBuilderCallbacks = 14 | [](PassBuilder &PB) { 15 | PB.registerPipelineParsingCallback( 16 | [](StringRef Name, FunctionPassManager &FPM, 17 | ArrayRef) -> bool { 18 | if (Name == "algebraic-identity") { 19 | FPM.addPass(AlgebraicIdentityPass()); 20 | return true; 21 | } 22 | if (Name == "strength-reduction") { 23 | FPM.addPass(StrengthReductionPass()); 24 | return true; 25 | } 26 | if (Name == "multi-inst-opt") { 27 | FPM.addPass(MultiInstOptPass()); 28 | return true; 29 | } 30 | return false; 31 | }); 32 | } // RegisterPassBuilderCallbacks 33 | }; // struct PassPluginLibraryInfo 34 | } 35 | -------------------------------------------------------------------------------- /Assignment1-Introduction_to_LLVM/LocalOpts/lib/LocalOpts.h: -------------------------------------------------------------------------------- 1 | #pragma once // NOLINT(llvm-header-guard) 2 | 3 | #include 4 | 5 | class AlgebraicIdentityPass final 6 | : public llvm::PassInfoMixin { 7 | public: 8 | llvm::PreservedAnalyses run(llvm::Function &, 9 | llvm::FunctionAnalysisManager &); 10 | }; // class AlgebraicIdentityPass 11 | 12 | class StrengthReductionPass final 13 | : public llvm::PassInfoMixin { 14 | public: 15 | llvm::PreservedAnalyses run(llvm::Function &, 16 | llvm::FunctionAnalysisManager &); 17 | }; // class StrengthReductionPass 18 | 19 | class MultiInstOptPass final : public llvm::PassInfoMixin { 20 | public: 21 | llvm::PreservedAnalyses run(llvm::Function &, 22 | llvm::FunctionAnalysisManager &); 23 | }; // class MultiInstOptPass 24 | -------------------------------------------------------------------------------- /Assignment1-Introduction_to_LLVM/LocalOpts/test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | execute_process( 2 | COMMAND llvm-config-${LLVM_VERSION} --bindir 3 | OUTPUT_VARIABLE LLVM_BINDIR 4 | OUTPUT_STRIP_TRAILING_WHITESPACE) 5 | set(CMAKE_LIBRARY_OUTPUT_DIR "${CMAKE_BINARY_DIR}/lib") 6 | 7 | configure_file(lit.cfg.in.py lit.cfg.py @ONLY) 8 | 9 | add_test(NAME LocalOptsTest COMMAND lit -a ${CMAKE_CURRENT_BINARY_DIR}) 10 | -------------------------------------------------------------------------------- /Assignment1-Introduction_to_LLVM/LocalOpts/test/TestCase1.ll: -------------------------------------------------------------------------------- 1 | ; RUN: opt -load-pass-plugin=%dylibdir/libLocalOpts.so \ 2 | ; RUN: -p=algebraic-identity,strength-reduction,multi-inst-opt \ 3 | ; RUN: -S %s -o %basename_t 4 | ; RUN: FileCheck --match-full-lines %s --input-file=%basename_t 5 | 6 | ; #include 7 | 8 | ; void foo(int a) { 9 | ; int r0 = a + 0; 10 | ; int r1 = r0 * 16; 11 | ; int r2 = r1 * r0; 12 | ; int r3 = r2 / a; 13 | ; int r4 = r2 / 10; 14 | ; int r5 = 54 * r3; 15 | ; int r6 = r4 / 128; 16 | ; int r7 = r5 / 54; 17 | ; int r8 = r4 / 1; 18 | ; int r9 = r7 - 0; 19 | ; printf("%d,%d,%d,%d,%d,%d,%d,%d,%d,%d\n", r0, r1, r2, r3, r4, r5, r6, r7, r8, 20 | ; r9); 21 | ; } 22 | 23 | @.str = private unnamed_addr constant [31 x i8] c"%d,%d,%d,%d,%d,%d,%d,%d,%d,%d\0A\00", align 1 24 | 25 | define dso_local void @foo(i32 noundef %0) { 26 | ; CHECK-LABEL: define dso_local void @foo(i32 noundef %0) { 27 | ; @todo(CSCD70) Please complete the CHECK directives. 28 | %2 = add nsw i32 %0, 0 29 | %3 = mul nsw i32 %2, 16 30 | %4 = mul nsw i32 %3, %2 31 | %5 = sdiv i32 %4, %0 32 | %6 = sdiv i32 %4, 10 33 | %7 = mul nsw i32 54, %5 34 | %8 = sdiv i32 %6, 128 35 | %9 = sdiv i32 %7, 54 36 | %10 = sdiv i32 %6, 1 37 | %11 = sub nsw i32 %9, 0 38 | %12 = call i32 (ptr, ...) @printf(ptr noundef @.str, i32 noundef %2, i32 noundef %3, i32 noundef %4, i32 noundef %5, i32 noundef %6, i32 noundef %7, i32 noundef %8, i32 noundef %9, i32 noundef %10, i32 noundef %11) 39 | ret void 40 | } 41 | 42 | declare i32 @printf(ptr noundef, ...) #1 43 | -------------------------------------------------------------------------------- /Assignment1-Introduction_to_LLVM/LocalOpts/test/TestCase2.ll: -------------------------------------------------------------------------------- 1 | ; RUN: opt -load-pass-plugin=%dylibdir/libLocalOpts.so \ 2 | ; RUN: -p=algebraic-identity,strength-reduction,multi-inst-opt \ 3 | ; RUN: -S %s -o %basename_t 4 | ; RUN: FileCheck --match-full-lines %s --input-file=%basename_t 5 | 6 | ; #include 7 | 8 | ; void foo(int a) { 9 | ; int r0 = a + 0; 10 | ; int r1 = r0 * 16; 11 | ; int r2 = 0, r3 = 0, r4 = 0, r5 = 0; 12 | ; if (a) { 13 | ; r2 = r1 * r0; 14 | ; r3 = r2 / a; 15 | ; } else { 16 | ; r4 = r2 / 10; 17 | ; r5 = 54 * r3; 18 | ; } 19 | ; int r6 = r1 / 16; 20 | ; int r7 = r5 / 54; 21 | ; int r8 = r4 / 1; 22 | ; int r9 = r7 - 0; 23 | ; printf("%d,%d,%d,%d,%d,%d,%d,%d,%d,%d\n", r0, r1, r2, r3, r4, r5, r6, r7, r8, 24 | ; r9); 25 | ; } 26 | 27 | @.str = private unnamed_addr constant [31 x i8] c"%d,%d,%d,%d,%d,%d,%d,%d,%d,%d\0A\00", align 1 28 | 29 | define dso_local void @foo(i32 noundef %0) { 30 | ; CHECK-LABEL: define dso_local void @foo(i32 noundef %0) { 31 | ; @todo(CSCD70) Please complete the CHECK directives. 32 | %2 = add nsw i32 %0, 0 33 | %3 = mul nsw i32 %2, 16 34 | %4 = icmp ne i32 %0, 0 35 | br i1 %4, label %5, label %8 36 | 37 | 5: ; preds = %1 38 | %6 = mul nsw i32 %3, %2 39 | %7 = sdiv i32 %6, %0 40 | br label %11 41 | 42 | 8: ; preds = %1 43 | %9 = sdiv i32 0, 10 44 | %10 = mul nsw i32 54, 0 45 | br label %11 46 | 47 | 11: ; preds = %8, %5 48 | %.03 = phi i32 [ %6, %5 ], [ 0, %8 ] 49 | %.02 = phi i32 [ %7, %5 ], [ 0, %8 ] 50 | %.01 = phi i32 [ 0, %5 ], [ %9, %8 ] 51 | %.0 = phi i32 [ 0, %5 ], [ %10, %8 ] 52 | %12 = sdiv i32 %3, 16 53 | %13 = sdiv i32 %.0, 54 54 | %14 = sdiv i32 %.01, 1 55 | %15 = sub nsw i32 %13, 0 56 | %16 = call i32 (ptr, ...) @printf(ptr noundef @.str, i32 noundef %2, i32 noundef %3, i32 noundef %.03, i32 noundef %.02, i32 noundef %.01, i32 noundef %.0, i32 noundef %12, i32 noundef %13, i32 noundef %14, i32 noundef %15) 57 | ret void 58 | } 59 | 60 | declare i32 @printf(ptr noundef, ...) 61 | -------------------------------------------------------------------------------- /Assignment1-Introduction_to_LLVM/LocalOpts/test/TestCaseBasic.ll: -------------------------------------------------------------------------------- 1 | ; RUN: opt -load-pass-plugin=%dylibdir/libLocalOpts.so \ 2 | ; RUN: -p=algebraic-identity,strength-reduction,multi-inst-opt \ 3 | ; RUN: -S %s -o %basename_t 4 | ; RUN: FileCheck --match-full-lines %s --input-file=%basename_t 5 | 6 | ; #include 7 | 8 | ; void AlgebraicIdentity(int a) { 9 | ; int r0 = a + 0; 10 | ; int r1 = 0 + a; 11 | ; int r2 = a * 1; 12 | ; int r3 = 1 * a; 13 | ; int r4 = a - 0; 14 | ; int r5 = a / 1; 15 | ; printf("%d,%d,%d,%d,%d,%d\n", r0, r1, r2, r3, r4, r5); 16 | ; } 17 | 18 | ; void StrengthReduction(int a) { 19 | ; int r0 = a * 2; 20 | ; int r1 = 64 * a; 21 | ; int r2 = a / 4; 22 | ; int r3 = a / 128; 23 | ; printf("%d,%d,%d,%d\n", r0, r1, r2, r3); 24 | ; } 25 | 26 | ; void MultiInstOpt(int a, int b) { 27 | ; int r0 = a + 3; 28 | ; int r1 = r0 - 3; 29 | ; int r2 = a + b; 30 | ; int r3 = r2 - b; 31 | ; printf("%d,%d,%d,%d\n", r0, r1, r2, r3); 32 | ; } 33 | 34 | @.str = private unnamed_addr constant [19 x i8] c"%d,%d,%d,%d,%d,%d\0A\00", align 1 35 | @.str.1 = private unnamed_addr constant [13 x i8] c"%d,%d,%d,%d\0A\00", align 1 36 | 37 | define dso_local void @AlgebraicIdentity(i32 noundef %0) { 38 | ; CHECK-LABEL: define dso_local void @AlgebraicIdentity(i32 noundef %0) { 39 | ; @todo(CSCD70) Please complete the CHECK directives. 40 | %2 = add nsw i32 %0, 0 41 | %3 = add nsw i32 0, %0 42 | %4 = mul nsw i32 %0, 1 43 | %5 = mul nsw i32 1, %0 44 | %6 = sub nsw i32 %0, 0 45 | %7 = sdiv i32 %0, 1 46 | %8 = call i32 (ptr, ...) @printf(ptr noundef @.str, i32 noundef %2, i32 noundef %3, i32 noundef %4, i32 noundef %5, i32 noundef %6, i32 noundef %7) 47 | ret void 48 | } 49 | 50 | define dso_local void @StrengthReduction(i32 noundef %0) { 51 | ; CHECK-LABEL: define dso_local void @StrengthReduction(i32 noundef %0) { 52 | ; @todo(CSCD70) Please complete the CHECK directives. 53 | %2 = mul nsw i32 %0, 2 54 | %3 = mul nsw i32 64, %0 55 | %4 = sdiv i32 %0, 4 56 | %5 = sdiv i32 %0, 128 57 | %6 = call i32 (ptr, ...) @printf(ptr noundef @.str.1, i32 noundef %2, i32 noundef %3, i32 noundef %4, i32 noundef %5) 58 | ret void 59 | } 60 | 61 | define dso_local void @MultiInstOpt(i32 noundef %0, i32 noundef %1) { 62 | ; CHECK-LABEL: define dso_local void @MultiInstOpt(i32 noundef %0, i32 noundef %1) { 63 | ; @todo(CSCD70) Please complete the CHECK directives. 64 | %3 = add nsw i32 %0, 3 65 | %4 = sub nsw i32 %3, 3 66 | %5 = add nsw i32 %0, %1 67 | %6 = sub nsw i32 %5, %1 68 | %7 = call i32 (ptr, ...) @printf(ptr noundef @.str.1, i32 noundef %3, i32 noundef %4, i32 noundef %5, i32 noundef %6) 69 | ret void 70 | } 71 | 72 | declare i32 @printf(ptr noundef, ...) 73 | -------------------------------------------------------------------------------- /Assignment1-Introduction_to_LLVM/LocalOpts/test/lit.cfg.in.py: -------------------------------------------------------------------------------- 1 | import lit 2 | import lit.llvm 3 | 4 | lit.llvm.initialize(lit_config, config) 5 | 6 | from lit.llvm import llvm_config 7 | 8 | 9 | config.name = "@CMAKE_PROJECT_NAME@" 10 | config.test_format = lit.formats.ShTest() 11 | config.test_source_root = "@CMAKE_CURRENT_SOURCE_DIR@" 12 | config.test_exec_root = "@CMAKE_CURRENT_BINARY_DIR@" 13 | config.suffixes = [".c", ".ll"] 14 | 15 | config.substitutions.append((r"%dylibdir", "@CMAKE_LIBRARY_OUTPUT_DIR@")) 16 | 17 | config.llvm_config_bindir = "@LLVM_BINDIR@" 18 | llvm_config.add_tool_substitutions(["opt", "FileCheck"], config.llvm_config_bindir) 19 | -------------------------------------------------------------------------------- /Assignment1-Introduction_to_LLVM/README.md: -------------------------------------------------------------------------------- 1 | # Assignment 1 Introduction to LLVM 2 | 3 | **Due Date**: Jan. 27th, **Handout**: 4 | [\[Overleaf\]](https://www.overleaf.com/read/nvmnmbntgwqn), **GitHub 5 | Classroom**: \[Invitation\] 6 | 7 | Please click on the links above for the assignment handout and the invitation to 8 | GitHub Classroom. Note that 9 | 10 | - The repository is initialized to be empty, so you will have to copy the files 11 | in this folder into your own repository. 12 | - TODO items have been marked using `todo(CSCD70)` in the source code. **These 13 | include both the optimization passes and the test cases.** Please make sure 14 | that you have completed both parts before submitting. 15 | -------------------------------------------------------------------------------- /Assignment2-Dataflow_Analysis/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.18.4) 2 | project(DFA) 3 | set(CMAKE_EXPORT_COMPILE_COMMANDS ON) 4 | 5 | set(LLVM_VERSION 6 | "16" 7 | CACHE STRING "LLVM Version") 8 | 9 | execute_process( 10 | COMMAND llvm-config-${LLVM_VERSION} --cxxflags 11 | OUTPUT_VARIABLE LLVM_CXXFLAGS 12 | OUTPUT_STRIP_TRAILING_WHITESPACE) 13 | execute_process( 14 | COMMAND llvm-config-${LLVM_VERSION} --includedir 15 | OUTPUT_VARIABLE LLVM_INCLUDEDIR 16 | OUTPUT_STRIP_TRAILING_WHITESPACE) 17 | set(CMAKE_CXX_FLAGS "${LLVM_CXXFLAGS} -isystem ${LLVM_INCLUDEDIR} -Wall") 18 | if(NOT CMAKE_BUILD_TYPE OR CMAKE_BUILD_TYPE STREQUAL "Debug") 19 | set(CMAKE_CXX_CLANG_TIDY 20 | "clang-tidy-${LLVM_VERSION};-header-filter=.*;--extra-arg-before=-stdlib=libc++" 21 | ) 22 | message(STATUS "Enabling clang-tidy") 23 | endif() 24 | include_directories(${CMAKE_SOURCE_DIR}/include) 25 | 26 | add_subdirectory(lib) 27 | 28 | include(CTest) 29 | enable_testing() 30 | add_subdirectory(test) 31 | -------------------------------------------------------------------------------- /Assignment2-Dataflow_Analysis/README.md: -------------------------------------------------------------------------------- 1 | # Assignment 2 Dataflow Analysis 2 | 3 | **Due Date**: Mar. 3rd, **Handout**: 4 | [\[Overleaf\]](https://www.overleaf.com/read/cncbrtszrfpx), **GitHub 5 | Classroom**: [\[Invitation\]](https://classroom.github.com/a/uifbknCz) 6 | 7 | Please click on the links above for the assignment handout and the invitation to 8 | GitHub Classroom. Note that 9 | 10 | - The repository is initialized to be empty, so you will have to copy the files 11 | in this folder into your own repository. 12 | - TODO items have been marked using `todo(CSCD70)` in the source code. **These 13 | include both the optimization passes and the test cases.** Please make sure 14 | that you have completed both parts before submitting. 15 | 16 | ## Changelog 17 | 18 | - `[2/6]`: Update the LCM test case with expression uses. 19 | -------------------------------------------------------------------------------- /Assignment2-Dataflow_Analysis/include/DFA/Domain/Base.h: -------------------------------------------------------------------------------- 1 | #pragma once // NOLINT(llvm-header-guard) 2 | 3 | #include 4 | #include 5 | 6 | namespace dfa { 7 | 8 | template struct DomainBase { 9 | virtual bool operator==(const TDerivedDomainElem &Other) const = 0; 10 | 11 | /// @brief Check whether the domain element contains the given value. 12 | /// @param Val 13 | /// @return 14 | virtual bool contain(const llvm::Value *const Val) const = 0; 15 | /// @brief Replace all the occurrences of the source value with the 16 | /// destination value. 17 | /// @param SrcVal 18 | /// @param DstVal 19 | /// @return 20 | virtual TDerivedDomainElem 21 | replaceValueWith(const llvm::Value *const SrcVal, 22 | const llvm::Value *const DstVal) const = 0; 23 | 24 | using DomainIdMap_t = std::unordered_map; 25 | using DomainVector_t = std::vector; 26 | }; 27 | 28 | } // namespace dfa 29 | -------------------------------------------------------------------------------- /Assignment2-Dataflow_Analysis/include/DFA/Domain/Expression.h: -------------------------------------------------------------------------------- 1 | #pragma once // NOLINT(llvm-header-guard) 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "Base.h" 10 | #include "Utility.h" 11 | 12 | namespace dfa { 13 | 14 | struct Expression final : DomainBase { 15 | const unsigned Opcode; 16 | const llvm::Value *const LHS = nullptr, *const RHS = nullptr; 17 | Expression(const llvm::BinaryOperator &BinaryOp) 18 | : Opcode(BinaryOp.getOpcode()), LHS(BinaryOp.getOperand(0)), 19 | RHS(BinaryOp.getOperand(1)) {} 20 | Expression(const unsigned Opcode, const llvm::Value *const LHS, 21 | const llvm::Value *const RHS) 22 | : Opcode(Opcode), LHS(LHS), RHS(RHS) {} 23 | 24 | bool operator==(const Expression &Other) const final { 25 | 26 | /// @todo(CSCD70) Please complete this method. 27 | return false; 28 | } 29 | 30 | bool contain(const llvm::Value *const Val) const final { 31 | 32 | /// @todo(CSCD70) Please complete this method. 33 | 34 | return false; 35 | } 36 | Expression replaceValueWith(const llvm::Value *const SrcVal, 37 | const llvm::Value *const DstVal) const final { 38 | 39 | /// @todo(CSCD70) Please complete this method. 40 | 41 | return *this; 42 | } 43 | 44 | using DomainBase::DomainIdMap_t; 45 | using DomainBase::DomainVector_t; 46 | 47 | struct Initializer : public llvm::InstVisitor { 48 | DomainIdMap_t &DomainIdMap; 49 | DomainVector_t &DomainVector; 50 | explicit Initializer(DomainIdMap_t &DomainIdMap, 51 | DomainVector_t &DomainVector) 52 | : DomainIdMap(DomainIdMap), DomainVector(DomainVector) {} 53 | void visitBinaryOperator(llvm::BinaryOperator &); 54 | }; 55 | }; 56 | 57 | } // namespace dfa 58 | 59 | llvm::raw_ostream &operator<<(llvm::raw_ostream &, const dfa::Expression &); 60 | 61 | namespace std { 62 | 63 | template <> struct hash<::dfa::Expression> { 64 | size_t operator()(const dfa::Expression &Expr) const { 65 | size_t HashVal = 0; 66 | 67 | /// @todo(CSCD70) Please complete this method. 68 | 69 | return HashVal; 70 | } 71 | }; 72 | 73 | } // namespace std 74 | -------------------------------------------------------------------------------- /Assignment2-Dataflow_Analysis/include/DFA/Domain/Variable.h: -------------------------------------------------------------------------------- 1 | #pragma once // NOLINT(llvm-header-guard) 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "Base.h" 10 | #include "Utility.h" 11 | 12 | namespace dfa { 13 | 14 | struct Variable final : DomainBase { 15 | const llvm::Value *const Var; 16 | Variable(const llvm::Value *const Var) : Var(Var) {} 17 | 18 | bool operator==(const Variable &Other) const { return Var == Other.Var; } 19 | 20 | bool contain(const llvm::Value *const Val) const final { 21 | 22 | /// @todo(CSCD70) Please complete this method. 23 | 24 | return false; 25 | } 26 | Variable replaceValueWith(const llvm::Value *const SrcVal, 27 | const llvm::Value *const DstVal) const final { 28 | 29 | /// @todo(CSCD70) Please complete this method. 30 | 31 | return *this; 32 | } 33 | 34 | using DomainBase::DomainIdMap_t; 35 | using DomainBase::DomainVector_t; 36 | 37 | struct Initializer : public llvm::InstVisitor { 38 | DomainIdMap_t &DomainIdMap; 39 | DomainVector_t &DomainVector; 40 | explicit Initializer(DomainIdMap_t &DomainIdMap, 41 | DomainVector_t &DomainVector) 42 | : DomainIdMap(DomainIdMap), DomainVector(DomainVector) {} 43 | void visitInstruction(llvm::Instruction &I); 44 | }; 45 | }; 46 | 47 | } // namespace dfa 48 | 49 | llvm::raw_ostream &operator<<(llvm::raw_ostream &, const dfa::Variable &); 50 | 51 | namespace std { 52 | 53 | template <> struct hash<::dfa::Variable> { 54 | size_t operator()(const dfa::Variable &Var) const { 55 | return hash()(Var.Var); 56 | } 57 | }; 58 | 59 | } // namespace std 60 | -------------------------------------------------------------------------------- /Assignment2-Dataflow_Analysis/include/DFA/Flow/BackwardAnalysis.h: -------------------------------------------------------------------------------- 1 | #pragma once // NOLINT(llvm-header-guard) 2 | 3 | #include "Framework.h" 4 | 5 | /// @todo(CSCD70) Please instantiate for the backward pass, similar to the 6 | /// forward one. 7 | /// @sa @c ForwardAnalysis 8 | -------------------------------------------------------------------------------- /Assignment2-Dataflow_Analysis/include/DFA/Flow/ForwardAnalysis.h: -------------------------------------------------------------------------------- 1 | #pragma once // NOLINT(llvm-header-guard) 2 | 3 | #include "Framework.h" 4 | 5 | namespace dfa { 6 | 7 | /// @todo(CSCD70) Please modify the traversal ranges. 8 | 9 | typedef llvm::iterator_range 10 | ForwardMeetBBConstRange_t; 11 | typedef llvm::iterator_range 12 | ForwardBBConstRange_t; 13 | typedef llvm::iterator_range 14 | ForwardInstConstRange_t; 15 | 16 | template 17 | class ForwardAnalysis 18 | : public Framework { 20 | protected: 21 | using Framework_t = 22 | Framework; 24 | using typename Framework_t::AnalysisResult_t; 25 | using typename Framework_t::BBConstRange_t; 26 | using typename Framework_t::InstConstRange_t; 27 | using typename Framework_t::MeetBBConstRange_t; 28 | 29 | using Framework_t::BVs; 30 | using Framework_t::DomainIdMap; 31 | using Framework_t::DomainVector; 32 | using Framework_t::InstDomainValMap; 33 | 34 | using Framework_t::getName; 35 | using Framework_t::run; 36 | using Framework_t::stringifyDomainWithMask; 37 | 38 | void printInstDomainValMap(const llvm::Instruction &Inst) const final { 39 | using llvm::errs; 40 | using llvm::outs; 41 | const llvm::BasicBlock *const ParentBB = Inst.getParent(); 42 | 43 | if (&Inst == &(ParentBB->front())) { 44 | errs() << "\n"; 45 | LOG_ANALYSIS_INFO << "\t" << stringifyDomainWithMask(BVs.at(ParentBB)); 46 | } // if (&Inst == &(*ParentBB->begin())) 47 | outs() << Inst << "\n"; 48 | LOG_ANALYSIS_INFO << "\t" 49 | << stringifyDomainWithMask(InstDomainValMap.at(&Inst)); 50 | } 51 | 52 | MeetBBConstRange_t 53 | getMeetBBConstRange(const llvm::BasicBlock &BB) const final { 54 | return llvm::predecessors(&BB); 55 | } 56 | InstConstRange_t getInstConstRange(const llvm::BasicBlock &BB) const final { 57 | return make_range(BB.begin(), BB.end()); 58 | } 59 | BBConstRange_t getBBConstRange(const llvm::Function &F) const final { 60 | return make_range(F.begin(), F.end()); 61 | } 62 | }; 63 | 64 | } // namespace dfa 65 | -------------------------------------------------------------------------------- /Assignment2-Dataflow_Analysis/include/DFA/Flow/Framework.h: -------------------------------------------------------------------------------- 1 | #pragma once // NOLINT(llvm-header-guard) 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | namespace dfa { 10 | 11 | template struct ValuePrinter { 12 | static std::string print(const TValue &V) { return ""; } 13 | }; 14 | 15 | template 18 | class Framework { 19 | protected: 20 | using DomainIdMap_t = typename TDomainElem::DomainIdMap_t; 21 | using DomainVector_t = typename TDomainElem::DomainVector_t; 22 | using DomainVal_t = typename TMeetOp::DomainVal_t; 23 | using MeetOperands_t = std::vector; 24 | using MeetBBConstRange_t = TMeetBBConstRange; 25 | using BBConstRange_t = TBBConstRange; 26 | using InstConstRange_t = TInstConstRange; 27 | using AnalysisResult_t = 28 | std::tuple, 30 | std::unordered_map>; 31 | 32 | DomainIdMap_t DomainIdMap; 33 | DomainVector_t DomainVector; 34 | std::unordered_map BVs; 35 | std::unordered_map InstDomainValMap; 36 | 37 | /// @name Print utility functions 38 | /// @{ 39 | 40 | std::string stringifyDomainWithMask(const DomainVal_t &Mask) const { 41 | std::string StringBuf; 42 | llvm::raw_string_ostream Strout(StringBuf); 43 | Strout << "{"; 44 | CHECK(Mask.size() == DomainIdMap.size() && 45 | Mask.size() == DomainVector.size()) 46 | << "The size of mask must be equal to the size of domain, but got " 47 | << Mask.size() << " vs. " << DomainIdMap.size() << " vs. " 48 | << DomainVector.size() << " instead"; 49 | for (size_t DomainId = 0; DomainId < DomainIdMap.size(); ++DomainId) { 50 | if (!static_cast(Mask[DomainId])) { 51 | continue; 52 | } 53 | Strout << DomainVector.at(DomainId) 54 | << ValuePrinter::print(Mask[DomainId]) << ", "; 55 | } // for (MaskIdx : [0, Mask.size())) 56 | Strout << "}"; 57 | return StringBuf; 58 | } 59 | virtual void printInstDomainValMap(const llvm::Instruction &Inst) const = 0; 60 | void printInstDomainValMap(const llvm::Function &F) const { 61 | for (const llvm::Instruction &Inst : llvm::instructions(&F)) { 62 | printInstDomainValMap(Inst); 63 | } 64 | } 65 | virtual std::string getName() const = 0; 66 | 67 | /// @} 68 | /// @name Boundary values 69 | /// @{ 70 | 71 | DomainVal_t getBoundaryVal(const llvm::BasicBlock &BB) const { 72 | MeetOperands_t MeetOperands = getMeetOperands(BB); 73 | 74 | /// @todo(CSCD70) Please complete this method. 75 | 76 | return meet(MeetOperands); 77 | } 78 | /// @brief Get the list of basic blocks to which the meet operator will be 79 | /// applied. 80 | /// @param BB 81 | /// @return 82 | virtual MeetBBConstRange_t 83 | getMeetBBConstRange(const llvm::BasicBlock &BB) const = 0; 84 | /// @brief Get the list of domain values to which the meet operator will be 85 | /// applied. 86 | /// @param BB 87 | /// @return 88 | /// @sa @c getMeetBBConstRange 89 | virtual MeetOperands_t getMeetOperands(const llvm::BasicBlock &BB) const { 90 | MeetOperands_t Operands; 91 | 92 | /// @todo(CSCD70) Please complete this method. 93 | 94 | return Operands; 95 | } 96 | DomainVal_t bc() const { return DomainVal_t(DomainIdMap.size()); } 97 | DomainVal_t meet(const MeetOperands_t &MeetOperands) const { 98 | 99 | /// @todo(CSCD70) Please complete this method. 100 | 101 | return DomainVal_t(DomainIdMap.size()); 102 | } 103 | 104 | /// @} 105 | /// @name CFG traversal 106 | /// @{ 107 | 108 | /// @brief Get the list of basic blocks from the function. 109 | /// @param F 110 | /// @return 111 | virtual BBConstRange_t getBBConstRange(const llvm::Function &F) const = 0; 112 | /// @brief Get the list of instructions from the basic block. 113 | /// @param BB 114 | /// @return 115 | virtual InstConstRange_t 116 | getInstConstRange(const llvm::BasicBlock &BB) const = 0; 117 | /// @brief Traverse through the CFG of the function. 118 | /// @param F 119 | /// @return True if either BasicBlock-DomainValue mapping or 120 | /// Instruction-DomainValue mapping has been modified, false 121 | /// otherwise. 122 | bool traverseCFG(const llvm::Function &F) { 123 | bool Changed = false; 124 | 125 | /// @todo(CSCD70) Please complete this method. 126 | 127 | return Changed; 128 | } 129 | 130 | /// @} 131 | 132 | virtual ~Framework() {} 133 | 134 | /// @brief Apply the transfer function to the input domain value at 135 | /// instruction @p inst . 136 | /// @param Inst 137 | /// @param IDV 138 | /// @param ODV 139 | /// @return Whether the output domain value is to be changed. 140 | virtual bool transferFunc(const llvm::Instruction &Inst, 141 | const DomainVal_t &IDV, DomainVal_t &ODV) = 0; 142 | 143 | virtual AnalysisResult_t run(llvm::Function &F, 144 | llvm::FunctionAnalysisManager &FAM) { 145 | 146 | /// @todo(CSCD70) Please complete this method. 147 | 148 | return std::make_tuple(DomainIdMap, DomainVector, BVs, InstDomainValMap); 149 | } 150 | 151 | }; // class Framework 152 | 153 | /// @brief For each domain element type, we have to define: 154 | /// - The default constructor 155 | /// - The meet operators (for intersect/union) 156 | /// - The top element 157 | /// - Conversion to bool (for logging) 158 | struct Bool { 159 | bool Value = false; 160 | Bool operator&(const Bool &Other) const { 161 | return {.Value = Value && Other.Value}; 162 | } 163 | Bool operator|(const Bool &Other) const { 164 | return {.Value = Value || Other.Value}; 165 | } 166 | static Bool top() { return {.Value = true}; } 167 | explicit operator bool() const { return Value; } 168 | }; 169 | 170 | } // namespace dfa 171 | -------------------------------------------------------------------------------- /Assignment2-Dataflow_Analysis/include/DFA/MeetOp.h: -------------------------------------------------------------------------------- 1 | #pragma once // NOLINT(llvm-header-guard) 2 | 3 | #include 4 | 5 | namespace dfa { 6 | 7 | template struct MeetOpBase { 8 | using DomainVal_t = std::vector; 9 | /// @brief Apply the meet operator using two operands. 10 | /// @param LHS 11 | /// @param RHS 12 | /// @return 13 | virtual DomainVal_t operator()(const DomainVal_t &LHS, 14 | const DomainVal_t &RHS) const = 0; 15 | /// @brief Return a domain value that represents the top element, used when 16 | /// doing the initialization. 17 | /// @param DomainSize 18 | /// @return 19 | virtual DomainVal_t top(const std::size_t DomainSize) const = 0; 20 | }; 21 | 22 | template struct Intersect final : MeetOpBase { 23 | using DomainVal_t = typename MeetOpBase::DomainVal_t; 24 | 25 | DomainVal_t operator()(const DomainVal_t &LHS, 26 | const DomainVal_t &RHS) const final { 27 | 28 | /// @todo(CSCD70) Please complete this method. 29 | 30 | return LHS; 31 | } 32 | DomainVal_t top(const std::size_t DomainSize) const final { 33 | 34 | /// @todo(CSCD70) Please complete this method. 35 | 36 | return DomainVal_t(DomainSize); 37 | } 38 | }; 39 | 40 | /// @todo(CSCD70) Please add another subclass for the Union meet operator. 41 | 42 | } // namespace dfa 43 | -------------------------------------------------------------------------------- /Assignment2-Dataflow_Analysis/include/Utility.h: -------------------------------------------------------------------------------- 1 | #pragma once // NOLINT(llvm-header-guard) 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | 8 | inline void hashCombine(std::size_t *const Seed) {} 9 | 10 | /// @brief This is a function for combining hash values from multiple members. 11 | /// Example usage: 12 | /// 13 | /// size_t seed; 14 | /// hashCombine(&seed, memberA, memberB); 15 | /// 16 | /// Reference: https://stackoverflow.com/a/2595226/6320608 17 | template 18 | inline void hashCombine(std::size_t *const Seed, const T &Item, 19 | TVarArg... VarArg) { 20 | std::hash Hasher; 21 | (*Seed) ^= Hasher(Item) + 0x9e3779b9 + ((*Seed) << 6) + ((*Seed) >> 2); 22 | hashCombine(Seed, VarArg...); 23 | } 24 | 25 | class InternalRuntimeChecker { 26 | private: 27 | const bool Cond; 28 | 29 | public: 30 | InternalRuntimeChecker(const bool Cond) : Cond(Cond) {} 31 | ~InternalRuntimeChecker() { 32 | if (!Cond) { 33 | llvm::errs() << "\n"; 34 | abort(); 35 | } 36 | } 37 | operator bool() const { return !Cond; } 38 | }; 39 | 40 | struct InternalInfoLogger { 41 | llvm::raw_ostream &Outs; 42 | InternalInfoLogger(llvm::raw_ostream &Outs = llvm::outs()) : Outs(Outs) {} 43 | ~InternalInfoLogger() { Outs << "\n"; } 44 | operator bool() const { return true; } 45 | }; 46 | 47 | #define CHECK(cond) \ 48 | if (auto Checker = InternalRuntimeChecker((cond))) \ 49 | llvm::errs() << "[" << __FILE__ << ":" << __LINE__ << ", E] " 50 | 51 | #define LOG_INFO \ 52 | if (auto Logger = InternalInfoLogger()) \ 53 | llvm::outs() << "[" << __FILE__ << ":" << __LINE__ << ", I] " 54 | 55 | #define LOG_ANALYSIS_INFO \ 56 | if (auto Logger = InternalInfoLogger(llvm::errs())) \ 57 | llvm::errs() << "[" << getName() << "] " 58 | 59 | template 60 | inline bool operator!=(const std::vector &LHS, const std::vector &RHS) { 61 | CHECK(LHS.size() == RHS.size()) << "Size of domain values has to be the same"; 62 | for (size_t Idx = 0; Idx < LHS.size(); ++Idx) { 63 | if (LHS[Idx] != RHS[Idx]) { 64 | return true; 65 | } 66 | } 67 | return false; 68 | } 69 | -------------------------------------------------------------------------------- /Assignment2-Dataflow_Analysis/lib/1-AvailExprs.cpp: -------------------------------------------------------------------------------- 1 | #include "DFA.h" 2 | 3 | using namespace llvm; 4 | 5 | AnalysisKey AvailExprs::Key; 6 | 7 | bool AvailExprs::transferFunc(const Instruction &Inst, const DomainVal_t &IDV, 8 | DomainVal_t &ODV) { 9 | 10 | /// @todo(CSCD70) Please complete this method. 11 | 12 | return false; 13 | } 14 | -------------------------------------------------------------------------------- /Assignment2-Dataflow_Analysis/lib/2-Liveness.cpp: -------------------------------------------------------------------------------- 1 | #include "DFA.h" 2 | 3 | /// @todo(CSCD70) Please complete this file. 4 | -------------------------------------------------------------------------------- /Assignment2-Dataflow_Analysis/lib/3-SCCP.cpp: -------------------------------------------------------------------------------- 1 | #include "DFA.h" 2 | 3 | /// @todo(CSCD70) Please complete this file. 4 | -------------------------------------------------------------------------------- /Assignment2-Dataflow_Analysis/lib/4-LCM/1-AnticipatedExprs.cpp: -------------------------------------------------------------------------------- 1 | #include "LCM.h" 2 | 3 | /// @todo(CSCD70) Please complete this file. 4 | -------------------------------------------------------------------------------- /Assignment2-Dataflow_Analysis/lib/4-LCM/2-WBAvailExprs.cpp: -------------------------------------------------------------------------------- 1 | #include "LCM.h" 2 | 3 | /// @todo(CSCD70) Please complete this file. 4 | -------------------------------------------------------------------------------- /Assignment2-Dataflow_Analysis/lib/4-LCM/3-EarliestPlacement.cpp: -------------------------------------------------------------------------------- 1 | #include "LCM.h" 2 | 3 | /// @todo(CSCD70) Please complete this file. 4 | -------------------------------------------------------------------------------- /Assignment2-Dataflow_Analysis/lib/4-LCM/4-PostponableExprs.cpp: -------------------------------------------------------------------------------- 1 | #include "LCM.h" 2 | 3 | /// @todo(CSCD70) Please complete this file. 4 | -------------------------------------------------------------------------------- /Assignment2-Dataflow_Analysis/lib/4-LCM/5-LatestPlacement.cpp: -------------------------------------------------------------------------------- 1 | #include "LCM.h" 2 | 3 | /// @todo(CSCD70) Please complete this file. 4 | -------------------------------------------------------------------------------- /Assignment2-Dataflow_Analysis/lib/4-LCM/6-UsedExprs.cpp: -------------------------------------------------------------------------------- 1 | #include "LCM.h" 2 | 3 | /// @todo(CSCD70) Please complete this file. 4 | -------------------------------------------------------------------------------- /Assignment2-Dataflow_Analysis/lib/4-LCM/LCM.h: -------------------------------------------------------------------------------- 1 | #pragma once // NOLINT(llvm-header-guard) 2 | 3 | #include 4 | #include 5 | 6 | class LCMWrapperPass : public llvm::PassInfoMixin { 7 | public: 8 | llvm::PreservedAnalyses run(llvm::Function &F, 9 | llvm::FunctionAnalysisManager &FAM) { 10 | 11 | /// @todo(CSCD70) Get the result from the main body. 12 | 13 | return llvm::PreservedAnalyses::all(); 14 | } 15 | }; 16 | -------------------------------------------------------------------------------- /Assignment2-Dataflow_Analysis/lib/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_library(DFA SHARED DFA.cpp 2 | 1-AvailExprs.cpp 3 | 2-Liveness.cpp 4 | 3-SCCP.cpp 5 | 4-LCM/1-AnticipatedExprs.cpp 6 | 4-LCM/2-WBAvailExprs.cpp 7 | 4-LCM/3-EarliestPlacement.cpp 8 | 4-LCM/4-PostponableExprs.cpp 9 | 4-LCM/5-LatestPlacement.cpp 10 | 4-LCM/6-UsedExprs.cpp 11 | DFA/Domain/Expression.cpp 12 | DFA/Domain/Variable.cpp) 13 | -------------------------------------------------------------------------------- /Assignment2-Dataflow_Analysis/lib/DFA.cpp: -------------------------------------------------------------------------------- 1 | #include "DFA.h" 2 | 3 | #include 4 | #include 5 | 6 | using namespace llvm; 7 | 8 | extern "C" PassPluginLibraryInfo llvmGetPassPluginInfo() { 9 | return { 10 | .APIVersion = LLVM_PLUGIN_API_VERSION, 11 | .PluginName = "DFA", 12 | .PluginVersion = LLVM_VERSION_STRING, 13 | .RegisterPassBuilderCallbacks = 14 | [](PassBuilder &PB) { 15 | PB.registerAnalysisRegistrationCallback( 16 | [](FunctionAnalysisManager &FAM) { 17 | FAM.registerPass([&]() { return AvailExprs(); }); 18 | /// @todo(CSCD70) Please complete the registration of other 19 | /// passes. 20 | }); 21 | PB.registerPipelineParsingCallback( 22 | [](StringRef Name, FunctionPassManager &FPM, 23 | ArrayRef) -> bool { 24 | if (Name == "avail-expr") { 25 | FPM.addPass(AvailExprsWrapperPass()); 26 | return true; 27 | } 28 | if (Name == "liveness") { 29 | FPM.addPass(LivenessWrapperPass()); 30 | return true; 31 | } 32 | if (Name == "const-prop") { 33 | FPM.addPass(SCCPWrapperPass()); 34 | return true; 35 | } 36 | if (Name == "lcm") { 37 | FPM.addPass(LCMWrapperPass()); 38 | return true; 39 | } 40 | return false; 41 | }); 42 | } // RegisterPassBuilderCallbacks 43 | }; // struct PassPluginLibraryInfo 44 | } 45 | -------------------------------------------------------------------------------- /Assignment2-Dataflow_Analysis/lib/DFA.h: -------------------------------------------------------------------------------- 1 | #pragma once // NOLINT(llvm-header-guard) 2 | 3 | #include "4-LCM/LCM.h" 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | 11 | class AvailExprs final : public dfa::ForwardAnalysis>, 13 | public llvm::AnalysisInfoMixin { 14 | private: 15 | using ForwardAnalysis_t = dfa::ForwardAnalysis>; 17 | 18 | friend llvm::AnalysisInfoMixin; 19 | static llvm::AnalysisKey Key; 20 | 21 | std::string getName() const final { return "AvailExprs"; } 22 | bool transferFunc(const llvm::Instruction &, const DomainVal_t &, 23 | DomainVal_t &) final; 24 | 25 | public: 26 | using Result = typename ForwardAnalysis_t::AnalysisResult_t; 27 | using ForwardAnalysis_t::run; 28 | }; 29 | 30 | class AvailExprsWrapperPass 31 | : public llvm::PassInfoMixin { 32 | public: 33 | llvm::PreservedAnalyses run(llvm::Function &F, 34 | llvm::FunctionAnalysisManager &FAM) { 35 | FAM.getResult(F); 36 | return llvm::PreservedAnalyses::all(); 37 | } 38 | }; 39 | 40 | /// @todo(CSCD70) Please complete the main body of the following passes, similar 41 | /// to the Available Expressions pass above. 42 | 43 | class LivenessWrapperPass : public llvm::PassInfoMixin { 44 | public: 45 | llvm::PreservedAnalyses run(llvm::Function &F, 46 | llvm::FunctionAnalysisManager &FAM) { 47 | 48 | /// @todo(CSCD70) Get the result from the main body. 49 | 50 | return llvm::PreservedAnalyses::all(); 51 | } 52 | }; 53 | 54 | class SCCPWrapperPass : public llvm::PassInfoMixin { 55 | public: 56 | llvm::PreservedAnalyses run(llvm::Function &F, 57 | llvm::FunctionAnalysisManager &FAM) { 58 | 59 | /// @todo(CSCD70) Get the result from the main body. 60 | 61 | return llvm::PreservedAnalyses::all(); 62 | } 63 | }; 64 | -------------------------------------------------------------------------------- /Assignment2-Dataflow_Analysis/lib/DFA/Domain/Expression.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace llvm; 4 | using dfa::Expression; 5 | 6 | raw_ostream &operator<<(raw_ostream &Outs, const Expression &Expr) { 7 | Outs << "[" << Instruction::getOpcodeName(Expr.Opcode) << " "; 8 | Expr.LHS->printAsOperand(Outs, false); 9 | Outs << ", "; 10 | Expr.RHS->printAsOperand(Outs, false); 11 | Outs << "]"; 12 | return Outs; 13 | } 14 | 15 | void Expression::Initializer::visitBinaryOperator(BinaryOperator &BO) { 16 | 17 | /// @todo(CSCD70) Please complete this method. 18 | } 19 | -------------------------------------------------------------------------------- /Assignment2-Dataflow_Analysis/lib/DFA/Domain/Variable.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace llvm; 4 | using dfa::Variable; 5 | 6 | raw_ostream &operator<<(raw_ostream &Outs, const Variable &Var) { 7 | CHECK(Var.Var != nullptr); 8 | Var.Var->printAsOperand(Outs); 9 | return Outs; 10 | } 11 | 12 | void Variable::Initializer::visitInstruction(Instruction &I) { 13 | 14 | /// @todo(CSCD70) Please complete this method. 15 | } 16 | -------------------------------------------------------------------------------- /Assignment2-Dataflow_Analysis/test/1-AvailExpr.ll: -------------------------------------------------------------------------------- 1 | ; RUN: opt -S -load-pass-plugin=%dylibdir/libDFA.so \ 2 | ; RUN: -p=avail-expr %s -o %basename_t 2>%basename_t.log 3 | ; @todo(CSCD70): FileCheck --match-full-lines %s --input-file=%basename_t.log 4 | 5 | ; int main(int argc, char *argv[]) { 6 | ; int a, b, c, d, e, f; 7 | ; a = 50; 8 | ; b = argc + a; 9 | ; c = 96; 10 | ; e = b + c; 11 | ; if (a < b) { 12 | ; f = b - a; 13 | ; e = c * b; 14 | ; } else { 15 | ; f = b + a; 16 | ; e = c * b; 17 | ; } 18 | ; b = a - c; 19 | ; d = b + f; 20 | ; return 0; 21 | ; } 22 | ; @todo(CSCD70) Please complete the CHECK directives. 23 | define i32 @main(i32 noundef %0, ptr noundef %1) { 24 | ; [AvailExpr] {} 25 | %3 = add nsw i32 %0, 50 26 | ; [AvailExpr] {[add %0, 50], } 27 | %4 = add nsw i32 %3, 96 28 | %5 = icmp slt i32 50, %3 29 | br i1 %5, label %6, label %9 30 | 31 | 6: ; preds = %2 32 | %7 = sub nsw i32 %3, 50 33 | %8 = mul nsw i32 96, %3 34 | br label %12 35 | 36 | 9: ; preds = %2 37 | %10 = add nsw i32 %3, 50 38 | %11 = mul nsw i32 96, %3 39 | br label %12 40 | 41 | 12: ; preds = %9, %6 42 | %.0 = phi i32 [ %7, %6 ], [ %10, %9 ] 43 | %13 = sub nsw i32 50, 96 44 | %14 = add nsw i32 %13, %.0 45 | ret i32 0 46 | } 47 | -------------------------------------------------------------------------------- /Assignment2-Dataflow_Analysis/test/2-Liveness.ll: -------------------------------------------------------------------------------- 1 | ; RUN: opt -S -load-pass-plugin=%dylibdir/libDFA.so \ 2 | ; RUN: -p=liveness %s -o %basename_t 2>%basename_t.log 3 | ; @todo(CSCD70): FileCheck --match-full-lines %s --input-file=%basename_t.log 4 | 5 | ; int sum(int a, int b) { 6 | ; int res = 1; 7 | ; for (int i = a; i < b; i++) { 8 | ; res += i; 9 | ; } 10 | ; return res; 11 | ; } 12 | ; @todo(CSCD70) Please complete the CHECK directives. 13 | define i32 @sum(i32 noundef %0, i32 noundef %1) { 14 | br label %3 15 | 16 | 3: ; preds = %7, %2 17 | %.01 = phi i32 [ 1, %2 ], [ %6, %7 ] 18 | %.0 = phi i32 [ %0, %2 ], [ %8, %7 ] 19 | %4 = icmp slt i32 %.0, %1 20 | br i1 %4, label %5, label %9 21 | 22 | 5: ; preds = %3 23 | %6 = add nsw i32 %.01, %.0 24 | br label %7 25 | 26 | 7: ; preds = %5 27 | %8 = add nsw i32 %.0, 1 28 | br label %3 29 | 30 | 9: ; preds = %3 31 | ret i32 %.01 32 | } 33 | -------------------------------------------------------------------------------- /Assignment2-Dataflow_Analysis/test/3-SCCP.ll: -------------------------------------------------------------------------------- 1 | ; RUN: opt -S -load-pass-plugin=%dylibdir/libDFA.so \ 2 | ; RUN: -p=const-prop %s -o %basename_t 2>%basename_t.log 3 | ; @todo(CSCD70): FileCheck --match-full-lines %s --input-file=%basename_t.log 4 | 5 | ; int Loop() { 6 | ; int i = 1, j = 1; 7 | ; for (int k = 0; k < 100;) { 8 | ; if (j < 20) { 9 | ; j = i; 10 | ; k = k + 1; 11 | ; } else { 12 | ; j = k; 13 | ; k = k + 2; 14 | ; } 15 | ; } 16 | ; return j; 17 | ; } 18 | ; @todo(CSCD70) Please complete the CHECK directives. 19 | define i32 @Loop() { 20 | br label %1 21 | 22 | 1: ; preds = %9, %0 23 | %.01 = phi i32 [ 1, %0 ], [ %.12, %9 ] 24 | %.0 = phi i32 [ 0, %0 ], [ %.1, %9 ] 25 | %2 = icmp slt i32 %.0, 100 26 | br i1 %2, label %3, label %10 27 | 28 | 3: ; preds = %1 29 | %4 = icmp slt i32 %.01, 20 30 | br i1 %4, label %5, label %7 31 | 32 | 5: ; preds = %3 33 | %6 = add nsw i32 %.0, 1 34 | br label %9 35 | 36 | 7: ; preds = %3 37 | %8 = add nsw i32 %.0, 2 38 | br label %9 39 | 40 | 9: ; preds = %7, %5 41 | %.12 = phi i32 [ 1, %5 ], [ %.0, %7 ] 42 | %.1 = phi i32 [ %6, %5 ], [ %8, %7 ] 43 | br label %1 44 | 45 | 10: ; preds = %1 46 | ret i32 %.01 47 | } 48 | -------------------------------------------------------------------------------- /Assignment2-Dataflow_Analysis/test/4-LCM.ll: -------------------------------------------------------------------------------- 1 | ; RUN: opt -S -load-pass-plugin=%dylibdir/libDFA.so \ 2 | ; RUN: -p=lcm %s -o %basename_t 2>%basename_t.log 3 | ; @todo(CSCD70): FileCheck --match-full-lines %s --input-file=%basename_t.log 4 | 5 | ; #include "stdio.h" 6 | 7 | ; int foo(int a, int b, int c) { 8 | ; if (a > 5) { 9 | ; int g = b + c; 10 | ; printf("%d", g); 11 | ; } else { 12 | ; while (b < 5) { 13 | ; b = b + 1; 14 | ; int d = b + c; 15 | ; printf("%d", d); 16 | ; } 17 | ; } 18 | ; int e = b + c; 19 | ; return e; 20 | ; } 21 | ; @todo(CSCD70) Please complete the CHECK directives. Note that: 22 | ; - The critical edges have to be broken first. 23 | ; - The outputs from both the 4 analysis passes and the 2 24 | ; placements have to be checked. 25 | @.str = private unnamed_addr constant [3 x i8] c"%d\00", align 1 26 | 27 | define i32 @foo(i32 noundef %0, i32 noundef %1, i32 noundef %2) #0 { 28 | %4 = icmp sgt i32 %0, 5 29 | br i1 %4, label %5, label %8 30 | 31 | 5: ; preds = %3 32 | %6 = add nsw i32 %1, %2 33 | %7 = call i32 (ptr, ...) @printf(ptr noundef @.str, i32 noundef %6) 34 | br label %16 35 | 36 | 8: ; preds = %3 37 | br label %9 38 | 39 | 9: ; preds = %11, %8 40 | %.0 = phi i32 [ %1, %8 ], [ %12, %11 ] 41 | %10 = icmp slt i32 %.0, 5 42 | br i1 %10, label %11, label %15 43 | 44 | 11: ; preds = %9 45 | %12 = add nsw i32 %.0, 1 46 | %13 = add nsw i32 %12, %2 47 | %14 = call i32 (ptr, ...) @printf(ptr noundef @.str, i32 noundef %13) 48 | br label %9 49 | 50 | 15: ; preds = %9 51 | br label %16 52 | 53 | 16: ; preds = %15, %5 54 | %.1 = phi i32 [ %1, %5 ], [ %.0, %15 ] 55 | %17 = add nsw i32 %.1, %2 56 | ret i32 %17 57 | } 58 | 59 | declare i32 @printf(ptr noundef, ...) #1 60 | -------------------------------------------------------------------------------- /Assignment2-Dataflow_Analysis/test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | execute_process(COMMAND llvm-config-${LLVM_VERSION} --bindir 2 | OUTPUT_VARIABLE LLVM_BINDIR 3 | OUTPUT_STRIP_TRAILING_WHITESPACE) 4 | set(CMAKE_LIBRARY_OUTPUT_DIR "${CMAKE_BINARY_DIR}/lib") 5 | 6 | configure_file(lit.cfg.in.py lit.cfg.py @ONLY) 7 | 8 | add_test(NAME FunctionInfoTest COMMAND lit -a ${CMAKE_CURRENT_BINARY_DIR}) 9 | -------------------------------------------------------------------------------- /Assignment2-Dataflow_Analysis/test/lit.cfg.in.py: -------------------------------------------------------------------------------- 1 | import lit 2 | import lit.llvm 3 | 4 | lit.llvm.initialize(lit_config, config) 5 | 6 | from lit.llvm import llvm_config 7 | 8 | 9 | config.name = "@CMAKE_PROJECT_NAME@" 10 | config.test_format = lit.formats.ShTest() 11 | config.test_source_root = "@CMAKE_CURRENT_SOURCE_DIR@" 12 | config.test_exec_root = "@CMAKE_CURRENT_BINARY_DIR@" 13 | config.suffixes = [".c", ".ll"] 14 | 15 | config.substitutions.append((r"%dylibdir", "@CMAKE_LIBRARY_OUTPUT_DIR@")) 16 | 17 | config.llvm_config_bindir = "@LLVM_BINDIR@" 18 | llvm_config.add_tool_substitutions( 19 | ["opt", "FileCheck"], config.llvm_config_bindir 20 | ) 21 | -------------------------------------------------------------------------------- /Assignment3-Loop_Invariant_Code_Motion/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.18.4) 2 | project(LICM) 3 | set(CMAKE_EXPORT_COMPILE_COMMANDS ON) 4 | 5 | set(LLVM_VERSION 6 | "16" 7 | CACHE STRING "LLVM Version") 8 | 9 | execute_process( 10 | COMMAND llvm-config-${LLVM_VERSION} --cxxflags 11 | OUTPUT_VARIABLE LLVM_CXXFLAGS 12 | OUTPUT_STRIP_TRAILING_WHITESPACE) 13 | execute_process( 14 | COMMAND llvm-config-${LLVM_VERSION} --includedir 15 | OUTPUT_VARIABLE LLVM_INCLUDEDIR 16 | OUTPUT_STRIP_TRAILING_WHITESPACE) 17 | set(CMAKE_CXX_FLAGS "${LLVM_CXXFLAGS} -isystem ${LLVM_INCLUDEDIR} -Wall") 18 | if(NOT CMAKE_BUILD_TYPE OR CMAKE_BUILD_TYPE STREQUAL "Debug") 19 | set(CMAKE_CXX_CLANG_TIDY 20 | "clang-tidy-${LLVM_VERSION};-header-filter=.*;--extra-arg-before=-stdlib=libc++" 21 | ) 22 | message(STATUS "Enabling clang-tidy") 23 | endif() 24 | include_directories(${CMAKE_SOURCE_DIR}/include) 25 | 26 | add_subdirectory(lib) 27 | 28 | include(CTest) 29 | enable_testing() 30 | add_subdirectory(test) 31 | -------------------------------------------------------------------------------- /Assignment3-Loop_Invariant_Code_Motion/README.md: -------------------------------------------------------------------------------- 1 | # Assignment 3 Loop Invariant Code Motion 2 | 3 | **Due Date**: April. 7th, **Handout**: 4 | [\[Overleaf\]](https://www.overleaf.com/read/xctvxpqvxrvk), **GitHub 5 | Classroom**: [\[Invitation\]](https://classroom.github.com/a/PLVehVFF) 6 | 7 | Please click on the links above for the assignment handout and the invitation to 8 | GitHub Classroom. Note that 9 | 10 | - The repository is initialized to be empty, so you will have to copy the files 11 | in this folder into your own repository. 12 | - TODO items have been marked using `todo(CSCD70)` in the source code. **These 13 | include both the optimization passes and the test cases.** Please make sure 14 | that you have completed both parts before submitting. 15 | -------------------------------------------------------------------------------- /Assignment3-Loop_Invariant_Code_Motion/lib/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_library(LICM SHARED LICM.cpp RegAllocIntfGraph.cpp) 2 | -------------------------------------------------------------------------------- /Assignment3-Loop_Invariant_Code_Motion/lib/LICM.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * @file Loop Invariant Code Motion 3 | */ 4 | #include 5 | #include 6 | 7 | using namespace llvm; 8 | 9 | namespace { 10 | 11 | class LoopInvariantCodeMotion final : public LoopPass { 12 | public: 13 | static char ID; 14 | 15 | LoopInvariantCodeMotion() : LoopPass(ID) {} 16 | 17 | virtual void getAnalysisUsage(AnalysisUsage &AU) const override { 18 | /** 19 | * @todo(CSCD70) Request the dominator tree and the loop simplify pass. 20 | */ 21 | AU.setPreservesCFG(); 22 | } 23 | 24 | /** 25 | * @todo(CSCD70) Please finish the implementation of this method. 26 | */ 27 | virtual bool runOnLoop(Loop *L, LPPassManager &LPM) override { return false; } 28 | }; 29 | 30 | char LoopInvariantCodeMotion::ID = 0; 31 | RegisterPass X("loop-invariant-code-motion", 32 | "Loop Invariant Code Motion"); 33 | 34 | } // anonymous namespace 35 | -------------------------------------------------------------------------------- /Assignment3-Loop_Invariant_Code_Motion/lib/RegAllocIntfGraph.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * @file Interference Graph Register Allocator 3 | */ 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | using namespace llvm; 30 | 31 | namespace llvm { 32 | 33 | void initializeRAIntfGraphPass(PassRegistry &Registry); 34 | 35 | } // namespace llvm 36 | 37 | namespace std { 38 | 39 | template <> // 40 | struct hash { 41 | size_t operator()(const Register &Reg) const { 42 | return DenseMapInfo::getHashValue(Reg); 43 | } 44 | }; 45 | 46 | template <> // 47 | struct greater { 48 | bool operator()(LiveInterval *const &LHS, LiveInterval *const &RHS) const { 49 | /** 50 | * @todo(CSCD70) Please finish the implementation of this function that is 51 | * used for determining whether one live interval has spill 52 | * cost greater than the other. 53 | */ 54 | return false; 55 | } 56 | }; 57 | 58 | } // namespace std 59 | 60 | namespace { 61 | 62 | class RAIntfGraph; 63 | 64 | class AllocationHints { 65 | private: 66 | SmallVector Hints; 67 | 68 | public: 69 | AllocationHints(RAIntfGraph *const RA, const LiveInterval *const LI); 70 | SmallVectorImpl::iterator begin() { return Hints.begin(); } 71 | SmallVectorImpl::iterator end() { return Hints.end(); } 72 | }; 73 | 74 | class RAIntfGraph final : public MachineFunctionPass, 75 | private LiveRangeEdit::Delegate { 76 | private: 77 | MachineFunction *MF; 78 | 79 | SlotIndexes *SI; 80 | VirtRegMap *VRM; 81 | const TargetRegisterInfo *TRI; 82 | MachineRegisterInfo *MRI; 83 | RegisterClassInfo RCI; 84 | LiveRegMatrix *LRM; 85 | MachineLoopInfo *MLI; 86 | LiveIntervals *LIS; 87 | 88 | /** 89 | * @brief Interference Graph 90 | */ 91 | class IntfGraph { 92 | private: 93 | RAIntfGraph *RA; 94 | 95 | /// Interference Relations 96 | std::multimap, 97 | std::greater> 98 | IntfRels; 99 | 100 | /** 101 | * @brief Try to materialize all the virtual registers (internal). 102 | * 103 | * @return (nullptr, VirtPhysRegMap) in the case when a successful 104 | * materialization is made, (LI, *) in the case when unsuccessful 105 | * (and LI is the live interval to spill) 106 | * 107 | * @sa tryMaterializeAll 108 | */ 109 | using MaterializeResult_t = 110 | std::tuple>; 112 | MaterializeResult_t tryMaterializeAllInternal(); 113 | 114 | public: 115 | explicit IntfGraph(RAIntfGraph *const RA) : RA(RA) {} 116 | /** 117 | * @brief Insert a virtual register @c Reg into the interference graph. 118 | */ 119 | void insert(const Register &Reg); 120 | /** 121 | * @brief Erase a virtual register @c Reg from the interference graph. 122 | * 123 | * @sa RAIntfGraph::LRE_CanEraseVirtReg 124 | */ 125 | void erase(const Register &Reg); 126 | /** 127 | * @brief Build the whole graph. 128 | */ 129 | void build(); 130 | /** 131 | * @brief Try to materialize all the virtual registers. 132 | */ 133 | void tryMaterializeAll(); 134 | void clear() { IntfRels.clear(); } 135 | } G; 136 | 137 | SmallPtrSet DeadRemats; 138 | std::unique_ptr SpillerInst; 139 | 140 | void postOptimization() { 141 | SpillerInst->postOptimization(); 142 | for (MachineInstr *const DeadInst : DeadRemats) { 143 | LIS->RemoveMachineInstrFromMaps(*DeadInst); 144 | DeadInst->eraseFromParent(); 145 | } 146 | DeadRemats.clear(); 147 | G.clear(); 148 | } 149 | 150 | friend class AllocationHints; 151 | friend class IntfGraph; 152 | 153 | /// The following two methods are inherited from @c LiveRangeEdit::Delegate 154 | /// and implicitly used by the spiller to edit the live ranges. 155 | bool LRE_CanEraseVirtReg(Register Reg) override { 156 | /** 157 | * @todo(cscd70) Please implement this method. 158 | */ 159 | // If the virtual register has been materialized, undo its physical 160 | // assignment and erase it from the interference graph. 161 | return true; 162 | } 163 | void LRE_WillShrinkVirtReg(Register Reg) override { 164 | /** 165 | * @todo(cscd70) Please implement this method. 166 | */ 167 | // If the virtual register has been materialized, undo its physical 168 | // assignment and re-insert it into the interference graph. 169 | } 170 | 171 | public: 172 | static char ID; 173 | 174 | StringRef getPassName() const override { 175 | return "Interference Graph Register Allocator"; 176 | } 177 | 178 | RAIntfGraph() : MachineFunctionPass(ID), G(this) {} 179 | 180 | void getAnalysisUsage(AnalysisUsage &AU) const override { 181 | MachineFunctionPass::getAnalysisUsage(AU); 182 | AU.setPreservesCFG(); 183 | #define REQUIRE_AND_PRESERVE_PASS(PassName) \ 184 | AU.addRequired(); \ 185 | AU.addPreserved() 186 | 187 | REQUIRE_AND_PRESERVE_PASS(SlotIndexes); 188 | REQUIRE_AND_PRESERVE_PASS(VirtRegMap); 189 | REQUIRE_AND_PRESERVE_PASS(LiveIntervals); 190 | REQUIRE_AND_PRESERVE_PASS(LiveRegMatrix); 191 | REQUIRE_AND_PRESERVE_PASS(LiveStacks); 192 | REQUIRE_AND_PRESERVE_PASS(AAResultsWrapperPass); 193 | REQUIRE_AND_PRESERVE_PASS(MachineDominatorTree); 194 | REQUIRE_AND_PRESERVE_PASS(MachineLoopInfo); 195 | REQUIRE_AND_PRESERVE_PASS(MachineBlockFrequencyInfo); 196 | } 197 | 198 | MachineFunctionProperties getRequiredProperties() const override { 199 | return MachineFunctionProperties().set( 200 | MachineFunctionProperties::Property::NoPHIs); 201 | } 202 | MachineFunctionProperties getClearedProperties() const override { 203 | return MachineFunctionProperties().set( 204 | MachineFunctionProperties::Property::IsSSA); 205 | } 206 | 207 | bool runOnMachineFunction(MachineFunction &MF) override; 208 | }; // class RAIntfGraph 209 | 210 | AllocationHints::AllocationHints(RAIntfGraph *const RA, 211 | const LiveInterval *const LI) { 212 | const TargetRegisterClass *const RC = RA->MRI->getRegClass(LI->reg()); 213 | 214 | /** 215 | * @todo(CSCD70) Please complete this part by constructing the allocation 216 | * hints, similar to the tutorial example. 217 | */ 218 | 219 | outs() << "Hint Registers for Class " << RA->TRI->getRegClassName(RC) 220 | << ": ["; 221 | for (const MCPhysReg &PhysReg : Hints) { 222 | outs() << RA->TRI->getRegAsmName(PhysReg) << ", "; 223 | } 224 | outs() << "]\n"; 225 | } 226 | 227 | bool RAIntfGraph::runOnMachineFunction(MachineFunction &MF) { 228 | outs() << "************************************************\n" 229 | << "* Machine Function\n" 230 | << "************************************************\n"; 231 | SI = &getAnalysis(); 232 | for (const MachineBasicBlock &MBB : MF) { 233 | MBB.print(outs(), SI); 234 | outs() << "\n"; 235 | } 236 | outs() << "\n\n"; 237 | 238 | this->MF = &MF; 239 | 240 | VRM = &getAnalysis(); 241 | TRI = &VRM->getTargetRegInfo(); 242 | MRI = &VRM->getRegInfo(); 243 | MRI->freezeReservedRegs(MF); 244 | LIS = &getAnalysis(); 245 | LRM = &getAnalysis(); 246 | RCI.runOnMachineFunction(MF); 247 | MLI = &getAnalysis(); 248 | 249 | VirtRegAuxInfo VRAI(MF, *LIS, *VRM, getAnalysis(), 250 | getAnalysis()); 251 | VRAI.calculateSpillWeightsAndHints(); 252 | SpillerInst.reset(createInlineSpiller(*this, MF, *VRM, VRAI)); 253 | 254 | G.build(); 255 | G.tryMaterializeAll(); 256 | 257 | postOptimization(); 258 | return true; 259 | } 260 | 261 | void RAIntfGraph::IntfGraph::insert(const Register &Reg) { 262 | /** 263 | * @todo(CSCD70) Please implement this method. 264 | */ 265 | // 1. Collect all VIRTUAL registers that interfere with 'Reg'. 266 | // 2. Collect all PHYSICAL registers that interfere with 'Reg'. 267 | // 3. Insert 'Reg' into the graph. 268 | } 269 | 270 | void RAIntfGraph::IntfGraph::erase(const Register &Reg) { 271 | /** 272 | * @todo(cscd70) Please implement this method. 273 | */ 274 | // 1. ∀n ∈ neighbors(Reg), erase 'Reg' from n's interfering set and update its 275 | // weights accordingly. 276 | // 2. Erase 'Reg' from the interference graph. 277 | } 278 | 279 | void RAIntfGraph::IntfGraph::build() { 280 | /** 281 | * @todo(CSCD70) Please implement this method. 282 | */ 283 | } 284 | 285 | RAIntfGraph::IntfGraph::MaterializeResult_t 286 | RAIntfGraph::IntfGraph::tryMaterializeAllInternal() { 287 | std::unordered_map PhysRegAssignment; 288 | 289 | /** 290 | * @todo(CSCD70) Please implement this method. 291 | */ 292 | // ∀r ∈ IntfRels.keys, try to materialize it. If successful, cache it in 293 | // PhysRegAssignment, else mark it as to be spilled. 294 | 295 | return std::make_tuple(nullptr, PhysRegAssignment); 296 | } 297 | 298 | void RAIntfGraph::IntfGraph::tryMaterializeAll() { 299 | std::unordered_map PhysRegAssignment; 300 | 301 | /** 302 | * @todo(CSCD70) Please implement this method. 303 | */ 304 | // Keep looping until a valid assignment is made. In the case of spilling, 305 | // modify the interference graph accordingly. 306 | 307 | for (auto &PhysRegAssignPair : PhysRegAssignment) { 308 | RA->LRM->assign(*PhysRegAssignPair.first, PhysRegAssignPair.second); 309 | } 310 | } 311 | 312 | char RAIntfGraph::ID = 0; 313 | 314 | static RegisterRegAlloc X("intfgraph", "Interference Graph Register Allocator", 315 | []() -> FunctionPass * { return new RAIntfGraph(); }); 316 | 317 | } // anonymous namespace 318 | 319 | INITIALIZE_PASS_BEGIN(RAIntfGraph, "regallointfgraph", 320 | "Interference Graph Register Allocator", false, false) 321 | INITIALIZE_PASS_DEPENDENCY(SlotIndexes) 322 | INITIALIZE_PASS_DEPENDENCY(VirtRegMap) 323 | INITIALIZE_PASS_DEPENDENCY(LiveIntervals) 324 | INITIALIZE_PASS_DEPENDENCY(LiveRegMatrix) 325 | INITIALIZE_PASS_DEPENDENCY(LiveStacks); 326 | INITIALIZE_PASS_DEPENDENCY(AAResultsWrapperPass); 327 | INITIALIZE_PASS_DEPENDENCY(MachineDominatorTree); 328 | INITIALIZE_PASS_DEPENDENCY(MachineLoopInfo); 329 | INITIALIZE_PASS_DEPENDENCY(MachineBlockFrequencyInfo); 330 | INITIALIZE_PASS_END(RAIntfGraph, "regallointfgraph", 331 | "Interference Graph Register Allocator", false, false) 332 | -------------------------------------------------------------------------------- /Assignment3-Loop_Invariant_Code_Motion/test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | execute_process( 2 | COMMAND llvm-config-${LLVM_VERSION} --bindir 3 | OUTPUT_VARIABLE LLVM_BINDIR 4 | OUTPUT_STRIP_TRAILING_WHITESPACE) 5 | set(CMAKE_LIBRARY_OUTPUT_DIR "${CMAKE_BINARY_DIR}/lib") 6 | 7 | configure_file(lit.cfg.in.py lit.cfg.py @ONLY) 8 | 9 | add_test(NAME FunctionInfoTest COMMAND lit -a ${CMAKE_CURRENT_BINARY_DIR}) 10 | -------------------------------------------------------------------------------- /Assignment3-Loop_Invariant_Code_Motion/test/LICM.ll: -------------------------------------------------------------------------------- 1 | ; RUN: opt -S -load %dylibdir/libLICM.so --enable-new-pm=0 \ 2 | ; RUN: -loop-invariant-code-motion %s -o %basename_t 3 | ; RUN: FileCheck --match-full-lines --check-prefix=CODEGEN %s --input-file=%basename_t 4 | ; RUN: llc -load %dylibdir/libLICM.so \ 5 | ; RUN: -regalloc=basic --relocation-model=pic \ 6 | ; RUN: %basename_t -o %basename_t.s 7 | 8 | ; @todo(CSCD70) Please replace the register allocator with 'intfgraph' after you 9 | ; have completed the interference graph register allocator. 10 | 11 | ; RUN: clang %basename_t.s -o %basename_t.exe 12 | ; RUN: ./%basename_t.exe | FileCheck --match-full-lines --check-prefix=CORRECTNESS %s 13 | ; CORRECTNESS: 3,4,10,6,7,12,3,10 14 | ; CORRECTNESS-NEXT: 8,4,0,0,7,0,3,13 15 | 16 | ; #include 17 | 18 | ; void foo(int c, int z) { 19 | ; int a = 9, h, m = 0, n = 0, q, r = 0, y = 0; 20 | 21 | ; LOOP: 22 | ; z = z + 1; 23 | ; y = c + 3; 24 | ; q = c + 7; 25 | ; if (z < 5) { 26 | ; a = a + 2; 27 | ; h = c + 3; 28 | ; } else { 29 | ; a = a - 1; 30 | ; h = c + 4; 31 | ; if (z >= 10) { 32 | ; goto EXIT; 33 | ; } 34 | ; } 35 | ; m = y + 7; 36 | ; n = h + 2; 37 | ; y = c + 7; 38 | ; r = q + 5; 39 | ; goto LOOP; 40 | ; EXIT: 41 | ; printf("%d,%d,%d,%d,%d,%d,%d,%d\n", a, h, m, n, q, r, y, z); 42 | ; } 43 | 44 | ; int main() { 45 | ; foo(0, 4); 46 | ; foo(0, 12); 47 | ; return 0; 48 | ; } 49 | @.str = private constant [25 x i8] c"%d,%d,%d,%d,%d,%d,%d,%d\0A\00", align 1 50 | 51 | define void @foo(i32 %0, i32 %1) { 52 | ; CODEGEN-LABEL: define void @foo(i32 %0, i32 %1) { 53 | ; @todo(CSCD70) Please complete the CHECK directives on the optimized code. 54 | br label %3 55 | 56 | 3: ; preds = %15, %2 57 | %.05 = phi i32 [ 0, %2 ], [ %19, %15 ] 58 | %.04 = phi i32 [ 0, %2 ], [ %17, %15 ] 59 | %.03 = phi i32 [ 0, %2 ], [ %16, %15 ] 60 | %.01 = phi i32 [ 9, %2 ], [ %.1, %15 ] 61 | %.0 = phi i32 [ %1, %2 ], [ %4, %15 ] 62 | %4 = add nsw i32 %.0, 1 63 | %5 = add nsw i32 %0, 3 64 | %6 = add nsw i32 %0, 7 65 | %7 = icmp slt i32 %4, 5 66 | br i1 %7, label %8, label %11 67 | 68 | 8: ; preds = %3 69 | %9 = add nsw i32 %.01, 2 70 | %10 = add nsw i32 %0, 3 71 | br label %15 72 | 73 | 11: ; preds = %3 74 | %12 = sub nsw i32 %.01, 1 75 | %13 = add nsw i32 %0, 4 76 | %14 = icmp sge i32 %4, 10 77 | br i1 %14, label %20, label %15 78 | 79 | 15: ; preds = %11, %8 80 | %.02 = phi i32 [ %10, %8 ], [ %13, %11 ] 81 | %.1 = phi i32 [ %9, %8 ], [ %12, %11 ] 82 | %16 = add nsw i32 %5, 7 83 | %17 = add nsw i32 %.02, 2 84 | %18 = add nsw i32 %0, 7 85 | %19 = add nsw i32 %6, 5 86 | br label %3 87 | 88 | 20: ; preds = %11 89 | %21 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([25 x i8], [25 x i8]* @.str, i64 0, i64 0), i32 %12, i32 %13, i32 %.03, i32 %.04, i32 %6, i32 %.05, i32 %5, i32 %4) 90 | ret void 91 | } 92 | 93 | declare i32 @printf(i8*, ...) 94 | 95 | define i32 @main() { 96 | call void @foo(i32 0, i32 4) 97 | call void @foo(i32 0, i32 12) 98 | ret i32 0 99 | } 100 | -------------------------------------------------------------------------------- /Assignment3-Loop_Invariant_Code_Motion/test/RegAlloc.c: -------------------------------------------------------------------------------- 1 | // RUN: clang -O0 -Xclang -disable-O0-optnone -emit-llvm -c %s -o %basename_t.bc 2 | // RUN: opt -S -passes=mem2reg %basename_t.bc -o %basename_t.ll 3 | // RUN: llc -load %dylibdir/libLICM.so \ 4 | // RUN: -regalloc=basic --relocation-model=pic \ 5 | // RUN: %basename_t.ll -o %basename_t.s 6 | 7 | // @todo(cscd70) Please replace the register allocator with 'intfgraph' after 8 | // you have completed the interference graph register allocator. 9 | 10 | // RUN: clang %basename_t.s -o %basename_t.exe 11 | // RUN: ./%basename_t.exe | FileCheck %s 12 | // CHECK: 023 13 | #include 14 | 15 | int g = 0; 16 | 17 | int def() { return g++; } 18 | 19 | void use(int i) { printf("%d", i); } 20 | 21 | int main() { 22 | int A = def(), B, C, D; 23 | 24 | if (A) { 25 | B = def(); 26 | use(A); 27 | D = B + 1; 28 | } else { 29 | C = def(); 30 | use(A); 31 | D = C + 2; 32 | } 33 | A = def(); 34 | use(A); 35 | use(D); 36 | return 0; 37 | } 38 | -------------------------------------------------------------------------------- /Assignment3-Loop_Invariant_Code_Motion/test/lit.cfg.in.py: -------------------------------------------------------------------------------- 1 | import lit.llvm 2 | 3 | lit.llvm.initialize(lit_config, config) 4 | 5 | from lit.llvm import llvm_config 6 | 7 | 8 | config.name = "LICM" 9 | config.test_format = lit.formats.ShTest() 10 | config.test_source_root = "@CMAKE_CURRENT_SOURCE_DIR@" 11 | config.test_exec_root = "@CMAKE_CURRENT_BINARY_DIR@" 12 | config.suffixes = [".c", ".cpp", ".ll"] 13 | 14 | config.substitutions.append((r"%testdir", "@CMAKE_CURRENT_BINARY_DIR@")) 15 | config.substitutions.append((r"%dylibdir", "@CMAKE_LIBRARY_OUTPUT_DIR@")) 16 | config.substitutions.append((r"%llvm_cxxflags", "@LLVM_CXXFLAGS@")) 17 | 18 | config.llvm_config_bindir = "@LLVM_BINDIR@" 19 | llvm_config.add_tool_substitutions( 20 | ["clang", "opt", "llc", "FileCheck"], config.llvm_config_bindir 21 | ) 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CSCD70 Compiler Optimization ![build status](https://github.com/UofT-EcoSystem/CSCD70/workflows/build/badge.svg) ![website status](https://github.com/UofT-EcoSystem/CSCD70/workflows/website/badge.svg) 2 | 3 | This repository contains the course materials for class **CSCD70 Compiler 4 | Optimization** @ **University of Toronto**. 5 | 6 | ## Questions or Concerns? 7 | 8 | If you have any questions or concerns, please open a new thread on 9 | [Piazza](https://piazza.com/utoronto.ca/winter2023/cscd70/home) so that all your 10 | colleagues can benefit. 11 | 12 | ## Acknowledgement 13 | 14 | Thanks to Professor Gennady Pekhimenko, Professor Nandita Vijaykumar, and many 15 | talented and hardworking students from previous offerings of CSCD70 (University 16 | of Toronto). 17 | -------------------------------------------------------------------------------- /Tools/C_to_LLVM_IR/.gitignore: -------------------------------------------------------------------------------- 1 | *.ll 2 | -------------------------------------------------------------------------------- /Tools/C_to_LLVM_IR/C_to_LLVM_IR.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | 3 | OPTIMIZATION_LEVEL=0 4 | EXTRA_PASSES= 5 | 6 | BOLD_PREFIX="\033[1m" 7 | BOLD_SUFFIX="\033[0m" 8 | 9 | function print_usage() 10 | { 11 | echo -e \ 12 | "Usage: ./C_to_LLVM_IR.sh [${BOLD_PREFIX}-O${BOLD_SUFFIX}x]" \ 13 | "[${BOLD_PREFIX}--passes${BOLD_SUFFIX} \"xxx\" (comma separated)]" \ 14 | "${BOLD_PREFIX}-c${BOLD_SUFFIX} file" 15 | } 16 | 17 | while [[ $# -gt 0 ]] 18 | do 19 | case $1 in 20 | -O*) 21 | OPTIMIZATION_LEVEL=${1#*O} 22 | shift 23 | ;; 24 | -p|-passes) 25 | EXTRA_PASSES=$2 26 | shift 27 | shift 28 | ;; 29 | -p=*|-passes=*) 30 | EXTRA_PASSES=${1#*=} 31 | shift 32 | ;; 33 | -c) 34 | CSRC_FILE=$2 35 | shift 36 | shift 37 | ;; 38 | *) 39 | echo -e "Unrecognized argument: ${BOLD_PREFIX}$1${BOLD_SUFFIX}" 40 | print_usage 41 | exit -1 42 | ;; 43 | esac 44 | done 45 | 46 | if [ -z ${CSRC_FILE} ] 47 | then 48 | CSRC_FILE=$(realpath ${BASH_SOURCE[0]}) 49 | CSRC_FILE=${CSRC_FILE/C_to_LLVM_IR.sh/main.c} 50 | fi 51 | 52 | EXTRA_OPT_PASSES="" 53 | 54 | if [ ! -z ${EXTRA_PASSES} ] 55 | then 56 | EXTRA_OPT_PASSES="-p=${EXTRA_PASSES}" 57 | fi 58 | 59 | CLANG_FLAGS="-O${OPTIMIZATION_LEVEL}" 60 | 61 | if [ ${OPTIMIZATION_LEVEL} -eq "0" ] 62 | then 63 | CLANG_FLAGS+=" -Xclang -disable-O0-optnone" 64 | fi 65 | 66 | LLVM_VERSION=${LLVM_VERSION:-16} 67 | 68 | BC_FILE=${CSRC_FILE/.c/.bc} 69 | LL_FILE=${CSRC_FILE/.c/.ll} 70 | 71 | function print_and_exec() 72 | { 73 | echo $@ 74 | $@ 75 | } 76 | 77 | print_and_exec clang-${LLVM_VERSION} ${CLANG_FLAGS} -emit-llvm -c ${CSRC_FILE} -o ${BC_FILE} 78 | print_and_exec opt-${LLVM_VERSION} -S ${EXTRA_OPT_PASSES} ${BC_FILE} -o ${LL_FILE} 79 | rm -f ${BC_FILE} 80 | -------------------------------------------------------------------------------- /Tools/C_to_LLVM_IR/main.c: -------------------------------------------------------------------------------- 1 | int main() { return 0; } 2 | -------------------------------------------------------------------------------- /Tools/README.md: -------------------------------------------------------------------------------- 1 | # Tools 2 | 3 | This folder contains tools that you might find helpful for your development. 4 | 5 | - `C_to_LLVM_IR` helps you convert a C source file to its equivalent LLVM IR format. 6 | ```Bash 7 | ./C_to_LLVM_IR/C_to_LLVM_IR.sh [-Ox] # Optimization level 8 | [-p/--passes=xxx (comma separated)] # Passes to execute 9 | -c file # C source code to compile 10 | ``` 11 | E.g., 12 | 13 | ```Bash 14 | /Tools$ ./C_to_LLVM_IR/C_to_LLVM_IR.sh -O0 -p=mem2reg -c C_to_LLVM_IR/main.c 15 | ``` 16 | -------------------------------------------------------------------------------- /Tutorial01-Introduction_to_LLVM/Example1-Cpp_Fundamentals/.gitignore: -------------------------------------------------------------------------------- 1 | 1-VarReference 2 | 2-PublicInheritance 3 | 3-STL 4 | -------------------------------------------------------------------------------- /Tutorial01-Introduction_to_LLVM/Example1-Cpp_Fundamentals/1-VarReference.cpp: -------------------------------------------------------------------------------- 1 | /// @file Variable Reference 2 | /// @note We do NOT need to "take the address of" and/or "dereference" when 3 | /// dealing when references, which make them a cleaner solution compared 4 | /// with pointers. 5 | #include // Print 6 | 7 | int main() { 8 | int X = 100; 9 | int *XPtr = &X; // `XPtr` is a pointer to `X`. 10 | int &XRef = X; // `XRef` is a *reference* to `X`. 11 | int XCopy = X; // `XCopy` is a copy of `X`. 12 | 13 | X = 50; // When we modify the value of `X`, we are modifying the value of 14 | //` XRef` and the value that `XPtr` is pointing to and at the same 15 | // time, but NOT the value of `XCopy`. 16 | std::cout << "X: " << X << ", " 17 | << "XPtr: " << *XPtr << ", " 18 | << "XRef: " << XRef << ", " 19 | << "XCopy: " << XCopy 20 | << std::endl; // 'endl' is the newline character 21 | return 0; 22 | } 23 | -------------------------------------------------------------------------------- /Tutorial01-Introduction_to_LLVM/Example1-Cpp_Fundamentals/2-PublicInheritance.cpp: -------------------------------------------------------------------------------- 1 | /// @file Public Inheritance 2 | #include 3 | #include // std::bad_cast 4 | 5 | /// Abstract Base Class @c Animal 6 | class Animal { 7 | public: 8 | /// @note If a base class method is marked as *virtual*, then all the 9 | /// inherited methods will also be virtual. 10 | /// 11 | /// Furthermore, when invoking a virtual method from a base class 12 | /// pointer/reference, the decision on which to call is made based on the type 13 | /// that the pointer/reference is referring to. 14 | /// 15 | /// Clearly, an abstract method should always be virtual. 16 | virtual void run() = 0; 17 | }; 18 | 19 | class Fox : public Animal { 20 | public: 21 | Fox() = default; // Constructor 22 | virtual ~Fox() = default; // Destructor 23 | 24 | virtual void run() override { std::cout << "Fox is running" << std::endl; } 25 | }; 26 | 27 | class Dog : public Animal { 28 | public: 29 | Dog() = default; // Constructor 30 | virtual ~Dog() = default; // Destructor 31 | 32 | virtual void run() override { std::cout << "Dog is running" << std::endl; } 33 | }; 34 | 35 | int main() { 36 | Fox FoxObj = Fox(); 37 | Animal &AnimalRef = FoxObj; 38 | AnimalRef.run(); 39 | Fox &FoxRef = dynamic_cast(AnimalRef); 40 | FoxRef.run(); 41 | try { 42 | Dog &DogRef = dynamic_cast(AnimalRef); 43 | DogRef.run(); 44 | } catch (std::bad_cast &Except) { 45 | std::cerr << Except.what() << std::endl; 46 | } 47 | return 0; 48 | } 49 | -------------------------------------------------------------------------------- /Tutorial01-Introduction_to_LLVM/Example1-Cpp_Fundamentals/3-STL.cpp: -------------------------------------------------------------------------------- 1 | // clang-format off 2 | /// @file C++ Standard-Template-Library (STL) Data Structure and Variable Reference 3 | /// 4 | /// Please refer to the following websites for more detailed documentations regarding: 5 | /// - std::vector: http://www.cplusplus.com/reference/vector/vector/ 6 | /// - std::unordered_map: http://www.cplusplus.com/reference/unordered_map/unordered_map/ 7 | /// - More C++ Containers: http://www.cplusplus.com/reference/stl/ 8 | // clang-format on 9 | #include // Print 10 | #include // String 11 | #include // Dictionary 12 | #include // List 13 | 14 | int main() { 15 | // 'std' is the standard namespace. It is used to avoid name clashes of 16 | // classes, variables, and functions. Classes/Variables/Functions that are 17 | // supported by the C++ standard library belong to this namespace. 18 | // 19 | // 'vector' is the list-like data structure in STL. It is a *template class*. 20 | // A template class can be *instantiated* for various types. In the example 21 | // below, '' is an instantiation of the 'vector' template class (for 22 | // unsigned integer). Similarly, we can create another array of floating point 23 | // values using the statement: 24 | // 25 | // std::vector b = {1.0, 2.0, 3.0}; 26 | // 27 | std::vector A{1, 2, 3, 4, 5}; 28 | std::unordered_map B{ 29 | {"Red", 0}, {"Green", 1}, {"Blue", 2}}; 30 | // Traverse through 'a' using *iterators*. 'std::vector::iterator' 31 | // is the typename for the iterators. If you find it tedious, you can let the 32 | // compiler automatically infer the typename for you: 33 | // 34 | // for (auto iter = a.begin(); ...) 35 | // 36 | for (std::vector::iterator Iter = A.begin(); Iter != A.end(); 37 | ++Iter) { 38 | // dereference the iterator the obtain the array value 39 | std::cout << *Iter << ", "; 40 | } 41 | std::cout << std::endl; // newline character 42 | 43 | for (std::unordered_map::iterator Iter = B.begin(); 44 | Iter != B.end(); ++Iter) { 45 | // When we dereference the iterator, what we get is a *reference* to a 46 | // *pair* object. The first element of the pair reference is the *constant* 47 | // key, and the second element is the value corresponding to the key. 48 | std::pair &KeyValuePair = *Iter; 49 | 50 | std::cout << "(" << KeyValuePair.first << ", " << KeyValuePair.second 51 | << "), "; 52 | // Alternatively, we can also write: 53 | // 54 | // std::cout << ... Iter->first ... Iter->second ... 55 | // 56 | } 57 | std::cout << std::endl; // newline character 58 | return 0; 59 | } 60 | -------------------------------------------------------------------------------- /Tutorial01-Introduction_to_LLVM/Example1-Cpp_Fundamentals/Makefile: -------------------------------------------------------------------------------- 1 | CC := g++ 2 | CXXFLAGS := -std=c++11 -Wall 3 | 4 | EXES := $(basename $(wildcard *.cpp)) 5 | all: $(EXES) 6 | 7 | %: %.cpp 8 | 9 | .PHONY: format tidy clean 10 | format: *.cpp 11 | clang-format -i $^ 12 | 13 | tidy: *.cpp 14 | clang-tidy --header-filter=.* $^ -- 15 | 16 | clean: 17 | $(RM) $(EXES) 18 | -------------------------------------------------------------------------------- /Tutorial01-Introduction_to_LLVM/README.md: -------------------------------------------------------------------------------- 1 | # Tutorial 1 Introduction to LLVM 2 | 3 | **Handout**: [\[Overleaf\]](https://www.overleaf.com/read/ntrxhjmhkkrt) 4 | 5 | ## TL'DR 6 | 7 | - C++ Fundamentals 8 | - Pass by Reference 9 | - Public Inheritance 10 | - Templates and Instantiations 11 | - Standard Template Library (STL) 12 | - How to write an LLVM Analysis pass? 13 | - Intermediate Representation (IR) and Optimization Passes 14 | - Analysis vs. Transform 15 | - LLVM Module, Iterators, Downcasting 16 | - LLVM Pass Interfaces 17 | 18 | ## Examples 19 | 20 | 1. `Cpp_Fundamentals` shows you some basic concepts and usage of C++, including 21 | variable references, public inheritance, and standard template libraries. 22 | ```Bash 23 | /Example1-Cpp_Fundamentals$ make 24 | /Example1-Cpp_Fundamentals$ ./1-VarReference 25 | /Example1-Cpp_Fundamentals$ ./2-PublicInheritance 26 | /Example1-Cpp_Fundamentals$ ./3-STL 27 | ``` 28 | -------------------------------------------------------------------------------- /Tutorial02-Introduction_to_LLVM_ii/Example1-Transform_Pass_Example/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.18.4) 2 | project(TransformPassSample) 3 | set(CMAKE_EXPORT_COMPILE_COMMANDS ON) 4 | 5 | set(LLVM_VERSION 6 | "16" 7 | CACHE STRING "LLVM Version") 8 | 9 | execute_process( 10 | COMMAND llvm-config-${LLVM_VERSION} --cxxflags 11 | OUTPUT_VARIABLE LLVM_CXXFLAGS 12 | OUTPUT_STRIP_TRAILING_WHITESPACE) 13 | set(CMAKE_CXX_FLAGS "${LLVM_CXXFLAGS}") 14 | if(NOT CMAKE_BUILD_TYPE OR CMAKE_BUILD_TYPE STREQUAL "Debug") 15 | set(CMAKE_CXX_CLANG_TIDY 16 | "clang-tidy-${LLVM_VERSION};--extra-arg-before=-stdlib=libc++") 17 | message(STATUS "Enabling clang-tidy") 18 | 19 | execute_process( 20 | COMMAND llvm-config-${LLVM_VERSION} --includedir 21 | OUTPUT_VARIABLE LLVM_INCLUDEDIR 22 | OUTPUT_STRIP_TRAILING_WHITESPACE) 23 | set(CMAKE_CXX_FLAGS 24 | "${CMAKE_CXX_FLAGS} -isystem ${LLVM_INCLUDEDIR} -Wall -Wextra -Werror") 25 | endif() 26 | 27 | add_subdirectory(lib) 28 | 29 | include(CTest) 30 | enable_testing() 31 | add_subdirectory(test) 32 | -------------------------------------------------------------------------------- /Tutorial02-Introduction_to_LLVM_ii/Example1-Transform_Pass_Example/lib/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_library(TransformPassSample SHARED Transform.cpp) 2 | -------------------------------------------------------------------------------- /Tutorial02-Introduction_to_LLVM_ii/Example1-Transform_Pass_Example/lib/Transform.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | using namespace llvm; 10 | 11 | namespace { 12 | 13 | class TransformPass final : public PassInfoMixin { 14 | private: 15 | bool runOnBasicBlock(BasicBlock &B) { 16 | // get the first and second instruction 17 | Instruction &Inst1st = *B.begin(), &Inst2nd = *(++B.begin()); 18 | 19 | // The address of the 1st instruction is equal to that of the 1st operand of 20 | // the 2nd instruction. 21 | assert(&Inst1st == Inst2nd.getOperand(0)); 22 | 23 | // print the 1st instruction 24 | outs() << "I am the first instruction: " << Inst1st << "\n"; 25 | // print the 1st instruction as an operand 26 | outs() << "Me as an operand: "; 27 | Inst1st.printAsOperand(outs(), false); 28 | outs() << "\n"; 29 | 30 | // User-Use-Value 31 | outs() << "My operands:\n"; 32 | for (auto *Iter = Inst1st.op_begin(); Iter != Inst1st.op_end(); ++Iter) { 33 | Value *Operand = *Iter; 34 | 35 | if (Argument *Arg = dyn_cast(Operand)) { 36 | outs() << "\tI am function " << Arg->getParent()->getName() << "\'s #" 37 | << Arg->getArgNo() << " argument" 38 | << "\n"; 39 | } 40 | if (ConstantInt *C = dyn_cast(Operand)) { 41 | outs() << "\tI am a constant integer of value " << C->getValue() 42 | << "\n"; 43 | } 44 | } 45 | 46 | outs() << "My users:\n"; 47 | for (auto Iter = Inst1st.user_begin(); Iter != Inst1st.user_end(); ++Iter) { 48 | outs() << "\t" << *(dyn_cast(*Iter)) << "\n"; 49 | } 50 | 51 | outs() << "My uses (same with users):\n"; 52 | for (auto Iter = Inst1st.use_begin(); Iter != Inst1st.use_end(); ++Iter) { 53 | outs() << "\t" << *(dyn_cast(Iter->getUser())) << "\n"; 54 | } 55 | 56 | // Instruction Manipulation 57 | Instruction *NewInst = BinaryOperator::Create( 58 | Instruction::Add, Inst1st.getOperand(0), Inst1st.getOperand(0)); 59 | 60 | NewInst->insertAfter(&Inst1st); 61 | // Two Questions for you to answer: 62 | // 63 | // (1) Is there any alternative to updating each reference separately? 64 | // Please check the documentation and try answering this. 65 | // 66 | // (2) What happens if we update the use references without the insertion? 67 | Inst1st.user_begin()->setOperand(0, NewInst); 68 | 69 | return true; 70 | } 71 | 72 | bool runOnFunction(Function &F) { 73 | bool Transformed = false; 74 | 75 | for (auto Iter = F.begin(); Iter != F.end(); ++Iter) { 76 | if (runOnBasicBlock(*Iter)) { 77 | Transformed = true; 78 | } 79 | } 80 | 81 | return Transformed; 82 | } 83 | 84 | public: 85 | PreservedAnalyses run(Module &M, ModuleAnalysisManager &) { 86 | for (auto Iter = M.begin(); Iter != M.end(); ++Iter) { 87 | if (runOnFunction(*Iter)) { 88 | return PreservedAnalyses::none(); 89 | } 90 | } 91 | return PreservedAnalyses::all(); 92 | } 93 | }; 94 | 95 | } // anonymous namespace 96 | 97 | extern "C" PassPluginLibraryInfo llvmGetPassPluginInfo() { 98 | return { 99 | .APIVersion = LLVM_PLUGIN_API_VERSION, 100 | .PluginName = "FunctionInfo", 101 | .PluginVersion = LLVM_VERSION_STRING, 102 | .RegisterPassBuilderCallbacks = 103 | [](PassBuilder &PB) { 104 | PB.registerPipelineParsingCallback( 105 | [](StringRef Name, ModulePassManager &MPM, 106 | ArrayRef) -> bool { 107 | if (Name == "transform") { 108 | MPM.addPass(TransformPass()); 109 | return true; 110 | } 111 | return false; 112 | }); 113 | } // RegisterPassBuilderCallbacks 114 | }; // struct PassPluginLibraryInfo 115 | } 116 | -------------------------------------------------------------------------------- /Tutorial02-Introduction_to_LLVM_ii/Example1-Transform_Pass_Example/test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | execute_process( 2 | COMMAND llvm-config-${LLVM_VERSION} --bindir 3 | OUTPUT_VARIABLE LLVM_BINDIR 4 | OUTPUT_STRIP_TRAILING_WHITESPACE) 5 | set(CMAKE_LIBRARY_OUTPUT_DIR "${CMAKE_BINARY_DIR}/lib") 6 | 7 | configure_file(lit.cfg.in.py lit.cfg.py @ONLY) 8 | 9 | add_test(NAME TransformPassSampleTest COMMAND lit -a 10 | ${CMAKE_CURRENT_BINARY_DIR}) 11 | -------------------------------------------------------------------------------- /Tutorial02-Introduction_to_LLVM_ii/Example1-Transform_Pass_Example/test/Foo.ll: -------------------------------------------------------------------------------- 1 | ; RUN: opt -S -load-pass-plugin %dylibdir/libTransformPassSample.so \ 2 | ; RUN: -p=transform %s -o %basename_t | \ 3 | ; RUN: FileCheck --match-full-lines %s --check-prefix=LOG 4 | ; RUN: FileCheck --match-full-lines %s --input-file=%basename_t 5 | 6 | ; int foo(int e, int a) { 7 | ; int b = a + 1; 8 | ; int c = b * 2; 9 | ; b = e << 1; 10 | ; int d = b / 4; 11 | ; return c * d; 12 | ; } 13 | ; CHECK-LABEL: define dso_local i32 @foo(i32 noundef %0, i32 noundef %1) { 14 | define dso_local i32 @foo(i32 noundef %0, i32 noundef %1) #0 { 15 | ; LOG-LABEL: I am the first instruction: %3 = add nsw i32 %1, 1 16 | ; LOG-NEXT: Me as an operand: %3 17 | ; LOG-NEXT: My operands: 18 | ; LOG-NEXT: I am function foo's #1 argument 19 | ; LOG-NEXT: I am a constant integer of value 1 20 | ; LOG-NEXT: My users: 21 | ; LOG-NEXT: %4 = mul nsw i32 %3, 2 22 | ; LOG-NEXT: My uses (same with users): 23 | ; LOG-NEXT: %4 = mul nsw i32 %3, 2 24 | ; CHECK-NEXT: %3 = add nsw i32 %1, 1 25 | ; CHECK-NEXT: %4 = add i32 %1, %1 26 | %3 = add nsw i32 %1, 1 27 | ; CHECK-NEXT: %5 = mul nsw i32 %4, 2 28 | %4 = mul nsw i32 %3, 2 29 | ; @note The same variable 'b' gets assigned to a different value '%5'. 30 | ; CHECK-NEXT: %6 = shl i32 %0, 1 31 | %5 = shl i32 %0, 1 32 | ; CHECK-NEXT: %7 = sdiv i32 %6, 4 33 | %6 = sdiv i32 %5, 4 34 | ; CHECK-NEXT: %8 = mul nsw i32 %5, %7 35 | %7 = mul nsw i32 %4, %6 36 | ; CHECK-NEXT: ret i32 %8 37 | ret i32 %7 38 | } 39 | -------------------------------------------------------------------------------- /Tutorial02-Introduction_to_LLVM_ii/Example1-Transform_Pass_Example/test/lit.cfg.in.py: -------------------------------------------------------------------------------- 1 | import lit 2 | import lit.llvm 3 | 4 | lit.llvm.initialize(lit_config, config) 5 | 6 | from lit.llvm import llvm_config 7 | 8 | 9 | config.name = "TransformPassSample" 10 | config.test_format = lit.formats.ShTest() 11 | config.test_source_root = "@CMAKE_CURRENT_SOURCE_DIR@" 12 | config.test_exec_root = "@CMAKE_CURRENT_BINARY_DIR@" 13 | config.suffixes = [".c", ".ll"] 14 | 15 | config.substitutions.append((r"%dylibdir", "@CMAKE_LIBRARY_OUTPUT_DIR@")) 16 | 17 | config.llvm_config_bindir = "@LLVM_BINDIR@" 18 | llvm_config.add_tool_substitutions(["opt", "FileCheck"], config.llvm_config_bindir) 19 | -------------------------------------------------------------------------------- /Tutorial02-Introduction_to_LLVM_ii/Example2-Pass_Manager/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.18.4) 2 | project(PassManager) 3 | set(CMAKE_EXPORT_COMPILE_COMMANDS ON) 4 | 5 | set(LLVM_VERSION 6 | "16" 7 | CACHE STRING "LLVM Version") 8 | 9 | execute_process( 10 | COMMAND llvm-config-${LLVM_VERSION} --cxxflags 11 | OUTPUT_VARIABLE LLVM_CXXFLAGS 12 | OUTPUT_STRIP_TRAILING_WHITESPACE) 13 | set(CMAKE_CXX_FLAGS "${LLVM_CXXFLAGS}") 14 | if(NOT CMAKE_BUILD_TYPE OR CMAKE_BUILD_TYPE STREQUAL "Debug") 15 | set(CMAKE_CXX_CLANG_TIDY 16 | "clang-tidy-${LLVM_VERSION};--extra-arg-before=-stdlib=libc++") 17 | message(STATUS "Enabling clang-tidy") 18 | 19 | execute_process( 20 | COMMAND llvm-config-${LLVM_VERSION} --includedir 21 | OUTPUT_VARIABLE LLVM_INCLUDEDIR 22 | OUTPUT_STRIP_TRAILING_WHITESPACE) 23 | set(CMAKE_CXX_FLAGS 24 | "${CMAKE_CXX_FLAGS} -isystem ${LLVM_INCLUDEDIR} -Wall -Wextra -Werror") 25 | endif() 26 | 27 | add_subdirectory(lib) 28 | 29 | include(CTest) 30 | enable_testing() 31 | add_subdirectory(test) 32 | -------------------------------------------------------------------------------- /Tutorial02-Introduction_to_LLVM_ii/Example2-Pass_Manager/lib/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_library(PassManager SHARED PassManager.cpp) 2 | -------------------------------------------------------------------------------- /Tutorial02-Introduction_to_LLVM_ii/Example2-Pass_Manager/lib/PassManager.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | using namespace llvm; 8 | 9 | /// An analysis pass that hypothetically gathers some information from the 10 | /// module. 11 | class SomeAnalysis final : public AnalysisInfoMixin { 12 | public: 13 | /// The information that is collected by @c SomeAnalysis . In this specific 14 | /// example we are assuming it to be of type vector. 15 | struct Result : std::vector { 16 | /// Verify the validity of the analysis results. This method is implicitly 17 | /// invoked by the pass manager. 18 | bool invalidate(Module &, const PreservedAnalyses &PA, 19 | ModuleAnalysisManager::Invalidator &) { 20 | PreservedAnalyses::PreservedAnalysisChecker PAC = 21 | PA.getChecker(); 22 | bool ResIsNotValid = 23 | !(PAC.preserved() || PAC.preservedSet>()); 24 | outs() << "Verifying the validity of the analysis results: " 25 | << (ResIsNotValid ? 'N' : 'Y') << "\n"; 26 | return ResIsNotValid; 27 | } 28 | }; 29 | 30 | private: 31 | friend AnalysisInfoMixin; 32 | static AnalysisKey Key; 33 | 34 | public: 35 | Result run(Module &, ModuleAnalysisManager &) { 36 | outs() << "Some Analysis" 37 | << "\n"; 38 | Result SomeAnalysisResults; 39 | // pretend as if we have gathered some information here 40 | SomeAnalysisResults.push_back(1); 41 | SomeAnalysisResults.push_back(2); 42 | SomeAnalysisResults.push_back(3); 43 | return SomeAnalysisResults; 44 | } 45 | }; 46 | 47 | AnalysisKey SomeAnalysis::Key; 48 | 49 | class SomeTransformThatPreserves final 50 | : public PassInfoMixin { 51 | public: 52 | PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM) { 53 | outs() << "Some Transform that preserves" 54 | << "\n"; 55 | SomeAnalysis::Result &SomeAnalysisResult = MAM.getResult(M); 56 | for (const unsigned Res : SomeAnalysisResult) { 57 | outs() << Res << ", "; 58 | } 59 | outs() << "\n"; 60 | // indicate that we are preserving `SomeAnalysis` 61 | PreservedAnalyses PA = PreservedAnalyses::none(); 62 | PA.preserve(); 63 | return PA; 64 | } 65 | }; 66 | 67 | class SomeTransformThatDoesNOTPreserve final 68 | : public PassInfoMixin { 69 | public: 70 | PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM) { 71 | outs() << "Some Transform that does NOT preserve" 72 | << "\n"; 73 | SomeAnalysis::Result &SomeAnalysisResult = MAM.getResult(M); 74 | for (const unsigned Res : SomeAnalysisResult) { 75 | outs() << Res << ", "; 76 | } 77 | outs() << "\n"; 78 | // indicate that we are abandoning (i.e., not preserving) `SomeAnalysis` 79 | PreservedAnalyses PA = PreservedAnalyses::all(); 80 | PA.abandon(); 81 | return PA; 82 | } 83 | }; 84 | 85 | class AnotherTransform final : public PassInfoMixin { 86 | public: 87 | PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM) { 88 | outs() << "Another Transform" 89 | << "\n"; 90 | SomeAnalysis::Result &SomeAnalysisResult = MAM.getResult(M); 91 | for (const unsigned Res : SomeAnalysisResult) { 92 | outs() << Res << ", "; 93 | } 94 | outs() << "\n"; 95 | return PreservedAnalyses::none(); 96 | } 97 | }; 98 | 99 | extern "C" PassPluginLibraryInfo llvmGetPassPluginInfo() { 100 | return { 101 | .APIVersion = LLVM_PLUGIN_API_VERSION, 102 | .PluginName = "PassManager", 103 | .PluginVersion = LLVM_VERSION_STRING, 104 | .RegisterPassBuilderCallbacks = 105 | [](PassBuilder &PB) { 106 | // register the analysis pass so that it can be requested by others 107 | PB.registerAnalysisRegistrationCallback( 108 | [](ModuleAnalysisManager &MAM) { 109 | MAM.registerPass([&]() { return SomeAnalysis(); }); 110 | }); 111 | PB.registerPipelineParsingCallback( 112 | [](StringRef Name, ModulePassManager &MPM, 113 | ArrayRef) -> bool { 114 | if (Name == "some-transform-that-preserves") { 115 | MPM.addPass(SomeTransformThatPreserves()); 116 | return true; 117 | } 118 | if (Name == "some-transform-that-does-NOT-preserve") { 119 | MPM.addPass(SomeTransformThatDoesNOTPreserve()); 120 | return true; 121 | } 122 | if (Name == "another-transform") { 123 | MPM.addPass(AnotherTransform()); 124 | return true; 125 | } 126 | return false; 127 | }); 128 | } // RegisterPassBuilderCallbacks 129 | }; // struct PassPluginLibraryInfo 130 | } 131 | -------------------------------------------------------------------------------- /Tutorial02-Introduction_to_LLVM_ii/Example2-Pass_Manager/test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | execute_process( 2 | COMMAND llvm-config-${LLVM_VERSION} --bindir 3 | OUTPUT_VARIABLE LLVM_BINDIR 4 | OUTPUT_STRIP_TRAILING_WHITESPACE) 5 | set(CMAKE_LIBRARY_OUTPUT_DIR "${CMAKE_BINARY_DIR}/lib") 6 | 7 | configure_file(lit.cfg.in.py lit.cfg.py @ONLY) 8 | 9 | add_test(NAME PassManagerTest COMMAND lit -a ${CMAKE_CURRENT_BINARY_DIR}) 10 | -------------------------------------------------------------------------------- /Tutorial02-Introduction_to_LLVM_ii/Example2-Pass_Manager/test/Foo.c: -------------------------------------------------------------------------------- 1 | // clang-format off 2 | // RUN: clang -O2 -S -emit-llvm -c %s -o %basename_t.ll 3 | // RUN: opt -load-pass-plugin=%dylibdir/libPassManager.so \ 4 | // RUN: -p=some-transform-that-preserves,another-transform,some-transform-that-does-NOT-preserve,another-transform \ 5 | // RUN: -disable-output %basename_t.ll 2>&1 | \ 6 | // RUN: FileCheck --match-full-lines %s 7 | // clang-format on 8 | 9 | // CHECK: Some Transform that preserves 10 | // CHECK-NEXT: Some Analysis 11 | // CHECK-NEXT: 1, 2, 3, 12 | // CHECK-NEXT: Verifying the validity of the analysis results: Y 13 | // CHECK-NEXT: Another Transform 14 | // CHECK-NEXT: 1, 2, 3, 15 | // CHECK-NEXT: Verifying the validity of the analysis results: N 16 | 17 | // CHECK-NEXT: Some Transform that does NOT preserve 18 | // CHECK-NEXT: Some Analysis 19 | // CHECK-NEXT: 1, 2, 3, 20 | // CHECK-NEXT: Verifying the validity of the analysis results: N 21 | // CHECK-NEXT: Another Transform 22 | 23 | // Note that `SomeAnalysis` is invoked again, due to the fact that the previous 24 | // transform abandons its results. 25 | 26 | // CHECK-NEXT: Some Analysis 27 | // CHECK-NEXT: 1, 2, 3, 28 | // CHECK-NEXT: Verifying the validity of the analysis results: N 29 | int main() { return 0; } 30 | -------------------------------------------------------------------------------- /Tutorial02-Introduction_to_LLVM_ii/Example2-Pass_Manager/test/lit.cfg.in.py: -------------------------------------------------------------------------------- 1 | import lit 2 | import lit.llvm 3 | 4 | lit.llvm.initialize(lit_config, config) 5 | 6 | from lit.llvm import llvm_config 7 | 8 | 9 | config.name = "@CMAKE_PROJECT_NAME@" 10 | config.test_format = lit.formats.ShTest() 11 | config.test_source_root = "@CMAKE_CURRENT_SOURCE_DIR@" 12 | config.test_exec_root = "@CMAKE_CURRENT_BINARY_DIR@" 13 | config.suffixes = [".c", ".ll"] 14 | 15 | config.substitutions.append((r"%dylibdir", "@CMAKE_LIBRARY_OUTPUT_DIR@")) 16 | 17 | config.llvm_config_bindir = "@LLVM_BINDIR@" 18 | llvm_config.add_tool_substitutions( 19 | ["clang", "opt", "FileCheck"], config.llvm_config_bindir 20 | ) 21 | -------------------------------------------------------------------------------- /Tutorial02-Introduction_to_LLVM_ii/README.md: -------------------------------------------------------------------------------- 1 | # Tutorial 2 Introduction to LLVM ii 2 | 3 | **Handout**: [\[Overleaf\]](https://www.overleaf.com/read/vdwnnwdcshyx) 4 | 5 | ## TL'DR 6 | 7 | - User-Use-Value Relationship 8 | - LLVM Pass Manager: Require & Preserve 9 | 10 | ## Examples 11 | 12 | 1. `Transform_Pass_Example` shows you how to traverse through the users and 13 | operands of an instruction, and also how to insert new instructions into the 14 | module. 15 | ```Bash 16 | /Example1-Transform_Pass_Example$ mkdir build && cd build 17 | /Example1-Transform_Pass_Example/build$ cmake -DCMAKE_BUILD_TYPE=Release .. 18 | /Example1-Transform_Pass_Example/build$ make 19 | /Example1-Transform_Pass_Example/build$ ctest -V 20 | ``` 21 | 1. `Pass_Manager` shows you how to require and preserve/abandon other analysis 22 | passes. 23 | ```Bash 24 | /Example2-Pass_Manager$ mkdir build && cd build 25 | /Example2-Pass_Manager/build$ cmake -DCMAKE_BUILD_TYPE=Release .. 26 | /Example2-Pass_Manager/build$ make 27 | /Example2-Pass_Manager/build$ ctest -V 28 | ``` 29 | -------------------------------------------------------------------------------- /Tutorial03-Dataflow_Analysis/README.md: -------------------------------------------------------------------------------- 1 | # Tutorial 3 Dataflow Analysis 2 | 3 | **Handout**: [\[Overleaf\]](https://www.overleaf.com/read/bbkbmgnqqffw) 4 | 5 | ## TL'DR 6 | 7 | - Dataflow Analysis Case Studies: 8 | - Available Expressions 9 | - Dominators 10 | - Constant Propagation 11 | - Dataflow Analysis Solutions: $\mathrm{FP}\le\mathrm{MFP}\le\mathrm{MOP}\le\mathrm{Perfect}$ 12 | -------------------------------------------------------------------------------- /Tutorial04-Dataflow_Analysis_ii/README.md: -------------------------------------------------------------------------------- 1 | # Tutorial 4 Dataflow Analysis (ii) 2 | 3 | **Handout**: [\[Overleaf\]](https://www.overleaf.com/read/ptfcckrwdpvn) 4 | 5 | ## TL'DR 6 | 7 | - Iterative Framework 8 | - Available Expressions: 9 | - Forward Analysis 10 | - Expression: `InstVisitor` 11 | - Expression 12 | - Intersect 13 | -------------------------------------------------------------------------------- /Tutorial05-Lazy_Code_Motion/README.md: -------------------------------------------------------------------------------- 1 | # Tutorial 5 Lazy Code Motion 2 | 3 | **Handout**: [\[Overleaf\]](https://www.overleaf.com/read/dyjffnjmznyn) 4 | 5 | ## TL'DR 6 | 7 | - Lazy Code Motion 8 | - Preprocessing: Critical Edge and Synthetic Block 9 |

10 | 11 |

12 | -------------------------------------------------------------------------------- /Tutorial06-Scalar_Evolution/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.18.4) 2 | project(SCEV) 3 | set(CMAKE_EXPORT_COMPILE_COMMANDS ON) 4 | 5 | set(LLVM_VERSION 6 | "16" 7 | CACHE STRING "LLVM Version") 8 | 9 | execute_process( 10 | COMMAND llvm-config-${LLVM_VERSION} --cxxflags 11 | OUTPUT_VARIABLE LLVM_CXXFLAGS 12 | OUTPUT_STRIP_TRAILING_WHITESPACE) 13 | set(CMAKE_CXX_FLAGS "${LLVM_CXXFLAGS}") 14 | if(NOT CMAKE_BUILD_TYPE OR CMAKE_BUILD_TYPE STREQUAL "Debug") 15 | set(CMAKE_CXX_CLANG_TIDY 16 | "clang-tidy-${LLVM_VERSION};--extra-arg-before=-stdlib=libc++") 17 | message(STATUS "Enabling clang-tidy") 18 | 19 | execute_process( 20 | COMMAND llvm-config-${LLVM_VERSION} --includedir 21 | OUTPUT_VARIABLE LLVM_INCLUDEDIR 22 | OUTPUT_STRIP_TRAILING_WHITESPACE) 23 | set(CMAKE_CXX_FLAGS 24 | "${CMAKE_CXX_FLAGS} -isystem ${LLVM_INCLUDEDIR} -Wall -Wextra -Werror") 25 | endif() 26 | 27 | add_subdirectory(lib) 28 | 29 | include(CTest) 30 | enable_testing() 31 | add_subdirectory(test) 32 | -------------------------------------------------------------------------------- /Tutorial06-Scalar_Evolution/README.md: -------------------------------------------------------------------------------- 1 | # Tutorial 6 Scalar Evolution 2 | 3 | **Handout**: [\[Overleaf\]](https://www.overleaf.com/read/qyzvpfzxkrns) 4 | 5 | ## TL'DR 6 | 7 | - Scalar Evolution 8 | - Chain of Recurrences 9 | - Strength Reduction 10 | - Folding Chains of Recurrences 11 | - SCEV in LLVM 12 | 13 | ## Examples 14 | 15 | The example shows you how to use the `print` pass of LLVM to 16 | print interesting information of loop variables in a program, and furthermore, 17 | how to build on top of the `ScalarEvolution` pass by obtaining its result within 18 | a function pass. 19 | ``` 20 | $ mkdir build && cd build 21 | $ cmake -DCMAKE_BUILD_TYPE=Release .. 22 | $ make 23 | $ ctest -V 24 | ``` 25 | -------------------------------------------------------------------------------- /Tutorial06-Scalar_Evolution/lib/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_library(SCEV SHARED SCEV.cpp) 2 | -------------------------------------------------------------------------------- /Tutorial06-Scalar_Evolution/lib/SCEV.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | using namespace llvm; 10 | 11 | class SomePassThatUsesSCEV final : public PassInfoMixin { 12 | public: 13 | PreservedAnalyses run(Function &F, FunctionAnalysisManager &FAM) { 14 | ScalarEvolution &SCEVAnalysisResult = 15 | FAM.getResult(F); 16 | 17 | for (Instruction &I : instructions(F)) { 18 | if (const SCEV *SCEVOfI = SCEVAnalysisResult.getSCEV(&I)) { 19 | if (!isa(SCEVOfI) && !isa(SCEVOfI)) { 20 | continue; 21 | } 22 | outs() << "Instruction=" << I << " : " << *SCEVOfI << "\n"; 23 | } 24 | } 25 | return PreservedAnalyses::all(); 26 | } 27 | }; 28 | 29 | extern "C" PassPluginLibraryInfo llvmGetPassPluginInfo() { 30 | return { 31 | .APIVersion = LLVM_PLUGIN_API_VERSION, 32 | .PluginName = "SCEV", 33 | .PluginVersion = LLVM_VERSION_STRING, 34 | .RegisterPassBuilderCallbacks = 35 | [](PassBuilder &PB) { 36 | PB.registerPipelineParsingCallback( 37 | [](StringRef Name, FunctionPassManager &FPM, 38 | ArrayRef) -> bool { 39 | if (Name == "some-pass-that-uses-scev") { 40 | FPM.addPass(SomePassThatUsesSCEV()); 41 | return true; 42 | } 43 | return false; 44 | }); 45 | } // RegisterPassBuilderCallbacks 46 | }; // struct PassPluginLibraryInfo 47 | } 48 | -------------------------------------------------------------------------------- /Tutorial06-Scalar_Evolution/test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | execute_process( 2 | COMMAND llvm-config-${LLVM_VERSION} --bindir 3 | OUTPUT_VARIABLE LLVM_BINDIR 4 | OUTPUT_STRIP_TRAILING_WHITESPACE) 5 | set(CMAKE_LIBRARY_OUTPUT_DIR "${CMAKE_BINARY_DIR}/lib") 6 | 7 | configure_file(lit.cfg.in.py lit.cfg.py @ONLY) 8 | 9 | add_test(NAME SCEVTest COMMAND lit -a ${CMAKE_CURRENT_BINARY_DIR}) 10 | -------------------------------------------------------------------------------- /Tutorial06-Scalar_Evolution/test/Foo.c: -------------------------------------------------------------------------------- 1 | // clang-format off 2 | // RUN: clang -Xclang -disable-O0-optnone -S -emit-llvm -c %s -o %basename_t.ll 3 | // RUN: opt -p=mem2reg -S -o %basename_t.M2R.ll %basename_t.ll 4 | // RUN: opt -load-pass-plugin=%dylibdir/libSCEV.so -p=some-pass-that-uses-scev \ 5 | // RUN: -disable-output %basename_t.M2R.ll 2>&1 | \ 6 | // RUN: FileCheck --match-full-lines --check-prefix=SCEV %s 7 | // RUN: opt -p="print" \ 8 | // RUN: -disable-output %basename_t.M2R.ll 2>&1 | \ 9 | // RUN: FileCheck --match-full-lines --check-prefix=SCEVPRINT %s 10 | // clang-format on 11 | #include 12 | 13 | void foo() { 14 | for (int i = 0; i < 100; ++i) { 15 | // SCEV: Instruction= %11 = add nsw i32 %10, 7 : {7,+,6,+,10,+,6}<%1> 16 | // SCEVPRINT-LABEL: %11 = add nsw i32 %10, 7 17 | // SCEVPRINT-NEXT: --> {7,+,6,+,10,+,6}<%1> U: full-set S: full-set Exits: 1020307 LoopDispositions: { %1: Computable } 18 | int j = i * i * i + 2 * i * i + 3 * i + 7; 19 | // SCEV: Instruction= %18 = sub nsw i32 %16, %17 : 1 20 | // SCEVPRINT-LABEL: %18 = sub nsw i32 %16, %17 21 | // SCEVPRINT-NEXT: --> 1 U: [1,2) S: [1,2) Exits: 1 LoopDispositions: { %1: Invariant } 22 | int k = (i + 1) * (i + 1) - i * i - 2 * i; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Tutorial06-Scalar_Evolution/test/lit.cfg.in.py: -------------------------------------------------------------------------------- 1 | import lit 2 | import lit.llvm 3 | 4 | lit.llvm.initialize(lit_config, config) 5 | 6 | from lit.llvm import llvm_config 7 | 8 | 9 | config.name = "@CMAKE_PROJECT_NAME@" 10 | config.test_format = lit.formats.ShTest() 11 | config.test_source_root = "@CMAKE_CURRENT_SOURCE_DIR@" 12 | config.test_exec_root = "@CMAKE_CURRENT_BINARY_DIR@" 13 | config.suffixes = [".c", ".ll"] 14 | 15 | config.substitutions.append((r"%dylibdir", "@CMAKE_LIBRARY_OUTPUT_DIR@")) 16 | 17 | config.llvm_config_bindir = "@LLVM_BINDIR@" 18 | llvm_config.add_tool_substitutions( 19 | ["clang", "opt", "FileCheck"], config.llvm_config_bindir 20 | ) 21 | -------------------------------------------------------------------------------- /Tutorial07-Register_Allocation/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.18.4) 2 | project(RegAlloc) 3 | set(CMAKE_EXPORT_COMPILE_COMMANDS ON) 4 | 5 | set(LLVM_VERSION 6 | "16" 7 | CACHE STRING "LLVM Version") 8 | 9 | execute_process( 10 | COMMAND llvm-config-${LLVM_VERSION} --cxxflags 11 | OUTPUT_VARIABLE LLVM_CXXFLAGS 12 | OUTPUT_STRIP_TRAILING_WHITESPACE) 13 | set(CMAKE_CXX_FLAGS "${LLVM_CXXFLAGS}") 14 | if(NOT CMAKE_BUILD_TYPE OR CMAKE_BUILD_TYPE STREQUAL "Debug") 15 | set(CMAKE_CXX_CLANG_TIDY 16 | "clang-tidy-${LLVM_VERSION};--extra-arg-before=-stdlib=libc++") 17 | message(STATUS "Enabling clang-tidy") 18 | 19 | execute_process( 20 | COMMAND llvm-config-${LLVM_VERSION} --includedir 21 | OUTPUT_VARIABLE LLVM_INCLUDEDIR 22 | OUTPUT_STRIP_TRAILING_WHITESPACE) 23 | set(CMAKE_CXX_FLAGS 24 | "${CMAKE_CXX_FLAGS} -isystem ${LLVM_INCLUDEDIR} -Wall -Wextra -Werror") 25 | endif() 26 | 27 | add_subdirectory(lib) 28 | 29 | include(CTest) 30 | enable_testing() 31 | add_subdirectory(test) 32 | -------------------------------------------------------------------------------- /Tutorial07-Register_Allocation/RAGreedy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UofT-EcoSystem/CSCD70/2400817bc46b6affae99769e613b8b5a9cf0d39a/Tutorial07-Register_Allocation/RAGreedy.png -------------------------------------------------------------------------------- /Tutorial07-Register_Allocation/RAMinimal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UofT-EcoSystem/CSCD70/2400817bc46b6affae99769e613b8b5a9cf0d39a/Tutorial07-Register_Allocation/RAMinimal.png -------------------------------------------------------------------------------- /Tutorial07-Register_Allocation/README.md: -------------------------------------------------------------------------------- 1 | # Tutorial 7 Register Allocation 2 | 3 | **Handout**: [\[Overleaf\]](https://www.overleaf.com/read/bjrphznfydcg) 4 | 5 | ## TL'DR 6 | 7 | 8 | 9 | 14 | 19 | 20 | 21 | 26 | 31 | 32 |
10 | 11 | RAMinimal 12 | 13 | 15 | 16 | RAGreedy 17 | 18 |
22 | 23 | ![](./RAMinimal.png) 24 | 25 | 27 | 28 | ![](./RAGreedy.png) 29 | 30 |
33 | 34 | - x86 Registers 35 | - Register Overlapping 36 | - Caller- vs. Callee-Saved Registers 37 | 38 | ## Examples 39 | 40 | The example shows you how to build a minimal register allocator that goes 41 | through the list of live intervals and materialize them whenever there are 42 | physical registers available. If none is available then the interval is spilled. 43 | ``` 44 | $ mkdir build && cd build 45 | $ cmake -DCMAKE_BUILD_TYPE=Release .. 46 | $ make 47 | $ ctest -V 48 | ``` 49 | -------------------------------------------------------------------------------- /Tutorial07-Register_Allocation/lib/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_library(RegAlloc SHARED RegAllocMinimal.cpp) 2 | -------------------------------------------------------------------------------- /Tutorial07-Register_Allocation/lib/Logging.h: -------------------------------------------------------------------------------- 1 | #pragma once // NOLINT(llvm-header-guard) 2 | 3 | #include 4 | 5 | namespace internal { 6 | 7 | struct InfoLogger { 8 | llvm::raw_ostream &Outs; 9 | InfoLogger(llvm::raw_ostream &Outs = llvm::outs()) : Outs(Outs) {} 10 | ~InfoLogger() { Outs << "\n"; } 11 | operator bool() const { return true; } 12 | }; 13 | 14 | } // namespace internal 15 | 16 | #define LOG_INFO \ 17 | if (auto Logger = internal::InfoLogger()) \ 18 | llvm::outs() << "[" << __FILE__ << ":" << __LINE__ << ", I] " 19 | 20 | #define BOLD(str) "\033[1m" << str << "\033[0m" 21 | -------------------------------------------------------------------------------- /Tutorial07-Register_Allocation/lib/RegAllocMinimal.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #include 19 | 20 | #include "Logging.h" 21 | 22 | using namespace llvm; 23 | 24 | namespace llvm { 25 | 26 | void initializeRAMinimalPass(PassRegistry &Registry); 27 | 28 | } // namespace llvm 29 | 30 | /// A minimal register allocator that goes through the list of live intervals 31 | /// and materialize them whenever there are physical registers available. If 32 | /// none is available then the interval is spilled. 33 | class RAMinimal final : public MachineFunctionPass, 34 | private LiveRangeEdit::Delegate { 35 | private: 36 | MachineFunction *MF; 37 | 38 | // Slot Indices 39 | const SlotIndexes *SI; 40 | // Virtual Register Mapping 41 | VirtRegMap *VRM; 42 | const TargetRegisterInfo *TRI; 43 | MachineRegisterInfo *MRI; 44 | // Live Intervals 45 | LiveIntervals *LIS; 46 | std::queue LIQ; // FIFO Queue 47 | void enqueue(LiveInterval *const LI) { 48 | LOG_INFO << "Pushing {Reg=" << BOLD(*LI) << "}"; 49 | LIQ.push(LI); 50 | } 51 | LiveInterval *dequeue() { 52 | if (LIQ.empty()) { 53 | return nullptr; 54 | } 55 | LiveInterval *LI = LIQ.front(); 56 | LOG_INFO << "Popping {Reg=" << BOLD(*LI) << "}"; 57 | LIQ.pop(); 58 | return LI; 59 | } 60 | // Live Register Matrix 61 | LiveRegMatrix *LRM; 62 | // Register Class Information 63 | RegisterClassInfo RCI; 64 | 65 | // Spiller 66 | std::unique_ptr SpillerInstance; 67 | SmallPtrSet DeadRemats; 68 | 69 | /// @brief Attempt to spill all live intervals that interfere with @c LI but 70 | /// have less spill weights. 71 | /// @return True if successful, false otherwise 72 | /// @sa selectOrSplit 3.3. 73 | bool spillInterferences(LiveInterval *const LI, MCRegister PhysReg, 74 | SmallVectorImpl *const SplitVirtRegs) { 75 | SmallVector IntfLIs; 76 | 77 | for (MCRegUnitIterator Units(PhysReg, TRI); Units.isValid(); ++Units) { 78 | LiveIntervalUnion::Query &Q = LRM->query(*LI, *Units); 79 | for (const LiveInterval *const IntfLI : reverse(Q.interferingVRegs())) { 80 | if (!IntfLI->isSpillable() || IntfLI->weight() > LI->weight()) { 81 | return false; 82 | } 83 | IntfLIs.push_back(IntfLI); 84 | } 85 | } 86 | // Spill each interfering vreg allocated to PhysRegs. 87 | for (unsigned IntfIdx = 0; IntfIdx < IntfLIs.size(); ++IntfIdx) { 88 | const LiveInterval *const LIToSpill = IntfLIs[IntfIdx]; 89 | // avoid duplicates 90 | if (!VRM->hasPhys(LIToSpill->reg())) { 91 | continue; 92 | } 93 | // Deallocate the interfering virtual registers. 94 | LRM->unassign(*LIToSpill); 95 | LiveRangeEdit LRE(LIToSpill, *SplitVirtRegs, *MF, *LIS, VRM, this, 96 | &DeadRemats); 97 | SpillerInstance->spill(LRE); 98 | } 99 | return true; 100 | } 101 | 102 | /// Allocate a physical register for @c LI , or have the spiller splits it 103 | /// into a list of virtual registers. 104 | MCRegister selectOrSplit(LiveInterval *const LI, 105 | SmallVectorImpl *const SplitVirtRegs) { 106 | /// 3.1. Obtain a plausible allocation order. 107 | ArrayRef Order = 108 | RCI.getOrder(MF->getRegInfo().getRegClass(LI->reg())); 109 | SmallVector Hints; 110 | bool IsHardHint = 111 | TRI->getRegAllocationHints(LI->reg(), Order, Hints, *MF, VRM, LRM); 112 | if (!IsHardHint) { 113 | for (const MCPhysReg &PhysReg : Order) { 114 | Hints.push_back(PhysReg); 115 | } 116 | } 117 | outs() << "Hint Registers: ["; 118 | for (const MCPhysReg &PhysReg : Hints) { 119 | outs() << TRI->getRegAsmName(PhysReg) << ", "; 120 | } 121 | outs() << "]\n"; 122 | 123 | SmallVector PhysRegSpillCandidates; 124 | for (MCRegister PhysReg : Hints) { 125 | /// 3.2. Check for interference on physical registers. 126 | switch (LRM->checkInterference(*LI, PhysReg)) { 127 | case LiveRegMatrix::IK_Free: 128 | // Here we directly (and naively) return the first physical register 129 | // that is available. 130 | outs() << "Allocating physical register " 131 | << BOLD(TRI->getRegAsmName(PhysReg)) << "\n"; 132 | return PhysReg; 133 | case LiveRegMatrix::IK_VirtReg: 134 | PhysRegSpillCandidates.push_back(PhysReg); 135 | continue; 136 | default: 137 | continue; 138 | } 139 | } 140 | /// 3.3. Attempt to spill all the interfering registers with less spill 141 | /// weight. 142 | /// @sa spillInterferences 143 | for (MCRegister PhysReg : PhysRegSpillCandidates) { 144 | if (!spillInterferences(LI, PhysReg, SplitVirtRegs)) { 145 | continue; 146 | } 147 | return PhysReg; 148 | } 149 | /// 3.4. Spill the current virtual register. 150 | LiveRangeEdit LRE(LI, *SplitVirtRegs, *MF, *LIS, VRM, this, &DeadRemats); 151 | SpillerInstance->spill(LRE); 152 | return 0; 153 | } 154 | 155 | public: 156 | static char ID; 157 | 158 | StringRef getPassName() const final { return "Minimal Register Allocator"; } 159 | RAMinimal() : MachineFunctionPass(ID) {} 160 | 161 | void getAnalysisUsage(AnalysisUsage &AU) const final { 162 | MachineFunctionPass::getAnalysisUsage(AU); 163 | AU.setPreservesCFG(); 164 | #define REQUIRE_AND_PRESERVE_PASS(PassName) \ 165 | AU.addRequired(); \ 166 | AU.addPreserved() 167 | 168 | REQUIRE_AND_PRESERVE_PASS(SlotIndexes); 169 | REQUIRE_AND_PRESERVE_PASS(VirtRegMap); 170 | REQUIRE_AND_PRESERVE_PASS(LiveIntervals); 171 | REQUIRE_AND_PRESERVE_PASS(LiveRegMatrix); 172 | 173 | // The following passes are implicitly requested by the spiller. 174 | REQUIRE_AND_PRESERVE_PASS(LiveStacks); 175 | REQUIRE_AND_PRESERVE_PASS(AAResultsWrapperPass); 176 | REQUIRE_AND_PRESERVE_PASS(MachineDominatorTree); 177 | REQUIRE_AND_PRESERVE_PASS(MachineLoopInfo); 178 | REQUIRE_AND_PRESERVE_PASS(MachineBlockFrequencyInfo); 179 | } 180 | 181 | /// Request the all PHINode's are removed before doing the register 182 | /// allocation. 183 | MachineFunctionProperties getRequiredProperties() const final { 184 | return MachineFunctionProperties().set( 185 | MachineFunctionProperties::Property::NoPHIs); 186 | } 187 | /// After the register allocation, each virtual register no longer has a 188 | /// single definition. 189 | MachineFunctionProperties getClearedProperties() const final { 190 | return MachineFunctionProperties().set( 191 | MachineFunctionProperties::Property::IsSSA); 192 | } 193 | 194 | bool runOnMachineFunction(MachineFunction &MF) final { 195 | this->MF = &MF; 196 | 197 | outs() << "************************************************\n" 198 | << "* Machine Function\n" 199 | << "************************************************\n"; 200 | // The *SlotIndexes* maps each machine instruction to a unique ID. 201 | SI = &getAnalysis(); 202 | for (const MachineBasicBlock &MBB : MF) { 203 | MBB.print(outs(), SI); 204 | outs() << "\n"; 205 | } 206 | outs() << "************************************************\n\n"; 207 | 208 | // 1. Get the requested analysis results from the following passes: 209 | // - VirtRegMap 210 | // - LiveIntervals 211 | // - LiveRegMatrix 212 | // and setup the spiller. 213 | 214 | // The *VirtRegMap* maps virtual registers to physical registers and stack 215 | // slots. 216 | VRM = &getAnalysis(); 217 | // The *TargetRegisterInfo* is an immutable description of all the machine 218 | // registers the target has. 219 | TRI = &VRM->getTargetRegInfo(); 220 | // The *MachineRegisterInfo* has information of both the physical and the 221 | // virtual registers. 222 | MRI = &VRM->getRegInfo(); 223 | MRI->freezeReservedRegs(MF); // freeze the reserved registers before the 224 | // actual allocations begin 225 | // The *LiveIntervals* describe the live range of each virtual register. 226 | LIS = &getAnalysis(); 227 | // The *LiveRegMatrix* keeps track of virtual register interference along 228 | // two dimensions: slot indices and register units. The matrix is used by 229 | // register allocators to ensure that no interfering virtual registers get 230 | // assigned to overlapping physical registers. 231 | LRM = &getAnalysis(); 232 | // The *RegisterClassInfo* provides dynamic information about target 233 | // register classes. We will be using it to obtain a plausible allocation 234 | // order of physical registers. 235 | RCI.runOnMachineFunction(MF); 236 | 237 | VirtRegAuxInfo VRAI(MF, *LIS, *VRM, getAnalysis(), 238 | getAnalysis()); 239 | VRAI.calculateSpillWeightsAndHints(); 240 | SpillerInstance.reset(createInlineSpiller(*this, MF, *VRM, VRAI)); 241 | 242 | // 2. Obtain the virtual registers and push them to the worklist. 243 | for (unsigned VirtualRegIdx = 0; VirtualRegIdx < MRI->getNumVirtRegs(); 244 | ++VirtualRegIdx) { 245 | Register Reg = Register::index2VirtReg(VirtualRegIdx); 246 | // skip all unused registers 247 | if (MRI->reg_nodbg_empty(Reg)) { 248 | continue; 249 | } 250 | enqueue(&LIS->getInterval(Reg)); 251 | } 252 | 253 | // 3. Keep traversing until all the workitems in the list have been 254 | // processed. 255 | while (LiveInterval *const LI = dequeue()) { 256 | // again, skip all unused registers 257 | if (MRI->reg_nodbg_empty(LI->reg())) { 258 | LIS->removeInterval(LI->reg()); 259 | continue; 260 | } 261 | // invalidate all previous interference queries. 262 | LRM->invalidateVirtRegs(); 263 | 264 | // For each virtual register, Allocate to a physical register (if 265 | // available) or split to a list of virtual registers. 266 | SmallVector SplitVirtRegs; 267 | MCRegister PhysReg = selectOrSplit(LI, &SplitVirtRegs); 268 | 269 | if (PhysReg) { 270 | LRM->assign(*LI, PhysReg); 271 | } 272 | // enqueue the splitted live ranges 273 | for (Register Reg : SplitVirtRegs) { 274 | LiveInterval *LI = &LIS->getInterval(Reg); 275 | if (MRI->reg_nodbg_empty(LI->reg())) { 276 | LIS->removeInterval(LI->reg()); 277 | continue; 278 | } 279 | enqueue(LI); 280 | } 281 | } // while (dequeue()) 282 | // cleanup 283 | SpillerInstance->postOptimization(); 284 | for (MachineInstr *const DeadInst : DeadRemats) { 285 | LIS->RemoveMachineInstrFromMaps(*DeadInst); 286 | DeadInst->eraseFromParent(); 287 | } 288 | DeadRemats.clear(); 289 | return true; 290 | } 291 | }; 292 | 293 | char RAMinimal::ID = 0; 294 | 295 | namespace { 296 | 297 | RegisterRegAlloc MinimalRegAllocator("minimal", "Minimal Register Allocator", 298 | []() -> FunctionPass * { 299 | return new RAMinimal(); 300 | }); 301 | 302 | } // anonymous namespace 303 | 304 | INITIALIZE_PASS_BEGIN(RAMinimal, // NOLINT(misc-use-anonymous-namespace) 305 | "regallominimal", "Minimal Register Allocator", false, 306 | false) 307 | INITIALIZE_PASS_DEPENDENCY(SlotIndexes) 308 | INITIALIZE_PASS_DEPENDENCY(VirtRegMap) 309 | INITIALIZE_PASS_DEPENDENCY(LiveIntervals) 310 | INITIALIZE_PASS_DEPENDENCY(LiveRegMatrix) 311 | INITIALIZE_PASS_DEPENDENCY(LiveStacks); 312 | INITIALIZE_PASS_DEPENDENCY(AAResultsWrapperPass); 313 | INITIALIZE_PASS_DEPENDENCY(MachineDominatorTree); 314 | INITIALIZE_PASS_DEPENDENCY(MachineLoopInfo); 315 | INITIALIZE_PASS_DEPENDENCY(MachineBlockFrequencyInfo); 316 | INITIALIZE_PASS_END(RAMinimal, // NOLINT(misc-use-anonymous-namespace) 317 | "regallominimal", "Minimal Register Allocator", false, 318 | false) 319 | -------------------------------------------------------------------------------- /Tutorial07-Register_Allocation/test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | execute_process( 2 | COMMAND llvm-config-${LLVM_VERSION} --bindir 3 | OUTPUT_VARIABLE LLVM_BINDIR 4 | OUTPUT_STRIP_TRAILING_WHITESPACE) 5 | set(CMAKE_LIBRARY_OUTPUT_DIR "${CMAKE_BINARY_DIR}/lib") 6 | 7 | configure_file(lit.cfg.in.py lit.cfg.py @ONLY) 8 | 9 | add_test(NAME SCEVTest COMMAND lit -a ${CMAKE_CURRENT_BINARY_DIR}) 10 | -------------------------------------------------------------------------------- /Tutorial07-Register_Allocation/test/Foo.c: -------------------------------------------------------------------------------- 1 | // RUN: clang -O0 -Xclang -disable-O0-optnone -emit-llvm -c %s -o %basename_t.bc 2 | // RUN: opt -S -p=mem2reg %basename_t.bc -o %basename_t.ll 3 | // Run the minimal register allocator on the LLVM IR. 4 | // RUN: llc -load %dylibdir/libRegAlloc.so \ 5 | // RUN: -regalloc=minimal --relocation-model=pic \ 6 | // RUN: %basename_t.ll -o %basename_t.s 7 | // Compile the generated assembly into executable. 8 | // RUN: clang %basename_t.s -o %basename_t.exe 9 | // RUN: ./%basename_t.exe | FileCheck %s 10 | // CHECK: 023 11 | #include 12 | 13 | int g = 0; 14 | 15 | #define DEF() g++ 16 | #define USE(v) printf("%d", v) 17 | 18 | int main() { 19 | int A = DEF(), B, C, D; 20 | 21 | if (A) { 22 | B = DEF(); 23 | USE(A); 24 | D = B + 1; 25 | } else { 26 | C = DEF(); 27 | USE(A); 28 | D = C + 2; 29 | } 30 | A = DEF(); 31 | USE(A); 32 | USE(D); 33 | return 0; 34 | } 35 | -------------------------------------------------------------------------------- /Tutorial07-Register_Allocation/test/lit.cfg.in.py: -------------------------------------------------------------------------------- 1 | import lit 2 | import lit.llvm 3 | 4 | lit.llvm.initialize(lit_config, config) 5 | 6 | from lit.llvm import llvm_config 7 | 8 | 9 | config.name = "@CMAKE_PROJECT_NAME@" 10 | config.test_format = lit.formats.ShTest() 11 | config.test_source_root = "@CMAKE_CURRENT_SOURCE_DIR@" 12 | config.test_exec_root = "@CMAKE_CURRENT_BINARY_DIR@" 13 | config.suffixes = [".c", ".ll"] 14 | 15 | config.substitutions.append((r"%dylibdir", "@CMAKE_LIBRARY_OUTPUT_DIR@")) 16 | 17 | config.llvm_config_bindir = "@LLVM_BINDIR@" 18 | llvm_config.add_tool_substitutions( 19 | ["clang", "opt", "llc", "FileCheck"], config.llvm_config_bindir 20 | ) 21 | -------------------------------------------------------------------------------- /Tutorial10-Data_Dependency_Analysis/README.md: -------------------------------------------------------------------------------- 1 | # Tutorial 10 Data Dependency Analysis 2 | 3 | **Handout**: [\[Overleaf\]](https://www.overleaf.com/read/fsmqxzttmvvt) 4 | 5 | ## TL'DR 6 | 7 | - 4 Types of Basic Data Dependencies: RAW, WAR, WAW, RAR 8 | - Data Dependencies in Loops 9 | - Loop-Carried Dependence 10 | - Lexicographically-positive dependence distance 11 | - Loop Parallelization: Dependence as parallelization check 12 | - Loop Interchange: Dependence as validity check 13 | -------------------------------------------------------------------------------- /Website/Assignments/0.md: -------------------------------------------------------------------------------- 1 | ../../Assignment0-Introduction_to_Docker/README.md -------------------------------------------------------------------------------- /Website/Assignments/1.md: -------------------------------------------------------------------------------- 1 | ../../Assignment1-Introduction_to_LLVM/README.md -------------------------------------------------------------------------------- /Website/Assignments/2.md: -------------------------------------------------------------------------------- 1 | ../../Assignment2-Dataflow_Analysis/README.md -------------------------------------------------------------------------------- /Website/Assignments/3.md: -------------------------------------------------------------------------------- 1 | ../../Assignment3-Loop_Invariant_Code_Motion/README.md -------------------------------------------------------------------------------- /Website/Assignments/index.rst: -------------------------------------------------------------------------------- 1 | Assignments 2 | =========== 3 | 4 | .. toctree:: 5 | :hidden: 6 | 7 | 0 8 | 1 9 | 2 10 | 3 11 | 12 | ============================ ===================== ===================== 13 | | Release Due 14 | ============================ ===================== ===================== 15 | :doc:`0` Jan. 9 N/A 16 | :doc:`1` Jan. 9 Jan. 27 17 | :doc:`2` Feb. 4 Mar. 3 18 | :doc:`3` Mar. 24 Apr. 7 19 | ============================ ===================== ===================== 20 | -------------------------------------------------------------------------------- /Website/Doxygen/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # https://github.com/llvm/llvm-project/blob/main/llvm/docs/CMakeLists.txt 2 | cmake_minimum_required(VERSION 3.18.4) 3 | project(DoxygenDocs) 4 | 5 | find_package(Doxygen REQUIRED dot) 6 | 7 | if (DOXYGEN_FOUND) 8 | set(abs_top_srcdir ${CMAKE_CURRENT_SOURCE_DIR}/../..) 9 | set(DOT ${DOXYGEN_DOT_EXECUTABLE}) 10 | set(enable_searchengine "NO") 11 | set(searchengine_url "") 12 | set(enable_server_based_search "NO") 13 | set(enable_external_search "NO") 14 | set(extra_search_mappings "") 15 | set(llvm_doxygen_generate_qhp "NO") 16 | set(llvm_doxygen_qch_filename "") 17 | set(llvm_doxygen_qhp_namespace "") 18 | set(llvm_doxygen_qhelpgenerator_path "") 19 | set(llvm_doxygen_qhp_cust_filter_name "") 20 | set(llvm_doxygen_qhp_cust_filter_attrs "") 21 | set(DOT_IMAGE_FORMAT "png") 22 | 23 | configure_file(${CMAKE_CURRENT_SOURCE_DIR}/doxygen.cfg.in 24 | ${CMAKE_CURRENT_BINARY_DIR}/doxygen.cfg @ONLY) 25 | 26 | add_custom_target(Name ALL COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/doxygen.cfg 27 | WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) 28 | endif() 29 | -------------------------------------------------------------------------------- /Website/Lecture_Slides/CSCD70-Machine_Learning_Compilers-20230320.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UofT-EcoSystem/CSCD70/2400817bc46b6affae99769e613b8b5a9cf0d39a/Website/Lecture_Slides/CSCD70-Machine_Learning_Compilers-20230320.pdf -------------------------------------------------------------------------------- /Website/Lecture_Slides/CSCD70-Machine_Learning_Compilers-20230320.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UofT-EcoSystem/CSCD70/2400817bc46b6affae99769e613b8b5a9cf0d39a/Website/Lecture_Slides/CSCD70-Machine_Learning_Compilers-20230320.pptx -------------------------------------------------------------------------------- /Website/Lecture_Slides/Lecture 1 [Intro] 01.09.2023.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UofT-EcoSystem/CSCD70/2400817bc46b6affae99769e613b8b5a9cf0d39a/Website/Lecture_Slides/Lecture 1 [Intro] 01.09.2023.pptx -------------------------------------------------------------------------------- /Website/Lecture_Slides/Lecture 10 [Parallelization] 04.03.2023.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UofT-EcoSystem/CSCD70/2400817bc46b6affae99769e613b8b5a9cf0d39a/Website/Lecture_Slides/Lecture 10 [Parallelization] 04.03.2023.pptx -------------------------------------------------------------------------------- /Website/Lecture_Slides/Lecture 2 [Dataflow] 01.16.2023.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UofT-EcoSystem/CSCD70/2400817bc46b6affae99769e613b8b5a9cf0d39a/Website/Lecture_Slides/Lecture 2 [Dataflow] 01.16.2023.pptx -------------------------------------------------------------------------------- /Website/Lecture_Slides/Lecture 3 [Dataflow-2 and Loops] 01.23.2023.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UofT-EcoSystem/CSCD70/2400817bc46b6affae99769e613b8b5a9cf0d39a/Website/Lecture_Slides/Lecture 3 [Dataflow-2 and Loops] 01.23.2023.pptx -------------------------------------------------------------------------------- /Website/Lecture_Slides/Lecture 4 [SSA] 01.30.2023.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UofT-EcoSystem/CSCD70/2400817bc46b6affae99769e613b8b5a9cf0d39a/Website/Lecture_Slides/Lecture 4 [SSA] 01.30.2023.pptx -------------------------------------------------------------------------------- /Website/Lecture_Slides/Lecture 5 [LICM and Strength Reduction] 02.06.2023.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UofT-EcoSystem/CSCD70/2400817bc46b6affae99769e613b8b5a9cf0d39a/Website/Lecture_Slides/Lecture 5 [LICM and Strength Reduction] 02.06.2023.pptx -------------------------------------------------------------------------------- /Website/Lecture_Slides/Lecture 6 [Register Allocation] 02.13.2023.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UofT-EcoSystem/CSCD70/2400817bc46b6affae99769e613b8b5a9cf0d39a/Website/Lecture_Slides/Lecture 6 [Register Allocation] 02.13.2023.pptx -------------------------------------------------------------------------------- /Website/Lecture_Slides/Lecture 7 [Pointer Analysis] 02.27.2023.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UofT-EcoSystem/CSCD70/2400817bc46b6affae99769e613b8b5a9cf0d39a/Website/Lecture_Slides/Lecture 7 [Pointer Analysis] 02.27.2023.pptx -------------------------------------------------------------------------------- /Website/Lecture_Slides/Lecture 8 [Memory Optimizations] 03.13.2023.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UofT-EcoSystem/CSCD70/2400817bc46b6affae99769e613b8b5a9cf0d39a/Website/Lecture_Slides/Lecture 8 [Memory Optimizations] 03.13.2023.pptx -------------------------------------------------------------------------------- /Website/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line, and also 5 | # from the environment for the first two. 6 | SPHINXOPTS ?= 7 | SPHINXBUILD ?= sphinx-build 8 | SOURCEDIR = . 9 | BUILDDIR = build 10 | 11 | # Put it first so that "make" without argument is like "make help". 12 | help: 13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 14 | 15 | .PHONY: help Makefile 16 | 17 | # Catch-all target: route all unknown targets to Sphinx using the new 18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 19 | %: Makefile 20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 21 | -------------------------------------------------------------------------------- /Website/Slides.rst: -------------------------------------------------------------------------------- 1 | Slides 2 | ====== 3 | 4 | Slides be posted here every week after class. Tutorial code samples will be 5 | posted at the `GitHub repository`_. 6 | 7 | .. _GitHub repository: https://github.com/UofT-EcoSystem/CSCD70 8 | 9 | ========= ============================== ========================= 10 | # Topic Slides 11 | ========= ============================== ========================= 12 | Lec 1 Introduction [|PPTX Lec1|] 13 | Tut 1 Introduction to LLVM [|Overleaf Tut1|_] 14 | Lec 2 Dataflow [|PPTX Lec2|] 15 | Tut 2 Introduction to LLVM ii [|Overleaf Tut2|_] 16 | Lec 3 Dataflow-2 and Loops [|PPTX Lec3|] 17 | Tut 3 Dataflow Analysis [|Overleaf Tut3|_] 18 | Lec 4 SSA [|PPTX Lec4|] 19 | Tut 4 Dataflow Analysis ii [|Overleaf Tut4|_] 20 | Lec 5 LICM and Strength Reduction [|PPTX Lec5|] 21 | Tut 5 Lazy Code Motion [|Overleaf Tut5|_] 22 | Lec 6 Register Allocation [|PPTX Lec6|] 23 | Tut 6 Scalar Evolution [|Overleaf Tut6|_] 24 | Lec 7 Pointer Analysis [|PPTX Lec7|] 25 | Tut 7 Register Allocation [|Overleaf Tut7|_] 26 | Lec 8 Memory Optimizations [|PPTX Lec8|] 27 | Lec 9 Machine Learning Compilers [|PPTX Lec9|][|PDF Lec9|] 28 | Lec 10 Parallelization [|PPTX Lec10|] 29 | ========= ============================== ========================= 30 | 31 | .. |PPTX Lec1| replace:: :download:`pptx ` 32 | .. |Overleaf Tut1| replace:: Overleaf 33 | .. _Overleaf Tut1: https://www.overleaf.com/read/ntrxhjmhkkrt 34 | 35 | .. |PPTX Lec2| replace:: :download:`pptx ` 36 | .. |Overleaf Tut2| replace:: Overleaf 37 | .. _Overleaf Tut2: https://www.overleaf.com/read/vdwnnwdcshyx 38 | 39 | .. |PPTX Lec3| replace:: :download:`pptx ` 40 | .. |Overleaf Tut3| replace:: Overleaf 41 | .. _Overleaf Tut3: https://www.overleaf.com/read/bbkbmgnqqffw 42 | 43 | .. |PPTX Lec4| replace:: :download:`pptx ` 44 | .. |Overleaf Tut4| replace:: Overleaf 45 | .. _Overleaf Tut4: https://www.overleaf.com/read/ptfcckrwdpvn 46 | 47 | .. |PPTX Lec5| replace:: :download:`pptx ` 48 | .. |Overleaf Tut5| replace:: Overleaf 49 | .. _Overleaf Tut5: https://www.overleaf.com/read/dyjffnjmznyn 50 | 51 | .. |PPTX Lec6| replace:: :download:`pptx ` 52 | .. |Overleaf Tut6| replace:: Overleaf 53 | .. _Overleaf Tut6: https://www.overleaf.com/read/qyzvpfzxkrns 54 | 55 | .. |PPTX Lec7| replace:: :download:`pptx ` 56 | .. |Overleaf Tut7| replace:: Overleaf 57 | .. _Overleaf Tut7: https://www.overleaf.com/read/bjrphznfydcg 58 | 59 | .. |PPTX Lec8| replace:: :download:`pptx ` 60 | 61 | .. |PPTX Lec9| replace:: :download:`pptx ` 62 | .. |PDF Lec9| replace:: :download:`pdf ` 63 | 64 | .. |PPTX Lec10| replace:: :download:`pptx ` 65 | -------------------------------------------------------------------------------- /Website/Tutorial_Slide_Hdr.tex: -------------------------------------------------------------------------------- 1 | \usepackage{microtype} % Micro Typography 2 | 3 | \usepackage[ruled, noend]{algorithm2e} 4 | \usepackage{hyperref} 5 | \usepackage[super]{nth} 6 | \usepackage{pifont} 7 | \usepackage{soul} 8 | \usepackage{transparent} 9 | % Figures and Tables 10 | \usepackage{graphicx} 11 | \usepackage{booktabs, multirow} 12 | % Monospaced Code Blocks 13 | \usepackage{listings} 14 | % Math Packages 15 | \usepackage{nicefrac} 16 | 17 | \lstset{ % 18 | backgroundcolor=\color{white}, % choose the background color; you must add \usepackage{color} or \usepackage{xcolor}; should come as last argument 19 | basicstyle=\ttfamily, % the size of the fonts that are used for the code 20 | breakatwhitespace=false, % sets if automatic breaks should only happen at whitespace 21 | breaklines=true, % sets automatic line breaking 22 | captionpos=b, % sets the caption-position to bottom 23 | columns=fullflexible, % reduce the column spacing 24 | commentstyle=\color{gray}, % comment style 25 | deletekeywords={}, % if you want to delete keywords from the given language 26 | escapeinside={\%*}{*)}, % if you want to add LaTeX within your code 27 | extendedchars=true, % lets you use non-ASCII characters; for 8-bits encodings only, does not work with UTF-8 28 | frame=none, % adds no frame around the code 29 | keepspaces=true, % keeps spaces in text, useful for keeping indentation of code (possibly needs columns=flexible) 30 | keywordstyle=\color{blue}, % keyword style 31 | language=C++, % the language of the code 32 | morekeywords={}, % if you want to add more keywords to the set 33 | numbers=none, % where to put the line-numbers; possible values are (none, left, right) 34 | numbersep=5pt, % how far the line-numbers are from the code 35 | numberstyle=\color{black}, % the style that is used for the line-numbers 36 | rulecolor=\color{black}, % if not set, the frame-color may be changed on line-breaks within not-black text (e.g. comments (green here)) 37 | showspaces=false, % show spaces everywhere adding particular underscores; it overrides 'showstringspaces' 38 | showstringspaces=false, % underline spaces within strings only 39 | showtabs=false, % show tabs within strings adding particular underscores 40 | stepnumber=1, % the step between two line-numbers. If it's 1, each line will be numbered 41 | stringstyle=\color{red}, % string literal style 42 | tabsize=4, % sets default tabsize to 4 spaces 43 | } 44 | 45 | \newcommand{\cmark}{{\color{green!80!black}\ding{52}}} 46 | \newcommand{\xmark}{{\color{red}\ding{56}}} 47 | \newcommand{\positive}[1]{{\color{green!50!black}{\textbf{#1}}}} 48 | \newcommand{\negative}[1]{{\color{red}{\textbf{#1}}}} 49 | 50 | \hypersetup{colorlinks, linkcolor=, urlcolor=blue} 51 | 52 | \newcommand{\transparentize}[1]{{\transparent{0.4} #1}} 53 | 54 | \newcommand\algocommentfont[1]{\footnotesize\ttfamily\textcolor{blue}{#1}} 55 | \SetCommentSty{algocommentfont} 56 | \resetcounteronoverlays{algocf} 57 | 58 | \usetheme{CambridgeUS} 59 | 60 | \usefonttheme{serif} 61 | \usepackage{lmodern} 62 | \renewcommand{\rmdefault}{ptm} 63 | \renewcommand{\sfdefault}{phv} 64 | 65 | \setbeamertemplate{caption}[numbered] 66 | \setbeamertemplate{itemize items}[default] 67 | \setbeamertemplate{navigation symbols}{} 68 | \setbeamertemplate{headline}{} 69 | \setbeamertemplate{footline}{% 70 | % https://github.com/josephwright/beamer/blob/main/base/themes/outer/beamerouterthemeinfolines.sty 71 | \begin{beamercolorbox}[wd=\paperwidth, ht=2.25ex, dp=1ex, 72 | leftskip=2ex, rightskip=2ex, sep=0pt]{transparent}% 73 | \hfill\footnotesize% 74 | \usebeamercolor[fg]{date in head/foot}% 75 | \usebeamertemplate{page number in head/foot}% 76 | \end{beamercolorbox}% 77 | } 78 | 79 | \newcommand{\sectiontitleframe}{ 80 | \begin{frame} 81 | \vfill 82 | \centering 83 | \begin{beamercolorbox}[sep=6pt, center, shadow=true, rounded=true]{title} 84 | \usebeamerfont{title}\insertsectionhead 85 | \end{beamercolorbox} 86 | \vfill 87 | \end{frame} 88 | } 89 | 90 | \usebackgroundtemplate{ 91 | \transparent{0.10} 92 | \includegraphics[width=\paperwidth,height=\paperheight]{figures/LLVM.png} 93 | } 94 | 95 | \makeatletter 96 | \g@addto@macro\normalsize{\setlength\belowdisplayskip{-0pt}} 97 | \makeatother 98 | 99 | % https://tex.stackexchange.com/a/32600/152909 100 | \def\Vhrulefill{\leavevmode\leaders\hrule height 0.7ex depth \dimexpr0.4pt-0.7ex\hfill\kern0pt} 101 | -------------------------------------------------------------------------------- /Website/_templates/indexsidebar.html: -------------------------------------------------------------------------------- 1 | {# This template defines sidebar which can be used to provide common links on 2 | all documentation pages. #} 3 | 4 |

Course Materials

5 | 6 | 11 | 12 |

Additional Links

13 | 14 | 17 | 18 |

Documentations

19 | 20 | 25 | -------------------------------------------------------------------------------- /Website/_templates/layout.html: -------------------------------------------------------------------------------- 1 | {% extends "!layout.html" %} 2 | 3 | {% block rootrellink %} 4 |
  • CSCD70 2023S Home | 
  • 5 |
  • »
  • 6 | {% endblock %} 7 | 8 | {% block extrahead %} 9 | 14 | {% endblock %} 15 | -------------------------------------------------------------------------------- /Website/conf.py: -------------------------------------------------------------------------------- 1 | # Configuration file for the Sphinx documentation builder. 2 | # 3 | # This file only contains a selection of the most common options. For a full 4 | # list see the documentation: 5 | # https://www.sphinx-doc.org/en/master/usage/configuration.html 6 | 7 | # -- Path setup -------------------------------------------------------------- 8 | 9 | # If extensions (or modules to document with autodoc) are in another directory, 10 | # add these directories to sys.path here. If the directory is relative to the 11 | # documentation root, use os.path.abspath to make it absolute, like shown here. 12 | # 13 | # import os 14 | # import sys 15 | # sys.path.insert(0, os.path.abspath('.')) 16 | 17 | 18 | # -- Project information ----------------------------------------------------- 19 | 20 | project = "CSCD70" 21 | copyright = "2023, University of Toronto" 22 | author = "University of Toronto" 23 | 24 | # The full version, including alpha/beta/rc tags 25 | release = "2023S" 26 | 27 | 28 | # -- General configuration --------------------------------------------------- 29 | 30 | # Add any Sphinx extension module names here, as strings. They can be 31 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom 32 | # ones. 33 | extensions = [ 34 | "recommonmark", 35 | "sphinxemoji.sphinxemoji", 36 | ] 37 | 38 | # Add any paths that contain templates here, relative to this directory. 39 | templates_path = ["_templates"] 40 | 41 | # List of patterns, relative to source directory, that match files and 42 | # directories to ignore when looking for source files. 43 | # This pattern also affects html_static_path and html_extra_path. 44 | exclude_patterns = [] 45 | 46 | 47 | # -- Options for HTML output ------------------------------------------------- 48 | 49 | # The theme to use for HTML and HTML Help pages. See the documentation for 50 | # a list of builtin themes. 51 | # 52 | html_theme = "sphinxdoc" 53 | 54 | # Add any paths that contain custom static files (such as style sheets) here, 55 | # relative to this directory. They are copied after the builtin static files, 56 | # so a file named "default.css" will overwrite the builtin "default.css". 57 | html_static_path = [] 58 | 59 | html_sidebars = { 60 | "**": [ 61 | "indexsidebar.html", 62 | "searchbox.html", 63 | ] 64 | } 65 | -------------------------------------------------------------------------------- /Website/index.rst: -------------------------------------------------------------------------------- 1 | .. CSCD70 documentation master file. 2 | You can adapt this file completely to your liking, but it should at least 3 | contain the root `toctree` directive. 4 | 5 | CSCD70 Compiler Optimization 6 | ============================ 7 | 8 | .. toctree:: 9 | :hidden: 10 | 11 | Slides 12 | Assignments/index 13 | 14 | 15 | Welcome everyone to CSCD70. The first lecture and tutorial will be on **Jan. 16 | 9**. We will be using Quercus and Piazza for important announcements and this 17 | webpage for uploading course materials (|:point_right:| the right sidebar), so 18 | please make sure that you check them regularly for any updates. 19 | 20 | 21 | Syllabus 22 | -------- 23 | 24 | General Course Information 25 | ^^^^^^^^^^^^^^^^^^^^^^^^^^ 26 | 27 | :Instructor: Professor Gennady Pekhimenko 28 | :Teaching Assistant: Bojian Zheng 29 | :Lectures: Mon. 1:00-3:00 p.m. AA 206 30 | :Tutorials: Mon. 11:00-12:00 a.m. HW 402 [#]_ 31 | :Discussion Board: https://piazza.com/utoronto.ca/winter2023/cscd70/home 32 | 33 | .. [#] Please make sure that you are enrolled in the tutorials. If, after Jan. 34 | 22 (the add/drop deadline) you are still not in a tutorial, please send an 35 | email to Jenn Chaskavich (`jenn.chaskavich@utoronto.ca`_) and she will 36 | enroll you. 37 | 38 | .. _jenn.chaskavich@utoronto.ca: mailto:jenn.chaskavich@utoronto.ca 39 | 40 | Course Description 41 | ^^^^^^^^^^^^^^^^^^ 42 | 43 | The goal of this course is to introduce students to the theoretical and 44 | practical aspects of building optimizing compilers that effectively exploit 45 | modern architectures. The course will begin with the fundamentals of compiler 46 | optimization, and will build upon these fundamentals to address issues in 47 | state-of-the-art commercial and research machines. Topics include the 48 | followings: intermediate representations, basic blocks and control flow graphs, 49 | dataflow analysis, partial redundancy elimination, loop optimizations, register 50 | allocation, instruction scheduling, inter-procedural analysis, memory hierarchy 51 | optimizations, extracting parallelism, and dynamic optimizations. Students will 52 | implement significant optimizations within LLVM, a modern research compiler 53 | framework. 54 | 55 | Prerequisites 56 | ^^^^^^^^^^^^^ 57 | 58 | **This course is not supposed to be your first C/C++ course. Previous knowledge 59 | on compiler frontend is recommended but not required.** If you feel uncertain 60 | about whether you are adequately prepared to take this class, please discuss 61 | this with the instructor. 62 | 63 | Course Works and Grading 64 | ^^^^^^^^^^^^^^^^^^^^^^^^ 65 | 66 | * **Assignments (45%)** 67 | 68 | A major focus of this course is the assignments. We prefer that you work in 69 | **groups of two** on the assignments. The assignments will contain both 70 | programming and theoretical questions. There will be three assignments, each 71 | worth 15% of your final grade. The first assignment will be distributed on 72 | Jan. 9 and it will introduce you to the LLVM compiler framework. 73 | 74 | * **Midterm (20%)** and **Final Exam (35%)** 75 | 76 | There will be a midterm exam covering the first half of the course material 77 | and a final covering the whole. Both exams will be closed book, closed notes. 78 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '2.3' 2 | 3 | services: 4 | dev: 5 | image: cscd70:2023S 6 | build: 7 | context: Assignment0-Introduction_to_Docker 8 | volumes: 9 | - .:/mnt 10 | environment: 11 | - CMAKE_EXPORT_COMPILE_COMMANDS=1 12 | working_dir: /mnt 13 | --------------------------------------------------------------------------------