mirror of
https://github.com/roc-lang/roc.git
synced 2025-10-02 16:21:11 +00:00
add llvm expect cloning
This commit is contained in:
parent
ab3a431db7
commit
d4feaf871b
4 changed files with 296 additions and 107 deletions
|
@ -14,6 +14,7 @@ use crate::llvm::convert::{
|
||||||
self, argument_type_from_layout, basic_type_from_builtin, basic_type_from_layout,
|
self, argument_type_from_layout, basic_type_from_builtin, basic_type_from_layout,
|
||||||
block_of_memory_slices, zig_str_type,
|
block_of_memory_slices, zig_str_type,
|
||||||
};
|
};
|
||||||
|
use crate::llvm::expect::clone_to_shared_memory;
|
||||||
use crate::llvm::refcounting::{
|
use crate::llvm::refcounting::{
|
||||||
build_reset, decrement_refcount_layout, increment_refcount_layout, PointerToRefcount,
|
build_reset, decrement_refcount_layout, increment_refcount_layout, PointerToRefcount,
|
||||||
};
|
};
|
||||||
|
@ -2911,105 +2912,14 @@ pub fn build_exp_stmt<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
match env.target_info.ptr_width() {
|
match env.target_info.ptr_width() {
|
||||||
roc_target::PtrWidth::Bytes8 => {
|
roc_target::PtrWidth::Bytes8 => {
|
||||||
let func = env
|
clone_to_shared_memory(
|
||||||
.module
|
env,
|
||||||
.get_function(bitcode::UTILS_EXPECT_FAILED_START)
|
scope,
|
||||||
.unwrap();
|
layout_ids,
|
||||||
|
*cond_symbol,
|
||||||
let call_result = bd.build_call(func, &[], "call_expect_start_failed");
|
*region,
|
||||||
|
lookups,
|
||||||
let mut ptr = call_result
|
);
|
||||||
.try_as_basic_value()
|
|
||||||
.left()
|
|
||||||
.unwrap()
|
|
||||||
.into_pointer_value();
|
|
||||||
|
|
||||||
{
|
|
||||||
let value = env
|
|
||||||
.context
|
|
||||||
.i32_type()
|
|
||||||
.const_int(region.start().offset as _, false);
|
|
||||||
|
|
||||||
let cast_ptr = env.builder.build_pointer_cast(
|
|
||||||
ptr,
|
|
||||||
value.get_type().ptr_type(AddressSpace::Generic),
|
|
||||||
"to_store_pointer",
|
|
||||||
);
|
|
||||||
|
|
||||||
env.builder.build_store(cast_ptr, value);
|
|
||||||
|
|
||||||
// let increment = layout.stack_size(env.target_info);
|
|
||||||
let increment = 4;
|
|
||||||
let increment = env.ptr_int().const_int(increment as _, false);
|
|
||||||
|
|
||||||
ptr = unsafe {
|
|
||||||
env.builder.build_gep(ptr, &[increment], "increment_ptr")
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
let value = env
|
|
||||||
.context
|
|
||||||
.i32_type()
|
|
||||||
.const_int(region.end().offset as _, false);
|
|
||||||
|
|
||||||
let cast_ptr = env.builder.build_pointer_cast(
|
|
||||||
ptr,
|
|
||||||
value.get_type().ptr_type(AddressSpace::Generic),
|
|
||||||
"to_store_pointer",
|
|
||||||
);
|
|
||||||
|
|
||||||
env.builder.build_store(cast_ptr, value);
|
|
||||||
|
|
||||||
// let increment = layout.stack_size(env.target_info);
|
|
||||||
let increment = 4;
|
|
||||||
let increment = env.ptr_int().const_int(increment as _, false);
|
|
||||||
|
|
||||||
ptr = unsafe {
|
|
||||||
env.builder.build_gep(ptr, &[increment], "increment_ptr")
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
let region_bytes: u32 =
|
|
||||||
unsafe { std::mem::transmute(cond_symbol.module_id()) };
|
|
||||||
let value = env.context.i32_type().const_int(region_bytes as _, false);
|
|
||||||
|
|
||||||
let cast_ptr = env.builder.build_pointer_cast(
|
|
||||||
ptr,
|
|
||||||
value.get_type().ptr_type(AddressSpace::Generic),
|
|
||||||
"to_store_pointer",
|
|
||||||
);
|
|
||||||
|
|
||||||
env.builder.build_store(cast_ptr, value);
|
|
||||||
|
|
||||||
// let increment = layout.stack_size(env.target_info);
|
|
||||||
let increment = 4;
|
|
||||||
let increment = env.ptr_int().const_int(increment as _, false);
|
|
||||||
|
|
||||||
ptr = unsafe {
|
|
||||||
env.builder.build_gep(ptr, &[increment], "increment_ptr")
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
for lookup in lookups.iter() {
|
|
||||||
let (value, layout) = load_symbol_and_layout(scope, lookup);
|
|
||||||
|
|
||||||
let cast_ptr = env.builder.build_pointer_cast(
|
|
||||||
ptr,
|
|
||||||
value.get_type().ptr_type(AddressSpace::Generic),
|
|
||||||
"to_store_pointer",
|
|
||||||
);
|
|
||||||
|
|
||||||
store_roc_value(env, *layout, cast_ptr, value);
|
|
||||||
|
|
||||||
let increment = layout.stack_size(env.target_info);
|
|
||||||
let increment = env.ptr_int().const_int(increment as _, false);
|
|
||||||
|
|
||||||
ptr = unsafe {
|
|
||||||
env.builder.build_gep(ptr, &[increment], "increment_ptr")
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// NOTE: signals to the parent process that an expect failed
|
// NOTE: signals to the parent process that an expect failed
|
||||||
if env.mode.runs_expects_in_separate_process() {
|
if env.mode.runs_expects_in_separate_process() {
|
||||||
|
|
261
crates/compiler/gen_llvm/src/llvm/expect.rs
Normal file
261
crates/compiler/gen_llvm/src/llvm/expect.rs
Normal file
|
@ -0,0 +1,261 @@
|
||||||
|
use crate::llvm::bitcode::{call_bitcode_fn, call_str_bitcode_fn};
|
||||||
|
use crate::llvm::build::{get_tag_id, tag_pointer_clear_tag_id, Env, FAST_CALL_CONV};
|
||||||
|
use crate::llvm::build_list::{list_len, load_list_ptr};
|
||||||
|
use crate::llvm::build_str::str_equal;
|
||||||
|
use crate::llvm::convert::basic_type_from_layout;
|
||||||
|
use bumpalo::collections::Vec;
|
||||||
|
use inkwell::types::BasicType;
|
||||||
|
use inkwell::values::{
|
||||||
|
BasicValue, BasicValueEnum, FunctionValue, IntValue, PointerValue, StructValue,
|
||||||
|
};
|
||||||
|
use inkwell::{AddressSpace, FloatPredicate, IntPredicate};
|
||||||
|
use roc_builtins::bitcode;
|
||||||
|
use roc_builtins::bitcode::{FloatWidth, IntWidth};
|
||||||
|
use roc_module::symbol::Symbol;
|
||||||
|
use roc_mono::layout::{Builtin, Layout, LayoutIds, UnionLayout};
|
||||||
|
use roc_region::all::Region;
|
||||||
|
|
||||||
|
use super::build::{
|
||||||
|
dec_binop_with_unchecked, load_roc_value, load_symbol_and_layout, use_roc_value, Scope,
|
||||||
|
};
|
||||||
|
use super::convert::argument_type_from_union_layout;
|
||||||
|
|
||||||
|
pub(crate) fn clone_to_shared_memory<'a, 'ctx, 'env>(
|
||||||
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
|
scope: &Scope<'a, 'ctx>,
|
||||||
|
layout_ids: &mut LayoutIds<'a>,
|
||||||
|
condition: Symbol,
|
||||||
|
region: Region,
|
||||||
|
lookups: &[Symbol],
|
||||||
|
) {
|
||||||
|
let func = env
|
||||||
|
.module
|
||||||
|
.get_function(bitcode::UTILS_EXPECT_FAILED_START)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let call_result = env
|
||||||
|
.builder
|
||||||
|
.build_call(func, &[], "call_expect_start_failed");
|
||||||
|
|
||||||
|
let original_ptr = call_result
|
||||||
|
.try_as_basic_value()
|
||||||
|
.left()
|
||||||
|
.unwrap()
|
||||||
|
.into_pointer_value();
|
||||||
|
|
||||||
|
let mut ptr = original_ptr;
|
||||||
|
|
||||||
|
{
|
||||||
|
let value = env
|
||||||
|
.context
|
||||||
|
.i32_type()
|
||||||
|
.const_int(region.start().offset as _, false);
|
||||||
|
|
||||||
|
let cast_ptr = env.builder.build_pointer_cast(
|
||||||
|
ptr,
|
||||||
|
value.get_type().ptr_type(AddressSpace::Generic),
|
||||||
|
"to_store_pointer",
|
||||||
|
);
|
||||||
|
|
||||||
|
env.builder.build_store(cast_ptr, value);
|
||||||
|
|
||||||
|
// let increment = layout.stack_size(env.target_info);
|
||||||
|
let increment = 4;
|
||||||
|
let increment = env.ptr_int().const_int(increment as _, false);
|
||||||
|
|
||||||
|
ptr = unsafe { env.builder.build_gep(ptr, &[increment], "increment_ptr") };
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
let value = env
|
||||||
|
.context
|
||||||
|
.i32_type()
|
||||||
|
.const_int(region.end().offset as _, false);
|
||||||
|
|
||||||
|
let cast_ptr = env.builder.build_pointer_cast(
|
||||||
|
ptr,
|
||||||
|
value.get_type().ptr_type(AddressSpace::Generic),
|
||||||
|
"to_store_pointer",
|
||||||
|
);
|
||||||
|
|
||||||
|
env.builder.build_store(cast_ptr, value);
|
||||||
|
|
||||||
|
// let increment = layout.stack_size(env.target_info);
|
||||||
|
let increment = 4;
|
||||||
|
let increment = env.ptr_int().const_int(increment as _, false);
|
||||||
|
|
||||||
|
ptr = unsafe { env.builder.build_gep(ptr, &[increment], "increment_ptr") };
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
let region_bytes: u32 = unsafe { std::mem::transmute(condition.module_id()) };
|
||||||
|
let value = env.context.i32_type().const_int(region_bytes as _, false);
|
||||||
|
|
||||||
|
let cast_ptr = env.builder.build_pointer_cast(
|
||||||
|
ptr,
|
||||||
|
value.get_type().ptr_type(AddressSpace::Generic),
|
||||||
|
"to_store_pointer",
|
||||||
|
);
|
||||||
|
|
||||||
|
env.builder.build_store(cast_ptr, value);
|
||||||
|
|
||||||
|
// let increment = layout.stack_size(env.target_info);
|
||||||
|
let increment = 4;
|
||||||
|
let increment = env.ptr_int().const_int(increment as _, false);
|
||||||
|
|
||||||
|
ptr = unsafe { env.builder.build_gep(ptr, &[increment], "increment_ptr") };
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut offset = env.ptr_int().const_int(12, false);
|
||||||
|
let mut ptr = original_ptr;
|
||||||
|
|
||||||
|
for lookup in lookups.iter() {
|
||||||
|
let (value, layout) = load_symbol_and_layout(scope, lookup);
|
||||||
|
|
||||||
|
offset = build_clone(
|
||||||
|
env,
|
||||||
|
layout_ids,
|
||||||
|
ptr,
|
||||||
|
offset,
|
||||||
|
value,
|
||||||
|
*layout,
|
||||||
|
WhenRecursive::Unreachable,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
enum WhenRecursive<'a> {
|
||||||
|
Unreachable,
|
||||||
|
Loop(UnionLayout<'a>),
|
||||||
|
}
|
||||||
|
|
||||||
|
fn build_clone<'a, 'ctx, 'env>(
|
||||||
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
|
_layout_ids: &mut LayoutIds<'a>,
|
||||||
|
ptr: PointerValue<'ctx>,
|
||||||
|
offset: IntValue<'ctx>,
|
||||||
|
value: BasicValueEnum<'ctx>,
|
||||||
|
layout: Layout<'a>,
|
||||||
|
when_recursive: WhenRecursive<'a>,
|
||||||
|
) -> IntValue<'ctx> {
|
||||||
|
match layout {
|
||||||
|
Layout::Builtin(builtin) => {
|
||||||
|
build_clone_builtin(env, ptr, offset, value, builtin, when_recursive)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Layout::Struct { field_layouts, .. } => build_struct_eq(
|
||||||
|
env,
|
||||||
|
layout_ids,
|
||||||
|
field_layouts,
|
||||||
|
when_recursive,
|
||||||
|
lhs_val.into_struct_value(),
|
||||||
|
rhs_val.into_struct_value(),
|
||||||
|
),
|
||||||
|
|
||||||
|
Layout::LambdaSet(_) => unreachable!("cannot compare closures"),
|
||||||
|
|
||||||
|
Layout::Union(union_layout) => build_tag_eq(
|
||||||
|
env,
|
||||||
|
layout_ids,
|
||||||
|
when_recursive,
|
||||||
|
union_layout,
|
||||||
|
lhs_val,
|
||||||
|
rhs_val,
|
||||||
|
),
|
||||||
|
|
||||||
|
Layout::Boxed(inner_layout) => build_box_eq(
|
||||||
|
env,
|
||||||
|
layout_ids,
|
||||||
|
when_recursive,
|
||||||
|
lhs_layout,
|
||||||
|
inner_layout,
|
||||||
|
lhs_val,
|
||||||
|
rhs_val,
|
||||||
|
),
|
||||||
|
|
||||||
|
Layout::RecursivePointer => match when_recursive {
|
||||||
|
WhenRecursive::Unreachable => {
|
||||||
|
unreachable!("recursion pointers should never be compared directly")
|
||||||
|
}
|
||||||
|
|
||||||
|
WhenRecursive::Loop(union_layout) => {
|
||||||
|
let layout = Layout::Union(union_layout);
|
||||||
|
|
||||||
|
let bt = basic_type_from_layout(env, &layout);
|
||||||
|
|
||||||
|
// cast the i64 pointer to a pointer to block of memory
|
||||||
|
let field1_cast = env
|
||||||
|
.builder
|
||||||
|
.build_bitcast(lhs_val, bt, "i64_to_opaque")
|
||||||
|
.into_pointer_value();
|
||||||
|
|
||||||
|
let field2_cast = env
|
||||||
|
.builder
|
||||||
|
.build_bitcast(rhs_val, bt, "i64_to_opaque")
|
||||||
|
.into_pointer_value();
|
||||||
|
|
||||||
|
build_tag_eq(
|
||||||
|
env,
|
||||||
|
layout_ids,
|
||||||
|
WhenRecursive::Loop(union_layout),
|
||||||
|
&union_layout,
|
||||||
|
field1_cast.into(),
|
||||||
|
field2_cast.into(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
*/
|
||||||
|
_ => todo!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn build_copy<'a, 'ctx, 'env>(
|
||||||
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
|
ptr: PointerValue<'ctx>,
|
||||||
|
offset: IntValue<'ctx>,
|
||||||
|
value: BasicValueEnum<'ctx>,
|
||||||
|
) -> IntValue<'ctx> {
|
||||||
|
let ptr = unsafe {
|
||||||
|
env.builder
|
||||||
|
.build_in_bounds_gep(ptr, &[offset], "at_current_offset")
|
||||||
|
};
|
||||||
|
|
||||||
|
let ptr_type = value.get_type().ptr_type(AddressSpace::Generic);
|
||||||
|
let ptr = env
|
||||||
|
.builder
|
||||||
|
.build_pointer_cast(ptr, ptr_type, "cast_ptr_type");
|
||||||
|
|
||||||
|
env.builder.build_store(ptr, value);
|
||||||
|
|
||||||
|
let width = value.get_type().size_of().unwrap();
|
||||||
|
env.builder.build_int_add(offset, width, "new_offset")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn build_clone_builtin<'a, 'ctx, 'env>(
|
||||||
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
|
ptr: PointerValue<'ctx>,
|
||||||
|
offset: IntValue<'ctx>,
|
||||||
|
value: BasicValueEnum<'ctx>,
|
||||||
|
builtin: Builtin<'a>,
|
||||||
|
when_recursive: WhenRecursive<'a>,
|
||||||
|
) -> IntValue<'ctx> {
|
||||||
|
use Builtin::*;
|
||||||
|
|
||||||
|
match builtin {
|
||||||
|
Int(_) | Float(_) | Bool | Decimal => build_copy(env, ptr, offset, value),
|
||||||
|
|
||||||
|
Builtin::Str => {
|
||||||
|
//
|
||||||
|
|
||||||
|
call_bitcode_fn(
|
||||||
|
env,
|
||||||
|
&[ptr.into(), offset.into(), value],
|
||||||
|
bitcode::STR_CLONE_TO,
|
||||||
|
)
|
||||||
|
.into_int_value()
|
||||||
|
}
|
||||||
|
Builtin::List(elem) => todo!(),
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,5 +4,6 @@ pub mod build_list;
|
||||||
pub mod build_str;
|
pub mod build_str;
|
||||||
pub mod compare;
|
pub mod compare;
|
||||||
pub mod convert;
|
pub mod convert;
|
||||||
|
mod expect;
|
||||||
pub mod externs;
|
pub mod externs;
|
||||||
pub mod refcounting;
|
pub mod refcounting;
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
use std::cell::RefCell;
|
||||||
|
|
||||||
use roc_module::symbol::Interns;
|
use roc_module::symbol::Interns;
|
||||||
use roc_mono::{
|
use roc_mono::{
|
||||||
ir::ProcLayout,
|
ir::ProcLayout,
|
||||||
|
@ -23,9 +25,13 @@ pub fn get_values<'a>(
|
||||||
variables: &[Variable],
|
variables: &[Variable],
|
||||||
) -> Result<Vec<Expr<'a>>, ToAstProblem> {
|
) -> Result<Vec<Expr<'a>>, ToAstProblem> {
|
||||||
let mut result = Vec::with_capacity(variables.len());
|
let mut result = Vec::with_capacity(variables.len());
|
||||||
let memory = ExpectMemory { start };
|
|
||||||
|
|
||||||
for variable in variables {
|
for variable in variables {
|
||||||
|
let memory = ExpectMemory {
|
||||||
|
start,
|
||||||
|
extra_offset: Default::default(),
|
||||||
|
};
|
||||||
|
|
||||||
let expr = {
|
let expr = {
|
||||||
let variable = *variable;
|
let variable = *variable;
|
||||||
|
|
||||||
|
@ -34,6 +40,8 @@ pub fn get_values<'a>(
|
||||||
start_offset,
|
start_offset,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let app = arena.alloc(app);
|
||||||
|
|
||||||
let content = subs.get_content_without_compacting(variable);
|
let content = subs.get_content_without_compacting(variable);
|
||||||
|
|
||||||
let mut layout_cache = LayoutCache::new(target_info);
|
let mut layout_cache = LayoutCache::new(target_info);
|
||||||
|
@ -45,19 +53,24 @@ pub fn get_values<'a>(
|
||||||
captures_niche: CapturesNiche::no_niche(),
|
captures_niche: CapturesNiche::no_niche(),
|
||||||
};
|
};
|
||||||
|
|
||||||
start_offset += layout.stack_size(target_info) as usize;
|
let element = jit_to_ast(
|
||||||
|
|
||||||
jit_to_ast(
|
|
||||||
arena,
|
arena,
|
||||||
arena.alloc(app),
|
app,
|
||||||
"expect_repl_main_fn",
|
"expect_repl_main_fn",
|
||||||
proc_layout,
|
proc_layout,
|
||||||
content,
|
content,
|
||||||
subs,
|
subs,
|
||||||
interns,
|
interns,
|
||||||
target_info,
|
target_info,
|
||||||
)
|
)?;
|
||||||
}?;
|
|
||||||
|
start_offset += layout.stack_size(target_info) as usize;
|
||||||
|
let mut extra_offset = app.memory.extra_offset.borrow_mut();
|
||||||
|
start_offset += *extra_offset;
|
||||||
|
*extra_offset = 0;
|
||||||
|
|
||||||
|
element
|
||||||
|
};
|
||||||
|
|
||||||
result.push(expr);
|
result.push(expr);
|
||||||
}
|
}
|
||||||
|
@ -65,9 +78,10 @@ pub fn get_values<'a>(
|
||||||
Ok(result)
|
Ok(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone)]
|
||||||
struct ExpectMemory {
|
struct ExpectMemory {
|
||||||
start: *const u8,
|
start: *const u8,
|
||||||
|
extra_offset: RefCell<usize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! deref_number {
|
macro_rules! deref_number {
|
||||||
|
@ -113,6 +127,9 @@ impl ReplAppMemory for ExpectMemory {
|
||||||
} else {
|
} else {
|
||||||
let offset = self.deref_usize(addr);
|
let offset = self.deref_usize(addr);
|
||||||
let length = self.deref_usize(addr + std::mem::size_of::<usize>());
|
let length = self.deref_usize(addr + std::mem::size_of::<usize>());
|
||||||
|
let capacity = self.deref_usize(addr + std::mem::size_of::<usize>());
|
||||||
|
|
||||||
|
*self.extra_offset.borrow_mut() += capacity;
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let ptr = self.start.add(offset);
|
let ptr = self.start.add(offset);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue