[llvm] c357f59 - [docs] Finish MyST migration for tutorial docs (#217160)
via llvm-commits
llvm-commits at lists.llvm.org
Wed Aug 19 11:58:04 PDT 2026
Author: Reid Kleckner
Date: 2026-08-19T11:57:52-07:00
New Revision: c357f592ca3db1fde763a8d65d1e52b1a06f5d18
URL: https://github.com/llvm/llvm-project/commit/c357f592ca3db1fde763a8d65d1e52b1a06f5d18
DIFF: https://github.com/llvm/llvm-project/commit/c357f592ca3db1fde763a8d65d1e52b1a06f5d18.diff
LOG: [docs] Finish MyST migration for tutorial docs (#217160)
Tracking issue: #201242
See the [migration guide] for more information.
[migration guide]:
https://llvm.org/docs/SphinxQuickstartTemplate.html#markdown-migration-guidelines
This is a stacked PR based on #217158 , which will be a standalone
commit that
renames *.rst -> *.md before this PR lands for history preservation
purposes.
This was prepared with rst2myst plus LLM-assisted cleanup. I paged
through all the generated HTML looking for migration artifacts, and all
of the differences I could find appear to be formatting error
corrections. Please spot check my work and approve if it looks good. You
can use the HTML links below to confirm it renders properly.
-----
Before/after validation links:
| Source file | Before HTML | After HTML |
| --- | --- | --- |
| `llvm/docs/tutorial/BuildingAJIT1.md` |
[before](https://llvmdocs.staging.reidkleckner.dev/before/llvm/docs/tutorial/BuildingAJIT1.html)
|
[after](https://llvmdocs.staging.reidkleckner.dev/after/llvm/docs/tutorial/BuildingAJIT1.html)
|
| `llvm/docs/tutorial/BuildingAJIT2.md` |
[before](https://llvmdocs.staging.reidkleckner.dev/before/llvm/docs/tutorial/BuildingAJIT2.html)
|
[after](https://llvmdocs.staging.reidkleckner.dev/after/llvm/docs/tutorial/BuildingAJIT2.html)
|
| `llvm/docs/tutorial/BuildingAJIT3.md` |
[before](https://llvmdocs.staging.reidkleckner.dev/before/llvm/docs/tutorial/BuildingAJIT3.html)
|
[after](https://llvmdocs.staging.reidkleckner.dev/after/llvm/docs/tutorial/BuildingAJIT3.html)
|
| `llvm/docs/tutorial/BuildingAJIT4.md` |
[before](https://llvmdocs.staging.reidkleckner.dev/before/llvm/docs/tutorial/BuildingAJIT4.html)
|
[after](https://llvmdocs.staging.reidkleckner.dev/after/llvm/docs/tutorial/BuildingAJIT4.html)
|
| `llvm/docs/tutorial/LangImpl01.md` |
[before](https://llvmdocs.staging.reidkleckner.dev/before/llvm/docs/tutorial/LangImpl01.html)
|
[after](https://llvmdocs.staging.reidkleckner.dev/after/llvm/docs/tutorial/LangImpl01.html)
|
| `llvm/docs/tutorial/LangImpl02.md` |
[before](https://llvmdocs.staging.reidkleckner.dev/before/llvm/docs/tutorial/LangImpl02.html)
|
[after](https://llvmdocs.staging.reidkleckner.dev/after/llvm/docs/tutorial/LangImpl02.html)
|
| `llvm/docs/tutorial/LangImpl03.md` |
[before](https://llvmdocs.staging.reidkleckner.dev/before/llvm/docs/tutorial/LangImpl03.html)
|
[after](https://llvmdocs.staging.reidkleckner.dev/after/llvm/docs/tutorial/LangImpl03.html)
|
| `llvm/docs/tutorial/LangImpl04.md` |
[before](https://llvmdocs.staging.reidkleckner.dev/before/llvm/docs/tutorial/LangImpl04.html)
|
[after](https://llvmdocs.staging.reidkleckner.dev/after/llvm/docs/tutorial/LangImpl04.html)
|
| `llvm/docs/tutorial/LangImpl05.md` |
[before](https://llvmdocs.staging.reidkleckner.dev/before/llvm/docs/tutorial/LangImpl05.html)
|
[after](https://llvmdocs.staging.reidkleckner.dev/after/llvm/docs/tutorial/LangImpl05.html)
|
| `llvm/docs/tutorial/LangImpl06.md` |
[before](https://llvmdocs.staging.reidkleckner.dev/before/llvm/docs/tutorial/LangImpl06.html)
|
[after](https://llvmdocs.staging.reidkleckner.dev/after/llvm/docs/tutorial/LangImpl06.html)
|
| `llvm/docs/tutorial/LangImpl07.md` |
[before](https://llvmdocs.staging.reidkleckner.dev/before/llvm/docs/tutorial/LangImpl07.html)
|
[after](https://llvmdocs.staging.reidkleckner.dev/after/llvm/docs/tutorial/LangImpl07.html)
|
| `llvm/docs/tutorial/LangImpl08.md` |
[before](https://llvmdocs.staging.reidkleckner.dev/before/llvm/docs/tutorial/LangImpl08.html)
|
[after](https://llvmdocs.staging.reidkleckner.dev/after/llvm/docs/tutorial/LangImpl08.html)
|
| `llvm/docs/tutorial/LangImpl09.md` |
[before](https://llvmdocs.staging.reidkleckner.dev/before/llvm/docs/tutorial/LangImpl09.html)
|
[after](https://llvmdocs.staging.reidkleckner.dev/after/llvm/docs/tutorial/LangImpl09.html)
|
| `llvm/docs/tutorial/LangImpl10.md` |
[before](https://llvmdocs.staging.reidkleckner.dev/before/llvm/docs/tutorial/LangImpl10.html)
|
[after](https://llvmdocs.staging.reidkleckner.dev/after/llvm/docs/tutorial/LangImpl10.html)
|
| `llvm/docs/tutorial/MyFirstLanguageFrontend/LangImpl01.md` |
[before](https://llvmdocs.staging.reidkleckner.dev/before/llvm/docs/tutorial/MyFirstLanguageFrontend/LangImpl01.html)
|
[after](https://llvmdocs.staging.reidkleckner.dev/after/llvm/docs/tutorial/MyFirstLanguageFrontend/LangImpl01.html)
|
| `llvm/docs/tutorial/MyFirstLanguageFrontend/LangImpl02.md` |
[before](https://llvmdocs.staging.reidkleckner.dev/before/llvm/docs/tutorial/MyFirstLanguageFrontend/LangImpl02.html)
|
[after](https://llvmdocs.staging.reidkleckner.dev/after/llvm/docs/tutorial/MyFirstLanguageFrontend/LangImpl02.html)
|
| `llvm/docs/tutorial/MyFirstLanguageFrontend/LangImpl03.md` |
[before](https://llvmdocs.staging.reidkleckner.dev/before/llvm/docs/tutorial/MyFirstLanguageFrontend/LangImpl03.html)
|
[after](https://llvmdocs.staging.reidkleckner.dev/after/llvm/docs/tutorial/MyFirstLanguageFrontend/LangImpl03.html)
|
| `llvm/docs/tutorial/MyFirstLanguageFrontend/LangImpl04.md` |
[before](https://llvmdocs.staging.reidkleckner.dev/before/llvm/docs/tutorial/MyFirstLanguageFrontend/LangImpl04.html)
|
[after](https://llvmdocs.staging.reidkleckner.dev/after/llvm/docs/tutorial/MyFirstLanguageFrontend/LangImpl04.html)
|
| `llvm/docs/tutorial/MyFirstLanguageFrontend/LangImpl05.md` |
[before](https://llvmdocs.staging.reidkleckner.dev/before/llvm/docs/tutorial/MyFirstLanguageFrontend/LangImpl05.html)
|
[after](https://llvmdocs.staging.reidkleckner.dev/after/llvm/docs/tutorial/MyFirstLanguageFrontend/LangImpl05.html)
|
| `llvm/docs/tutorial/MyFirstLanguageFrontend/LangImpl06.md` |
[before](https://llvmdocs.staging.reidkleckner.dev/before/llvm/docs/tutorial/MyFirstLanguageFrontend/LangImpl06.html)
|
[after](https://llvmdocs.staging.reidkleckner.dev/after/llvm/docs/tutorial/MyFirstLanguageFrontend/LangImpl06.html)
|
| `llvm/docs/tutorial/MyFirstLanguageFrontend/LangImpl07.md` |
[before](https://llvmdocs.staging.reidkleckner.dev/before/llvm/docs/tutorial/MyFirstLanguageFrontend/LangImpl07.html)
|
[after](https://llvmdocs.staging.reidkleckner.dev/after/llvm/docs/tutorial/MyFirstLanguageFrontend/LangImpl07.html)
|
| `llvm/docs/tutorial/MyFirstLanguageFrontend/LangImpl08.md` |
[before](https://llvmdocs.staging.reidkleckner.dev/before/llvm/docs/tutorial/MyFirstLanguageFrontend/LangImpl08.html)
|
[after](https://llvmdocs.staging.reidkleckner.dev/after/llvm/docs/tutorial/MyFirstLanguageFrontend/LangImpl08.html)
|
| `llvm/docs/tutorial/MyFirstLanguageFrontend/LangImpl09.md` |
[before](https://llvmdocs.staging.reidkleckner.dev/before/llvm/docs/tutorial/MyFirstLanguageFrontend/LangImpl09.html)
|
[after](https://llvmdocs.staging.reidkleckner.dev/after/llvm/docs/tutorial/MyFirstLanguageFrontend/LangImpl09.html)
|
| `llvm/docs/tutorial/MyFirstLanguageFrontend/LangImpl10.md` |
[before](https://llvmdocs.staging.reidkleckner.dev/before/llvm/docs/tutorial/MyFirstLanguageFrontend/LangImpl10.html)
|
[after](https://llvmdocs.staging.reidkleckner.dev/after/llvm/docs/tutorial/MyFirstLanguageFrontend/LangImpl10.html)
|
| `llvm/docs/tutorial/MyFirstLanguageFrontend/index.md` |
[before](https://llvmdocs.staging.reidkleckner.dev/before/llvm/docs/tutorial/MyFirstLanguageFrontend/index.html)
|
[after](https://llvmdocs.staging.reidkleckner.dev/after/llvm/docs/tutorial/MyFirstLanguageFrontend/index.html)
|
Added:
Modified:
llvm/docs/tutorial/BuildingAJIT1.md
llvm/docs/tutorial/BuildingAJIT2.md
llvm/docs/tutorial/BuildingAJIT3.md
llvm/docs/tutorial/BuildingAJIT4.md
llvm/docs/tutorial/LangImpl01.md
llvm/docs/tutorial/LangImpl02.md
llvm/docs/tutorial/LangImpl03.md
llvm/docs/tutorial/LangImpl04.md
llvm/docs/tutorial/LangImpl05.md
llvm/docs/tutorial/LangImpl06.md
llvm/docs/tutorial/LangImpl07.md
llvm/docs/tutorial/LangImpl08.md
llvm/docs/tutorial/LangImpl09.md
llvm/docs/tutorial/LangImpl10.md
llvm/docs/tutorial/MyFirstLanguageFrontend/LangImpl01.md
llvm/docs/tutorial/MyFirstLanguageFrontend/LangImpl02.md
llvm/docs/tutorial/MyFirstLanguageFrontend/LangImpl03.md
llvm/docs/tutorial/MyFirstLanguageFrontend/LangImpl04.md
llvm/docs/tutorial/MyFirstLanguageFrontend/LangImpl05.md
llvm/docs/tutorial/MyFirstLanguageFrontend/LangImpl06.md
llvm/docs/tutorial/MyFirstLanguageFrontend/LangImpl07.md
llvm/docs/tutorial/MyFirstLanguageFrontend/LangImpl08.md
llvm/docs/tutorial/MyFirstLanguageFrontend/LangImpl09.md
llvm/docs/tutorial/MyFirstLanguageFrontend/LangImpl10.md
llvm/docs/tutorial/MyFirstLanguageFrontend/index.md
Removed:
################################################################################
diff --git a/llvm/docs/tutorial/BuildingAJIT1.md b/llvm/docs/tutorial/BuildingAJIT1.md
index d6caf0f7f1222..7add8d3ecc95f 100644
--- a/llvm/docs/tutorial/BuildingAJIT1.md
+++ b/llvm/docs/tutorial/BuildingAJIT1.md
@@ -1,10 +1,6 @@
-=======================================================
-Building a JIT: Starting out with KaleidoscopeJIT
-=======================================================
+# Building a JIT: Starting out with KaleidoscopeJIT
-
-Chapter 1 Introduction
-======================
+## Chapter 1 Introduction
**Warning: This tutorial is currently being updated to account for ORC API
changes. Only Chapters 1 and 2 are up-to-date.**
@@ -16,7 +12,7 @@ Welcome to Chapter 1 of the "Building an ORC-based JIT in LLVM" tutorial. This
tutorial runs through the implementation of a JIT compiler using LLVM's
On-Request-Compilation (ORC) APIs. It begins with a simplified version of the
KaleidoscopeJIT class used in the
-`Implementing a language with LLVM <LangImpl01.html>`_ tutorials and then
+[Implementing a language with LLVM](LangImpl01.md) tutorials and then
introduces new features like concurrent compilation, optimization, lazy
compilation and remote execution.
@@ -29,23 +25,19 @@ The structure of the tutorial is:
- Chapter #1: Investigate the simple KaleidoscopeJIT class. This will
introduce some of the basic concepts of the ORC JIT APIs, including the
idea of an ORC *Layer*.
-
-- `Chapter #2 <BuildingAJIT2.html>`_: Extend the basic KaleidoscopeJIT by adding
+- [Chapter #2](BuildingAJIT2.md): Extend the basic KaleidoscopeJIT by adding
a new layer that will optimize IR and generated code.
-
-- `Chapter #3 <BuildingAJIT3.html>`_: Further extend the JIT by adding a
+- [Chapter #3](BuildingAJIT3.md): Further extend the JIT by adding a
Compile-On-Demand layer to lazily compile IR.
-
-- `Chapter #4 <BuildingAJIT4.html>`_: Improve the laziness of our JIT by
+- [Chapter #4](BuildingAJIT4.md): Improve the laziness of our JIT by
replacing the Compile-On-Demand layer with a custom layer that uses the ORC
Compile Callbacks API directly to defer IR-generation until functions are
called.
-
-- `Chapter #5 <BuildingAJIT5.html>`_: Add process isolation by JITing code into
+- [Chapter #5](https://llvm.org/docs/tutorial/BuildingAJIT5.html): Add process isolation by JITing code into
a remote process with reduced privileges using the JIT Remote APIs.
To provide input for our JIT we will use a lightly modified version of the
-Kaleidoscope REPL from `Chapter 7 <LangImpl07.html>`_ of the "Implementing a
+Kaleidoscope REPL from [Chapter 7](LangImpl07.md) of the "Implementing a
language in LLVM tutorial".
Finally, a word on API generations: ORC is the 3rd generation of LLVM JIT API.
@@ -55,28 +47,27 @@ readers acquainted with them will see many familiar elements. Where appropriate
we will make this connection with the earlier APIs explicit to help people who
are transitioning from them to ORC.
-JIT API Basics
-==============
+## JIT API Basics
The purpose of a JIT compiler is to compile code "on-the-fly" as it is needed,
rather than compiling whole programs to disk ahead of time as a traditional
compiler does. To support that aim our initial, bare-bones JIT API will have
just two functions:
-1. ``Error addModule(std::unique_ptr<Module> M)``: Make the given IR module
+1. `Error addModule(std::unique_ptr<Module> M)`: Make the given IR module
available for execution.
-2. ``Expected<ExecutorSymbolDef> lookup()``: Search for pointers to
+2. `Expected<ExecutorSymbolDef> lookup()`: Search for pointers to
symbols (functions or variables) that have been added to the JIT.
A basic use-case for this API, executing the 'main' function from a module,
will look like:
-.. code-block:: c++
-
- JIT J;
- J.addModule(buildModule());
- auto *Main = J.lookup("main").getAddress().toPtr<int(*)(int, char *[])>();
- int Result = Main();
+```c++
+JIT J;
+J.addModule(buildModule());
+auto *Main = J.lookup("main").getAddress().toPtr<int(*)(int, char *[])>();
+int Result = Main();
+```
The APIs that we build in these tutorials will all be variations on this simple
theme. Behind this API we will refine the implementation of the JIT to add
@@ -84,13 +75,12 @@ support for concurrent compilation, optimization and lazy compilation.
Eventually we will extend the API itself to allow higher-level program
representations (e.g. ASTs) to be added to the JIT.
-KaleidoscopeJIT
-===============
+## KaleidoscopeJIT
In the previous section we described our API, now we examine a simple
-implementation of it: The KaleidoscopeJIT class [1]_ that was used in the
-`Implementing a language with LLVM <LangImpl01.html>`_ tutorials. We will use
-the REPL code from `Chapter 7 <LangImpl07.html>`_ of that tutorial to supply the
+implementation of it: The KaleidoscopeJIT class [^footnote-1] that was used in the
+[Implementing a language with LLVM](LangImpl01.md) tutorials. We will use
+the REPL code from [Chapter 7](LangImpl07.md) of that tutorial to supply the
input for our JIT: Each time the user enters an expression the REPL will add a
new IR module containing the code for that expression to the JIT. If the
expression is a top-level expression like '1+1' or 'sin(x)', the REPL will also
@@ -100,63 +90,63 @@ new interactions with our JIT class, but for now we will take this setup for
granted and focus our attention on the implementation of our JIT itself.
Our KaleidoscopeJIT class is defined in the KaleidoscopeJIT.h header. After the
-usual include guards and #includes [2]_, we get to the definition of our class:
-
-.. code-block:: c++
-
- #ifndef LLVM_EXECUTIONENGINE_ORC_KALEIDOSCOPEJIT_H
- #define LLVM_EXECUTIONENGINE_ORC_KALEIDOSCOPEJIT_H
-
- #include "llvm/ADT/StringRef.h"
- #include "llvm/ExecutionEngine/Orc/CompileUtils.h"
- #include "llvm/ExecutionEngine/Orc/Core.h"
- #include "llvm/ExecutionEngine/Orc/ExecutionUtils.h"
- #include "llvm/ExecutionEngine/Orc/IRCompileLayer.h"
- #include "llvm/ExecutionEngine/Orc/JITTargetMachineBuilder.h"
- #include "llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h"
- #include "llvm/ExecutionEngine/SectionMemoryManager.h"
- #include "llvm/IR/DataLayout.h"
- #include "llvm/IR/LLVMContext.h"
- #include <memory>
-
- namespace llvm {
- namespace orc {
-
- class KaleidoscopeJIT {
- private:
- ExecutionSession ES;
- RTDyldObjectLinkingLayer ObjectLayer;
- IRCompileLayer CompileLayer;
-
- DataLayout DL;
- MangleAndInterner Mangle;
- ThreadSafeContext Ctx;
-
- public:
- KaleidoscopeJIT(JITTargetMachineBuilder JTMB, DataLayout DL)
- : ObjectLayer(ES,
- []() { return std::make_unique<SectionMemoryManager>(); }),
- CompileLayer(ES, ObjectLayer, ConcurrentIRCompiler(std::move(JTMB))),
- DL(std::move(DL)), Mangle(ES, this->DL),
- Ctx(std::make_unique<LLVMContext>()) {
- ES.getMainJITDylib().addGenerator(
- cantFail(DynamicLibrarySearchGenerator::GetForCurrentProcess(DL.getGlobalPrefix())));
- }
-
-Our class begins with six member variables: An ExecutionSession member, ``ES``,
+usual include guards and #includes [^footnote-2], we get to the definition of our class:
+
+```c++
+#ifndef LLVM_EXECUTIONENGINE_ORC_KALEIDOSCOPEJIT_H
+#define LLVM_EXECUTIONENGINE_ORC_KALEIDOSCOPEJIT_H
+
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ExecutionEngine/Orc/CompileUtils.h"
+#include "llvm/ExecutionEngine/Orc/Core.h"
+#include "llvm/ExecutionEngine/Orc/ExecutionUtils.h"
+#include "llvm/ExecutionEngine/Orc/IRCompileLayer.h"
+#include "llvm/ExecutionEngine/Orc/JITTargetMachineBuilder.h"
+#include "llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h"
+#include "llvm/ExecutionEngine/SectionMemoryManager.h"
+#include "llvm/IR/DataLayout.h"
+#include "llvm/IR/LLVMContext.h"
+#include <memory>
+
+namespace llvm {
+namespace orc {
+
+class KaleidoscopeJIT {
+private:
+ ExecutionSession ES;
+ RTDyldObjectLinkingLayer ObjectLayer;
+ IRCompileLayer CompileLayer;
+
+ DataLayout DL;
+ MangleAndInterner Mangle;
+ ThreadSafeContext Ctx;
+
+public:
+ KaleidoscopeJIT(JITTargetMachineBuilder JTMB, DataLayout DL)
+ : ObjectLayer(ES,
+ []() { return std::make_unique<SectionMemoryManager>(); }),
+ CompileLayer(ES, ObjectLayer, ConcurrentIRCompiler(std::move(JTMB))),
+ DL(std::move(DL)), Mangle(ES, this->DL),
+ Ctx(std::make_unique<LLVMContext>()) {
+ ES.getMainJITDylib().addGenerator(
+ cantFail(DynamicLibrarySearchGenerator::GetForCurrentProcess(DL.getGlobalPrefix())));
+ }
+```
+
+Our class begins with six member variables: An ExecutionSession member, `ES`,
which provides context for our running JIT'd code (including the string pool,
global mutex, and error reporting facilities); An RTDyldObjectLinkingLayer,
-``ObjectLayer``, that can be used to add object files to our JIT (though we will
-not use it directly); An IRCompileLayer, ``CompileLayer``, that can be used to
+`ObjectLayer`, that can be used to add object files to our JIT (though we will
+not use it directly); An IRCompileLayer, `CompileLayer`, that can be used to
add LLVM Modules to our JIT (and which builds on the ObjectLayer), A DataLayout
-and MangleAndInterner, ``DL`` and ``Mangle``, that will be used for symbol mangling
+and MangleAndInterner, `DL` and `Mangle`, that will be used for symbol mangling
(more on that later); and finally an LLVMContext that clients will use when
building IR files for the JIT.
-Next up we have our class constructor, which takes a `JITTargetMachineBuilder``
-that will be used by our IRCompiler, and a ``DataLayout`` that we will use to
+Next up we have our class constructor, which takes a `` JITTargetMachineBuilder` ``
+that will be used by our IRCompiler, and a `DataLayout` that we will use to
initialize our DL member. The constructor begins by initializing our
-ObjectLayer. The ObjectLayer requires a reference to the ExecutionSession, and
+ObjectLayer. The ObjectLayer requires a reference to the ExecutionSession, and
a function object that will build a JIT memory manager for each module that is
added (a JIT memory manager manages memory allocations, memory permissions, and
registration of exception handlers for JIT'd code). For this we use a lambda
@@ -169,61 +159,60 @@ files. We use the off-the-shelf ConcurrentIRCompiler utility as our compiler,
which we construct using this constructor's JITTargetMachineBuilder argument.
The ConcurrentIRCompiler utility will use the JITTargetMachineBuilder to build
llvm TargetMachines (which are not thread safe) as needed for compiles. After
-this, we initialize our supporting members: ``DL``, ``Mangler`` and ``Ctx`` with
+this, we initialize our supporting members: `DL`, `Mangler` and `Ctx` with
the input DataLayout, the ExecutionSession and DL member, and a new default
constructed LLVMContext respectively. Now that our members have been initialized,
so the one thing that remains to do is to tweak the configuration of the
*JITDylib* that we will store our code in. We want to modify this dylib to
contain not only the symbols that we add to it, but also the symbols from our
REPL process as well. We do this by attaching a
-``DynamicLibrarySearchGenerator`` instance using the
-``DynamicLibrarySearchGenerator::GetForCurrentProcess`` method.
+`DynamicLibrarySearchGenerator` instance using the
+`DynamicLibrarySearchGenerator::GetForCurrentProcess` method.
+```c++
+static Expected<std::unique_ptr<KaleidoscopeJIT>> Create() {
+ auto JTMB = JITTargetMachineBuilder::detectHost();
-.. code-block:: c++
+ if (!JTMB)
+ return JTMB.takeError();
- static Expected<std::unique_ptr<KaleidoscopeJIT>> Create() {
- auto JTMB = JITTargetMachineBuilder::detectHost();
+ auto DL = JTMB->getDefaultDataLayoutForTarget();
+ if (!DL)
+ return DL.takeError();
- if (!JTMB)
- return JTMB.takeError();
+ return std::make_unique<KaleidoscopeJIT>(std::move(*JTMB), std::move(*DL));
+}
- auto DL = JTMB->getDefaultDataLayoutForTarget();
- if (!DL)
- return DL.takeError();
+const DataLayout &getDataLayout() const { return DL; }
- return std::make_unique<KaleidoscopeJIT>(std::move(*JTMB), std::move(*DL));
- }
-
- const DataLayout &getDataLayout() const { return DL; }
+LLVMContext &getContext() { return *Ctx.getContext(); }
+```
- LLVMContext &getContext() { return *Ctx.getContext(); }
-
-Next we have a named constructor, ``Create``, which will build a KaleidoscopeJIT
+Next we have a named constructor, `Create`, which will build a KaleidoscopeJIT
instance that is configured to generate code for our host process. It does this
by first generating a JITTargetMachineBuilder instance using that classes'
detectHost method and then using that instance to generate a datalayout for
the target process. Each of these operations can fail, so each returns its
-result wrapped in an Expected value [3]_ that we must check for error before
+result wrapped in an Expected value [^footnote-3] that we must check for error before
continuing. If both operations succeed we can unwrap their results (using the
dereference operator) and pass them into KaleidoscopeJIT's constructor on the
last line of the function.
-Following the named constructor we have the ``getDataLayout()`` and
-``getContext()`` methods. These are used to make data structures created and
+Following the named constructor we have the `getDataLayout()` and
+`getContext()` methods. These are used to make data structures created and
managed by the JIT (especially the LLVMContext) available to the REPL code that
will build our IR modules.
-.. code-block:: c++
-
- void addModule(std::unique_ptr<Module> M) {
- cantFail(CompileLayer.add(ES.getMainJITDylib(),
- ThreadSafeModule(std::move(M), Ctx)));
- }
+```c++
+void addModule(std::unique_ptr<Module> M) {
+ cantFail(CompileLayer.add(ES.getMainJITDylib(),
+ ThreadSafeModule(std::move(M), Ctx)));
+}
- Expected<ExecutorSymbolDef> lookup(StringRef Name) {
- return ES.lookup({&ES.getMainJITDylib()}, Mangle(Name.str()));
- }
+Expected<ExecutorSymbolDef> lookup(StringRef Name) {
+ return ES.lookup({&ES.getMainJITDylib()}, Mangle(Name.str()));
+}
+```
Now we come to the first of our JIT API methods: addModule. This method is
responsible for adding IR to the JIT and making it available for execution. In
@@ -234,14 +223,14 @@ in the JITDylib for each definition in the module, and will defer compilation of
the module until any of its definitions is looked up. Note that this is not lazy
compilation: just referencing a definition, even if it is never used, will be
enough to trigger compilation. In later chapters we will teach our JIT to defer
-compilation of functions until they're actually called. To add our Module we
+compilation of functions until they're actually called. To add our Module we
must first wrap it in a ThreadSafeModule instance, which manages the lifetime of
the Module's LLVMContext (our Ctx member) in a thread-friendly way. In our
example, all modules will share the Ctx member, which will exist for the
duration of the JIT. Once we switch to concurrent compilation in later chapters
we will use a new context per module.
-Our last method is ``lookup``, which allows us to look up addresses for
+Our last method is `lookup`, which allows us to look up addresses for
function and variable definitions added to the JIT based on their symbol names.
As noted above, lookup will implicitly trigger compilation for any symbol
that has not already been compiled. Our lookup method calls through to
@@ -254,7 +243,7 @@ to interoperate easily with precompiled code in the application or shared
libraries. The kind of mangling will depend on the DataLayout, which in turn
depends on the target platform. To allow us to remain portable and search based
on the un-mangled name, we just re-produce this mangling ourselves using our
-``Mangle`` member function object.
+`Mangle` member function object.
This brings us to the end of Chapter 1 of Building a JIT. You now have a basic
but fully functioning JIT stack that you can use to take LLVM IR and make it
@@ -262,56 +251,46 @@ executable within the context of your JIT process. In the next chapter we'll
look at how to extend this JIT to produce better quality code, and in the
process take a deeper look at the ORC layer concept.
-`Next: Extending the KaleidoscopeJIT <BuildingAJIT2.html>`_
+[Next: Extending the KaleidoscopeJIT](BuildingAJIT2.md)
-Full Code Listing
-=================
+## Full Code Listing
Here is the complete code listing for our running example. To build this
example, use:
-.. code-block:: bash
-
- # Compile
- clang++ -g toy.cpp `llvm-config --cxxflags --ldflags --system-libs --libs core orcjit native` -O3 -o toy
- # Run
- ./toy
+```bash
+# Compile
+clang++ -g toy.cpp `llvm-config --cxxflags --ldflags --system-libs --libs core orcjit native` -O3 -o toy
+# Run
+./toy
+```
Here is the code:
-.. literalinclude:: ../../examples/Kaleidoscope/BuildingAJIT/Chapter1/KaleidoscopeJIT.h
- :language: c++
-
-.. [1] Actually we use a cut-down version of KaleidoscopeJIT that makes a
- simplifying assumption: symbols cannot be re-defined. This will make it
- impossible to re-define symbols in the REPL, but will make our symbol
- lookup logic simpler. Re-introducing support for symbol redefinition is
- left as an exercise for the reader. (The KaleidoscopeJIT.h used in the
- original tutorials will be a helpful reference).
-
-.. [2] +-----------------------------+-----------------------------------------------+
- | File | Reason for inclusion |
- +=============================+===============================================+
- | CompileUtils.h | Provides the SimpleCompiler class. |
- +-----------------------------+-----------------------------------------------+
- | Core.h | Core utilities such as ExecutionSession and |
- | | JITDylib. |
- +-----------------------------+-----------------------------------------------+
- | ExecutionUtils.h | Provides the DynamicLibrarySearchGenerator |
- | | class. |
- +-----------------------------+-----------------------------------------------+
- | IRCompileLayer.h | Provides the IRCompileLayer class. |
- +-----------------------------+-----------------------------------------------+
- | JITTargetMachineBuilder.h | Provides the JITTargetMachineBuilder class. |
- +-----------------------------+-----------------------------------------------+
- | RTDyldObjectLinkingLayer.h | Provides the RTDyldObjectLinkingLayer class. |
- +-----------------------------+-----------------------------------------------+
- | SectionMemoryManager.h | Provides the SectionMemoryManager class. |
- +-----------------------------+-----------------------------------------------+
- | DataLayout.h | Provides the DataLayout class. |
- +-----------------------------+-----------------------------------------------+
- | LLVMContext.h | Provides the LLVMContext class. |
- +-----------------------------+-----------------------------------------------+
-
-.. [3] See the ErrorHandling section in the LLVM Programmer's Manual
- (https://llvm.org/docs/ProgrammersManual.html#error-handling)
+```{literalinclude} ../../examples/Kaleidoscope/BuildingAJIT/Chapter1/KaleidoscopeJIT.h
+:language: c++
+```
+
+[^footnote-1]: Actually we use a cut-down version of KaleidoscopeJIT that makes a
+ simplifying assumption: symbols cannot be re-defined. This will make it
+ impossible to re-define symbols in the REPL, but will make our symbol
+ lookup logic simpler. Re-introducing support for symbol redefinition is
+ left as an exercise for the reader. (The KaleidoscopeJIT.h used in the
+ original tutorials will be a helpful reference).
+
+[^footnote-2]:
+ | File | Reason for inclusion |
+ | -------------------------- | ----------------------------------------------------- |
+ | CompileUtils.h | Provides the SimpleCompiler class. |
+ | Core.h | Core utilities such as ExecutionSession and JITDylib. |
+ | ExecutionUtils.h | Provides the DynamicLibrarySearchGenerator class. |
+ | IRCompileLayer.h | Provides the IRCompileLayer class. |
+ | JITTargetMachineBuilder.h | Provides the JITTargetMachineBuilder class. |
+ | RTDyldObjectLinkingLayer.h | Provides the RTDyldObjectLinkingLayer class. |
+ | SectionMemoryManager.h | Provides the SectionMemoryManager class. |
+ | DataLayout.h | Provides the DataLayout class. |
+ | LLVMContext.h | Provides the LLVMContext class. |
+
+[^footnote-3]: See the ErrorHandling section in the LLVM Programmer's Manual
+ (<https://llvm.org/docs/ProgrammersManual.html#error-handling>)
+
diff --git a/llvm/docs/tutorial/BuildingAJIT2.md b/llvm/docs/tutorial/BuildingAJIT2.md
index c48c2e7b51883..28754b8c36884 100644
--- a/llvm/docs/tutorial/BuildingAJIT2.md
+++ b/llvm/docs/tutorial/BuildingAJIT2.md
@@ -1,14 +1,10 @@
-=====================================================================
-Building a JIT: Adding Optimizations -- An introduction to ORC Layers
-=====================================================================
-
+# Building a JIT: Adding Optimizations -- An introduction to ORC Layers
**This tutorial is under active development. It is incomplete and details may
change frequently.** Nonetheless we invite you to try it out as it stands, and
we welcome any feedback.
-Chapter 2 Introduction
-======================
+## Chapter 2 Introduction
**Warning: This tutorial is currently being updated to account for ORC API
changes. Only Chapters 1 and 2 are up-to-date.**
@@ -17,7 +13,7 @@ changes. Only Chapters 1 and 2 are up-to-date.**
updated**
Welcome to Chapter 2 of the "Building an ORC-based JIT in LLVM" tutorial. In
-`Chapter 1 <BuildingAJIT1.html>`_ of this series we examined a basic JIT
+[Chapter 1](BuildingAJIT1.md) of this series we examined a basic JIT
class, KaleidoscopeJIT, that could take LLVM IR modules as input and produce
executable code in memory. KaleidoscopeJIT was able to do this with relatively
little code by composing two off-the-shelf *ORC layers*: IRCompileLayer and
@@ -26,10 +22,9 @@ ObjectLinkingLayer, to do much of the heavy lifting.
In this layer we'll learn more about the ORC layer concept by using a new layer,
IRTransformLayer, to add IR optimization support to KaleidoscopeJIT.
-Optimizing Modules using the IRTransformLayer
-=============================================
+## Optimizing Modules using the IRTransformLayer
-In `Chapter 4 <LangImpl04.html>`_ of the "Implementing a language with LLVM"
+In [Chapter 4](LangImpl04.md) of the "Implementing a language with LLVM"
tutorial series the llvm *FunctionPassManager* is introduced as a means for
optimizing LLVM IR. Interested readers may read that chapter for details, but
in short: to optimize a Module we create an llvm::FunctionPassManager
@@ -52,31 +47,31 @@ constructor for this layer takes a reference to the execution session and the
layer below (as all layers do) plus an *IR optimization function* that it will
apply to each Module that is added via addModule:
-.. code-block:: c++
-
- class KaleidoscopeJIT {
- private:
- ExecutionSession ES;
- RTDyldObjectLinkingLayer ObjectLayer;
- IRCompileLayer CompileLayer;
- IRTransformLayer TransformLayer;
-
- DataLayout DL;
- MangleAndInterner Mangle;
- ThreadSafeContext Ctx;
-
- public:
-
- KaleidoscopeJIT(JITTargetMachineBuilder JTMB, DataLayout DL)
- : ObjectLayer(ES,
- []() { return std::make_unique<SectionMemoryManager>(); }),
- CompileLayer(ES, ObjectLayer, ConcurrentIRCompiler(std::move(JTMB))),
- TransformLayer(ES, CompileLayer, optimizeModule),
- DL(std::move(DL)), Mangle(ES, this->DL),
- Ctx(std::make_unique<LLVMContext>()) {
- ES.getMainJITDylib().addGenerator(
- cantFail(DynamicLibrarySearchGenerator::GetForCurrentProcess(DL.getGlobalPrefix())));
- }
+```c++
+class KaleidoscopeJIT {
+private:
+ ExecutionSession ES;
+ RTDyldObjectLinkingLayer ObjectLayer;
+ IRCompileLayer CompileLayer;
+ IRTransformLayer TransformLayer;
+
+ DataLayout DL;
+ MangleAndInterner Mangle;
+ ThreadSafeContext Ctx;
+
+public:
+
+ KaleidoscopeJIT(JITTargetMachineBuilder JTMB, DataLayout DL)
+ : ObjectLayer(ES,
+ []() { return std::make_unique<SectionMemoryManager>(); }),
+ CompileLayer(ES, ObjectLayer, ConcurrentIRCompiler(std::move(JTMB))),
+ TransformLayer(ES, CompileLayer, optimizeModule),
+ DL(std::move(DL)), Mangle(ES, this->DL),
+ Ctx(std::make_unique<LLVMContext>()) {
+ ES.getMainJITDylib().addGenerator(
+ cantFail(DynamicLibrarySearchGenerator::GetForCurrentProcess(DL.getGlobalPrefix())));
+ }
+```
Our extended KaleidoscopeJIT class starts out the same as it did in Chapter 1,
but after the CompileLayer we introduce a new member, TransformLayer, which sits
@@ -85,48 +80,48 @@ the ExecutionSession and output layer (standard practice for layers), along with
a *transform function*. For our transform function we supply our classes
optimizeModule static method.
-.. code-block:: c++
-
- // ...
- return cantFail(OptimizeLayer.addModule(std::move(M),
- std::move(Resolver)));
- // ...
+```c++
+// ...
+return cantFail(OptimizeLayer.addModule(std::move(M),
+ std::move(Resolver)));
+// ...
+```
Next we need to update our addModule method to replace the call to
-``CompileLayer::add`` with a call to ``OptimizeLayer::add`` instead.
-
-.. code-block:: c++
-
- static Expected<ThreadSafeModule>
- optimizeModule(ThreadSafeModule M, const MaterializationResponsibility &R) {
- // Create a function pass manager.
- auto FPM = std::make_unique<legacy::FunctionPassManager>(M.get());
-
- // Add some optimizations.
- FPM->add(createInstructionCombiningPass());
- FPM->add(createReassociatePass());
- FPM->add(createGVNPass());
- FPM->add(createCFGSimplificationPass());
- FPM->doInitialization();
-
- // Run the optimizations over all functions in the module being added to
- // the JIT.
- for (auto &F : *M)
- FPM->run(F);
-
- return M;
- }
+`CompileLayer::add` with a call to `OptimizeLayer::add` instead.
+
+```c++
+static Expected<ThreadSafeModule>
+optimizeModule(ThreadSafeModule M, const MaterializationResponsibility &R) {
+ // Create a function pass manager.
+ auto FPM = std::make_unique<legacy::FunctionPassManager>(M.get());
+
+ // Add some optimizations.
+ FPM->add(createInstructionCombiningPass());
+ FPM->add(createReassociatePass());
+ FPM->add(createGVNPass());
+ FPM->add(createCFGSimplificationPass());
+ FPM->doInitialization();
+
+ // Run the optimizations over all functions in the module being added to
+ // the JIT.
+ for (auto &F : *M)
+ FPM->run(F);
+
+ return M;
+}
+```
At the bottom of our JIT we add a private method to do the actual optimization:
*optimizeModule*. This function takes the module to be transformed as input (as
a ThreadSafeModule) along with a reference to a reference to a new class:
-``MaterializationResponsibility``. The MaterializationResponsibility argument
+`MaterializationResponsibility`. The MaterializationResponsibility argument
can be used to query JIT state for the module being transformed, such as the set
of definitions in the module that JIT'd code is actively trying to call/access.
For now we will ignore this argument and use a standard optimization
pipeline. To do this we set up a FunctionPassManager, add some passes to it, run
it over every function in the module, and then return the mutated module. The
-specific optimizations are the same ones used in `Chapter 4 <LangImpl04.html>`_
+specific optimizations are the same ones used in [Chapter 4](LangImpl04.md)
of the "Implementing a language with LLVM" tutorial series. Readers may visit
that chapter for a more in-depth discussion of these, and of IR optimization in
general.
@@ -140,67 +135,67 @@ to see how layers compose. It also provides a neat entry point to the *layer*
concept itself, because IRTransformLayer is one of the simplest layers that
can be implemented.
-.. code-block:: c++
+```c++
+// From IRTransformLayer.h:
+class IRTransformLayer : public IRLayer {
+public:
+ using TransformFunction = std::function<Expected<ThreadSafeModule>(
+ ThreadSafeModule, const MaterializationResponsibility &R)>;
- // From IRTransformLayer.h:
- class IRTransformLayer : public IRLayer {
- public:
- using TransformFunction = std::function<Expected<ThreadSafeModule>(
- ThreadSafeModule, const MaterializationResponsibility &R)>;
+ IRTransformLayer(ExecutionSession &ES, IRLayer &BaseLayer,
+ TransformFunction Transform = identityTransform);
- IRTransformLayer(ExecutionSession &ES, IRLayer &BaseLayer,
- TransformFunction Transform = identityTransform);
-
- void setTransform(TransformFunction Transform) {
- this->Transform = std::move(Transform);
- }
+ void setTransform(TransformFunction Transform) {
+ this->Transform = std::move(Transform);
+ }
- static ThreadSafeModule
- identityTransform(ThreadSafeModule TSM,
- const MaterializationResponsibility &R) {
- return TSM;
- }
+ static ThreadSafeModule
+ identityTransform(ThreadSafeModule TSM,
+ const MaterializationResponsibility &R) {
+ return TSM;
+ }
- void emit(MaterializationResponsibility R, ThreadSafeModule TSM) override;
+ void emit(MaterializationResponsibility R, ThreadSafeModule TSM) override;
- private:
- IRLayer &BaseLayer;
- TransformFunction Transform;
- };
+private:
+ IRLayer &BaseLayer;
+ TransformFunction Transform;
+};
- // From IRTransformLayer.cpp:
+// From IRTransformLayer.cpp:
- IRTransformLayer::IRTransformLayer(ExecutionSession &ES,
- IRLayer &BaseLayer,
- TransformFunction Transform)
- : IRLayer(ES), BaseLayer(BaseLayer), Transform(std::move(Transform)) {}
+IRTransformLayer::IRTransformLayer(ExecutionSession &ES,
+ IRLayer &BaseLayer,
+ TransformFunction Transform)
+ : IRLayer(ES), BaseLayer(BaseLayer), Transform(std::move(Transform)) {}
- void IRTransformLayer::emit(MaterializationResponsibility R,
- ThreadSafeModule TSM) {
- assert(TSM.getModule() && "Module must not be null");
+void IRTransformLayer::emit(MaterializationResponsibility R,
+ ThreadSafeModule TSM) {
+ assert(TSM.getModule() && "Module must not be null");
- if (auto TransformedTSM = Transform(std::move(TSM), R))
- BaseLayer.emit(std::move(R), std::move(*TransformedTSM));
- else {
- R.failMaterialization();
- getExecutionSession().reportError(TransformedTSM.takeError());
- }
+ if (auto TransformedTSM = Transform(std::move(TSM), R))
+ BaseLayer.emit(std::move(R), std::move(*TransformedTSM));
+ else {
+ R.failMaterialization();
+ getExecutionSession().reportError(TransformedTSM.takeError());
}
+}
+```
This is the whole definition of IRTransformLayer, from
-``llvm/include/llvm/ExecutionEngine/Orc/IRTransformLayer.h`` and
-``llvm/lib/ExecutionEngine/Orc/IRTransformLayer.cpp``. This class is concerned
+`llvm/include/llvm/ExecutionEngine/Orc/IRTransformLayer.h` and
+`llvm/lib/ExecutionEngine/Orc/IRTransformLayer.cpp`. This class is concerned
with two very simple jobs: (1) Running every IR Module that is emitted via this
layer through the transform function object, and (2) implementing the ORC
-``IRLayer`` interface (which itself conforms to the general ORC Layer concept,
+`IRLayer` interface (which itself conforms to the general ORC Layer concept,
more on that below). Most of the class is straightforward: a typedef for the
transform function, a constructor to initialize the members, a setter for the
transform function value, and a default no-op transform. The most important
-method is ``emit`` as this is half of our IRLayer interface. The emit method
+method is `emit` as this is half of our IRLayer interface. The emit method
applies our transform to each module that it is called on and, if the transform
succeeds, passes the transformed module to the base layer. If the transform
fails, our emit function calls
-``MaterializationResponsibility::failMaterialization`` (this JIT clients who
+`MaterializationResponsibility::failMaterialization` (this JIT clients who
may be waiting on other threads know that the code they were waiting for has
failed to compile) and logs the error with the execution session before bailing
out.
@@ -208,27 +203,27 @@ out.
The other half of the IRLayer interface we inherit unmodified from the IRLayer
class:
-.. code-block:: c++
-
- Error IRLayer::add(JITDylib &JD, ThreadSafeModule TSM, VModuleKey K) {
- return JD.define(std::make_unique<BasicIRLayerMaterializationUnit>(
- *this, std::move(K), std::move(TSM)));
- }
+```c++
+Error IRLayer::add(JITDylib &JD, ThreadSafeModule TSM, VModuleKey K) {
+ return JD.define(std::make_unique<BasicIRLayerMaterializationUnit>(
+ *this, std::move(K), std::move(TSM)));
+}
+```
-This code, from ``llvm/lib/ExecutionEngine/Orc/Layer.cpp``, adds a
+This code, from `llvm/lib/ExecutionEngine/Orc/Layer.cpp`, adds a
ThreadSafeModule to a given JITDylib by wrapping it up in a
-``MaterializationUnit`` (in this case a ``BasicIRLayerMaterializationUnit``).
+`MaterializationUnit` (in this case a `BasicIRLayerMaterializationUnit`).
Most layers that derived from IRLayer can rely on this default implementation
-of the ``add`` method.
+of the `add` method.
-These two operations, ``add`` and ``emit``, together constitute the layer
+These two operations, `add` and `emit`, together constitute the layer
concept: A layer is a way to wrap a part of a compiler pipeline (in this case
the "opt" phase of an LLVM compiler) whose API is opaque to ORC with an
interface that ORC can call as needed. The add method takes an
module in some input program representation (in this case an LLVM IR module)
-and stores it in the target ``JITDylib``, arranging for it to be passed back
+and stores it in the target `JITDylib`, arranging for it to be passed back
to the layer's emit method when any symbol defined by that module is requested.
-Each layer can complete its own work by calling the ``emit`` method of its base
+Each layer can complete its own work by calling the `emit` method of its base
layer. For example, in this tutorial our IRTransformLayer calls through to
our IRCompileLayer to compile the transformed IR, and our IRCompileLayer in
turn calls our ObjectLayer to link the object file produced by our compiler.
@@ -253,22 +248,23 @@ one-size-fits all solution to them, but by providing composable layers we leave
the decisions to the person implementing the JIT, and make it easy for them to
experiment with
diff erent configurations.
-`Next: Adding Per-function Lazy Compilation <BuildingAJIT3.html>`_
+[Next: Adding Per-function Lazy Compilation](BuildingAJIT3.md)
-Full Code Listing
-=================
+## Full Code Listing
Here is the complete code listing for our running example with an
IRTransformLayer added to enable optimization. To build this example, use:
-.. code-block:: bash
-
- # Compile
- clang++ -g toy.cpp `llvm-config --cxxflags --ldflags --system-libs --libs core orcjit native` -O3 -o toy
- # Run
- ./toy
+```bash
+# Compile
+clang++ -g toy.cpp `llvm-config --cxxflags --ldflags --system-libs --libs core orcjit native` -O3 -o toy
+# Run
+./toy
+```
Here is the code:
-.. literalinclude:: ../../examples/Kaleidoscope/BuildingAJIT/Chapter2/KaleidoscopeJIT.h
- :language: c++
+```{literalinclude} ../../examples/Kaleidoscope/BuildingAJIT/Chapter2/KaleidoscopeJIT.h
+:language: c++
+```
+
diff --git a/llvm/docs/tutorial/BuildingAJIT3.md b/llvm/docs/tutorial/BuildingAJIT3.md
index cf6da8f26aeef..b617258f4d029 100644
--- a/llvm/docs/tutorial/BuildingAJIT3.md
+++ b/llvm/docs/tutorial/BuildingAJIT3.md
@@ -1,14 +1,10 @@
-=============================================
-Building a JIT: Per-function Lazy Compilation
-=============================================
-
+# Building a JIT: Per-function Lazy Compilation
**This tutorial is under active development. It is incomplete and details may
change frequently.** Nonetheless we invite you to try it out as it stands, and
we welcome any feedback.
-Chapter 3 Introduction
-======================
+## Chapter 3 Introduction
**Warning: This text is currently out of date due to ORC API updates.**
@@ -17,10 +13,9 @@ once the API churn dies down.**
Welcome to Chapter 3 of the "Building an ORC-based JIT in LLVM" tutorial. This
chapter discusses lazy JITing and shows you how to enable it by adding an ORC
-CompileOnDemand layer the JIT from `Chapter 2 <BuildingAJIT2.html>`_.
+CompileOnDemand layer the JIT from [Chapter 2](BuildingAJIT2.md).
-Lazy Compilation
-================
+## Lazy Compilation
When we add a module to the KaleidoscopeJIT class from Chapter 2 it is
immediately optimized, compiled and linked for us by the IRTransformLayer,
@@ -63,63 +58,64 @@ set all the stubs and callbacks up for us. All we need to do is to add the
CompileOnDemandLayer to the top of our stack and we'll get the benefits of
lazy compilation. We just need a few changes to the source:
-.. code-block:: c++
-
- ...
- #include "llvm/ExecutionEngine/SectionMemoryManager.h"
- #include "llvm/ExecutionEngine/Orc/CompileOnDemandLayer.h"
- #include "llvm/ExecutionEngine/Orc/CompileUtils.h"
- ...
+```c++
+...
+#include "llvm/ExecutionEngine/SectionMemoryManager.h"
+#include "llvm/ExecutionEngine/Orc/CompileOnDemandLayer.h"
+#include "llvm/ExecutionEngine/Orc/CompileUtils.h"
+...
- ...
- class KaleidoscopeJIT {
- private:
- std::unique_ptr<TargetMachine> TM;
- const DataLayout DL;
- RTDyldObjectLinkingLayer ObjectLayer;
- IRCompileLayer<decltype(ObjectLayer), SimpleCompiler> CompileLayer;
+...
+class KaleidoscopeJIT {
+private:
+ std::unique_ptr<TargetMachine> TM;
+ const DataLayout DL;
+ RTDyldObjectLinkingLayer ObjectLayer;
+ IRCompileLayer<decltype(ObjectLayer), SimpleCompiler> CompileLayer;
- using OptimizeFunction =
- std::function<std::shared_ptr<Module>(std::shared_ptr<Module>)>;
+ using OptimizeFunction =
+ std::function<std::shared_ptr<Module>(std::shared_ptr<Module>)>;
- IRTransformLayer<decltype(CompileLayer), OptimizeFunction> OptimizeLayer;
+ IRTransformLayer<decltype(CompileLayer), OptimizeFunction> OptimizeLayer;
- std::unique_ptr<JITCompileCallbackManager> CompileCallbackManager;
- CompileOnDemandLayer<decltype(OptimizeLayer)> CODLayer;
+ std::unique_ptr<JITCompileCallbackManager> CompileCallbackManager;
+ CompileOnDemandLayer<decltype(OptimizeLayer)> CODLayer;
- public:
- using ModuleHandle = decltype(CODLayer)::ModuleHandleT;
+public:
+ using ModuleHandle = decltype(CODLayer)::ModuleHandleT;
+```
First we need to include the CompileOnDemandLayer.h header, then add two new
-members: a std::unique_ptr<JITCompileCallbackManager> and a CompileOnDemandLayer,
-to our class. The CompileCallbackManager member is used by the CompileOnDemandLayer
-to create the compile callback needed for each function.
-
-.. code-block:: c++
-
- KaleidoscopeJIT()
- : TM(EngineBuilder().selectTarget()), DL(TM->createDataLayout()),
- ObjectLayer([]() { return std::make_shared<SectionMemoryManager>(); }),
- CompileLayer(ObjectLayer, SimpleCompiler(*TM)),
- OptimizeLayer(CompileLayer,
- [this](std::shared_ptr<Module> M) {
- return optimizeModule(std::move(M));
- }),
- CompileCallbackManager(
- orc::createLocalCompileCallbackManager(TM->getTargetTriple(), 0)),
- CODLayer(OptimizeLayer,
- [this](Function &F) { return std::set<Function*>({&F}); },
- *CompileCallbackManager,
- orc::createLocalIndirectStubsManagerBuilder(
- TM->getTargetTriple())) {
- llvm::sys::DynamicLibrary::LoadLibraryPermanently(nullptr);
- }
+members: a `std::unique_ptr<JITCompileCallbackManager>` and a
+`CompileOnDemandLayer`, to our class. The CompileCallbackManager member is used
+by the CompileOnDemandLayer to create the compile callback needed for each
+function.
+
+```c++
+KaleidoscopeJIT()
+ : TM(EngineBuilder().selectTarget()), DL(TM->createDataLayout()),
+ ObjectLayer([]() { return std::make_shared<SectionMemoryManager>(); }),
+ CompileLayer(ObjectLayer, SimpleCompiler(*TM)),
+ OptimizeLayer(CompileLayer,
+ [this](std::shared_ptr<Module> M) {
+ return optimizeModule(std::move(M));
+ }),
+ CompileCallbackManager(
+ orc::createLocalCompileCallbackManager(TM->getTargetTriple(), 0)),
+ CODLayer(OptimizeLayer,
+ [this](Function &F) { return std::set<Function*>({&F}); },
+ *CompileCallbackManager,
+ orc::createLocalIndirectStubsManagerBuilder(
+ TM->getTargetTriple())) {
+ llvm::sys::DynamicLibrary::LoadLibraryPermanently(nullptr);
+}
+```
Next we have to update our constructor to initialize the new members. To create
an appropriate compile callback manager we use the
createLocalCompileCallbackManager function, which takes a TargetMachine and an
ExecutorAddr to call if it receives a request to compile an unknown
-function. In our simple JIT this situation is unlikely to come up, so we'll
+function. In our simple JIT this situation is unlikely to come up, so we'll
cheat and just pass '0' here. In a production quality JIT you could give the
address of a function that throws an exception in order to unwind the JIT'd
code's stack.
@@ -144,46 +140,46 @@ removed from the JIT the indirect stubs manager will be deleted, freeing any
memory allocated to the stubs. We supply this function by using the
createLocalIndirectStubsManagerBuilder utility.
-.. code-block:: c++
+```c++
+// ...
+ if (auto Sym = CODLayer.findSymbol(Name, false))
+// ...
+return cantFail(CODLayer.addModule(std::move(Ms),
+ std::move(Resolver)));
+// ...
- // ...
- if (auto Sym = CODLayer.findSymbol(Name, false))
- // ...
- return cantFail(CODLayer.addModule(std::move(Ms),
- std::move(Resolver)));
- // ...
+// ...
+return CODLayer.findSymbol(MangledNameStream.str(), true);
+// ...
- // ...
- return CODLayer.findSymbol(MangledNameStream.str(), true);
- // ...
-
- // ...
- CODLayer.removeModule(H);
- // ...
+// ...
+CODLayer.removeModule(H);
+// ...
+```
Finally, we need to replace the references to OptimizeLayer in our addModule,
findSymbol, and removeModule methods. With that, we're up and running.
**To be done:**
-** Chapter conclusion.**
+\*\* Chapter conclusion.\*\*
-Full Code Listing
-=================
+## Full Code Listing
Here is the complete code listing for our running example with a CompileOnDemand
layer added to enable lazy function-at-a-time compilation. To build this example, use:
-.. code-block:: bash
-
- # Compile
- clang++ -g toy.cpp `llvm-config --cxxflags --ldflags --system-libs --libs core orcjit native` -O3 -o toy
- # Run
- ./toy
+```bash
+# Compile
+clang++ -g toy.cpp `llvm-config --cxxflags --ldflags --system-libs --libs core orcjit native` -O3 -o toy
+# Run
+./toy
+```
Here is the code:
-.. literalinclude:: ../../examples/Kaleidoscope/BuildingAJIT/Chapter3/KaleidoscopeJIT.h
- :language: c++
+```{literalinclude} ../../examples/Kaleidoscope/BuildingAJIT/Chapter3/KaleidoscopeJIT.h
+:language: c++
+```
-`Next: Extreme Laziness -- Using Compile Callbacks to JIT directly from ASTs <BuildingAJIT4.html>`_
+[Next: Extreme Laziness -- Using Compile Callbacks to JIT directly from ASTs](BuildingAJIT4.md)
diff --git a/llvm/docs/tutorial/BuildingAJIT4.md b/llvm/docs/tutorial/BuildingAJIT4.md
index cbeca48e44342..fd3d4d6950046 100644
--- a/llvm/docs/tutorial/BuildingAJIT4.md
+++ b/llvm/docs/tutorial/BuildingAJIT4.md
@@ -1,19 +1,15 @@
-=======================================================================
-Building a JIT: Extreme Laziness - Using LazyReexports to JIT from ASTs
-=======================================================================
-
+# Building a JIT: Extreme Laziness - Using LazyReexports to JIT from ASTs
**This tutorial is under active development. It is incomplete and details may
change frequently.** Nonetheless we invite you to try it out as it stands, and
we welcome any feedback.
-Chapter 4 Introduction
-======================
+## Chapter 4 Introduction
Welcome to Chapter 4 of the "Building an ORC-based JIT in LLVM" tutorial. This
chapter introduces custom MaterializationUnits and Layers, and the lazy
reexports API. Together these will be used to replace the CompileOnDemandLayer
-from `Chapter 3 <BuildingAJIT3.html>`_ with a custom lazy-JITing scheme that JITs
+from [Chapter 3](BuildingAJIT3.md) with a custom lazy-JITing scheme that JITs
directly from Kaleidoscope ASTs.
**To be done:**
@@ -25,22 +21,23 @@ which reduces the benefits of laziness).**
**(3) Run through the implementation of addFunctionAST.**
-Full Code Listing
-=================
+## Full Code Listing
Here is the complete code listing for our running example that JITs lazily from
Kaleidoscope ASTS. To build this example, use:
-.. code-block:: bash
-
- # Compile
- clang++ -g toy.cpp `llvm-config --cxxflags --ldflags --system-libs --libs core orcjit native` -O3 -o toy
- # Run
- ./toy
+```bash
+# Compile
+clang++ -g toy.cpp `llvm-config --cxxflags --ldflags --system-libs --libs core orcjit native` -O3 -o toy
+# Run
+./toy
+```
Here is the code:
-.. literalinclude:: ../../examples/Kaleidoscope/BuildingAJIT/Chapter4/KaleidoscopeJIT.h
- :language: c++
+```{literalinclude} ../../examples/Kaleidoscope/BuildingAJIT/Chapter4/KaleidoscopeJIT.h
+:language: c++
+```
+
+[Next: Remote-JITing -- Process-isolation and laziness-at-a-distance](https://llvm.org/docs/tutorial/BuildingAJIT5.html)
-`Next: Remote-JITing -- Process-isolation and laziness-at-a-distance <BuildingAJIT5.html>`_
diff --git a/llvm/docs/tutorial/LangImpl01.md b/llvm/docs/tutorial/LangImpl01.md
index 6b90634055a05..1d20b76ef0ae1 100644
--- a/llvm/docs/tutorial/LangImpl01.md
+++ b/llvm/docs/tutorial/LangImpl01.md
@@ -1,7 +1,8 @@
-:orphan:
+---
+orphan: true
+---
-=====================
-Kaleidoscope Tutorial
-=====================
+# Kaleidoscope Tutorial
+
+The Kaleidoscope Tutorial has moved to {doc}`MyFirstLanguageFrontend/index`.
-The Kaleidoscope Tutorial has moved to :doc:`MyFirstLanguageFrontend/index`.
diff --git a/llvm/docs/tutorial/LangImpl02.md b/llvm/docs/tutorial/LangImpl02.md
index 6b90634055a05..1d20b76ef0ae1 100644
--- a/llvm/docs/tutorial/LangImpl02.md
+++ b/llvm/docs/tutorial/LangImpl02.md
@@ -1,7 +1,8 @@
-:orphan:
+---
+orphan: true
+---
-=====================
-Kaleidoscope Tutorial
-=====================
+# Kaleidoscope Tutorial
+
+The Kaleidoscope Tutorial has moved to {doc}`MyFirstLanguageFrontend/index`.
-The Kaleidoscope Tutorial has moved to :doc:`MyFirstLanguageFrontend/index`.
diff --git a/llvm/docs/tutorial/LangImpl03.md b/llvm/docs/tutorial/LangImpl03.md
index 6b90634055a05..1d20b76ef0ae1 100644
--- a/llvm/docs/tutorial/LangImpl03.md
+++ b/llvm/docs/tutorial/LangImpl03.md
@@ -1,7 +1,8 @@
-:orphan:
+---
+orphan: true
+---
-=====================
-Kaleidoscope Tutorial
-=====================
+# Kaleidoscope Tutorial
+
+The Kaleidoscope Tutorial has moved to {doc}`MyFirstLanguageFrontend/index`.
-The Kaleidoscope Tutorial has moved to :doc:`MyFirstLanguageFrontend/index`.
diff --git a/llvm/docs/tutorial/LangImpl04.md b/llvm/docs/tutorial/LangImpl04.md
index 6b90634055a05..1d20b76ef0ae1 100644
--- a/llvm/docs/tutorial/LangImpl04.md
+++ b/llvm/docs/tutorial/LangImpl04.md
@@ -1,7 +1,8 @@
-:orphan:
+---
+orphan: true
+---
-=====================
-Kaleidoscope Tutorial
-=====================
+# Kaleidoscope Tutorial
+
+The Kaleidoscope Tutorial has moved to {doc}`MyFirstLanguageFrontend/index`.
-The Kaleidoscope Tutorial has moved to :doc:`MyFirstLanguageFrontend/index`.
diff --git a/llvm/docs/tutorial/LangImpl05.md b/llvm/docs/tutorial/LangImpl05.md
index 6b90634055a05..1d20b76ef0ae1 100644
--- a/llvm/docs/tutorial/LangImpl05.md
+++ b/llvm/docs/tutorial/LangImpl05.md
@@ -1,7 +1,8 @@
-:orphan:
+---
+orphan: true
+---
-=====================
-Kaleidoscope Tutorial
-=====================
+# Kaleidoscope Tutorial
+
+The Kaleidoscope Tutorial has moved to {doc}`MyFirstLanguageFrontend/index`.
-The Kaleidoscope Tutorial has moved to :doc:`MyFirstLanguageFrontend/index`.
diff --git a/llvm/docs/tutorial/LangImpl06.md b/llvm/docs/tutorial/LangImpl06.md
index 6b90634055a05..1d20b76ef0ae1 100644
--- a/llvm/docs/tutorial/LangImpl06.md
+++ b/llvm/docs/tutorial/LangImpl06.md
@@ -1,7 +1,8 @@
-:orphan:
+---
+orphan: true
+---
-=====================
-Kaleidoscope Tutorial
-=====================
+# Kaleidoscope Tutorial
+
+The Kaleidoscope Tutorial has moved to {doc}`MyFirstLanguageFrontend/index`.
-The Kaleidoscope Tutorial has moved to :doc:`MyFirstLanguageFrontend/index`.
diff --git a/llvm/docs/tutorial/LangImpl07.md b/llvm/docs/tutorial/LangImpl07.md
index 6b90634055a05..1d20b76ef0ae1 100644
--- a/llvm/docs/tutorial/LangImpl07.md
+++ b/llvm/docs/tutorial/LangImpl07.md
@@ -1,7 +1,8 @@
-:orphan:
+---
+orphan: true
+---
-=====================
-Kaleidoscope Tutorial
-=====================
+# Kaleidoscope Tutorial
+
+The Kaleidoscope Tutorial has moved to {doc}`MyFirstLanguageFrontend/index`.
-The Kaleidoscope Tutorial has moved to :doc:`MyFirstLanguageFrontend/index`.
diff --git a/llvm/docs/tutorial/LangImpl08.md b/llvm/docs/tutorial/LangImpl08.md
index 6b90634055a05..1d20b76ef0ae1 100644
--- a/llvm/docs/tutorial/LangImpl08.md
+++ b/llvm/docs/tutorial/LangImpl08.md
@@ -1,7 +1,8 @@
-:orphan:
+---
+orphan: true
+---
-=====================
-Kaleidoscope Tutorial
-=====================
+# Kaleidoscope Tutorial
+
+The Kaleidoscope Tutorial has moved to {doc}`MyFirstLanguageFrontend/index`.
-The Kaleidoscope Tutorial has moved to :doc:`MyFirstLanguageFrontend/index`.
diff --git a/llvm/docs/tutorial/LangImpl09.md b/llvm/docs/tutorial/LangImpl09.md
index 6b90634055a05..1d20b76ef0ae1 100644
--- a/llvm/docs/tutorial/LangImpl09.md
+++ b/llvm/docs/tutorial/LangImpl09.md
@@ -1,7 +1,8 @@
-:orphan:
+---
+orphan: true
+---
-=====================
-Kaleidoscope Tutorial
-=====================
+# Kaleidoscope Tutorial
+
+The Kaleidoscope Tutorial has moved to {doc}`MyFirstLanguageFrontend/index`.
-The Kaleidoscope Tutorial has moved to :doc:`MyFirstLanguageFrontend/index`.
diff --git a/llvm/docs/tutorial/LangImpl10.md b/llvm/docs/tutorial/LangImpl10.md
index 6b90634055a05..1d20b76ef0ae1 100644
--- a/llvm/docs/tutorial/LangImpl10.md
+++ b/llvm/docs/tutorial/LangImpl10.md
@@ -1,7 +1,8 @@
-:orphan:
+---
+orphan: true
+---
-=====================
-Kaleidoscope Tutorial
-=====================
+# Kaleidoscope Tutorial
+
+The Kaleidoscope Tutorial has moved to {doc}`MyFirstLanguageFrontend/index`.
-The Kaleidoscope Tutorial has moved to :doc:`MyFirstLanguageFrontend/index`.
diff --git a/llvm/docs/tutorial/MyFirstLanguageFrontend/LangImpl01.md b/llvm/docs/tutorial/MyFirstLanguageFrontend/LangImpl01.md
index b1183cb19d376..13e01c7142952 100644
--- a/llvm/docs/tutorial/MyFirstLanguageFrontend/LangImpl01.md
+++ b/llvm/docs/tutorial/MyFirstLanguageFrontend/LangImpl01.md
@@ -1,13 +1,9 @@
-=====================================================
-Kaleidoscope: Kaleidoscope Introduction and the Lexer
-=====================================================
+# Kaleidoscope: Kaleidoscope Introduction and the Lexer
-
-The Kaleidoscope Language
-=========================
+## The Kaleidoscope Language
This tutorial is illustrated with a toy language called
-"`Kaleidoscope <http://en.wikipedia.org/wiki/Kaleidoscope>`_" (derived
+"[Kaleidoscope](http://en.wikipedia.org/wiki/Kaleidoscope)" (derived
from "meaning beautiful, form, and view"). Kaleidoscope is a procedural
language that allows you to define functions, use conditionals, math,
etc. Over the course of the tutorial, we'll extend Kaleidoscope to
@@ -19,174 +15,173 @@ is a 64-bit floating point type (aka 'double' in C parlance). As such,
all values are implicitly double precision and the language doesn't
require type declarations. This gives the language a very nice and
simple syntax. For example, the following simple example computes
-`Fibonacci numbers: <http://en.wikipedia.org/wiki/Fibonacci_number>`_
-
-::
+[Fibonacci numbers:](http://en.wikipedia.org/wiki/Fibonacci_number)
- # Compute the x'th fibonacci number.
- def fib(x)
- if x < 3 then
- 1
- else
- fib(x-1)+fib(x-2)
+```
+# Compute the x'th fibonacci number.
+def fib(x)
+ if x < 3 then
+ 1
+ else
+ fib(x-1)+fib(x-2)
- # This expression will compute the 40th number.
- fib(40)
+# This expression will compute the 40th number.
+fib(40)
+```
We also allow Kaleidoscope to call into standard library functions - the
LLVM JIT makes this really easy. This means that you can use the
'extern' keyword to define a function before you use it (this is also
-useful for mutually recursive functions). For example:
-
-::
+useful for mutually recursive functions). For example:
- extern sin(arg);
- extern cos(arg);
- extern atan2(arg1 arg2);
+```
+extern sin(arg);
+extern cos(arg);
+extern atan2(arg1 arg2);
- atan2(sin(.4), cos(42))
+atan2(sin(.4), cos(42))
+```
A more interesting example is included in Chapter 6 where we write a
-little Kaleidoscope application that `displays a Mandelbrot
-Set <LangImpl06.html#kicking-the-tires>`_ at various levels of magnification.
+little Kaleidoscope application that [displays a Mandelbrot
+Set](LangImpl06.md#kicking-the-tires) at various levels of magnification.
Let's dive into the implementation of this language!
-The Lexer
-=========
+## The Lexer
When it comes to implementing a language, the first thing needed is the
ability to process a text file and recognize what it says. The
traditional way to do this is to use a
-"`lexer <http://en.wikipedia.org/wiki/Lexical_analysis>`_" (aka
+"[lexer](http://en.wikipedia.org/wiki/Lexical_analysis)" (aka
'scanner') to break the input up into "tokens". Each token returned by
the lexer includes a token code and potentially some metadata (e.g. the
numeric value of a number). First, we define the possibilities:
-.. code-block:: c++
+```c++
+// The lexer returns tokens [0-255] if it is an unknown character, otherwise one
+// of these for known things.
+enum Token {
+ tok_eof = -1,
- // The lexer returns tokens [0-255] if it is an unknown character, otherwise one
- // of these for known things.
- enum Token {
- tok_eof = -1,
+ // commands
+ tok_def = -2,
+ tok_extern = -3,
- // commands
- tok_def = -2,
- tok_extern = -3,
+ // primary
+ tok_identifier = -4,
+ tok_number = -5,
+};
- // primary
- tok_identifier = -4,
- tok_number = -5,
- };
-
- static std::string IdentifierStr; // Filled in if tok_identifier
- static double NumVal; // Filled in if tok_number
+static std::string IdentifierStr; // Filled in if tok_identifier
+static double NumVal; // Filled in if tok_number
+```
Each token returned by our lexer will either be one of the Token enum
values or it will be an 'unknown' character like '+', which is returned
as its ASCII value. If the current token is an identifier, the
-``IdentifierStr`` global variable holds the name of the identifier. If
-the current token is a numeric literal (like 1.0), ``NumVal`` holds its
+`IdentifierStr` global variable holds the name of the identifier. If
+the current token is a numeric literal (like 1.0), `NumVal` holds its
value. We use global variables for simplicity, but this is not the
best choice for a real language implementation :).
The actual implementation of the lexer is a single function named
-``gettok``. The ``gettok`` function is called to return the next token
+`gettok`. The `gettok` function is called to return the next token
from standard input. Its definition starts as:
-.. code-block:: c++
-
- /// gettok - Return the next token from standard input.
- static int gettok() {
- static int LastChar = ' ';
+```c++
+/// gettok - Return the next token from standard input.
+static int gettok() {
+ static int LastChar = ' ';
- // Skip any whitespace.
- while (isspace(LastChar))
- LastChar = getchar();
+ // Skip any whitespace.
+ while (isspace(LastChar))
+ LastChar = getchar();
+```
-``gettok`` works by calling the C ``getchar()`` function to read
+`gettok` works by calling the C `getchar()` function to read
characters one at a time from standard input. It eats them as it
recognizes them and stores the last character read, but not processed,
in LastChar. The first thing that it has to do is ignore whitespace
between tokens. This is accomplished with the loop above.
-The next thing ``gettok`` needs to do is recognize identifiers and
+The next thing `gettok` needs to do is recognize identifiers and
specific keywords like "def". Kaleidoscope does this with this simple
loop:
-.. code-block:: c++
-
- if (isalpha(LastChar)) { // identifier: [a-zA-Z][a-zA-Z0-9]*
- IdentifierStr = LastChar;
- while (isalnum((LastChar = getchar())))
- IdentifierStr += LastChar;
-
- if (IdentifierStr == "def")
- return tok_def;
- if (IdentifierStr == "extern")
- return tok_extern;
- return tok_identifier;
- }
-
-Note that this code sets the '``IdentifierStr``' global whenever it
+```c++
+if (isalpha(LastChar)) { // identifier: [a-zA-Z][a-zA-Z0-9]*
+ IdentifierStr = LastChar;
+ while (isalnum((LastChar = getchar())))
+ IdentifierStr += LastChar;
+
+ if (IdentifierStr == "def")
+ return tok_def;
+ if (IdentifierStr == "extern")
+ return tok_extern;
+ return tok_identifier;
+}
+```
+
+Note that this code sets the '`IdentifierStr`' global whenever it
lexes an identifier. Also, since language keywords are matched by the
same loop, we handle them here inline. Numeric values are similar:
-.. code-block:: c++
-
- if (isdigit(LastChar) || LastChar == '.') { // Number: [0-9.]+
- std::string NumStr;
- do {
- NumStr += LastChar;
- LastChar = getchar();
- } while (isdigit(LastChar) || LastChar == '.');
+```c++
+if (isdigit(LastChar) || LastChar == '.') { // Number: [0-9.]+
+ std::string NumStr;
+ do {
+ NumStr += LastChar;
+ LastChar = getchar();
+ } while (isdigit(LastChar) || LastChar == '.');
- NumVal = strtod(NumStr.c_str(), 0);
- return tok_number;
- }
+ NumVal = strtod(NumStr.c_str(), 0);
+ return tok_number;
+}
+```
This is all pretty straightforward code for processing input. When
-reading a numeric value from input, we use the C ``strtod`` function to
-convert it to a numeric value that we store in ``NumVal``. Note that
+reading a numeric value from input, we use the C `strtod` function to
+convert it to a numeric value that we store in `NumVal`. Note that
this isn't doing sufficient error checking: it will incorrectly read
"1.23.45.67" and handle it as if you typed in "1.23". Feel free to
-extend it! Next we handle comments:
+extend it! Next we handle comments:
-.. code-block:: c++
+```c++
+if (LastChar == '#') {
+ // Comment until end of line.
+ do
+ LastChar = getchar();
+ while (LastChar != EOF && LastChar != '\n' && LastChar != '\r');
- if (LastChar == '#') {
- // Comment until end of line.
- do
- LastChar = getchar();
- while (LastChar != EOF && LastChar != '\n' && LastChar != '\r');
-
- if (LastChar != EOF)
- return gettok();
- }
+ if (LastChar != EOF)
+ return gettok();
+}
+```
We handle comments by skipping to the end of the line and then return
the next token. Finally, if the input doesn't match one of the above
cases, it is either an operator character like '+' or the end of the
file. These are handled with this code:
-.. code-block:: c++
-
- // Check for end of file. Don't eat the EOF.
- if (LastChar == EOF)
- return tok_eof;
+```c++
+ // Check for end of file. Don't eat the EOF.
+ if (LastChar == EOF)
+ return tok_eof;
- // Otherwise, just return the character as its ascii value.
- int ThisChar = LastChar;
- LastChar = getchar();
- return ThisChar;
- }
+ // Otherwise, just return the character as its ascii value.
+ int ThisChar = LastChar;
+ LastChar = getchar();
+ return ThisChar;
+}
+```
With this, we have the complete lexer for the basic Kaleidoscope
-language (the `full code listing <LangImpl02.html#full-code-listing>`_ for the Lexer
-is available in the `next chapter <LangImpl02.html>`_ of the tutorial).
-Next we'll `build a simple parser that uses this to build an Abstract
-Syntax Tree <LangImpl02.html>`_. When we have that, we'll include a
+language (the [full code listing](LangImpl02.md#full-code-listing) for the Lexer
+is available in the [next chapter](LangImpl02.md) of the tutorial).
+Next we'll [build a simple parser that uses this to build an Abstract
+Syntax Tree](LangImpl02.md). When we have that, we'll include a
driver so that you can use the lexer and parser together.
-`Next: Implementing a Parser and AST <LangImpl02.html>`_
+[Next: Implementing a Parser and AST](LangImpl02.md)
diff --git a/llvm/docs/tutorial/MyFirstLanguageFrontend/LangImpl02.md b/llvm/docs/tutorial/MyFirstLanguageFrontend/LangImpl02.md
index 2c8a51dfd1a33..a7b244d1ab092 100644
--- a/llvm/docs/tutorial/MyFirstLanguageFrontend/LangImpl02.md
+++ b/llvm/docs/tutorial/MyFirstLanguageFrontend/LangImpl02.md
@@ -1,28 +1,23 @@
-===========================================
-Kaleidoscope: Implementing a Parser and AST
-===========================================
+# Kaleidoscope: Implementing a Parser and AST
+## Chapter 2 Introduction
-Chapter 2 Introduction
-======================
+Welcome to Chapter 2 of the "[Implementing a language with
+LLVM](index.md)" tutorial. This chapter shows you how to use the
+lexer, built in [Chapter 1](LangImpl01.md), to build a full
+[parser](http://en.wikipedia.org/wiki/Parsing) for our Kaleidoscope
+language. Once we have a parser, we'll define and build an [Abstract
+Syntax Tree](http://en.wikipedia.org/wiki/Abstract_syntax_tree) (AST).
-Welcome to Chapter 2 of the "`Implementing a language with
-LLVM <index.html>`_" tutorial. This chapter shows you how to use the
-lexer, built in `Chapter 1 <LangImpl01.html>`_, to build a full
-`parser <http://en.wikipedia.org/wiki/Parsing>`_ for our Kaleidoscope
-language. Once we have a parser, we'll define and build an `Abstract
-Syntax Tree <http://en.wikipedia.org/wiki/Abstract_syntax_tree>`_ (AST).
-
-The parser we will build uses a combination of `Recursive Descent
-Parsing <http://en.wikipedia.org/wiki/Recursive_descent_parser>`_ and
-`Operator-Precedence
-Parsing <http://en.wikipedia.org/wiki/Operator-precedence_parser>`_ to
+The parser we will build uses a combination of [Recursive Descent
+Parsing](http://en.wikipedia.org/wiki/Recursive_descent_parser) and
+[Operator-Precedence
+Parsing](http://en.wikipedia.org/wiki/Operator-precedence_parser) to
parse the Kaleidoscope language (the latter for binary expressions and
the former for everything else). Before we get to parsing though, let's
talk about the output of the parser: the Abstract Syntax Tree.
-The Abstract Syntax Tree (AST)
-==============================
+## The Abstract Syntax Tree (AST)
The AST for a program captures its behavior in such a way that it is
easy for later stages of the compiler (e.g. code generation) to
@@ -31,21 +26,21 @@ language, and the AST should closely model the language. In
Kaleidoscope, we have expressions, a prototype, and a function object.
We'll start with expressions first:
-.. code-block:: c++
-
- /// ExprAST - Base class for all expression nodes.
- class ExprAST {
- public:
- virtual ~ExprAST() = default;
- };
+```c++
+/// ExprAST - Base class for all expression nodes.
+class ExprAST {
+public:
+ virtual ~ExprAST() = default;
+};
- /// NumberExprAST - Expression class for numeric literals like "1.0".
- class NumberExprAST : public ExprAST {
- double Val;
+/// NumberExprAST - Expression class for numeric literals like "1.0".
+class NumberExprAST : public ExprAST {
+ double Val;
- public:
- NumberExprAST(double Val) : Val(Val) {}
- };
+public:
+ NumberExprAST(double Val) : Val(Val) {}
+};
+```
The code above shows the definition of the base ExprAST class and one
subclass which we use for numeric literals. The important thing to note
@@ -59,37 +54,37 @@ print the code, for example. Here are the other expression AST node
definitions that we'll use in the basic form of the Kaleidoscope
language:
-.. code-block:: c++
-
- /// VariableExprAST - Expression class for referencing a variable, like "a".
- class VariableExprAST : public ExprAST {
- std::string Name;
-
- public:
- VariableExprAST(const std::string &Name) : Name(Name) {}
- };
-
- /// BinaryExprAST - Expression class for a binary operator.
- class BinaryExprAST : public ExprAST {
- char Op;
- std::unique_ptr<ExprAST> LHS, RHS;
-
- public:
- BinaryExprAST(char Op, std::unique_ptr<ExprAST> LHS,
- std::unique_ptr<ExprAST> RHS)
- : Op(Op), LHS(std::move(LHS)), RHS(std::move(RHS)) {}
- };
-
- /// CallExprAST - Expression class for function calls.
- class CallExprAST : public ExprAST {
- std::string Callee;
- std::vector<std::unique_ptr<ExprAST>> Args;
-
- public:
- CallExprAST(const std::string &Callee,
- std::vector<std::unique_ptr<ExprAST>> Args)
- : Callee(Callee), Args(std::move(Args)) {}
- };
+```c++
+/// VariableExprAST - Expression class for referencing a variable, like "a".
+class VariableExprAST : public ExprAST {
+ std::string Name;
+
+public:
+ VariableExprAST(const std::string &Name) : Name(Name) {}
+};
+
+/// BinaryExprAST - Expression class for a binary operator.
+class BinaryExprAST : public ExprAST {
+ char Op;
+ std::unique_ptr<ExprAST> LHS, RHS;
+
+public:
+ BinaryExprAST(char Op, std::unique_ptr<ExprAST> LHS,
+ std::unique_ptr<ExprAST> RHS)
+ : Op(Op), LHS(std::move(LHS)), RHS(std::move(RHS)) {}
+};
+
+/// CallExprAST - Expression class for function calls.
+class CallExprAST : public ExprAST {
+ std::string Callee;
+ std::vector<std::unique_ptr<ExprAST>> Args;
+
+public:
+ CallExprAST(const std::string &Callee,
+ std::vector<std::unique_ptr<ExprAST>> Args)
+ : Callee(Callee), Args(std::move(Args)) {}
+};
+```
This is all (intentionally) rather straight-forward: variables capture
the variable name, binary operators capture their opcode (e.g. '+'), and
@@ -105,32 +100,32 @@ Turing-complete; we'll fix that in a later installment. The two things
we need next are a way to talk about the interface to a function, and a
way to talk about functions themselves:
-.. code-block:: c++
-
- /// PrototypeAST - This class represents the "prototype" for a function,
- /// which captures its name, and its argument names (thus implicitly the number
- /// of arguments the function takes).
- class PrototypeAST {
- std::string Name;
- std::vector<std::string> Args;
-
- public:
- PrototypeAST(const std::string &Name, std::vector<std::string> Args)
- : Name(Name), Args(std::move(Args)) {}
-
- const std::string &getName() const { return Name; }
- };
-
- /// FunctionAST - This class represents a function definition itself.
- class FunctionAST {
- std::unique_ptr<PrototypeAST> Proto;
- std::unique_ptr<ExprAST> Body;
-
- public:
- FunctionAST(std::unique_ptr<PrototypeAST> Proto,
- std::unique_ptr<ExprAST> Body)
- : Proto(std::move(Proto)), Body(std::move(Body)) {}
- };
+```c++
+/// PrototypeAST - This class represents the "prototype" for a function,
+/// which captures its name, and its argument names (thus implicitly the number
+/// of arguments the function takes).
+class PrototypeAST {
+ std::string Name;
+ std::vector<std::string> Args;
+
+public:
+ PrototypeAST(const std::string &Name, std::vector<std::string> Args)
+ : Name(Name), Args(std::move(Args)) {}
+
+ const std::string &getName() const { return Name; }
+};
+
+/// FunctionAST - This class represents a function definition itself.
+class FunctionAST {
+ std::unique_ptr<PrototypeAST> Proto;
+ std::unique_ptr<ExprAST> Body;
+
+public:
+ FunctionAST(std::unique_ptr<PrototypeAST> Proto,
+ std::unique_ptr<ExprAST> Body)
+ : Proto(std::move(Proto)), Body(std::move(Body)) {}
+};
+```
In Kaleidoscope, functions are typed with just a count of their
arguments. Since all values are double precision floating point, the
@@ -141,52 +136,50 @@ have a type field.
With this scaffolding, we can now talk about parsing expressions and
function bodies in Kaleidoscope.
-Parser Basics
-=============
+## Parser Basics
Now that we have an AST to build, we need to define the parser code to
build it. The idea here is that we want to parse something like "x+y"
(which is returned as three tokens by the lexer) into an AST that could
be generated with calls like this:
-.. code-block:: c++
-
- auto LHS = std::make_unique<VariableExprAST>("x");
- auto RHS = std::make_unique<VariableExprAST>("y");
- auto Result = std::make_unique<BinaryExprAST>('+', std::move(LHS),
- std::move(RHS));
+```c++
+auto LHS = std::make_unique<VariableExprAST>("x");
+auto RHS = std::make_unique<VariableExprAST>("y");
+auto Result = std::make_unique<BinaryExprAST>('+', std::move(LHS),
+ std::move(RHS));
+```
In order to do this, we'll start by defining some basic helper routines:
-.. code-block:: c++
-
- /// CurTok/getNextToken - Provide a simple token buffer. CurTok is the current
- /// token the parser is looking at. getNextToken reads another token from the
- /// lexer and updates CurTok with its results.
- static int CurTok;
- static int getNextToken() {
- return CurTok = gettok();
- }
+```c++
+/// CurTok/getNextToken - Provide a simple token buffer. CurTok is the current
+/// token the parser is looking at. getNextToken reads another token from the
+/// lexer and updates CurTok with its results.
+static int CurTok;
+static int getNextToken() {
+ return CurTok = gettok();
+}
+```
This implements a simple token buffer around the lexer. This allows us
to look one token ahead at what the lexer is returning. Every function
in our parser will assume that CurTok is the current token that needs to
be parsed.
-.. code-block:: c++
-
-
- /// LogError* - These are little helper functions for error handling.
- std::unique_ptr<ExprAST> LogError(const char *Str) {
- fprintf(stderr, "Error: %s\n", Str);
- return nullptr;
- }
- std::unique_ptr<PrototypeAST> LogErrorP(const char *Str) {
- LogError(Str);
- return nullptr;
- }
-
-The ``LogError`` routines are simple helper routines that our parser will
+```c++
+/// LogError* - These are little helper functions for error handling.
+std::unique_ptr<ExprAST> LogError(const char *Str) {
+ fprintf(stderr, "Error: %s\n", Str);
+ return nullptr;
+}
+std::unique_ptr<PrototypeAST> LogErrorP(const char *Str) {
+ LogError(Str);
+ return nullptr;
+}
+```
+
+The `LogError` routines are simple helper routines that our parser will
use to handle errors. The error recovery in our parser will not be the
best and is not particular user-friendly, but it will be enough for our
tutorial. These routines make it easier to handle errors in routines
@@ -195,25 +188,24 @@ that have various return types: they always return null.
With these basic helper functions, we can implement the first piece of
our grammar: numeric literals.
-Basic Expression Parsing
-========================
+## Basic Expression Parsing
We start with numeric literals, because they are the simplest to
process. For each production in our grammar, we'll define a function
which parses that production. For numeric literals, we have:
-.. code-block:: c++
-
- /// numberexpr ::= number
- static std::unique_ptr<ExprAST> ParseNumberExpr() {
- auto Result = std::make_unique<NumberExprAST>(NumVal);
- getNextToken(); // consume the number
- return std::move(Result);
- }
+```c++
+/// numberexpr ::= number
+static std::unique_ptr<ExprAST> ParseNumberExpr() {
+ auto Result = std::make_unique<NumberExprAST>(NumVal);
+ getNextToken(); // consume the number
+ return std::move(Result);
+}
+```
This routine is very simple: it expects to be called when the current
-token is a ``tok_number`` token. It takes the current number value,
-creates a ``NumberExprAST`` node, advances the lexer to the next token,
+token is a `tok_number` token. It takes the current number value,
+creates a `NumberExprAST` node, advances the lexer to the next token,
and finally returns.
There are some interesting aspects to this. The most important one is
@@ -223,34 +215,34 @@ not part of the grammar production) ready to go. This is a fairly
standard way to go for recursive descent parsers. For a better example,
the parenthesis operator is defined like this:
-.. code-block:: c++
-
- /// parenexpr ::= '(' expression ')'
- static std::unique_ptr<ExprAST> ParseParenExpr() {
- getNextToken(); // eat (.
- auto V = ParseExpression();
- if (!V)
- return nullptr;
-
- if (CurTok != ')')
- return LogError("expected ')'");
- getNextToken(); // eat ).
- return V;
- }
+```c++
+/// parenexpr ::= '(' expression ')'
+static std::unique_ptr<ExprAST> ParseParenExpr() {
+ getNextToken(); // eat (.
+ auto V = ParseExpression();
+ if (!V)
+ return nullptr;
+
+ if (CurTok != ')')
+ return LogError("expected ')'");
+ getNextToken(); // eat ).
+ return V;
+}
+```
This function illustrates a number of interesting things about the
parser:
-1) It shows how we use the LogError routines. When called, this function
+1\) It shows how we use the LogError routines. When called, this function
expects that the current token is a '(' token, but after parsing the
subexpression, it is possible that there is no ')' waiting. For example,
if the user types in "(4 x" instead of "(4)", the parser should emit an
error. Because errors can occur, the parser needs a way to indicate that
they happened: in our parser, we return null on an error.
-2) Another interesting aspect of this function is that it uses recursion
-by calling ``ParseExpression`` (we will soon see that
-``ParseExpression`` can call ``ParseParenExpr``). This is powerful
+2\) Another interesting aspect of this function is that it uses recursion
+by calling `ParseExpression` (we will soon see that
+`ParseExpression` can call `ParseParenExpr`). This is powerful
because it allows us to handle recursive grammars, and keeps each
production very simple. Note that parentheses do not cause construction
of AST nodes themselves. While we could do it this way, the most
@@ -261,78 +253,78 @@ needed.
The next simple production is for handling variable references and
function calls:
-.. code-block:: c++
-
- /// identifierexpr
- /// ::= identifier
- /// ::= identifier '(' expression* ')'
- static std::unique_ptr<ExprAST> ParseIdentifierExpr() {
- std::string IdName = IdentifierStr;
-
- getNextToken(); // eat identifier.
-
- if (CurTok != '(') // Simple variable ref.
- return std::make_unique<VariableExprAST>(IdName);
-
- // Call.
- getNextToken(); // eat (
- std::vector<std::unique_ptr<ExprAST>> Args;
- if (CurTok != ')') {
- while (true) {
- if (auto Arg = ParseExpression())
- Args.push_back(std::move(Arg));
- else
- return nullptr;
-
- if (CurTok == ')')
- break;
+```c++
+/// identifierexpr
+/// ::= identifier
+/// ::= identifier '(' expression* ')'
+static std::unique_ptr<ExprAST> ParseIdentifierExpr() {
+ std::string IdName = IdentifierStr;
+
+ getNextToken(); // eat identifier.
+
+ if (CurTok != '(') // Simple variable ref.
+ return std::make_unique<VariableExprAST>(IdName);
+
+ // Call.
+ getNextToken(); // eat (
+ std::vector<std::unique_ptr<ExprAST>> Args;
+ if (CurTok != ')') {
+ while (true) {
+ if (auto Arg = ParseExpression())
+ Args.push_back(std::move(Arg));
+ else
+ return nullptr;
- if (CurTok != ',')
- return LogError("Expected ')' or ',' in argument list");
- getNextToken();
- }
- }
+ if (CurTok == ')')
+ break;
- // Eat the ')'.
+ if (CurTok != ',')
+ return LogError("Expected ')' or ',' in argument list");
getNextToken();
-
- return std::make_unique<CallExprAST>(IdName, std::move(Args));
}
+ }
+
+ // Eat the ')'.
+ getNextToken();
+
+ return std::make_unique<CallExprAST>(IdName, std::move(Args));
+}
+```
This routine follows the same style as the other routines. (It expects
-to be called if the current token is a ``tok_identifier`` token). It
+to be called if the current token is a `tok_identifier` token). It
also has recursion and error handling. One interesting aspect of this is
that it uses *look-ahead* to determine if the current identifier is a
stand alone variable reference or if it is a function call expression.
It handles this by checking to see if the token after the identifier is
-a '(' token, constructing either a ``VariableExprAST`` or
-``CallExprAST`` node as appropriate.
+a '(' token, constructing either a `VariableExprAST` or
+`CallExprAST` node as appropriate.
Now that we have all of our simple expression-parsing logic in place, we
can define a helper function to wrap it together into one entry point.
We call this class of expressions "primary" expressions, for reasons
-that will become more clear `later in the
-tutorial <LangImpl06.html#user-defined-unary-operators>`_. In order to parse an arbitrary
+that will become more clear [later in the
+tutorial](LangImpl06.md#user-defined-unary-operators). In order to parse an arbitrary
primary expression, we need to determine what sort of expression it is:
-.. code-block:: c++
-
- /// primary
- /// ::= identifierexpr
- /// ::= numberexpr
- /// ::= parenexpr
- static std::unique_ptr<ExprAST> ParsePrimary() {
- switch (CurTok) {
- default:
- return LogError("unknown token when expecting an expression");
- case tok_identifier:
- return ParseIdentifierExpr();
- case tok_number:
- return ParseNumberExpr();
- case '(':
- return ParseParenExpr();
- }
- }
+```c++
+/// primary
+/// ::= identifierexpr
+/// ::= numberexpr
+/// ::= parenexpr
+static std::unique_ptr<ExprAST> ParsePrimary() {
+ switch (CurTok) {
+ default:
+ return LogError("unknown token when expecting an expression");
+ case tok_identifier:
+ return ParseIdentifierExpr();
+ case tok_number:
+ return ParseNumberExpr();
+ case '(':
+ return ParseParenExpr();
+ }
+}
+```
Now that you see the definition of this function, it is more obvious why
we can assume the state of CurTok in the various functions. This uses
@@ -342,8 +334,7 @@ then parses it with a function call.
Now that basic expressions are handled, we need to handle binary
expressions. They are a bit more complex.
-Binary Expression Parsing
-=========================
+## Binary Expression Parsing
Binary expressions are significantly harder to parse because they are
often ambiguous. For example, when given the string "x+y\*z", the parser
@@ -352,46 +343,46 @@ definitions from mathematics, we expect the later parse, because "\*"
(multiplication) has higher *precedence* than "+" (addition).
There are many ways to handle this, but an elegant and efficient way is
-to use `Operator-Precedence
-Parsing <http://en.wikipedia.org/wiki/Operator-precedence_parser>`_.
+to use [Operator-Precedence
+Parsing](http://en.wikipedia.org/wiki/Operator-precedence_parser).
This parsing technique uses the precedence of binary operators to guide
recursion. To start with, we need a table of precedences:
-.. code-block:: c++
-
- /// BinopPrecedence - This holds the precedence for each binary operator that is
- /// defined.
- static std::map<char, int> BinopPrecedence;
-
- /// GetTokPrecedence - Get the precedence of the pending binary operator token.
- static int GetTokPrecedence() {
- if (!isascii(CurTok))
- return -1;
-
- // Make sure it's a declared binop.
- int TokPrec = BinopPrecedence[CurTok];
- if (TokPrec <= 0) return -1;
- return TokPrec;
- }
-
- int main() {
- // Install standard binary operators.
- // 1 is lowest precedence.
- BinopPrecedence['<'] = 10;
- BinopPrecedence['+'] = 20;
- BinopPrecedence['-'] = 20;
- BinopPrecedence['*'] = 40; // highest.
- ...
- }
+```c++
+/// BinopPrecedence - This holds the precedence for each binary operator that is
+/// defined.
+static std::map<char, int> BinopPrecedence;
+
+/// GetTokPrecedence - Get the precedence of the pending binary operator token.
+static int GetTokPrecedence() {
+ if (!isascii(CurTok))
+ return -1;
+
+ // Make sure it's a declared binop.
+ int TokPrec = BinopPrecedence[CurTok];
+ if (TokPrec <= 0) return -1;
+ return TokPrec;
+}
+
+int main() {
+ // Install standard binary operators.
+ // 1 is lowest precedence.
+ BinopPrecedence['<'] = 10;
+ BinopPrecedence['+'] = 20;
+ BinopPrecedence['-'] = 20;
+ BinopPrecedence['*'] = 40; // highest.
+ ...
+}
+```
For the basic form of Kaleidoscope, we will only support 4 binary
operators (this can obviously be extended by you, our brave and intrepid
-reader). The ``GetTokPrecedence`` function returns the precedence for
+reader). The `GetTokPrecedence` function returns the precedence for
the current token, or -1 if the token is not a binary operator. Having a
map makes it easy to add new operators and makes it clear that the
algorithm doesn't depend on the specific operators involved, but it
would be easy enough to eliminate the map and do the comparisons in the
-``GetTokPrecedence`` function. (Or just use a fixed-size array).
+`GetTokPrecedence` function. (Or just use a fixed-size array).
With the helper above defined, we can now start parsing binary
expressions. The basic idea of operator precedence parsing is to break
@@ -407,48 +398,48 @@ about nested subexpressions like (c+d) at all.
To start, an expression is a primary expression potentially followed by
a sequence of [binop,primaryexpr] pairs:
-.. code-block:: c++
-
- /// expression
- /// ::= primary binoprhs
- ///
- static std::unique_ptr<ExprAST> ParseExpression() {
- auto LHS = ParsePrimary();
- if (!LHS)
- return nullptr;
+```c++
+/// expression
+/// ::= primary binoprhs
+///
+static std::unique_ptr<ExprAST> ParseExpression() {
+ auto LHS = ParsePrimary();
+ if (!LHS)
+ return nullptr;
- return ParseBinOpRHS(0, std::move(LHS));
- }
+ return ParseBinOpRHS(0, std::move(LHS));
+}
+```
-``ParseBinOpRHS`` is the function that parses the sequence of pairs for
+`ParseBinOpRHS` is the function that parses the sequence of pairs for
us. It takes a precedence and a pointer to an expression for the part
that has been parsed so far. Note that "x" is a perfectly valid
expression: As such, "binoprhs" is allowed to be empty, in which case it
returns the expression that is passed into it. In our example above, the
-code passes the expression for "a" into ``ParseBinOpRHS`` and the
+code passes the expression for "a" into `ParseBinOpRHS` and the
current token is "+".
-The precedence value passed into ``ParseBinOpRHS`` indicates the
+The precedence value passed into `ParseBinOpRHS` indicates the
*minimal operator precedence* that the function is allowed to eat. For
-example, if the current pair stream is [+, x] and ``ParseBinOpRHS`` is
+example, if the current pair stream is [+, x] and `ParseBinOpRHS` is
passed in a precedence of 40, it will not consume any tokens (because
-the precedence of '+' is only 20). With this in mind, ``ParseBinOpRHS``
+the precedence of '+' is only 20). With this in mind, `ParseBinOpRHS`
starts with:
-.. code-block:: c++
-
- /// binoprhs
- /// ::= ('+' primary)*
- static std::unique_ptr<ExprAST> ParseBinOpRHS(int ExprPrec,
- std::unique_ptr<ExprAST> LHS) {
- // If this is a binop, find its precedence.
- while (true) {
- int TokPrec = GetTokPrecedence();
-
- // If this is a binop that binds at least as tightly as the current binop,
- // consume it, otherwise we are done.
- if (TokPrec < ExprPrec)
- return LHS;
+```c++
+/// binoprhs
+/// ::= ('+' primary)*
+static std::unique_ptr<ExprAST> ParseBinOpRHS(int ExprPrec,
+ std::unique_ptr<ExprAST> LHS) {
+ // If this is a binop, find its precedence.
+ while (true) {
+ int TokPrec = GetTokPrecedence();
+
+ // If this is a binop that binds at least as tightly as the current binop,
+ // consume it, otherwise we are done.
+ if (TokPrec < ExprPrec)
+ return LHS;
+```
This code gets the precedence of the current token and checks to see if
it is too low. Because we defined invalid tokens to have a precedence of
@@ -457,16 +448,16 @@ stream runs out of binary operators. If this check succeeds, we know
that the token is a binary operator and that it will be included in this
expression:
-.. code-block:: c++
-
- // Okay, we know this is a binop.
- int BinOp = CurTok;
- getNextToken(); // eat binop
+```c++
+// Okay, we know this is a binop.
+int BinOp = CurTok;
+getNextToken(); // eat binop
- // Parse the primary expression after the binary operator.
- auto RHS = ParsePrimary();
- if (!RHS)
- return nullptr;
+// Parse the primary expression after the binary operator.
+auto RHS = ParsePrimary();
+if (!RHS)
+ return nullptr;
+```
As such, this code eats (and remembers) the binary operator and then
parses the primary expression that follows. This builds up the whole
@@ -479,12 +470,12 @@ unparsed)". To determine this, we look ahead at "binop" to determine its
precedence and compare it to BinOp's precedence (which is '+' in this
case):
-.. code-block:: c++
-
- // If BinOp binds less tightly with RHS than the operator after RHS, let
- // the pending operator take RHS as its LHS.
- int NextPrec = GetTokPrecedence();
- if (TokPrec < NextPrec) {
+```c++
+// If BinOp binds less tightly with RHS than the operator after RHS, let
+// the pending operator take RHS as its LHS.
+int NextPrec = GetTokPrecedence();
+if (TokPrec < NextPrec) {
+```
If the precedence of the binop to the right of "RHS" is lower or equal
to the precedence of our current operator, then we know that the
@@ -493,17 +484,17 @@ operator is "+" and the next operator is "+", we know that they have the
same precedence. In this case we'll create the AST node for "a+b", and
then continue parsing:
-.. code-block:: c++
-
- ... if body omitted ...
- }
-
- // Merge LHS/RHS.
- LHS = std::make_unique<BinaryExprAST>(BinOp, std::move(LHS),
- std::move(RHS));
- } // loop around to the top of the while loop.
+```c++
+ ... if body omitted ...
}
+ // Merge LHS/RHS.
+ LHS = std::make_unique<BinaryExprAST>(BinOp, std::move(LHS),
+ std::move(RHS));
+ } // loop around to the top of the while loop.
+}
+```
+
In our example above, this will turn "a+b+" into "(a+b)" and execute the
next iteration of the loop, with "+" as the current token. The code
above will eat, remember, and parse "(c+d)" as the primary expression,
@@ -518,27 +509,27 @@ our example, it needs to get all of "(c+d)\*e\*f" as the RHS expression
variable. The code to do this is surprisingly simple (code from the
above two blocks duplicated for context):
-.. code-block:: c++
-
- // If BinOp binds less tightly with RHS than the operator after RHS, let
- // the pending operator take RHS as its LHS.
- int NextPrec = GetTokPrecedence();
- if (TokPrec < NextPrec) {
- RHS = ParseBinOpRHS(TokPrec+1, std::move(RHS));
- if (!RHS)
- return nullptr;
- }
- // Merge LHS/RHS.
- LHS = std::make_unique<BinaryExprAST>(BinOp, std::move(LHS),
- std::move(RHS));
- } // loop around to the top of the while loop.
+```c++
+ // If BinOp binds less tightly with RHS than the operator after RHS, let
+ // the pending operator take RHS as its LHS.
+ int NextPrec = GetTokPrecedence();
+ if (TokPrec < NextPrec) {
+ RHS = ParseBinOpRHS(TokPrec+1, std::move(RHS));
+ if (!RHS)
+ return nullptr;
}
+ // Merge LHS/RHS.
+ LHS = std::make_unique<BinaryExprAST>(BinOp, std::move(LHS),
+ std::move(RHS));
+ } // loop around to the top of the while loop.
+}
+```
At this point, we know that the binary operator to the RHS of our
primary has higher precedence than the binop we are currently parsing.
As such, we know that any sequence of pairs whose operators are all
higher precedence than "+" should be parsed together and returned as
-"RHS". To do this, we recursively invoke the ``ParseBinOpRHS`` function
+"RHS". To do this, we recursively invoke the `ParseBinOpRHS` function
specifying "TokPrec+1" as the minimum precedence required for it to
continue. In our example above, this will cause it to return the AST
node for "(c+d)\*e\*f" as RHS, which is then set as the RHS of the '+'
@@ -556,8 +547,7 @@ parser at an arbitrary token stream and build an expression from it,
stopping at the first token that is not part of the expression. Next up
we need to handle function definitions, etc.
-Parsing the Rest
-================
+## Parsing the Rest
The next thing missing is handling of function prototypes. In
Kaleidoscope, these are used both for 'extern' function declarations as
@@ -565,112 +555,111 @@ well as function body definitions. The code to do this is
straight-forward and not very interesting (once you've survived
expressions):
-.. code-block:: c++
-
- /// prototype
- /// ::= id '(' id* ')'
- static std::unique_ptr<PrototypeAST> ParsePrototype() {
- if (CurTok != tok_identifier)
- return LogErrorP("Expected function name in prototype");
+```c++
+/// prototype
+/// ::= id '(' id* ')'
+static std::unique_ptr<PrototypeAST> ParsePrototype() {
+ if (CurTok != tok_identifier)
+ return LogErrorP("Expected function name in prototype");
- std::string FnName = IdentifierStr;
- getNextToken();
+ std::string FnName = IdentifierStr;
+ getNextToken();
- if (CurTok != '(')
- return LogErrorP("Expected '(' in prototype");
+ if (CurTok != '(')
+ return LogErrorP("Expected '(' in prototype");
- // Read the list of argument names.
- std::vector<std::string> ArgNames;
- while (getNextToken() == tok_identifier)
- ArgNames.push_back(IdentifierStr);
- if (CurTok != ')')
- return LogErrorP("Expected ')' in prototype");
+ // Read the list of argument names.
+ std::vector<std::string> ArgNames;
+ while (getNextToken() == tok_identifier)
+ ArgNames.push_back(IdentifierStr);
+ if (CurTok != ')')
+ return LogErrorP("Expected ')' in prototype");
- // success.
- getNextToken(); // eat ')'.
+ // success.
+ getNextToken(); // eat ')'.
- return std::make_unique<PrototypeAST>(FnName, std::move(ArgNames));
- }
+ return std::make_unique<PrototypeAST>(FnName, std::move(ArgNames));
+}
+```
Given this, a function definition is very simple, just a prototype plus
an expression to implement the body:
-.. code-block:: c++
+```c++
+/// definition ::= 'def' prototype expression
+static std::unique_ptr<FunctionAST> ParseDefinition() {
+ getNextToken(); // eat def.
+ auto Proto = ParsePrototype();
+ if (!Proto) return nullptr;
- /// definition ::= 'def' prototype expression
- static std::unique_ptr<FunctionAST> ParseDefinition() {
- getNextToken(); // eat def.
- auto Proto = ParsePrototype();
- if (!Proto) return nullptr;
-
- if (auto E = ParseExpression())
- return std::make_unique<FunctionAST>(std::move(Proto), std::move(E));
- return nullptr;
- }
+ if (auto E = ParseExpression())
+ return std::make_unique<FunctionAST>(std::move(Proto), std::move(E));
+ return nullptr;
+}
+```
In addition, we support 'extern' to declare functions like 'sin' and
'cos' as well as to support forward declaration of user functions. These
'extern's are just prototypes with no body:
-.. code-block:: c++
-
- /// external ::= 'extern' prototype
- static std::unique_ptr<PrototypeAST> ParseExtern() {
- getNextToken(); // eat extern.
- return ParsePrototype();
- }
+```c++
+/// external ::= 'extern' prototype
+static std::unique_ptr<PrototypeAST> ParseExtern() {
+ getNextToken(); // eat extern.
+ return ParsePrototype();
+}
+```
Finally, we'll also let the user type in arbitrary top-level expressions
and evaluate them on the fly. We will handle this by defining anonymous
nullary (zero argument) functions for them:
-.. code-block:: c++
-
- /// toplevelexpr ::= expression
- static std::unique_ptr<FunctionAST> ParseTopLevelExpr() {
- if (auto E = ParseExpression()) {
- // Make an anonymous proto.
- auto Proto = std::make_unique<PrototypeAST>("__anon_expr", std::vector<std::string>());
- return std::make_unique<FunctionAST>(std::move(Proto), std::move(E));
- }
- return nullptr;
- }
+```c++
+/// toplevelexpr ::= expression
+static std::unique_ptr<FunctionAST> ParseTopLevelExpr() {
+ if (auto E = ParseExpression()) {
+ // Make an anonymous proto.
+ auto Proto = std::make_unique<PrototypeAST>("__anon_expr", std::vector<std::string>());
+ return std::make_unique<FunctionAST>(std::move(Proto), std::move(E));
+ }
+ return nullptr;
+}
+```
Now that we have all the pieces, let's build a little driver that will
let us actually *execute* this code we've built!
-The Driver
-==========
+## The Driver
The driver for this simply invokes all of the parsing pieces with a
top-level dispatch loop. There isn't much interesting here, so I'll just
-include the top-level loop. See `below <#full-code-listing>`_ for full code in the
+include the top-level loop. See [below](#full-code-listing) for full code in the
"Top-Level Parsing" section.
-.. code-block:: c++
-
- /// top ::= definition | external | expression | ';'
- static void MainLoop() {
- while (true) {
- fprintf(stderr, "ready> ");
- switch (CurTok) {
- case tok_eof:
- return;
- case ';': // ignore top-level semicolons.
- getNextToken();
- break;
- case tok_def:
- HandleDefinition();
- break;
- case tok_extern:
- HandleExtern();
- break;
- default:
- HandleTopLevelExpression();
- break;
- }
- }
+```c++
+/// top ::= definition | external | expression | ';'
+static void MainLoop() {
+ while (true) {
+ fprintf(stderr, "ready> ");
+ switch (CurTok) {
+ case tok_eof:
+ return;
+ case ';': // ignore top-level semicolons.
+ getNextToken();
+ break;
+ case tok_def:
+ HandleDefinition();
+ break;
+ case tok_extern:
+ HandleExtern();
+ break;
+ default:
+ HandleTopLevelExpression();
+ break;
}
+ }
+}
+```
The most interesting part of this is that we ignore top-level
semicolons. Why is this, you ask? The basic reason is that if you type
@@ -681,8 +670,7 @@ expression. Alternatively you could type "\* 6", which would continue
the expression. Having top-level semicolons allows you to type "4+5;",
and the parser will know you are done.
-Conclusions
-===========
+## Conclusions
With just under 400 lines of commented code (240 lines of non-comment,
non-blank code), we fully defined our minimal language, including a
@@ -690,43 +678,43 @@ lexer, parser, and AST builder. With this done, the executable will
validate Kaleidoscope code and tell us if it is grammatically invalid.
For example, here is a sample interaction:
-.. code-block:: bash
-
- $ ./a.out
- ready> def foo(x y) x+foo(y, 4.0);
- Parsed a function definition.
- ready> def foo(x y) x+y y;
- Parsed a function definition.
- Parsed a top-level expr
- ready> def foo(x y) x+y );
- Parsed a function definition.
- Error: unknown token when expecting an expression
- ready> extern sin(a);
- ready> Parsed an extern
- ready> ^D
- $
+```bash
+$ ./a.out
+ready> def foo(x y) x+foo(y, 4.0);
+Parsed a function definition.
+ready> def foo(x y) x+y y;
+Parsed a function definition.
+Parsed a top-level expr
+ready> def foo(x y) x+y );
+Parsed a function definition.
+Error: unknown token when expecting an expression
+ready> extern sin(a);
+ready> Parsed an extern
+ready> ^D
+$
+```
There is a lot of room for extension here. You can define new AST nodes,
-extend the language in many ways, etc. In the `next
-installment <LangImpl03.html>`_, we will describe how to generate LLVM
+extend the language in many ways, etc. In the [next
+installment](LangImpl03.md), we will describe how to generate LLVM
Intermediate Representation (IR) from the AST.
-Full Code Listing
-=================
+## Full Code Listing
Here is the complete code listing for our running example.
-.. code-block:: bash
-
- # Compile
- clang++ -g -O3 toy.cpp
- # Run
- ./a.out
+```bash
+# Compile
+clang++ -g -O3 toy.cpp
+# Run
+./a.out
+```
Here is the code:
-.. literalinclude:: ../../../examples/Kaleidoscope/Chapter2/toy.cpp
- :language: c++
+```{literalinclude} ../../../examples/Kaleidoscope/Chapter2/toy.cpp
+:language: c++
+```
-`Next: Implementing Code Generation to LLVM IR <LangImpl03.html>`_
+[Next: Implementing Code Generation to LLVM IR](LangImpl03.md)
diff --git a/llvm/docs/tutorial/MyFirstLanguageFrontend/LangImpl03.md b/llvm/docs/tutorial/MyFirstLanguageFrontend/LangImpl03.md
index a174562ffcb0e..0275a65516a45 100644
--- a/llvm/docs/tutorial/MyFirstLanguageFrontend/LangImpl03.md
+++ b/llvm/docs/tutorial/MyFirstLanguageFrontend/LangImpl03.md
@@ -1,14 +1,10 @@
-========================================
-Kaleidoscope: Code generation to LLVM IR
-========================================
+# Kaleidoscope: Code generation to LLVM IR
+## Chapter 3 Introduction
-Chapter 3 Introduction
-======================
-
-Welcome to Chapter 3 of the "`Implementing a language with
-LLVM <index.html>`_" tutorial. This chapter shows you how to transform
-the `Abstract Syntax Tree <LangImpl02.html>`_, built in Chapter 2, into
+Welcome to Chapter 3 of the "[Implementing a language with
+LLVM](index.md)" tutorial. This chapter shows you how to transform
+the [Abstract Syntax Tree](LangImpl02.md), built in Chapter 2, into
LLVM IR. This will teach you a little bit about how LLVM does things, as
well as demonstrate how easy it is to use. It's much more work to build
a lexer and parser than it is to generate LLVM IR code. :)
@@ -17,50 +13,49 @@ a lexer and parser than it is to generate LLVM IR code. :)
later. LLVM 3.6 and before will not work with it. Also note that you
need to use a version of this tutorial that matches your LLVM release:
If you are using an official LLVM release, use the version of the
-documentation included with your release or on the `llvm.org releases
-page <https://llvm.org/releases/>`_.
+documentation included with your release or on the [llvm.org releases
+page](https://llvm.org/releases/).
-Code Generation Setup
-=====================
+## Code Generation Setup
In order to generate LLVM IR, we want some simple setup to get started.
First we define virtual code generation (codegen) methods in each AST
class:
-.. code-block:: c++
-
- /// ExprAST - Base class for all expression nodes.
- class ExprAST {
- public:
- virtual ~ExprAST() = default;
- virtual Value *codegen() = 0;
- };
-
- /// NumberExprAST - Expression class for numeric literals like "1.0".
- class NumberExprAST : public ExprAST {
- double Val;
-
- public:
- NumberExprAST(double Val) : Val(Val) {}
- Value *codegen() override;
- };
- ...
+```c++
+/// ExprAST - Base class for all expression nodes.
+class ExprAST {
+public:
+ virtual ~ExprAST() = default;
+ virtual Value *codegen() = 0;
+};
+
+/// NumberExprAST - Expression class for numeric literals like "1.0".
+class NumberExprAST : public ExprAST {
+ double Val;
+
+public:
+ NumberExprAST(double Val) : Val(Val) {}
+ Value *codegen() override;
+};
+...
+```
The codegen() method says to emit IR for that AST node along with all
the things it depends on, and they all return an LLVM Value object.
-"Value" is the class used to represent a "`Static Single Assignment
-(SSA) <http://en.wikipedia.org/wiki/Static_single_assignment_form>`_
+"Value" is the class used to represent a "[Static Single Assignment
+(SSA)](http://en.wikipedia.org/wiki/Static_single_assignment_form)
register" or "SSA value" in LLVM. The most distinct aspect of SSA values
is that their value is computed as the related instruction executes, and
it does not get a new value until (and if) the instruction re-executes.
In other words, there is no way to "change" an SSA value. For more
-information, please read up on `Static Single
-Assignment <http://en.wikipedia.org/wiki/Static_single_assignment_form>`_
-- the concepts are really quite natural once you grok them.
+information, please read up on [Static Single
+Assignment](http://en.wikipedia.org/wiki/Static_single_assignment_form)
+\- the concepts are really quite natural once you grok them.
Note that instead of adding virtual methods to the ExprAST class
-hierarchy, it could also make sense to use a `visitor
-pattern <http://en.wikipedia.org/wiki/Visitor_pattern>`_ or some other
+hierarchy, it could also make sense to use a [visitor
+pattern](http://en.wikipedia.org/wiki/Visitor_pattern) or some other
way to model this. Again, this tutorial won't dwell on good software
engineering practices: for our purposes, adding a virtual method is
simplest.
@@ -69,36 +64,36 @@ The second thing we want is a "LogError" method like we used for the
parser, which will be used to report errors found during code generation
(for example, use of an undeclared parameter):
-.. code-block:: c++
+```c++
+static std::unique_ptr<LLVMContext> TheContext;
+static std::unique_ptr<IRBuilder<>> Builder;
+static std::unique_ptr<Module> TheModule;
+static std::map<std::string, Value *> NamedValues;
- static std::unique_ptr<LLVMContext> TheContext;
- static std::unique_ptr<IRBuilder<>> Builder;
- static std::unique_ptr<Module> TheModule;
- static std::map<std::string, Value *> NamedValues;
+Value *LogErrorV(const char *Str) {
+ LogError(Str);
+ return nullptr;
+}
+```
- Value *LogErrorV(const char *Str) {
- LogError(Str);
- return nullptr;
- }
-
-The static variables will be used during code generation. ``TheContext``
+The static variables will be used during code generation. `TheContext`
is an opaque object that owns a lot of core LLVM data structures, such as
the type and constant value tables. We don't need to understand it in
detail, we just need a single instance to pass into APIs that require it.
-The ``Builder`` object is a helper object that makes it easy to generate
+The `Builder` object is a helper object that makes it easy to generate
LLVM instructions. Instances of the
-`IRBuilder <https://llvm.org/doxygen/IRBuilder_8h_source.html>`_
+[IRBuilder](https://llvm.org/doxygen/IRBuilder_8h_source.html)
class template keep track of the current place to insert instructions
and has methods to create new instructions.
-``TheModule`` is an LLVM construct that contains functions and global
+`TheModule` is an LLVM construct that contains functions and global
variables. In many ways, it is the top-level structure that the LLVM IR
uses to contain code. It will own the memory for all of the IR that we
-generate, which is why the codegen() method returns a raw Value\*,
-rather than a unique_ptr<Value>.
+generate, which is why the codegen() method returns a raw `Value*`,
+rather than a `unique_ptr<Value>`.
-The ``NamedValues`` map keeps track of which values are defined in the
+The `NamedValues` map keeps track of which values are defined in the
current scope and what their LLVM representation is. (In other words, it
is a symbol table for the code). In this form of Kaleidoscope, the only
things that can be referenced are function parameters. As such, function
@@ -106,75 +101,74 @@ parameters will be in this map when generating code for their function
body.
With these basics in place, we can start talking about how to generate
-code for each expression. Note that this assumes that the ``Builder``
+code for each expression. Note that this assumes that the `Builder`
has been set up to generate code *into* something. For now, we'll assume
that this has already been done, and we'll just use it to emit code.
-Expression Code Generation
-==========================
+## Expression Code Generation
Generating LLVM code for expression nodes is very straightforward: less
than 45 lines of commented code for all four of our expression nodes.
First we'll do numeric literals:
-.. code-block:: c++
-
- Value *NumberExprAST::codegen() {
- return ConstantFP::get(*TheContext, APFloat(Val));
- }
+```c++
+Value *NumberExprAST::codegen() {
+ return ConstantFP::get(*TheContext, APFloat(Val));
+}
+```
In the LLVM IR, numeric constants are represented with the
-``ConstantFP`` class, which holds the numeric value in an ``APFloat``
-internally (``APFloat`` has the capability of holding floating point
+`ConstantFP` class, which holds the numeric value in an `APFloat`
+internally (`APFloat` has the capability of holding floating point
constants of Arbitrary Precision). This code basically just creates
-and returns a ``ConstantFP``. Note that in the LLVM IR that constants
+and returns a `ConstantFP`. Note that in the LLVM IR that constants
are all uniqued together and shared. For this reason, the API uses the
"foo::get(...)" idiom instead of "new foo(..)" or "foo::Create(..)".
-.. code-block:: c++
-
- Value *VariableExprAST::codegen() {
- // Look this variable up in the function.
- Value *V = NamedValues[Name];
- if (!V)
- LogErrorV("Unknown variable name");
- return V;
- }
+```c++
+Value *VariableExprAST::codegen() {
+ // Look this variable up in the function.
+ Value *V = NamedValues[Name];
+ if (!V)
+ LogErrorV("Unknown variable name");
+ return V;
+}
+```
References to variables are also quite simple using LLVM. In the simple
version of Kaleidoscope, we assume that the variable has already been
emitted somewhere and its value is available. In practice, the only
-values that can be in the ``NamedValues`` map are function arguments.
+values that can be in the `NamedValues` map are function arguments.
This code simply checks to see that the specified name is in the map (if
not, an unknown variable is being referenced) and returns the value for
-it. In future chapters, we'll add support for `loop induction
-variables <LangImpl05.html#for-loop-expression>`_ in the symbol table, and for `local
-variables <LangImpl07.html#user-defined-local-variables>`_.
-
-.. code-block:: c++
-
- Value *BinaryExprAST::codegen() {
- Value *L = LHS->codegen();
- Value *R = RHS->codegen();
- if (!L || !R)
- return nullptr;
-
- switch (Op) {
- case '+':
- return Builder->CreateFAdd(L, R, "addtmp");
- case '-':
- return Builder->CreateFSub(L, R, "subtmp");
- case '*':
- return Builder->CreateFMul(L, R, "multmp");
- case '<':
- L = Builder->CreateFCmpULT(L, R, "cmptmp");
- // Convert bool 0/1 to double 0.0 or 1.0
- return Builder->CreateUIToFP(L, Type::getDoubleTy(*TheContext),
- "booltmp");
- default:
- return LogErrorV("invalid binary operator");
- }
- }
+it. In future chapters, we'll add support for [loop induction
+variables](LangImpl05.md#for-loop-expression) in the symbol table, and for [local
+variables](LangImpl07.md#user-defined-local-variables).
+
+```c++
+Value *BinaryExprAST::codegen() {
+ Value *L = LHS->codegen();
+ Value *R = RHS->codegen();
+ if (!L || !R)
+ return nullptr;
+
+ switch (Op) {
+ case '+':
+ return Builder->CreateFAdd(L, R, "addtmp");
+ case '-':
+ return Builder->CreateFSub(L, R, "subtmp");
+ case '*':
+ return Builder->CreateFMul(L, R, "multmp");
+ case '<':
+ L = Builder->CreateFCmpULT(L, R, "cmptmp");
+ // Convert bool 0/1 to double 0.0 or 1.0
+ return Builder->CreateUIToFP(L, Type::getDoubleTy(*TheContext),
+ "booltmp");
+ default:
+ return LogErrorV("invalid binary operator");
+ }
+}
+```
Binary operators start to get more interesting. The basic idea here is
that we recursively emit code for the left-hand side of the expression,
@@ -185,7 +179,7 @@ the right LLVM instruction.
In the example above, the LLVM builder class is starting to show its
value. IRBuilder knows where to insert the newly created instruction,
all you have to do is specify what instruction to create (e.g. with
-``CreateFAdd``), which operands to use (``L`` and ``R`` here) and
+`CreateFAdd`), which operands to use (`L` and `R` here) and
optionally provide a name for the generated instruction.
One nice thing about LLVM is that the name is just a hint. For instance,
@@ -194,45 +188,45 @@ automatically provide each one with an increasing, unique numeric
suffix. Local value names for instructions are purely optional, but it
makes it much easier to read the IR dumps.
-`LLVM instructions <../../LangRef.html#instruction-reference>`_ are constrained by strict
-rules: for example, the Left and Right operands of an `add
-instruction <../../LangRef.html#add-instruction>`_ must have the same type, and the
+[LLVM instructions](../../LangRef.md#instruction-reference) are constrained by strict
+rules: for example, the Left and Right operands of an [add
+instruction](../../LangRef.md#add-instruction) must have the same type, and the
result type of the add must match the operand types. Because all values
in Kaleidoscope are doubles, this makes for very simple code for add,
sub and mul.
-On the other hand, LLVM specifies that the `fcmp
-instruction <../../LangRef.html#fcmp-instruction>`_ always returns an 'i1' value (a
+On the other hand, LLVM specifies that the [fcmp
+instruction](../../LangRef.md#fcmp-instruction) always returns an 'i1' value (a
one bit integer). The problem with this is that Kaleidoscope wants the
value to be a 0.0 or 1.0 value. In order to get these semantics, we
-combine the fcmp instruction with a `uitofp
-instruction <../../LangRef.html#uitofp-to-instruction>`_. This instruction converts its
+combine the fcmp instruction with a [uitofp
+instruction](../../LangRef.md#uitofp-to-instruction). This instruction converts its
input integer into a floating point value by treating the input as an
-unsigned value. In contrast, if we used the `sitofp
-instruction <../../LangRef.html#sitofp-to-instruction>`_, the Kaleidoscope '<' operator
+unsigned value. In contrast, if we used the [sitofp
+instruction](../../LangRef.md#sitofp-to-instruction), the Kaleidoscope `<` operator
would return 0.0 and -1.0, depending on the input value.
-.. code-block:: c++
-
- Value *CallExprAST::codegen() {
- // Look up the name in the global module table.
- Function *CalleeF = TheModule->getFunction(Callee);
- if (!CalleeF)
- return LogErrorV("Unknown function referenced");
-
- // If argument mismatch error.
- if (CalleeF->arg_size() != Args.size())
- return LogErrorV("Incorrect # arguments passed");
-
- std::vector<Value *> ArgsV;
- for (unsigned i = 0, e = Args.size(); i != e; ++i) {
- ArgsV.push_back(Args[i]->codegen());
- if (!ArgsV.back())
- return nullptr;
- }
+```c++
+Value *CallExprAST::codegen() {
+ // Look up the name in the global module table.
+ Function *CalleeF = TheModule->getFunction(Callee);
+ if (!CalleeF)
+ return LogErrorV("Unknown function referenced");
+
+ // If argument mismatch error.
+ if (CalleeF->arg_size() != Args.size())
+ return LogErrorV("Incorrect # arguments passed");
+
+ std::vector<Value *> ArgsV;
+ for (unsigned i = 0, e = Args.size(); i != e; ++i) {
+ ArgsV.push_back(Args[i]->codegen());
+ if (!ArgsV.back())
+ return nullptr;
+ }
- return Builder->CreateCall(CalleeF, ArgsV, "calltmp");
- }
+ return Builder->CreateCall(CalleeF, ArgsV, "calltmp");
+}
+```
Code generation for function calls is quite straightforward with LLVM. The code
above initially does a function name lookup in the LLVM Module's symbol table.
@@ -241,20 +235,19 @@ JIT'ing. By giving each function the same name as what the user specifies, we
can use the LLVM symbol table to resolve function names for us.
Once we have the function to call, we recursively codegen each argument
-that is to be passed in, and create an LLVM `call
-instruction <../../LangRef.html#call-instruction>`_. Note that LLVM uses the native C
+that is to be passed in, and create an LLVM [call
+instruction](../../LangRef.md#call-instruction). Note that LLVM uses the native C
calling conventions by default, allowing these calls to also call into
standard library functions like "sin" and "cos", with no additional
effort.
This wraps up our handling of the four basic expressions that we have so
far in Kaleidoscope. Feel free to go in and add some more. For example,
-by browsing the `LLVM language reference <../../LangRef.html>`_ you'll find
+by browsing the [LLVM language reference](../../LangRef.md) you'll find
several other interesting instructions that are really easy to plug into
our basic framework.
-Function Code Generation
-========================
+## Function Code Generation
Code generation for prototypes and functions must handle a number of
details, which make their code less beautiful than expression code
@@ -263,28 +256,28 @@ let's talk about code generation for prototypes: they are used both for
function bodies and external function declarations. The code starts
with:
-.. code-block:: c++
-
- Function *PrototypeAST::codegen() {
- // Make the function type: double(double,double) etc.
- std::vector<Type*> Doubles(Args.size(),
- Type::getDoubleTy(*TheContext));
- FunctionType *FT =
- FunctionType::get(Type::getDoubleTy(*TheContext), Doubles, false);
+```c++
+Function *PrototypeAST::codegen() {
+ // Make the function type: double(double,double) etc.
+ std::vector<Type*> Doubles(Args.size(),
+ Type::getDoubleTy(*TheContext));
+ FunctionType *FT =
+ FunctionType::get(Type::getDoubleTy(*TheContext), Doubles, false);
- Function *F =
- Function::Create(FT, Function::ExternalLinkage, Name, TheModule.get());
+ Function *F =
+ Function::Create(FT, Function::ExternalLinkage, Name, TheModule.get());
+```
This code packs a lot of power into a few lines. Note first that this
-function returns a "Function\*" instead of a "Value\*". Because a
+function returns a `Function*` instead of a `Value*`. Because a
"prototype" really talks about the external interface for a function
(not the value computed by an expression), it makes sense for it to
return the LLVM Function it corresponds to when codegen'd.
-The call to ``FunctionType::get`` creates the ``FunctionType`` that
+The call to `FunctionType::get` creates the `FunctionType` that
should be used for a given Prototype. Since all function arguments in
Kaleidoscope are of type double, the first line creates a vector of "N"
-LLVM double types. It then uses the ``Functiontype::get`` method to
+LLVM double types. It then uses the `Functiontype::get` method to
create a function type that takes "N" doubles as arguments, returns one
double as a result, and that is not vararg (the false parameter
indicates this). Note that Types in LLVM are uniqued just like Constants
@@ -292,21 +285,21 @@ are, so you don't "new" a type, you "get" it.
The final line above actually creates the IR Function corresponding to
the Prototype. This indicates the type, linkage and name to use, as
-well as which module to insert into. "`external
-linkage <../../LangRef.html#linkage>`_" means that the function may be
+well as which module to insert into. "[external
+linkage](../../LangRef.md#linkage-types)" means that the function may be
defined outside the current module and/or that it is callable by
functions outside the module. The Name passed in is the name the user
-specified: since "``TheModule``" is specified, this name is registered
-in "``TheModule``"s symbol table.
-
-.. code-block:: c++
+specified: since "`TheModule`" is specified, this name is registered
+in "`TheModule`"s symbol table.
- // Set names for all arguments.
- unsigned Idx = 0;
- for (auto &Arg : F->args())
- Arg.setName(Args[Idx++]);
+```c++
+// Set names for all arguments.
+unsigned Idx = 0;
+for (auto &Arg : F->args())
+ Arg.setName(Args[Idx++]);
- return F;
+return F;
+```
Finally, we set the name of each of the function's arguments according to the
names given in the Prototype. This step isn't strictly necessary, but keeping
@@ -319,21 +312,20 @@ represents function declarations. For extern statements in Kaleidoscope, this
is as far as we need to go. For function definitions however, we need to
codegen and attach a function body.
-.. code-block:: c++
+```c++
+Function *FunctionAST::codegen() {
+ // First, check for an existing function from a previous 'extern' declaration.
+ Function *TheFunction = TheModule->getFunction(Proto->getName());
- Function *FunctionAST::codegen() {
- // First, check for an existing function from a previous 'extern' declaration.
- Function *TheFunction = TheModule->getFunction(Proto->getName());
+ if (!TheFunction)
+ TheFunction = Proto->codegen();
- if (!TheFunction)
- TheFunction = Proto->codegen();
-
- if (!TheFunction)
- return nullptr;
-
- if (!TheFunction->empty())
- return (Function*)LogErrorV("Function cannot be redefined.");
+ if (!TheFunction)
+ return nullptr;
+ if (!TheFunction->empty())
+ return (Function*)LogErrorV("Function cannot be redefined.");
+```
For function definitions, we start by searching TheModule's symbol table for an
existing version of this function, in case one has already been created using an
@@ -341,67 +333,67 @@ existing version of this function, in case one has already been created using an
exists, so we'll codegen one from the Prototype. In either case, we want to
assert that the function is empty (i.e. has no body yet) before we start.
-.. code-block:: c++
-
- // Create a new basic block to start insertion into.
- BasicBlock *BB = BasicBlock::Create(*TheContext, "entry", TheFunction);
- Builder->SetInsertPoint(BB);
+```c++
+// Create a new basic block to start insertion into.
+BasicBlock *BB = BasicBlock::Create(*TheContext, "entry", TheFunction);
+Builder->SetInsertPoint(BB);
- // Record the function arguments in the NamedValues map.
- NamedValues.clear();
- for (auto &Arg : TheFunction->args())
- NamedValues[std::string(Arg.getName())] = &Arg;
+// Record the function arguments in the NamedValues map.
+NamedValues.clear();
+for (auto &Arg : TheFunction->args())
+ NamedValues[std::string(Arg.getName())] = &Arg;
+```
-Now we get to the point where the ``Builder`` is set up. The first line
-creates a new `basic block <http://en.wikipedia.org/wiki/Basic_block>`_
-(named "entry"), which is inserted into ``TheFunction``. The second line
+Now we get to the point where the `Builder` is set up. The first line
+creates a new [basic block](http://en.wikipedia.org/wiki/Basic_block)
+(named "entry"), which is inserted into `TheFunction`. The second line
then tells the builder that new instructions should be inserted into the
end of the new basic block. Basic blocks in LLVM are an important part
-of functions that define the `Control Flow
-Graph <http://en.wikipedia.org/wiki/Control_flow_graph>`_. Since we
+of functions that define the [Control Flow
+Graph](http://en.wikipedia.org/wiki/Control_flow_graph). Since we
don't have any control flow, our functions will only contain one block
-at this point. We'll fix this in `Chapter 5 <LangImpl05.html>`_ :).
+at this point. We'll fix this in [Chapter 5](LangImpl05.md) :).
Next we add the function arguments to the NamedValues map (after first clearing
-it out) so that they're accessible to ``VariableExprAST`` nodes.
+it out) so that they're accessible to `VariableExprAST` nodes.
-.. code-block:: c++
+```c++
+if (Value *RetVal = Body->codegen()) {
+ // Finish off the function.
+ Builder->CreateRet(RetVal);
- if (Value *RetVal = Body->codegen()) {
- // Finish off the function.
- Builder->CreateRet(RetVal);
+ // Validate the generated code, checking for consistency.
+ verifyFunction(*TheFunction);
- // Validate the generated code, checking for consistency.
- verifyFunction(*TheFunction);
-
- return TheFunction;
- }
+ return TheFunction;
+}
+```
Once the insertion point has been set up and the NamedValues map populated,
-we call the ``codegen()`` method for the root expression of the function. If no
+we call the `codegen()` method for the root expression of the function. If no
error happens, this emits code to compute the expression into the entry block
and returns the value that was computed. Assuming no error, we then create an
-LLVM `ret instruction <../../LangRef.html#ret-instruction>`_, which completes the function.
-Once the function is built, we call ``verifyFunction``, which is
+LLVM [ret instruction](../../LangRef.md#ret-instruction), which completes the function.
+Once the function is built, we call `verifyFunction`, which is
provided by LLVM. This function does a variety of consistency checks on
the generated code, to determine if our compiler is doing everything
right. Using this is important: it can catch a lot of bugs. Once the
function is finished and validated, we return it.
-.. code-block:: c++
-
- // Error reading body, remove function.
- TheFunction->eraseFromParent();
- return nullptr;
- }
+```c++
+ // Error reading body, remove function.
+ TheFunction->eraseFromParent();
+ return nullptr;
+}
+```
The only piece left here is handling of the error case. For simplicity,
we handle this by merely deleting the function we produced with the
-``eraseFromParent`` method. This allows the user to redefine a function
+`eraseFromParent` method. This allows the user to redefine a function
that they incorrectly typed in before: if we didn't delete it, it would
live in the symbol table, with a body, preventing future redefinition.
-This code does have a bug, though: If the ``FunctionAST::codegen()`` method
+This code does have a bug, though: If the `FunctionAST::codegen()` method
finds an existing IR Function, it does not validate its signature against the
definition's own prototype. This means that an earlier 'extern' declaration will
take precedence over the function definition's signature, which can cause
@@ -409,127 +401,128 @@ codegen to fail, for instance if the function arguments are named
diff erently.
There are a number of ways to fix this bug, see what you can come up with! Here
is a testcase:
-::
+```
+extern foo(a); # ok, defines foo.
+def foo(b) b; # Error: Unknown variable name. (decl using 'a' takes precedence).
+```
- extern foo(a); # ok, defines foo.
- def foo(b) b; # Error: Unknown variable name. (decl using 'a' takes precedence).
-
-Driver Changes and Closing Thoughts
-===================================
+## Driver Changes and Closing Thoughts
For now, code generation to LLVM doesn't really get us much, except that
we can look at the pretty IR calls. The sample code inserts calls to
-codegen into the "``HandleDefinition``", "``HandleExtern``" etc
+codegen into the "`HandleDefinition`", "`HandleExtern`" etc
functions, and then dumps out the LLVM IR. This gives a nice way to look
at the LLVM IR for simple functions. For example:
-::
-
- ready> 4+5;
- Read top-level expression:
- define double @__anon_expr() {
- entry:
- ret double 9.000000e+00
- }
+```
+ready> 4+5;
+Read top-level expression:
+define double @__anon_expr() {
+entry:
+ ret double 9.000000e+00
+}
+```
Note how the parser turns the top-level expression into anonymous
-functions for us. This will be handy when we add `JIT
-support <LangImpl04.html#adding-a-jit-compiler>`_ in the next chapter. Also note that the
+functions for us. This will be handy when we add [JIT
+support](LangImpl04.md#adding-a-jit-compiler) in the next chapter. Also note that the
code is very literally transcribed, no optimizations are being performed
-except simple constant folding done by IRBuilder. We will `add
-optimizations <LangImpl04.html#trivial-constant-folding>`_ explicitly in the next
+except simple constant folding done by IRBuilder. We will [add
+optimizations](LangImpl04.md#trivial-constant-folding) explicitly in the next
chapter.
-::
-
- ready> def foo(a b) a*a + 2*a*b + b*b;
- Read function definition:
- define double @foo(double %a, double %b) {
- entry:
- %multmp = fmul double %a, %a
- %multmp1 = fmul double 2.000000e+00, %a
- %multmp2 = fmul double %multmp1, %b
- %addtmp = fadd double %multmp, %multmp2
- %multmp3 = fmul double %b, %b
- %addtmp4 = fadd double %addtmp, %multmp3
- ret double %addtmp4
- }
+```
+ready> def foo(a b) a*a + 2*a*b + b*b;
+Read function definition:
+define double @foo(double %a, double %b) {
+entry:
+ %multmp = fmul double %a, %a
+ %multmp1 = fmul double 2.000000e+00, %a
+ %multmp2 = fmul double %multmp1, %b
+ %addtmp = fadd double %multmp, %multmp2
+ %multmp3 = fmul double %b, %b
+ %addtmp4 = fadd double %addtmp, %multmp3
+ ret double %addtmp4
+}
+```
This shows some simple arithmetic. Notice the striking similarity to the
LLVM builder calls that we use to create the instructions.
-::
-
- ready> def bar(a) foo(a, 4.0) + bar(31337);
- Read function definition:
- define double @bar(double %a) {
- entry:
- %calltmp = call double @foo(double %a, double 4.000000e+00)
- %calltmp1 = call double @bar(double 3.133700e+04)
- %addtmp = fadd double %calltmp, %calltmp1
- ret double %addtmp
- }
+```
+ready> def bar(a) foo(a, 4.0) + bar(31337);
+Read function definition:
+define double @bar(double %a) {
+entry:
+ %calltmp = call double @foo(double %a, double 4.000000e+00)
+ %calltmp1 = call double @bar(double 3.133700e+04)
+ %addtmp = fadd double %calltmp, %calltmp1
+ ret double %addtmp
+}
+```
This shows some function calls. Note that this function will take a long
time to execute if you call it. In the future we'll add conditional
control flow to actually make recursion useful :).
-::
+```
+ready> extern cos(x);
+Read extern:
+declare double @cos(double)
- ready> extern cos(x);
- Read extern:
- declare double @cos(double)
-
- ready> cos(1.234);
- Read top-level expression:
- define double @__anon_expr() {
- entry:
- %calltmp = call double @cos(double 1.234000e+00)
- ret double %calltmp
- }
+ready> cos(1.234);
+Read top-level expression:
+define double @__anon_expr() {
+entry:
+ %calltmp = call double @cos(double 1.234000e+00)
+ ret double %calltmp
+}
+```
This shows an extern for the libm "cos" function, and a call to it.
-.. TODO:: Abandon Pygments' horrible `llvm` lexer. It just totally gives up
- on highlighting this due to the first line.
-
-::
-
- ready> ^D
- ; ModuleID = 'my cool jit'
-
- define double @0() {
- entry:
- %addtmp = fadd double 4.000000e+00, 5.000000e+00
- ret double %addtmp
- }
-
- define double @foo(double %a, double %b) {
- entry:
- %multmp = fmul double %a, %a
- %multmp1 = fmul double 2.000000e+00, %a
- %multmp2 = fmul double %multmp1, %b
- %addtmp = fadd double %multmp, %multmp2
- %multmp3 = fmul double %b, %b
- %addtmp4 = fadd double %addtmp, %multmp3
- ret double %addtmp4
- }
-
- define double @bar(double %a) {
- entry:
- %calltmp = call double @foo(double %a, double 4.000000e+00)
- %calltmp1 = call double @bar(double 3.133700e+04)
- %addtmp = fadd double %calltmp, %calltmp1
- ret double %addtmp
- }
-
- declare double @cos(double)
-
- define double @1() {
- entry:
- %calltmp = call double @cos(double 1.234000e+00)
- ret double %calltmp
- }
+:::{todo}
+Abandon Pygments' horrible `llvm` lexer. It just totally gives up
+on highlighting this due to the first line.
+:::
+
+```
+ready> ^D
+; ModuleID = 'my cool jit'
+
+define double @0() {
+entry:
+ %addtmp = fadd double 4.000000e+00, 5.000000e+00
+ ret double %addtmp
+}
+
+define double @foo(double %a, double %b) {
+entry:
+ %multmp = fmul double %a, %a
+ %multmp1 = fmul double 2.000000e+00, %a
+ %multmp2 = fmul double %multmp1, %b
+ %addtmp = fadd double %multmp, %multmp2
+ %multmp3 = fmul double %b, %b
+ %addtmp4 = fadd double %addtmp, %multmp3
+ ret double %addtmp4
+}
+
+define double @bar(double %a) {
+entry:
+ %calltmp = call double @foo(double %a, double 4.000000e+00)
+ %calltmp1 = call double @bar(double 3.133700e+04)
+ %addtmp = fadd double %calltmp, %calltmp1
+ ret double %addtmp
+}
+
+declare double @cos(double)
+
+define double @1() {
+entry:
+ %calltmp = call double @cos(double 1.234000e+00)
+ ret double %calltmp
+}
+```
When you quit the current demo (by sending an EOF via CTRL+D on Linux
or CTRL+Z and ENTER on Windows), it dumps out the IR for the entire
@@ -537,30 +530,29 @@ module generated. Here you can see the big picture with all the
functions referencing each other.
This wraps up the third chapter of the Kaleidoscope tutorial. Up next,
-we'll describe how to `add JIT codegen and optimizer
-support <LangImpl04.html>`_ to this so we can actually start running
+we'll describe how to [add JIT codegen and optimizer
+support](LangImpl04.md) to this so we can actually start running
code!
-Full Code Listing
-=================
+## Full Code Listing
Here is the complete code listing for our running example, enhanced with
the LLVM code generator. Because this uses the LLVM libraries, we need
to link them in. To do this, we use the
-`llvm-config <https://llvm.org/cmds/llvm-config.html>`_ tool to inform
+[llvm-config](https://llvm.org/cmds/llvm-config.html) tool to inform
our makefile/command line about which options to use:
-.. code-block:: bash
-
- # Compile
- clang++ -g -O3 toy.cpp `llvm-config --cxxflags --ldflags --system-libs --libs core` -o toy
- # Run
- ./toy
+```bash
+# Compile
+clang++ -g -O3 toy.cpp `llvm-config --cxxflags --ldflags --system-libs --libs core` -o toy
+# Run
+./toy
+```
Here is the code:
-.. literalinclude:: ../../../examples/Kaleidoscope/Chapter3/toy.cpp
- :language: c++
-
-`Next: Adding JIT and Optimizer Support <LangImpl04.html>`_
+```{literalinclude} ../../../examples/Kaleidoscope/Chapter3/toy.cpp
+:language: c++
+```
+[Next: Adding JIT and Optimizer Support](LangImpl04.md)
diff --git a/llvm/docs/tutorial/MyFirstLanguageFrontend/LangImpl04.md b/llvm/docs/tutorial/MyFirstLanguageFrontend/LangImpl04.md
index 9c54ccd4cb319..1a833244f9c1a 100644
--- a/llvm/docs/tutorial/MyFirstLanguageFrontend/LangImpl04.md
+++ b/llvm/docs/tutorial/MyFirstLanguageFrontend/LangImpl04.md
@@ -1,49 +1,44 @@
-==============================================
-Kaleidoscope: Adding JIT and Optimizer Support
-==============================================
+# Kaleidoscope: Adding JIT and Optimizer Support
+## Chapter 4 Introduction
-Chapter 4 Introduction
-======================
-
-Welcome to Chapter 4 of the "`Implementing a language with
-LLVM <index.html>`_" tutorial. Chapters 1-3 described the implementation
+Welcome to Chapter 4 of the "[Implementing a language with
+LLVM](index.md)" tutorial. Chapters 1-3 described the implementation
of a simple language and added support for generating LLVM IR. This
chapter describes two new techniques: adding optimizer support to your
language, and adding JIT compiler support. These additions will
demonstrate how to get nice, efficient code for the Kaleidoscope
language.
-Trivial Constant Folding
-========================
+## Trivial Constant Folding
Our demonstration for Chapter 3 is elegant and easy to extend.
Unfortunately, it does not produce wonderful code. The IRBuilder,
however, does give us obvious optimizations when compiling simple code:
-::
-
- ready> def test(x) 1+2+x;
- Read function definition:
- define double @test(double %x) {
- entry:
- %addtmp = fadd double 3.000000e+00, %x
- ret double %addtmp
- }
+```
+ready> def test(x) 1+2+x;
+Read function definition:
+define double @test(double %x) {
+entry:
+ %addtmp = fadd double 3.000000e+00, %x
+ ret double %addtmp
+}
+```
This code is not a literal transcription of the AST built by parsing the
input. That would be:
-::
-
- ready> def test(x) 1+2+x;
- Read function definition:
- define double @test(double %x) {
- entry:
- %addtmp = fadd double 2.000000e+00, 1.000000e+00
- %addtmp1 = fadd double %addtmp, %x
- ret double %addtmp1
- }
+```
+ready> def test(x) 1+2+x;
+Read function definition:
+define double @test(double %x) {
+entry:
+ %addtmp = fadd double 2.000000e+00, 1.000000e+00
+ %addtmp1 = fadd double %addtmp, %x
+ ret double %addtmp1
+}
+```
Constant folding, as seen above, in particular, is a very common and
very important optimization: so much so that many language implementors
@@ -56,31 +51,31 @@ so, it just does the constant fold and return the constant instead of
creating an instruction.
Well, that was easy :). In practice, we recommend always using
-``IRBuilder`` when generating code like this. It has no "syntactic
+`IRBuilder` when generating code like this. It has no "syntactic
overhead" for its use (you don't have to uglify your compiler with
constant checks everywhere) and it can dramatically reduce the amount of
LLVM IR that is generated in some cases (particular for languages with a
macro preprocessor or that use a lot of constants).
-On the other hand, the ``IRBuilder`` is limited by the fact that it does
+On the other hand, the `IRBuilder` is limited by the fact that it does
all of its analysis inline with the code as it is built. If you take a
slightly more complex example:
-::
-
- ready> def test(x) (1+2+x)*(x+(1+2));
- ready> Read function definition:
- define double @test(double %x) {
- entry:
- %addtmp = fadd double 3.000000e+00, %x
- %addtmp1 = fadd double %x, 3.000000e+00
- %multmp = fmul double %addtmp, %addtmp1
- ret double %multmp
- }
+```
+ready> def test(x) (1+2+x)*(x+(1+2));
+ready> Read function definition:
+define double @test(double %x) {
+entry:
+ %addtmp = fadd double 3.000000e+00, %x
+ %addtmp1 = fadd double %x, 3.000000e+00
+ %multmp = fmul double %addtmp, %addtmp1
+ ret double %multmp
+}
+```
In this case, the LHS and RHS of the multiplication are the same value.
-We'd really like to see this generate "``tmp = x+3; result = tmp*tmp;``"
-instead of computing "``x+3``" twice.
+We'd really like to see this generate "`tmp = x+3; result = tmp*tmp;`"
+instead of computing "`x+3`" twice.
Unfortunately, no amount of local analysis will be able to detect and
correct this. This requires two transformations: reassociation of
@@ -89,8 +84,7 @@ Subexpression Elimination (CSE) to delete the redundant add instruction.
Fortunately, LLVM provides a broad range of optimizations that you can
use, in the form of "passes".
-LLVM Optimization Passes
-========================
+## LLVM Optimization Passes
LLVM provides many optimization passes, which do many
diff erent sorts of
things and have
diff erent tradeoffs. Unlike other systems, LLVM doesn't
@@ -105,8 +99,8 @@ but if run at link time, this can be a substantial portion of the whole
program). It also supports and includes "per-function" passes which just
operate on a single function at a time, without looking at other
functions. For more information on passes and how they are run, see the
-`How to Write a Pass <../../WritingAnLLVMPass.html>`_ document and the
-`List of LLVM Passes <../../Passes.html>`_.
+[How to Write a Pass](../../WritingAnLLVMPass.md) document and the
+[List of LLVM Passes](../../Passes.md).
For Kaleidoscope, we are currently generating functions on the fly, one
at a time, as the user types them in. We aren't shooting for the
@@ -124,39 +118,39 @@ a transform pass, all analysis passes it depends upon must be registered in
advance.
In order to get per-function optimizations going, we need to set up a
-`FunctionPassManager <../../WritingAnLLVMPass.html#what-passmanager-doesr>`_ to hold
+[FunctionPassManager](../../WritingAnLLVMPass.md#what-passmanager-does) to hold
and organize the LLVM optimizations that we want to run. Once we have
that, we can add a set of optimizations to run. We'll need a new
FunctionPassManager for each module that we want to optimize, so we'll
-add to a function created in the previous chapter (``InitializeModule()``):
-
-.. code-block:: c++
-
- void InitializeModuleAndManagers(void) {
- // Open a new context and module.
- TheContext = std::make_unique<LLVMContext>();
- TheModule = std::make_unique<Module>("KaleidoscopeJIT", *TheContext);
- TheModule->setDataLayout(TheJIT->getDataLayout());
-
- // Create a new builder for the module.
- Builder = std::make_unique<IRBuilder<>>(*TheContext);
-
- // Create new pass and analysis managers.
- TheFPM = std::make_unique<FunctionPassManager>();
- TheLAM = std::make_unique<LoopAnalysisManager>();
- TheFAM = std::make_unique<FunctionAnalysisManager>();
- TheCGAM = std::make_unique<CGSCCAnalysisManager>();
- TheMAM = std::make_unique<ModuleAnalysisManager>();
- ThePIC = std::make_unique<PassInstrumentationCallbacks>();
- TheSI = std::make_unique<StandardInstrumentations>(*TheContext,
- /*DebugLogging*/ true);
- TheSI->registerCallbacks(*ThePIC, TheMAM.get());
- ...
-
-Besides the initialization we have a `TheModule->setDataLayout(TheJIT->getDataLayout());`
+add to a function created in the previous chapter (`InitializeModule()`):
+
+```c++
+void InitializeModuleAndManagers(void) {
+ // Open a new context and module.
+ TheContext = std::make_unique<LLVMContext>();
+ TheModule = std::make_unique<Module>("KaleidoscopeJIT", *TheContext);
+ TheModule->setDataLayout(TheJIT->getDataLayout());
+
+ // Create a new builder for the module.
+ Builder = std::make_unique<IRBuilder<>>(*TheContext);
+
+ // Create new pass and analysis managers.
+ TheFPM = std::make_unique<FunctionPassManager>();
+ TheLAM = std::make_unique<LoopAnalysisManager>();
+ TheFAM = std::make_unique<FunctionAnalysisManager>();
+ TheCGAM = std::make_unique<CGSCCAnalysisManager>();
+ TheMAM = std::make_unique<ModuleAnalysisManager>();
+ ThePIC = std::make_unique<PassInstrumentationCallbacks>();
+ TheSI = std::make_unique<StandardInstrumentations>(*TheContext,
+ /*DebugLogging*/ true);
+ TheSI->registerCallbacks(*ThePIC, TheMAM.get());
+ ...
+```
+
+Besides the initialization we have a `TheModule->setDataLayout(TheJIT->getDataLayout());`
in the code. We will discuss about it later in this chapter.
-After initializing the global module ``TheModule`` and the FunctionPassManager,
+After initializing the global module `TheModule` and the FunctionPassManager,
we need to initialize other parts of the framework. The four AnalysisManagers
allow us to add analysis passes that run across the four levels of the IR
hierarchy. PassInstrumentationCallbacks and StandardInstrumentations are
@@ -166,17 +160,17 @@ customize what happens between passes.
Once these managers are set up, we use a series of "addPass" calls to add a
bunch of LLVM transform passes:
-.. code-block:: c++
-
- // Add transform passes.
- // Do simple "peephole" optimizations and bit-twiddling optzns.
- TheFPM->addPass(InstCombinePass());
- // Reassociate expressions.
- TheFPM->addPass(ReassociatePass());
- // Eliminate Common SubExpressions.
- TheFPM->addPass(GVNPass());
- // Simplify the control flow graph (deleting unreachable blocks, etc).
- TheFPM->addPass(SimplifyCFGPass());
+```c++
+// Add transform passes.
+// Do simple "peephole" optimizations and bit-twiddling optzns.
+TheFPM->addPass(InstCombinePass());
+// Reassociate expressions.
+TheFPM->addPass(ReassociatePass());
+// Eliminate Common SubExpressions.
+TheFPM->addPass(GVNPass());
+// Simplify the control flow graph (deleting unreachable blocks, etc).
+TheFPM->addPass(SimplifyCFGPass());
+```
In this case, we choose to add four optimization passes.
The passes we choose here are a pretty standard set
@@ -185,66 +179,65 @@ delve into what they do but, believe me, they are a good starting place :).
Next, we register the analysis passes used by the transform passes.
-.. code-block:: c++
-
- // Register analysis passes used in these transform passes.
- PassBuilder PB;
- PB.registerModuleAnalyses(*TheMAM);
- PB.registerFunctionAnalyses(*TheFAM);
- PB.crossRegisterProxies(*TheLAM, *TheFAM, *TheCGAM, *TheMAM);
- }
+```c++
+ // Register analysis passes used in these transform passes.
+ PassBuilder PB;
+ PB.registerModuleAnalyses(*TheMAM);
+ PB.registerFunctionAnalyses(*TheFAM);
+ PB.crossRegisterProxies(*TheLAM, *TheFAM, *TheCGAM, *TheMAM);
+}
+```
Once the PassManager is set up, we need to make use of it. We do this by
running it after our newly created function is constructed (in
-``FunctionAST::codegen()``), but before it is returned to the client:
+`FunctionAST::codegen()`), but before it is returned to the client:
-.. code-block:: c++
+```c++
+if (Value *RetVal = Body->codegen()) {
+ // Finish off the function.
+ Builder.CreateRet(RetVal);
- if (Value *RetVal = Body->codegen()) {
- // Finish off the function.
- Builder.CreateRet(RetVal);
+ // Validate the generated code, checking for consistency.
+ verifyFunction(*TheFunction);
- // Validate the generated code, checking for consistency.
- verifyFunction(*TheFunction);
+ // Optimize the function.
+ TheFPM->run(*TheFunction, *TheFAM);
- // Optimize the function.
- TheFPM->run(*TheFunction, *TheFAM);
-
- return TheFunction;
- }
+ return TheFunction;
+}
+```
As you can see, this is pretty straightforward. The
-``FunctionPassManager`` optimizes and updates the LLVM Function\* in
+`FunctionPassManager` optimizes and updates the LLVM `Function*` in
place, improving (hopefully) its body. With this in place, we can try
our test above again:
-::
-
- ready> def test(x) (1+2+x)*(x+(1+2));
- ready> Read function definition:
- define double @test(double %x) {
- entry:
- %addtmp = fadd double %x, 3.000000e+00
- %multmp = fmul double %addtmp, %addtmp
- ret double %multmp
- }
+```
+ready> def test(x) (1+2+x)*(x+(1+2));
+ready> Read function definition:
+define double @test(double %x) {
+entry:
+ %addtmp = fadd double %x, 3.000000e+00
+ %multmp = fmul double %addtmp, %addtmp
+ ret double %multmp
+}
+```
As expected, we now get our nicely optimized code, saving a floating
point add instruction from every execution of this function.
LLVM provides a wide variety of optimizations that can be used in
-certain circumstances. Some `documentation about the various
-passes <../../Passes.html>`_ is available, but it isn't very complete.
+certain circumstances. Some [documentation about the various
+passes](../../Passes.md) is available, but it isn't very complete.
Another good source of ideas can come from looking at the passes that
-``Clang`` runs to get started. The "``opt``" tool allows you to
+`Clang` runs to get started. The "`opt`" tool allows you to
experiment with passes from the command line, so you can see if they do
anything.
Now that we have reasonable code coming out of our front-end, let's talk
about executing it!
-Adding a JIT Compiler
-=====================
+## Adding a JIT Compiler
Code that is available in LLVM IR can have a wide variety of tools
applied to it. For example, you can run optimizations on it (as we did
@@ -262,165 +255,163 @@ be able to call it from the command line.
In order to do this, we first prepare the environment to create code for
the current native target and declare and initialize the JIT. This is
-done by calling some ``InitializeNativeTarget*`` functions and
-adding a global variable ``TheJIT``, and initializing it in
-``main``:
-
-.. code-block:: c++
-
- static std::unique_ptr<KaleidoscopeJIT> TheJIT;
- ...
- int main() {
- InitializeNativeTarget();
- InitializeNativeTargetAsmPrinter();
- InitializeNativeTargetAsmParser();
-
- // Install standard binary operators.
- // 1 is lowest precedence.
- BinopPrecedence['<'] = 10;
- BinopPrecedence['+'] = 20;
- BinopPrecedence['-'] = 20;
- BinopPrecedence['*'] = 40; // highest.
-
- // Prime the first token.
- fprintf(stderr, "ready> ");
- getNextToken();
-
- TheJIT = std::make_unique<KaleidoscopeJIT>();
-
- // Run the main "interpreter loop" now.
- MainLoop();
-
- return 0;
- }
-
-We also need to set up the data layout for the JIT. Now that ``TheJIT`` exists,
-we can add a ``setDataLayout`` call to ``InitializeModuleAndManagers``:
-
-.. code-block:: c++
-
- void InitializeModuleAndManagers(void) {
- // Open a new context and module.
- TheContext = std::make_unique<LLVMContext>();
- TheModule = std::make_unique<Module>("KaleidoscopeJIT", *TheContext);
- TheModule->setDataLayout(TheJIT->getDataLayout());
- ...
+done by calling some `InitializeNativeTarget*` functions and
+adding a global variable `TheJIT`, and initializing it in
+`main`:
+
+```c++
+static std::unique_ptr<KaleidoscopeJIT> TheJIT;
+...
+int main() {
+ InitializeNativeTarget();
+ InitializeNativeTargetAsmPrinter();
+ InitializeNativeTargetAsmParser();
+
+ // Install standard binary operators.
+ // 1 is lowest precedence.
+ BinopPrecedence['<'] = 10;
+ BinopPrecedence['+'] = 20;
+ BinopPrecedence['-'] = 20;
+ BinopPrecedence['*'] = 40; // highest.
+
+ // Prime the first token.
+ fprintf(stderr, "ready> ");
+ getNextToken();
+
+ TheJIT = std::make_unique<KaleidoscopeJIT>();
+
+ // Run the main "interpreter loop" now.
+ MainLoop();
+
+ return 0;
+}
+```
+
+We also need to set up the data layout for the JIT. Now that `TheJIT` exists,
+we can add a `setDataLayout` call to `InitializeModuleAndManagers`:
+
+```c++
+void InitializeModuleAndManagers(void) {
+ // Open a new context and module.
+ TheContext = std::make_unique<LLVMContext>();
+ TheModule = std::make_unique<Module>("KaleidoscopeJIT", *TheContext);
+ TheModule->setDataLayout(TheJIT->getDataLayout());
+ ...
+```
The KaleidoscopeJIT class is a simple JIT built specifically for these
tutorials, available inside the LLVM source code
-at `llvm-src/examples/Kaleidoscope/include/KaleidoscopeJIT.h
-<https://github.com/llvm/llvm-project/blob/main/llvm/examples/Kaleidoscope/include/KaleidoscopeJIT.h>`_.
+at [llvm-src/examples/Kaleidoscope/include/KaleidoscopeJIT.h](https://github.com/llvm/llvm-project/blob/main/llvm/examples/Kaleidoscope/include/KaleidoscopeJIT.h).
In later chapters we will look at how it works and extend it with
new features, but for now we will take it as given. Its API is very simple:
-``addModule`` adds an LLVM IR module to the JIT, making its functions
-available for execution (with its memory managed by a ``ResourceTracker``); and
-``lookup`` allows us to look up pointers to the compiled code.
+`addModule` adds an LLVM IR module to the JIT, making its functions
+available for execution (with its memory managed by a `ResourceTracker`); and
+`lookup` allows us to look up pointers to the compiled code.
We can take this simple API and change our code that parses top-level expressions to
look like this:
-.. code-block:: c++
-
- static ExitOnError ExitOnErr;
- ...
- static void HandleTopLevelExpression() {
- // Evaluate a top-level expression into an anonymous function.
- if (auto FnAST = ParseTopLevelExpr()) {
- if (FnAST->codegen()) {
- // Create a ResourceTracker to track JIT'd memory allocated to our
- // anonymous expression -- that way we can free it after executing.
- auto RT = TheJIT->getMainJITDylib().createResourceTracker();
-
- auto TSM = ThreadSafeModule(std::move(TheModule), std::move(TheContext));
- ExitOnErr(TheJIT->addModule(std::move(TSM), RT));
- InitializeModuleAndManagers();
-
- // Search the JIT for the __anon_expr symbol.
- auto ExprSymbol = ExitOnErr(TheJIT->lookup("__anon_expr"));
-
- // Get the symbol's address and cast it to the right type (takes no
- // arguments, returns a double) so we can call it as a native function.
- double (*FP)() = ExprSymbol.toPtr<double (*)()>();
- fprintf(stderr, "Evaluated to %f\n", FP());
-
- // Delete the anonymous expression module from the JIT.
- ExitOnErr(RT->remove());
- }
+```c++
+static ExitOnError ExitOnErr;
+...
+static void HandleTopLevelExpression() {
+ // Evaluate a top-level expression into an anonymous function.
+ if (auto FnAST = ParseTopLevelExpr()) {
+ if (FnAST->codegen()) {
+ // Create a ResourceTracker to track JIT'd memory allocated to our
+ // anonymous expression -- that way we can free it after executing.
+ auto RT = TheJIT->getMainJITDylib().createResourceTracker();
+
+ auto TSM = ThreadSafeModule(std::move(TheModule), std::move(TheContext));
+ ExitOnErr(TheJIT->addModule(std::move(TSM), RT));
+ InitializeModuleAndManagers();
+
+ // Search the JIT for the __anon_expr symbol.
+ auto ExprSymbol = ExitOnErr(TheJIT->lookup("__anon_expr"));
+
+ // Get the symbol's address and cast it to the right type (takes no
+ // arguments, returns a double) so we can call it as a native function.
+ double (*FP)() = ExprSymbol.toPtr<double (*)()>();
+ fprintf(stderr, "Evaluated to %f\n", FP());
+
+ // Delete the anonymous expression module from the JIT.
+ ExitOnErr(RT->remove());
+ }
+```
If parsing and codegen succeed, the next step is to add the module containing
the top-level expression to the JIT. We do this by calling addModule, which
triggers code generation for all the functions in the module, and accepts a
-``ResourceTracker`` which can be used to remove the module from the JIT later. Once
+`ResourceTracker` which can be used to remove the module from the JIT later. Once
the module has been added to the JIT it can no longer be modified, so we also open a
-new module to hold subsequent code by calling ``InitializeModuleAndManagers()``.
+new module to hold subsequent code by calling `InitializeModuleAndManagers()`.
Once we've added the module to the JIT we need to get a pointer to the final
-generated code. We do this by calling the JIT's ``lookup`` method, and passing
-the name of the top-level expression function: ``__anon_expr``.
+generated code. We do this by calling the JIT's `lookup` method, and passing
+the name of the top-level expression function: `__anon_expr`.
-Next, we get the in-memory address of the ``__anon_expr`` function. Recall
-that we compile top-level expressions into a self-contained LLVM function that
+Next, we get the in-memory address of the `__anon_expr` function. Recall
+that we compile top-level expressions into a self-contained LLVM function that
takes no arguments and returns the computed double. Because the LLVM JIT compiler
matches the native platform ABI, this means that you can just cast the result pointer
-to a function pointer of that type and call it directly. This means, there is no
-
diff erence between JIT compiled code and native machine code that is statically
+to a function pointer of that type and call it directly. This means, there is no
+
diff erence between JIT compiled code and native machine code that is statically
linked into your application.
Finally, since we don't support re-evaluation of top-level expressions, we
remove the module from the JIT when we're done to free the associated memory.
Recall, however, that the module we created a few lines earlier (via
-``InitializeModuleAndManagers``) is still open and waiting for new code to be
+`InitializeModuleAndManagers`) is still open and waiting for new code to be
added.
With just these two changes, let's see how Kaleidoscope works now!
-::
-
- ready> 4+5;
- Read top-level expression:
- define double @0() {
- entry:
- ret double 9.000000e+00
- }
+```
+ready> 4+5;
+Read top-level expression:
+define double @0() {
+entry:
+ ret double 9.000000e+00
+}
- Evaluated to 9.000000
+Evaluated to 9.000000
+```
Well this looks like it is basically working. The dump of the function
shows the "no argument function that always returns double" that we
synthesize for each top-level expression that is typed in. This
demonstrates very basic functionality, but can we do more?
-::
-
- ready> def testfunc(x y) x + y*2;
- Read function definition:
- define double @testfunc(double %x, double %y) {
- entry:
- %multmp = fmul double %y, 2.000000e+00
- %addtmp = fadd double %multmp, %x
- ret double %addtmp
- }
-
- ready> testfunc(4, 10);
- Read top-level expression:
- define double @1() {
- entry:
- %calltmp = call double @testfunc(double 4.000000e+00, double 1.000000e+01)
- ret double %calltmp
- }
-
- Evaluated to 24.000000
-
- ready> testfunc(5, 10);
- ready> LLVM ERROR: Program used external function 'testfunc' which could not be resolved!
-
+```
+ready> def testfunc(x y) x + y*2;
+Read function definition:
+define double @testfunc(double %x, double %y) {
+entry:
+ %multmp = fmul double %y, 2.000000e+00
+ %addtmp = fadd double %multmp, %x
+ ret double %addtmp
+}
+
+ready> testfunc(4, 10);
+Read top-level expression:
+define double @1() {
+entry:
+ %calltmp = call double @testfunc(double 4.000000e+00, double 1.000000e+01)
+ ret double %calltmp
+}
+
+Evaluated to 24.000000
+
+ready> testfunc(5, 10);
+ready> LLVM ERROR: Program used external function 'testfunc' which could not be resolved!
+```
Function definitions and calls also work, but something went very wrong on that
last line. The call looks valid, so what happened? As you may have guessed from
the API a Module is a unit of allocation for the JIT, and testfunc was part
of the same module that contained anonymous expression. When we removed that
module from the JIT to free the memory for the anonymous expression, we deleted
-the definition of ``testfunc`` along with it. Then, when we tried to call
+the definition of `testfunc` along with it. Then, when we tried to call
testfunc a second time, the JIT could no longer find it.
The easiest way to fix this is to put the anonymous expression in a separate
@@ -437,197 +428,196 @@ JIT more than once (unlike a module where every function must have a unique
definition). When you look up a symbol in KaleidoscopeJIT it will always return
the most recent definition:
-::
-
- ready> def foo(x) x + 1;
- Read function definition:
- define double @foo(double %x) {
- entry:
- %addtmp = fadd double %x, 1.000000e+00
- ret double %addtmp
- }
-
- ready> foo(2);
- Evaluated to 3.000000
-
- ready> def foo(x) x + 2;
- define double @foo(double %x) {
- entry:
- %addtmp = fadd double %x, 2.000000e+00
- ret double %addtmp
- }
-
- ready> foo(2);
- Evaluated to 4.000000
-
+```
+ready> def foo(x) x + 1;
+Read function definition:
+define double @foo(double %x) {
+entry:
+ %addtmp = fadd double %x, 1.000000e+00
+ ret double %addtmp
+}
+
+ready> foo(2);
+Evaluated to 3.000000
+
+ready> def foo(x) x + 2;
+define double @foo(double %x) {
+entry:
+ %addtmp = fadd double %x, 2.000000e+00
+ ret double %addtmp
+}
+
+ready> foo(2);
+Evaluated to 4.000000
+```
To allow each function to live in its own module we'll need a way to
re-generate previous function declarations into each new module we open:
-.. code-block:: c++
-
- static std::unique_ptr<KaleidoscopeJIT> TheJIT;
-
- ...
+```c++
+static std::unique_ptr<KaleidoscopeJIT> TheJIT;
- Function *getFunction(std::string Name) {
- // First, see if the function has already been added to the current module.
- if (auto *F = TheModule->getFunction(Name))
- return F;
+...
- // If not, check whether we can codegen the declaration from some existing
- // prototype.
- auto FI = FunctionProtos.find(Name);
- if (FI != FunctionProtos.end())
- return FI->second->codegen();
+Function *getFunction(std::string Name) {
+ // First, see if the function has already been added to the current module.
+ if (auto *F = TheModule->getFunction(Name))
+ return F;
- // If no existing prototype exists, return null.
- return nullptr;
- }
+ // If not, check whether we can codegen the declaration from some existing
+ // prototype.
+ auto FI = FunctionProtos.find(Name);
+ if (FI != FunctionProtos.end())
+ return FI->second->codegen();
- ...
+ // If no existing prototype exists, return null.
+ return nullptr;
+}
- Value *CallExprAST::codegen() {
- // Look up the name in the global module table.
- Function *CalleeF = getFunction(Callee);
+...
- ...
+Value *CallExprAST::codegen() {
+ // Look up the name in the global module table.
+ Function *CalleeF = getFunction(Callee);
- Function *FunctionAST::codegen() {
- // Transfer ownership of the prototype to the FunctionProtos map, but keep a
- // reference to it for use below.
- auto &P = *Proto;
- FunctionProtos[Proto->getName()] = std::move(Proto);
- Function *TheFunction = getFunction(P.getName());
- if (!TheFunction)
- return nullptr;
+...
+Function *FunctionAST::codegen() {
+ // Transfer ownership of the prototype to the FunctionProtos map, but keep a
+ // reference to it for use below.
+ auto &P = *Proto;
+ FunctionProtos[Proto->getName()] = std::move(Proto);
+ Function *TheFunction = getFunction(P.getName());
+ if (!TheFunction)
+ return nullptr;
+```
-To enable this, we'll start by adding a new global, ``FunctionProtos``, that
+To enable this, we'll start by adding a new global, `FunctionProtos`, that
holds the most recent prototype for each function. We'll also add a convenience
-method, ``getFunction()``, to replace calls to ``TheModule->getFunction()``.
-Our convenience method searches ``TheModule`` for an existing function
+method, `getFunction()`, to replace calls to `TheModule->getFunction()`.
+Our convenience method searches `TheModule` for an existing function
declaration, falling back to generating a new declaration from FunctionProtos if
-it doesn't find one. In ``CallExprAST::codegen()`` we just need to replace the
-call to ``TheModule->getFunction()``. In ``FunctionAST::codegen()`` we need to
-update the FunctionProtos map first, then call ``getFunction()``. With this
+it doesn't find one. In `CallExprAST::codegen()` we just need to replace the
+call to `TheModule->getFunction()`. In `FunctionAST::codegen()` we need to
+update the FunctionProtos map first, then call `getFunction()`. With this
done, we can always obtain a function declaration in the current module for any
previously declared function.
We also need to update HandleDefinition and HandleExtern:
-.. code-block:: c++
-
- static void HandleDefinition() {
- if (auto FnAST = ParseDefinition()) {
- if (auto *FnIR = FnAST->codegen()) {
- fprintf(stderr, "Read function definition:");
- FnIR->print(errs());
- fprintf(stderr, "\n");
- ExitOnErr(TheJIT->addModule(
- ThreadSafeModule(std::move(TheModule), std::move(TheContext))));
- InitializeModuleAndManagers();
- }
- } else {
- // Skip token for error recovery.
- getNextToken();
- }
+```c++
+static void HandleDefinition() {
+ if (auto FnAST = ParseDefinition()) {
+ if (auto *FnIR = FnAST->codegen()) {
+ fprintf(stderr, "Read function definition:");
+ FnIR->print(errs());
+ fprintf(stderr, "\n");
+ ExitOnErr(TheJIT->addModule(
+ ThreadSafeModule(std::move(TheModule), std::move(TheContext))));
+ InitializeModuleAndManagers();
}
-
- static void HandleExtern() {
- if (auto ProtoAST = ParseExtern()) {
- if (auto *FnIR = ProtoAST->codegen()) {
- fprintf(stderr, "Read extern: ");
- FnIR->print(errs());
- fprintf(stderr, "\n");
- FunctionProtos[ProtoAST->getName()] = std::move(ProtoAST);
- }
- } else {
- // Skip token for error recovery.
- getNextToken();
- }
+ } else {
+ // Skip token for error recovery.
+ getNextToken();
+ }
+}
+
+static void HandleExtern() {
+ if (auto ProtoAST = ParseExtern()) {
+ if (auto *FnIR = ProtoAST->codegen()) {
+ fprintf(stderr, "Read extern: ");
+ FnIR->print(errs());
+ fprintf(stderr, "\n");
+ FunctionProtos[ProtoAST->getName()] = std::move(ProtoAST);
}
+ } else {
+ // Skip token for error recovery.
+ getNextToken();
+ }
+}
+```
In HandleDefinition, we add two lines to transfer the newly defined function to
the JIT and open a new module. In HandleExtern, we just need to add one line to
add the prototype to FunctionProtos.
-.. warning::
- Duplication of symbols in separate modules is not allowed since LLVM-9. That means you can not redefine function in your Kaleidoscope as its shown below. Just skip this part.
+:::{warning}
+Duplication of symbols in separate modules is not allowed since LLVM-9. That means you can not redefine function in your Kaleidoscope as its shown below. Just skip this part.
- The reason is that the newer OrcV2 JIT APIs are trying to stay very close to the static and dynamic linker rules, including rejecting duplicate symbols. Requiring symbol names to be unique allows us to support concurrent compilation for symbols using the (unique) symbol names as keys for tracking.
+The reason is that the newer OrcV2 JIT APIs are trying to stay very close to the static and dynamic linker rules, including rejecting duplicate symbols. Requiring symbol names to be unique allows us to support concurrent compilation for symbols using the (unique) symbol names as keys for tracking.
+:::
With these changes made, let's try our REPL again (I removed the dump of the
anonymous functions this time, you should get the idea by now :) :
-::
+```
+ready> def foo(x) x + 1;
+ready> foo(2);
+Evaluated to 3.000000
- ready> def foo(x) x + 1;
- ready> foo(2);
- Evaluated to 3.000000
-
- ready> def foo(x) x + 2;
- ready> foo(2);
- Evaluated to 4.000000
+ready> def foo(x) x + 2;
+ready> foo(2);
+Evaluated to 4.000000
+```
It works!
Even with this simple code, we get some surprisingly powerful capabilities -
check this out:
-::
-
- ready> extern sin(x);
- Read extern:
- declare double @sin(double)
-
- ready> extern cos(x);
- Read extern:
- declare double @cos(double)
-
- ready> sin(1.0);
- Read top-level expression:
- define double @2() {
- entry:
- ret double 0x3FEAED548F090CEE
- }
-
- Evaluated to 0.841471
-
- ready> def foo(x) sin(x)*sin(x) + cos(x)*cos(x);
- Read function definition:
- define double @foo(double %x) {
- entry:
- %calltmp = call double @sin(double %x)
- %multmp = fmul double %calltmp, %calltmp
- %calltmp2 = call double @cos(double %x)
- %multmp4 = fmul double %calltmp2, %calltmp2
- %addtmp = fadd double %multmp, %multmp4
- ret double %addtmp
- }
-
- ready> foo(4.0);
- Read top-level expression:
- define double @3() {
- entry:
- %calltmp = call double @foo(double 4.000000e+00)
- ret double %calltmp
- }
-
- Evaluated to 1.000000
+```
+ready> extern sin(x);
+Read extern:
+declare double @sin(double)
+
+ready> extern cos(x);
+Read extern:
+declare double @cos(double)
+
+ready> sin(1.0);
+Read top-level expression:
+define double @2() {
+entry:
+ ret double 0x3FEAED548F090CEE
+}
+
+Evaluated to 0.841471
+
+ready> def foo(x) sin(x)*sin(x) + cos(x)*cos(x);
+Read function definition:
+define double @foo(double %x) {
+entry:
+ %calltmp = call double @sin(double %x)
+ %multmp = fmul double %calltmp, %calltmp
+ %calltmp2 = call double @cos(double %x)
+ %multmp4 = fmul double %calltmp2, %calltmp2
+ %addtmp = fadd double %multmp, %multmp4
+ ret double %addtmp
+}
+
+ready> foo(4.0);
+Read top-level expression:
+define double @3() {
+entry:
+ %calltmp = call double @foo(double 4.000000e+00)
+ ret double %calltmp
+}
+
+Evaluated to 1.000000
+```
Whoa, how does the JIT know about sin and cos? The answer is surprisingly
simple: The KaleidoscopeJIT has a straightforward symbol resolution rule that
it uses to find symbols that aren't available in any given module: First
it searches all the modules that have already been added to the JIT, from the
most recent to the oldest, to find the newest definition. If no definition is
-found inside the JIT, it falls back to calling "``dlsym("sin")``" on the
-Kaleidoscope process itself. Since "``sin``" is defined within the JIT's
+found inside the JIT, it falls back to calling "`dlsym("sin")`" on the
+Kaleidoscope process itself. Since "`sin`" is defined within the JIT's
address space, it simply patches up calls in the module to call the libm
-version of ``sin`` directly. But in some cases this even goes further:
+version of `sin` directly. But in some cases this even goes further:
as sin and cos are names of standard math functions, the constant folder
will directly evaluate the function calls to the correct result when called
-with constants like in the "``sin(1.0)``" above.
+with constants like in the "`sin(1.0)`" above.
In the future we'll see how tweaking this symbol resolution rule can be used to
enable all sorts of useful features, from security (restricting the set of
@@ -638,25 +628,25 @@ One immediate benefit of the symbol resolution rule is that we can now extend
the language by writing arbitrary C++ code to implement operations. For example,
if we add:
-.. code-block:: c++
+```c++
+#ifdef _WIN32
+#define DLLEXPORT __declspec(dllexport)
+#else
+#define DLLEXPORT
+#endif
- #ifdef _WIN32
- #define DLLEXPORT __declspec(dllexport)
- #else
- #define DLLEXPORT
- #endif
-
- /// putchard - putchar that takes a double and returns 0.
- extern "C" DLLEXPORT double putchard(double X) {
- fputc((char)X, stderr);
- return 0;
- }
+/// putchard - putchar that takes a double and returns 0.
+extern "C" DLLEXPORT double putchard(double X) {
+ fputc((char)X, stderr);
+ return 0;
+}
+```
Note, that for Windows we need to actually export the functions because
-the dynamic symbol loader will use ``GetProcAddress`` to find the symbols.
+the dynamic symbol loader will use `GetProcAddress` to find the symbols.
Now we can produce simple output to the console by using things like:
-"``extern putchard(x); putchard(120);``", which prints a lowercase 'x'
+"`extern putchard(x); putchard(120);`", which prints a lowercase 'x'
on the console (120 is the ASCII code for 'x'). Similar code could be
used to implement file I/O, console input, and many other capabilities
in Kaleidoscope.
@@ -664,22 +654,21 @@ in Kaleidoscope.
This completes the JIT and optimizer chapter of the Kaleidoscope
tutorial. At this point, we can compile a non-Turing-complete
programming language, optimize and JIT compile it in a user-driven way.
-Next up we'll look into `extending the language with control flow
-constructs <LangImpl05.html>`_, tackling some interesting LLVM IR issues
+Next up we'll look into [extending the language with control flow
+constructs](LangImpl05.md), tackling some interesting LLVM IR issues
along the way.
-Full Code Listing
-=================
+## Full Code Listing
Here is the complete code listing for our running example, enhanced with
the LLVM JIT and optimizer. To build this example, use:
-.. code-block:: bash
-
- # Compile
- clang++ -g toy.cpp `llvm-config --cxxflags --ldflags --system-libs --libs core orcjit native` -O3 -o toy
- # Run
- ./toy
+```bash
+# Compile
+clang++ -g toy.cpp `llvm-config --cxxflags --ldflags --system-libs --libs core orcjit native` -O3 -o toy
+# Run
+./toy
+```
If you are compiling this on Linux, make sure to add the "-rdynamic"
option as well. This makes sure that the external functions are resolved
@@ -687,8 +676,8 @@ properly at runtime.
Here is the code:
-.. literalinclude:: ../../../examples/Kaleidoscope/Chapter4/toy.cpp
- :language: c++
-
-`Next: Extending the language: control flow <LangImpl05.html>`_
+```{literalinclude} ../../../examples/Kaleidoscope/Chapter4/toy.cpp
+:language: c++
+```
+[Next: Extending the language: control flow](LangImpl05.md)
diff --git a/llvm/docs/tutorial/MyFirstLanguageFrontend/LangImpl05.md b/llvm/docs/tutorial/MyFirstLanguageFrontend/LangImpl05.md
index 419a79b4e135a..81e06e823c537 100644
--- a/llvm/docs/tutorial/MyFirstLanguageFrontend/LangImpl05.md
+++ b/llvm/docs/tutorial/MyFirstLanguageFrontend/LangImpl05.md
@@ -1,13 +1,9 @@
-==================================================
-Kaleidoscope: Extending the Language: Control Flow
-==================================================
+# Kaleidoscope: Extending the Language: Control Flow
+## Chapter 5 Introduction
-Chapter 5 Introduction
-======================
-
-Welcome to Chapter 5 of the "`Implementing a language with
-LLVM <index.html>`_" tutorial. Parts 1-4 described the implementation of
+Welcome to Chapter 5 of the "[Implementing a language with
+LLVM](index.md)" tutorial. Parts 1-4 described the implementation of
the simple Kaleidoscope language and included support for generating
LLVM IR, followed by optimizations and a JIT compiler. Unfortunately, as
presented, Kaleidoscope is mostly useless: it has no control flow other
@@ -16,8 +12,7 @@ branches in the code, significantly limiting its power. In this episode
of "build that compiler", we'll extend Kaleidoscope to have an
if/then/else expression plus a simple 'for' loop.
-If/Then/Else
-============
+## If/Then/Else
Extending Kaleidoscope to support if/then/else is quite straightforward.
It basically requires adding support for this "new" concept to the
@@ -29,13 +24,13 @@ Before we get going on "how" we add this extension, let's talk about
"what" we want. The basic idea is that we want to be able to write this
sort of thing:
-::
-
- def fib(x)
- if x < 3 then
- 1
- else
- fib(x-1)+fib(x-2);
+```
+def fib(x)
+ if x < 3 then
+ 1
+ else
+ fib(x-1)+fib(x-2);
+```
In Kaleidoscope, every construct is an expression: there are no
statements. As such, the if/then/else expression needs to return a value
@@ -55,118 +50,114 @@ down.
Now that we know what we "want", let's break this down into its
constituent pieces.
-Lexer Extensions for If/Then/Else
----------------------------------
+### Lexer Extensions for If/Then/Else
The lexer extensions are straightforward. First we add new enum values
for the relevant tokens:
-.. code-block:: c++
-
- // control
- tok_if = -6,
- tok_then = -7,
- tok_else = -8,
+```c++
+// control
+tok_if = -6,
+tok_then = -7,
+tok_else = -8,
+```
Once we have that, we recognize the new keywords in the lexer. This is
pretty simple stuff:
-.. code-block:: c++
-
- ...
- if (IdentifierStr == "def")
- return tok_def;
- if (IdentifierStr == "extern")
- return tok_extern;
- if (IdentifierStr == "if")
- return tok_if;
- if (IdentifierStr == "then")
- return tok_then;
- if (IdentifierStr == "else")
- return tok_else;
- return tok_identifier;
-
-AST Extensions for If/Then/Else
--------------------------------
+```c++
+...
+if (IdentifierStr == "def")
+ return tok_def;
+if (IdentifierStr == "extern")
+ return tok_extern;
+if (IdentifierStr == "if")
+ return tok_if;
+if (IdentifierStr == "then")
+ return tok_then;
+if (IdentifierStr == "else")
+ return tok_else;
+return tok_identifier;
+```
+
+### AST Extensions for If/Then/Else
To represent the new expression we add a new AST node for it:
-.. code-block:: c++
-
- /// IfExprAST - Expression class for if/then/else.
- class IfExprAST : public ExprAST {
- std::unique_ptr<ExprAST> Cond, Then, Else;
+```c++
+/// IfExprAST - Expression class for if/then/else.
+class IfExprAST : public ExprAST {
+ std::unique_ptr<ExprAST> Cond, Then, Else;
- public:
- IfExprAST(std::unique_ptr<ExprAST> Cond, std::unique_ptr<ExprAST> Then,
- std::unique_ptr<ExprAST> Else)
- : Cond(std::move(Cond)), Then(std::move(Then)), Else(std::move(Else)) {}
+public:
+ IfExprAST(std::unique_ptr<ExprAST> Cond, std::unique_ptr<ExprAST> Then,
+ std::unique_ptr<ExprAST> Else)
+ : Cond(std::move(Cond)), Then(std::move(Then)), Else(std::move(Else)) {}
- Value *codegen() override;
- };
+ Value *codegen() override;
+};
+```
The AST node just has pointers to the various subexpressions.
-Parser Extensions for If/Then/Else
-----------------------------------
+### Parser Extensions for If/Then/Else
Now that we have the relevant tokens coming from the lexer and we have
the AST node to build, our parsing logic is relatively straightforward.
First we define a new parsing function:
-.. code-block:: c++
+```c++
+/// ifexpr ::= 'if' expression 'then' expression 'else' expression
+static std::unique_ptr<ExprAST> ParseIfExpr() {
+ getNextToken(); // eat the if.
- /// ifexpr ::= 'if' expression 'then' expression 'else' expression
- static std::unique_ptr<ExprAST> ParseIfExpr() {
- getNextToken(); // eat the if.
+ // condition.
+ auto Cond = ParseExpression();
+ if (!Cond)
+ return nullptr;
- // condition.
- auto Cond = ParseExpression();
- if (!Cond)
- return nullptr;
+ if (CurTok != tok_then)
+ return LogError("expected then");
+ getNextToken(); // eat the then
- if (CurTok != tok_then)
- return LogError("expected then");
- getNextToken(); // eat the then
+ auto Then = ParseExpression();
+ if (!Then)
+ return nullptr;
- auto Then = ParseExpression();
- if (!Then)
- return nullptr;
+ if (CurTok != tok_else)
+ return LogError("expected else");
- if (CurTok != tok_else)
- return LogError("expected else");
+ getNextToken();
- getNextToken();
+ auto Else = ParseExpression();
+ if (!Else)
+ return nullptr;
- auto Else = ParseExpression();
- if (!Else)
- return nullptr;
-
- return std::make_unique<IfExprAST>(std::move(Cond), std::move(Then),
- std::move(Else));
- }
+ return std::make_unique<IfExprAST>(std::move(Cond), std::move(Then),
+ std::move(Else));
+}
+```
Next we hook it up as a primary expression:
-.. code-block:: c++
-
- static std::unique_ptr<ExprAST> ParsePrimary() {
- switch (CurTok) {
- default:
- return LogError("unknown token when expecting an expression");
- case tok_identifier:
- return ParseIdentifierExpr();
- case tok_number:
- return ParseNumberExpr();
- case '(':
- return ParseParenExpr();
- case tok_if:
- return ParseIfExpr();
- }
- }
-
-LLVM IR for If/Then/Else
-------------------------
+```c++
+static std::unique_ptr<ExprAST> ParsePrimary() {
+ switch (CurTok) {
+ default:
+ return LogError("unknown token when expecting an expression");
+ case tok_identifier:
+ return ParseIdentifierExpr();
+ case tok_number:
+ return ParseNumberExpr();
+ case '(':
+ return ParseParenExpr();
+ case tok_if:
+ return ParseIfExpr();
+ }
+}
+```
+
+### LLVM IR for If/Then/Else
Now that we have it parsing and building the AST, the final piece is
adding LLVM code generation support. This is the most interesting part
@@ -177,60 +168,61 @@ described in previous chapters.
To motivate the code we want to produce, let's take a look at a simple
example. Consider:
-::
-
- extern foo();
- extern bar();
- def baz(x) if x then foo() else bar();
+```
+extern foo();
+extern bar();
+def baz(x) if x then foo() else bar();
+```
If you disable optimizations, the code you'll (soon) get from
Kaleidoscope looks like this:
-.. code-block:: llvm
+```llvm
+declare double @foo()
- declare double @foo()
+declare double @bar()
- declare double @bar()
+define double @baz(double %x) {
+entry:
+ %ifcond = fcmp one double %x, 0.000000e+00
+ br i1 %ifcond, label %then, label %else
- define double @baz(double %x) {
- entry:
- %ifcond = fcmp one double %x, 0.000000e+00
- br i1 %ifcond, label %then, label %else
+then: ; preds = %entry
+ %calltmp = call double @foo()
+ br label %ifcont
- then: ; preds = %entry
- %calltmp = call double @foo()
- br label %ifcont
+else: ; preds = %entry
+ %calltmp1 = call double @bar()
+ br label %ifcont
- else: ; preds = %entry
- %calltmp1 = call double @bar()
- br label %ifcont
-
- ifcont: ; preds = %else, %then
- %iftmp = phi double [ %calltmp, %then ], [ %calltmp1, %else ]
- ret double %iftmp
- }
+ifcont: ; preds = %else, %then
+ %iftmp = phi double [ %calltmp, %then ], [ %calltmp1, %else ]
+ ret double %iftmp
+}
+```
To visualize the control flow graph, you can use a nifty feature of the
-LLVM '`opt <https://llvm.org/cmds/opt.html>`_' tool. If you put this LLVM
-IR into "t.ll" and run "``llvm-as < t.ll | opt -passes=view-cfg``", `a
-window will pop up <../../ProgrammersManual.html#viewing-graphs-while-debugging-code>`_ and you'll
+LLVM '[opt](https://llvm.org/cmds/opt.html)' tool. If you put this LLVM
+IR into "t.ll" and run "`llvm-as < t.ll | opt -passes=view-cfg`", [a
+window will pop up](../../ProgrammersManual.md#viewing-graphs-while-debugging-code) and you'll
see this graph:
-.. figure:: LangImpl05-cfg.png
- :align: center
- :alt: Example CFG
+:::{figure} LangImpl05-cfg.png
+:align: center
+:alt: Example CFG
- Example CFG
+Example CFG
+:::
-Another way to get this is to call "``F->viewCFG()``" or
-"``F->viewCFGOnly()``" (where F is a "``Function*``") either by
+Another way to get this is to call "`F->viewCFG()`" or
+"`F->viewCFGOnly()`" (where F is a "`Function*`") either by
inserting actual calls into the code and recompiling or by calling these
in the debugger. LLVM has many nice features for visualizing various
graphs.
Getting back to the generated code, it is fairly simple: the entry block
evaluates the conditional expression ("x" in our case here) and compares
-the result to 0.0 with the "``fcmp one``" instruction ('one' is "Ordered
+the result to 0.0 with the "`fcmp one`" instruction ('one' is "Ordered
and Not Equal"). Based on the result of this expression, the code jumps
to either the "then" or "else" blocks, which contain the expressions for
the true/false cases.
@@ -242,10 +234,10 @@ caller of the function. The question then becomes: how does the code
know which expression to return?
The answer to this question involves an important SSA operation: the
-`Phi
-operation <http://en.wikipedia.org/wiki/Static_single_assignment_form>`_.
-If you're not familiar with SSA, `the wikipedia
-article <http://en.wikipedia.org/wiki/Static_single_assignment_form>`_
+[Phi
+operation](http://en.wikipedia.org/wiki/Static_single_assignment_form).
+If you're not familiar with SSA, [the wikipedia
+article](http://en.wikipedia.org/wiki/Static_single_assignment_form)
is a good introduction and there are various other introductions to it
available on your favorite search engine. The short version is that
"execution" of the Phi operation requires "remembering" which block
@@ -263,11 +255,11 @@ practice, there are two sorts of values that float around in code
written for your average imperative programming language that might need
Phi nodes:
-#. Code that involves user variables: ``x = 1; x = x + 1;``
-#. Values that are implicit in the structure of your AST, such as the
+1. Code that involves user variables: `x = 1; x = x + 1;`
+2. Values that are implicit in the structure of your AST, such as the
Phi node in this case.
-In `Chapter 7 <LangImpl07.html>`_ of this tutorial ("mutable variables"),
+In [Chapter 7](LangImpl07.md) of this tutorial ("mutable variables"),
we'll talk about #1 in depth. For now, just believe me that you don't
need SSA construction to handle this case. For #2, you have the choice
of using the techniques that we will describe for #1, or you can insert
@@ -276,39 +268,38 @@ easy to generate the Phi node, so we choose to do it directly.
Okay, enough of the motivation and overview, let's generate code!
-Code Generation for If/Then/Else
---------------------------------
-
-In order to generate code for this, we implement the ``codegen`` method
-for ``IfExprAST``:
+### Code Generation for If/Then/Else
-.. code-block:: c++
+In order to generate code for this, we implement the `codegen` method
+for `IfExprAST`:
- Value *IfExprAST::codegen() {
- Value *CondV = Cond->codegen();
- if (!CondV)
- return nullptr;
+```c++
+Value *IfExprAST::codegen() {
+ Value *CondV = Cond->codegen();
+ if (!CondV)
+ return nullptr;
- // Convert condition to a bool by comparing non-equal to 0.0.
- CondV = Builder->CreateFCmpONE(
- CondV, ConstantFP::get(*TheContext, APFloat(0.0)), "ifcond");
+ // Convert condition to a bool by comparing non-equal to 0.0.
+ CondV = Builder->CreateFCmpONE(
+ CondV, ConstantFP::get(*TheContext, APFloat(0.0)), "ifcond");
+```
This code is straightforward and similar to what we saw before. We emit
the expression for the condition, then compare that value to zero to get
a truth value as a 1-bit (bool) value.
-.. code-block:: c++
+```c++
+Function *TheFunction = Builder->GetInsertBlock()->getParent();
- Function *TheFunction = Builder->GetInsertBlock()->getParent();
+// Create blocks for the then and else cases. Insert the 'then' block at the
+// end of the function.
+BasicBlock *ThenBB =
+ BasicBlock::Create(*TheContext, "then", TheFunction);
+BasicBlock *ElseBB = BasicBlock::Create(*TheContext, "else");
+BasicBlock *MergeBB = BasicBlock::Create(*TheContext, "ifcont");
- // Create blocks for the then and else cases. Insert the 'then' block at the
- // end of the function.
- BasicBlock *ThenBB =
- BasicBlock::Create(*TheContext, "then", TheFunction);
- BasicBlock *ElseBB = BasicBlock::Create(*TheContext, "else");
- BasicBlock *MergeBB = BasicBlock::Create(*TheContext, "ifcont");
-
- Builder->CreateCondBr(CondV, ThenBB, ElseBB);
+Builder->CreateCondBr(CondV, ThenBB, ElseBB);
+```
This code creates the basic blocks that are related to the if/then/else
statement, and correspond directly to the blocks in the example above.
@@ -331,18 +322,18 @@ condition went into. Also note that it is creating a branch to the
inserted into the function yet. This is all ok: it is the standard way
that LLVM supports forward references.
-.. code-block:: c++
-
- // Emit then value.
- Builder->SetInsertPoint(ThenBB);
+```c++
+// Emit then value.
+Builder->SetInsertPoint(ThenBB);
- Value *ThenV = Then->codegen();
- if (!ThenV)
- return nullptr;
+Value *ThenV = Then->codegen();
+if (!ThenV)
+ return nullptr;
- Builder->CreateBr(MergeBB);
- // Codegen of 'Then' can change the current block, update ThenBB for the PHI.
- ThenBB = Builder->GetInsertBlock();
+Builder->CreateBr(MergeBB);
+// Codegen of 'Then' can change the current block, update ThenBB for the PHI.
+ThenBB = Builder->GetInsertBlock();
+```
After the conditional branch is inserted, we move the builder to start
inserting into the "then" block. Strictly speaking, this call moves the
@@ -353,9 +344,9 @@ beginning of the block. :)
Once the insertion point is set, we recursively codegen the "then"
expression from the AST. To finish off the "then" block, we create an
unconditional branch to the merge block. One interesting (and very
-important) aspect of the LLVM IR is that it :ref:`requires all basic
-blocks to be "terminated" <functionstructure>` with a :ref:`control
-flow instruction <terminators>` such as return or branch. This means
+important) aspect of the LLVM IR is that it {ref}`requires all basic
+blocks to be "terminated" <functionstructure>` with a {ref}`control
+flow instruction <terminators>` such as return or branch. This means
that all control flow, *including fall throughs* must be made explicit
in the LLVM IR. If you violate this rule, the verifier will emit an
error.
@@ -368,23 +359,23 @@ of the block in the CFG. Why then, are we getting the current block when
we just set it to ThenBB 5 lines above? The problem is that the "Then"
expression may actually itself change the block that the Builder is
emitting into if, for example, it contains a nested "if/then/else"
-expression. Because calling ``codegen()`` recursively could arbitrarily change
+expression. Because calling `codegen()` recursively could arbitrarily change
the notion of the current block, we are required to get an up-to-date
value for code that will set up the Phi node.
-.. code-block:: c++
+```c++
+// Emit else block.
+TheFunction->insert(TheFunction->end(), ElseBB);
+Builder->SetInsertPoint(ElseBB);
- // Emit else block.
- TheFunction->insert(TheFunction->end(), ElseBB);
- Builder->SetInsertPoint(ElseBB);
+Value *ElseV = Else->codegen();
+if (!ElseV)
+ return nullptr;
- Value *ElseV = Else->codegen();
- if (!ElseV)
- return nullptr;
-
- Builder->CreateBr(MergeBB);
- // codegen of 'Else' can change the current block, update ElseBB for the PHI.
- ElseBB = Builder->GetInsertBlock();
+Builder->CreateBr(MergeBB);
+// codegen of 'Else' can change the current block, update ElseBB for the PHI.
+ElseBB = Builder->GetInsertBlock();
+```
Code generation for the 'else' block is basically identical to codegen
for the 'then' block. The only significant
diff erence is the first line,
@@ -393,18 +384,18 @@ which adds the 'else' block to the function. Recall previously that the
'then' and 'else' blocks are emitted, we can finish up with the merge
code:
-.. code-block:: c++
-
- // Emit merge block.
- TheFunction->insert(TheFunction->end(), MergeBB);
- Builder->SetInsertPoint(MergeBB);
- PHINode *PN =
- Builder->CreatePHI(Type::getDoubleTy(*TheContext), 2, "iftmp");
+```c++
+ // Emit merge block.
+ TheFunction->insert(TheFunction->end(), MergeBB);
+ Builder->SetInsertPoint(MergeBB);
+ PHINode *PN =
+ Builder->CreatePHI(Type::getDoubleTy(*TheContext), 2, "iftmp");
- PN->addIncoming(ThenV, ThenBB);
- PN->addIncoming(ElseV, ElseBB);
- return PN;
- }
+ PN->addIncoming(ThenV, ThenBB);
+ PN->addIncoming(ElseV, ElseBB);
+ return PN;
+}
+```
The first two lines here are now familiar: the first adds the "merge"
block to the Function object (it was previously floating, like the else
@@ -423,22 +414,21 @@ language that can calculate a wide variety of numeric functions. Next up
we'll add another useful expression that is familiar from non-functional
languages...
-'for' Loop Expression
-=====================
+## 'for' Loop Expression
Now that we know how to add basic control flow constructs to the
language, we have the tools to add more powerful things. Let's add
something more aggressive, a 'for' expression:
-::
+```
+extern putchard(char);
+def printstar(n)
+ for i = 1, i < n, 1.0 in
+ putchard(42); # ascii 42 = '*'
- extern putchard(char);
- def printstar(n)
- for i = 1, i < n, 1.0 in
- putchard(42); # ascii 42 = '*'
-
- # print 100 '*' characters
- printstar(100);
+# print 100 '*' characters
+printstar(100);
+```
This expression defines a new variable ("i" in this case) which iterates
from a starting value, while the condition ("i < n" in this case) is
@@ -451,188 +441,183 @@ future when we have mutable variables, it will get more useful.
As before, let's talk about the changes that we need to Kaleidoscope to
support this.
-Lexer Extensions for the 'for' Loop
------------------------------------
+### Lexer Extensions for the 'for' Loop
The lexer extensions are the same sort of thing as for if/then/else:
-.. code-block:: c++
-
- ... in enum Token ...
- // control
- tok_if = -6, tok_then = -7, tok_else = -8,
- tok_for = -9, tok_in = -10
-
- ... in gettok ...
- if (IdentifierStr == "def")
- return tok_def;
- if (IdentifierStr == "extern")
- return tok_extern;
- if (IdentifierStr == "if")
- return tok_if;
- if (IdentifierStr == "then")
- return tok_then;
- if (IdentifierStr == "else")
- return tok_else;
- if (IdentifierStr == "for")
- return tok_for;
- if (IdentifierStr == "in")
- return tok_in;
- return tok_identifier;
-
-AST Extensions for the 'for' Loop
----------------------------------
+```c++
+... in enum Token ...
+// control
+tok_if = -6, tok_then = -7, tok_else = -8,
+tok_for = -9, tok_in = -10
+
+... in gettok ...
+if (IdentifierStr == "def")
+ return tok_def;
+if (IdentifierStr == "extern")
+ return tok_extern;
+if (IdentifierStr == "if")
+ return tok_if;
+if (IdentifierStr == "then")
+ return tok_then;
+if (IdentifierStr == "else")
+ return tok_else;
+if (IdentifierStr == "for")
+ return tok_for;
+if (IdentifierStr == "in")
+ return tok_in;
+return tok_identifier;
+```
+
+### AST Extensions for the 'for' Loop
The AST node is just as simple. It basically boils down to capturing the
variable name and the constituent expressions in the node.
-.. code-block:: c++
-
- /// ForExprAST - Expression class for for/in.
- class ForExprAST : public ExprAST {
- std::string VarName;
- std::unique_ptr<ExprAST> Start, End, Step, Body;
+```c++
+/// ForExprAST - Expression class for for/in.
+class ForExprAST : public ExprAST {
+ std::string VarName;
+ std::unique_ptr<ExprAST> Start, End, Step, Body;
- public:
- ForExprAST(const std::string &VarName, std::unique_ptr<ExprAST> Start,
- std::unique_ptr<ExprAST> End, std::unique_ptr<ExprAST> Step,
- std::unique_ptr<ExprAST> Body)
- : VarName(VarName), Start(std::move(Start)), End(std::move(End)),
- Step(std::move(Step)), Body(std::move(Body)) {}
+public:
+ ForExprAST(const std::string &VarName, std::unique_ptr<ExprAST> Start,
+ std::unique_ptr<ExprAST> End, std::unique_ptr<ExprAST> Step,
+ std::unique_ptr<ExprAST> Body)
+ : VarName(VarName), Start(std::move(Start)), End(std::move(End)),
+ Step(std::move(Step)), Body(std::move(Body)) {}
- Value *codegen() override;
- };
+ Value *codegen() override;
+};
+```
-Parser Extensions for the 'for' Loop
-------------------------------------
+### Parser Extensions for the 'for' Loop
The parser code is also fairly standard. The only interesting thing here
is handling of the optional step value. The parser code handles it by
checking to see if the second comma is present. If not, it sets the step
value to null in the AST node:
-.. code-block:: c++
+```c++
+/// forexpr ::= 'for' identifier '=' expr ',' expr (',' expr)? 'in' expression
+static std::unique_ptr<ExprAST> ParseForExpr() {
+ getNextToken(); // eat the for.
- /// forexpr ::= 'for' identifier '=' expr ',' expr (',' expr)? 'in' expression
- static std::unique_ptr<ExprAST> ParseForExpr() {
- getNextToken(); // eat the for.
+ if (CurTok != tok_identifier)
+ return LogError("expected identifier after for");
- if (CurTok != tok_identifier)
- return LogError("expected identifier after for");
+ std::string IdName = IdentifierStr;
+ getNextToken(); // eat identifier.
- std::string IdName = IdentifierStr;
- getNextToken(); // eat identifier.
+ if (CurTok != '=')
+ return LogError("expected '=' after for");
+ getNextToken(); // eat '='.
- if (CurTok != '=')
- return LogError("expected '=' after for");
- getNextToken(); // eat '='.
+ auto Start = ParseExpression();
+ if (!Start)
+ return nullptr;
+ if (CurTok != ',')
+ return LogError("expected ',' after for start value");
+ getNextToken();
- auto Start = ParseExpression();
- if (!Start)
- return nullptr;
- if (CurTok != ',')
- return LogError("expected ',' after for start value");
- getNextToken();
+ auto End = ParseExpression();
+ if (!End)
+ return nullptr;
- auto End = ParseExpression();
- if (!End)
- return nullptr;
+ // The step value is optional.
+ std::unique_ptr<ExprAST> Step;
+ if (CurTok == ',') {
+ getNextToken();
+ Step = ParseExpression();
+ if (!Step)
+ return nullptr;
+ }
- // The step value is optional.
- std::unique_ptr<ExprAST> Step;
- if (CurTok == ',') {
- getNextToken();
- Step = ParseExpression();
- if (!Step)
- return nullptr;
- }
+ if (CurTok != tok_in)
+ return LogError("expected 'in' after for");
+ getNextToken(); // eat 'in'.
- if (CurTok != tok_in)
- return LogError("expected 'in' after for");
- getNextToken(); // eat 'in'.
+ auto Body = ParseExpression();
+ if (!Body)
+ return nullptr;
- auto Body = ParseExpression();
- if (!Body)
- return nullptr;
-
- return std::make_unique<ForExprAST>(IdName, std::move(Start),
- std::move(End), std::move(Step),
- std::move(Body));
- }
+ return std::make_unique<ForExprAST>(IdName, std::move(Start),
+ std::move(End), std::move(Step),
+ std::move(Body));
+}
+```
And again we hook it up as a primary expression:
-.. code-block:: c++
-
- static std::unique_ptr<ExprAST> ParsePrimary() {
- switch (CurTok) {
- default:
- return LogError("unknown token when expecting an expression");
- case tok_identifier:
- return ParseIdentifierExpr();
- case tok_number:
- return ParseNumberExpr();
- case '(':
- return ParseParenExpr();
- case tok_if:
- return ParseIfExpr();
- case tok_for:
- return ParseForExpr();
- }
- }
-
-LLVM IR for the 'for' Loop
---------------------------
+```c++
+static std::unique_ptr<ExprAST> ParsePrimary() {
+ switch (CurTok) {
+ default:
+ return LogError("unknown token when expecting an expression");
+ case tok_identifier:
+ return ParseIdentifierExpr();
+ case tok_number:
+ return ParseNumberExpr();
+ case '(':
+ return ParseParenExpr();
+ case tok_if:
+ return ParseIfExpr();
+ case tok_for:
+ return ParseForExpr();
+ }
+}
+```
+
+### LLVM IR for the 'for' Loop
Now we get to the good part: the LLVM IR we want to generate for this
thing. With the simple example above, we get this LLVM IR (note that
this dump is generated with optimizations disabled for clarity):
-.. code-block:: llvm
-
- declare double @putchard(double)
-
- define double @printstar(double %n) {
- entry:
- ; initial value = 1.0 (inlined into phi)
- br label %loop
-
- loop: ; preds = %loop, %entry
- %i = phi double [ 1.000000e+00, %entry ], [ %nextvar, %loop ]
- ; body
- %calltmp = call double @putchard(double 4.200000e+01)
- ; increment
- %nextvar = fadd double %i, 1.000000e+00
-
- ; termination test
- %cmptmp = fcmp ult double %i, %n
- %booltmp = uitofp i1 %cmptmp to double
- %loopcond = fcmp one double %booltmp, 0.000000e+00
- br i1 %loopcond, label %loop, label %afterloop
-
- afterloop: ; preds = %loop
- ; loop always returns 0.0
- ret double 0.000000e+00
- }
+```llvm
+declare double @putchard(double)
+
+define double @printstar(double %n) {
+entry:
+ ; initial value = 1.0 (inlined into phi)
+ br label %loop
+
+loop: ; preds = %loop, %entry
+ %i = phi double [ 1.000000e+00, %entry ], [ %nextvar, %loop ]
+ ; body
+ %calltmp = call double @putchard(double 4.200000e+01)
+ ; increment
+ %nextvar = fadd double %i, 1.000000e+00
+
+ ; termination test
+ %cmptmp = fcmp ult double %i, %n
+ %booltmp = uitofp i1 %cmptmp to double
+ %loopcond = fcmp one double %booltmp, 0.000000e+00
+ br i1 %loopcond, label %loop, label %afterloop
+
+afterloop: ; preds = %loop
+ ; loop always returns 0.0
+ ret double 0.000000e+00
+}
+```
This loop contains all the same constructs we saw before: a phi node,
several expressions, and some basic blocks. Let's see how this fits
together.
-Code Generation for the 'for' Loop
-----------------------------------
+### Code Generation for the 'for' Loop
The first part of codegen is very simple: we just output the start
expression for the loop value:
-.. code-block:: c++
-
- Value *ForExprAST::codegen() {
- // Emit the start code first, without 'variable' in scope.
- Value *StartVal = Start->codegen();
- if (!StartVal)
- return nullptr;
+```c++
+Value *ForExprAST::codegen() {
+ // Emit the start code first, without 'variable' in scope.
+ Value *StartVal = Start->codegen();
+ if (!StartVal)
+ return nullptr;
+```
With this out of the way, the next step is to set up the LLVM basic
block for the start of the loop body. In the case above, the whole loop
@@ -640,17 +625,17 @@ body is one block, but remember that the body code itself could consist
of multiple blocks (e.g. if it contains an if/then/else or a for/in
expression).
-.. code-block:: c++
-
- // Make the new basic block for the loop header, inserting after current
- // block.
- Function *TheFunction = Builder->GetInsertBlock()->getParent();
- BasicBlock *PreheaderBB = Builder->GetInsertBlock();
- BasicBlock *LoopBB =
- BasicBlock::Create(*TheContext, "loop", TheFunction);
+```c++
+// Make the new basic block for the loop header, inserting after current
+// block.
+Function *TheFunction = Builder->GetInsertBlock()->getParent();
+BasicBlock *PreheaderBB = Builder->GetInsertBlock();
+BasicBlock *LoopBB =
+ BasicBlock::Create(*TheContext, "loop", TheFunction);
- // Insert an explicit fall through from the current block to the LoopBB.
- Builder->CreateBr(LoopBB);
+// Insert an explicit fall through from the current block to the LoopBB.
+Builder->CreateBr(LoopBB);
+```
This code is similar to what we saw for if/then/else. Because we will
need it to create the Phi node, we remember the block that falls through
@@ -658,15 +643,15 @@ into the loop. Once we have that, we create the actual block that starts
the loop and create an unconditional branch for the fall-through between
the two blocks.
-.. code-block:: c++
+```c++
+// Start insertion in LoopBB.
+Builder->SetInsertPoint(LoopBB);
- // Start insertion in LoopBB.
- Builder->SetInsertPoint(LoopBB);
-
- // Start the PHI node with an entry for Start.
- PHINode *Variable = Builder->CreatePHI(Type::getDoubleTy(*TheContext),
- 2, VarName);
- Variable->addIncoming(StartVal, PreheaderBB);
+// Start the PHI node with an entry for Start.
+PHINode *Variable = Builder->CreatePHI(Type::getDoubleTy(*TheContext),
+ 2, VarName);
+Variable->addIncoming(StartVal, PreheaderBB);
+```
Now that the "preheader" for the loop is set up, we switch to emitting
code for the loop body. To begin with, we move the insertion point and
@@ -675,18 +660,18 @@ know the incoming value for the starting value, we add it to the Phi
node. Note that the Phi will eventually get a second value for the
backedge, but we can't set it up yet (because it doesn't exist!).
-.. code-block:: c++
-
- // Within the loop, the variable is defined equal to the PHI node. If it
- // shadows an existing variable, we have to restore it, so save it now.
- Value *OldVal = NamedValues[VarName];
- NamedValues[VarName] = Variable;
+```c++
+// Within the loop, the variable is defined equal to the PHI node. If it
+// shadows an existing variable, we have to restore it, so save it now.
+Value *OldVal = NamedValues[VarName];
+NamedValues[VarName] = Variable;
- // Emit the body of the loop. This, like any other expr, can change the
- // current BB. Note that we ignore the value computed by the body, but don't
- // allow an error.
- if (!Body->codegen())
- return nullptr;
+// Emit the body of the loop. This, like any other expr, can change the
+// current BB. Note that we ignore the value computed by the body, but don't
+// allow an error.
+if (!Body->codegen())
+ return nullptr;
+```
Now the code starts to get more interesting. Our 'for' loop introduces a
new variable to the symbol table. This means that our symbol table can
@@ -697,7 +682,7 @@ variable of the same name in the outer scope. It would be easy to make
this an error (emit an error and return null if there is already an
entry for VarName) but we choose to allow shadowing of variables. In
order to handle this correctly, we remember the Value that we are
-potentially shadowing in ``OldVal`` (which will be null if there is no
+potentially shadowing in `OldVal` (which will be null if there is no
shadowed variable).
Once the loop variable is set into the symbol table, the code
@@ -705,53 +690,53 @@ recursively codegen's the body. This allows the body to use the loop
variable: any references to it will naturally find it in the symbol
table.
-.. code-block:: c++
-
- // Emit the step value.
- Value *StepVal = nullptr;
- if (Step) {
- StepVal = Step->codegen();
- if (!StepVal)
- return nullptr;
- } else {
- // If not specified, use 1.0.
- StepVal = ConstantFP::get(*TheContext, APFloat(1.0));
- }
-
- Value *NextVar = Builder->CreateFAdd(Variable, StepVal, "nextvar");
+```c++
+// Emit the step value.
+Value *StepVal = nullptr;
+if (Step) {
+ StepVal = Step->codegen();
+ if (!StepVal)
+ return nullptr;
+} else {
+ // If not specified, use 1.0.
+ StepVal = ConstantFP::get(*TheContext, APFloat(1.0));
+}
+
+Value *NextVar = Builder->CreateFAdd(Variable, StepVal, "nextvar");
+```
Now that the body is emitted, we compute the next value of the iteration
variable by adding the step value, or 1.0 if it isn't present.
-'``NextVar``' will be the value of the loop variable on the next
+'`NextVar`' will be the value of the loop variable on the next
iteration of the loop.
-.. code-block:: c++
+```c++
+// Compute the end condition.
+Value *EndCond = End->codegen();
+if (!EndCond)
+ return nullptr;
- // Compute the end condition.
- Value *EndCond = End->codegen();
- if (!EndCond)
- return nullptr;
-
- // Convert condition to a bool by comparing non-equal to 0.0.
- EndCond = Builder->CreateFCmpONE(
- EndCond, ConstantFP::get(*TheContext, APFloat(0.0)), "loopcond");
+// Convert condition to a bool by comparing non-equal to 0.0.
+EndCond = Builder->CreateFCmpONE(
+ EndCond, ConstantFP::get(*TheContext, APFloat(0.0)), "loopcond");
+```
Finally, we evaluate the exit value of the loop, to determine whether
the loop should exit. This mirrors the condition evaluation for the
if/then/else statement.
-.. code-block:: c++
-
- // Create the "after loop" block and insert it.
- BasicBlock *LoopEndBB = Builder->GetInsertBlock();
- BasicBlock *AfterBB =
- BasicBlock::Create(*TheContext, "afterloop", TheFunction);
+```c++
+// Create the "after loop" block and insert it.
+BasicBlock *LoopEndBB = Builder->GetInsertBlock();
+BasicBlock *AfterBB =
+ BasicBlock::Create(*TheContext, "afterloop", TheFunction);
- // Insert the conditional branch into the end of LoopEndBB.
- Builder->CreateCondBr(EndCond, LoopBB, AfterBB);
+// Insert the conditional branch into the end of LoopEndBB.
+Builder->CreateCondBr(EndCond, LoopBB, AfterBB);
- // Any new code will be inserted in AfterBB.
- Builder->SetInsertPoint(AfterBB);
+// Any new code will be inserted in AfterBB.
+Builder->SetInsertPoint(AfterBB);
+```
With the code for the body of the loop complete, we just need to finish
up the control flow for it. This code remembers the end block (for the
@@ -761,52 +746,52 @@ chooses between executing the loop again and exiting the loop. Any
future code is emitted in the "afterloop" block, so it sets the
insertion position to it.
-.. code-block:: c++
+```c++
+ // Add a new entry to the PHI node for the backedge.
+ Variable->addIncoming(NextVar, LoopEndBB);
- // Add a new entry to the PHI node for the backedge.
- Variable->addIncoming(NextVar, LoopEndBB);
+ // Restore the unshadowed variable.
+ if (OldVal)
+ NamedValues[VarName] = OldVal;
+ else
+ NamedValues.erase(VarName);
- // Restore the unshadowed variable.
- if (OldVal)
- NamedValues[VarName] = OldVal;
- else
- NamedValues.erase(VarName);
-
- // for expr always returns 0.0.
- return Constant::getNullValue(Type::getDoubleTy(*TheContext));
- }
+ // for expr always returns 0.0.
+ return Constant::getNullValue(Type::getDoubleTy(*TheContext));
+}
+```
The final code handles various cleanups: now that we have the "NextVar"
value, we can add the incoming value to the loop PHI node. After that,
we remove the loop variable from the symbol table, so that it isn't in
scope after the for loop. Finally, code generation of the for loop
always returns 0.0, so that is what we return from
-``ForExprAST::codegen()``.
+`ForExprAST::codegen()`.
With this, we conclude the "adding control flow to Kaleidoscope" chapter
of the tutorial. In this chapter we added two control flow constructs,
and used them to motivate a couple of aspects of the LLVM IR that are
important for front-end implementors to know. In the next chapter of our
-saga, we will get a bit crazier and add `user-defined
-operators <LangImpl06.html>`_ to our poor innocent language.
+saga, we will get a bit crazier and add [user-defined
+operators](LangImpl06.md) to our poor innocent language.
-Full Code Listing
-=================
+## Full Code Listing
Here is the complete code listing for our running example, enhanced with
the if/then/else and for expressions. To build this example, use:
-.. code-block:: bash
-
- # Compile
- clang++ -g toy.cpp `llvm-config --cxxflags --ldflags --system-libs --libs core orcjit native` -O3 -o toy
- # Run
- ./toy
+```bash
+# Compile
+clang++ -g toy.cpp `llvm-config --cxxflags --ldflags --system-libs --libs core orcjit native` -O3 -o toy
+# Run
+./toy
+```
Here is the code:
-.. literalinclude:: ../../../examples/Kaleidoscope/Chapter5/toy.cpp
- :language: c++
+```{literalinclude} ../../../examples/Kaleidoscope/Chapter5/toy.cpp
+:language: c++
+```
-`Next: Extending the language: user-defined operators <LangImpl06.html>`_
+[Next: Extending the language: user-defined operators](LangImpl06.md)
diff --git a/llvm/docs/tutorial/MyFirstLanguageFrontend/LangImpl06.md b/llvm/docs/tutorial/MyFirstLanguageFrontend/LangImpl06.md
index 3ac05471a192f..225605c9f607e 100644
--- a/llvm/docs/tutorial/MyFirstLanguageFrontend/LangImpl06.md
+++ b/llvm/docs/tutorial/MyFirstLanguageFrontend/LangImpl06.md
@@ -1,13 +1,9 @@
-============================================================
-Kaleidoscope: Extending the Language: User-defined Operators
-============================================================
+# Kaleidoscope: Extending the Language: User-defined Operators
+## Chapter 6 Introduction
-Chapter 6 Introduction
-======================
-
-Welcome to Chapter 6 of the "`Implementing a language with
-LLVM <index.html>`_" tutorial. At this point in our tutorial, we now
+Welcome to Chapter 6 of the "[Implementing a language with
+LLVM](index.md)" tutorial. At this point in our tutorial, we now
have a fully functional language that is fairly minimal, but also
useful. There is still one big problem with it, however. Our language
doesn't have many useful operators (like division, logical negation, or
@@ -22,11 +18,10 @@ is good or bad. In this tutorial we'll assume that it is okay to use
this as a way to show some interesting parsing techniques.
At the end of this tutorial, we'll run through an example Kaleidoscope
-application that `renders the Mandelbrot set <#kicking-the-tires>`_. This gives an
+application that [renders the Mandelbrot set](#kicking-the-tires). This gives an
example of what you can build with Kaleidoscope and its feature set.
-User-defined Operators: the Idea
-================================
+## User-defined Operators: the Idea
The "operator overloading" that we will add to Kaleidoscope is more
general than in languages like C++. In C++, you are only allowed to
@@ -39,7 +34,7 @@ The point of going into user-defined operators in a tutorial like this
is to show the power and flexibility of using a hand-written parser.
Thus far, the parser we have been implementing uses recursive descent
for most parts of the grammar and operator precedence parsing for the
-expressions. See `Chapter 2 <LangImpl02.html>`_ for details. By
+expressions. See [Chapter 2](LangImpl02.md) for details. By
using operator precedence parsing, it is very easy to allow
the programmer to introduce new operators into the grammar: the grammar
is dynamically extensible as the JIT runs.
@@ -48,31 +43,31 @@ The two specific features we'll add are programmable unary operators
(right now, Kaleidoscope has no unary operators at all) as well as
binary operators. An example of this is:
-::
-
- # Logical unary not.
- def unary!(v)
- if v then
- 0
- else
- 1;
-
- # Define > with the same precedence as <.
- def binary> 10 (LHS RHS)
- RHS < LHS;
-
- # Binary "logical or", (note that it does not "short circuit")
- def binary| 5 (LHS RHS)
- if LHS then
- 1
- else if RHS then
- 1
- else
- 0;
-
- # Define = with slightly lower precedence than relationals.
- def binary= 9 (LHS RHS)
- !(LHS < RHS | LHS > RHS);
+```
+# Logical unary not.
+def unary!(v)
+ if v then
+ 0
+ else
+ 1;
+
+# Define > with the same precedence as <.
+def binary> 10 (LHS RHS)
+ RHS < LHS;
+
+# Binary "logical or", (note that it does not "short circuit")
+def binary| 5 (LHS RHS)
+ if LHS then
+ 1
+ else if RHS then
+ 1
+ else
+ 0;
+
+# Define = with slightly lower precedence than relationals.
+def binary= 9 (LHS RHS)
+ !(LHS < RHS | LHS > RHS);
+```
Many languages aspire to being able to implement their standard runtime
library in the language itself. In Kaleidoscope, we can implement
@@ -82,78 +77,77 @@ We will break down implementation of these features into two parts:
implementing support for user-defined binary operators and adding unary
operators.
-User-defined Binary Operators
-=============================
+## User-defined Binary Operators
Adding support for user-defined binary operators is pretty simple with
our current framework. We'll first add support for the unary/binary
keywords:
-.. code-block:: c++
-
- enum Token {
- ...
- // operators
- tok_binary = -11,
- tok_unary = -12
- };
- ...
- static int gettok() {
- ...
- if (IdentifierStr == "for")
- return tok_for;
- if (IdentifierStr == "in")
- return tok_in;
- if (IdentifierStr == "binary")
- return tok_binary;
- if (IdentifierStr == "unary")
- return tok_unary;
- return tok_identifier;
+```c++
+enum Token {
+ ...
+ // operators
+ tok_binary = -11,
+ tok_unary = -12
+};
+...
+static int gettok() {
+...
+ if (IdentifierStr == "for")
+ return tok_for;
+ if (IdentifierStr == "in")
+ return tok_in;
+ if (IdentifierStr == "binary")
+ return tok_binary;
+ if (IdentifierStr == "unary")
+ return tok_unary;
+ return tok_identifier;
+```
This just adds lexer support for the unary and binary keywords, like we
-did in `previous chapters <LangImpl05.html#lexer-extensions-for-if-then-else>`_. One nice thing
+did in [previous chapters](LangImpl05.md#lexer-extensions-for-if-then-else). One nice thing
about our current AST, is that we represent binary operators with full
generalisation by using their ASCII code as the opcode. For our extended
operators, we'll use this same representation, so we don't need any new
AST or parser support.
On the other hand, we have to be able to represent the definitions of
-these new operators, in the "def binary\| 5" part of the function
+these new operators, in the "def binary| 5" part of the function
definition. In our grammar so far, the "name" for the function
definition is parsed as the "prototype" production and into the
-``PrototypeAST`` AST node. To represent our new user-defined operators
-as prototypes, we have to extend the ``PrototypeAST`` AST node like
+`PrototypeAST` AST node. To represent our new user-defined operators
+as prototypes, we have to extend the `PrototypeAST` AST node like
this:
-.. code-block:: c++
+```c++
+/// PrototypeAST - This class represents the "prototype" for a function,
+/// which captures its argument names as well as if it is an operator.
+class PrototypeAST {
+ std::string Name;
+ std::vector<std::string> Args;
+ bool IsOperator;
+ unsigned Precedence; // Precedence if a binary op.
- /// PrototypeAST - This class represents the "prototype" for a function,
- /// which captures its argument names as well as if it is an operator.
- class PrototypeAST {
- std::string Name;
- std::vector<std::string> Args;
- bool IsOperator;
- unsigned Precedence; // Precedence if a binary op.
+public:
+ PrototypeAST(const std::string &Name, std::vector<std::string> Args,
+ bool IsOperator = false, unsigned Prec = 0)
+ : Name(Name), Args(std::move(Args)), IsOperator(IsOperator),
+ Precedence(Prec) {}
- public:
- PrototypeAST(const std::string &Name, std::vector<std::string> Args,
- bool IsOperator = false, unsigned Prec = 0)
- : Name(Name), Args(std::move(Args)), IsOperator(IsOperator),
- Precedence(Prec) {}
+ Function *codegen();
+ const std::string &getName() const { return Name; }
- Function *codegen();
- const std::string &getName() const { return Name; }
+ bool isUnaryOp() const { return IsOperator && Args.size() == 1; }
+ bool isBinaryOp() const { return IsOperator && Args.size() == 2; }
- bool isUnaryOp() const { return IsOperator && Args.size() == 1; }
- bool isBinaryOp() const { return IsOperator && Args.size() == 2; }
+ char getOperatorName() const {
+ assert(isUnaryOp() || isBinaryOp());
+ return Name[Name.size() - 1];
+ }
- char getOperatorName() const {
- assert(isUnaryOp() || isBinaryOp());
- return Name[Name.size() - 1];
- }
-
- unsigned getBinaryPrecedence() const { return Precedence; }
- };
+ unsigned getBinaryPrecedence() const { return Precedence; }
+};
+```
Basically, in addition to knowing a name for the prototype, we now keep
track of whether it was an operator, and if it was, what precedence
@@ -162,67 +156,67 @@ operators (as you'll see below, it just doesn't apply for unary
operators). Now that we have a way to represent the prototype for a
user-defined operator, we need to parse it:
-.. code-block:: c++
-
- /// prototype
- /// ::= id '(' id* ')'
- /// ::= binary LETTER number? (id, id)
- static std::unique_ptr<PrototypeAST> ParsePrototype() {
- std::string FnName;
-
- unsigned Kind = 0; // 0 = identifier, 1 = unary, 2 = binary.
- unsigned BinaryPrecedence = 30;
-
- switch (CurTok) {
- default:
- return LogErrorP("Expected function name in prototype");
- case tok_identifier:
- FnName = IdentifierStr;
- Kind = 0;
- getNextToken();
- break;
- case tok_binary:
- getNextToken();
- if (!isascii(CurTok))
- return LogErrorP("Expected binary operator");
- FnName = "binary";
- FnName += (char)CurTok;
- Kind = 2;
- getNextToken();
-
- // Read the precedence if present.
- if (CurTok == tok_number) {
- if (NumVal < 1 || NumVal > 100)
- return LogErrorP("Invalid precedence: must be 1..100");
- BinaryPrecedence = (unsigned)NumVal;
- getNextToken();
- }
- break;
- }
-
- if (CurTok != '(')
- return LogErrorP("Expected '(' in prototype");
-
- std::vector<std::string> ArgNames;
- while (getNextToken() == tok_identifier)
- ArgNames.push_back(IdentifierStr);
- if (CurTok != ')')
- return LogErrorP("Expected ')' in prototype");
-
- // success.
- getNextToken(); // eat ')'.
-
- // Verify right number of names for operator.
- if (Kind && ArgNames.size() != Kind)
- return LogErrorP("Invalid number of operands for operator");
-
- return std::make_unique<PrototypeAST>(FnName, std::move(ArgNames), Kind != 0,
- BinaryPrecedence);
+```c++
+/// prototype
+/// ::= id '(' id* ')'
+/// ::= binary LETTER number? (id, id)
+static std::unique_ptr<PrototypeAST> ParsePrototype() {
+ std::string FnName;
+
+ unsigned Kind = 0; // 0 = identifier, 1 = unary, 2 = binary.
+ unsigned BinaryPrecedence = 30;
+
+ switch (CurTok) {
+ default:
+ return LogErrorP("Expected function name in prototype");
+ case tok_identifier:
+ FnName = IdentifierStr;
+ Kind = 0;
+ getNextToken();
+ break;
+ case tok_binary:
+ getNextToken();
+ if (!isascii(CurTok))
+ return LogErrorP("Expected binary operator");
+ FnName = "binary";
+ FnName += (char)CurTok;
+ Kind = 2;
+ getNextToken();
+
+ // Read the precedence if present.
+ if (CurTok == tok_number) {
+ if (NumVal < 1 || NumVal > 100)
+ return LogErrorP("Invalid precedence: must be 1..100");
+ BinaryPrecedence = (unsigned)NumVal;
+ getNextToken();
}
+ break;
+ }
+
+ if (CurTok != '(')
+ return LogErrorP("Expected '(' in prototype");
+
+ std::vector<std::string> ArgNames;
+ while (getNextToken() == tok_identifier)
+ ArgNames.push_back(IdentifierStr);
+ if (CurTok != ')')
+ return LogErrorP("Expected ')' in prototype");
+
+ // success.
+ getNextToken(); // eat ')'.
+
+ // Verify right number of names for operator.
+ if (Kind && ArgNames.size() != Kind)
+ return LogErrorP("Invalid number of operands for operator");
+
+ return std::make_unique<PrototypeAST>(FnName, std::move(ArgNames), Kind != 0,
+ BinaryPrecedence);
+}
+```
This is all fairly straightforward parsing code, and we have already
seen a lot of similar code in the past. One interesting part about the
-code above is the couple lines that set up ``FnName`` for binary
+code above is the couple lines that set up `FnName` for binary
operators. This builds names like "binary@" for a newly defined "@"
operator. It then takes advantage of the fact that symbol names in the
LLVM symbol table are allowed to have any character in them, including
@@ -232,38 +226,38 @@ The next interesting thing to add, is codegen support for these binary
operators. Given our current structure, this is a simple addition of a
default case for our existing binary operator node:
-.. code-block:: c++
-
- Value *BinaryExprAST::codegen() {
- Value *L = LHS->codegen();
- Value *R = RHS->codegen();
- if (!L || !R)
- return nullptr;
-
- switch (Op) {
- case '+':
- return Builder->CreateFAdd(L, R, "addtmp");
- case '-':
- return Builder->CreateFSub(L, R, "subtmp");
- case '*':
- return Builder->CreateFMul(L, R, "multmp");
- case '<':
- L = Builder->CreateFCmpULT(L, R, "cmptmp");
- // Convert bool 0/1 to double 0.0 or 1.0
- return Builder->CreateUIToFP(L, Type::getDoubleTy(*TheContext),
- "booltmp");
- default:
- break;
- }
-
- // If it wasn't a builtin binary operator, it must be a user defined one. Emit
- // a call to it.
- Function *F = getFunction(std::string("binary") + Op);
- assert(F && "binary operator not found!");
-
- Value *Ops[2] = { L, R };
- return Builder->CreateCall(F, Ops, "binop");
- }
+```c++
+Value *BinaryExprAST::codegen() {
+ Value *L = LHS->codegen();
+ Value *R = RHS->codegen();
+ if (!L || !R)
+ return nullptr;
+
+ switch (Op) {
+ case '+':
+ return Builder->CreateFAdd(L, R, "addtmp");
+ case '-':
+ return Builder->CreateFSub(L, R, "subtmp");
+ case '*':
+ return Builder->CreateFMul(L, R, "multmp");
+ case '<':
+ L = Builder->CreateFCmpULT(L, R, "cmptmp");
+ // Convert bool 0/1 to double 0.0 or 1.0
+ return Builder->CreateUIToFP(L, Type::getDoubleTy(*TheContext),
+ "booltmp");
+ default:
+ break;
+ }
+
+ // If it wasn't a builtin binary operator, it must be a user defined one. Emit
+ // a call to it.
+ Function *F = getFunction(std::string("binary") + Op);
+ assert(F && "binary operator not found!");
+
+ Value *Ops[2] = { L, R };
+ return Builder->CreateCall(F, Ops, "binop");
+}
+```
As you can see above, the new code is actually really simple. It just
does a lookup for the appropriate operator in the symbol table and
@@ -273,24 +267,24 @@ function with the right name) everything falls into place.
The final piece of code we are missing, is a bit of top-level magic:
-.. code-block:: c++
-
- Function *FunctionAST::codegen() {
- // Transfer ownership of the prototype to the FunctionProtos map, but keep a
- // reference to it for use below.
- auto &P = *Proto;
- FunctionProtos[Proto->getName()] = std::move(Proto);
- Function *TheFunction = getFunction(P.getName());
- if (!TheFunction)
- return nullptr;
-
- // If this is an operator, install it.
- if (P.isBinaryOp())
- BinopPrecedence[P.getOperatorName()] = P.getBinaryPrecedence();
-
- // Create a new basic block to start insertion into.
- BasicBlock *BB = BasicBlock::Create(*TheContext, "entry", TheFunction);
- ...
+```c++
+Function *FunctionAST::codegen() {
+ // Transfer ownership of the prototype to the FunctionProtos map, but keep a
+ // reference to it for use below.
+ auto &P = *Proto;
+ FunctionProtos[Proto->getName()] = std::move(Proto);
+ Function *TheFunction = getFunction(P.getName());
+ if (!TheFunction)
+ return nullptr;
+
+ // If this is an operator, install it.
+ if (P.isBinaryOp())
+ BinopPrecedence[P.getOperatorName()] = P.getBinaryPrecedence();
+
+ // Create a new basic block to start insertion into.
+ BasicBlock *BB = BasicBlock::Create(*TheContext, "entry", TheFunction);
+ ...
+```
Basically, before codegening a function, if it is a user-defined
operator, we register it in the precedence table. This allows the binary
@@ -303,50 +297,49 @@ the previous framework we built for other operators. Adding unary
operators is a bit more challenging, because we don't have any framework
for it yet - let's see what it takes.
-User-defined Unary Operators
-============================
+## User-defined Unary Operators
Since we don't currently support unary operators in the Kaleidoscope
language, we'll need to add everything to support them. Above, we added
simple support for the 'unary' keyword to the lexer. In addition to
that, we need an AST node:
-.. code-block:: c++
-
- /// UnaryExprAST - Expression class for a unary operator.
- class UnaryExprAST : public ExprAST {
- char Opcode;
- std::unique_ptr<ExprAST> Operand;
+```c++
+/// UnaryExprAST - Expression class for a unary operator.
+class UnaryExprAST : public ExprAST {
+ char Opcode;
+ std::unique_ptr<ExprAST> Operand;
- public:
- UnaryExprAST(char Opcode, std::unique_ptr<ExprAST> Operand)
- : Opcode(Opcode), Operand(std::move(Operand)) {}
+public:
+ UnaryExprAST(char Opcode, std::unique_ptr<ExprAST> Operand)
+ : Opcode(Opcode), Operand(std::move(Operand)) {}
- Value *codegen() override;
- };
+ Value *codegen() override;
+};
+```
This AST node is very simple and obvious by now. It directly mirrors the
binary operator AST node, except that it only has one child. With this,
we need to add the parsing logic. Parsing a unary operator is pretty
simple: we'll add a new function to do it:
-.. code-block:: c++
-
- /// unary
- /// ::= primary
- /// ::= '!' unary
- static std::unique_ptr<ExprAST> ParseUnary() {
- // If the current token is not an operator, it must be a primary expr.
- if (!isascii(CurTok) || CurTok == '(' || CurTok == ',')
- return ParsePrimary();
-
- // If this is a unary operator, read it.
- int Opc = CurTok;
- getNextToken();
- if (auto Operand = ParseUnary())
- return std::make_unique<UnaryExprAST>(Opc, std::move(Operand));
- return nullptr;
- }
+```c++
+/// unary
+/// ::= primary
+/// ::= '!' unary
+static std::unique_ptr<ExprAST> ParseUnary() {
+ // If the current token is not an operator, it must be a primary expr.
+ if (!isascii(CurTok) || CurTok == '(' || CurTok == ',')
+ return ParsePrimary();
+
+ // If this is a unary operator, read it.
+ int Opc = CurTok;
+ getNextToken();
+ if (auto Operand = ParseUnary())
+ return std::make_unique<UnaryExprAST>(Opc, std::move(Operand));
+ return nullptr;
+}
+```
The grammar we add is pretty straightforward here. If we see a unary
operator when parsing a primary operator, we eat the operator as a
@@ -359,92 +352,91 @@ The problem with this function, is that we need to call ParseUnary from
somewhere. To do this, we change previous callers of ParsePrimary to
call ParseUnary instead:
-.. code-block:: c++
-
- /// binoprhs
- /// ::= ('+' unary)*
- static std::unique_ptr<ExprAST> ParseBinOpRHS(int ExprPrec,
- std::unique_ptr<ExprAST> LHS) {
- ...
- // Parse the unary expression after the binary operator.
- auto RHS = ParseUnary();
- if (!RHS)
- return nullptr;
- ...
- }
- /// expression
- /// ::= unary binoprhs
- ///
- static std::unique_ptr<ExprAST> ParseExpression() {
- auto LHS = ParseUnary();
- if (!LHS)
- return nullptr;
-
- return ParseBinOpRHS(0, std::move(LHS));
- }
+```c++
+/// binoprhs
+/// ::= ('+' unary)*
+static std::unique_ptr<ExprAST> ParseBinOpRHS(int ExprPrec,
+ std::unique_ptr<ExprAST> LHS) {
+ ...
+ // Parse the unary expression after the binary operator.
+ auto RHS = ParseUnary();
+ if (!RHS)
+ return nullptr;
+ ...
+}
+/// expression
+/// ::= unary binoprhs
+///
+static std::unique_ptr<ExprAST> ParseExpression() {
+ auto LHS = ParseUnary();
+ if (!LHS)
+ return nullptr;
+
+ return ParseBinOpRHS(0, std::move(LHS));
+}
+```
With these two simple changes, we are now able to parse unary operators
and build the AST for them. Next up, we need to add parser support for
prototypes, to parse the unary operator prototype. We extend the binary
operator code above with:
-.. code-block:: c++
-
- /// prototype
- /// ::= id '(' id* ')'
- /// ::= binary LETTER number? (id, id)
- /// ::= unary LETTER (id)
- static std::unique_ptr<PrototypeAST> ParsePrototype() {
- std::string FnName;
-
- unsigned Kind = 0; // 0 = identifier, 1 = unary, 2 = binary.
- unsigned BinaryPrecedence = 30;
-
- switch (CurTok) {
- default:
- return LogErrorP("Expected function name in prototype");
- case tok_identifier:
- FnName = IdentifierStr;
- Kind = 0;
- getNextToken();
- break;
- case tok_unary:
- getNextToken();
- if (!isascii(CurTok))
- return LogErrorP("Expected unary operator");
- FnName = "unary";
- FnName += (char)CurTok;
- Kind = 1;
- getNextToken();
- break;
- case tok_binary:
- ...
+```c++
+/// prototype
+/// ::= id '(' id* ')'
+/// ::= binary LETTER number? (id, id)
+/// ::= unary LETTER (id)
+static std::unique_ptr<PrototypeAST> ParsePrototype() {
+ std::string FnName;
+
+ unsigned Kind = 0; // 0 = identifier, 1 = unary, 2 = binary.
+ unsigned BinaryPrecedence = 30;
+
+ switch (CurTok) {
+ default:
+ return LogErrorP("Expected function name in prototype");
+ case tok_identifier:
+ FnName = IdentifierStr;
+ Kind = 0;
+ getNextToken();
+ break;
+ case tok_unary:
+ getNextToken();
+ if (!isascii(CurTok))
+ return LogErrorP("Expected unary operator");
+ FnName = "unary";
+ FnName += (char)CurTok;
+ Kind = 1;
+ getNextToken();
+ break;
+ case tok_binary:
+ ...
+```
As with binary operators, we name unary operators with a name that
includes the operator character. This assists us at code generation
time. Speaking of, the final piece we need to add is codegen support for
unary operators. It looks like this:
-.. code-block:: c++
+```c++
+Value *UnaryExprAST::codegen() {
+ Value *OperandV = Operand->codegen();
+ if (!OperandV)
+ return nullptr;
- Value *UnaryExprAST::codegen() {
- Value *OperandV = Operand->codegen();
- if (!OperandV)
- return nullptr;
+ Function *F = getFunction(std::string("unary") + Opcode);
+ if (!F)
+ return LogErrorV("Unknown unary operator");
- Function *F = getFunction(std::string("unary") + Opcode);
- if (!F)
- return LogErrorV("Unknown unary operator");
-
- return Builder->CreateCall(F, OperandV, "unop");
- }
+ return Builder->CreateCall(F, OperandV, "unop");
+}
+```
This code is similar to, but simpler than, the code for binary
operators. It is simpler primarily because it doesn't need to handle any
predefined operators.
-Kicking the Tires
-=================
+## Kicking the Tires
It is somewhat hard to believe, but with a few simple extensions we've
covered in the last chapters, we have grown a real-ish language. With
@@ -453,270 +445,270 @@ bunch of other things. For example, we can now add a nice sequencing
operator (printd is defined to print out the specified value and a
newline):
-::
-
- ready> extern printd(x);
- Read extern:
- declare double @printd(double)
+```
+ready> extern printd(x);
+Read extern:
+declare double @printd(double)
- ready> def binary : 1 (x y) 0; # Low-precedence operator that ignores operands.
- ...
- ready> printd(123) : printd(456) : printd(789);
- 123.000000
- 456.000000
- 789.000000
- Evaluated to 0.000000
+ready> def binary : 1 (x y) 0; # Low-precedence operator that ignores operands.
+...
+ready> printd(123) : printd(456) : printd(789);
+123.000000
+456.000000
+789.000000
+Evaluated to 0.000000
+```
We can also define a bunch of other "primitive" operations, such as:
-::
-
- # Logical unary not.
- def unary!(v)
- if v then
- 0
- else
- 1;
-
- # Unary negate.
- def unary-(v)
- 0-v;
-
- # Define > with the same precedence as <.
- def binary> 10 (LHS RHS)
- RHS < LHS;
-
- # Binary logical or, which does not short circuit.
- def binary| 5 (LHS RHS)
- if LHS then
- 1
- else if RHS then
- 1
- else
- 0;
-
- # Binary logical and, which does not short circuit.
- def binary& 6 (LHS RHS)
- if !LHS then
- 0
- else
- !!RHS;
-
- # Define = with slightly lower precedence than relationals.
- def binary = 9 (LHS RHS)
- !(LHS < RHS | LHS > RHS);
-
- # Define ':' for sequencing: as a low-precedence operator that ignores operands
- # and just returns the RHS.
- def binary : 1 (x y) y;
+```
+# Logical unary not.
+def unary!(v)
+ if v then
+ 0
+ else
+ 1;
+
+# Unary negate.
+def unary-(v)
+ 0-v;
+
+# Define > with the same precedence as <.
+def binary> 10 (LHS RHS)
+ RHS < LHS;
+
+# Binary logical or, which does not short circuit.
+def binary| 5 (LHS RHS)
+ if LHS then
+ 1
+ else if RHS then
+ 1
+ else
+ 0;
+
+# Binary logical and, which does not short circuit.
+def binary& 6 (LHS RHS)
+ if !LHS then
+ 0
+ else
+ !!RHS;
+
+# Define = with slightly lower precedence than relationals.
+def binary = 9 (LHS RHS)
+ !(LHS < RHS | LHS > RHS);
+
+# Define ':' for sequencing: as a low-precedence operator that ignores operands
+# and just returns the RHS.
+def binary : 1 (x y) y;
+```
Given the previous if/then/else support, we can also define interesting
functions for I/O. For example, the following prints out a character
whose "density" reflects the value passed in: the lower the value, the
denser the character:
-::
-
- ready> extern putchard(char);
- ...
- ready> def printdensity(d)
- if d > 8 then
- putchard(32) # ' '
- else if d > 4 then
- putchard(46) # '.'
- else if d > 2 then
- putchard(43) # '+'
- else
- putchard(42); # '*'
- ...
- ready> printdensity(1): printdensity(2): printdensity(3):
- printdensity(4): printdensity(5): printdensity(9):
- putchard(10);
- **++.
- Evaluated to 0.000000
+```
+ready> extern putchard(char);
+...
+ready> def printdensity(d)
+ if d > 8 then
+ putchard(32) # ' '
+ else if d > 4 then
+ putchard(46) # '.'
+ else if d > 2 then
+ putchard(43) # '+'
+ else
+ putchard(42); # '*'
+...
+ready> printdensity(1): printdensity(2): printdensity(3):
+ printdensity(4): printdensity(5): printdensity(9):
+ putchard(10);
+**++.
+Evaluated to 0.000000
+```
Based on these simple primitive operations, we can start to define more
interesting things. For example, here's a little function that determines
the number of iterations it takes for a certain function in the complex
plane to diverge:
-::
-
- # Determine whether the specific location diverges.
- # Solve for z = z^2 + c in the complex plane.
- def mandelconverger(real imag iters creal cimag)
- if iters > 255 | (real*real + imag*imag > 4) then
- iters
- else
- mandelconverger(real*real - imag*imag + creal,
- 2*real*imag + cimag,
- iters+1, creal, cimag);
-
- # Return the number of iterations required for the iteration to escape
- def mandelconverge(real imag)
- mandelconverger(real, imag, 0, real, imag);
-
-This "``z = z2 + c``" function is a beautiful little creature that is
-the basis for computation of the `Mandelbrot
-Set <http://en.wikipedia.org/wiki/Mandelbrot_set>`_. Our
-``mandelconverge`` function returns the number of iterations that it
+```
+# Determine whether the specific location diverges.
+# Solve for z = z^2 + c in the complex plane.
+def mandelconverger(real imag iters creal cimag)
+ if iters > 255 | (real*real + imag*imag > 4) then
+ iters
+ else
+ mandelconverger(real*real - imag*imag + creal,
+ 2*real*imag + cimag,
+ iters+1, creal, cimag);
+
+# Return the number of iterations required for the iteration to escape
+def mandelconverge(real imag)
+ mandelconverger(real, imag, 0, real, imag);
+```
+
+This "`z = z2 + c`" function is a beautiful little creature that is
+the basis for computation of the [Mandelbrot
+Set](http://en.wikipedia.org/wiki/Mandelbrot_set). Our
+`mandelconverge` function returns the number of iterations that it
takes for a complex orbit to escape, saturating to 255. This is not a
very useful function by itself, but if you plot its value over a
two-dimensional plane, you can see the Mandelbrot set. Given that we are
limited to using putchard here, our amazing graphical output is limited,
but we can whip together something using the density plotter above:
-::
-
- # Compute and plot the mandelbrot set with the specified 2 dimensional range
- # info.
- def mandelhelp(xmin xmax xstep ymin ymax ystep)
- for y = ymin, y < ymax, ystep in (
- (for x = xmin, x < xmax, xstep in
- printdensity(mandelconverge(x,y)))
- : putchard(10)
- )
-
- # mandel - This is a convenient helper function for plotting the mandelbrot set
- # from the specified position with the specified Magnification.
- def mandel(realstart imagstart realmag imagmag)
- mandelhelp(realstart, realstart+realmag*78, realmag,
- imagstart, imagstart+imagmag*40, imagmag);
+```
+# Compute and plot the mandelbrot set with the specified 2 dimensional range
+# info.
+def mandelhelp(xmin xmax xstep ymin ymax ystep)
+ for y = ymin, y < ymax, ystep in (
+ (for x = xmin, x < xmax, xstep in
+ printdensity(mandelconverge(x,y)))
+ : putchard(10)
+ )
+
+# mandel - This is a convenient helper function for plotting the mandelbrot set
+# from the specified position with the specified Magnification.
+def mandel(realstart imagstart realmag imagmag)
+ mandelhelp(realstart, realstart+realmag*78, realmag,
+ imagstart, imagstart+imagmag*40, imagmag);
+```
Given this, we can try plotting out the mandelbrot set! Lets try it out:
-::
-
- ready> mandel(-2.3, -1.3, 0.05, 0.07);
- *******************************+++++++++++*************************************
- *************************+++++++++++++++++++++++*******************************
- **********************+++++++++++++++++++++++++++++****************************
- *******************+++++++++++++++++++++.. ...++++++++*************************
- *****************++++++++++++++++++++++.... ...+++++++++***********************
- ***************+++++++++++++++++++++++..... ...+++++++++*********************
- **************+++++++++++++++++++++++.... ....+++++++++********************
- *************++++++++++++++++++++++...... .....++++++++*******************
- ************+++++++++++++++++++++....... .......+++++++******************
- ***********+++++++++++++++++++.... ... .+++++++*****************
- **********+++++++++++++++++....... .+++++++****************
- *********++++++++++++++........... ...+++++++***************
- ********++++++++++++............ ...++++++++**************
- ********++++++++++... .......... .++++++++**************
- *******+++++++++..... .+++++++++*************
- *******++++++++...... ..+++++++++*************
- *******++++++....... ..+++++++++*************
- *******+++++...... ..+++++++++*************
- *******.... .... ...+++++++++*************
- *******.... . ...+++++++++*************
- *******+++++...... ...+++++++++*************
- *******++++++....... ..+++++++++*************
- *******++++++++...... .+++++++++*************
- *******+++++++++..... ..+++++++++*************
- ********++++++++++... .......... .++++++++**************
- ********++++++++++++............ ...++++++++**************
- *********++++++++++++++.......... ...+++++++***************
- **********++++++++++++++++........ .+++++++****************
- **********++++++++++++++++++++.... ... ..+++++++****************
- ***********++++++++++++++++++++++....... .......++++++++*****************
- ************+++++++++++++++++++++++...... ......++++++++******************
- **************+++++++++++++++++++++++.... ....++++++++********************
- ***************+++++++++++++++++++++++..... ...+++++++++*********************
- *****************++++++++++++++++++++++.... ...++++++++***********************
- *******************+++++++++++++++++++++......++++++++*************************
- *********************++++++++++++++++++++++.++++++++***************************
- *************************+++++++++++++++++++++++*******************************
- ******************************+++++++++++++************************************
- *******************************************************************************
- *******************************************************************************
- *******************************************************************************
- Evaluated to 0.000000
- ready> mandel(-2, -1, 0.02, 0.04);
- **************************+++++++++++++++++++++++++++++++++++++++++++++++++++++
- ***********************++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- *********************+++++++++++++++++++++++++++++++++++++++++++++++++++++++++.
- *******************+++++++++++++++++++++++++++++++++++++++++++++++++++++++++...
- *****************+++++++++++++++++++++++++++++++++++++++++++++++++++++++++.....
- ***************++++++++++++++++++++++++++++++++++++++++++++++++++++++++........
- **************++++++++++++++++++++++++++++++++++++++++++++++++++++++...........
- ************+++++++++++++++++++++++++++++++++++++++++++++++++++++..............
- ***********++++++++++++++++++++++++++++++++++++++++++++++++++........ .
- **********++++++++++++++++++++++++++++++++++++++++++++++.............
- ********+++++++++++++++++++++++++++++++++++++++++++..................
- *******+++++++++++++++++++++++++++++++++++++++.......................
- ******+++++++++++++++++++++++++++++++++++...........................
- *****++++++++++++++++++++++++++++++++............................
- *****++++++++++++++++++++++++++++...............................
- ****++++++++++++++++++++++++++...... .........................
- ***++++++++++++++++++++++++......... ...... ...........
- ***++++++++++++++++++++++............
- **+++++++++++++++++++++..............
- **+++++++++++++++++++................
- *++++++++++++++++++.................
- *++++++++++++++++............ ...
- *++++++++++++++..............
- *+++....++++................
- *.......... ...........
- *
- *.......... ...........
- *+++....++++................
- *++++++++++++++..............
- *++++++++++++++++............ ...
- *++++++++++++++++++.................
- **+++++++++++++++++++................
- **+++++++++++++++++++++..............
- ***++++++++++++++++++++++............
- ***++++++++++++++++++++++++......... ...... ...........
- ****++++++++++++++++++++++++++...... .........................
- *****++++++++++++++++++++++++++++...............................
- *****++++++++++++++++++++++++++++++++............................
- ******+++++++++++++++++++++++++++++++++++...........................
- *******+++++++++++++++++++++++++++++++++++++++.......................
- ********+++++++++++++++++++++++++++++++++++++++++++..................
- Evaluated to 0.000000
- ready> mandel(-0.9, -1.4, 0.02, 0.03);
- *******************************************************************************
- *******************************************************************************
- *******************************************************************************
- **********+++++++++++++++++++++************************************************
- *+++++++++++++++++++++++++++++++++++++++***************************************
- +++++++++++++++++++++++++++++++++++++++++++++**********************************
- ++++++++++++++++++++++++++++++++++++++++++++++++++*****************************
- ++++++++++++++++++++++++++++++++++++++++++++++++++++++*************************
- +++++++++++++++++++++++++++++++++++++++++++++++++++++++++**********************
- +++++++++++++++++++++++++++++++++.........++++++++++++++++++*******************
- +++++++++++++++++++++++++++++++.... ......+++++++++++++++++++****************
- +++++++++++++++++++++++++++++....... ........+++++++++++++++++++**************
- ++++++++++++++++++++++++++++........ ........++++++++++++++++++++************
- +++++++++++++++++++++++++++......... .. ...+++++++++++++++++++++**********
- ++++++++++++++++++++++++++........... ....++++++++++++++++++++++********
- ++++++++++++++++++++++++............. .......++++++++++++++++++++++******
- +++++++++++++++++++++++............. ........+++++++++++++++++++++++****
- ++++++++++++++++++++++........... ..........++++++++++++++++++++++***
- ++++++++++++++++++++........... .........++++++++++++++++++++++*
- ++++++++++++++++++............ ...........++++++++++++++++++++
- ++++++++++++++++............... .............++++++++++++++++++
- ++++++++++++++................. ...............++++++++++++++++
- ++++++++++++.................. .................++++++++++++++
- +++++++++.................. .................+++++++++++++
- ++++++........ . ......... ..++++++++++++
- ++............ ...... ....++++++++++
- .............. ...++++++++++
- .............. ....+++++++++
- .............. .....++++++++
- ............. ......++++++++
- ........... .......++++++++
- ......... ........+++++++
- ......... ........+++++++
- ......... ....+++++++
- ........ ...+++++++
- ....... ...+++++++
- ....+++++++
- .....+++++++
- ....+++++++
- ....+++++++
- ....+++++++
- Evaluated to 0.000000
- ready> ^D
+```
+ready> mandel(-2.3, -1.3, 0.05, 0.07);
+*******************************+++++++++++*************************************
+*************************+++++++++++++++++++++++*******************************
+**********************+++++++++++++++++++++++++++++****************************
+*******************+++++++++++++++++++++.. ...++++++++*************************
+*****************++++++++++++++++++++++.... ...+++++++++***********************
+***************+++++++++++++++++++++++..... ...+++++++++*********************
+**************+++++++++++++++++++++++.... ....+++++++++********************
+*************++++++++++++++++++++++...... .....++++++++*******************
+************+++++++++++++++++++++....... .......+++++++******************
+***********+++++++++++++++++++.... ... .+++++++*****************
+**********+++++++++++++++++....... .+++++++****************
+*********++++++++++++++........... ...+++++++***************
+********++++++++++++............ ...++++++++**************
+********++++++++++... .......... .++++++++**************
+*******+++++++++..... .+++++++++*************
+*******++++++++...... ..+++++++++*************
+*******++++++....... ..+++++++++*************
+*******+++++...... ..+++++++++*************
+*******.... .... ...+++++++++*************
+*******.... . ...+++++++++*************
+*******+++++...... ...+++++++++*************
+*******++++++....... ..+++++++++*************
+*******++++++++...... .+++++++++*************
+*******+++++++++..... ..+++++++++*************
+********++++++++++... .......... .++++++++**************
+********++++++++++++............ ...++++++++**************
+*********++++++++++++++.......... ...+++++++***************
+**********++++++++++++++++........ .+++++++****************
+**********++++++++++++++++++++.... ... ..+++++++****************
+***********++++++++++++++++++++++....... .......++++++++*****************
+************+++++++++++++++++++++++...... ......++++++++******************
+**************+++++++++++++++++++++++.... ....++++++++********************
+***************+++++++++++++++++++++++..... ...+++++++++*********************
+*****************++++++++++++++++++++++.... ...++++++++***********************
+*******************+++++++++++++++++++++......++++++++*************************
+*********************++++++++++++++++++++++.++++++++***************************
+*************************+++++++++++++++++++++++*******************************
+******************************+++++++++++++************************************
+*******************************************************************************
+*******************************************************************************
+*******************************************************************************
+Evaluated to 0.000000
+ready> mandel(-2, -1, 0.02, 0.04);
+**************************+++++++++++++++++++++++++++++++++++++++++++++++++++++
+***********************++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+*********************+++++++++++++++++++++++++++++++++++++++++++++++++++++++++.
+*******************+++++++++++++++++++++++++++++++++++++++++++++++++++++++++...
+*****************+++++++++++++++++++++++++++++++++++++++++++++++++++++++++.....
+***************++++++++++++++++++++++++++++++++++++++++++++++++++++++++........
+**************++++++++++++++++++++++++++++++++++++++++++++++++++++++...........
+************+++++++++++++++++++++++++++++++++++++++++++++++++++++..............
+***********++++++++++++++++++++++++++++++++++++++++++++++++++........ .
+**********++++++++++++++++++++++++++++++++++++++++++++++.............
+********+++++++++++++++++++++++++++++++++++++++++++..................
+*******+++++++++++++++++++++++++++++++++++++++.......................
+******+++++++++++++++++++++++++++++++++++...........................
+*****++++++++++++++++++++++++++++++++............................
+*****++++++++++++++++++++++++++++...............................
+****++++++++++++++++++++++++++...... .........................
+***++++++++++++++++++++++++......... ...... ...........
+***++++++++++++++++++++++............
+**+++++++++++++++++++++..............
+**+++++++++++++++++++................
+*++++++++++++++++++.................
+*++++++++++++++++............ ...
+*++++++++++++++..............
+*+++....++++................
+*.......... ...........
+*
+*.......... ...........
+*+++....++++................
+*++++++++++++++..............
+*++++++++++++++++............ ...
+*++++++++++++++++++.................
+**+++++++++++++++++++................
+**+++++++++++++++++++++..............
+***++++++++++++++++++++++............
+***++++++++++++++++++++++++......... ...... ...........
+****++++++++++++++++++++++++++...... .........................
+*****++++++++++++++++++++++++++++...............................
+*****++++++++++++++++++++++++++++++++............................
+******+++++++++++++++++++++++++++++++++++...........................
+*******+++++++++++++++++++++++++++++++++++++++.......................
+********+++++++++++++++++++++++++++++++++++++++++++..................
+Evaluated to 0.000000
+ready> mandel(-0.9, -1.4, 0.02, 0.03);
+*******************************************************************************
+*******************************************************************************
+*******************************************************************************
+**********+++++++++++++++++++++************************************************
+*+++++++++++++++++++++++++++++++++++++++***************************************
++++++++++++++++++++++++++++++++++++++++++++++**********************************
+++++++++++++++++++++++++++++++++++++++++++++++++++*****************************
+++++++++++++++++++++++++++++++++++++++++++++++++++++++*************************
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++**********************
++++++++++++++++++++++++++++++++++.........++++++++++++++++++*******************
++++++++++++++++++++++++++++++++.... ......+++++++++++++++++++****************
++++++++++++++++++++++++++++++....... ........+++++++++++++++++++**************
+++++++++++++++++++++++++++++........ ........++++++++++++++++++++************
++++++++++++++++++++++++++++......... .. ...+++++++++++++++++++++**********
+++++++++++++++++++++++++++........... ....++++++++++++++++++++++********
+++++++++++++++++++++++++............. .......++++++++++++++++++++++******
++++++++++++++++++++++++............. ........+++++++++++++++++++++++****
+++++++++++++++++++++++........... ..........++++++++++++++++++++++***
+++++++++++++++++++++........... .........++++++++++++++++++++++*
+++++++++++++++++++............ ...........++++++++++++++++++++
+++++++++++++++++............... .............++++++++++++++++++
+++++++++++++++................. ...............++++++++++++++++
+++++++++++++.................. .................++++++++++++++
++++++++++.................. .................+++++++++++++
+++++++........ . ......... ..++++++++++++
+++............ ...... ....++++++++++
+.............. ...++++++++++
+.............. ....+++++++++
+.............. .....++++++++
+............. ......++++++++
+........... .......++++++++
+......... ........+++++++
+......... ........+++++++
+......... ....+++++++
+........ ...+++++++
+....... ...+++++++
+ ....+++++++
+ .....+++++++
+ ....+++++++
+ ....+++++++
+ ....+++++++
+Evaluated to 0.000000
+ready> ^D
+```
At this point, you may be starting to realize that Kaleidoscope is a
real and powerful language. It may not be self-similar :), but it can be
@@ -731,23 +723,22 @@ applications that are functional and can call functions with
side-effects, but it can't actually define and mutate a variable itself.
Strikingly, variable mutation is an important feature of some languages,
-and it is not at all obvious how to `add support for mutable
-variables <LangImpl07.html>`_ without having to add an "SSA construction"
+and it is not at all obvious how to [add support for mutable
+variables](LangImpl07.md) without having to add an "SSA construction"
phase to your front-end. In the next chapter, we will describe how you
can add variable mutation without building SSA in your front-end.
-Full Code Listing
-=================
+## Full Code Listing
Here is the complete code listing for our running example, enhanced with
the support for user-defined operators. To build this example, use:
-.. code-block:: bash
-
- # Compile
- clang++ -g toy.cpp `llvm-config --cxxflags --ldflags --system-libs --libs core orcjit native` -O3 -o toy
- # Run
- ./toy
+```bash
+# Compile
+clang++ -g toy.cpp `llvm-config --cxxflags --ldflags --system-libs --libs core orcjit native` -O3 -o toy
+# Run
+./toy
+```
On some platforms, you will need to specify -rdynamic or
-Wl,--export-dynamic when linking. This ensures that symbols defined in
@@ -758,9 +749,10 @@ will cause problems on Windows.
Here is the code:
-.. literalinclude:: ../../../examples/Kaleidoscope/Chapter6/toy.cpp
- :language: c++
+```{literalinclude} ../../../examples/Kaleidoscope/Chapter6/toy.cpp
+:language: c++
+```
-`Next: Extending the language: mutable variables / SSA
-construction <LangImpl07.html>`_
+[Next: Extending the language: mutable variables / SSA
+construction](LangImpl07.md)
diff --git a/llvm/docs/tutorial/MyFirstLanguageFrontend/LangImpl07.md b/llvm/docs/tutorial/MyFirstLanguageFrontend/LangImpl07.md
index 21158f6b9ab62..56e71f5679b99 100644
--- a/llvm/docs/tutorial/MyFirstLanguageFrontend/LangImpl07.md
+++ b/llvm/docs/tutorial/MyFirstLanguageFrontend/LangImpl07.md
@@ -1,15 +1,11 @@
-=======================================================
-Kaleidoscope: Extending the Language: Mutable Variables
-=======================================================
+# Kaleidoscope: Extending the Language: Mutable Variables
+## Chapter 7 Introduction
-Chapter 7 Introduction
-======================
-
-Welcome to Chapter 7 of the "`Implementing a language with
-LLVM <index.html>`_" tutorial. In chapters 1 through 6, we've built a
-very respectable, albeit simple, `functional programming
-language <http://en.wikipedia.org/wiki/Functional_programming>`_. In our
+Welcome to Chapter 7 of the "[Implementing a language with
+LLVM](index.md)" tutorial. In chapters 1 through 6, we've built a
+very respectable, albeit simple, [functional programming
+language](http://en.wikipedia.org/wiki/Functional_programming). In our
journey, we learned some parsing techniques, how to build and represent
an AST, how to build LLVM IR, and how to optimize the resultant code as
well as JIT compile it.
@@ -17,8 +13,8 @@ well as JIT compile it.
While Kaleidoscope is interesting as a functional language, the fact
that it is functional makes it "too easy" to generate LLVM IR for it. In
particular, a functional language makes it very easy to build LLVM IR
-directly in `SSA
-form <http://en.wikipedia.org/wiki/Static_single_assignment_form>`_.
+directly in [SSA
+form](http://en.wikipedia.org/wiki/Static_single_assignment_form).
Since LLVM requires that the input code be in SSA form, this is a very
nice property and it is often unclear to newcomers how to generate code
for an imperative language with mutable variables.
@@ -28,61 +24,60 @@ for your front-end to build SSA form: LLVM provides highly tuned and
well tested support for this, though the way it works is a bit
unexpected for some.
-Why is this a hard problem?
-===========================
+## Why is this a hard problem?
To understand why mutable variables cause complexities in SSA
construction, consider this extremely simple C example:
-.. code-block:: c
-
- int G, H;
- int test(_Bool Condition) {
- int X;
- if (Condition)
- X = G;
- else
- X = H;
- return X;
- }
+```c
+int G, H;
+int test(_Bool Condition) {
+ int X;
+ if (Condition)
+ X = G;
+ else
+ X = H;
+ return X;
+}
+```
In this case, we have the variable "X", whose value depends on the path
executed in the program. Because there are two
diff erent possible values
for X before the return instruction, a PHI node is inserted to merge the
two values. The LLVM IR that we want for this example looks like this:
-.. code-block:: llvm
+```llvm
+ at G = weak global i32 0 ; type of @G is i32*
+ at H = weak global i32 0 ; type of @H is i32*
- @G = weak global i32 0 ; type of @G is i32*
- @H = weak global i32 0 ; type of @H is i32*
+define i32 @test(i1 %Condition) {
+entry:
+ br i1 %Condition, label %cond_true, label %cond_false
- define i32 @test(i1 %Condition) {
- entry:
- br i1 %Condition, label %cond_true, label %cond_false
+cond_true:
+ %X.0 = load i32, i32* @G
+ br label %cond_next
- cond_true:
- %X.0 = load i32, i32* @G
- br label %cond_next
+cond_false:
+ %X.1 = load i32, i32* @H
+ br label %cond_next
- cond_false:
- %X.1 = load i32, i32* @H
- br label %cond_next
-
- cond_next:
- %X.2 = phi i32 [ %X.1, %cond_false ], [ %X.0, %cond_true ]
- ret i32 %X.2
- }
+cond_next:
+ %X.2 = phi i32 [ %X.1, %cond_false ], [ %X.0, %cond_true ]
+ ret i32 %X.2
+}
+```
In this example, the loads from the G and H global variables are
explicit in the LLVM IR, and they live in the then/else branches of the
-if statement (cond\_true/cond\_false). In order to merge the incoming
-values, the X.2 phi node in the cond\_next block selects the right value
+if statement (cond_true/cond_false). In order to merge the incoming
+values, the X.2 phi node in the cond_next block selects the right value
to use based on where control flow is coming from: if control flow comes
-from the cond\_false block, X.2 gets the value of X.1. Alternatively, if
-control flow comes from cond\_true, it gets the value of X.0. The intent
+from the cond_false block, X.2 gets the value of X.1. Alternatively, if
+control flow comes from cond_true, it gets the value of X.0. The intent
of this chapter is not to explain the details of SSA form. For more
-information, see one of the many `online
-references <http://en.wikipedia.org/wiki/Static_single_assignment_form>`_.
+information, see one of the many [online
+references](http://en.wikipedia.org/wiki/Static_single_assignment_form).
The question for this article is "who places the phi nodes when lowering
assignments to mutable variables?". The issue here is that LLVM
@@ -91,8 +86,7 @@ it. However, SSA construction requires non-trivial algorithms and data
structures, so it is inconvenient and wasteful for every front-end to
have to reproduce this logic.
-Memory in LLVM
-==============
+## Memory in LLVM
The 'trick' here is that while LLVM does require all register values to
be in SSA form, it does not require (or permit) memory objects to be in
@@ -100,8 +94,8 @@ SSA form. In the example above, note that the loads from G and H are
direct accesses to G and H: they are not renamed or versioned. This
diff ers from some other compiler systems, which do try to version memory
objects. In LLVM, instead of encoding dataflow analysis of memory into
-the LLVM IR, it is handled with `Analysis
-Passes <../../WritingAnLLVMPass.html>`_ which are computed on demand.
+the LLVM IR, it is handled with [Analysis
+Passes](../../WritingAnLLVMPass.md) which are computed on demand.
With this in mind, the high-level idea is that we want to make a stack
variable (which lives in memory, because it is on the stack) for each
@@ -111,23 +105,23 @@ to talk about how LLVM represents stack variables.
In LLVM, all memory accesses are explicit with load/store instructions,
and it is carefully designed not to have (or need) an "address-of"
operator. Notice how the type of the @G/@H global variables is actually
-"i32\*" even though the variable is defined as "i32". What this means is
+`i32*` even though the variable is defined as "i32". What this means is
that @G defines *space* for an i32 in the global data area, but its
*name* actually refers to the address for that space. Stack variables
work the same way, except that instead of being declared with global
-variable definitions, they are declared with the `LLVM alloca
-instruction <../../LangRef.html#alloca-instruction>`_:
-
-.. code-block:: llvm
-
- define i32 @example() {
- entry:
- %X = alloca i32 ; type of %X is i32*.
- ...
- %tmp = load i32, i32* %X ; load the stack value %X from the stack.
- %tmp2 = add i32 %tmp, 1 ; increment it
- store i32 %tmp2, i32* %X ; store it back
- ...
+variable definitions, they are declared with the [LLVM alloca
+instruction](../../LangRef.md#alloca-instruction):
+
+```llvm
+define i32 @example() {
+entry:
+ %X = alloca i32 ; type of %X is i32*.
+ ...
+ %tmp = load i32, i32* %X ; load the stack value %X from the stack.
+ %tmp2 = add i32 %tmp, 1 ; increment it
+ store i32 %tmp2, i32* %X ; store it back
+ ...
+```
This code shows an example of how you can declare and manipulate a stack
variable in the LLVM IR. Stack memory allocated with the alloca
@@ -136,38 +130,38 @@ to functions, you can store it in other variables, etc. In our example
above, we could rewrite the example to use the alloca technique to avoid
using a PHI node:
-.. code-block:: llvm
-
- @G = weak global i32 0 ; type of @G is i32*
- @H = weak global i32 0 ; type of @H is i32*
+```llvm
+ at G = weak global i32 0 ; type of @G is i32*
+ at H = weak global i32 0 ; type of @H is i32*
- define i32 @test(i1 %Condition) {
- entry:
- %X = alloca i32 ; type of %X is i32*.
- br i1 %Condition, label %cond_true, label %cond_false
+define i32 @test(i1 %Condition) {
+entry:
+ %X = alloca i32 ; type of %X is i32*.
+ br i1 %Condition, label %cond_true, label %cond_false
- cond_true:
- %X.0 = load i32, i32* @G
- store i32 %X.0, i32* %X ; Update X
- br label %cond_next
+cond_true:
+ %X.0 = load i32, i32* @G
+ store i32 %X.0, i32* %X ; Update X
+ br label %cond_next
- cond_false:
- %X.1 = load i32, i32* @H
- store i32 %X.1, i32* %X ; Update X
- br label %cond_next
+cond_false:
+ %X.1 = load i32, i32* @H
+ store i32 %X.1, i32* %X ; Update X
+ br label %cond_next
- cond_next:
- %X.2 = load i32, i32* %X ; Read X
- ret i32 %X.2
- }
+cond_next:
+ %X.2 = load i32, i32* %X ; Read X
+ ret i32 %X.2
+}
+```
With this, we have discovered a way to handle arbitrary mutable
variables without the need to create Phi nodes at all:
-#. Each mutable variable becomes a stack allocation.
-#. Each read of the variable becomes a load from the stack.
-#. Each update of the variable becomes a store to the stack.
-#. Taking the address of a variable just uses the stack address
+1. Each mutable variable becomes a stack allocation.
+2. Each read of the variable becomes a load from the stack.
+3. Each update of the variable becomes a store to the stack.
+4. Taking the address of a variable just uses the stack address
directly.
While this solution has solved our immediate problem, it introduced
@@ -178,28 +172,28 @@ pass named "mem2reg" that handles this case, promoting allocas like this
into SSA registers, inserting Phi nodes as appropriate. If you run this
example through the pass, for example, you'll get:
-.. code-block:: bash
-
- $ llvm-as < example.ll | opt -passes=mem2reg | llvm-dis
- @G = weak global i32 0
- @H = weak global i32 0
+```bash
+$ llvm-as < example.ll | opt -passes=mem2reg | llvm-dis
+ at G = weak global i32 0
+ at H = weak global i32 0
- define i32 @test(i1 %Condition) {
- entry:
- br i1 %Condition, label %cond_true, label %cond_false
+define i32 @test(i1 %Condition) {
+entry:
+ br i1 %Condition, label %cond_true, label %cond_false
- cond_true:
- %X.0 = load i32, i32* @G
- br label %cond_next
+cond_true:
+ %X.0 = load i32, i32* @G
+ br label %cond_next
- cond_false:
- %X.1 = load i32, i32* @H
- br label %cond_next
+cond_false:
+ %X.1 = load i32, i32* @H
+ br label %cond_next
- cond_next:
- %X.01 = phi i32 [ %X.1, %cond_false ], [ %X.0, %cond_true ]
- ret i32 %X.01
- }
+cond_next:
+ %X.01 = phi i32 [ %X.1, %cond_false ], [ %X.0, %cond_true ]
+ ret i32 %X.01
+}
+```
The mem2reg pass implements the standard "iterated dominance frontier"
algorithm for constructing SSA form and has a number of optimizations
@@ -208,18 +202,18 @@ pass is the answer to dealing with mutable variables, and we highly
recommend that you depend on it. Note that mem2reg only works on
variables in certain circumstances:
-#. mem2reg is alloca-driven: it looks for allocas and if it can handle
+1. mem2reg is alloca-driven: it looks for allocas and if it can handle
them, it promotes them. It does not apply to global variables or heap
allocations.
-#. mem2reg only looks for alloca instructions in the entry block of the
+2. mem2reg only looks for alloca instructions in the entry block of the
function. Being in the entry block guarantees that the alloca is only
executed once, which makes analysis simpler.
-#. mem2reg only promotes allocas whose uses are direct loads and stores.
+3. mem2reg only promotes allocas whose uses are direct loads and stores.
If the address of the stack object is passed to a function, or if any
funny pointer arithmetic is involved, the alloca will not be
promoted.
-#. mem2reg only works on allocas of `first
- class <../../LangRef.html#first-class-types>`_ values (such as pointers,
+4. mem2reg only works on allocas of [first
+ class](../../LangRef.md#first-class-types) values (such as pointers,
scalars and vectors), and only if the array size of the allocation is
1 (or missing in the .ll file). mem2reg is not capable of promoting
structs or arrays to registers. Note that the "sroa" pass is
@@ -235,33 +229,32 @@ strongly recommend that you use this technique for building SSA form,
unless there is an extremely good reason not to. Using this technique
is:
-- Proven and well tested: clang uses this technique
- for local mutable variables. As such, the most common clients of LLVM
- are using this to handle a bulk of their variables. You can be sure
- that bugs are found fast and fixed early.
-- Extremely Fast: mem2reg has a number of special cases that make it
- fast in common cases as well as fully general. For example, it has
- fast-paths for variables that are only used in a single block,
- variables that only have one assignment point, good heuristics to
- avoid insertion of unneeded phi nodes, etc.
-- Needed for debug info generation: `Debug information in
- LLVM <../../SourceLevelDebugging.html>`_ relies on having the address of
- the variable exposed so that debug info can be attached to it. This
- technique dovetails very naturally with this style of debug info.
+- Proven and well tested: clang uses this technique
+ for local mutable variables. As such, the most common clients of LLVM
+ are using this to handle a bulk of their variables. You can be sure
+ that bugs are found fast and fixed early.
+- Extremely Fast: mem2reg has a number of special cases that make it
+ fast in common cases as well as fully general. For example, it has
+ fast-paths for variables that are only used in a single block,
+ variables that only have one assignment point, good heuristics to
+ avoid insertion of unneeded phi nodes, etc.
+- Needed for debug info generation: [Debug information in
+ LLVM](../../SourceLevelDebugging.md) relies on having the address of
+ the variable exposed so that debug info can be attached to it. This
+ technique dovetails very naturally with this style of debug info.
If nothing else, this makes it much easier to get your front-end up and
running, and is very simple to implement. Let's extend Kaleidoscope with
mutable variables now!
-Mutable Variables in Kaleidoscope
-=================================
+## Mutable Variables in Kaleidoscope
Now that we know the sort of problem we want to tackle, let's see what
this looks like in the context of our little Kaleidoscope language.
We're going to add two features:
-#. The ability to mutate variables with the '=' operator.
-#. The ability to define new variables.
+1. The ability to mutate variables with the '=' operator.
+2. The ability to define new variables.
While the first item is really what this is about, we only have
variables for incoming arguments as well as for induction variables, and
@@ -269,43 +262,42 @@ redefining those only goes so far :). Also, the ability to define new
variables is a useful thing regardless of whether you will be mutating
them. Here's a motivating example that shows how we could use these:
-::
-
- # Define ':' for sequencing: as a low-precedence operator that ignores operands
- # and just returns the RHS.
- def binary : 1 (x y) y;
-
- # Recursive fib, we could do this before.
- def fib(x)
- if (x < 3) then
- 1
- else
- fib(x-1)+fib(x-2);
-
- # Iterative fib.
- def fibi(x)
- var a = 1, b = 1, c in
- (for i = 3, i < x in
- c = a + b :
- a = b :
- b = c) :
- b;
-
- # Call it.
- fibi(10);
+```
+# Define ':' for sequencing: as a low-precedence operator that ignores operands
+# and just returns the RHS.
+def binary : 1 (x y) y;
+
+# Recursive fib, we could do this before.
+def fib(x)
+ if (x < 3) then
+ 1
+ else
+ fib(x-1)+fib(x-2);
+
+# Iterative fib.
+def fibi(x)
+ var a = 1, b = 1, c in
+ (for i = 3, i < x in
+ c = a + b :
+ a = b :
+ b = c) :
+ b;
+
+# Call it.
+fibi(10);
+```
In order to mutate variables, we have to change our existing variables
to use the "alloca trick". Once we have that, we'll add our new
operator, then extend Kaleidoscope to support new variable definitions.
-Adjusting Existing Variables for Mutation
-=========================================
+## Adjusting Existing Variables for Mutation
The symbol table in Kaleidoscope is managed at code generation time by
-the '``NamedValues``' map. This map currently keeps track of the LLVM
-"Value\*" that holds the double value for the named variable. In order
+the '`NamedValues`' map. This map currently keeps track of the LLVM
+`Value*` that holds the double value for the named variable. In order
to support mutation, we need to change this slightly, so that
-``NamedValues`` holds the *memory location* of the variable in question.
+`NamedValues` holds the *memory location* of the variable in question.
Note that this change is a refactoring: it changes the structure of the
code, but does not (by itself) change the behavior of the compiler. All
of these changes are isolated in the Kaleidoscope code generator.
@@ -317,29 +309,29 @@ variables in addition to other user-defined variables. This means that
these will both need memory locations.
To start our transformation of Kaleidoscope, we'll change the
-``NamedValues`` map so that it maps to AllocaInst\* instead of Value\*. Once
+`NamedValues` map so that it maps to `AllocaInst*` instead of `Value*`. Once
we do this, the C++ compiler will tell us what parts of the code we need
to update:
-.. code-block:: c++
-
- static std::map<std::string, AllocaInst*> NamedValues;
+```c++
+static std::map<std::string, AllocaInst*> NamedValues;
+```
Also, since we will need to create these allocas, we'll use a helper
function that ensures that the allocas are created in the entry block of
the function:
-.. code-block:: c++
-
- /// CreateEntryBlockAlloca - Create an alloca instruction in the entry block of
- /// the function. This is used for mutable variables etc.
- static AllocaInst *CreateEntryBlockAlloca(Function *TheFunction,
- StringRef VarName) {
- IRBuilder<> TmpB(&TheFunction->getEntryBlock(),
- TheFunction->getEntryBlock().begin());
- return TmpB.CreateAlloca(Type::getDoubleTy(*TheContext), nullptr,
- VarName);
- }
+```c++
+/// CreateEntryBlockAlloca - Create an alloca instruction in the entry block of
+/// the function. This is used for mutable variables etc.
+static AllocaInst *CreateEntryBlockAlloca(Function *TheFunction,
+ StringRef VarName) {
+ IRBuilder<> TmpB(&TheFunction->getEntryBlock(),
+ TheFunction->getEntryBlock().begin());
+ return TmpB.CreateAlloca(Type::getDoubleTy(*TheContext), nullptr,
+ VarName);
+}
+```
This funny looking code creates an IRBuilder object that is pointing at
the first instruction (.begin()) of the entry block. It then creates an
@@ -351,133 +343,133 @@ variable references. In our new scheme, variables live on the stack, so
code generating a reference to them actually needs to produce a load
from the stack slot:
-.. code-block:: c++
+```c++
+Value *VariableExprAST::codegen() {
+ // Look this variable up in the function.
+ AllocaInst *A = NamedValues[Name];
+ if (!A)
+ return LogErrorV("Unknown variable name");
- Value *VariableExprAST::codegen() {
- // Look this variable up in the function.
- AllocaInst *A = NamedValues[Name];
- if (!A)
- return LogErrorV("Unknown variable name");
-
- // Load the value.
- return Builder->CreateLoad(A->getAllocatedType(), A, Name.c_str());
- }
+ // Load the value.
+ return Builder->CreateLoad(A->getAllocatedType(), A, Name.c_str());
+}
+```
As you can see, this is pretty straightforward. Now we need to update
the things that define the variables to set up the alloca. We'll start
-with ``ForExprAST::codegen()`` (see the `full code listing <#id1>`_ for
+with `ForExprAST::codegen()` (see the [full code listing](#full-code-listing) for
the unabridged code):
-.. code-block:: c++
-
- Function *TheFunction = Builder->GetInsertBlock()->getParent();
-
- // Create an alloca for the variable in the entry block.
- AllocaInst *Alloca = CreateEntryBlockAlloca(TheFunction, VarName);
-
- // Emit the start code first, without 'variable' in scope.
- Value *StartVal = Start->codegen();
- if (!StartVal)
- return nullptr;
-
- // Store the value into the alloca.
- Builder->CreateStore(StartVal, Alloca);
- ...
-
- // Compute the end condition.
- Value *EndCond = End->codegen();
- if (!EndCond)
- return nullptr;
-
- // Reload, increment, and restore the alloca. This handles the case where
- // the body of the loop mutates the variable.
- Value *CurVar = Builder->CreateLoad(Alloca->getAllocatedType(), Alloca,
- VarName.c_str());
- Value *NextVar = Builder->CreateFAdd(CurVar, StepVal, "nextvar");
- Builder->CreateStore(NextVar, Alloca);
- ...
-
-This code is virtually identical to the code `before we allowed mutable
-variables <LangImpl05.html#code-generation-for-the-for-loop>`_. The big
diff erence is that we
+```c++
+Function *TheFunction = Builder->GetInsertBlock()->getParent();
+
+// Create an alloca for the variable in the entry block.
+AllocaInst *Alloca = CreateEntryBlockAlloca(TheFunction, VarName);
+
+// Emit the start code first, without 'variable' in scope.
+Value *StartVal = Start->codegen();
+if (!StartVal)
+ return nullptr;
+
+// Store the value into the alloca.
+Builder->CreateStore(StartVal, Alloca);
+...
+
+// Compute the end condition.
+Value *EndCond = End->codegen();
+if (!EndCond)
+ return nullptr;
+
+// Reload, increment, and restore the alloca. This handles the case where
+// the body of the loop mutates the variable.
+Value *CurVar = Builder->CreateLoad(Alloca->getAllocatedType(), Alloca,
+ VarName.c_str());
+Value *NextVar = Builder->CreateFAdd(CurVar, StepVal, "nextvar");
+Builder->CreateStore(NextVar, Alloca);
+...
+```
+
+This code is virtually identical to the code [before we allowed mutable
+variables](LangImpl05.md#code-generation-for-the-for-loop). The big
diff erence is that we
no longer have to construct a PHI node, and we use load/store to access
the variable as needed.
To support mutable argument variables, we need to also make allocas for
them. The code for this is also pretty simple:
-.. code-block:: c++
-
- Function *FunctionAST::codegen() {
- ...
- Builder->SetInsertPoint(BB);
+```c++
+Function *FunctionAST::codegen() {
+ ...
+ Builder->SetInsertPoint(BB);
- // Record the function arguments in the NamedValues map.
- NamedValues.clear();
- for (auto &Arg : TheFunction->args()) {
- // Create an alloca for this variable.
- AllocaInst *Alloca = CreateEntryBlockAlloca(TheFunction, Arg.getName());
+ // Record the function arguments in the NamedValues map.
+ NamedValues.clear();
+ for (auto &Arg : TheFunction->args()) {
+ // Create an alloca for this variable.
+ AllocaInst *Alloca = CreateEntryBlockAlloca(TheFunction, Arg.getName());
- // Store the initial value into the alloca.
- Builder->CreateStore(&Arg, Alloca);
+ // Store the initial value into the alloca.
+ Builder->CreateStore(&Arg, Alloca);
- // Add arguments to variable symbol table.
- NamedValues[std::string(Arg.getName())] = Alloca;
- }
+ // Add arguments to variable symbol table.
+ NamedValues[std::string(Arg.getName())] = Alloca;
+ }
- if (Value *RetVal = Body->codegen()) {
- ...
+ if (Value *RetVal = Body->codegen()) {
+ ...
+```
For each argument, we make an alloca, store the input value to the
function into the alloca, and register the alloca as the memory location
-for the argument. This method gets invoked by ``FunctionAST::codegen()``
+for the argument. This method gets invoked by `FunctionAST::codegen()`
right after it sets up the entry block for the function.
The final missing piece is adding the mem2reg pass, which allows us to
get good codegen once again:
-.. code-block:: c++
-
- // Promote allocas to registers.
- TheFPM->addPass(PromotePass());
- // Do simple "peephole" optimizations and bit-twiddling optzns.
- TheFPM->addPass(InstCombinePass());
- // Reassociate expressions.
- TheFPM->addPass(ReassociatePass());
- ...
+```c++
+// Promote allocas to registers.
+TheFPM->addPass(PromotePass());
+// Do simple "peephole" optimizations and bit-twiddling optzns.
+TheFPM->addPass(InstCombinePass());
+// Reassociate expressions.
+TheFPM->addPass(ReassociatePass());
+...
+```
It is interesting to see what the code looks like before and after the
mem2reg optimization runs. For example, this is the before/after code
for our recursive fib function. Before the optimization:
-.. code-block:: llvm
-
- define double @fib(double %x) {
- entry:
- %x1 = alloca double
- store double %x, double* %x1
- %x2 = load double, double* %x1
- %cmptmp = fcmp ult double %x2, 3.000000e+00
- %booltmp = uitofp i1 %cmptmp to double
- %ifcond = fcmp one double %booltmp, 0.000000e+00
- br i1 %ifcond, label %then, label %else
-
- then: ; preds = %entry
- br label %ifcont
-
- else: ; preds = %entry
- %x3 = load double, double* %x1
- %subtmp = fsub double %x3, 1.000000e+00
- %calltmp = call double @fib(double %subtmp)
- %x4 = load double, double* %x1
- %subtmp5 = fsub double %x4, 2.000000e+00
- %calltmp6 = call double @fib(double %subtmp5)
- %addtmp = fadd double %calltmp, %calltmp6
- br label %ifcont
-
- ifcont: ; preds = %else, %then
- %iftmp = phi double [ 1.000000e+00, %then ], [ %addtmp, %else ]
- ret double %iftmp
- }
+```llvm
+define double @fib(double %x) {
+entry:
+ %x1 = alloca double
+ store double %x, double* %x1
+ %x2 = load double, double* %x1
+ %cmptmp = fcmp ult double %x2, 3.000000e+00
+ %booltmp = uitofp i1 %cmptmp to double
+ %ifcond = fcmp one double %booltmp, 0.000000e+00
+ br i1 %ifcond, label %then, label %else
+
+then: ; preds = %entry
+ br label %ifcont
+
+else: ; preds = %entry
+ %x3 = load double, double* %x1
+ %subtmp = fsub double %x3, 1.000000e+00
+ %calltmp = call double @fib(double %subtmp)
+ %x4 = load double, double* %x1
+ %subtmp5 = fsub double %x4, 2.000000e+00
+ %calltmp6 = call double @fib(double %subtmp5)
+ %addtmp = fadd double %calltmp, %calltmp6
+ br label %ifcont
+
+ifcont: ; preds = %else, %then
+ %iftmp = phi double [ 1.000000e+00, %then ], [ %addtmp, %else ]
+ ret double %iftmp
+}
+```
Here there is only one variable (x, the input argument) but you can
still see the extremely simple-minded code generation strategy we are
@@ -490,30 +482,30 @@ still just make the PHI.
Here is the code after the mem2reg pass runs:
-.. code-block:: llvm
-
- define double @fib(double %x) {
- entry:
- %cmptmp = fcmp ult double %x, 3.000000e+00
- %booltmp = uitofp i1 %cmptmp to double
- %ifcond = fcmp one double %booltmp, 0.000000e+00
- br i1 %ifcond, label %then, label %else
-
- then:
- br label %ifcont
-
- else:
- %subtmp = fsub double %x, 1.000000e+00
- %calltmp = call double @fib(double %subtmp)
- %subtmp5 = fsub double %x, 2.000000e+00
- %calltmp6 = call double @fib(double %subtmp5)
- %addtmp = fadd double %calltmp, %calltmp6
- br label %ifcont
-
- ifcont: ; preds = %else, %then
- %iftmp = phi double [ 1.000000e+00, %then ], [ %addtmp, %else ]
- ret double %iftmp
- }
+```llvm
+define double @fib(double %x) {
+entry:
+ %cmptmp = fcmp ult double %x, 3.000000e+00
+ %booltmp = uitofp i1 %cmptmp to double
+ %ifcond = fcmp one double %booltmp, 0.000000e+00
+ br i1 %ifcond, label %then, label %else
+
+then:
+ br label %ifcont
+
+else:
+ %subtmp = fsub double %x, 1.000000e+00
+ %calltmp = call double @fib(double %subtmp)
+ %subtmp5 = fsub double %x, 2.000000e+00
+ %calltmp6 = call double @fib(double %subtmp5)
+ %addtmp = fadd double %calltmp, %calltmp6
+ br label %ifcont
+
+ifcont: ; preds = %else, %then
+ %iftmp = phi double [ 1.000000e+00, %then ], [ %addtmp, %else ]
+ ret double %iftmp
+}
+```
This is a trivial case for mem2reg, since there are no redefinitions of
the variable. The point of showing this is to calm your tension about
@@ -521,26 +513,26 @@ inserting such blatant inefficiencies :).
After the rest of the optimizers run, we get:
-.. code-block:: llvm
-
- define double @fib(double %x) {
- entry:
- %cmptmp = fcmp ult double %x, 3.000000e+00
- %booltmp = uitofp i1 %cmptmp to double
- %ifcond = fcmp ueq double %booltmp, 0.000000e+00
- br i1 %ifcond, label %else, label %ifcont
-
- else:
- %subtmp = fsub double %x, 1.000000e+00
- %calltmp = call double @fib(double %subtmp)
- %subtmp5 = fsub double %x, 2.000000e+00
- %calltmp6 = call double @fib(double %subtmp5)
- %addtmp = fadd double %calltmp, %calltmp6
- ret double %addtmp
-
- ifcont:
- ret double 1.000000e+00
- }
+```llvm
+define double @fib(double %x) {
+entry:
+ %cmptmp = fcmp ult double %x, 3.000000e+00
+ %booltmp = uitofp i1 %cmptmp to double
+ %ifcond = fcmp ueq double %booltmp, 0.000000e+00
+ br i1 %ifcond, label %else, label %ifcont
+
+else:
+ %subtmp = fsub double %x, 1.000000e+00
+ %calltmp = call double @fib(double %subtmp)
+ %subtmp5 = fsub double %x, 2.000000e+00
+ %calltmp6 = call double @fib(double %subtmp5)
+ %addtmp = fadd double %calltmp, %calltmp6
+ ret double %addtmp
+
+ifcont:
+ ret double 1.000000e+00
+}
+```
Here we see that the simplifycfg pass decided to clone the return
instruction into the end of the 'else' block. This allowed it to
@@ -549,39 +541,38 @@ eliminate some branches and the PHI node.
Now that all symbol table references are updated to use stack variables,
we'll add the assignment operator.
-New Assignment Operator
-=======================
+## New Assignment Operator
With our current framework, adding a new assignment operator is really
simple. We will parse it just like any other binary operator, but handle
it internally (instead of allowing the user to define it). The first
step is to set a precedence:
-.. code-block:: c++
-
- int main() {
- // Install standard binary operators.
- // 1 is lowest precedence.
- BinopPrecedence['='] = 2;
- BinopPrecedence['<'] = 10;
- BinopPrecedence['+'] = 20;
- BinopPrecedence['-'] = 20;
+```c++
+int main() {
+ // Install standard binary operators.
+ // 1 is lowest precedence.
+ BinopPrecedence['='] = 2;
+ BinopPrecedence['<'] = 10;
+ BinopPrecedence['+'] = 20;
+ BinopPrecedence['-'] = 20;
+```
Now that the parser knows the precedence of the binary operator, it
takes care of all the parsing and AST generation. We just need to
implement codegen for the assignment operator. This looks like:
-.. code-block:: c++
-
- Value *BinaryExprAST::codegen() {
- // Special case '=' because we don't want to emit the LHS as an expression.
- if (Op == '=') {
- // This assume we're building without RTTI because LLVM builds that way by
- // default. If you build LLVM with RTTI this can be changed to a
- // dynamic_cast for automatic error checking.
- VariableExprAST *LHSE = static_cast<VariableExprAST*>(LHS.get());
- if (!LHSE)
- return LogErrorV("destination of '=' must be a variable");
+```c++
+Value *BinaryExprAST::codegen() {
+ // Special case '=' because we don't want to emit the LHS as an expression.
+ if (Op == '=') {
+ // This assume we're building without RTTI because LLVM builds that way by
+ // default. If you build LLVM with RTTI this can be changed to a
+ // dynamic_cast for automatic error checking.
+ VariableExprAST *LHSE = static_cast<VariableExprAST*>(LHS.get());
+ if (!LHSE)
+ return LogErrorV("destination of '=' must be a variable");
+```
Unlike the rest of the binary operators, our assignment operator doesn't
follow the "emit LHS, emit RHS, do computation" model. As such, it is
@@ -590,22 +581,22 @@ The other strange thing is that it requires the LHS to be a variable. It
is invalid to have "(x+1) = expr" - only things like "x = expr" are
allowed.
-.. code-block:: c++
-
- // Codegen the RHS.
- Value *Val = RHS->codegen();
- if (!Val)
- return nullptr;
+```c++
+ // Codegen the RHS.
+ Value *Val = RHS->codegen();
+ if (!Val)
+ return nullptr;
- // Look up the name.
- AllocaInst *Alloca = NamedValues[LHSE->getName()];
- if (!Alloca)
- return LogErrorV("Unknown variable name");
+ // Look up the name.
+ AllocaInst *Alloca = NamedValues[LHSE->getName()];
+ if (!Alloca)
+ return LogErrorV("Unknown variable name");
- Builder->CreateStore(Val, Alloca);
- return Val;
- }
- ...
+ Builder->CreateStore(Val, Alloca);
+ return Val;
+}
+...
+```
Once we have the variable, codegen'ing the assignment is
straightforward: we emit the RHS of the assignment, create a store, and
@@ -615,21 +606,21 @@ assignments like "X = (Y = Z)".
Now that we have an assignment operator, we can mutate loop variables
and arguments. For example, we can now run code like this:
-::
+```
+# Function to print a double.
+extern printd(x);
- # Function to print a double.
- extern printd(x);
+# Define ':' for sequencing: as a low-precedence operator that ignores operands
+# and just returns the RHS.
+def binary : 1 (x y) y;
- # Define ':' for sequencing: as a low-precedence operator that ignores operands
- # and just returns the RHS.
- def binary : 1 (x y) y;
+def test(x)
+ printd(x) :
+ x = 4 :
+ printd(x);
- def test(x)
- printd(x) :
- x = 4 :
- printd(x);
-
- test(123);
+test(123);
+```
When run, this example prints "123" and then "4", showing that we did
actually mutate the value! Okay, we have now officially implemented our
@@ -637,8 +628,7 @@ goal: getting this to work requires SSA construction in the general
case. However, to be really useful, we want the ability to define our
own local variables, let's add this next!
-User-defined Local Variables
-============================
+## User-defined Local Variables
Adding var/in is just like any other extension we made to
Kaleidoscope: we extend the lexer, the parser, the AST and the code
@@ -646,45 +636,45 @@ generator. The first step for adding our new 'var/in' construct is to
extend the lexer. As before, this is pretty trivial, the code looks like
this:
-.. code-block:: c++
-
- enum Token {
- ...
- // var definition
- tok_var = -13
- ...
- }
- ...
- static int gettok() {
- ...
- if (IdentifierStr == "in")
- return tok_in;
- if (IdentifierStr == "binary")
- return tok_binary;
- if (IdentifierStr == "unary")
- return tok_unary;
- if (IdentifierStr == "var")
- return tok_var;
- return tok_identifier;
- ...
+```c++
+enum Token {
+ ...
+ // var definition
+ tok_var = -13
+...
+}
+...
+static int gettok() {
+...
+ if (IdentifierStr == "in")
+ return tok_in;
+ if (IdentifierStr == "binary")
+ return tok_binary;
+ if (IdentifierStr == "unary")
+ return tok_unary;
+ if (IdentifierStr == "var")
+ return tok_var;
+ return tok_identifier;
+...
+```
The next step is to define the AST node that we will construct. For
var/in, it looks like this:
-.. code-block:: c++
+```c++
+/// VarExprAST - Expression class for var/in
+class VarExprAST : public ExprAST {
+ std::vector<std::pair<std::string, std::unique_ptr<ExprAST>>> VarNames;
+ std::unique_ptr<ExprAST> Body;
- /// VarExprAST - Expression class for var/in
- class VarExprAST : public ExprAST {
- std::vector<std::pair<std::string, std::unique_ptr<ExprAST>>> VarNames;
- std::unique_ptr<ExprAST> Body;
+public:
+ VarExprAST(std::vector<std::pair<std::string, std::unique_ptr<ExprAST>>> VarNames,
+ std::unique_ptr<ExprAST> Body)
+ : VarNames(std::move(VarNames)), Body(std::move(Body)) {}
- public:
- VarExprAST(std::vector<std::pair<std::string, std::unique_ptr<ExprAST>>> VarNames,
- std::unique_ptr<ExprAST> Body)
- : VarNames(std::move(VarNames)), Body(std::move(Body)) {}
-
- Value *codegen() override;
- };
+ Value *codegen() override;
+};
+```
var/in allows a list of names to be defined all at once, and each name
can optionally have an initializer value. As such, we capture this
@@ -694,164 +684,164 @@ is allowed to access the variables defined by the var/in.
With this in place, we can define the parser pieces. The first thing we
do is add it as a primary expression:
-.. code-block:: c++
-
- /// primary
- /// ::= identifierexpr
- /// ::= numberexpr
- /// ::= parenexpr
- /// ::= ifexpr
- /// ::= forexpr
- /// ::= varexpr
- static std::unique_ptr<ExprAST> ParsePrimary() {
- switch (CurTok) {
- default:
- return LogError("unknown token when expecting an expression");
- case tok_identifier:
- return ParseIdentifierExpr();
- case tok_number:
- return ParseNumberExpr();
- case '(':
- return ParseParenExpr();
- case tok_if:
- return ParseIfExpr();
- case tok_for:
- return ParseForExpr();
- case tok_var:
- return ParseVarExpr();
- }
- }
+```c++
+/// primary
+/// ::= identifierexpr
+/// ::= numberexpr
+/// ::= parenexpr
+/// ::= ifexpr
+/// ::= forexpr
+/// ::= varexpr
+static std::unique_ptr<ExprAST> ParsePrimary() {
+ switch (CurTok) {
+ default:
+ return LogError("unknown token when expecting an expression");
+ case tok_identifier:
+ return ParseIdentifierExpr();
+ case tok_number:
+ return ParseNumberExpr();
+ case '(':
+ return ParseParenExpr();
+ case tok_if:
+ return ParseIfExpr();
+ case tok_for:
+ return ParseForExpr();
+ case tok_var:
+ return ParseVarExpr();
+ }
+}
+```
Next we define ParseVarExpr:
-.. code-block:: c++
-
- /// varexpr ::= 'var' identifier ('=' expression)?
- // (',' identifier ('=' expression)?)* 'in' expression
- static std::unique_ptr<ExprAST> ParseVarExpr() {
- getNextToken(); // eat the var.
+```c++
+/// varexpr ::= 'var' identifier ('=' expression)?
+// (',' identifier ('=' expression)?)* 'in' expression
+static std::unique_ptr<ExprAST> ParseVarExpr() {
+ getNextToken(); // eat the var.
- std::vector<std::pair<std::string, std::unique_ptr<ExprAST>>> VarNames;
+ std::vector<std::pair<std::string, std::unique_ptr<ExprAST>>> VarNames;
- // At least one variable name is required.
- if (CurTok != tok_identifier)
- return LogError("expected identifier after var");
+ // At least one variable name is required.
+ if (CurTok != tok_identifier)
+ return LogError("expected identifier after var");
+```
The first part of this code parses the list of identifier/expr pairs
-into the local ``VarNames`` vector.
-
-.. code-block:: c++
+into the local `VarNames` vector.
- while (true) {
- std::string Name = IdentifierStr;
- getNextToken(); // eat identifier.
+```c++
+while (true) {
+ std::string Name = IdentifierStr;
+ getNextToken(); // eat identifier.
- // Read the optional initializer.
- std::unique_ptr<ExprAST> Init;
- if (CurTok == '=') {
- getNextToken(); // eat the '='.
+ // Read the optional initializer.
+ std::unique_ptr<ExprAST> Init;
+ if (CurTok == '=') {
+ getNextToken(); // eat the '='.
- Init = ParseExpression();
- if (!Init) return nullptr;
- }
+ Init = ParseExpression();
+ if (!Init) return nullptr;
+ }
- VarNames.push_back(std::make_pair(Name, std::move(Init)));
+ VarNames.push_back(std::make_pair(Name, std::move(Init)));
- // End of var list, exit loop.
- if (CurTok != ',') break;
- getNextToken(); // eat the ','.
+ // End of var list, exit loop.
+ if (CurTok != ',') break;
+ getNextToken(); // eat the ','.
- if (CurTok != tok_identifier)
- return LogError("expected identifier list after var");
- }
+ if (CurTok != tok_identifier)
+ return LogError("expected identifier list after var");
+}
+```
Once all the variables are parsed, we then parse the body and create the
AST node:
-.. code-block:: c++
+```c++
+ // At this point, we have to have 'in'.
+ if (CurTok != tok_in)
+ return LogError("expected 'in' keyword after 'var'");
+ getNextToken(); // eat 'in'.
- // At this point, we have to have 'in'.
- if (CurTok != tok_in)
- return LogError("expected 'in' keyword after 'var'");
- getNextToken(); // eat 'in'.
+ auto Body = ParseExpression();
+ if (!Body)
+ return nullptr;
- auto Body = ParseExpression();
- if (!Body)
- return nullptr;
-
- return std::make_unique<VarExprAST>(std::move(VarNames),
- std::move(Body));
- }
+ return std::make_unique<VarExprAST>(std::move(VarNames),
+ std::move(Body));
+}
+```
Now that we can parse and represent the code, we need to support
emission of LLVM IR for it. This code starts out with:
-.. code-block:: c++
-
- Value *VarExprAST::codegen() {
- std::vector<AllocaInst *> OldBindings;
+```c++
+Value *VarExprAST::codegen() {
+ std::vector<AllocaInst *> OldBindings;
- Function *TheFunction = Builder->GetInsertBlock()->getParent();
+ Function *TheFunction = Builder->GetInsertBlock()->getParent();
- // Register all variables and emit their initializer.
- for (unsigned i = 0, e = VarNames.size(); i != e; ++i) {
- const std::string &VarName = VarNames[i].first;
- ExprAST *Init = VarNames[i].second.get();
+ // Register all variables and emit their initializer.
+ for (unsigned i = 0, e = VarNames.size(); i != e; ++i) {
+ const std::string &VarName = VarNames[i].first;
+ ExprAST *Init = VarNames[i].second.get();
+```
Basically it loops over all the variables, installing them one at a
time. For each variable we put into the symbol table, we remember the
previous value that we replace in OldBindings.
-.. code-block:: c++
-
- // Emit the initializer before adding the variable to scope, this prevents
- // the initializer from referencing the variable itself, and permits stuff
- // like this:
- // var a = 1 in
- // var a = a in ... # refers to outer 'a'.
- Value *InitVal;
- if (Init) {
- InitVal = Init->codegen();
- if (!InitVal)
- return nullptr;
- } else { // If not specified, use 0.0.
- InitVal = ConstantFP::get(*TheContext, APFloat(0.0));
- }
-
- AllocaInst *Alloca = CreateEntryBlockAlloca(TheFunction, VarName);
- Builder->CreateStore(InitVal, Alloca);
-
- // Remember the old variable binding so that we can restore the binding when
- // we unrecurse.
- OldBindings.push_back(NamedValues[VarName]);
-
- // Remember this binding.
- NamedValues[VarName] = Alloca;
- }
+```c++
+ // Emit the initializer before adding the variable to scope, this prevents
+ // the initializer from referencing the variable itself, and permits stuff
+ // like this:
+ // var a = 1 in
+ // var a = a in ... # refers to outer 'a'.
+ Value *InitVal;
+ if (Init) {
+ InitVal = Init->codegen();
+ if (!InitVal)
+ return nullptr;
+ } else { // If not specified, use 0.0.
+ InitVal = ConstantFP::get(*TheContext, APFloat(0.0));
+ }
+
+ AllocaInst *Alloca = CreateEntryBlockAlloca(TheFunction, VarName);
+ Builder->CreateStore(InitVal, Alloca);
+
+ // Remember the old variable binding so that we can restore the binding when
+ // we unrecurse.
+ OldBindings.push_back(NamedValues[VarName]);
+
+ // Remember this binding.
+ NamedValues[VarName] = Alloca;
+}
+```
There are more comments here than code. The basic idea is that we emit
the initializer, create the alloca, then update the symbol table to
point to it. Once all the variables are installed in the symbol table,
we evaluate the body of the var/in expression:
-.. code-block:: c++
-
- // Codegen the body, now that all vars are in scope.
- Value *BodyVal = Body->codegen();
- if (!BodyVal)
- return nullptr;
+```c++
+// Codegen the body, now that all vars are in scope.
+Value *BodyVal = Body->codegen();
+if (!BodyVal)
+ return nullptr;
+```
Finally, before returning, we restore the previous variable bindings:
-.. code-block:: c++
+```c++
+ // Pop all our variables from scope.
+ for (unsigned i = 0, e = VarNames.size(); i != e; ++i)
+ NamedValues[VarNames[i].first] = OldBindings[i];
- // Pop all our variables from scope.
- for (unsigned i = 0, e = VarNames.size(); i != e; ++i)
- NamedValues[VarNames[i].first] = OldBindings[i];
-
- // Return the body computation.
- return BodyVal;
- }
+ // Return the body computation.
+ return BodyVal;
+}
+```
The end result of all of this is that we get properly scoped variable
definitions, and we even (trivially) allow mutation of them :).
@@ -862,23 +852,22 @@ optimizes all of our stack variables into SSA registers, inserting PHI
nodes where needed, and our front-end remains simple: no "iterated
dominance frontier" computation anywhere in sight.
-Full Code Listing
-=================
+## Full Code Listing
Here is the complete code listing for our running example, enhanced with
mutable variables and var/in support. To build this example, use:
-.. code-block:: bash
-
- # Compile
- clang++ -g toy.cpp `llvm-config --cxxflags --ldflags --system-libs --libs core orcjit native` -O3 -o toy
- # Run
- ./toy
+```bash
+# Compile
+clang++ -g toy.cpp `llvm-config --cxxflags --ldflags --system-libs --libs core orcjit native` -O3 -o toy
+# Run
+./toy
+```
Here is the code:
-.. literalinclude:: ../../../examples/Kaleidoscope/Chapter7/toy.cpp
- :language: c++
-
-`Next: Compiling to Object Code <LangImpl08.html>`_
+```{literalinclude} ../../../examples/Kaleidoscope/Chapter7/toy.cpp
+:language: c++
+```
+[Next: Compiling to Object Code](LangImpl08.md)
diff --git a/llvm/docs/tutorial/MyFirstLanguageFrontend/LangImpl08.md b/llvm/docs/tutorial/MyFirstLanguageFrontend/LangImpl08.md
index 8940164d0572d..9f92f7da7b8d8 100644
--- a/llvm/docs/tutorial/MyFirstLanguageFrontend/LangImpl08.md
+++ b/llvm/docs/tutorial/MyFirstLanguageFrontend/LangImpl08.md
@@ -1,17 +1,11 @@
-========================================
- Kaleidoscope: Compiling to Object Code
-========================================
+# Kaleidoscope: Compiling to Object Code
+## Chapter 8 Introduction
-Chapter 8 Introduction
-======================
-
-Welcome to Chapter 8 of the "`Implementing a language with LLVM
-<index.html>`_" tutorial. This chapter describes how to compile our
+Welcome to Chapter 8 of the "[Implementing a language with LLVM](index.md)" tutorial. This chapter describes how to compile our
language down to object files.
-Choosing a target
-=================
+## Choosing a target
LLVM has native support for cross-compilation. You can compile to the
architecture of your current machine, or just as easily compile for
@@ -20,27 +14,26 @@ machine.
To specify the architecture that you want to target, we use a string
called a "target triple". This takes the form
-``<arch><sub>-<vendor>-<sys>-<abi>`` (see the `cross compilation docs
-<https://clang.llvm.org/docs/CrossCompilation.html#target-triple>`_).
+`<arch><sub>-<vendor>-<sys>-<abi>` (see the [cross compilation docs](https://clang.llvm.org/docs/CrossCompilation.html#target-triple)).
As an example, we can see what clang thinks is our current target
triple:
-::
-
- $ clang --version | grep Target
- Target: x86_64-unknown-linux-gnu
+```
+$ clang --version | grep Target
+Target: x86_64-unknown-linux-gnu
+```
Running this command may show something
diff erent on your machine as
you might be using a
diff erent architecture or operating system to me.
Fortunately, we don't need to hard-code a target triple to target the
-current machine. LLVM provides ``sys::getDefaultTargetTriple``, which
+current machine. LLVM provides `sys::getDefaultTargetTriple`, which
returns the target triple of the current machine.
-.. code-block:: c++
-
- auto TargetTriple = sys::getDefaultTargetTriple();
+```c++
+auto TargetTriple = sys::getDefaultTargetTriple();
+```
LLVM doesn't require us to link in all the target
functionality. For example, if we're just using the JIT, we don't need
@@ -51,165 +44,161 @@ architectures.
For this example, we'll initialize all the targets for emitting object
code.
-.. code-block:: c++
-
- InitializeAllTargetInfos();
- InitializeAllTargets();
- InitializeAllTargetMCs();
- InitializeAllAsmParsers();
- InitializeAllAsmPrinters();
+```c++
+InitializeAllTargetInfos();
+InitializeAllTargets();
+InitializeAllTargetMCs();
+InitializeAllAsmParsers();
+InitializeAllAsmPrinters();
+```
-We can now use our target triple to get a ``Target``:
+We can now use our target triple to get a `Target`:
-.. code-block:: c++
+```c++
+std::string Error;
+auto Target = TargetRegistry::lookupTarget(TargetTriple, Error);
- std::string Error;
- auto Target = TargetRegistry::lookupTarget(TargetTriple, Error);
+// Print an error and exit if we couldn't find the requested target.
+// This generally occurs if we've forgotten to initialise the
+// TargetRegistry or we have a bogus target triple.
+if (!Target) {
+ errs() << Error;
+ return 1;
+}
+```
- // Print an error and exit if we couldn't find the requested target.
- // This generally occurs if we've forgotten to initialise the
- // TargetRegistry or we have a bogus target triple.
- if (!Target) {
- errs() << Error;
- return 1;
- }
+## Target Machine
-Target Machine
-==============
-
-We will also need a ``TargetMachine``. This class provides a complete
+We will also need a `TargetMachine`. This class provides a complete
machine description of the machine we're targeting. If we want to
target a specific feature (such as SSE) or a specific CPU (such as
Intel's Sandylake), we do so now.
To see which features and CPUs that LLVM knows about, we can use
-``llc``. For example, let's look at x86:
-
-::
+`llc`. For example, let's look at x86:
- $ llvm-as < /dev/null | llc -march=x86 -mattr=help
- Available CPUs for this target:
+```
+$ llvm-as < /dev/null | llc -march=x86 -mattr=help
+Available CPUs for this target:
- amdfam10 - Select the amdfam10 processor.
- athlon - Select the athlon processor.
- athlon-4 - Select the athlon-4 processor.
- ...
+ amdfam10 - Select the amdfam10 processor.
+ athlon - Select the athlon processor.
+ athlon-4 - Select the athlon-4 processor.
+ ...
- Available features for this target:
+Available features for this target:
- 16bit-mode - 16-bit mode (i8086).
- 32bit-mode - 32-bit mode (80386).
- 3dnow - Enable 3DNow! instructions.
- 3dnowa - Enable 3DNow! Athlon instructions.
- ...
+ 16bit-mode - 16-bit mode (i8086).
+ 32bit-mode - 32-bit mode (80386).
+ 3dnow - Enable 3DNow! instructions.
+ 3dnowa - Enable 3DNow! Athlon instructions.
+ ...
+```
For our example, we'll use the generic CPU without any additional feature or
target option.
-.. code-block:: c++
-
- auto CPU = "generic";
- auto Features = "";
+```c++
+auto CPU = "generic";
+auto Features = "";
- TargetOptions opt;
- auto TargetMachine = Target->createTargetMachine(TargetTriple, CPU, Features, opt, Reloc::PIC_);
+TargetOptions opt;
+auto TargetMachine = Target->createTargetMachine(TargetTriple, CPU, Features, opt, Reloc::PIC_);
+```
-
-Configuring the Module
-======================
+## Configuring the Module
We're now ready to configure our module, to specify the target and
-data layout. This isn't strictly necessary, but the `frontend
-performance guide <../../Frontend/PerformanceTips.html>`_ recommends
+data layout. This isn't strictly necessary, but the [frontend
+performance guide](../../Frontend/PerformanceTips.md) recommends
this. Optimizations benefit from knowing about the target and data
layout.
-.. code-block:: c++
-
- TheModule->setDataLayout(TargetMachine->createDataLayout());
- TheModule->setTargetTriple(TargetTriple);
+```c++
+TheModule->setDataLayout(TargetMachine->createDataLayout());
+TheModule->setTargetTriple(TargetTriple);
+```
-Emit Object Code
-================
+## Emit Object Code
We're ready to emit object code! Let's define where we want to write
our file to:
-.. code-block:: c++
+```c++
+auto Filename = "output.o";
+std::error_code EC;
+raw_fd_ostream dest(Filename, EC, sys::fs::OF_None);
- auto Filename = "output.o";
- std::error_code EC;
- raw_fd_ostream dest(Filename, EC, sys::fs::OF_None);
-
- if (EC) {
- errs() << "Could not open file: " << EC.message();
- return 1;
- }
+if (EC) {
+ errs() << "Could not open file: " << EC.message();
+ return 1;
+}
+```
Finally, we define a pass that emits object code, then we run that
pass:
-.. code-block:: c++
-
- legacy::PassManager pass;
- auto FileType = CodeGenFileType::ObjectFile;
+```c++
+legacy::PassManager pass;
+auto FileType = CodeGenFileType::ObjectFile;
- if (TargetMachine->addPassesToEmitFile(pass, dest, nullptr, FileType)) {
- errs() << "TargetMachine can't emit a file of this type";
- return 1;
- }
+if (TargetMachine->addPassesToEmitFile(pass, dest, nullptr, FileType)) {
+ errs() << "TargetMachine can't emit a file of this type";
+ return 1;
+}
- pass.run(*TheModule);
- dest.flush();
+pass.run(*TheModule);
+dest.flush();
+```
-Putting It All Together
-=======================
+## Putting It All Together
Does it work? Let's give it a try. We need to compile our code, but
-note that the arguments to ``llvm-config`` are
diff erent to the previous chapters.
+note that the arguments to `llvm-config` are
diff erent to the previous chapters.
-::
+```
+$ clang++ -g -O3 toy.cpp `llvm-config --cxxflags --ldflags --system-libs --libs all` -o toy
+```
- $ clang++ -g -O3 toy.cpp `llvm-config --cxxflags --ldflags --system-libs --libs all` -o toy
-
-Let's run it, and define a simple ``average`` function. Press Ctrl-D
+Let's run it, and define a simple `average` function. Press Ctrl-D
when you're done.
-::
-
- $ ./toy
- ready> def average(x y) (x + y) * 0.5;
- ^D
- Wrote output.o
+```
+$ ./toy
+ready> def average(x y) (x + y) * 0.5;
+^D
+Wrote output.o
+```
We have an object file! To test it, let's write a simple program and
link it with our output. Here's the source code:
-.. code-block:: c++
-
- #include <iostream>
+```c++
+#include <iostream>
- extern "C" {
- double average(double, double);
- }
+extern "C" {
+ double average(double, double);
+}
- int main() {
- std::cout << "average of 3.0 and 4.0: " << average(3.0, 4.0) << std::endl;
- }
+int main() {
+ std::cout << "average of 3.0 and 4.0: " << average(3.0, 4.0) << std::endl;
+}
+```
We link our program to output.o and check the result is what we
expected:
-::
+```
+$ clang++ main.cpp output.o -o main
+$ ./main
+average of 3.0 and 4.0: 3.5
+```
- $ clang++ main.cpp output.o -o main
- $ ./main
- average of 3.0 and 4.0: 3.5
+## Full Code Listing
-Full Code Listing
-=================
+```{literalinclude} ../../../examples/Kaleidoscope/Chapter8/toy.cpp
+:language: c++
+```
-.. literalinclude:: ../../../examples/Kaleidoscope/Chapter8/toy.cpp
- :language: c++
+[Next: Adding Debug Information](LangImpl09.md)
-`Next: Adding Debug Information <LangImpl09.html>`_
diff --git a/llvm/docs/tutorial/MyFirstLanguageFrontend/LangImpl09.md b/llvm/docs/tutorial/MyFirstLanguageFrontend/LangImpl09.md
index 5a1581b59adab..cd2b9fbe4fbd4 100644
--- a/llvm/docs/tutorial/MyFirstLanguageFrontend/LangImpl09.md
+++ b/llvm/docs/tutorial/MyFirstLanguageFrontend/LangImpl09.md
@@ -1,13 +1,9 @@
-======================================
-Kaleidoscope: Adding Debug Information
-======================================
+# Kaleidoscope: Adding Debug Information
+## Chapter 9 Introduction
-Chapter 9 Introduction
-======================
-
-Welcome to Chapter 9 of the "`Implementing a language with
-LLVM <index.html>`_" tutorial. In chapters 1 through 8, we've built a
+Welcome to Chapter 9 of the "[Implementing a language with
+LLVM](index.md)" tutorial. In chapters 1 through 8, we've built a
decent little programming language with functions and variables.
What happens if something goes wrong though, how do you debug your
program?
@@ -15,7 +11,7 @@ program?
Source level debugging uses formatted data that helps a debugger
translate from binary and the state of the machine back to the
source that the programmer wrote. In LLVM we generally use a format
-called `DWARF <http://dwarfstd.org>`_. DWARF is a compact encoding
+called [DWARF](http://dwarfstd.org). DWARF is a compact encoding
that represents types, source locations, and variable locations.
The short summary of this chapter is that we'll go through the
@@ -33,19 +29,17 @@ changes necessary.
Here's the sample program we'll be compiling:
-.. code-block:: python
-
- def fib(x)
- if x < 3 then
- 1
- else
- fib(x-1)+fib(x-2);
-
- fib(10)
+```python
+def fib(x)
+ if x < 3 then
+ 1
+ else
+ fib(x-1)+fib(x-2);
+fib(10)
+```
-Why is this a hard problem?
-===========================
+## Why is this a hard problem?
Debug information is a hard problem for a few
diff erent reasons - mostly
centered around optimized code. First, optimization makes keeping source
@@ -59,8 +53,7 @@ with other variables, or
diff icult to track. For the purposes of this
tutorial we're going to avoid optimization (as you'll see with one of the
next sets of patches).
-Ahead-of-Time Compilation Mode
-==============================
+## Ahead-of-Time Compilation Mode
To highlight only the aspects of adding debug information to a source
language without needing to worry about the complexities of JIT debugging
@@ -71,105 +64,103 @@ you can execute, debug, and see results.
First we make our anonymous function that contains our top level
statement be our "main":
-.. code-block:: u
diff
-
- - auto Proto = std::make_unique<PrototypeAST>("", std::vector<std::string>());
- + auto Proto = std::make_unique<PrototypeAST>("main", std::vector<std::string>());
+```u
diff
+- auto Proto = std::make_unique<PrototypeAST>("", std::vector<std::string>());
++ auto Proto = std::make_unique<PrototypeAST>("main", std::vector<std::string>());
+```
just with the simple change of giving it a name.
Then we're going to remove the command line code wherever it exists:
-.. code-block:: u
diff
-
- @@ -1129,7 +1129,6 @@ static void HandleTopLevelExpression() {
- /// top ::= definition | external | expression | ';'
- static void MainLoop() {
- while (true) {
- - fprintf(stderr, "ready> ");
- switch (CurTok) {
- case tok_eof:
- return;
- @@ -1184,7 +1183,6 @@ int main() {
- BinopPrecedence['*'] = 40; // highest.
-
- // Prime the first token.
- - fprintf(stderr, "ready> ");
- getNextToken();
+```u
diff
+@@ -1129,7 +1129,6 @@ static void HandleTopLevelExpression() {
+ /// top ::= definition | external | expression | ';'
+ static void MainLoop() {
+ while (true) {
+- fprintf(stderr, "ready> ");
+ switch (CurTok) {
+ case tok_eof:
+ return;
+@@ -1184,7 +1183,6 @@ int main() {
+ BinopPrecedence['*'] = 40; // highest.
+
+ // Prime the first token.
+- fprintf(stderr, "ready> ");
+ getNextToken();
+```
Lastly we're going to disable all of the optimization passes and the JIT so
that the only thing that happens after we're done parsing and generating
code is that the LLVM IR goes to standard error:
-.. code-block:: u
diff
-
- @@ -1108,17 +1108,8 @@ static void HandleExtern() {
- static void HandleTopLevelExpression() {
- // Evaluate a top-level expression into an anonymous function.
- if (auto FnAST = ParseTopLevelExpr()) {
- - if (auto *FnIR = FnAST->codegen()) {
- - // We're just doing this to make sure it executes.
- - TheExecutionEngine->finalizeObject();
- - // JIT the function, returning a function pointer.
- - void *FPtr = TheExecutionEngine->getPointerToFunction(FnIR);
- -
- - // Cast it to the right type (takes no arguments, returns a double) so we
- - // can call it as a native function.
- - double (*FP)() = (double (*)())(intptr_t)FPtr;
- - // Ignore the return value for this.
- - (void)FP;
- + if (!FnAST->codegen()) {
- + fprintf(stderr, "Error generating code for top level expr");
- }
- } else {
- // Skip token for error recovery.
- @@ -1439,11 +1459,11 @@ int main() {
- // target lays out data structures.
- TheModule->setDataLayout(TheExecutionEngine->getDataLayout());
- OurFPM.add(new DataLayoutPass());
- +#if 0
- OurFPM.add(createBasicAliasAnalysisPass());
- // Promote allocas to registers.
- OurFPM.add(createPromoteMemoryToRegisterPass());
- @@ -1218,7 +1210,7 @@ int main() {
- OurFPM.add(createGVNPass());
- // Simplify the control flow graph (deleting unreachable blocks, etc).
- OurFPM.add(createCFGSimplificationPass());
- -
- + #endif
- OurFPM.doInitialization();
-
- // Set the global so the code gen can use this.
+```u
diff
+@@ -1108,17 +1108,8 @@ static void HandleExtern() {
+ static void HandleTopLevelExpression() {
+ // Evaluate a top-level expression into an anonymous function.
+ if (auto FnAST = ParseTopLevelExpr()) {
+- if (auto *FnIR = FnAST->codegen()) {
+- // We're just doing this to make sure it executes.
+- TheExecutionEngine->finalizeObject();
+- // JIT the function, returning a function pointer.
+- void *FPtr = TheExecutionEngine->getPointerToFunction(FnIR);
+-
+- // Cast it to the right type (takes no arguments, returns a double) so we
+- // can call it as a native function.
+- double (*FP)() = (double (*)())(intptr_t)FPtr;
+- // Ignore the return value for this.
+- (void)FP;
++ if (!FnAST->codegen()) {
++ fprintf(stderr, "Error generating code for top level expr");
+ }
+ } else {
+ // Skip token for error recovery.
+@@ -1439,11 +1459,11 @@ int main() {
+ // target lays out data structures.
+ TheModule->setDataLayout(TheExecutionEngine->getDataLayout());
+ OurFPM.add(new DataLayoutPass());
++#if 0
+ OurFPM.add(createBasicAliasAnalysisPass());
+ // Promote allocas to registers.
+ OurFPM.add(createPromoteMemoryToRegisterPass());
+@@ -1218,7 +1210,7 @@ int main() {
+ OurFPM.add(createGVNPass());
+ // Simplify the control flow graph (deleting unreachable blocks, etc).
+ OurFPM.add(createCFGSimplificationPass());
+-
++ #endif
+ OurFPM.doInitialization();
+
+ // Set the global so the code gen can use this.
+```
This relatively small set of changes get us to the point that we can compile
our piece of Kaleidoscope language down to an executable program via this
command line:
-.. code-block:: bash
-
- Kaleidoscope-Ch9 < fib.ks | & clang -x ir -
+```bash
+Kaleidoscope-Ch9 < fib.ks | & clang -x ir -
+```
which gives an a.out/a.exe in the current working directory.
-Compile Unit
-============
+## Compile Unit
The top level container for a section of code in DWARF is a compile unit.
This contains the type and function data for an individual translation unit
(read: one file of source code). So the first thing we need to do is
construct one for our fib.ks file.
-DWARF Emission Setup
-====================
+## DWARF Emission Setup
-Similar to the ``IRBuilder`` class we have a
-`DIBuilder <https://llvm.org/doxygen/classllvm_1_1DIBuilder.html>`_ class
+Similar to the `IRBuilder` class we have a
+[DIBuilder](https://llvm.org/doxygen/classllvm_1_1DIBuilder.html) class
that helps in constructing debug metadata for an LLVM IR file. It
-corresponds 1:1 similarly to ``IRBuilder`` and LLVM IR, but with nicer names.
+corresponds 1:1 similarly to `IRBuilder` and LLVM IR, but with nicer names.
Using it does require that you be more familiar with DWARF terminology than
-you needed to be with ``IRBuilder`` and ``Instruction`` names, but if you
+you needed to be with `IRBuilder` and `Instruction` names, but if you
read through the general documentation on the
-`Metadata Format <https://llvm.org/docs/SourceLevelDebugging.html>`_ it
+[Metadata Format](https://llvm.org/docs/SourceLevelDebugging.html) it
should be a little more clear. We'll be using this class to construct all
of our IR level descriptions. Construction for it takes a module so we
need to construct it shortly after we construct our module. We've left it
@@ -180,34 +171,34 @@ data. The first will be our compile unit, but we'll also write a bit of
code for our one type since we won't have to worry about multiple typed
expressions:
-.. code-block:: c++
-
- static std::unique_ptr<DIBuilder> DBuilder;
-
- struct DebugInfo {
- DICompileUnit *TheCU;
- DIType *DblTy;
+```c++
+static std::unique_ptr<DIBuilder> DBuilder;
- DIType *getDoubleTy();
- } KSDbgInfo;
+struct DebugInfo {
+ DICompileUnit *TheCU;
+ DIType *DblTy;
- DIType *DebugInfo::getDoubleTy() {
- if (DblTy)
- return DblTy;
+ DIType *getDoubleTy();
+} KSDbgInfo;
- DblTy = DBuilder->createBasicType("double", 64, dwarf::DW_ATE_float);
+DIType *DebugInfo::getDoubleTy() {
+ if (DblTy)
return DblTy;
- }
-And then later on in ``main`` when we're constructing our module:
+ DblTy = DBuilder->createBasicType("double", 64, dwarf::DW_ATE_float);
+ return DblTy;
+}
+```
-.. code-block:: c++
+And then later on in `main` when we're constructing our module:
- DBuilder = std::make_unique<DIBuilder>(*TheModule);
+```c++
+DBuilder = std::make_unique<DIBuilder>(*TheModule);
- KSDbgInfo.TheCU = DBuilder->createCompileUnit(
- dwarf::DW_LANG_C, DBuilder->createFile("fib.ks", "."),
- "Kaleidoscope Compiler", false, "", 0);
+KSDbgInfo.TheCU = DBuilder->createCompileUnit(
+ dwarf::DW_LANG_C, DBuilder->createFile("fib.ks", "."),
+ "Kaleidoscope Compiler", false, "", 0);
+```
There are a couple of things to note here. First, while we're producing a
compile unit for a language called Kaleidoscope we used the language
@@ -216,7 +207,7 @@ the calling conventions or default ABI for a language it doesn't recognize
and we follow the C ABI in our LLVM code generation so it's the closest
thing to accurate. This ensures we can actually call functions from the
debugger and have them execute. Secondly, you'll see the "fib.ks" in the
-call to ``createCompileUnit``. This is a default hard coded value since
+call to `createCompileUnit`. This is a default hard coded value since
we're using shell redirection to put our source into the Kaleidoscope
compiler. In a usual front end you'd have an input file name and it would
go there.
@@ -226,195 +217,191 @@ we need to "finalize" the debug information. The reasons are part of the
underlying API for DIBuilder, but make sure you do this near the end of
main:
-.. code-block:: c++
-
- DBuilder->finalize();
+```c++
+DBuilder->finalize();
+```
before you dump out the module.
-Functions
-=========
+## Functions
-Now that we have our ``Compile Unit`` and our source locations, we can add
-function definitions to the debug info. So in ``FunctionAST::codegen()`` we
+Now that we have our `Compile Unit` and our source locations, we can add
+function definitions to the debug info. So in `FunctionAST::codegen()` we
add a few lines of code to describe a context for our subprogram, in this
case the "File", and the actual definition of the function itself.
So the context:
-.. code-block:: c++
-
- DIFile *Unit = DBuilder->createFile(KSDbgInfo.TheCU->getFilename(),
- KSDbgInfo.TheCU->getDirectory());
+```c++
+DIFile *Unit = DBuilder->createFile(KSDbgInfo.TheCU->getFilename(),
+ KSDbgInfo.TheCU->getDirectory());
+```
-giving us an DIFile and asking the ``Compile Unit`` we created above for the
+giving us an DIFile and asking the `Compile Unit` we created above for the
directory and filename where we are currently. Then, for now, we use some
source locations of 0 (since our AST doesn't currently have source location
information) and construct our function definition:
-.. code-block:: c++
-
- DIScope *FContext = Unit;
- unsigned LineNo = 0;
- unsigned ScopeLine = 0;
- DISubprogram *SP = DBuilder->createFunction(
- FContext, P.getName(), StringRef(), Unit, LineNo,
- CreateFunctionType(TheFunction->arg_size()),
- ScopeLine,
- DINode::FlagPrototyped,
- DISubprogram::SPFlagDefinition);
- TheFunction->setSubprogram(SP);
+```c++
+DIScope *FContext = Unit;
+unsigned LineNo = 0;
+unsigned ScopeLine = 0;
+DISubprogram *SP = DBuilder->createFunction(
+ FContext, P.getName(), StringRef(), Unit, LineNo,
+ CreateFunctionType(TheFunction->arg_size()),
+ ScopeLine,
+ DINode::FlagPrototyped,
+ DISubprogram::SPFlagDefinition);
+TheFunction->setSubprogram(SP);
+```
and we now have an DISubprogram that contains a reference to all of our
metadata for the function.
-Source Locations
-================
+## Source Locations
The most important thing for debug information is accurate source location -
this makes it possible to map your source code back. We have a problem though,
Kaleidoscope really doesn't have any source location information in the lexer
or parser so we'll need to add it.
-.. code-block:: c++
-
- struct SourceLocation {
- int Line;
- int Col;
- };
- static SourceLocation CurLoc;
- static SourceLocation LexLoc = {1, 0};
-
- static int advance() {
- int LastChar = getchar();
-
- if (LastChar == '\n' || LastChar == '\r') {
- LexLoc.Line++;
- LexLoc.Col = 0;
- } else
- LexLoc.Col++;
- return LastChar;
- }
+```c++
+struct SourceLocation {
+ int Line;
+ int Col;
+};
+static SourceLocation CurLoc;
+static SourceLocation LexLoc = {1, 0};
+
+static int advance() {
+ int LastChar = getchar();
+
+ if (LastChar == '\n' || LastChar == '\r') {
+ LexLoc.Line++;
+ LexLoc.Col = 0;
+ } else
+ LexLoc.Col++;
+ return LastChar;
+}
+```
In this set of code we've added some functionality on how to keep track of the
line and column of the "source file". As we lex every token we set our
current "lexical location" to the assorted line and column for the beginning
of the token. We do this by overriding all of the previous calls to
-``getchar()`` with our new ``advance()`` that keeps track of the information
+`getchar()` with our new `advance()` that keeps track of the information
and then we have added to all of our AST classes a source location:
-.. code-block:: c++
-
- class ExprAST {
- SourceLocation Loc;
-
- public:
- ExprAST(SourceLocation Loc = CurLoc) : Loc(Loc) {}
- virtual ~ExprAST() {}
- virtual Value* codegen() = 0;
- int getLine() const { return Loc.Line; }
- int getCol() const { return Loc.Col; }
- virtual raw_ostream &dump(raw_ostream &out, int ind) {
- return out << ':' << getLine() << ':' << getCol() << '\n';
- }
+```c++
+class ExprAST {
+ SourceLocation Loc;
+
+ public:
+ ExprAST(SourceLocation Loc = CurLoc) : Loc(Loc) {}
+ virtual ~ExprAST() {}
+ virtual Value* codegen() = 0;
+ int getLine() const { return Loc.Line; }
+ int getCol() const { return Loc.Col; }
+ virtual raw_ostream &dump(raw_ostream &out, int ind) {
+ return out << ':' << getLine() << ':' << getCol() << '\n';
+ }
+```
that we pass down through when we create a new expression:
-.. code-block:: c++
-
- LHS = std::make_unique<BinaryExprAST>(BinLoc, BinOp, std::move(LHS),
- std::move(RHS));
+```c++
+LHS = std::make_unique<BinaryExprAST>(BinLoc, BinOp, std::move(LHS),
+ std::move(RHS));
+```
giving us locations for each of our expressions and variables.
To make sure that every instruction gets proper source location information,
-we have to tell ``Builder`` whenever we're at a new source location.
+we have to tell `Builder` whenever we're at a new source location.
We use a small helper function for this:
-.. code-block:: c++
-
- void DebugInfo::emitLocation(ExprAST *AST) {
- if (!AST)
- return Builder->SetCurrentDebugLocation(DebugLoc());
- DIScope *Scope;
- if (LexicalBlocks.empty())
- Scope = TheCU;
- else
- Scope = LexicalBlocks.back();
- Builder->SetCurrentDebugLocation(
- DILocation::get(Scope->getContext(), AST->getLine(), AST->getCol(), Scope));
- }
-
-This both tells the main ``IRBuilder`` where we are, but also what scope
+```c++
+void DebugInfo::emitLocation(ExprAST *AST) {
+ if (!AST)
+ return Builder->SetCurrentDebugLocation(DebugLoc());
+ DIScope *Scope;
+ if (LexicalBlocks.empty())
+ Scope = TheCU;
+ else
+ Scope = LexicalBlocks.back();
+ Builder->SetCurrentDebugLocation(
+ DILocation::get(Scope->getContext(), AST->getLine(), AST->getCol(), Scope));
+}
+```
+
+This both tells the main `IRBuilder` where we are, but also what scope
we're in. The scope can either be on compile-unit level or be the nearest
enclosing lexical block like the current function.
-To represent this we create a stack of scopes in ``DebugInfo``:
-
-.. code-block:: c++
+To represent this we create a stack of scopes in `DebugInfo`:
- std::vector<DIScope *> LexicalBlocks;
+```c++
+std::vector<DIScope *> LexicalBlocks;
+```
and push the scope (function) to the top of the stack when we start
generating the code for each function:
-.. code-block:: c++
-
- KSDbgInfo.LexicalBlocks.push_back(SP);
+```c++
+KSDbgInfo.LexicalBlocks.push_back(SP);
+```
Also, we may not forget to pop the scope back off of the scope stack at the
end of the code generation for the function:
-.. code-block:: c++
-
- // Pop off the lexical block for the function since we added it
- // unconditionally.
- KSDbgInfo.LexicalBlocks.pop_back();
+```c++
+// Pop off the lexical block for the function since we added it
+// unconditionally.
+KSDbgInfo.LexicalBlocks.pop_back();
+```
Then we make sure to emit the location every time we start to generate code
for a new AST object:
-.. code-block:: c++
-
- KSDbgInfo.emitLocation(this);
+```c++
+KSDbgInfo.emitLocation(this);
+```
-Variables
-=========
+## Variables
Now that we have functions, we need to be able to print out the variables
we have in scope. Let's get our function arguments set up so we can get
decent backtraces and see how our functions are being called. It isn't
a lot of code, and we generally handle it when we're creating the
-argument allocas in ``FunctionAST::codegen``.
-
-.. code-block:: c++
-
- // Record the function arguments in the NamedValues map.
- NamedValues.clear();
- unsigned ArgIdx = 0;
- for (auto &Arg : TheFunction->args()) {
- // Create an alloca for this variable.
- AllocaInst *Alloca = CreateEntryBlockAlloca(TheFunction, Arg.getName());
-
- // Create a debug descriptor for the variable.
- DILocalVariable *D = DBuilder->createParameterVariable(
- SP, Arg.getName(), ++ArgIdx, Unit, LineNo, KSDbgInfo.getDoubleTy(),
- true);
-
- DBuilder->insertDeclare(Alloca, D, DBuilder->createExpression(),
- DILocation::get(SP->getContext(), LineNo, 0, SP),
- Builder->GetInsertBlock());
-
- // Store the initial value into the alloca.
- Builder->CreateStore(&Arg, Alloca);
-
- // Add arguments to variable symbol table.
- NamedValues[std::string(Arg.getName())] = Alloca;
- }
-
-
-Here we're first creating the variable, giving it the scope (``SP``),
+argument allocas in `FunctionAST::codegen`.
+
+```c++
+// Record the function arguments in the NamedValues map.
+NamedValues.clear();
+unsigned ArgIdx = 0;
+for (auto &Arg : TheFunction->args()) {
+ // Create an alloca for this variable.
+ AllocaInst *Alloca = CreateEntryBlockAlloca(TheFunction, Arg.getName());
+
+ // Create a debug descriptor for the variable.
+ DILocalVariable *D = DBuilder->createParameterVariable(
+ SP, Arg.getName(), ++ArgIdx, Unit, LineNo, KSDbgInfo.getDoubleTy(),
+ true);
+
+ DBuilder->insertDeclare(Alloca, D, DBuilder->createExpression(),
+ DILocation::get(SP->getContext(), LineNo, 0, SP),
+ Builder->GetInsertBlock());
+
+ // Store the initial value into the alloca.
+ Builder->CreateStore(&Arg, Alloca);
+
+ // Add arguments to variable symbol table.
+ NamedValues[std::string(Arg.getName())] = Alloca;
+}
+```
+
+Here we're first creating the variable, giving it the scope (`SP`),
the name, source location, type, and since it's an argument, the argument
-index. Next, we create a ``#dbg_declare`` record to indicate at the IR
+index. Next, we create a `#dbg_declare` record to indicate at the IR
level that we've got a variable in an alloca (and it gives a starting
location for the variable), and setting a source location for the
beginning of the scope on the declare.
@@ -424,43 +411,43 @@ assumptions based on how code and debug information was generated for them
in the past. In this case we need to do a little bit of a hack to avoid
generating line information for the function prologue so that the debugger
knows to skip over those instructions when setting a breakpoint. So in
-``FunctionAST::CodeGen`` we add some more lines:
-
-.. code-block:: c++
+`FunctionAST::CodeGen` we add some more lines:
- // Unset the location for the prologue emission (leading instructions with no
- // location in a function are considered part of the prologue and the debugger
- // will run past them when breaking on a function)
- KSDbgInfo.emitLocation(nullptr);
+```c++
+// Unset the location for the prologue emission (leading instructions with no
+// location in a function are considered part of the prologue and the debugger
+// will run past them when breaking on a function)
+KSDbgInfo.emitLocation(nullptr);
+```
and then emit a new location when we actually start generating code for the
body of the function:
-.. code-block:: c++
-
- KSDbgInfo.emitLocation(Body.get());
+```c++
+KSDbgInfo.emitLocation(Body.get());
+```
With this we have enough debug information to set breakpoints in functions,
print out argument variables, and call functions. Not too bad for just a
few simple lines of code!
-Full Code Listing
-=================
+## Full Code Listing
Here is the complete code listing for our running example, enhanced with
debug information. To build this example, use:
-.. code-block:: bash
-
- # Compile
- clang++ -g toy.cpp `llvm-config --cxxflags --ldflags --system-libs --libs core orcjit native` -O3 -o toy
- # Run
- ./toy
+```bash
+# Compile
+clang++ -g toy.cpp `llvm-config --cxxflags --ldflags --system-libs --libs core orcjit native` -O3 -o toy
+# Run
+./toy
+```
Here is the code:
-.. literalinclude:: ../../../examples/Kaleidoscope/Chapter9/toy.cpp
- :language: c++
+```{literalinclude} ../../../examples/Kaleidoscope/Chapter9/toy.cpp
+:language: c++
+```
-`Next: Conclusion and other useful LLVM tidbits <LangImpl10.html>`_
+[Next: Conclusion and other useful LLVM tidbits](LangImpl10.md)
diff --git a/llvm/docs/tutorial/MyFirstLanguageFrontend/LangImpl10.md b/llvm/docs/tutorial/MyFirstLanguageFrontend/LangImpl10.md
index feb34dc5cfc91..4213ec9ff4f54 100644
--- a/llvm/docs/tutorial/MyFirstLanguageFrontend/LangImpl10.md
+++ b/llvm/docs/tutorial/MyFirstLanguageFrontend/LangImpl10.md
@@ -1,13 +1,9 @@
-======================================================
-Kaleidoscope: Conclusion and other useful LLVM tidbits
-======================================================
+# Kaleidoscope: Conclusion and other useful LLVM tidbits
+## Tutorial Conclusion
-Tutorial Conclusion
-===================
-
-Welcome to the final chapter of the "`Implementing a language with
-LLVM <index.html>`_" tutorial. In the course of this tutorial, we have
+Welcome to the final chapter of the "[Implementing a language with
+LLVM](index.md)" tutorial. In the course of this tutorial, we have
grown our little Kaleidoscope language from being a useless toy, to
being a semi-interesting (but probably still useless) toy. :)
@@ -28,65 +24,64 @@ need not be a scary or mystical process! Now that you've seen some of
the basics, I strongly encourage you to take the code and hack on it.
For example, try adding:
-- **global variables** - While global variables have questionable value
- in modern software engineering, they are often useful when putting
- together quick little hacks like the Kaleidoscope compiler itself.
- Fortunately, our current setup makes it very easy to add global
- variables: just have value lookup check to see if an unresolved
- variable is in the global variable symbol table before rejecting it.
- To create a new global variable, make an instance of the LLVM
- ``GlobalVariable`` class.
-- **typed variables** - Kaleidoscope currently only supports variables
- of type double. This gives the language a very nice elegance, because
- only supporting one type means that you never have to specify types.
- Different languages have
diff erent ways of handling this. The easiest
- way is to require the user to specify types for every variable
- definition, and record the type of the variable in the symbol table
- along with its Value\*.
-- **arrays, structs, vectors, etc** - Once you add types, you can start
- extending the type system in all sorts of interesting ways. Simple
- arrays are very easy and are quite useful for many
diff erent
- applications. Adding them is mostly an exercise in learning how the
- LLVM `getelementptr <../../LangRef.html#getelementptr-instruction>`_ instruction
- works: it is so nifty/unconventional, it `has its own
- FAQ <../../GetElementPtr.html>`_!
-- **standard runtime** - Our current language allows the user to access
- arbitrary external functions, and we use it for things like "printd"
- and "putchard". As you extend the language to add higher-level
- constructs, often these constructs make the most sense if they are
- lowered to calls into a language-supplied runtime. For example, if
- you add hash tables to the language, it would probably make sense to
- add the routines to a runtime, instead of inlining them all the way.
-- **memory management** - Currently we can only access the stack in
- Kaleidoscope. It would also be useful to be able to allocate heap
- memory, either with calls to the standard libc malloc/free interface
- or with a garbage collector. If you would like to use garbage
- collection, note that LLVM fully supports `Accurate Garbage
- Collection <../../GarbageCollection.html>`_ including algorithms that
- move objects and need to scan/update the stack.
-- **exception handling support** - LLVM supports generation of `zero
- cost exceptions <../../ExceptionHandling.html>`_ which interoperate with
- code compiled in other languages. You could also generate code by
- implicitly making every function return an error value and checking
- it. You could also make explicit use of setjmp/longjmp. There are
- many
diff erent ways to go here.
-- **object orientation, generics, database access, complex numbers,
- geometric programming, ...** - Really, there is no end of crazy
- features that you can add to the language.
-- **unusual domains** - We've been talking about applying LLVM to a
- domain that many people are interested in: building a compiler for a
- specific language. However, there are many other domains that can use
- compiler technology that are not typically considered. For example,
- LLVM has been used to implement OpenGL graphics acceleration,
- translate C++ code to ActionScript, and many other cute and clever
- things. Maybe you will be the first to JIT compile a regular
- expression interpreter into native code with LLVM?
+- **global variables** - While global variables have questionable value
+ in modern software engineering, they are often useful when putting
+ together quick little hacks like the Kaleidoscope compiler itself.
+ Fortunately, our current setup makes it very easy to add global
+ variables: just have value lookup check to see if an unresolved
+ variable is in the global variable symbol table before rejecting it.
+ To create a new global variable, make an instance of the LLVM
+ `GlobalVariable` class.
+- **typed variables** - Kaleidoscope currently only supports variables
+ of type double. This gives the language a very nice elegance, because
+ only supporting one type means that you never have to specify types.
+ Different languages have
diff erent ways of handling this. The easiest
+ way is to require the user to specify types for every variable
+ definition, and record the type of the variable in the symbol table
+ along with its `Value*`.
+- **arrays, structs, vectors, etc** - Once you add types, you can start
+ extending the type system in all sorts of interesting ways. Simple
+ arrays are very easy and are quite useful for many
diff erent
+ applications. Adding them is mostly an exercise in learning how the
+ LLVM [getelementptr](../../LangRef.md#getelementptr-instruction) instruction
+ works: it is so nifty/unconventional, it [has its own
+ FAQ](../../GetElementPtr.rst)!
+- **standard runtime** - Our current language allows the user to access
+ arbitrary external functions, and we use it for things like "printd"
+ and "putchard". As you extend the language to add higher-level
+ constructs, often these constructs make the most sense if they are
+ lowered to calls into a language-supplied runtime. For example, if
+ you add hash tables to the language, it would probably make sense to
+ add the routines to a runtime, instead of inlining them all the way.
+- **memory management** - Currently we can only access the stack in
+ Kaleidoscope. It would also be useful to be able to allocate heap
+ memory, either with calls to the standard libc malloc/free interface
+ or with a garbage collector. If you would like to use garbage
+ collection, note that LLVM fully supports [Accurate Garbage
+ Collection](../../GarbageCollection.md) including algorithms that
+ move objects and need to scan/update the stack.
+- **exception handling support** - LLVM supports generation of [zero
+ cost exceptions](../../ExceptionHandling.md) which interoperate with
+ code compiled in other languages. You could also generate code by
+ implicitly making every function return an error value and checking
+ it. You could also make explicit use of setjmp/longjmp. There are
+ many
diff erent ways to go here.
+- **object orientation, generics, database access, complex numbers,
+ geometric programming, ...** - Really, there is no end of crazy
+ features that you can add to the language.
+- **unusual domains** - We've been talking about applying LLVM to a
+ domain that many people are interested in: building a compiler for a
+ specific language. However, there are many other domains that can use
+ compiler technology that are not typically considered. For example,
+ LLVM has been used to implement OpenGL graphics acceleration,
+ translate C++ code to ActionScript, and many other cute and clever
+ things. Maybe you will be the first to JIT compile a regular
+ expression interpreter into native code with LLVM?
Have fun - try doing something crazy and unusual. Building a language
like everyone else always has, is much less fun than trying something a
little crazy or off the wall and seeing how it turns out. If you get
-stuck or want to talk about it, please post on the `LLVM forums
-<https://discourse.llvm.org>`_: it has lots of people who are interested
+stuck or want to talk about it, please post on the [LLVM forums](https://discourse.llvm.org): it has lots of people who are interested
in languages and are often willing to help out.
Before we end this tutorial, I want to talk about some "tips and tricks"
@@ -94,14 +89,12 @@ for generating LLVM IR. These are some of the more subtle things that
may not be obvious, but are very useful if you want to take advantage of
LLVM's capabilities.
-Properties of the LLVM IR
-=========================
+## Properties of the LLVM IR
We have a couple of common questions about code in the LLVM IR form -
let's just get these out of the way right now, shall we?
-Target Independence
--------------------
+### Target Independence
Kaleidoscope is an example of a "portable language": any program written
in Kaleidoscope will work the same way on any target that it runs on.
@@ -131,13 +124,13 @@ laden with target-specific assumptions. As one simple example, the
preprocessor often destructively removes target-independence from the
code when it processes the input text:
-.. code-block:: c
-
- #ifdef __i386__
- int X = 1;
- #else
- int X = 42;
- #endif
+```c
+#ifdef __i386__
+ int X = 1;
+#else
+ int X = 42;
+#endif
+```
While it is possible to engineer more and more complex solutions to
problems like this, it cannot be solved in full generality in a way that
@@ -150,8 +143,7 @@ existing binaries, and are willing to give up some other minor features,
you can have portable code. This can make sense for specialized domains
such as an in-kernel language.
-Safety Guarantees
------------------
+### Safety Guarantees
Many of the languages above are also "safe" languages: it is impossible
for a program written in Java to corrupt its address space and crash the
@@ -163,17 +155,16 @@ It is certainly possible to implement a safe language in LLVM, but LLVM
IR does not itself guarantee safety. The LLVM IR allows unsafe pointer
casts, use after free bugs, buffer over-runs, and a variety of other
problems. Safety needs to be implemented as a layer on top of LLVM and,
-conveniently, several groups have investigated this. Ask on the `LLVM
-forums <https://discourse.llvm.org>`_ if you are interested in more details.
+conveniently, several groups have investigated this. Ask on the [LLVM
+forums](https://discourse.llvm.org) if you are interested in more details.
-Language-Specific Optimizations
--------------------------------
+### Language-Specific Optimizations
One thing about LLVM that turns off many people is that it does not
-solve all the world's problems in one system. One specific
+solve all the world's problems in one system. One specific
complaint is that people perceive LLVM as being incapable of performing
high-level language-specific optimization: LLVM "loses too much
-information". Here are a few observations about this:
+information". Here are a few observations about this:
First, you're right that LLVM does lose information. For example, as of
this writing, there is no way to distinguish in the LLVM IR whether an
@@ -212,16 +203,14 @@ the llvm-dev list. At the very worst, you can always treat LLVM as if it
were a "dumb code generator" and implement the high-level optimizations
you desire in your front-end, on the language-specific AST.
-Tips and Tricks
-===============
+## Tips and Tricks
There is a variety of useful tips and tricks that you come to know after
working on/with LLVM that aren't obvious at first glance. Instead of
letting everyone rediscover them, this section talks about some of these
issues.
-Implementing portable offsetof/sizeof
--------------------------------------
+### Implementing portable offsetof/sizeof
One interesting thing that comes up, if you are trying to keep the code
generated by your compiler "target independent", is that you often need
@@ -231,20 +220,18 @@ into a function that allocates memory.
Unfortunately, this can vary widely across targets: for example the
width of a pointer is trivially target-specific. However, there is a
-`clever way to use the getelementptr
-instruction <http://nondot.org/sabre/LLVMNotes/SizeOf-OffsetOf-VariableSizedStructs.txt>`_
+[clever way to use the getelementptr
+instruction](http://nondot.org/sabre/LLVMNotes/SizeOf-OffsetOf-VariableSizedStructs.txt)
that allows you to compute this in a portable way.
-Garbage Collected Stack Frames
-------------------------------
+### Garbage Collected Stack Frames
Some languages want to explicitly manage their stack frames, often so
that they are garbage collected or to allow easy implementation of
closures. There are often better ways to implement these features than
-explicit stack frames, but `LLVM does support
-them, <http://nondot.org/sabre/LLVMNotes/ExplicitlyManagedStackFrames.txt>`_
+explicit stack frames, but [LLVM does support
+them,](http://nondot.org/sabre/LLVMNotes/ExplicitlyManagedStackFrames.txt)
if you want. It requires your front-end to convert the code into
-`Continuation Passing
-Style <http://en.wikipedia.org/wiki/Continuation-passing_style>`_ and
+[Continuation Passing
+Style](http://en.wikipedia.org/wiki/Continuation-passing_style) and
the use of tail calls (which LLVM also supports).
-
diff --git a/llvm/docs/tutorial/MyFirstLanguageFrontend/index.md b/llvm/docs/tutorial/MyFirstLanguageFrontend/index.md
index 230313ddd21db..4a7cd5fd5fe7c 100644
--- a/llvm/docs/tutorial/MyFirstLanguageFrontend/index.md
+++ b/llvm/docs/tutorial/MyFirstLanguageFrontend/index.md
@@ -1,13 +1,11 @@
-=============================================
-My First Language Frontend with LLVM Tutorial
-=============================================
+# My First Language Frontend with LLVM Tutorial
**Requirements:** This tutorial assumes you know C++, but no previous
compiler experience is necessary.
Welcome to the "My First Language Frontend with LLVM" tutorial. Here we
run through the implementation of a simple language, showing
-how fun and easy it can be. This tutorial will get you up and running
+how fun and easy it can be. This tutorial will get you up and running
fast and show a concrete example of something that uses LLVM to generate
code.
@@ -15,70 +13,69 @@ This tutorial introduces the simple "Kaleidoscope" language, building it
iteratively over the course of several chapters, showing how it is built
over time. This lets us cover a range of language design and LLVM-specific
ideas, showing and explaining the code for it all along the way,
-and reduces the overwhelming amount of details up front. We strongly
+and reduces the overwhelming amount of details up front. We strongly
encourage that you *work with this code* - make a copy and hack it up and
experiment.
**Warning**: In order to focus on teaching compiler techniques and LLVM
specifically,
this tutorial does *not* show best practices in software engineering
-principles. For example, the code uses global variables
+principles. For example, the code uses global variables
pervasively, doesn't use
-`visitors <http://en.wikipedia.org/wiki/Visitor_pattern>`_, etc... but
+[visitors](http://en.wikipedia.org/wiki/Visitor_pattern), etc... but
instead keeps things simple and focuses on the topics at hand.
This tutorial is structured into chapters covering individual topics,
allowing you to skip ahead as you wish:
-- `Chapter #1: Kaleidoscope language and Lexer <LangImpl01.html>`_ -
- This shows where we are
- going and the basic functionality that we want to build. A lexer
- is also the first part of building a parser for a language, and we
- use a simple C++ lexer which is easy to understand.
-- `Chapter #2: Implementing a Parser and AST <LangImpl02.html>`_ -
- With the lexer in place, we can talk about parsing techniques and
- basic AST construction. This tutorial describes recursive descent
- parsing and operator precedence parsing.
-- `Chapter #3: Code generation to LLVM IR <LangImpl03.html>`_ - with
- the AST ready, we show how easy it is to generate LLVM IR, and show
- a simple way to incorporate LLVM into your project.
-- `Chapter #4: Adding JIT and Optimizer Support <LangImpl04.html>`_ -
- One great thing about LLVM is its support for JIT compilation, so
- we'll dive right into it and show you the 3 lines it takes to add JIT
- support. Later chapters show how to generate .o files.
-- `Chapter #5: Extending the Language: Control Flow <LangImpl05.html>`_ - With
- the basic language up and running, we show how to extend
- it with control flow operations ('if' statement and a 'for' loop). This
- gives us a chance to talk about SSA construction and control
- flow.
-- `Chapter #6: Extending the Language: User-defined Operators
- <LangImpl06.html>`_ - This chapter extends the language to let
- users define arbitrary unary and binary operators - with assignable
- precedence! This allows us to build a significant piece of the
- "language" as library routines.
-- `Chapter #7: Extending the Language: Mutable Variables
- <LangImpl07.html>`_ - This chapter talks about adding user-defined local
- variables along with an assignment operator. This shows how easy it is
- to construct SSA form in LLVM: LLVM does *not* require your front-end
- to construct SSA form in order to use it!
-- `Chapter #8: Compiling to Object Files <LangImpl08.html>`_ - This
- chapter explains how to take LLVM IR and compile it down to object
- files, like a static compiler does.
-- `Chapter #9: Debug Information <LangImpl09.html>`_ - A real language
- needs to support debuggers, so we
- add debug information that allows setting breakpoints in Kaleidoscope
- functions, print out argument variables, and call functions!
-- `Chapter #10: Conclusion and other tidbits <LangImpl10.html>`_ - This
- chapter wraps up the series by discussing ways to extend the language
- and includes pointers to info on "special topics" like adding garbage
- collection support, exceptions, debugging, support for "spaghetti
- stacks", etc.
+- [Chapter #1: Kaleidoscope language and Lexer](LangImpl01.md) -
+ This shows where we are
+ going and the basic functionality that we want to build. A lexer
+ is also the first part of building a parser for a language, and we
+ use a simple C++ lexer which is easy to understand.
+- [Chapter #2: Implementing a Parser and AST](LangImpl02.md) -
+ With the lexer in place, we can talk about parsing techniques and
+ basic AST construction. This tutorial describes recursive descent
+ parsing and operator precedence parsing.
+- [Chapter #3: Code generation to LLVM IR](LangImpl03.md) - with
+ the AST ready, we show how easy it is to generate LLVM IR, and show
+ a simple way to incorporate LLVM into your project.
+- [Chapter #4: Adding JIT and Optimizer Support](LangImpl04.md) -
+ One great thing about LLVM is its support for JIT compilation, so
+ we'll dive right into it and show you the 3 lines it takes to add JIT
+ support. Later chapters show how to generate .o files.
+- [Chapter #5: Extending the Language: Control Flow](LangImpl05.md) - With
+ the basic language up and running, we show how to extend
+ it with control flow operations ('if' statement and a 'for' loop). This
+ gives us a chance to talk about SSA construction and control
+ flow.
+- [Chapter #6: Extending the Language: User-defined Operators](LangImpl06.md) - This chapter extends the language to let
+ users define arbitrary unary and binary operators - with assignable
+ precedence! This allows us to build a significant piece of the
+ "language" as library routines.
+- [Chapter #7: Extending the Language: Mutable Variables](LangImpl07.md) - This chapter talks about adding user-defined local
+ variables along with an assignment operator. This shows how easy it is
+ to construct SSA form in LLVM: LLVM does *not* require your front-end
+ to construct SSA form in order to use it!
+- [Chapter #8: Compiling to Object Files](LangImpl08.md) - This
+ chapter explains how to take LLVM IR and compile it down to object
+ files, like a static compiler does.
+- [Chapter #9: Debug Information](LangImpl09.md) - A real language
+ needs to support debuggers, so we
+ add debug information that allows setting breakpoints in Kaleidoscope
+ functions, print out argument variables, and call functions!
+- [Chapter #10: Conclusion and other tidbits](LangImpl10.md) - This
+ chapter wraps up the series by discussing ways to extend the language
+ and includes pointers to info on "special topics" like adding garbage
+ collection support, exceptions, debugging, support for "spaghetti
+ stacks", etc.
By the end of the tutorial, we'll have written a bit less than 1000 lines
of (non-comment, non-blank) lines of code. With this small amount of
code, we'll have built up a nice little compiler for a non-trivial
language including a hand-written lexer, parser, AST, as well as code
-generation support - both static and JIT! The breadth of this is a great
+generation support - both static and JIT! The breadth of this is a great
testament to the strengths of LLVM and shows why it is such a popular
target for language designers and others who need high performance code
generation.
+
More information about the llvm-commits
mailing list