Git Product home page Git Product logo

llvm-tutorial's Introduction

llvm-tutorial

Helpful guide towards learning to LLVM passes (legacy and new passes) for beginners

At a glance

A step-by-step tutorial for building an out-of-source LLVM pass

Setup

LLVM is an umbrella project for building compilers and code transformation tools. It consists of several sub-projects like Clang, LLD and, confusingly enough, the LLVM sub-project. We consider in this tutorial:

  • Building the LLVM sub-project from source
  • Building a trivial out-of-source LLVM pass.

We will be building LLVM v12.0.1 which is the latest as of this writing. We assume that you have a working compiler toolchain (GCC or LLVM) and that CMake is installed (minimum version 3.4).

Current file structure

llvm-tutorial
├── .gitignore
├── ELI5.md
├── LICENSE
├── README.md
├── samples
│   ├── cfile.c
│   └── cppfile.cpp
└── src
    ├── CMakeLists.txt
    ├── CustomLegacyPass
    │   ├── CMakeLists.txt
    │   ├── MyLegacyPass.cpp
    │   └── MyLegacyPass.h
    └── CustomNewPass
        ├── CMakeLists.txt
        ├── MyNewPass.cpp
        └── MyNewPass.h

4 directories, 13 files
  • ./src dir: Boilerplate files for legacy and new passes are provided, along with CMake files for easy compilation.
  • ./samples dir: Sample [.c|.cpp] files are provided for testing passes.

Compiling LLVM

Compiling LLVM from source is mandatory if you are developing an in-source pass (within LLVM source tree). It can also be convenient in the case of developing out-of-source passes as it gives you full control over the compilation options. For example, a debug build of LLVM is much more pleasant to work with compared to an optimized one. To compile LLVM, please follow the following steps:

  1. Download LLVM source and unpack it in a directory of your choice which will refer to as [LLVM_SRC] or download from github repo The LLVM Compiler Infrastructure

  2. Create a separate build directory

    mkdir llvm-build
    cd llvm-build
  3. Instruct CMake to detect and configure your build environment:

    cmake -DCMAKE_BUILD_TYPE=Debug -DLLVM_TARGETS_TO_BUILD=X86 [PATH_TO_LLVM_SRC]   #or
    cmake -DLLVM_ENABLE_PROJECTS='clang;openmp' \
        -DCMAKE_BUILD_TYPE=Release \
        -DLLVM_ENABLE_ASSERTIONS=ON \
        -DLLVM_CCACHE_BUILD={ON,OFF} \
        -G Ninja [PATH_TO_LLVM_SRC]

    Note that we instructed cmake to only build X86 backend. You can choose a different backend if needed. If you do not specify LLVM_TARGETS_TO_BUILD, then all supported backends will be built by default which requires more time.

  4. Now start the actual compilation within your build directory

    cmake --build .

    The --build option is a portable why to tell cmake to invoke the underlying build tool (make, ninja, xcodebuild, msbuild, etc.)

  5. Building takes some time to finish. After that you can install LLVM in its default directory which is /usr/local

    cmake --build . --target install

    Alternatively, it's possible to set a different install directory [LLVM_HOME]. Since we will need [LLVM_HOME] in the next stage, we assume that you have defined it as an environment variable $LLVM_HOME. Now you can issue the following command

    cmake -DCMAKE_INSTALL_PREFIX=$LLVM_HOME -P cmake_install.cmake

    Note that $LLVM_HOME must not contain ~ (tilde) to refer to your home directory as it won't be expanded. Use $HOME or an absolute path instead.

Brew installation

Download header and pre-compiled binary files using Homebrew or Linuxbrew

  1. Download and install llvm

    brew install llvm
    brew install llvm@12 # alternative
    brew upgrade llvm # for upgrade
  2. Exporting lib and include flags

    export LDFLAGS="-L/usr/local/opt/llvm/lib"
    export CPPFLAGS="-I/usr/local/opt/llvm/include"

    [Optional] For those using VScode, include following path in c++ include path settings

    # PATH TO LLVM_HOME DIR
    /usr/local/opt/llvm/**
    

Building a trivial LLVM pass

To build the skeleton legacy LLVM pass found in CustomLegacyPass folder or, to build the skeleton new LLVM pass found in CustomNewPass folder :

[Important] Enable or add respective pass folder in CMakeLists.txt

cd llvm-tutorial
mkdir build
cd build
cmake ../src/
make

Clean build

git clean -d -f -x # or
rm -rf build && mkdir build

cmake needs to find its LLVM configurations in [LLVM_DIR]. We automatically setup [LLVM_DIR] based on $LLVM_HOME for you. Now the easiest way to run the skeleton pass is to use Clang:

[Legacy]

# C frontend
clang \
    -Xclang \
    -load -Xclang build/CustomLegacyPass/libCustomLegacyPass.so samples/{file}.c 

# C++ frontend
clang++ \
    -Xclang \
    -load -Xclang build/CustomLegacyPass/libCustomLegacyPass.* samples/{file}.cpp 

[New]

# C frontend
clang \
    -fexperimental-new-pass-manager \
    -fpass-plugin=build/CustomNewPass/libCustomNewPass.so samples/{file}.c

# C++ frontend
clang++ \
    -fexperimental-new-pass-manager \
    -fpass-plugin=build/CustomNewPass/libCustomNewPass.so samples/{file}.cpp

NOTE:

  • Execution of any command is from root dir, unless specifically mentioned
  • Clang is the compiler front-end of the LLVM project. It can be installed separately in binary form.

Using clang and opt [llvm optimiser]

for plugging in the pass in optimization pipeline

Building low level file (.ll) and bytecode file (.bc)

[.ll|.bc]

# samples/{file}.ll
clang -emit-llvm -S samples/{file}.c* 

# samples/{file}.bc
clang -O1 -emit-llvm samples/{file}.c* -c 
clang -Xclang -disable-O0-optnone -emit-llvm samples/test.c -c
# disable optimisation (O0)
# -O* represent optimization level

# To get IR in human readable format
cat samples/{file}.ll

Executing [.ll|.bc] files

lli samples/{file}[.ll|.bc]

We can also use the cc1 for generating IR:

clang \
    -cc1 \
    -emit-llvm samples/{file}[.c|.cpp] \
    -o samples/{file}.ll

opt commands to load and enable custom pass for [.ll|.bc] file

[Legacy]

opt \
    -load build/CustomLegacyPass/libCustomLegacyPass.so \
    -"MyLegacyPass" -disable-output samples/{file}.[bc|ll] 
    
# Alternative 
opt \
    -load build/CustomLegacyPass/libCustomLegacyPass.so \ 
    -MyLegacyPass < samples/{file}.[bc|ll] > /dev/null 

[New]

opt \
    -load-pass-plugin=build/CustomNewPass/libCustomNewPass.so \
    -passes="MyNewPass" -disable-output samples/{file}.[bc|ll]

To generate modified [.bc] file after optimization performed by plugged in pass, we add -S flag to get output and store it in new [.bc] file

opt \
    -S \
    -load-pass-plugin=build/CustomNewPass/libCustomNewPass.so \
    -passes="MyNewPass" samples/{file_V1}.bc > samples/{file_V2}.bc

To generate CFG files use -dot-cfg flag

opt -S -dot-cfg samples/{file_V1}.bc > {file_V2}.bc # or
opt -S -dot-cfg samples/{file_V1}.bc -o {file_V2}.bc

References

Further resources

This tutorial is based on the following resources

  • Adrian Sampson's blog entry "LLVM for Grad Students" (link)
  • tomgu1991.github.io blog : Introduction to LLVM Pass (link)
  • LLVM docs (llvm.org doc)
    • My First Language Frontend with LLVM Tutorial (link)
    • Writing an LLVM Pass (link)
    • Writing an LLVM New Pass (link)
    • Using New Pass Manager (link)
    • LLVM’s New Pass Manager (link)
    • LLVM documentation: Building LLVM with CMake (link)
    • Getting Started with the LLVM System (link)
    • Projects built with LLVM (link)
  • llvm: clang installed from linuxbrew is not able to link binary executable #22034 (github issue) (link)
  • Installed LLVM doesn't get added to $PATH #29733 (github issue) (link)
  • How to automatically register and load modern Pass in Clang? (so) (link)
  • How to write your own compiler (link)

Roadmap for becoming Compiler engineer

  • Compilers & LLVM roadmap (link)
  • How to contribute to LLVM Open Source as a student? (link)
  • Learning Compilers/LLVM: How to start? (link)
  • Preparing for Compiler Design as a Career (link)

llvm-tutorial's People

Watchers

James Cloos avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.