mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-29 23:04:49 +00:00
make uniqueness change codegen
This commit is contained in:
parent
9e11526c1d
commit
79ea62b9d4
6 changed files with 52 additions and 37 deletions
|
@ -362,8 +362,6 @@ pub fn gen(src: &[u8], target: Triple, opt_level: OptLevel) -> Result<(String, S
|
||||||
// Uncomment this to see the module's optimized LLVM instruction output:
|
// Uncomment this to see the module's optimized LLVM instruction output:
|
||||||
// env.module.print_to_stderr();
|
// env.module.print_to_stderr();
|
||||||
|
|
||||||
panic!("are we here?");
|
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let main: JitFunction<
|
let main: JitFunction<
|
||||||
unsafe extern "C" fn() -> i64, /* TODO have this return Str, and in the generated code make sure to call the appropriate string conversion function on the return val based on its type! */
|
unsafe extern "C" fn() -> i64, /* TODO have this return Str, and in the generated code make sure to call the appropriate string conversion function on the return val based on its type! */
|
||||||
|
@ -375,8 +373,6 @@ pub fn gen(src: &[u8], target: Triple, opt_level: OptLevel) -> Result<(String, S
|
||||||
|
|
||||||
let result = main.call();
|
let result = main.call();
|
||||||
let output = format!("{}", result);
|
let output = format!("{}", result);
|
||||||
std::mem::forget(result);
|
|
||||||
|
|
||||||
Ok((output, expr_type_str))
|
Ok((output, expr_type_str))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -107,6 +107,7 @@ mod cli_run {
|
||||||
let out = run_roc(&[
|
let out = run_roc(&[
|
||||||
"run",
|
"run",
|
||||||
example_file("quicksort", "Quicksort.roc").to_str().unwrap(),
|
example_file("quicksort", "Quicksort.roc").to_str().unwrap(),
|
||||||
|
"--optimize",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert_eq!(&out.stderr, "");
|
assert_eq!(&out.stderr, "");
|
||||||
|
|
|
@ -224,6 +224,8 @@ pub fn gen(
|
||||||
|
|
||||||
// Populate Procs further and get the low-level Expr from the canonical Expr
|
// Populate Procs further and get the low-level Expr from the canonical Expr
|
||||||
let main_body = Stmt::new(&mut mono_env, loc_expr.value, &mut procs);
|
let main_body = Stmt::new(&mut mono_env, loc_expr.value, &mut procs);
|
||||||
|
let main_body =
|
||||||
|
roc_mono::inc_dec::visit_declaration(mono_env.arena, mono_env.arena.alloc(main_body));
|
||||||
let mut headers = {
|
let mut headers = {
|
||||||
let num_headers = match &procs.pending_specializations {
|
let num_headers = match &procs.pending_specializations {
|
||||||
Some(map) => map.len(),
|
Some(map) => map.len(),
|
||||||
|
|
|
@ -20,7 +20,7 @@ use roc_collections::all::ImMap;
|
||||||
use roc_module::low_level::LowLevel;
|
use roc_module::low_level::LowLevel;
|
||||||
use roc_module::symbol::{Interns, Symbol};
|
use roc_module::symbol::{Interns, Symbol};
|
||||||
use roc_mono::ir::JoinPointId;
|
use roc_mono::ir::JoinPointId;
|
||||||
use roc_mono::layout::{Builtin, Layout, Ownership};
|
use roc_mono::layout::{Builtin, Layout, MemoryMode};
|
||||||
use target_lexicon::CallingConvention;
|
use target_lexicon::CallingConvention;
|
||||||
|
|
||||||
/// This is for Inkwell's FunctionValue::verify - we want to know the verification
|
/// This is for Inkwell's FunctionValue::verify - we want to know the verification
|
||||||
|
@ -441,7 +441,6 @@ pub fn build_exp_expr<'a, 'ctx, 'env>(
|
||||||
debug_assert!(*union_size > 1);
|
debug_assert!(*union_size > 1);
|
||||||
let ptr_size = env.ptr_bytes;
|
let ptr_size = env.ptr_bytes;
|
||||||
|
|
||||||
let whole_size = tag_layout.stack_size(ptr_size);
|
|
||||||
let mut filler = tag_layout.stack_size(ptr_size);
|
let mut filler = tag_layout.stack_size(ptr_size);
|
||||||
|
|
||||||
let ctx = env.context;
|
let ctx = env.context;
|
||||||
|
@ -800,9 +799,9 @@ pub fn build_exp_stmt<'a, 'ctx, 'env>(
|
||||||
Inc(symbol, cont) => {
|
Inc(symbol, cont) => {
|
||||||
let (value, layout) = load_symbol_and_layout(env, scope, symbol);
|
let (value, layout) = load_symbol_and_layout(env, scope, symbol);
|
||||||
let layout = layout.clone();
|
let layout = layout.clone();
|
||||||
// TODO exclude unique lists in the future
|
|
||||||
match layout {
|
match layout {
|
||||||
Layout::Builtin(Builtin::List(_, _)) => {
|
Layout::Builtin(Builtin::List(MemoryMode::Refcounted, _)) => {
|
||||||
increment_refcount_list(env, value.into_struct_value());
|
increment_refcount_list(env, value.into_struct_value());
|
||||||
build_exp_stmt(env, layout_ids, scope, parent, cont)
|
build_exp_stmt(env, layout_ids, scope, parent, cont)
|
||||||
}
|
}
|
||||||
|
@ -813,11 +812,9 @@ pub fn build_exp_stmt<'a, 'ctx, 'env>(
|
||||||
let (value, layout) = load_symbol_and_layout(env, scope, symbol);
|
let (value, layout) = load_symbol_and_layout(env, scope, symbol);
|
||||||
let layout = layout.clone();
|
let layout = layout.clone();
|
||||||
|
|
||||||
/*
|
|
||||||
if layout.contains_refcounted() {
|
if layout.contains_refcounted() {
|
||||||
decrement_refcount_layout(env, parent, value, &layout);
|
decrement_refcount_layout(env, parent, value, &layout);
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
build_exp_stmt(env, layout_ids, scope, parent, cont)
|
build_exp_stmt(env, layout_ids, scope, parent, cont)
|
||||||
}
|
}
|
||||||
|
@ -830,15 +827,13 @@ fn refcount_is_one_comparison<'ctx>(
|
||||||
context: &'ctx Context,
|
context: &'ctx Context,
|
||||||
refcount: IntValue<'ctx>,
|
refcount: IntValue<'ctx>,
|
||||||
) -> IntValue<'ctx> {
|
) -> IntValue<'ctx> {
|
||||||
let refcount_one: IntValue<'ctx> = context
|
let refcount_one: IntValue<'ctx> = context.i64_type().const_int((std::usize::MAX) as _, false);
|
||||||
.i64_type()
|
|
||||||
.const_int((std::usize::MAX - 1) as _, false);
|
|
||||||
// Note: Check for refcount < refcount_1 as the "true" condition,
|
// Note: Check for refcount < refcount_1 as the "true" condition,
|
||||||
// to avoid misprediction. (In practice this should usually pass,
|
// to avoid misprediction. (In practice this should usually pass,
|
||||||
// and CPUs generally default to predicting that a forward jump
|
// and CPUs generally default to predicting that a forward jump
|
||||||
// shouldn't be taken; that is, they predict "else" won't be taken.)
|
// shouldn't be taken; that is, they predict "else" won't be taken.)
|
||||||
builder.build_int_compare(
|
builder.build_int_compare(
|
||||||
IntPredicate::ULT,
|
IntPredicate::EQ,
|
||||||
refcount,
|
refcount,
|
||||||
refcount_one,
|
refcount_one,
|
||||||
"refcount_one_check",
|
"refcount_one_check",
|
||||||
|
@ -867,13 +862,13 @@ fn list_get_refcount_ptr<'a, 'ctx, 'env>(
|
||||||
let refcount_ptr = builder.build_int_sub(
|
let refcount_ptr = builder.build_int_sub(
|
||||||
ptr_as_int,
|
ptr_as_int,
|
||||||
ctx.i64_type().const_int(env.ptr_bytes as u64, false),
|
ctx.i64_type().const_int(env.ptr_bytes as u64, false),
|
||||||
"refcount_ptr",
|
"make_refcount_ptr",
|
||||||
);
|
);
|
||||||
|
|
||||||
builder.build_int_to_ptr(
|
builder.build_int_to_ptr(
|
||||||
refcount_ptr,
|
refcount_ptr,
|
||||||
int_type.ptr_type(AddressSpace::Generic),
|
int_type.ptr_type(AddressSpace::Generic),
|
||||||
"make ptr",
|
"get_refcount_ptr",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -958,13 +953,16 @@ fn decrement_refcount_builtin<'a, 'ctx, 'env>(
|
||||||
use Builtin::*;
|
use Builtin::*;
|
||||||
|
|
||||||
match builtin {
|
match builtin {
|
||||||
List(_, element_layout) => {
|
List(MemoryMode::Refcounted, element_layout) => {
|
||||||
if element_layout.contains_refcounted() {
|
if element_layout.contains_refcounted() {
|
||||||
// TODO decrement all values
|
// TODO decrement all values
|
||||||
}
|
}
|
||||||
let wrapper_struct = value.into_struct_value();
|
let wrapper_struct = value.into_struct_value();
|
||||||
decrement_refcount_list(env, parent, wrapper_struct);
|
decrement_refcount_list(env, parent, wrapper_struct);
|
||||||
}
|
}
|
||||||
|
List(MemoryMode::Unique, _element_layout) => {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
Set(element_layout) => {
|
Set(element_layout) => {
|
||||||
if element_layout.contains_refcounted() {
|
if element_layout.contains_refcounted() {
|
||||||
// TODO decrement all values
|
// TODO decrement all values
|
||||||
|
@ -1091,17 +1089,6 @@ fn load_symbol_and_layout<'a, 'ctx, 'env, 'b>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_symbol_and_layout<'a, 'ctx, 'env, 'b>(
|
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
|
||||||
scope: &'b Scope<'a, 'ctx>,
|
|
||||||
symbol: &Symbol,
|
|
||||||
) -> (PointerValue<'ctx>, &'b Layout<'a>) {
|
|
||||||
match scope.get(symbol) {
|
|
||||||
Some((layout, ptr)) => (*ptr, layout),
|
|
||||||
None => panic!("There was no entry for {:?} in scope {:?}", symbol, scope),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Cast a struct to another struct of the same (or smaller?) size
|
/// Cast a struct to another struct of the same (or smaller?) size
|
||||||
fn cast_struct_struct<'ctx>(
|
fn cast_struct_struct<'ctx>(
|
||||||
builder: &Builder<'ctx>,
|
builder: &Builder<'ctx>,
|
||||||
|
@ -1788,7 +1775,7 @@ fn clone_nonempty_list<'a, 'ctx, 'env>(
|
||||||
.const_int(elem_layout.stack_size(env.ptr_bytes) as u64, false);
|
.const_int(elem_layout.stack_size(env.ptr_bytes) as u64, false);
|
||||||
let size = env
|
let size = env
|
||||||
.builder
|
.builder
|
||||||
.build_int_mul(elem_bytes, list_len, "mul_len_by_elem_bytes");
|
.build_int_mul(elem_bytes, list_len, "clone_mul_len_by_elem_bytes");
|
||||||
|
|
||||||
// Allocate space for the new array that we'll copy into.
|
// Allocate space for the new array that we'll copy into.
|
||||||
let clone_ptr = allocate_list(env, elem_layout, list_len);
|
let clone_ptr = allocate_list(env, elem_layout, list_len);
|
||||||
|
@ -1839,6 +1826,7 @@ fn clone_nonempty_list<'a, 'ctx, 'env>(
|
||||||
(answer, clone_ptr)
|
(answer, clone_ptr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
enum InPlace {
|
enum InPlace {
|
||||||
InPlace,
|
InPlace,
|
||||||
Clone,
|
Clone,
|
||||||
|
@ -2043,7 +2031,7 @@ fn list_join<'a, 'ctx, 'env>(
|
||||||
| Layout::Builtin(Builtin::List(_, Layout::Builtin(Builtin::EmptyList))) => empty_list(env),
|
| Layout::Builtin(Builtin::List(_, Layout::Builtin(Builtin::EmptyList))) => empty_list(env),
|
||||||
Layout::Builtin(Builtin::List(_, Layout::Builtin(Builtin::List(_, elem_layout)))) => {
|
Layout::Builtin(Builtin::List(_, Layout::Builtin(Builtin::List(_, elem_layout)))) => {
|
||||||
let inner_list_layout =
|
let inner_list_layout =
|
||||||
Layout::Builtin(Builtin::List(Ownership::Borrowed, elem_layout));
|
Layout::Builtin(Builtin::List(MemoryMode::Refcounted, elem_layout));
|
||||||
|
|
||||||
let builder = env.builder;
|
let builder = env.builder;
|
||||||
let ctx = env.context;
|
let ctx = env.context;
|
||||||
|
|
|
@ -749,7 +749,8 @@ mod gen_list {
|
||||||
r#"
|
r#"
|
||||||
quicksort : List (Num a) -> List (Num a)
|
quicksort : List (Num a) -> List (Num a)
|
||||||
quicksort = \list ->
|
quicksort = \list ->
|
||||||
quicksortHelp list 0 (List.len list - 1)
|
n = List.len list
|
||||||
|
quicksortHelp list 0 (n - 1)
|
||||||
|
|
||||||
|
|
||||||
quicksortHelp : List (Num a), Int, Int -> List (Num a)
|
quicksortHelp : List (Num a), Int, Int -> List (Num a)
|
||||||
|
@ -787,7 +788,7 @@ mod gen_list {
|
||||||
Pair (low - 1) initialList
|
Pair (low - 1) initialList
|
||||||
|
|
||||||
|
|
||||||
partitionHelp : Int, Int, List (Num a), Int, Int -> [ Pair Int (List (Num a)) ]
|
partitionHelp : Int, Int, List (Num a), Int, (Num a) -> [ Pair Int (List (Num a)) ]
|
||||||
partitionHelp = \i, j, list, high, pivot ->
|
partitionHelp = \i, j, list, high, pivot ->
|
||||||
if j < high then
|
if j < high then
|
||||||
when List.get list j is
|
when List.get list j is
|
||||||
|
@ -802,8 +803,6 @@ mod gen_list {
|
||||||
else
|
else
|
||||||
Pair i list
|
Pair i list
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
quicksort [ 7, 4, 21, 19 ]
|
quicksort [ 7, 4, 21, 19 ]
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
|
@ -1016,6 +1015,27 @@ mod gen_list {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn list_pass_to_set() {
|
||||||
|
assert_evals_to!(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
x : List Int
|
||||||
|
x = [1,2,3]
|
||||||
|
|
||||||
|
id : List Int -> List Int
|
||||||
|
id = \y -> List.set y 0 0
|
||||||
|
|
||||||
|
id x
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
&[0, 2, 3],
|
||||||
|
&'static [i64],
|
||||||
|
|x| x,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// fn bad() {
|
// fn bad() {
|
||||||
// assert_evals_to!(
|
// assert_evals_to!(
|
||||||
// indoc!(
|
// indoc!(
|
||||||
|
|
|
@ -104,6 +104,9 @@ pub fn helper_without_uniqueness<'a>(
|
||||||
};
|
};
|
||||||
|
|
||||||
let main_body = roc_mono::ir::Stmt::new(&mut mono_env, loc_expr.value, &mut procs);
|
let main_body = roc_mono::ir::Stmt::new(&mut mono_env, loc_expr.value, &mut procs);
|
||||||
|
let main_body =
|
||||||
|
roc_mono::inc_dec::visit_declaration(mono_env.arena, mono_env.arena.alloc(main_body));
|
||||||
|
|
||||||
let mut headers = {
|
let mut headers = {
|
||||||
let num_headers = match &procs.pending_specializations {
|
let num_headers = match &procs.pending_specializations {
|
||||||
Some(map) => map.len(),
|
Some(map) => map.len(),
|
||||||
|
@ -194,7 +197,7 @@ pub fn helper_without_uniqueness<'a>(
|
||||||
}
|
}
|
||||||
|
|
||||||
// Uncomment this to see the module's optimized LLVM instruction output:
|
// Uncomment this to see the module's optimized LLVM instruction output:
|
||||||
env.module.print_to_stderr();
|
// env.module.print_to_stderr();
|
||||||
|
|
||||||
(main_fn_name, execution_engine.clone())
|
(main_fn_name, execution_engine.clone())
|
||||||
}
|
}
|
||||||
|
@ -216,6 +219,7 @@ pub fn helper_with_uniqueness<'a>(
|
||||||
let target = target_lexicon::Triple::host();
|
let target = target_lexicon::Triple::host();
|
||||||
let ptr_bytes = target.pointer_width().unwrap().bytes() as u32;
|
let ptr_bytes = target.pointer_width().unwrap().bytes() as u32;
|
||||||
let (loc_expr, _output, problems, subs, var, constraint, home, interns) = uniq_expr(src);
|
let (loc_expr, _output, problems, subs, var, constraint, home, interns) = uniq_expr(src);
|
||||||
|
|
||||||
let errors = problems
|
let errors = problems
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter(|problem| {
|
.filter(|problem| {
|
||||||
|
@ -292,6 +296,8 @@ pub fn helper_with_uniqueness<'a>(
|
||||||
};
|
};
|
||||||
|
|
||||||
let main_body = roc_mono::ir::Stmt::new(&mut mono_env, loc_expr.value, &mut procs);
|
let main_body = roc_mono::ir::Stmt::new(&mut mono_env, loc_expr.value, &mut procs);
|
||||||
|
let main_body =
|
||||||
|
roc_mono::inc_dec::visit_declaration(mono_env.arena, mono_env.arena.alloc(main_body));
|
||||||
let mut headers = {
|
let mut headers = {
|
||||||
let num_headers = match &procs.pending_specializations {
|
let num_headers = match &procs.pending_specializations {
|
||||||
Some(map) => map.len(),
|
Some(map) => map.len(),
|
||||||
|
@ -365,6 +371,8 @@ pub fn helper_with_uniqueness<'a>(
|
||||||
|
|
||||||
builder.build_return(Some(&ret));
|
builder.build_return(Some(&ret));
|
||||||
|
|
||||||
|
// you're in the version with uniqueness!
|
||||||
|
|
||||||
// Uncomment this to see the module's un-optimized LLVM instruction output:
|
// Uncomment this to see the module's un-optimized LLVM instruction output:
|
||||||
// env.module.print_to_stderr();
|
// env.module.print_to_stderr();
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue