Skip to content
forked from rust-lang/rust

Empowering everyone to build reliable and efficient software.

License

Apache-2.0, MIT licenses found

Licenses found

Apache-2.0
LICENSE-APACHE
MIT
LICENSE-MIT
Notifications You must be signed in to change notification settings

djtech-dev/rust

Folders and files

NameName
Last commit message
Last commit date
Apr 17, 2018
Oct 31, 2017
Apr 21, 2018
Apr 21, 2018
Apr 21, 2018
Jun 27, 2017
Apr 17, 2018
Aug 28, 2017
Apr 21, 2018
Jun 27, 2017
Apr 21, 2018

Repository files navigation

Inkwell(s)

Crates.io Build Status codecov lines of code Join the chat at https://gitter.im/inkwell-rs/Lobby

It's a New Kind of Wrapper for Exposing LLVM (Safely)

Inkwell aims to help you pen your own programming languages by safely wrapping llvm-sys. It provides a more strongly typed interface than the underlying LLVM API so that certain types of errors can be caught at compile time instead of at LLVM's runtime. This means we are trying to replicate LLVM IR's strong typing as closely as possible. The ultimate goal is to make LLVM safer from the rust end and a bit easier to learn (via documentation) and use.

Requirements

  • Any Rust version released in the last year or so
  • Rust Stable, Beta, or Nightly
  • LLVM 3.6, 3.7, or 3.8 (3.9+ support is planned: #1)

Usage

You'll need to point your Cargo.toml to a branch and use a feature flag corresponding to a supported LLVM version:

[dependencies]
inkwell = { git = "https://github.com/TheDan64/inkwell", branch = "llvm3-7", features = ["llvm3-7"] }

Supported versions:

GitHub Branch Feature Flag
llvm3-6 llvm3-6
llvm3-7 llvm3-7
llvm3-8 llvm3-8

In the root of your source code you will have to add an extern crate to begin using Inkwell:

extern crate inkwell;

Documentation

Documenation is automatically deployed here based on master. These docs are not yet 100% complete and only show the latest supported LLVM version due to a rustdoc issue. See #2 for more info.

Examples

Tari's llvm-sys example written in safe code1 with Inkwell:

extern crate inkwell;

use inkwell::OptimizationLevel;
use inkwell::builder::Builder;
use inkwell::context::Context;
use inkwell::execution_engine::{ExecutionEngine, Symbol};
use inkwell::module::Module;
use inkwell::targets::{InitializationConfig, Target};
use std::error::Error;

/// Convenience type alias for the `sum` function.
///
/// Calling `sum` is innately `unsafe` because there's no guarantee it doesn't
/// do `unsafe` operations internally.
type SumFunc = unsafe extern "C" fn(u64, u64, u64) -> u64;

fn main() {
    Target::initialize_native(&InitializationConfig::default()).unwrap();
    run().unwrap();
}

fn run() -> Result<(), Box<Error>> {
    let context = Context::create();
    let module = context.create_module("sum");
    let builder = context.create_builder();
    let execution_engine = module.create_jit_execution_engine(OptimizationLevel::None)?;

    let sum = jit_compile_sum(&context, &module, &builder, &execution_engine)
        .ok_or("Unable to JIT compile `sum`")?;

    let x = 1u64;
    let y = 2u64;
    let z = 3u64;

    unsafe {
        println!("{} + {} + {} = {}", x, y, z, sum(x, y, z));
        assert_eq!(sum(x, y, z), x + y + z);
    }

    Ok(())
}

fn jit_compile_sum(
    context: &Context,
    module: &Module,
    builder: &Builder,
    execution_engine: &ExecutionEngine,
) -> Option<Symbol<SumFunc>> {
    let i64_type = context.i64_type();
    let fn_type = i64_type.fn_type(&[&i64_type, &i64_type, &i64_type], false);

    let function = module.add_function("sum", &fn_type, None);
    let basic_block = context.append_basic_block(&function, "entry");

    builder.position_at_end(&basic_block);

    let x = function.get_nth_param(0)?.into_int_value();
    let y = function.get_nth_param(1)?.into_int_value();
    let z = function.get_nth_param(2)?.into_int_value();

    let sum = builder.build_int_add(&x, &y, "sum");
    let sum = builder.build_int_add(&sum, &z, "sum");

    builder.build_return(Some(&sum));

    unsafe { execution_engine.get_function("sum").ok() }
}

1 There are two uses of unsafe in this example because the actual act of compiling and executing code on the fly is innately unsafe. For one, there is no way of verifying we are calling get_function() with the right function signature. It is also unsafe to call the function we get because there's no guarantee the code itself doesn't do unsafe things internally (the same reason you need unsafe when calling into C).

Can be found in the examples directory.

Contributing

Check out our Contributing Guide

About

Empowering everyone to build reliable and efficient software.

Resources

License

Apache-2.0, MIT licenses found

Licenses found

Apache-2.0
LICENSE-APACHE
MIT
LICENSE-MIT

Code of conduct

Stars

Watchers

Forks

Packages

No packages published

Languages

  • Rust 97.9%
  • Python 0.4%
  • JavaScript 0.3%
  • Shell 0.3%
  • Makefile 0.3%
  • C++ 0.3%
  • Other 0.5%