Skip to content

Commit

Permalink
Merge pull request #19 from lambdaclass/progress
Browse files Browse the repository at this point in the history
Progress
  • Loading branch information
edg-l authored Dec 10, 2024
2 parents c35548c + 211d6a3 commit 2c0a0af
Show file tree
Hide file tree
Showing 9 changed files with 97 additions and 16 deletions.
2 changes: 2 additions & 0 deletions docs/src/workshop_p3.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ It is recommended to use the `arith` dialect in this case.

Some useful types you will need: `Type`, `IntegerAttribute`, `IntegerType`, `Location`.

> Types like `IntegerType` have a `into()` method to turn them into `Type`.
## Loading a variable value

To make things simpler, all variables are stored inside an `llvm.alloca`, which is an operation
Expand Down
8 changes: 8 additions & 0 deletions docs/src/workshop_p8.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,30 @@

Now to wrap up the function itself needs to be created, using the `func` dialect and adding it to the `module` `body()` block. (The module is available under the ctx variable.)

You also need to allocate space for the arguments, and store the value there. You can get the value from the block arguments.

Some useful types you will need: `Type`, `IntegerAttribute`, `IntegerType`, `FunctionType`, `TypeAttribute`, `StringAttribute`.

```rust
// src/codegen.rs:60+
fn compile_function(ctx: &ModuleCtx<'_>, func: &Function) {
let mut args: Vec<(Type, Location)> = vec![];
let mut func_args: Vec<Type> = Vec::new();

for _ in &func.args {
args.push((
IntegerType::new(ctx.ctx, 64).into(),
Location::unknown(ctx.ctx),
));
func_args.push(IntegerType::new(ctx.ctx, 64).into());
}

let region = Region::new();
let block = region.append_block(Block::new(&args));
let mut locals: HashMap<String, Value> = HashMap::new();

// Allocate space for the arguments, get them from the block, storing them and save them on locals hashmap.

for stmt in &func.body.stmts {
compile_statement(ctx, &mut locals, &block, stmt);
}
Expand Down
5 changes: 1 addition & 4 deletions src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,7 @@
pub enum Expr {
Number(i64),
Variable(String),
Call {
target: String,
args: Vec<Expr>,
},
Call { target: String, args: Vec<Expr> },
Op(Box<Expr>, Opcode, Box<Expr>),
}

Expand Down
50 changes: 47 additions & 3 deletions src/codegen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,19 @@ use std::{collections::HashMap, path::Path};
use ifelse_stmt::compile_if;
use let_stmt::compile_let;
use melior::{
dialect::DialectRegistry,
ir::{r#type::IntegerType, Block, Location, Module, Region, Type, Value},
dialect::{
func::{self, func},
DialectRegistry,
},
helpers::LlvmBlockExt,
ir::{
attribute::{StringAttribute, TypeAttribute},
r#type::{FunctionType, IntegerType},
Block, Location, Module, Region, Type, Value,
},
pass::{self, PassManager},
utility::register_all_dialects,
Context,
Context, ExecutionEngine,
};
use return_stmt::compile_return;

Expand Down Expand Up @@ -60,20 +68,56 @@ pub fn compile_program(program: &Program, optlevel: OptLevel, out_name: &Path) {
link_binary(&[out_obj], out_name).unwrap();
}

pub fn compile_program_jit(program: &Program) -> ExecutionEngine {
// We need a registry to hold all the dialects
let registry = DialectRegistry::new();
// Register all dialects that come with MLIR.
register_all_dialects(&registry);
let context = Context::new();
context.append_dialect_registry(&registry);
context.load_all_available_dialects();

let mut module = Module::new(Location::unknown(&context));
let ctx = ModuleCtx {
ctx: &context,
module: &module,
};

for func in &program.functions {
compile_function(&ctx, func);
}

// Run passes on module to convert all dialects to LLVM.
let pass_manager = PassManager::new(&context);
pass_manager.enable_verifier(true);
pass_manager.add_pass(pass::transform::create_canonicalizer());
pass_manager.add_pass(pass::conversion::create_scf_to_control_flow()); // needed because to_llvm doesn't include it.
pass_manager.add_pass(pass::conversion::create_to_llvm());
pass_manager.run(&mut module).unwrap();

println!("{}", module.as_operation().to_string());

ExecutionEngine::new(&module, 3, &[], false)
}

fn compile_function(ctx: &ModuleCtx<'_>, func: &Function) {
let mut args: Vec<(Type, Location)> = vec![];
let mut func_args: Vec<Type> = Vec::new();

for _ in &func.args {
args.push((
IntegerType::new(ctx.ctx, 64).into(),
Location::unknown(ctx.ctx),
));
func_args.push(IntegerType::new(ctx.ctx, 64).into());
}

let region = Region::new();
let block = region.append_block(Block::new(&args));
let mut locals: HashMap<String, Value> = HashMap::new();

// Allocate space for the arguments, get them from the block, storing them and save them on locals hashmap.

for stmt in &func.body.stmts {
compile_statement(ctx, &mut locals, &block, stmt);
}
Expand Down
5 changes: 2 additions & 3 deletions src/codegen/expressions.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
use std::collections::HashMap;

use melior::{
dialect::{arith, llvm},
ir::{
dialect::{arith, llvm}, helpers::{ArithBlockExt, LlvmBlockExt}, ir::{
attribute::IntegerAttribute, r#type::IntegerType, Block, BlockRef, Location, Type, Value,
},
}
};

use crate::ast::{Expr, Opcode};
Expand Down
6 changes: 3 additions & 3 deletions src/codegen/let_stmt.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use std::collections::HashMap;

use melior::ir::{Block, Value};
use melior::{helpers::LlvmBlockExt, ir::{r#type::IntegerType, Block, Location, Value}};

use crate::ast::LetStmt;
use crate::{ast::LetStmt, codegen::expressions::compile_expr};

use super::ModuleCtx;

Expand All @@ -12,5 +12,5 @@ pub fn compile_let<'ctx: 'parent, 'parent>(
block: &'parent Block<'ctx>,
stmt: &LetStmt,
) {
todo!()
todo!("implement let")
}
6 changes: 3 additions & 3 deletions src/codegen/return_stmt.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
use std::collections::HashMap;

use melior::ir::{Block, BlockRef, Value};
use melior::{dialect::func, ir::{Block, BlockRef, Location, Value}};

use crate::ast::ReturnStmt;

use super::ModuleCtx;
use super::{expressions::compile_expr, ModuleCtx};

pub fn compile_return<'ctx, 'parent>(
ctx: &ModuleCtx<'ctx>,
locals: &HashMap<String, Value>,
block: &'parent Block<'ctx>,
stmt: &ReturnStmt,
) {
todo!()
todo!("implement return")
}
27 changes: 27 additions & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,30 @@ fn main() {

compile_program(&program, args.opt_level.into(), &args.output);
}

#[cfg(test)]
mod tests {

use melior::ExecutionEngine;

use crate::{codegen::compile_program_jit, grammar};

fn call_program(engine: &ExecutionEngine, a: i64, b: i64) -> i64 {
unsafe {
let add: extern "C" fn(i64, i64) -> i64 = std::mem::transmute(engine.lookup("test"));
add(a, b)
}
}

#[test]
fn add() {
let program = grammar::ProgramParser::new()
.parse(include_str!("../test/add.prog"))
.unwrap();

let engine = compile_program_jit(&program);

let res = call_program(&engine, 2, 3);
assert_eq!(res, 5);
}
}
4 changes: 4 additions & 0 deletions test/add.prog
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
fn test(a, b) {
let x = a + b;
return x;
}

0 comments on commit 2c0a0af

Please sign in to comment.