DEV Community

Cover image for Use LLVM by JavaScript/TypeScript
ApsarasX
ApsarasX

Posted on

Use LLVM by JavaScript/TypeScript

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
Enter fullscreen mode Exit fullscreen mode

Install CMake and LLVM on Ubuntu

sudo apt-get install cmake
sudo bash -c "$(wget -O - https://apt.llvm.org/llvm.sh)"
Enter fullscreen mode Exit fullscreen mode

After making sure that CMake and LLVM are installed correctly on your system, you can install llvm-bindings through npm.

npm install llvm-bindings
Enter fullscreen mode Exit fullscreen mode

Usage

We will write all our code in a file called demo.js

First, import llvm-bindings

const llvm = require('llvm-bindings');
Enter fullscreen mode Exit fullscreen mode

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);
Enter fullscreen mode Exit fullscreen mode

We call this module mod because Node.js does not allow variables called module 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);
Enter fullscreen mode Exit fullscreen mode

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);
Enter fullscreen mode Exit fullscreen mode

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();
Enter fullscreen mode Exit fullscreen mode

Now you have implemented a basic example of using LLVM through JavaScript, by executing node demo.js, you can see:

Print Result

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();
Enter fullscreen mode Exit fullscreen mode

Note

Currently llvm-bindings only supports macOS and Ubuntu systems, and Windows is not yet supported.

References

Top comments (1)

Collapse
 
timibolu profile image
Oluwatimilehin Adesina

this is an amazing approach for js devs. is this project still in development?