Skip to content

couchand/petard

Repository files navigation

petard

a js llvm library

    For 'tis the sport to have the enginer
    Hoist with his own petar'...

                - Hamlet, Shakespeare

Build Status

introduction

Frustrated with the state of JS support for LLVM, I built another library. Rather than trying to be generic bindings to libLLVM, petard tries to make the most common case easy: generating fresh IR. You don't have total control over the LLVM machinery and there aren't really facilities for working with IR that already exists (so you can't write passes), but if those limitations aren't a problem petard makes dealing with LLVM much simpler.

This software is under active development. The README should reflect current functionality, but don't be surprised if something you think should work causes your computer to segfault. petard aims to catch these things and throw JavaScript errors, but we don't have very good coverage yet. Please do submit a ticket or pull request if there's a type of programmer error that could be caught earlier and an error thrown.

one more warning: it is currently VERY leaky. don't use in any program that will be running very long.

dependencies

  • a recent version of node
  • nan version 2.1
  • llvm version 3.9

getting started

First you need to install LLVM version 3.9 on your system, including the dev libs. Look to the Travis build config for details.

when you're building petard you will need to set the environment variable LLVM_CONFIG to be the llvm-config you've installed. For example, if you're on Ubuntu where it's isntalled as llvm-config-3.9, you'll enter:

> LLVM_CONFIG=llvm-config-3.9 npm run build

or

> LLVM_CONFIG=llvm-config-3.9 npm install petard

Once you've got it built successfully, try this:

llvm = require 'petard'

{i8, i32, pointerTo} = llvm.type

hello = llvm.CodeUnit "hello"

main = hello.makeFunction "main", i32
puts = hello.declareFunction "puts", i32, pointerTo i8

text = hello.constant "Hello, world!\n"

message = main.loadConstant text
main.callFunction puts, message

main.return 0

hello.writeBitcodeToFile "hello.bc"

Then use opt and clang as usual with the LLVM IR bitcode file. Look at the example folder for more examples.

Alternatively, you can JIT compile and call the function from JavaScript.

hi = hello.makeFunction "hi", i32, pointerTo i8

prefix = hello.constant "Hello, "

hi.callFunction puts, hi.loadConstant prefix
hi.callFunction puts, hi.parameter 0

hi.return 0

greet = hi.jitCompile()

greet "Bill"
greet "Janice"
greet "Bart"

documentation

The underlying C++ API exposes the basics of LLVM IR construction, and the node wrapper adds some higher-level functionality on top of that. In the listing the methods in JavaScript are marked with a (js).

petard types

Type

Represents an LLVM type. You'll see these most commonly when you get them from petard.type and pass them when constructing functions and values. The only thing you can do to a type is get its name as a string.

String type.toString()

Returns the type as a string.

Value

Represents an LLVM value, or if you look at it another way, represents an abstract expression. You'll get these and pass them in to many of the builder methods. The only thing you can do to a value is get its type.

Type value.type

A property containing the type of the value.

Builder

Something that can construct LLVM IR. It represents a particular part of a function (an LLVM block) as well as a cursor within that block where instructions will be placed. Calls to builder methods construct LLVM IR and take and return values and other builders.

return([Number|Value value])

Return from the function. If a value is provided, it is the return value of the function. You must ensure that the value passed is of the same type as the return type of the function.

Value parameter(Number index)

Reference function parameter index.

Value getElementPointer(Value base, Number|Value indexList...)

Perform pointer math on the aggregate type pointer to produce a new pointer to the given structure member. For details, see the GetElementPointer FAQ.

Value extractElement(Value vec, Number|Value index)

Extract the element at the specified index from the vector.

Value insertElement(Value vec, Value value, Number|Value index)

Insert the value as the element at the specified index from the vector.

Value loadConstant(Value constant)

Load a constant value. Currently the only usage is to load a string constant, see the first example.

Value callFunction(FunctionBuilder|FunctionValue fn, [Value params...])

Call the given internal or external function, passing in the parameter values.

Value alloca(Type type, [Number|Value arraySize])

Allocate space the size of type on the stack. If an arraySize is provided, instead allocate that much space times the arraySize. Returns a pointer value to the space.

Value load(Value pointer)

Load a value from the memory pointed to by pointer.

store(Value value, Value pointer)

Store the value in the memory pointed to by pointer.

Value add(Value left, Value right)

Add the values. Works on integer and float values.

Value sub(Value left, Value right)

Subtract the right value from the left. For integers and floats.

Value mul(Value left, Value right)

Multiply the values. They can be integers or floats.

Value udiv(Value left, Value right)

Unsigned integer divide the left value by the right.

Value sdiv(Value left, Value right)

Signed integer divide the left value by the right.

Value fdiv(Value left, Value right)

Floating point divide the left value by the right.

Value urem(Value left, Value right)

The remainder when the left value is unsigned integer divided by the right.

Value srem(Value left, Value right)

The remainder when the left value is signed integer divided by the right.

Value frem(Value left, Value right)

The remainder when the left value is floating point divided by the right.

Value and(Value left, Value right)

Bitwise and the values.

Value or(Value left, Value right)

Bitwise or the values.

Value xor(Value left, Value right)

Bitwise xor the values.

Value shl(Value left, Value right)

Shift the left value left by the right value number of bits.

Value lshr(Value left, Value right)

Shift the left value right logically (sign-ignoring) by the right value number of bits.

Value ashr(Value left, Value right)

Shift the left value right arithmetically (sign-preserving) by the right value number of bits.

Value equal(Value left, Value right)

Compare the values for equality.

Value notEqual(Value left, Value right)

Compare the values for inequality.

Value uGreaterThan(Value left, Value right)

Unsigned greater than comparison.

Value uAtLeast(Value left, Value right)

Unsigned greater than or equal to comparison.

Value uLessThan(Value left, Value right)

Unsigned less than comparison.

Value uAtMost(Value left, Value right)

Unsigned less than or equal to comparison.

Value sGreaterThan(Value left, Value right)

Signed greater than comparison.

Value sAtLeast(Value left, Value right)

Signed greater than or equal to comparison.

Value sLessThan(Value left, Value right)

Signed less than comparison.

Value sAtMost(Value left, Value right)

Signed less than or equal to comparison.

Value foEqual(Value left, Value right)

Float value ordered equality comparison.

Value foNotEqual(Value left, Value right)

Float value ordered inequality comparison.

Value foGreaterThan(Value left, Value right)

Float value ordered greater than comparison.

Value foAtLeast(Value left, Value right)

Float value ordered greater than or equal to comparison.

Value foLessThan(Value left, Value right)

Float value ordered less than comparison.

Value foAtMost(Value left, Value right)

Float value ordered less than or equal to comparison.

Value fuEqual(Value left, Value right)

Float value unordered equality comparison.

Value fuNotEqual(Value left, Value right)

Float value unordered inequality comparison.

Value fuGreaterThan(Value left, Value right)

Float value unordered greater than comparison.

Value fuAtLeast(Value left, Value right)

Float value unordered greater than or equal to comparison.

Value fuLessThan(Value left, Value right)

Float value unordered less than comparison.

Value fuAtMost(Value left, Value right)

Float value unordered less than or equal to comparison.

Value trunc(Value value, Type type)

Truncate the integer value to a smaller type.

Value zext(Value value, Type type)

Zero extend the integer value to a larger type.

Value sext(Value value, Type type)

Sign extend the integer value to a larger type.

Value fpToUI(Value value, Type type)

Convert the floating point value to an unsigned integer.

Value fpToSI(Value value, Type type)

Convert the floating point value to a signed integer.

Value uiToFP(Value value, Type type)

Convert the unsigned integer value to a floating point.

Value siToFP(Value value, Type type)

Convert the signed integer value to a floating point.

Value fpTrunc(Value value, Type type)

Truncate the floating point value to a smaller type.

Value fpext(Value value, Type type)

Extend the floating point value to a larger type.

Value ptrToInt(Value value, Type type)

Convert the pointer to an integer type.

Value intToPtr(Value value, Type type)

Convert the integer to a pointer type.

Value bitcast(Value value, Type type)

Cast the value to another type without changing the bits.

Value select(Value condition, Value ifTrue, Value ifFalse)

Non-branching value select. Returns the value corresponding to the ifTrue value if the condition is true, and the ifFalse value if the condition is not true. Also operates on vectors.

Value value(Type type, Any value)

Construct a new LLVM value of the given type for the given JavaScript value.

{Builder then, Builder else} if(Value condition) (js)

Builds the if conditional control structure for the given condition. Returns an object with then and else properties, each builders for the then and else blocks.

Builder while(BuilderCallback buildCondition) (js)

with Value BuilderCallback(Builder condition)

Builds the while loop control structure. The callback should take a builder for the loop condition and should return the condition value. Returns a builder for the body of the loop.

br(Builder target)

Unconditional branch to the target.

br(Value condition, Builder ifTrue, Builder ifFalse)

Conditional branch. If the condition is true, branch to the ifTrue builder, otherwise branch to the ifFalse builder.

SwitchBuilder switch(Value condition, Builder defaultDest)

Multi-way branch. If none of the cases added to the returned switch builder match the value of the condition, control follows the defaultDest.

ChooseBuilder choose(Value condition) (js)

Builds the switch control structure. While the switch method simply produces a multi-way branch, this provides the high-level control you're expecting out of the box, namely merging back to one place at the end.

Builder createBlock(String name)

Create another block in the same function. Use with the branching instructions to create custom control structures. See the node wrapper for examples on using createBlock, splitBlock, useBlock, insertBefore, insertAfter, and br to build control structures.

Builder splitBlock(String name)

Split the current block at the cursor. The object itself retains the top half (all the instructions written before) and the returned builder takes the bottom half (all the instructions written after). In practice this usually means the terminator of the block is the only instruction in the new block.

useBlock(Builder target)

Set this builder to start building in the target block. Make sure this builder already has a terminator or you'll get into trouble.

insertAfter()

Start inserting instructions after the cursor rather than before. Mainly useful to appending a terminator to a block ahead of time.

insertBefore()

Resume inserting instructions before the cursor, the default behavior. Used to restore the standard mode after inserting a terminator.

FunctionBuilder

A specialization of a builder corresponding to a complete function. In addition to the normal builder methods, it has a few special properties.

String fnBuilder.name

A property containing the name of the function.

Type fnBuilder.type

A property containing the type of the function.

Function jitCompile() (js)

JIT compile the function, the set up a foreign-function interface to make the function callable from JavaScript. Uses the ffi library to dynamically bind the functino pointer.

SwitchBuilder

A special tool for working with switch statements. It is returned from the switch method of a builder.

addCase(Number onVal, Builder target)

Adds a case for the value onVal, branching to target.

ChooseBuilder (js)

The same thing as the switch builder, but for choose statements.

Builder defaultCase

The default case builder.

Builder addCase(Number onVal)

Adds a case for the value onVal, returning a builder for the case.

CodeUnit

Represents an overall unit of code, such as a file. Directly corresponds to an LLVM Module. It has a few helpful methods.

Value unit.constant(Value value)

Compile a constant value into the IR. At the moment the only use is to load a constant string. See the first example for usage.

Value unit.declareFunction(String name, [Type returns], [Type takes...])

Declare a function external to this code unit that will be linked in. Takes the name of the function and optionally the return type and parameter types. Returns a special FunctionValue.

FunctionBuilder unit.makeFunction(String name, [Type returns], [Type takes...])

Create a new function in this code unit with the given name and optionall the return type and parameter types.

unit.dump()

Dump the code unit IR to the screen. Useful for debugging, not so much for regular usage, since the underlying LLVM method always dumps to stderr.

unit.writeBitcodeToFile(String filename)

Write the bitcode for this code unit to a file with the given filename. The file must not exist, if it does this method will fail.

Buffer unit.jitFunction(FunctionBuilder fn)

JIT compile the function. Returns the raw pointer to the function as a Buffer. You may find the corresponding helper method on FunctionBuilder to be more useful since you can call the result of that method from JavaScript.

helpers

type dict

This dict contains all the basic types for easy reference.

  • i1 - A one bit integer (a boolean).
  • i8 - A single byte.
  • i16 - A small word.
  • i32 - A medium word.
  • i64 - A long word.
  • f16 - A half-precision floating point value. (LLVM's half)
  • f32 - A single-precision floating point value. (LLVM's float)
  • f64 - A double-precision floating point value. (LLVM's double)
  • Type arrayOf(Number size, Type element) - Takes a size and type and returns an array of that size and type.
  • Type vectorOf(Number size, Type element) - Takes a size and type and returns a vector of that size and type.
  • Type structOf([Type] elements) - Takes an array of types and returns a struct composed of those types.
  • Type pointerTo(Type pointee) - Takes a type and returns a pointer to that type.

more information

╭╮☲☲☲╭╮