Extend Codon
Codon supports plugins that can be loaded dynamically. Plugins can contain IR passes that can be inserted into the Codon IR pass pipeline, as well as LLVM passes to be used during backend code generation.
Configuration¶
Plugin information is specified through a TOML file
called plugin.toml
. The following fields are supported:
about.name
: Plugin nameabout.description
: Plugin descriptionabout.version
: Plugin version, using semantic versioningabout.url
: Plugin URLabout.supported
: Supported Codon versions, using semantic versioning rangeslibrary.cpp
: Shared library to be loaded upon loading the plugin, which includes the plugin implementation (see below) and any necessary runtime functions. The library extension (i.e..so
or.dylib
) will be added automatically, and should not be included.library.codon
: Standard library code that should be included with the plugin. It is recommended to put this code in directorystdlib/<plugin_name>
, whereupon the value of this parameter would be"stdlib"
.library.link
: Libraries to be linked when compiling to an executable. The string{root}
will be replaced with the path to the TOML configuration file. For example, a value similar to{root}/build/libmyplugin.a
might be used, assuming the plugin also builds a static library containing necessary runtime functions.
Here is an example configuration file for the validate pass shown in the Codon IR docs:
[about]
name = "MyValidate"
description = "my validation plugin"
version = "0.0.1"
url = "https://example.com"
supported = ">=0.18.0"
[library]
cpp = "build/libmyvalidate"
Implementation¶
Plugins must extend the codon::DSL
class to implement their functionality, and provide
a function extern "C" std::unique_ptr<codon::DSL> load()
that returns an instance of
their subclass. The load()
function is invoked by Codon automatically when it loads a
plugin from a shared library.
Continuing on the same validate example from above, let's implement the pass as a
plugin. We can use the same pass code in the section linked above, and create a subclass
of the codon::DSL
class while adding a function load()
to our library that
returns an instance of it:
class MyValidate : public codon::DSL {
public:
void addIRPasses(transform::PassManager *pm, bool debug) override {
std::string insertBefore = debug ? "" : "core-folding-pass-group";
pm->registerPass(std::make_unique<ValidateFoo>(), insertBefore);
}
};
extern "C" std::unique_ptr<codon::DSL> load() {
return std::make_unique<MyValidate>();
}
The codon::DSL
class has methods for adding Codon IR passes, LLVM IR passes and even new
syntax features like keywords (hence the name DSL, since this class effectively
enables the creation of domain-specific languages within Codon). In this case,
we insert our pass into the Codon IR pass manager before the standard folding pass.
A CMakeLists.txt
is also required, which specifies how to build the plugin to a shared
library with CMake. A complete implementation of this example plugin, along with the CMakeLists.txt
,
can be found on GitHub.
Adding LLVM passes¶
Plugins can add new LLVM passes by overriding the void addLLVMPasses(llvm::PassBuilder *pb, bool debug)
method of the codon::DSL
class. Refer to the
llvm::PassBuilder
docs for details on adding
passes.