Skip to content
GitLab
Explore
Sign in
Register
Primary navigation
Search or go to…
Project
D
D7050E
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Model registry
Operate
Environments
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
Maxence Cornaton
D7050E
Commits
dfbdcd33
Commit
dfbdcd33
authored
5 years ago
by
Per
Browse files
Options
Downloads
Patches
Plain Diff
crust using inkwell
parent
b5de280c
No related branches found
No related tags found
No related merge requests found
Changes
1
Show whitespace changes
Inline
Side-by-side
Showing
1 changed file
examples/crust.rs
+530
-0
530 additions, 0 deletions
examples/crust.rs
with
530 additions
and
0 deletions
examples/crust.rs
0 → 100644
+
530
−
0
View file @
dfbdcd33
use
crust
::{
ast
::{
Expr
,
Func
,
Sig
,
Span
},
parse
::
parse_expr
,
};
use
inkwell
::{
builder
::
Builder
,
context
::
Context
,
execution_engine
::{
ExecutionEngine
,
JitFunction
},
module
::
Module
,
passes
::
PassManager
,
types
::
BasicTypeEnum
,
values
::{
BasicValueEnum
,
FloatValue
,
FunctionValue
,
PointerValue
},
FloatPredicate
,
OptimizationLevel
,
};
use
std
::
collections
::
HashMap
;
use
std
::
error
::
Error
;
type
ExprFunc
=
unsafe
extern
"C"
fn
()
->
i32
;
fn
jit_compile_sum
(
context
:
&
Context
,
module
:
&
Module
,
builder
:
&
Builder
,
execution_engine
:
&
ExecutionEngine
,
)
->
Option
<
JitFunction
<
ExprFunc
>>
{
let
u32_type
=
context
.i32_type
();
let
fn_type
=
u32_type
.fn_type
(
&
[],
false
);
let
function
=
module
.add_function
(
"expr"
,
fn_type
,
None
);
let
basic_block
=
context
.append_basic_block
(
&
function
,
"entry"
);
builder
.position_at_end
(
&
basic_block
);
let
x
=
context
.i32_type
()
.const_int
(
1
,
false
);
let
y
=
context
.i32_type
()
.const_int
(
2
,
false
);
let
z
=
context
.i32_type
()
.const_int
(
3
,
false
);
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
(
"expr"
)
.ok
()
}
}
fn
main
()
->
Result
<
(),
Box
<
dyn
Error
>>
{
let
context
=
Context
::
create
();
let
module
=
context
.create_module
(
"expr"
);
let
builder
=
context
.create_builder
();
let
execution_engine
=
module
.create_jit_execution_engine
(
OptimizationLevel
::
None
)
?
;
let
p
=
parse_expr
(
Span
::
new
(
"
1 + 2 + 3
"
,
));
println!
(
"{:?}"
,
&
p
);
let
fun_expr
=
jit_compile_sum
(
&
context
,
&
module
,
&
builder
,
&
execution_engine
)
.ok_or
(
"Unable to JIT compile `expr`"
)
?
;
unsafe
{
println!
(
"{}"
,
fun_expr
.call
());
}
Ok
(())
}
// fn main() {
// let p = parse_prog(Span::new(
// "
// fn main() -> i32
// {
// let a : i32 = 1 + 2;
// a = a + 1;
// return a
// }
// ",
// ));
// println!("{:?}", &p);
// }
// // ======================================================================================
// // COMPILER =============================================================================
// // ======================================================================================
// /// Defines the `Expr` compiler.
// pub struct Compiler<'a> {
// pub context: &'a Context,
// pub builder: &'a Builder,
// pub fpm: &'a PassManager<FunctionValue>,
// pub module: &'a Module,
// pub function: &'a Func<'a>,
// variables: HashMap<String, PointerValue>,
// fn_value_opt: Option<FunctionValue>,
// }
// impl<'a> Compiler<'a> {
// /// Gets a defined function given its name.
// #[inline]
// fn get_function(&self, name: &str) -> Option<FunctionValue> {
// self.module.get_function(name)
// }
// /// Returns the `FunctionValue` representing the function being compiled.
// #[inline]
// fn fn_value(&self) -> FunctionValue {
// self.fn_value_opt.unwrap()
// }
// /// Creates a new stack allocation instruction in the entry block of the function.
// fn create_entry_block_alloca(&self, name: &str) -> PointerValue {
// let builder = self.context.create_builder();
// let entry = self.fn_value().get_first_basic_block().unwrap();
// match entry.get_first_instruction() {
// Some(first_instr) => builder.position_before(&first_instr),
// None => builder.position_at_end(&entry),
// }
// builder.build_alloca(self.context.f64_type(), name)
// }
// /// Compiles the specified `Expr` into an LLVM `FloatValue`.
// fn compile_expr(
// &mut self,
// expr: &Expr,
// ) -> Result<FloatValue, &'static str> {
// match *expr {
// // Expr::Num(nb) => Ok(self.context.i32_type().const_int(nb, true)),
// // Expr::Variable(ref name) => {
// // match self.variables.get(name.as_str()) {
// // Some(var) => Ok(self
// // .builder
// // .build_load(*var, name.as_str())
// // .into_float_value()),
// // None => Err("Could not find a matching variable."),
// // }
// // }
// // Expr::VarIn {
// // ref variables,
// // ref body,
// // } => {
// // let mut old_bindings = Vec::new();
// // for &(ref var_name, ref initializer) in variables {
// // let var_name = var_name.as_str();
// // let initial_val = match *initializer {
// // Some(ref init) => self.compile_expr(init)?,
// // None => self.context.f64_type().const_float(0.),
// // };
// // let alloca = self.create_entry_block_alloca(var_name);
// // self.builder.build_store(alloca, initial_val);
// // if let Some(old_binding) = self.variables.remove(var_name) {
// // old_bindings.push(old_binding);
// // }
// // self.variables.insert(var_name.to_string(), alloca);
// // }
// // let body = self.compile_expr(body)?;
// // for binding in old_bindings {
// // self.variables.insert(
// // binding.get_name().to_str().unwrap().to_string(),
// // binding,
// // );
// // }
// // Ok(body)
// // }
// // Expr::Binary {
// // op,
// // ref left,
// // ref right,
// // } => {
// // if op == '=' {
// // // handle assignement
// // let var_name = match *left.borrow() {
// // Expr::Variable(ref var_name) => var_name,
// // _ => {
// // return Err("Expected variable as left-hand operator of assignement.");
// // }
// // };
// // let var_val = self.compile_expr(right)?;
// // let var = self
// // .variables
// // .get(var_name.as_str())
// // .ok_or("Undefined variable.")?;
// // self.builder.build_store(*var, var_val);
// // Ok(var_val)
// // } else {
// // let lhs = self.compile_expr(left)?;
// // let rhs = self.compile_expr(right)?;
// // match op {
// // '+' => {
// // Ok(self.builder.build_float_add(lhs, rhs, "tmpadd"))
// // }
// // '-' => {
// // Ok(self.builder.build_float_sub(lhs, rhs, "tmpsub"))
// // }
// // '*' => {
// // Ok(self.builder.build_float_mul(lhs, rhs, "tmpmul"))
// // }
// // '/' => {
// // Ok(self.builder.build_float_div(lhs, rhs, "tmpdiv"))
// // }
// // '<' => Ok({
// // let cmp = self.builder.build_float_compare(
// // FloatPredicate::ULT,
// // lhs,
// // rhs,
// // "tmpcmp",
// // );
// // self.builder.build_unsigned_int_to_float(
// // cmp,
// // self.context.f64_type(),
// // "tmpbool",
// // )
// // }),
// // '>' => Ok({
// // let cmp = self.builder.build_float_compare(
// // FloatPredicate::ULT,
// // rhs,
// // lhs,
// // "tmpcmp",
// // );
// // self.builder.build_unsigned_int_to_float(
// // cmp,
// // self.context.f64_type(),
// // "tmpbool",
// // )
// // }),
// // custom => {
// // let mut name = String::from("binary");
// // name.push(custom);
// // match self.get_function(name.as_str()) {
// // Some(fun) => {
// // match self
// // .builder
// // .build_call(
// // fun,
// // &[lhs.into(), rhs.into()],
// // "tmpbin",
// // )
// // .try_as_basic_value()
// // .left()
// // {
// // Some(value) => {
// // Ok(value.into_float_value())
// // }
// // None => Err("Invalid call produced."),
// // }
// // }
// // None => Err("Undefined binary operator."),
// // }
// // }
// // }
// // }
// // }
// // Expr::Call {
// // ref fn_name,
// // ref args,
// // } => match self.get_function(fn_name.as_str()) {
// // Some(fun) => {
// // let mut compiled_args = Vec::with_capacity(args.len());
// // for arg in args {
// // compiled_args.push(self.compile_expr(arg)?);
// // }
// // let argsv: Vec<BasicValueEnum> = compiled_args
// // .iter()
// // .by_ref()
// // .map(|&val| val.into())
// // .collect();
// // match self
// // .builder
// // .build_call(fun, argsv.as_slice(), "tmp")
// // .try_as_basic_value()
// // .left()
// // {
// // Some(value) => Ok(value.into_float_value()),
// // None => Err("Invalid call produced."),
// // }
// // }
// // None => Err("Unknown function."),
// // },
// // Expr::Conditional {
// // ref cond,
// // ref consequence,
// // ref alternative,
// // } => {
// // let parent = self.fn_value();
// // let zero_const = self.context.f64_type().const_float(0.0);
// // // create condition by comparing without 0.0 and returning an int
// // let cond = self.compile_expr(cond)?;
// // let cond = self.builder.build_float_compare(
// // FloatPredicate::ONE,
// // cond,
// // zero_const,
// // "ifcond",
// // );
// // // build branch
// // let then_bb = self.context.append_basic_block(&parent, "then");
// // let else_bb = self.context.append_basic_block(&parent, "else");
// // let cont_bb =
// // self.context.append_basic_block(&parent, "ifcont");
// // self.builder
// // .build_conditional_branch(cond, &then_bb, &else_bb);
// // // build then block
// // self.builder.position_at_end(&then_bb);
// // let then_val = self.compile_expr(consequence)?;
// // self.builder.build_unconditional_branch(&cont_bb);
// // let then_bb = self.builder.get_insert_block().unwrap();
// // // build else block
// // self.builder.position_at_end(&else_bb);
// // let else_val = self.compile_expr(alternative)?;
// // self.builder.build_unconditional_branch(&cont_bb);
// // let else_bb = self.builder.get_insert_block().unwrap();
// // // emit merge block
// // self.builder.position_at_end(&cont_bb);
// // let phi =
// // self.builder.build_phi(self.context.f64_type(), "iftmp");
// // phi.add_incoming(&[
// // (&then_val, &then_bb),
// // (&else_val, &else_bb),
// // ]);
// // Ok(phi.as_basic_value().into_float_value())
// // }
// // Expr::For {
// // ref var_name,
// // ref start,
// // ref end,
// // ref step,
// // ref body,
// // } => {
// // let parent = self.fn_value();
// // let start_alloca = self.create_entry_block_alloca(var_name);
// // let start = self.compile_expr(start)?;
// // self.builder.build_store(start_alloca, start);
// // // go from current block to loop block
// // let loop_bb = self.context.append_basic_block(&parent, "loop");
// // self.builder.build_unconditional_branch(&loop_bb);
// // self.builder.position_at_end(&loop_bb);
// // let old_val = self.variables.remove(var_name.as_str());
// // self.variables.insert(var_name.to_owned(), start_alloca);
// // // emit body
// // self.compile_expr(body)?;
// // // emit step
// // let step = match *step {
// // Some(ref step) => self.compile_expr(step)?,
// // None => self.context.f64_type().const_float(1.0),
// // };
// // // compile end condition
// // let end_cond = self.compile_expr(end)?;
// // let curr_var = self.builder.build_load(start_alloca, var_name);
// // let next_var = self.builder.build_float_add(
// // curr_var.into_float_value(),
// // step,
// // "nextvar",
// // );
// // self.builder.build_store(start_alloca, next_var);
// // let end_cond = self.builder.build_float_compare(
// // FloatPredicate::ONE,
// // end_cond,
// // self.context.f64_type().const_float(0.0),
// // "loopcond",
// // );
// // let after_bb =
// // self.context.append_basic_block(&parent, "afterloop");
// // self.builder
// // .build_conditional_branch(end_cond, &loop_bb, &after_bb);
// // self.builder.position_at_end(&after_bb);
// // self.variables.remove(var_name);
// // if let Some(val) = old_val {
// // self.variables.insert(var_name.to_owned(), val);
// // }
// // Ok(self.context.f64_type().const_float(0.0))
// // }
// _ => unimplemented!(),
// }
// }
// /// Compiles the specified `Prototype` into an extern LLVM `FunctionValue`.
// fn compile_prototype(
// &self,
// sig: &Sig,
// ) -> Result<FunctionValue, &'static str> {
// let ret_type = sig.2;
// let args_types = std::iter::repeat(ret_type)
// .take(sig.1.len())
// .map(|f| f.into())
// .collect::<Vec<BasicTypeEnum>>();
// let args_types = args_types.as_slice();
// let fn_type = self.context.f64_type().fn_type(args_types, false);
// let fn_val = self.module.add_function(sig.0.as_str(), fn_type, None);
// // set arguments names
// for (i, arg) in fn_val.get_param_iter().enumerate() {
// arg.into_float_value().set_name(proto.args[i].as_str());
// }
// // finally return built prototype
// Ok(fn_val)
// }
// /// Compiles the specified `Function` into an LLVM `FunctionValue`.
// fn compile_fn(&mut self) -> Result<FunctionValue, &'static str> {
// let sig = &self.function.sig;
// let function = self.compile_sig(sig)?;
// // got external function, returning only compiled prototype
// // if self.function.body.is_none() {
// // return Ok(function);
// // }
// let entry = self.context.append_basic_block(&function, "entry");
// self.builder.position_at_end(&entry);
// // update fn field
// self.fn_value_opt = Some(function);
// // build variables map
// self.variables.reserve(proto.args.len());
// for (i, arg) in function.get_param_iter().enumerate() {
// let arg_name = proto.args[i].as_str();
// let alloca = self.create_entry_block_alloca(arg_name);
// self.builder.build_store(alloca, arg);
// self.variables.insert(proto.args[i].clone(), alloca);
// }
// // compile body
// let body = self.compile_expr(self.function.body.as_ref().unwrap())?;
// self.builder.build_return(Some(&body));
// // return the whole thing after verification and optimization
// if function.verify(true) {
// self.fpm.run_on(&function);
// Ok(function)
// } else {
// unsafe {
// function.delete();
// }
// Err("Invalid generated function.")
// }
// }
// /// Compiles the specified `Function` in the given `Context` and using the specified `Builder`, `PassManager`, and `Module`.
// pub fn compile(
// context: &'a Context,
// builder: &'a Builder,
// pass_manager: &'a PassManager<FunctionValue>,
// module: &'a Module,
// function: &Function,
// ) -> Result<FunctionValue, &'static str> {
// let mut compiler = Compiler {
// context: context,
// builder: builder,
// fpm: pass_manager,
// module: module,
// function: function,
// fn_value_opt: None,
// variables: HashMap::new(),
// };
// compiler.compile_fn()
// }
// }
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment