Use LLVM by JavaScript/TypeScript
ApsarasX
Posted on December 18, 2021
Background
As a developer, have you ever wanted to implement your own compiler in the past?
Fortunately, in 2021, implementing a compiler is no longer a difficult task because of LLVM Website.
LLVM is a set of compiler infrastructure projects, a compiler framework. Both Rust and Swift use LLVM as their compiler backend.
Everyone can implement their own compiler based on LLVM.
But... LLVM is written in C++, which means that if you want to use LLVM, you must also use C++. Not everyone likes C++.
So I developed a library called llvm-bindings to allow you to use LLVM by JavaScript. Of course, there is no problem using LLVM through TypeScript.
Install
First, you need to install CMake and LLVM before llvm-bindings.
Install CMake and LLVM on macOS
brew install cmake llvm
Install CMake and LLVM on Ubuntu
sudo apt-get install cmake
sudo bash -c "$(wget -O - https://apt.llvm.org/llvm.sh)"
After making sure that CMake and LLVM are installed correctly on your system, you can install llvm-bindings
through npm.
npm install llvm-bindings
Usage
We will write all our code in a file called
demo.js
First, import llvm-bindings
const llvm = require('llvm-bindings');
Then, new a Context
, a Module
and a IR Builder
const context = new llvm.LLVMContext();
const mod = new llvm.Module('demo', context);
const builder = new llvm.IRBuilder(context);
We call this module
mod
because Node.js does not allow variables calledmodule
to be declared in the top level.
Then, build objects related to function signatures
const returnType = builder.getInt32Ty();
const paramTypes = [builder.getInt32Ty(), builder.getInt32Ty()];
const functionType = llvm.FunctionType.get(returnType, paramTypes, false);
const func = llvm.Function.Create(functionType, llvm.Function.LinkageTypes.ExternalLinkage, 'add', mod);
Then, build the basic blocks and instructions within the function
const entryBB = llvm.BasicBlock.Create(context, 'entry', func);
builder.SetInsertPoint(entryBB);
const a = func.getArg(0);
const b = func.getArg(1);
const result = builder.CreateAdd(a, b);
builder.CreateRet(result);
Finally, verify the function and the module, and print the LLVM IR of the entire module in text form
if (llvm.verifyFunction(func)) {
console.error('Verifying function failed');
return;
}
if (llvm.verifyModule(mod)) {
console.error('Verifying module failed');
return;
}
mod.print();
Now you have implemented a basic example of using LLVM through JavaScript, by executing node demo.js
, you can see:
Conclusion
llvm-bindings
provides developers with the ability to use LLVM through JavaScript/TypeScript. Friends who need to use llvm can try llvm-bindings.
llvm-bindings
is currently under development on demand. Maybe the LLVM API you need has not been added yet. You can submit an issue to request a new API. I will add it within one day of receiving the issue.
Full Code Listing
const llvm = require('llvm-bindings');
const context = new llvm.LLVMContext();
const mod = new llvm.Module('demo', context);
const builder = new llvm.IRBuilder(context);
const returnType = builder.getInt32Ty();
const paramTypes = [builder.getInt32Ty(), builder.getInt32Ty()];
const functionType = llvm.FunctionType.get(returnType, paramTypes, false);
const func = llvm.Function.Create(functionType, llvm.Function.LinkageTypes.ExternalLinkage, 'add', mod);
const entryBB = llvm.BasicBlock.Create(context, 'entry', func);
builder.SetInsertPoint(entryBB);
const a = func.getArg(0);
const b = func.getArg(1);
const result = builder.CreateAdd(a, b);
builder.CreateRet(result);
if (llvm.verifyFunction(func)) {
console.error('verifying the function failed');
return;
}
if (llvm.verifyModule(mod)) {
console.error('verifying the module failed');
return;
}
mod.print();
main();
Note
Currently llvm-bindings
only supports macOS and Ubuntu systems, and Windows is not yet supported.
References
Posted on December 18, 2021
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.