Table of contents : Learn LLVM 17 Contributors About the authors About the reviewers Preface What’s new in this edition Who this book is for What this book covers To get the most out of this book Download the example code files Conventions used Get in touch Share Your Thoughts Download a free PDF copy of this book Part 1: The Basics of Compiler Construction with LLVM Chapter 1: Installing LLVM Compiling LLVM versus installing binaries Getting the prerequisites ready Ubuntu Fedora and RedHat FreeBSD OS X Windows Cloning the repository and building from source Configuring Git Cloning the repository Creating a build directory Generating the build system files Compiling and installing LLVM Customizing the build process Variables defined by CMake Using LLVM-defined build configuration variables Summary Chapter 2: The Structure of a Compiler Building blocks of a compiler An arithmetic expression language Formalism for specifying the syntax of a programming language How does grammar help the compiler writer? Lexical analysis A hand-written lexer Syntactical analysis A hand-written parser The abstract syntax tree Semantic analysis Generating code with the LLVM backend Textual representation of LLVM IR Generating the IR from the AST The missing pieces – the driver and the runtime library Summary Part 2: From Source to Machine Code Generation Chapter 3: Turning the Source File into an Abstract Syntax Tree Defining a real programming language Creating the project layout Managing the input files for the compiler Handling messages for the user Structuring the lexer Constructing a recursive descent parser Performing semantic analysis Handling the scope of names Using an LLVM-style RTTI for the AST Creating the semantic analyzer Summary Chapter 4: Basics of IR Code Generation Generating IR from the AST Understanding the IR code Learning about the load-and-store approach Mapping the control flow to basic blocks Using AST numbering to generate IR code in SSA form Defining the data structure to hold values Reading and writing values local to a basic block Searching the predecessor blocks for a value Optimizing the generated phi instructions Sealing a block Creating the IR code for expressions Emitting the IR code for a function Controlling visibility with linkage and name mangling Converting a type from an AST description into LLVM types Creating the LLVM IR function Emitting the function body Setting up the module and the driver Wrapping all in the code generator Initializing the target machine class Emitting assembler text and object code Summary Chapter 5: IR Generation for High-Level Language Constructs Technical requirements Working with arrays, structs, and pointers Getting the application binary interface right Creating IR code for classes and virtual functions Implementing single inheritance Extending single inheritance with interfaces Adding support for multiple inheritance Summary Chapter 6: Advanced IR Generation Throwing and catching exceptions Raising an exception Catching an exception Integrating the exception handling code into the application Generating metadata for type-based alias analysis Understanding the need for additional metadata Creating TBAA metadata in LLVM Adding TBAA metadata to tinylang Adding debug metadata Understanding the general structure of debug metadata Tracking variables and their values Adding line numbers Adding debug support to tinylang Summary Chapter 7: Optimizing IR Technical requirements The LLVM pass manager Implementing a new pass Developing the ppprofiler pass as a plugin Adding the pass to the LLVM source tree Using the ppprofiler pass with LLVM tools Adding an optimization pipeline to your compiler Creating an optimization pipeline Extending the pass pipeline Summary Part 3: Taking LLVM to the Next Level Chapter 8: The TableGen Language Technical requirements Understanding the TableGen language Experimenting with the TableGen language Defining records and classes Creating multiple records at once with multiclasses Simulating function calls Generating C++ code from a TableGen file Defining data in the TableGen language Implementing a TableGen backend Drawbacks of TableGen Summary Chapter 9: JIT Compilation Technical requirements LLVM’s overall JIT implementation and use cases Using JIT compilation for direct execution Exploring the lli tool Implementing our own JIT compiler with LLJIT Integrating the LLJIT engine into the calculator Code generation changes to support JIT compilation via LLJIT Building an LLJIT-based calculator Building a JIT compiler class from scratch Creating a JIT compiler class Using our new JIT compiler class Summary Chapter 10: Debugging Using LLVM Tools Technical requirements Instrumenting an application with sanitizers Detecting memory access problems with the address sanitizer Finding uninitialized memory accesses with the memory sanitizer Pointing out data races with the thread sanitizer Finding bugs with libFuzzer Limitations and alternatives Performance profiling with XRay Checking the source with the clang static analyzer Adding a new checker to the clang static analyzer Creating your own clang-based tool Summary Part 4: Roll Your Own Backend Chapter 11: The Target Description Setting the stage for a new backend Adding the new architecture to the Triple class Extending the ELF file format definition in LLVM Creating the target description Adding the register definition Defining the instruction formats and the instruction information Creating the top-level file for the target description Adding the M88k backend to LLVM Implementing the assembler parser Creating the disassembler Summary Chapter 12: Instruction Selection Defining the rules of the calling convention Implementing the rules of the calling convention Instruction selection via the selection DAG Implementing DAG lowering – handling legal types and setting operations Implementing DAG lowering – lowering formal arguments Implementing DAG lowering – lowering return values Implementing DAG-to-DAG transformations within instruction selection Adding register and instruction information Putting an empty frame lowering in place Emitting machine instructions Creating the target machine and the sub-target Implementing M88kSubtarget Implementing M88kTargetMachine – defining the definitions Implementing M88kTargetMachine – adding the implementation Global instruction selection Lowering arguments and return values Legalizing the generic machine instructions Selecting a register bank for operands Translating generic machine instructions Running an example How to further evolve the backend Summary Chapter 13: Beyond Instruction Selection Adding a new machine function pass to LLVM Implementing the top-level interface for the M88k target Adding the TargetMachine implementation for machine function passes Developing the specifics of the machine function pass Building newly implemented machine function passes A glimpse of running a machine function pass with llc Integrating a new target into the clang frontend Implementing the driver integration within clang Implementing ABI support for M88k within clang Implementing the toolchain support for M88k within clang Building the M88k target with clang integration Targeting a different CPU architecture Summary Index Why subscribe? Other Books You May Enjoy Packt is searching for authors like you Share Your Thoughts Download a free PDF copy of this book