Skip to content

Commit

Permalink
Update Kaleidoscope example to LLVM 15 and 16
Browse files Browse the repository at this point in the history
  • Loading branch information
FnControlOption authored and TheDan64 committed Jan 10, 2024
1 parent 0b2cde9 commit c18e3e8
Show file tree
Hide file tree
Showing 2 changed files with 80 additions and 46 deletions.
26 changes: 16 additions & 10 deletions examples/kaleidoscope/implementation_typed_pointers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,12 @@ use std::str::Chars;
use inkwell::builder::Builder;
use inkwell::context::Context;
use inkwell::module::Module;
use inkwell::passes::PassManager;
use inkwell::types::BasicMetadataTypeEnum;
use inkwell::values::{BasicMetadataValueEnum, FloatValue, FunctionValue, PointerValue};
use inkwell::values::{BasicMetadataValueEnum, BasicValueEnum, FloatValue, FunctionValue, PointerValue};
use inkwell::FloatPredicate;

use inkwell_internals::llvm_versions;

use crate::Token::*;

const ANONYMOUS_FUNCTION_NAME: &str = "anonymous";
Expand Down Expand Up @@ -823,7 +824,6 @@ impl<'a> Parser<'a> {
pub struct Compiler<'a, 'ctx> {
pub context: &'ctx Context,
pub builder: &'a Builder<'ctx>,
pub fpm: &'a PassManager<FunctionValue<'ctx>>,
pub module: &'a Module<'ctx>,
pub function: &'a Function,

Expand Down Expand Up @@ -858,13 +858,23 @@ impl<'a, 'ctx> Compiler<'a, 'ctx> {
builder.build_alloca(self.context.f64_type(), name).unwrap()
}

#[llvm_versions(4.0..=14.0)]
pub fn build_load(&self, ptr: PointerValue<'ctx>, name: &str) -> BasicValueEnum<'ctx> {
self.builder.build_load(ptr, name).unwrap()
}

#[llvm_versions(15.0..=latest)]
pub fn build_load(&self, ptr: PointerValue<'ctx>, name: &str) -> BasicValueEnum<'ctx> {
self.builder.build_load(self.context.f64_type(), ptr, name).unwrap()
}

/// Compiles the specified `Expr` into an LLVM `FloatValue`.
fn compile_expr(&mut self, expr: &Expr) -> Result<FloatValue<'ctx>, &'static str> {
match *expr {
Expr::Number(nb) => Ok(self.context.f64_type().const_float(nb)),

Expr::Variable(ref name) => match self.variables.get(name.as_str()) {
Some(var) => Ok(self.builder.build_load(*var, name.as_str()).unwrap().into_float_value()),
Some(var) => Ok(self.build_load(*var, name.as_str()).into_float_value()),
None => Err("Could not find a matching variable."),
},

Expand Down Expand Up @@ -1086,7 +1096,7 @@ impl<'a, 'ctx> Compiler<'a, 'ctx> {
// compile end condition
let end_cond = self.compile_expr(end)?;

let curr_var = self.builder.build_load(start_alloca, var_name).unwrap();
let curr_var = self.build_load(start_alloca, var_name);
let next_var = self
.builder
.build_float_add(curr_var.into_float_value(), step, "nextvar")
Expand Down Expand Up @@ -1178,8 +1188,6 @@ impl<'a, 'ctx> Compiler<'a, 'ctx> {

// return the whole thing after verification and optimization
if function.verify(true) {
self.fpm.run_on(&function);

Ok(function)
} else {
unsafe {
Expand All @@ -1190,18 +1198,16 @@ impl<'a, 'ctx> Compiler<'a, 'ctx> {
}
}

/// Compiles the specified `Function` in the given `Context` and using the specified `Builder`, `PassManager`, and `Module`.
/// Compiles the specified `Function` in the given `Context` and using the specified `Builder` and `Module`.
pub fn compile(
context: &'ctx Context,
builder: &'a Builder<'ctx>,
pass_manager: &'a PassManager<FunctionValue<'ctx>>,
module: &'a Module<'ctx>,
function: &Function,
) -> Result<FunctionValue<'ctx>, &'static str> {
let mut compiler = Compiler {
context,
builder,
fpm: pass_manager,
module,
function,
fn_value_opt: None,
Expand Down
100 changes: 64 additions & 36 deletions examples/kaleidoscope/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,20 @@ use std::collections::HashMap;
use std::io::{self, Write};

use inkwell::context::Context;
use inkwell::module::Module;
#[llvm_versions(4.0..=15.0)]
use inkwell::passes::PassManager;
use inkwell::OptimizationLevel;
#[llvm_versions(16.0..=latest)]
use inkwell::{
passes::PassBuilderOptions,
targets::{CodeModel, InitializationConfig, RelocMode, Target, TargetMachine},
};

use inkwell_internals::llvm_versions;

#[cfg(not(any(feature = "llvm15-0", feature = "llvm16-0")))]
mod implementation_typed_pointers;

#[llvm_versions(4.0..=14.0)]
use crate::implementation_typed_pointers::*;

// ======================================================================================
Expand Down Expand Up @@ -57,8 +62,51 @@ pub extern "C" fn printd(x: f64) -> f64 {
#[used]
static EXTERNAL_FNS: [extern "C" fn(f64) -> f64; 2] = [putchard, printd];

#[llvm_versions(4.0..=15.0)]
fn run_passes_on(module: &Module) {
let fpm = PassManager::create(());

fpm.add_instruction_combining_pass();
fpm.add_reassociate_pass();
fpm.add_gvn_pass();
fpm.add_cfg_simplification_pass();
fpm.add_basic_alias_analysis_pass();
fpm.add_promote_memory_to_register_pass();

fpm.run_on(module);
}

#[llvm_versions(16.0..=latest)]
fn run_passes_on(module: &Module) {
Target::initialize_all(&InitializationConfig::default());
let target_triple = TargetMachine::get_default_triple();
let target = Target::from_triple(&target_triple).unwrap();
let target_machine = target
.create_target_machine(
&target_triple,
"generic",
"",
OptimizationLevel::None,
RelocMode::PIC,
CodeModel::Default,
)
.unwrap();

let passes: &[&str] = &[
"instcombine",
"reassociate",
"gvn",
"simplifycfg",
// "basic-aa",
"mem2reg",
];

module
.run_passes(passes.join(",").as_str(), &target_machine, PassBuilderOptions::create())
.unwrap();
}

/// Entry point of the program; acts as a REPL.
#[llvm_versions(4.0..=14.0)]
pub fn main() {
// use self::inkwell::support::add_symbol;
let mut display_lexer_output = false;
Expand All @@ -75,23 +123,8 @@ pub fn main() {
}

let context = Context::create();
let module = context.create_module("repl");
let builder = context.create_builder();

// Create FPM
let fpm = PassManager::create(&module);

fpm.add_instruction_combining_pass();
fpm.add_reassociate_pass();
fpm.add_gvn_pass();
fpm.add_cfg_simplification_pass();
fpm.add_basic_alias_analysis_pass();
fpm.add_promote_memory_to_register_pass();
fpm.add_instruction_combining_pass();
fpm.add_reassociate_pass();

fpm.initialize();

let mut previous_exprs = Vec::new();

loop {
Expand Down Expand Up @@ -133,11 +166,10 @@ pub fn main() {

// recompile every previously parsed function into the new module
for prev in &previous_exprs {
Compiler::compile(&context, &builder, &fpm, &module, prev)
.expect("Cannot re-add previously compiled function.");
Compiler::compile(&context, &builder, &module, prev).expect("Cannot re-add previously compiled function.");
}

let (name, is_anonymous) = match Parser::new(input, &mut prec).parse() {
let (function, is_anonymous) = match Parser::new(input, &mut prec).parse() {
Ok(fun) => {
let is_anon = fun.is_anon;

Expand All @@ -149,21 +181,14 @@ pub fn main() {
}
}

match Compiler::compile(&context, &builder, &fpm, &module, &fun) {
match Compiler::compile(&context, &builder, &module, &fun) {
Ok(function) => {
if display_compiler_output {
// Not printing a new line since LLVM automatically
// prefixes the generated string with one
print_flush!("-> Expression compiled to IR:");
function.print_to_stderr();
}

if !is_anon {
// only add it now to ensure it is correct
previous_exprs.push(fun);
}

(function.get_name().to_str().unwrap().to_string(), is_anon)
(function, is_anon)
},
Err(err) => {
println!("!> Error compiling function: {}", err);
Expand All @@ -177,10 +202,18 @@ pub fn main() {
},
};

run_passes_on(&module);

if display_compiler_output {
println!("-> Expression compiled to IR:");
function.print_to_stderr();
}

if is_anonymous {
let ee = module.create_jit_execution_engine(OptimizationLevel::None).unwrap();

let maybe_fn = unsafe { ee.get_function::<unsafe extern "C" fn() -> f64>(name.as_str()) };
let fn_name = function.get_name().to_str().unwrap();
let maybe_fn = unsafe { ee.get_function::<unsafe extern "C" fn() -> f64>(fn_name) };
let compiled_fn = match maybe_fn {
Ok(f) => f,
Err(err) => {
Expand All @@ -195,8 +228,3 @@ pub fn main() {
}
}
}

#[llvm_versions(15.0..=latest)]
pub fn main() {
eprintln!("Kaleidoscope example does not work yet with this llvm version");
}

0 comments on commit c18e3e8

Please sign in to comment.