mirror of
https://github.com/roc-lang/roc.git
synced 2025-10-02 16:21:11 +00:00
hooking everything up
This commit is contained in:
parent
84d5cbc4f1
commit
ee21f86f8f
9 changed files with 334 additions and 19 deletions
|
@ -129,6 +129,17 @@ pub fn dictLen(dict: RocDict) callconv(.C) usize {
|
|||
return dict.dict_entries_len;
|
||||
}
|
||||
|
||||
// Dict.insert : Dict k v, k, v -> Dict k v
|
||||
const Opaque = ?[*]u8;
|
||||
const HashFn = fn (u64, ?[*]u8) callconv(.C) u64;
|
||||
const EqFn = fn (?[*]u8, ?[*]u8) callconv(.C) bool;
|
||||
const Dec = fn (?[*]u8) callconv(.C) void;
|
||||
pub fn dictInsert(dict: RocDict, alignment: usize, key: Opaque, key_width: usize, value: Opaque, value_width: usize, hash: HashFn, is_eq: EqFn, dec_value: Dec, result: *RocDict) callconv(.C) void {
|
||||
result.* = RocDict.empty();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
test "RocDict.init() contains nothing" {
|
||||
const key_size = @sizeOf(usize);
|
||||
const value_size = @sizeOf(usize);
|
||||
|
|
|
@ -9,6 +9,7 @@ const hash = @import("hash.zig");
|
|||
comptime {
|
||||
exportDictFn(dict.dictLen, "len");
|
||||
exportDictFn(dict.dictEmpty, "empty");
|
||||
exportDictFn(dict.dictInsert, "insert");
|
||||
exportDictFn(hash.wyhash, "hash");
|
||||
exportDictFn(hash.wyhash_rocstr, "hash_str");
|
||||
}
|
||||
|
|
|
@ -39,3 +39,4 @@ pub const DICT_HASH: &str = "roc_builtins.dict.hash";
|
|||
pub const DICT_HASH_STR: &str = "roc_builtins.dict.hash_str";
|
||||
pub const DICT_LEN: &str = "roc_builtins.dict.len";
|
||||
pub const DICT_EMPTY: &str = "roc_builtins.dict.empty";
|
||||
pub const DICT_INSERT: &str = "roc_builtins.dict.insert";
|
||||
|
|
|
@ -4004,7 +4004,16 @@ fn run_low_level<'a, 'ctx, 'env>(
|
|||
let (dict, _) = load_symbol_and_layout(scope, &args[0]);
|
||||
let (key, key_layout) = load_symbol_and_layout(scope, &args[1]);
|
||||
let (value, value_layout) = load_symbol_and_layout(scope, &args[2]);
|
||||
dict_insert(env, scope, dict, key, key_layout, value, value_layout)
|
||||
dict_insert(
|
||||
env,
|
||||
layout_ids,
|
||||
scope,
|
||||
dict,
|
||||
key,
|
||||
key_layout,
|
||||
value,
|
||||
value_layout,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,14 +1,37 @@
|
|||
use crate::llvm::build::{
|
||||
call_bitcode_fn, call_void_bitcode_fn, complex_bitcast, load_symbol, load_symbol_and_layout,
|
||||
Env, Scope,
|
||||
set_name, Env, Scope,
|
||||
};
|
||||
use crate::llvm::convert::collection;
|
||||
use inkwell::types::BasicTypeEnum;
|
||||
use inkwell::values::{BasicValueEnum, IntValue, StructValue};
|
||||
use crate::llvm::convert::{basic_type_from_layout, collection};
|
||||
use inkwell::types::{BasicType, BasicTypeEnum};
|
||||
use inkwell::values::{BasicValueEnum, FunctionValue, IntValue, StructValue};
|
||||
use inkwell::AddressSpace;
|
||||
use roc_builtins::bitcode;
|
||||
use roc_module::symbol::Symbol;
|
||||
use roc_mono::layout::{Builtin, Layout};
|
||||
use roc_mono::layout::{Builtin, Layout, LayoutIds};
|
||||
|
||||
macro_rules! debug_info_init {
|
||||
($env:expr, $function_value:expr) => {{
|
||||
use inkwell::debug_info::AsDIScope;
|
||||
|
||||
let func_scope = $function_value.get_subprogram().unwrap();
|
||||
let lexical_block = $env.dibuilder.create_lexical_block(
|
||||
/* scope */ func_scope.as_debug_info_scope(),
|
||||
/* file */ $env.compile_unit.get_file(),
|
||||
/* line_no */ 0,
|
||||
/* column_no */ 0,
|
||||
);
|
||||
|
||||
let loc = $env.dibuilder.create_debug_location(
|
||||
$env.context,
|
||||
/* line */ 0,
|
||||
/* column */ 0,
|
||||
/* current_scope */ lexical_block.as_debug_info_scope(),
|
||||
/* inlined_at */ None,
|
||||
);
|
||||
$env.builder.set_current_debug_location(&$env.context, loc);
|
||||
}};
|
||||
}
|
||||
|
||||
pub fn dict_len<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
|
@ -21,9 +44,15 @@ pub fn dict_len<'a, 'ctx, 'env>(
|
|||
|
||||
match dict_layout {
|
||||
Layout::Builtin(Builtin::Dict(_, _)) => {
|
||||
let dict_as_int = dict_symbol_to_i128(env, scope, dict_symbol);
|
||||
// let dict_as_int = dict_symbol_to_i128(env, scope, dict_symbol);
|
||||
let dict_as_zig_dict = dict_symbol_to_zig_dict(env, scope, dict_symbol);
|
||||
|
||||
call_bitcode_fn(env, &[dict_as_int.into()], &bitcode::DICT_LEN)
|
||||
let dict_ptr = env
|
||||
.builder
|
||||
.build_alloca(dict_as_zig_dict.get_type(), "dict_ptr");
|
||||
env.builder.build_store(dict_ptr, dict_as_zig_dict);
|
||||
|
||||
call_bitcode_fn(env, &[dict_ptr.into()], &bitcode::DICT_LEN)
|
||||
}
|
||||
Layout::Builtin(Builtin::EmptyDict) => ctx.i64_type().const_zero().into(),
|
||||
_ => unreachable!("Invalid layout given to Dict.len : {:?}", dict_layout),
|
||||
|
@ -51,15 +80,231 @@ pub fn dict_empty<'a, 'ctx, 'env>(
|
|||
}
|
||||
|
||||
pub fn dict_insert<'a, 'ctx, 'env>(
|
||||
_env: &Env<'a, 'ctx, 'env>,
|
||||
_scope: &Scope<'a, 'ctx>,
|
||||
_dict: BasicValueEnum<'ctx>,
|
||||
_key: BasicValueEnum<'ctx>,
|
||||
_key_layout: &Layout<'a>,
|
||||
_value: BasicValueEnum<'ctx>,
|
||||
_value_layout: &Layout<'a>,
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
layout_ids: &mut LayoutIds<'a>,
|
||||
scope: &Scope<'a, 'ctx>,
|
||||
dict: BasicValueEnum<'ctx>,
|
||||
key: BasicValueEnum<'ctx>,
|
||||
key_layout: &Layout<'a>,
|
||||
value: BasicValueEnum<'ctx>,
|
||||
value_layout: &Layout<'a>,
|
||||
) -> BasicValueEnum<'ctx> {
|
||||
todo!()
|
||||
let builder = env.builder;
|
||||
|
||||
let zig_dict_type = env.module.get_struct_type("dict.RocDict").unwrap();
|
||||
let u8_ptr = env.context.i8_type().ptr_type(AddressSpace::Generic);
|
||||
|
||||
let dict_ptr = builder.build_alloca(zig_dict_type, "dict_ptr");
|
||||
let key_ptr = builder.build_alloca(key.get_type(), "key_ptr");
|
||||
let value_ptr = builder.build_alloca(key.get_type(), "value_ptr");
|
||||
|
||||
env.builder
|
||||
.build_store(dict_ptr, struct_to_zig_dict(env, dict.into_struct_value()));
|
||||
env.builder.build_store(key_ptr, key);
|
||||
env.builder.build_store(value_ptr, value);
|
||||
|
||||
let key_width = env
|
||||
.ptr_int()
|
||||
.const_int(key_layout.stack_size(env.ptr_bytes) as u64, false);
|
||||
|
||||
let value_width = env
|
||||
.ptr_int()
|
||||
.const_int(value_layout.stack_size(env.ptr_bytes) as u64, false);
|
||||
|
||||
let result_ptr = builder.build_alloca(zig_dict_type, "result_ptr");
|
||||
|
||||
let alignment = key_layout
|
||||
.alignment_bytes(env.ptr_bytes)
|
||||
.max(value_layout.alignment_bytes(env.ptr_bytes));
|
||||
|
||||
let alignment_iv = env.ptr_int().const_int(alignment as u64, false);
|
||||
|
||||
let hash_fn = build_hash_wrapper(env, layout_ids, key_layout);
|
||||
let eq_fn = build_eq_wrapper(env, layout_ids, key_layout);
|
||||
let dec_value_fn = build_rc_wrapper(env, layout_ids, key_layout);
|
||||
|
||||
call_void_bitcode_fn(
|
||||
env,
|
||||
&[
|
||||
dict_ptr.into(),
|
||||
alignment_iv.into(),
|
||||
env.builder.build_bitcast(key_ptr, u8_ptr, "to_u8_ptr"),
|
||||
key_width.into(),
|
||||
env.builder.build_bitcast(value_ptr, u8_ptr, "to_u8_ptr"),
|
||||
value_width.into(),
|
||||
hash_fn.as_global_value().as_pointer_value().into(),
|
||||
eq_fn.as_global_value().as_pointer_value().into(),
|
||||
dec_value_fn.as_global_value().as_pointer_value().into(),
|
||||
result_ptr.into(),
|
||||
],
|
||||
&bitcode::DICT_INSERT,
|
||||
);
|
||||
|
||||
zig_dict_to_struct(
|
||||
env,
|
||||
builder
|
||||
.build_load(result_ptr, "load_result")
|
||||
.into_struct_value(),
|
||||
)
|
||||
.into()
|
||||
}
|
||||
|
||||
fn build_hash_wrapper<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
layout_ids: &mut LayoutIds<'a>,
|
||||
layout: &Layout<'a>,
|
||||
) -> FunctionValue<'ctx> {
|
||||
let block = env.builder.get_insert_block().expect("to be in a function");
|
||||
let di_location = env.builder.get_current_debug_location().unwrap();
|
||||
|
||||
let symbol = Symbol::GENERIC_HASH_REF;
|
||||
let fn_name = layout_ids
|
||||
.get(symbol, &layout)
|
||||
.to_symbol_string(symbol, &env.interns);
|
||||
|
||||
let function_value = match env.module.get_function(fn_name.as_str()) {
|
||||
Some(function_value) => function_value,
|
||||
None => {
|
||||
let arena = env.arena;
|
||||
|
||||
let seed_type = env.context.i64_type();
|
||||
|
||||
let arg_type = env.context.i8_type().ptr_type(AddressSpace::Generic);
|
||||
|
||||
let function_value = crate::llvm::refcounting::build_header_help(
|
||||
env,
|
||||
&fn_name,
|
||||
seed_type.into(),
|
||||
&[seed_type.into(), arg_type.into()],
|
||||
);
|
||||
|
||||
let entry = env.context.append_basic_block(function_value, "entry");
|
||||
env.builder.position_at_end(entry);
|
||||
|
||||
debug_info_init!(env, function_value);
|
||||
|
||||
let mut it = function_value.get_param_iter();
|
||||
let seed_arg = it.next().unwrap().into_int_value();
|
||||
let value_ptr = it.next().unwrap().into_pointer_value();
|
||||
|
||||
set_name(seed_arg.into(), Symbol::ARG_1.ident_string(&env.interns));
|
||||
set_name(value_ptr.into(), Symbol::ARG_2.ident_string(&env.interns));
|
||||
|
||||
let value_type = basic_type_from_layout(env.arena, env.context, layout, env.ptr_bytes)
|
||||
.ptr_type(AddressSpace::Generic);
|
||||
|
||||
let value_cast = env
|
||||
.builder
|
||||
.build_bitcast(value_ptr, value_type, "load_opaque")
|
||||
.into_pointer_value();
|
||||
|
||||
let val_arg = env.builder.build_load(value_cast, "load_opaque");
|
||||
|
||||
let result =
|
||||
crate::llvm::build_hash::generic_hash(env, layout_ids, seed_arg, val_arg, layout);
|
||||
|
||||
env.builder.build_return(Some(&result));
|
||||
|
||||
function_value
|
||||
}
|
||||
};
|
||||
|
||||
env.builder.position_at_end(block);
|
||||
env.builder
|
||||
.set_current_debug_location(env.context, di_location);
|
||||
|
||||
function_value
|
||||
}
|
||||
|
||||
fn build_eq_wrapper<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
layout_ids: &mut LayoutIds<'a>,
|
||||
layout: &Layout<'a>,
|
||||
) -> FunctionValue<'ctx> {
|
||||
let block = env.builder.get_insert_block().expect("to be in a function");
|
||||
let di_location = env.builder.get_current_debug_location().unwrap();
|
||||
|
||||
let symbol = Symbol::GENERIC_EQ_REF;
|
||||
let fn_name = layout_ids
|
||||
.get(symbol, &layout)
|
||||
.to_symbol_string(symbol, &env.interns);
|
||||
|
||||
let function_value = match env.module.get_function(fn_name.as_str()) {
|
||||
Some(function_value) => function_value,
|
||||
None => {
|
||||
let arena = env.arena;
|
||||
|
||||
let arg_type = env.context.i8_type().ptr_type(AddressSpace::Generic);
|
||||
|
||||
let function_value = crate::llvm::refcounting::build_header_help(
|
||||
env,
|
||||
&fn_name,
|
||||
env.context.bool_type().into(),
|
||||
&[arg_type.into(), arg_type.into()],
|
||||
);
|
||||
|
||||
let entry = env.context.append_basic_block(function_value, "entry");
|
||||
env.builder.position_at_end(entry);
|
||||
|
||||
debug_info_init!(env, function_value);
|
||||
|
||||
env.builder
|
||||
.build_return(Some(&env.context.bool_type().const_zero()));
|
||||
|
||||
function_value
|
||||
}
|
||||
};
|
||||
|
||||
env.builder.position_at_end(block);
|
||||
env.builder
|
||||
.set_current_debug_location(env.context, di_location);
|
||||
|
||||
function_value
|
||||
}
|
||||
|
||||
fn build_rc_wrapper<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
layout_ids: &mut LayoutIds<'a>,
|
||||
layout: &Layout<'a>,
|
||||
) -> FunctionValue<'ctx> {
|
||||
let block = env.builder.get_insert_block().expect("to be in a function");
|
||||
let di_location = env.builder.get_current_debug_location().unwrap();
|
||||
|
||||
let symbol = Symbol::GENERIC_RC_REF;
|
||||
let fn_name = layout_ids
|
||||
.get(symbol, &layout)
|
||||
.to_symbol_string(symbol, &env.interns);
|
||||
|
||||
let function_value = match env.module.get_function(fn_name.as_str()) {
|
||||
Some(function_value) => function_value,
|
||||
None => {
|
||||
let arena = env.arena;
|
||||
|
||||
let arg_type = env.context.i8_type().ptr_type(AddressSpace::Generic);
|
||||
|
||||
let function_value = crate::llvm::refcounting::build_header_help(
|
||||
env,
|
||||
&fn_name,
|
||||
env.context.void_type().into(),
|
||||
&[arg_type.into()],
|
||||
);
|
||||
|
||||
let entry = env.context.append_basic_block(function_value, "entry");
|
||||
env.builder.position_at_end(entry);
|
||||
|
||||
debug_info_init!(env, function_value);
|
||||
|
||||
env.builder.build_return(None);
|
||||
|
||||
function_value
|
||||
}
|
||||
};
|
||||
|
||||
env.builder.position_at_end(block);
|
||||
env.builder
|
||||
.set_current_debug_location(env.context, di_location);
|
||||
|
||||
function_value
|
||||
}
|
||||
|
||||
fn dict_symbol_to_i128<'a, 'ctx, 'env>(
|
||||
|
@ -74,6 +319,19 @@ fn dict_symbol_to_i128<'a, 'ctx, 'env>(
|
|||
complex_bitcast(&env.builder, dict, i128_type, "dict_to_i128").into_int_value()
|
||||
}
|
||||
|
||||
fn dict_symbol_to_zig_dict<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
scope: &Scope<'a, 'ctx>,
|
||||
symbol: Symbol,
|
||||
) -> StructValue<'ctx> {
|
||||
let dict = load_symbol(scope, &symbol);
|
||||
|
||||
let zig_dict_type = env.module.get_struct_type("dict.RocDict").unwrap();
|
||||
|
||||
complex_bitcast(&env.builder, dict, zig_dict_type.into(), "dict_to_zig_dict")
|
||||
.into_struct_value()
|
||||
}
|
||||
|
||||
fn zig_dict_to_struct<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
zig_dict: StructValue<'ctx>,
|
||||
|
@ -108,3 +366,19 @@ fn zig_dict_to_struct<'a, 'ctx, 'env>(
|
|||
|
||||
builder.build_load(ptr4, "load").into_struct_value()
|
||||
}
|
||||
|
||||
fn struct_to_zig_dict<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
struct_dict: StructValue<'ctx>,
|
||||
) -> StructValue<'ctx> {
|
||||
// get the RocStr type defined by zig
|
||||
let zig_dict_type = env.module.get_struct_type("dict.RocDict").unwrap();
|
||||
|
||||
complex_bitcast(
|
||||
env.builder,
|
||||
struct_dict.into(),
|
||||
zig_dict_type.into(),
|
||||
"to_zig_dict",
|
||||
)
|
||||
.into_struct_value()
|
||||
}
|
||||
|
|
|
@ -394,8 +394,10 @@ fn modify_refcount_builtin<'a, 'ctx, 'env>(
|
|||
// TODO decrement all values
|
||||
}
|
||||
|
||||
todo!();
|
||||
// todo!();
|
||||
dbg!("DOING NOTHING WITH REFCOUNTING");
|
||||
}
|
||||
|
||||
Str => {
|
||||
let wrapper_struct = value.into_struct_value();
|
||||
modify_refcount_str(env, layout_ids, mode, layout, wrapper_struct);
|
||||
|
|
|
@ -25,4 +25,18 @@ mod gen_dict {
|
|||
usize
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn dict_insert_empty() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
Dict.insert Dict.empty 42 32
|
||||
|> Dict.len
|
||||
"#
|
||||
),
|
||||
1,
|
||||
usize
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -266,7 +266,7 @@ pub fn helper<'a>(
|
|||
);
|
||||
|
||||
fn_val.print_to_stderr();
|
||||
// module.print_to_stderr();
|
||||
module.print_to_stderr();
|
||||
|
||||
panic!(
|
||||
"The preceding code was from {:?}, which failed LLVM verification in {} build.",
|
||||
|
|
|
@ -741,7 +741,10 @@ define_builtins! {
|
|||
11 DEC: "#dec" // internal function that increments the refcount
|
||||
12 ARG_CLOSURE: "#arg_closure" // symbol used to store the closure record
|
||||
13 LIST_EQ: "#list_eq" // internal function that checks list equality
|
||||
14 GENERIC_HASH: "#generic_hash" // internal function that checks list equality
|
||||
14 GENERIC_HASH: "#generic_hash" // hash of arbitrary layouts
|
||||
15 GENERIC_HASH_REF: "#generic_hash_by_ref" // hash of arbitrary layouts, passed as an opaque pointer
|
||||
16 GENERIC_EQ_REF: "#generic_eq_by_ref" // equality of arbitrary layouts, passed as an opaque pointer
|
||||
17 GENERIC_RC_REF: "#generic_rc_by_ref" // refcount of arbitrary layouts, passed as an opaque pointer
|
||||
}
|
||||
1 NUM: "Num" => {
|
||||
0 NUM_NUM: "Num" imported // the Num.Num type alias
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue