mirror of
https://github.com/roc-lang/roc.git
synced 2024-11-11 05:34:11 +03:00
Merge remote-tracking branch 'origin/trunk' into add_loop_examples
This commit is contained in:
commit
3ade77374a
21
Cargo.lock
generated
21
Cargo.lock
generated
@ -3254,6 +3254,7 @@ dependencies = [
|
||||
"roc_parse",
|
||||
"roc_problem",
|
||||
"roc_region",
|
||||
"roc_target",
|
||||
"roc_types",
|
||||
"roc_unify",
|
||||
"snafu",
|
||||
@ -3283,6 +3284,7 @@ dependencies = [
|
||||
"roc_reporting",
|
||||
"roc_solve",
|
||||
"roc_std",
|
||||
"roc_target",
|
||||
"roc_types",
|
||||
"roc_unify",
|
||||
"serde_json",
|
||||
@ -3297,6 +3299,7 @@ dependencies = [
|
||||
"roc_collections",
|
||||
"roc_module",
|
||||
"roc_region",
|
||||
"roc_target",
|
||||
"roc_types",
|
||||
]
|
||||
|
||||
@ -3350,6 +3353,7 @@ dependencies = [
|
||||
"roc_region",
|
||||
"roc_reporting",
|
||||
"roc_solve",
|
||||
"roc_target",
|
||||
"roc_test_utils",
|
||||
"roc_types",
|
||||
"roc_unify",
|
||||
@ -3416,6 +3420,7 @@ dependencies = [
|
||||
"roc_module",
|
||||
"roc_parse",
|
||||
"roc_region",
|
||||
"roc_target",
|
||||
"roc_types",
|
||||
"snafu",
|
||||
"tempfile",
|
||||
@ -3508,6 +3513,7 @@ dependencies = [
|
||||
"roc_region",
|
||||
"roc_solve",
|
||||
"roc_std",
|
||||
"roc_target",
|
||||
"roc_types",
|
||||
"roc_unify",
|
||||
"target-lexicon",
|
||||
@ -3526,6 +3532,7 @@ dependencies = [
|
||||
"roc_module",
|
||||
"roc_mono",
|
||||
"roc_std",
|
||||
"roc_target",
|
||||
"target-lexicon",
|
||||
]
|
||||
|
||||
@ -3540,6 +3547,7 @@ dependencies = [
|
||||
"roc_module",
|
||||
"roc_mono",
|
||||
"roc_std",
|
||||
"roc_target",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -3587,6 +3595,7 @@ dependencies = [
|
||||
"roc_region",
|
||||
"roc_reporting",
|
||||
"roc_solve",
|
||||
"roc_target",
|
||||
"roc_types",
|
||||
"roc_unify",
|
||||
"tempfile",
|
||||
@ -3621,6 +3630,7 @@ dependencies = [
|
||||
"roc_region",
|
||||
"roc_solve",
|
||||
"roc_std",
|
||||
"roc_target",
|
||||
"roc_types",
|
||||
"roc_unify",
|
||||
"static_assertions",
|
||||
@ -3680,6 +3690,7 @@ dependencies = [
|
||||
"roc_problem",
|
||||
"roc_region",
|
||||
"roc_solve",
|
||||
"roc_target",
|
||||
"roc_test_utils",
|
||||
"roc_types",
|
||||
"ven_pretty",
|
||||
@ -3702,6 +3713,7 @@ dependencies = [
|
||||
"roc_problem",
|
||||
"roc_region",
|
||||
"roc_solve",
|
||||
"roc_target",
|
||||
"roc_types",
|
||||
"roc_unify",
|
||||
"tempfile",
|
||||
@ -3717,6 +3729,13 @@ dependencies = [
|
||||
"quickcheck_macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "roc_target"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"target-lexicon",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "roc_test_utils"
|
||||
version = "0.1.0"
|
||||
@ -4263,6 +4282,7 @@ dependencies = [
|
||||
"roc_reporting",
|
||||
"roc_solve",
|
||||
"roc_std",
|
||||
"roc_target",
|
||||
"roc_types",
|
||||
"roc_unify",
|
||||
"target-lexicon",
|
||||
@ -4284,6 +4304,7 @@ dependencies = [
|
||||
"roc_load",
|
||||
"roc_module",
|
||||
"roc_mono",
|
||||
"roc_target",
|
||||
"test_mono_macros",
|
||||
]
|
||||
|
||||
|
@ -22,6 +22,7 @@ members = [
|
||||
"compiler/build",
|
||||
"compiler/arena_pool",
|
||||
"compiler/test_gen",
|
||||
"compiler/roc_target",
|
||||
"vendor/ena",
|
||||
"vendor/inkwell",
|
||||
"vendor/pathfinding",
|
||||
|
@ -17,6 +17,7 @@ roc_problem = { path = "../compiler/problem" }
|
||||
roc_types = { path = "../compiler/types" }
|
||||
roc_unify = { path = "../compiler/unify"}
|
||||
roc_load = { path = "../compiler/load" }
|
||||
roc_target = { path = "../compiler/roc_target" }
|
||||
roc_error_macros = { path = "../error_macros" }
|
||||
arrayvec = "0.7.2"
|
||||
bumpalo = { version = "3.8.0", features = ["collections"] }
|
||||
|
@ -3,6 +3,7 @@ use std::path::Path;
|
||||
use bumpalo::Bump;
|
||||
use roc_collections::all::MutMap;
|
||||
use roc_load::file::LoadedModule;
|
||||
use roc_target::TargetInfo;
|
||||
|
||||
pub fn load_module(src_file: &Path) -> LoadedModule {
|
||||
let subs_by_module = MutMap::default();
|
||||
@ -19,7 +20,7 @@ pub fn load_module(src_file: &Path) -> LoadedModule {
|
||||
)
|
||||
}),
|
||||
subs_by_module,
|
||||
8,
|
||||
TargetInfo::default_x86_64(),
|
||||
roc_can::builtins::builtin_defs_map,
|
||||
);
|
||||
|
||||
|
@ -61,6 +61,7 @@ roc_load = { path = "../compiler/load" }
|
||||
roc_gen_llvm = { path = "../compiler/gen_llvm", optional = true }
|
||||
roc_build = { path = "../compiler/build", default-features = false }
|
||||
roc_fmt = { path = "../compiler/fmt" }
|
||||
roc_target = { path = "../compiler/roc_target" }
|
||||
roc_reporting = { path = "../reporting" }
|
||||
roc_error_macros = { path = "../error_macros" }
|
||||
roc_editor = { path = "../editor", optional = true }
|
||||
|
@ -8,6 +8,7 @@ use roc_can::builtins::builtin_defs_map;
|
||||
use roc_collections::all::MutMap;
|
||||
use roc_load::file::LoadingProblem;
|
||||
use roc_mono::ir::OptLevel;
|
||||
use roc_target::TargetInfo;
|
||||
use std::path::PathBuf;
|
||||
use std::time::{Duration, SystemTime};
|
||||
use target_lexicon::Triple;
|
||||
@ -58,7 +59,7 @@ pub fn build_file<'a>(
|
||||
target_valgrind: bool,
|
||||
) -> Result<BuiltFile, LoadingProblem<'a>> {
|
||||
let compilation_start = SystemTime::now();
|
||||
let ptr_bytes = target.pointer_width().unwrap().bytes() as u32;
|
||||
let target_info = TargetInfo::from(target);
|
||||
|
||||
// Step 1: compile the app and generate the .o file
|
||||
let subs_by_module = MutMap::default();
|
||||
@ -72,7 +73,7 @@ pub fn build_file<'a>(
|
||||
stdlib,
|
||||
src_dir.as_path(),
|
||||
subs_by_module,
|
||||
ptr_bytes,
|
||||
target_info,
|
||||
builtin_defs_map,
|
||||
)?;
|
||||
|
||||
@ -356,7 +357,7 @@ pub fn check_file(
|
||||
|
||||
// only used for generating errors. We don't do code generation, so hardcoding should be fine
|
||||
// we need monomorphization for when exhaustiveness checking
|
||||
let ptr_bytes = 8;
|
||||
let target_info = TargetInfo::default_x86_64();
|
||||
|
||||
// Step 1: compile the app and generate the .o file
|
||||
let subs_by_module = MutMap::default();
|
||||
@ -370,7 +371,7 @@ pub fn check_file(
|
||||
stdlib,
|
||||
src_dir.as_path(),
|
||||
subs_by_module,
|
||||
ptr_bytes,
|
||||
target_info,
|
||||
builtin_defs_map,
|
||||
)?;
|
||||
|
||||
|
@ -14,13 +14,14 @@ use roc_mono::layout::{
|
||||
};
|
||||
use roc_parse::ast::{AssignedField, Collection, Expr, StrLiteral};
|
||||
use roc_region::all::{Loc, Region};
|
||||
use roc_target::TargetInfo;
|
||||
use roc_types::subs::{Content, FlatType, GetSubsSlice, RecordFields, Subs, UnionTags, Variable};
|
||||
use std::cmp::{max_by_key, min_by_key};
|
||||
|
||||
struct Env<'a, 'env> {
|
||||
arena: &'a Bump,
|
||||
subs: &'env Subs,
|
||||
ptr_bytes: u32,
|
||||
target_info: TargetInfo,
|
||||
interns: &'env Interns,
|
||||
home: ModuleId,
|
||||
}
|
||||
@ -47,12 +48,12 @@ pub unsafe fn jit_to_ast<'a>(
|
||||
interns: &'a Interns,
|
||||
home: ModuleId,
|
||||
subs: &'a Subs,
|
||||
ptr_bytes: u32,
|
||||
target_info: TargetInfo,
|
||||
) -> Result<Expr<'a>, ToAstProblem> {
|
||||
let env = Env {
|
||||
arena,
|
||||
subs,
|
||||
ptr_bytes,
|
||||
target_info,
|
||||
interns,
|
||||
home,
|
||||
};
|
||||
@ -172,7 +173,7 @@ fn get_tags_vars_and_variant<'a>(
|
||||
let vars_of_tag: MutMap<_, _> = tags_vec.iter().cloned().collect();
|
||||
|
||||
let union_variant =
|
||||
union_sorted_tags_help(env.arena, tags_vec, opt_rec_var, env.subs, env.ptr_bytes);
|
||||
union_sorted_tags_help(env.arena, tags_vec, opt_rec_var, env.subs, env.target_info);
|
||||
|
||||
(vars_of_tag, union_variant)
|
||||
}
|
||||
@ -200,8 +201,12 @@ fn expr_of_tag<'a>(
|
||||
|
||||
/// Gets the tag ID of a union variant, assuming that the tag ID is stored alongside (after) the
|
||||
/// tag data. The caller is expected to check that the tag ID is indeed stored this way.
|
||||
fn tag_id_from_data(union_layout: UnionLayout, data_ptr: *const u8, ptr_bytes: u32) -> i64 {
|
||||
let offset = union_layout.data_size_without_tag_id(ptr_bytes).unwrap();
|
||||
fn tag_id_from_data(
|
||||
union_layout: UnionLayout,
|
||||
data_ptr: *const u8,
|
||||
target_info: TargetInfo,
|
||||
) -> i64 {
|
||||
let offset = union_layout.data_size_without_tag_id(target_info).unwrap();
|
||||
|
||||
unsafe {
|
||||
match union_layout.tag_id_builtin() {
|
||||
@ -218,13 +223,12 @@ fn tag_id_from_data(union_layout: UnionLayout, data_ptr: *const u8, ptr_bytes: u
|
||||
}
|
||||
}
|
||||
|
||||
fn deref_ptr_of_ptr(ptr_of_ptr: *const u8, ptr_bytes: u32) -> *const u8 {
|
||||
fn deref_ptr_of_ptr(ptr_of_ptr: *const u8, target_info: TargetInfo) -> *const u8 {
|
||||
unsafe {
|
||||
match ptr_bytes {
|
||||
match target_info.ptr_width() {
|
||||
// Our LLVM codegen represents pointers as i32/i64s.
|
||||
4 => *(ptr_of_ptr as *const i32) as *const u8,
|
||||
8 => *(ptr_of_ptr as *const i64) as *const u8,
|
||||
_ => unreachable!(),
|
||||
roc_target::PtrWidth::Bytes4 => *(ptr_of_ptr as *const i32) as *const u8,
|
||||
roc_target::PtrWidth::Bytes8 => *(ptr_of_ptr as *const i64) as *const u8,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -236,20 +240,20 @@ fn deref_ptr_of_ptr(ptr_of_ptr: *const u8, ptr_bytes: u32) -> *const u8 {
|
||||
fn tag_id_from_recursive_ptr(
|
||||
union_layout: UnionLayout,
|
||||
rec_ptr: *const u8,
|
||||
ptr_bytes: u32,
|
||||
target_info: TargetInfo,
|
||||
) -> (i64, *const u8) {
|
||||
let tag_in_ptr = union_layout.stores_tag_id_in_pointer(ptr_bytes);
|
||||
let tag_in_ptr = union_layout.stores_tag_id_in_pointer(target_info);
|
||||
if tag_in_ptr {
|
||||
let masked_ptr_to_data = deref_ptr_of_ptr(rec_ptr, ptr_bytes) as i64;
|
||||
let (tag_id_bits, tag_id_mask) = tag_pointer_tag_id_bits_and_mask(ptr_bytes);
|
||||
let masked_ptr_to_data = deref_ptr_of_ptr(rec_ptr, target_info) as i64;
|
||||
let (tag_id_bits, tag_id_mask) = tag_pointer_tag_id_bits_and_mask(target_info);
|
||||
let tag_id = masked_ptr_to_data & (tag_id_mask as i64);
|
||||
|
||||
// Clear the tag ID data from the pointer
|
||||
let ptr_to_data = ((masked_ptr_to_data >> tag_id_bits) << tag_id_bits) as *const u8;
|
||||
(tag_id as i64, ptr_to_data)
|
||||
} else {
|
||||
let ptr_to_data = deref_ptr_of_ptr(rec_ptr, ptr_bytes);
|
||||
let tag_id = tag_id_from_data(union_layout, ptr_to_data, ptr_bytes);
|
||||
let ptr_to_data = deref_ptr_of_ptr(rec_ptr, target_info);
|
||||
let tag_id = tag_id_from_data(union_layout, ptr_to_data, target_info);
|
||||
(tag_id, ptr_to_data)
|
||||
}
|
||||
}
|
||||
@ -388,7 +392,7 @@ fn jit_to_ast_help<'a>(
|
||||
let fields = [Layout::u64(), *layout];
|
||||
let layout = Layout::Struct(&fields);
|
||||
|
||||
let result_stack_size = layout.stack_size(env.ptr_bytes);
|
||||
let result_stack_size = layout.stack_size(env.target_info);
|
||||
|
||||
run_jit_function_dynamic_type!(
|
||||
lib,
|
||||
@ -398,7 +402,7 @@ fn jit_to_ast_help<'a>(
|
||||
)
|
||||
}
|
||||
Layout::Union(UnionLayout::NonRecursive(_)) => {
|
||||
let size = layout.stack_size(env.ptr_bytes);
|
||||
let size = layout.stack_size(env.target_info);
|
||||
Ok(run_jit_function_dynamic_type!(
|
||||
lib,
|
||||
main_fn_name,
|
||||
@ -412,7 +416,7 @@ fn jit_to_ast_help<'a>(
|
||||
| Layout::Union(UnionLayout::NonNullableUnwrapped(_))
|
||||
| Layout::Union(UnionLayout::NullableUnwrapped { .. })
|
||||
| Layout::Union(UnionLayout::NullableWrapped { .. }) => {
|
||||
let size = layout.stack_size(env.ptr_bytes);
|
||||
let size = layout.stack_size(env.target_info);
|
||||
Ok(run_jit_function_dynamic_type!(
|
||||
lib,
|
||||
main_fn_name,
|
||||
@ -506,7 +510,7 @@ fn ptr_to_ast<'a>(
|
||||
}
|
||||
(_, Layout::Builtin(Builtin::List(elem_layout))) => {
|
||||
// Turn the (ptr, len) wrapper struct into actual ptr and len values.
|
||||
let len = unsafe { *(ptr.offset(env.ptr_bytes as isize) as *const usize) };
|
||||
let len = unsafe { *(ptr.offset(env.target_info.ptr_width() as isize) as *const usize) };
|
||||
let ptr = unsafe { *(ptr as *const *const u8) };
|
||||
|
||||
list_to_ast(env, ptr, len, elem_layout, content)
|
||||
@ -573,7 +577,7 @@ fn ptr_to_ast<'a>(
|
||||
|
||||
// Because this is a `NonRecursive`, the tag ID is definitely after the data.
|
||||
let tag_id =
|
||||
tag_id_from_data(union_layout, ptr, env.ptr_bytes);
|
||||
tag_id_from_data(union_layout, ptr, env.target_info);
|
||||
|
||||
// use the tag ID as an index, to get its name and layout of any arguments
|
||||
let (tag_name, arg_layouts) =
|
||||
@ -605,7 +609,7 @@ fn ptr_to_ast<'a>(
|
||||
_ => unreachable!("any other variant would have a different layout"),
|
||||
};
|
||||
|
||||
let (tag_id, ptr_to_data) = tag_id_from_recursive_ptr(*union_layout, ptr, env.ptr_bytes);
|
||||
let (tag_id, ptr_to_data) = tag_id_from_recursive_ptr(*union_layout, ptr, env.target_info);
|
||||
|
||||
let (tag_name, arg_layouts) = &tags_and_layouts[tag_id as usize];
|
||||
expr_of_tag(
|
||||
@ -633,7 +637,7 @@ fn ptr_to_ast<'a>(
|
||||
_ => unreachable!("any other variant would have a different layout"),
|
||||
};
|
||||
|
||||
let ptr_to_data = deref_ptr_of_ptr(ptr, env.ptr_bytes);
|
||||
let ptr_to_data = deref_ptr_of_ptr(ptr, env.target_info);
|
||||
|
||||
expr_of_tag(
|
||||
env,
|
||||
@ -663,7 +667,7 @@ fn ptr_to_ast<'a>(
|
||||
_ => unreachable!("any other variant would have a different layout"),
|
||||
};
|
||||
|
||||
let ptr_to_data = deref_ptr_of_ptr(ptr, env.ptr_bytes);
|
||||
let ptr_to_data = deref_ptr_of_ptr(ptr, env.target_info);
|
||||
if ptr_to_data.is_null() {
|
||||
tag_name_to_expr(env, &nullable_name)
|
||||
} else {
|
||||
@ -694,11 +698,11 @@ fn ptr_to_ast<'a>(
|
||||
_ => unreachable!("any other variant would have a different layout"),
|
||||
};
|
||||
|
||||
let ptr_to_data = deref_ptr_of_ptr(ptr, env.ptr_bytes);
|
||||
let ptr_to_data = deref_ptr_of_ptr(ptr, env.target_info);
|
||||
if ptr_to_data.is_null() {
|
||||
tag_name_to_expr(env, &nullable_name)
|
||||
} else {
|
||||
let (tag_id, ptr_to_data) = tag_id_from_recursive_ptr(*union_layout, ptr, env.ptr_bytes);
|
||||
let (tag_id, ptr_to_data) = tag_id_from_recursive_ptr(*union_layout, ptr, env.target_info);
|
||||
|
||||
let tag_id = if tag_id > nullable_id.into() { tag_id - 1 } else { tag_id };
|
||||
|
||||
@ -749,7 +753,7 @@ fn list_to_ast<'a>(
|
||||
|
||||
let arena = env.arena;
|
||||
let mut output = Vec::with_capacity_in(len, arena);
|
||||
let elem_size = elem_layout.stack_size(env.ptr_bytes) as usize;
|
||||
let elem_size = elem_layout.stack_size(env.target_info) as usize;
|
||||
|
||||
for index in 0..len {
|
||||
let offset_bytes = index * elem_size;
|
||||
@ -823,7 +827,7 @@ where
|
||||
output.push(&*arena.alloc(loc_expr));
|
||||
|
||||
// Advance the field pointer to the next field.
|
||||
field_ptr = unsafe { field_ptr.offset(layout.stack_size(env.ptr_bytes) as isize) };
|
||||
field_ptr = unsafe { field_ptr.offset(layout.stack_size(env.target_info) as isize) };
|
||||
}
|
||||
|
||||
output
|
||||
@ -908,7 +912,7 @@ fn struct_to_ast<'a>(
|
||||
|
||||
// Advance the field pointer to the next field.
|
||||
field_ptr =
|
||||
unsafe { field_ptr.offset(field_layout.stack_size(env.ptr_bytes) as isize) };
|
||||
unsafe { field_ptr.offset(field_layout.stack_size(env.target_info) as isize) };
|
||||
}
|
||||
|
||||
let output = output.into_bump_slice();
|
||||
@ -1083,8 +1087,13 @@ fn byte_to_ast<'a>(env: &Env<'a, '_>, value: u8, content: &Content) -> Expr<'a>
|
||||
.map(|(a, b)| (a.clone(), b.to_vec()))
|
||||
.collect();
|
||||
|
||||
let union_variant =
|
||||
union_sorted_tags_help(env.arena, tags_vec, None, env.subs, env.ptr_bytes);
|
||||
let union_variant = union_sorted_tags_help(
|
||||
env.arena,
|
||||
tags_vec,
|
||||
None,
|
||||
env.subs,
|
||||
env.target_info,
|
||||
);
|
||||
|
||||
match union_variant {
|
||||
UnionVariant::ByteUnion(tagnames) => {
|
||||
|
@ -13,6 +13,7 @@ use roc_load::file::LoadingProblem;
|
||||
use roc_mono::ir::OptLevel;
|
||||
use roc_parse::parser::SyntaxError;
|
||||
use roc_region::all::LineInfo;
|
||||
use roc_target::TargetInfo;
|
||||
use roc_types::pretty_print::{content_to_string, name_all_type_vars};
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::str::from_utf8_unchecked;
|
||||
@ -43,7 +44,7 @@ pub fn gen_and_eval<'a>(
|
||||
|
||||
let module_src = promote_expr_to_module(src_str);
|
||||
|
||||
let ptr_bytes = target.pointer_width().unwrap().bytes() as u32;
|
||||
let target_info = TargetInfo::from(&target);
|
||||
|
||||
let exposed_types = MutMap::default();
|
||||
let loaded = roc_load::file::load_and_monomorphize_from_str(
|
||||
@ -53,7 +54,7 @@ pub fn gen_and_eval<'a>(
|
||||
&stdlib,
|
||||
src_dir,
|
||||
exposed_types,
|
||||
ptr_bytes,
|
||||
target_info,
|
||||
builtin_defs_map,
|
||||
);
|
||||
|
||||
@ -133,7 +134,6 @@ pub fn gen_and_eval<'a>(
|
||||
} else {
|
||||
let context = Context::create();
|
||||
let builder = context.create_builder();
|
||||
let ptr_bytes = target.pointer_width().unwrap().bytes() as u32;
|
||||
let module = arena.alloc(roc_gen_llvm::llvm::build::module_from_builtins(
|
||||
&target, &context, "",
|
||||
));
|
||||
@ -181,7 +181,7 @@ pub fn gen_and_eval<'a>(
|
||||
context: &context,
|
||||
interns,
|
||||
module,
|
||||
ptr_bytes,
|
||||
target_info,
|
||||
is_gen_test: true, // so roc_panic is generated
|
||||
// important! we don't want any procedures to get the C calling convention
|
||||
exposed_to_host: MutSet::default(),
|
||||
@ -237,7 +237,7 @@ pub fn gen_and_eval<'a>(
|
||||
&env.interns,
|
||||
home,
|
||||
&subs,
|
||||
ptr_bytes,
|
||||
target_info,
|
||||
)
|
||||
};
|
||||
let mut expr = roc_fmt::Buf::new_in(&arena);
|
||||
|
@ -421,9 +421,11 @@ mod cli_run {
|
||||
|
||||
macro_rules! benchmarks {
|
||||
($($test_name:ident => $benchmark:expr,)+) => {
|
||||
|
||||
$(
|
||||
#[test]
|
||||
#[cfg_attr(not(debug_assertions), serial(benchmark))]
|
||||
#[cfg(all(not(feature = "wasm32-cli-run"), not(feature = "i386-cli-run")))]
|
||||
fn $test_name() {
|
||||
let benchmark = $benchmark;
|
||||
let file_name = examples_dir("benchmarks").join(benchmark.filename);
|
||||
|
@ -19,6 +19,7 @@ roc_unify = { path = "../unify" }
|
||||
roc_solve = { path = "../solve" }
|
||||
roc_mono = { path = "../mono" }
|
||||
roc_load = { path = "../load" }
|
||||
roc_target = { path = "../roc_target" }
|
||||
roc_gen_llvm = { path = "../gen_llvm", optional = true }
|
||||
roc_gen_wasm = { path = "../gen_wasm", optional = true }
|
||||
roc_gen_dev = { path = "../gen_dev", default-features = false }
|
||||
|
@ -235,7 +235,7 @@ pub fn gen_from_mono_module_llvm(
|
||||
let code_gen_start = SystemTime::now();
|
||||
|
||||
// Generate the binary
|
||||
let ptr_bytes = target.pointer_width().unwrap().bytes() as u32;
|
||||
let target_info = roc_target::TargetInfo::from(target);
|
||||
let context = Context::create();
|
||||
let module = arena.alloc(module_from_builtins(target, &context, "app"));
|
||||
|
||||
@ -286,7 +286,7 @@ pub fn gen_from_mono_module_llvm(
|
||||
context: &context,
|
||||
interns: loaded.interns,
|
||||
module,
|
||||
ptr_bytes,
|
||||
target_info,
|
||||
// in gen_tests, the compiler provides roc_panic
|
||||
// and sets up the setjump/longjump exception handling
|
||||
is_gen_test: false,
|
||||
|
@ -10,3 +10,4 @@ roc_collections = { path = "../collections" }
|
||||
roc_region = { path = "../region" }
|
||||
roc_module = { path = "../module" }
|
||||
roc_types = { path = "../types" }
|
||||
roc_target = { path = "../roc_target" }
|
||||
|
@ -1,4 +1,5 @@
|
||||
use roc_module::symbol::Symbol;
|
||||
use roc_target::TargetInfo;
|
||||
use std::ops::Index;
|
||||
|
||||
pub const BUILTINS_HOST_OBJ_PATH: &str = env!(
|
||||
@ -46,14 +47,21 @@ impl FloatWidth {
|
||||
}
|
||||
}
|
||||
|
||||
pub const fn alignment_bytes(&self) -> u32 {
|
||||
pub const fn alignment_bytes(&self, target_info: TargetInfo) -> u32 {
|
||||
use roc_target::Architecture;
|
||||
use std::mem::align_of;
|
||||
use FloatWidth::*;
|
||||
|
||||
// TODO actually alignment is architecture-specific
|
||||
match self {
|
||||
F32 => align_of::<f32>() as u32,
|
||||
F64 => align_of::<f64>() as u32,
|
||||
F64 => match target_info.architecture {
|
||||
Architecture::X86_64
|
||||
| Architecture::Aarch64
|
||||
| Architecture::Arm
|
||||
| Architecture::Wasm32 => 8,
|
||||
Architecture::X86_32 => 4,
|
||||
},
|
||||
F128 => align_of::<i128>() as u32,
|
||||
}
|
||||
}
|
||||
@ -106,16 +114,22 @@ impl IntWidth {
|
||||
}
|
||||
}
|
||||
|
||||
pub const fn alignment_bytes(&self) -> u32 {
|
||||
pub const fn alignment_bytes(&self, target_info: TargetInfo) -> u32 {
|
||||
use roc_target::Architecture;
|
||||
use std::mem::align_of;
|
||||
use IntWidth::*;
|
||||
|
||||
// TODO actually alignment is architecture-specific
|
||||
match self {
|
||||
U8 | I8 => align_of::<i8>() as u32,
|
||||
U16 | I16 => align_of::<i16>() as u32,
|
||||
U32 | I32 => align_of::<i32>() as u32,
|
||||
U64 | I64 => align_of::<i64>() as u32,
|
||||
U64 | I64 => match target_info.architecture {
|
||||
Architecture::X86_64
|
||||
| Architecture::Aarch64
|
||||
| Architecture::Arm
|
||||
| Architecture::Wasm32 => 8,
|
||||
Architecture::X86_32 => 4,
|
||||
},
|
||||
U128 | I128 => align_of::<i128>() as u32,
|
||||
}
|
||||
}
|
||||
|
@ -124,7 +124,11 @@ where
|
||||
// This is a type alias
|
||||
|
||||
// the symbol should already be added to the scope when this module is canonicalized
|
||||
debug_assert!(scope.contains_alias(symbol));
|
||||
debug_assert!(
|
||||
scope.contains_alias(symbol),
|
||||
"apparently, {:?} is not actually a type alias",
|
||||
symbol
|
||||
);
|
||||
|
||||
// but now we know this symbol by a different identifier, so we still need to add it to
|
||||
// the scope
|
||||
|
@ -16,6 +16,7 @@ roc_builtins = { path = "../builtins" }
|
||||
roc_unify = { path = "../unify" }
|
||||
roc_solve = { path = "../solve" }
|
||||
roc_mono = { path = "../mono" }
|
||||
roc_target = { path = "../roc_target" }
|
||||
roc_error_macros = { path = "../../error_macros" }
|
||||
bumpalo = { version = "3.8.0", features = ["collections"] }
|
||||
target-lexicon = "0.12.2"
|
||||
|
@ -7,12 +7,13 @@ use roc_module::symbol::{Interns, Symbol};
|
||||
use roc_mono::code_gen_help::CodeGenHelp;
|
||||
use roc_mono::ir::{BranchInfo, JoinPointId, Literal, Param, ProcLayout, SelfRecursive, Stmt};
|
||||
use roc_mono::layout::{Builtin, Layout};
|
||||
use roc_target::TargetInfo;
|
||||
use std::marker::PhantomData;
|
||||
|
||||
pub mod aarch64;
|
||||
pub mod x86_64;
|
||||
|
||||
const PTR_SIZE: u32 = 8;
|
||||
const TARGET_INFO: TargetInfo = TargetInfo::default_x86_64();
|
||||
|
||||
pub trait CallConv<GeneralReg: RegTrait, FloatReg: RegTrait> {
|
||||
const BASE_PTR_REG: GeneralReg;
|
||||
@ -308,7 +309,7 @@ pub fn new_backend_64bit<
|
||||
phantom_cc: PhantomData,
|
||||
env,
|
||||
interns,
|
||||
helper_proc_gen: CodeGenHelp::new(env.arena, IntWidth::I64, env.module_id),
|
||||
helper_proc_gen: CodeGenHelp::new(env.arena, TARGET_INFO, env.module_id),
|
||||
helper_proc_symbols: bumpalo::vec![in env.arena],
|
||||
proc_name: None,
|
||||
is_self_recursive: None,
|
||||
@ -974,7 +975,7 @@ impl<
|
||||
}
|
||||
|
||||
fn create_struct(&mut self, sym: &Symbol, layout: &Layout<'a>, fields: &'a [Symbol]) {
|
||||
let struct_size = layout.stack_size(PTR_SIZE);
|
||||
let struct_size = layout.stack_size(TARGET_INFO);
|
||||
|
||||
if let Layout::Struct(field_layouts) = layout {
|
||||
if struct_size > 0 {
|
||||
@ -991,7 +992,7 @@ impl<
|
||||
let mut current_offset = offset;
|
||||
for (field, field_layout) in fields.iter().zip(field_layouts.iter()) {
|
||||
self.copy_symbol_to_stack_offset(current_offset, field, field_layout);
|
||||
let field_size = field_layout.stack_size(PTR_SIZE);
|
||||
let field_size = field_layout.stack_size(TARGET_INFO);
|
||||
current_offset += field_size as i32;
|
||||
}
|
||||
} else {
|
||||
@ -1029,14 +1030,14 @@ impl<
|
||||
if let Some(SymbolStorage::Base { offset, .. }) = self.symbol_storage_map.get(structure) {
|
||||
let mut data_offset = *offset;
|
||||
for i in 0..index {
|
||||
let field_size = field_layouts[i as usize].stack_size(PTR_SIZE);
|
||||
let field_size = field_layouts[i as usize].stack_size(TARGET_INFO);
|
||||
data_offset += field_size as i32;
|
||||
}
|
||||
self.symbol_storage_map.insert(
|
||||
*sym,
|
||||
SymbolStorage::Base {
|
||||
offset: data_offset,
|
||||
size: field_layouts[index as usize].stack_size(PTR_SIZE),
|
||||
size: field_layouts[index as usize].stack_size(TARGET_INFO),
|
||||
owned: false,
|
||||
},
|
||||
);
|
||||
@ -1569,10 +1570,10 @@ impl<
|
||||
{
|
||||
debug_assert_eq!(
|
||||
*size,
|
||||
layout.stack_size(PTR_SIZE),
|
||||
layout.stack_size(TARGET_INFO),
|
||||
"expected struct to have same size as data being stored in it"
|
||||
);
|
||||
for i in 0..layout.stack_size(PTR_SIZE) as i32 {
|
||||
for i in 0..layout.stack_size(TARGET_INFO) as i32 {
|
||||
ASM::mov_reg64_base32(&mut self.buf, tmp_reg, from_offset + i);
|
||||
ASM::mov_base32_reg64(&mut self.buf, to_offset + i, tmp_reg);
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
use crate::generic64::{Assembler, CallConv, RegTrait, SymbolStorage, PTR_SIZE};
|
||||
use crate::generic64::{Assembler, CallConv, RegTrait, SymbolStorage, TARGET_INFO};
|
||||
use crate::{
|
||||
single_register_builtins, single_register_floats, single_register_integers, Relocation,
|
||||
};
|
||||
@ -451,7 +451,7 @@ impl CallConv<X86_64GeneralReg, X86_64FloatReg> for X86_64SystemV {
|
||||
fn returns_via_arg_pointer(ret_layout: &Layout) -> bool {
|
||||
// TODO: This may need to be more complex/extended to fully support the calling convention.
|
||||
// details here: https://github.com/hjl-tools/x86-psABI/wiki/x86-64-psABI-1.0.pdf
|
||||
ret_layout.stack_size(PTR_SIZE) > 16
|
||||
ret_layout.stack_size(TARGET_INFO) > 16
|
||||
}
|
||||
}
|
||||
|
||||
@ -775,7 +775,7 @@ impl CallConv<X86_64GeneralReg, X86_64FloatReg> for X86_64WindowsFastcall {
|
||||
fn returns_via_arg_pointer(ret_layout: &Layout) -> bool {
|
||||
// TODO: This is not fully correct there are some exceptions for "vector" types.
|
||||
// details here: https://docs.microsoft.com/en-us/cpp/build/x64-calling-convention?view=msvc-160#return-values
|
||||
ret_layout.stack_size(PTR_SIZE) > 8
|
||||
ret_layout.stack_size(TARGET_INFO) > 8
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -12,6 +12,7 @@ roc_module = { path = "../module" }
|
||||
roc_builtins = { path = "../builtins" }
|
||||
roc_error_macros = { path = "../../error_macros" }
|
||||
roc_mono = { path = "../mono" }
|
||||
roc_target = { path = "../roc_target" }
|
||||
roc_std = { path = "../../roc_std" }
|
||||
morphic_lib = { path = "../../vendor/morphic_lib" }
|
||||
bumpalo = { version = "3.8.0", features = ["collections"] }
|
||||
|
@ -63,6 +63,7 @@ use roc_mono::ir::{
|
||||
ModifyRc, OptLevel, ProcLayout,
|
||||
};
|
||||
use roc_mono::layout::{Builtin, LambdaSet, Layout, LayoutIds, TagIdIntType, UnionLayout};
|
||||
use roc_target::TargetInfo;
|
||||
use target_lexicon::{Architecture, OperatingSystem, Triple};
|
||||
|
||||
/// This is for Inkwell's FunctionValue::verify - we want to know the verification
|
||||
@ -166,7 +167,7 @@ pub struct Env<'a, 'ctx, 'env> {
|
||||
pub compile_unit: &'env DICompileUnit<'ctx>,
|
||||
pub module: &'ctx Module<'ctx>,
|
||||
pub interns: Interns,
|
||||
pub ptr_bytes: u32,
|
||||
pub target_info: TargetInfo,
|
||||
pub is_gen_test: bool,
|
||||
pub exposed_to_host: MutSet<Symbol>,
|
||||
}
|
||||
@ -195,15 +196,9 @@ impl<'a, 'ctx, 'env> Env<'a, 'ctx, 'env> {
|
||||
pub fn ptr_int(&self) -> IntType<'ctx> {
|
||||
let ctx = self.context;
|
||||
|
||||
match self.ptr_bytes {
|
||||
1 => ctx.i8_type(),
|
||||
2 => ctx.i16_type(),
|
||||
4 => ctx.i32_type(),
|
||||
8 => ctx.i64_type(),
|
||||
_ => panic!(
|
||||
"Invalid target: Roc does't support compiling to {}-bit systems.",
|
||||
self.ptr_bytes * 8
|
||||
),
|
||||
match self.target_info.ptr_width() {
|
||||
roc_target::PtrWidth::Bytes4 => ctx.i32_type(),
|
||||
roc_target::PtrWidth::Bytes8 => ctx.i64_type(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -212,11 +207,11 @@ impl<'a, 'ctx, 'env> Env<'a, 'ctx, 'env> {
|
||||
/// on 64-bit systems, this is i128
|
||||
/// on 32-bit systems, this is i64
|
||||
pub fn str_list_c_abi(&self) -> IntType<'ctx> {
|
||||
crate::llvm::convert::str_list_int(self.context, self.ptr_bytes)
|
||||
crate::llvm::convert::str_list_int(self.context, self.target_info)
|
||||
}
|
||||
|
||||
pub fn small_str_bytes(&self) -> u32 {
|
||||
self.ptr_bytes * 2
|
||||
self.target_info.ptr_width() as u32 * 2
|
||||
}
|
||||
|
||||
pub fn build_intrinsic_call(
|
||||
@ -269,7 +264,7 @@ impl<'a, 'ctx, 'env> Env<'a, 'ctx, 'env> {
|
||||
}
|
||||
|
||||
pub fn alignment_intvalue(&self, element_layout: &Layout<'a>) -> BasicValueEnum<'ctx> {
|
||||
let alignment = element_layout.alignment_bytes(self.ptr_bytes);
|
||||
let alignment = element_layout.alignment_bytes(self.target_info);
|
||||
let alignment_iv = self.alignment_const(alignment);
|
||||
|
||||
alignment_iv.into()
|
||||
@ -317,12 +312,9 @@ impl<'a, 'ctx, 'env> Env<'a, 'ctx, 'env> {
|
||||
) -> CallSiteValue<'ctx> {
|
||||
let false_val = self.context.bool_type().const_int(0, false);
|
||||
|
||||
let intrinsic_name = match self.ptr_bytes {
|
||||
8 => LLVM_MEMSET_I64,
|
||||
4 => LLVM_MEMSET_I32,
|
||||
other => {
|
||||
unreachable!("Unsupported number of ptr_bytes {:?}", other);
|
||||
}
|
||||
let intrinsic_name = match self.target_info.ptr_width() {
|
||||
roc_target::PtrWidth::Bytes8 => LLVM_MEMSET_I64,
|
||||
roc_target::PtrWidth::Bytes4 => LLVM_MEMSET_I32,
|
||||
};
|
||||
|
||||
self.build_intrinsic_call(
|
||||
@ -1438,7 +1430,7 @@ fn build_wrapped_tag<'a, 'ctx, 'env>(
|
||||
let raw_data_ptr = allocate_tag(env, parent, reuse_allocation, union_layout, tags);
|
||||
let struct_type = env.context.struct_type(&field_types, false);
|
||||
|
||||
if union_layout.stores_tag_id_as_data(env.ptr_bytes) {
|
||||
if union_layout.stores_tag_id_as_data(env.target_info) {
|
||||
let tag_id_ptr = builder
|
||||
.build_struct_gep(raw_data_ptr, TAG_ID_INDEX, "tag_id_index")
|
||||
.unwrap();
|
||||
@ -1524,7 +1516,7 @@ pub fn build_tag<'a, 'ctx, 'env>(
|
||||
UnionLayout::NonRecursive(tags) => {
|
||||
debug_assert!(union_size > 1);
|
||||
|
||||
let internal_type = block_of_memory_slices(env.context, tags, env.ptr_bytes);
|
||||
let internal_type = block_of_memory_slices(env.context, tags, env.target_info);
|
||||
|
||||
let tag_id_type = basic_type_from_layout(env, &tag_id_layout).into_int_type();
|
||||
let wrapper_type = env
|
||||
@ -1711,7 +1703,7 @@ pub fn build_tag<'a, 'ctx, 'env>(
|
||||
other_fields,
|
||||
} => {
|
||||
let tag_struct_type =
|
||||
block_of_memory_slices(env.context, &[other_fields], env.ptr_bytes);
|
||||
block_of_memory_slices(env.context, &[other_fields], env.target_info);
|
||||
|
||||
if tag_id == *nullable_id as _ {
|
||||
let output_type = tag_struct_type.ptr_type(AddressSpace::Generic);
|
||||
@ -1788,7 +1780,7 @@ fn tag_pointer_set_tag_id<'a, 'ctx, 'env>(
|
||||
pointer: PointerValue<'ctx>,
|
||||
) -> PointerValue<'ctx> {
|
||||
// we only have 3 bits, so can encode only 0..7 (or on 32-bit targets, 2 bits to encode 0..3)
|
||||
debug_assert!((tag_id as u32) < env.ptr_bytes);
|
||||
debug_assert!((tag_id as u32) < env.target_info.ptr_width() as u32);
|
||||
|
||||
let ptr_int = env.ptr_int();
|
||||
|
||||
@ -1801,11 +1793,10 @@ fn tag_pointer_set_tag_id<'a, 'ctx, 'env>(
|
||||
.build_int_to_ptr(combined, pointer.get_type(), "to_ptr")
|
||||
}
|
||||
|
||||
pub fn tag_pointer_tag_id_bits_and_mask(ptr_bytes: u32) -> (u64, u64) {
|
||||
match ptr_bytes {
|
||||
8 => (3, 0b0000_0111),
|
||||
4 => (2, 0b0000_0011),
|
||||
_ => unreachable!(),
|
||||
pub fn tag_pointer_tag_id_bits_and_mask(target_info: TargetInfo) -> (u64, u64) {
|
||||
match target_info.ptr_width() {
|
||||
roc_target::PtrWidth::Bytes8 => (3, 0b0000_0111),
|
||||
roc_target::PtrWidth::Bytes4 => (2, 0b0000_0011),
|
||||
}
|
||||
}
|
||||
|
||||
@ -1813,7 +1804,7 @@ pub fn tag_pointer_read_tag_id<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
pointer: PointerValue<'ctx>,
|
||||
) -> IntValue<'ctx> {
|
||||
let (_, mask) = tag_pointer_tag_id_bits_and_mask(env.ptr_bytes);
|
||||
let (_, mask) = tag_pointer_tag_id_bits_and_mask(env.target_info);
|
||||
let ptr_int = env.ptr_int();
|
||||
|
||||
let as_int = env.builder.build_ptr_to_int(pointer, ptr_int, "to_int");
|
||||
@ -1831,7 +1822,7 @@ pub fn tag_pointer_clear_tag_id<'a, 'ctx, 'env>(
|
||||
) -> PointerValue<'ctx> {
|
||||
let ptr_int = env.ptr_int();
|
||||
|
||||
let (tag_id_bits_mask, _) = tag_pointer_tag_id_bits_and_mask(env.ptr_bytes);
|
||||
let (tag_id_bits_mask, _) = tag_pointer_tag_id_bits_and_mask(env.target_info);
|
||||
|
||||
let as_int = env.builder.build_ptr_to_int(pointer, ptr_int, "to_int");
|
||||
|
||||
@ -1918,7 +1909,7 @@ pub fn get_tag_id<'a, 'ctx, 'env>(
|
||||
UnionLayout::Recursive(_) => {
|
||||
let argument_ptr = argument.into_pointer_value();
|
||||
|
||||
if union_layout.stores_tag_id_as_data(env.ptr_bytes) {
|
||||
if union_layout.stores_tag_id_as_data(env.target_info) {
|
||||
get_tag_id_wrapped(env, argument_ptr)
|
||||
} else {
|
||||
tag_pointer_read_tag_id(env, argument_ptr)
|
||||
@ -1949,7 +1940,7 @@ pub fn get_tag_id<'a, 'ctx, 'env>(
|
||||
{
|
||||
env.builder.position_at_end(else_block);
|
||||
|
||||
let tag_id = if union_layout.stores_tag_id_as_data(env.ptr_bytes) {
|
||||
let tag_id = if union_layout.stores_tag_id_as_data(env.target_info) {
|
||||
get_tag_id_wrapped(env, argument_ptr)
|
||||
} else {
|
||||
tag_pointer_read_tag_id(env, argument_ptr)
|
||||
@ -2057,12 +2048,12 @@ fn lookup_at_index_ptr2<'a, 'ctx, 'env>(
|
||||
let result = if field_layout.is_passed_by_reference() {
|
||||
let field_type = basic_type_from_layout(env, &field_layout);
|
||||
|
||||
let align_bytes = field_layout.alignment_bytes(env.ptr_bytes);
|
||||
let align_bytes = field_layout.alignment_bytes(env.target_info);
|
||||
let alloca = tag_alloca(env, field_type, "copied_tag");
|
||||
if align_bytes > 0 {
|
||||
let size = env
|
||||
.ptr_int()
|
||||
.const_int(field_layout.stack_size(env.ptr_bytes) as u64, false);
|
||||
.const_int(field_layout.stack_size(env.target_info) as u64, false);
|
||||
|
||||
env.builder
|
||||
.build_memcpy(alloca, align_bytes, elem_ptr, align_bytes, size)
|
||||
@ -2095,8 +2086,8 @@ pub fn reserve_with_refcount<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
layout: &Layout<'a>,
|
||||
) -> PointerValue<'ctx> {
|
||||
let stack_size = layout.stack_size(env.ptr_bytes);
|
||||
let alignment_bytes = layout.alignment_bytes(env.ptr_bytes);
|
||||
let stack_size = layout.stack_size(env.target_info);
|
||||
let alignment_bytes = layout.alignment_bytes(env.target_info);
|
||||
|
||||
let basic_type = basic_type_from_layout(env, layout);
|
||||
|
||||
@ -2108,9 +2099,9 @@ fn reserve_with_refcount_union_as_block_of_memory<'a, 'ctx, 'env>(
|
||||
union_layout: UnionLayout<'a>,
|
||||
fields: &[&[Layout<'a>]],
|
||||
) -> PointerValue<'ctx> {
|
||||
let ptr_bytes = env.ptr_bytes;
|
||||
let ptr_bytes = env.target_info;
|
||||
|
||||
let block_type = block_of_memory_slices(env.context, fields, env.ptr_bytes);
|
||||
let block_type = block_of_memory_slices(env.context, fields, env.target_info);
|
||||
|
||||
let basic_type = if union_layout.stores_tag_id_as_data(ptr_bytes) {
|
||||
let tag_id_type = basic_type_from_layout(env, &union_layout.tag_id_layout());
|
||||
@ -2124,17 +2115,17 @@ fn reserve_with_refcount_union_as_block_of_memory<'a, 'ctx, 'env>(
|
||||
|
||||
let mut stack_size = fields
|
||||
.iter()
|
||||
.map(|tag| tag.iter().map(|l| l.stack_size(env.ptr_bytes)).sum())
|
||||
.map(|tag| tag.iter().map(|l| l.stack_size(env.target_info)).sum())
|
||||
.max()
|
||||
.unwrap_or_default();
|
||||
|
||||
if union_layout.stores_tag_id_as_data(ptr_bytes) {
|
||||
stack_size += union_layout.tag_id_layout().stack_size(env.ptr_bytes);
|
||||
stack_size += union_layout.tag_id_layout().stack_size(env.target_info);
|
||||
}
|
||||
|
||||
let alignment_bytes = fields
|
||||
.iter()
|
||||
.map(|tag| tag.iter().map(|l| l.alignment_bytes(env.ptr_bytes)))
|
||||
.map(|tag| tag.iter().map(|l| l.alignment_bytes(env.target_info)))
|
||||
.flatten()
|
||||
.max()
|
||||
.unwrap_or(0);
|
||||
@ -2154,7 +2145,7 @@ fn reserve_with_refcount_help<'a, 'ctx, 'env>(
|
||||
|
||||
let value_bytes_intvalue = len_type.const_int(stack_size as u64, false);
|
||||
|
||||
let rc1 = crate::llvm::refcounting::refcount_1(ctx, env.ptr_bytes);
|
||||
let rc1 = crate::llvm::refcounting::refcount_1(ctx, env.target_info);
|
||||
|
||||
allocate_with_refcount_help(env, basic_type, alignment_bytes, value_bytes_intvalue, rc1)
|
||||
}
|
||||
@ -2182,8 +2173,9 @@ pub fn allocate_with_refcount_help<'a, 'ctx, 'env>(
|
||||
let builder = env.builder;
|
||||
|
||||
let len_type = env.ptr_int();
|
||||
let ptr_width_u32 = env.target_info.ptr_width() as u32;
|
||||
|
||||
let extra_bytes = alignment_bytes.max(env.ptr_bytes);
|
||||
let extra_bytes = alignment_bytes.max(ptr_width_u32);
|
||||
|
||||
let ptr = {
|
||||
// number of bytes we will allocated
|
||||
@ -2208,8 +2200,8 @@ pub fn allocate_with_refcount_help<'a, 'ctx, 'env>(
|
||||
.into_pointer_value();
|
||||
|
||||
let index = match extra_bytes {
|
||||
n if n == env.ptr_bytes => 1,
|
||||
n if n == 2 * env.ptr_bytes => 2,
|
||||
n if n == ptr_width_u32 => 1,
|
||||
n if n == 2 * ptr_width_u32 => 2,
|
||||
_ => unreachable!("invalid extra_bytes, {}", extra_bytes),
|
||||
};
|
||||
|
||||
@ -2228,11 +2220,11 @@ pub fn allocate_with_refcount_help<'a, 'ctx, 'env>(
|
||||
};
|
||||
|
||||
let refcount_ptr = match extra_bytes {
|
||||
n if n == env.ptr_bytes => {
|
||||
n if n == ptr_width_u32 => {
|
||||
// the allocated pointer is the same as the refcounted pointer
|
||||
unsafe { PointerToRefcount::from_ptr(env, ptr) }
|
||||
}
|
||||
n if n == 2 * env.ptr_bytes => {
|
||||
n if n == 2 * ptr_width_u32 => {
|
||||
// the refcount is stored just before the start of the actual data
|
||||
// but in this case (because of alignment) not at the start of the allocated buffer
|
||||
PointerToRefcount::from_ptr_to_data(env, data_ptr)
|
||||
@ -2283,14 +2275,15 @@ fn list_literal<'a, 'ctx, 'env>(
|
||||
// if element_type.is_int_type() {
|
||||
if false {
|
||||
let element_type = element_type.into_int_type();
|
||||
let element_width = element_layout.stack_size(env.ptr_bytes);
|
||||
let element_width = element_layout.stack_size(env.target_info);
|
||||
let size = list_length * element_width as usize;
|
||||
let alignment = element_layout
|
||||
.alignment_bytes(env.ptr_bytes)
|
||||
.max(env.ptr_bytes);
|
||||
.alignment_bytes(env.target_info)
|
||||
.max(env.target_info.ptr_width() as u32);
|
||||
|
||||
let mut is_all_constant = true;
|
||||
let zero_elements = (env.ptr_bytes as f64 / element_width as f64).ceil() as usize;
|
||||
let zero_elements =
|
||||
(env.target_info.ptr_width() as u8 as f64 / element_width as f64).ceil() as usize;
|
||||
|
||||
// runtime-evaluated elements
|
||||
let mut runtime_evaluated_elements = Vec::with_capacity_in(list_length, env.arena);
|
||||
@ -2471,12 +2464,12 @@ pub fn store_roc_value<'a, 'ctx, 'env>(
|
||||
value: BasicValueEnum<'ctx>,
|
||||
) {
|
||||
if layout.is_passed_by_reference() {
|
||||
let align_bytes = layout.alignment_bytes(env.ptr_bytes);
|
||||
let align_bytes = layout.alignment_bytes(env.target_info);
|
||||
|
||||
if align_bytes > 0 {
|
||||
let size = env
|
||||
.ptr_int()
|
||||
.const_int(layout.stack_size(env.ptr_bytes) as u64, false);
|
||||
.const_int(layout.stack_size(env.target_info) as u64, false);
|
||||
|
||||
env.builder
|
||||
.build_memcpy(
|
||||
@ -2572,7 +2565,7 @@ pub fn build_exp_stmt<'a, 'ctx, 'env>(
|
||||
|
||||
let destination = out_parameter.into_pointer_value();
|
||||
if layout.is_passed_by_reference() {
|
||||
let align_bytes = layout.alignment_bytes(env.ptr_bytes);
|
||||
let align_bytes = layout.alignment_bytes(env.target_info);
|
||||
|
||||
if align_bytes > 0 {
|
||||
let value_ptr = value.into_pointer_value();
|
||||
@ -2585,7 +2578,7 @@ pub fn build_exp_stmt<'a, 'ctx, 'env>(
|
||||
} else {
|
||||
let size = env
|
||||
.ptr_int()
|
||||
.const_int(layout.stack_size(env.ptr_bytes) as u64, false);
|
||||
.const_int(layout.stack_size(env.target_info) as u64, false);
|
||||
|
||||
env.builder
|
||||
.build_memcpy(
|
||||
@ -2776,21 +2769,21 @@ pub fn build_exp_stmt<'a, 'ctx, 'env>(
|
||||
match layout {
|
||||
Layout::Builtin(Builtin::List(element_layout)) => {
|
||||
debug_assert!(value.is_struct_value());
|
||||
let alignment = element_layout.alignment_bytes(env.ptr_bytes);
|
||||
let alignment = element_layout.alignment_bytes(env.target_info);
|
||||
|
||||
build_list::decref(env, value.into_struct_value(), alignment);
|
||||
}
|
||||
Layout::Builtin(Builtin::Dict(key_layout, value_layout)) => {
|
||||
debug_assert!(value.is_struct_value());
|
||||
let alignment = key_layout
|
||||
.alignment_bytes(env.ptr_bytes)
|
||||
.max(value_layout.alignment_bytes(env.ptr_bytes));
|
||||
.alignment_bytes(env.target_info)
|
||||
.max(value_layout.alignment_bytes(env.target_info));
|
||||
|
||||
build_dict::decref(env, value.into_struct_value(), alignment);
|
||||
}
|
||||
Layout::Builtin(Builtin::Set(key_layout)) => {
|
||||
debug_assert!(value.is_struct_value());
|
||||
let alignment = key_layout.alignment_bytes(env.ptr_bytes);
|
||||
let alignment = key_layout.alignment_bytes(env.target_info);
|
||||
|
||||
build_dict::decref(env, value.into_struct_value(), alignment);
|
||||
}
|
||||
@ -3408,7 +3401,7 @@ fn expose_function_to_host_help_c_abi_generic<'a, 'ctx, 'env>(
|
||||
|
||||
builder.position_at_end(entry);
|
||||
|
||||
let wrapped_layout = roc_result_layout(env.arena, return_layout, env.ptr_bytes);
|
||||
let wrapped_layout = roc_result_layout(env.arena, return_layout, env.target_info);
|
||||
call_roc_function(env, roc_function, &wrapped_layout, arguments_for_call)
|
||||
} else {
|
||||
call_roc_function(env, roc_function, &return_layout, arguments_for_call)
|
||||
@ -3712,7 +3705,10 @@ fn expose_function_to_host_help_c_abi<'a, 'ctx, 'env>(
|
||||
}
|
||||
|
||||
pub fn get_sjlj_buffer<'a, 'ctx, 'env>(env: &Env<'a, 'ctx, 'env>) -> PointerValue<'ctx> {
|
||||
let type_ = env.context.i8_type().array_type(5 * env.ptr_bytes);
|
||||
let type_ = env
|
||||
.context
|
||||
.i8_type()
|
||||
.array_type(5 * env.target_info.ptr_width() as u32);
|
||||
|
||||
let global = match env.module.get_global("roc_sjlj_buffer") {
|
||||
Some(global) => global,
|
||||
@ -3880,8 +3876,12 @@ fn make_exception_catcher<'a, 'ctx, 'env>(
|
||||
function_value
|
||||
}
|
||||
|
||||
fn roc_result_layout<'a>(arena: &'a Bump, return_layout: Layout<'a>, ptr_bytes: u32) -> Layout<'a> {
|
||||
let elements = [Layout::u64(), Layout::usize(ptr_bytes), return_layout];
|
||||
fn roc_result_layout<'a>(
|
||||
arena: &'a Bump,
|
||||
return_layout: Layout<'a>,
|
||||
target_info: TargetInfo,
|
||||
) -> Layout<'a> {
|
||||
let elements = [Layout::u64(), Layout::usize(target_info), return_layout];
|
||||
|
||||
Layout::Struct(arena.alloc(elements))
|
||||
}
|
||||
@ -4315,12 +4315,12 @@ pub fn build_closure_caller<'a, 'ctx, 'env>(
|
||||
let call_result = call_roc_function(env, evaluator, return_layout, &evaluator_arguments);
|
||||
|
||||
if return_layout.is_passed_by_reference() {
|
||||
let align_bytes = return_layout.alignment_bytes(env.ptr_bytes);
|
||||
let align_bytes = return_layout.alignment_bytes(env.target_info);
|
||||
|
||||
if align_bytes > 0 {
|
||||
let size = env
|
||||
.ptr_int()
|
||||
.const_int(return_layout.stack_size(env.ptr_bytes) as u64, false);
|
||||
.const_int(return_layout.stack_size(env.target_info) as u64, false);
|
||||
|
||||
env.builder
|
||||
.build_memcpy(
|
||||
@ -5006,7 +5006,7 @@ fn run_higher_order_low_level<'a, 'ctx, 'env>(
|
||||
Layout::Builtin(Builtin::List(element_layout)),
|
||||
Layout::Builtin(Builtin::List(result_layout)),
|
||||
) => {
|
||||
let argument_layouts = &[Layout::usize(env.ptr_bytes), **element_layout];
|
||||
let argument_layouts = &[Layout::usize(env.target_info), **element_layout];
|
||||
|
||||
let roc_function_call = roc_function_call(
|
||||
env,
|
||||
@ -6061,8 +6061,8 @@ fn run_low_level<'a, 'ctx, 'env>(
|
||||
{
|
||||
bd.position_at_end(throw_block);
|
||||
|
||||
match env.ptr_bytes {
|
||||
8 => {
|
||||
match env.target_info.ptr_width() {
|
||||
roc_target::PtrWidth::Bytes8 => {
|
||||
let fn_ptr_type = context
|
||||
.void_type()
|
||||
.fn_type(&[], false)
|
||||
@ -6081,11 +6081,10 @@ fn run_low_level<'a, 'ctx, 'env>(
|
||||
|
||||
bd.build_unconditional_branch(then_block);
|
||||
}
|
||||
4 => {
|
||||
roc_target::PtrWidth::Bytes4 => {
|
||||
// temporary WASM implementation
|
||||
throw_exception(env, "An expectation failed!");
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -6211,8 +6210,8 @@ impl CCReturn {
|
||||
|
||||
/// According to the C ABI, how should we return a value with the given layout?
|
||||
fn to_cc_return<'a, 'ctx, 'env>(env: &Env<'a, 'ctx, 'env>, layout: &Layout<'a>) -> CCReturn {
|
||||
let return_size = layout.stack_size(env.ptr_bytes);
|
||||
let pass_result_by_pointer = return_size > 2 * env.ptr_bytes;
|
||||
let return_size = layout.stack_size(env.target_info);
|
||||
let pass_result_by_pointer = return_size > 2 * env.target_info.ptr_width() as u32;
|
||||
|
||||
if return_size == 0 {
|
||||
CCReturn::Void
|
||||
@ -7131,7 +7130,9 @@ fn define_global_str_literal_ptr<'a, 'ctx, 'env>(
|
||||
let ptr = unsafe {
|
||||
env.builder.build_in_bounds_gep(
|
||||
ptr,
|
||||
&[env.ptr_int().const_int(env.ptr_bytes as u64, false)],
|
||||
&[env
|
||||
.ptr_int()
|
||||
.const_int(env.target_info.ptr_width() as u64, false)],
|
||||
"get_rc_ptr",
|
||||
)
|
||||
};
|
||||
@ -7161,11 +7162,11 @@ fn define_global_str_literal<'a, 'ctx, 'env>(
|
||||
Some(current) => current,
|
||||
|
||||
None => {
|
||||
let size = message.bytes().len() + env.ptr_bytes as usize;
|
||||
let size = message.bytes().len() + env.target_info.ptr_width() as usize;
|
||||
let mut bytes = Vec::with_capacity_in(size, env.arena);
|
||||
|
||||
// insert NULL bytes for the refcount
|
||||
for _ in 0..env.ptr_bytes {
|
||||
for _ in 0..env.target_info.ptr_width() as usize {
|
||||
bytes.push(env.context.i8_type().const_zero());
|
||||
}
|
||||
|
||||
@ -7184,7 +7185,7 @@ fn define_global_str_literal<'a, 'ctx, 'env>(
|
||||
// strings are NULL-terminated, which means we can't store the refcount (which is 8
|
||||
// NULL bytes)
|
||||
global.set_constant(true);
|
||||
global.set_alignment(env.ptr_bytes);
|
||||
global.set_alignment(env.target_info.ptr_width() as u32);
|
||||
global.set_unnamed_addr(true);
|
||||
global.set_linkage(inkwell::module::Linkage::Private);
|
||||
|
||||
|
@ -17,14 +17,15 @@ use inkwell::AddressSpace;
|
||||
use roc_builtins::bitcode;
|
||||
use roc_module::symbol::Symbol;
|
||||
use roc_mono::layout::{Builtin, Layout, LayoutIds};
|
||||
use roc_target::TargetInfo;
|
||||
|
||||
#[repr(transparent)]
|
||||
struct Alignment(u8);
|
||||
|
||||
impl Alignment {
|
||||
fn from_key_value_layout(key: &Layout, value: &Layout, ptr_bytes: u32) -> Alignment {
|
||||
let key_align = key.alignment_bytes(ptr_bytes);
|
||||
let value_align = value.alignment_bytes(ptr_bytes);
|
||||
fn from_key_value_layout(key: &Layout, value: &Layout, target_info: TargetInfo) -> Alignment {
|
||||
let key_align = key.alignment_bytes(target_info);
|
||||
let value_align = value.alignment_bytes(target_info);
|
||||
|
||||
let mut bits = key_align.max(value_align) as u8;
|
||||
|
||||
@ -105,15 +106,15 @@ pub fn dict_insert<'a, 'ctx, 'env>(
|
||||
|
||||
let key_width = env
|
||||
.ptr_int()
|
||||
.const_int(key_layout.stack_size(env.ptr_bytes) as u64, false);
|
||||
.const_int(key_layout.stack_size(env.target_info) as u64, false);
|
||||
|
||||
let value_width = env
|
||||
.ptr_int()
|
||||
.const_int(value_layout.stack_size(env.ptr_bytes) as u64, false);
|
||||
.const_int(value_layout.stack_size(env.target_info) as u64, false);
|
||||
|
||||
let result_ptr = builder.build_alloca(zig_dict_type(env), "result_ptr");
|
||||
|
||||
let alignment = Alignment::from_key_value_layout(key_layout, value_layout, env.ptr_bytes);
|
||||
let alignment = Alignment::from_key_value_layout(key_layout, value_layout, env.target_info);
|
||||
let alignment_iv = alignment.as_int_value(env.context);
|
||||
|
||||
let hash_fn = build_hash_wrapper(env, layout_ids, key_layout);
|
||||
@ -162,15 +163,15 @@ pub fn dict_remove<'a, 'ctx, 'env>(
|
||||
|
||||
let key_width = env
|
||||
.ptr_int()
|
||||
.const_int(key_layout.stack_size(env.ptr_bytes) as u64, false);
|
||||
.const_int(key_layout.stack_size(env.target_info) as u64, false);
|
||||
|
||||
let value_width = env
|
||||
.ptr_int()
|
||||
.const_int(value_layout.stack_size(env.ptr_bytes) as u64, false);
|
||||
.const_int(value_layout.stack_size(env.target_info) as u64, false);
|
||||
|
||||
let result_ptr = builder.build_alloca(zig_dict_type(env), "result_ptr");
|
||||
|
||||
let alignment = Alignment::from_key_value_layout(key_layout, value_layout, env.ptr_bytes);
|
||||
let alignment = Alignment::from_key_value_layout(key_layout, value_layout, env.target_info);
|
||||
let alignment_iv = alignment.as_int_value(env.context);
|
||||
|
||||
let hash_fn = build_hash_wrapper(env, layout_ids, key_layout);
|
||||
@ -218,13 +219,13 @@ pub fn dict_contains<'a, 'ctx, 'env>(
|
||||
|
||||
let key_width = env
|
||||
.ptr_int()
|
||||
.const_int(key_layout.stack_size(env.ptr_bytes) as u64, false);
|
||||
.const_int(key_layout.stack_size(env.target_info) as u64, false);
|
||||
|
||||
let value_width = env
|
||||
.ptr_int()
|
||||
.const_int(value_layout.stack_size(env.ptr_bytes) as u64, false);
|
||||
.const_int(value_layout.stack_size(env.target_info) as u64, false);
|
||||
|
||||
let alignment = Alignment::from_key_value_layout(key_layout, value_layout, env.ptr_bytes);
|
||||
let alignment = Alignment::from_key_value_layout(key_layout, value_layout, env.target_info);
|
||||
let alignment_iv = alignment.as_int_value(env.context);
|
||||
|
||||
let hash_fn = build_hash_wrapper(env, layout_ids, key_layout);
|
||||
@ -264,13 +265,13 @@ pub fn dict_get<'a, 'ctx, 'env>(
|
||||
|
||||
let key_width = env
|
||||
.ptr_int()
|
||||
.const_int(key_layout.stack_size(env.ptr_bytes) as u64, false);
|
||||
.const_int(key_layout.stack_size(env.target_info) as u64, false);
|
||||
|
||||
let value_width = env
|
||||
.ptr_int()
|
||||
.const_int(value_layout.stack_size(env.ptr_bytes) as u64, false);
|
||||
.const_int(value_layout.stack_size(env.target_info) as u64, false);
|
||||
|
||||
let alignment = Alignment::from_key_value_layout(key_layout, value_layout, env.ptr_bytes);
|
||||
let alignment = Alignment::from_key_value_layout(key_layout, value_layout, env.target_info);
|
||||
let alignment_iv = alignment.as_int_value(env.context);
|
||||
|
||||
let hash_fn = build_hash_wrapper(env, layout_ids, key_layout);
|
||||
@ -366,13 +367,13 @@ pub fn dict_elements_rc<'a, 'ctx, 'env>(
|
||||
) {
|
||||
let key_width = env
|
||||
.ptr_int()
|
||||
.const_int(key_layout.stack_size(env.ptr_bytes) as u64, false);
|
||||
.const_int(key_layout.stack_size(env.target_info) as u64, false);
|
||||
|
||||
let value_width = env
|
||||
.ptr_int()
|
||||
.const_int(value_layout.stack_size(env.ptr_bytes) as u64, false);
|
||||
.const_int(value_layout.stack_size(env.target_info) as u64, false);
|
||||
|
||||
let alignment = Alignment::from_key_value_layout(key_layout, value_layout, env.ptr_bytes);
|
||||
let alignment = Alignment::from_key_value_layout(key_layout, value_layout, env.target_info);
|
||||
let alignment_iv = alignment.as_int_value(env.context);
|
||||
|
||||
let (key_fn, value_fn) = match rc_operation {
|
||||
@ -412,13 +413,13 @@ pub fn dict_keys<'a, 'ctx, 'env>(
|
||||
|
||||
let key_width = env
|
||||
.ptr_int()
|
||||
.const_int(key_layout.stack_size(env.ptr_bytes) as u64, false);
|
||||
.const_int(key_layout.stack_size(env.target_info) as u64, false);
|
||||
|
||||
let value_width = env
|
||||
.ptr_int()
|
||||
.const_int(value_layout.stack_size(env.ptr_bytes) as u64, false);
|
||||
.const_int(value_layout.stack_size(env.target_info) as u64, false);
|
||||
|
||||
let alignment = Alignment::from_key_value_layout(key_layout, value_layout, env.ptr_bytes);
|
||||
let alignment = Alignment::from_key_value_layout(key_layout, value_layout, env.target_info);
|
||||
let alignment_iv = alignment.as_int_value(env.context);
|
||||
|
||||
let inc_key_fn = build_inc_wrapper(env, layout_ids, key_layout);
|
||||
@ -454,19 +455,18 @@ fn pass_dict_c_abi<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
dict: BasicValueEnum<'ctx>,
|
||||
) -> BasicValueEnum<'ctx> {
|
||||
match env.ptr_bytes {
|
||||
4 => {
|
||||
match env.target_info.ptr_width() {
|
||||
roc_target::PtrWidth::Bytes4 => {
|
||||
let target_type = env.context.custom_width_int_type(96).into();
|
||||
|
||||
complex_bitcast(env.builder, dict, target_type, "to_i96")
|
||||
}
|
||||
8 => {
|
||||
roc_target::PtrWidth::Bytes8 => {
|
||||
let dict_ptr = env.builder.build_alloca(zig_dict_type(env), "dict_ptr");
|
||||
env.builder.build_store(dict_ptr, dict);
|
||||
|
||||
dict_ptr.into()
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -483,13 +483,13 @@ pub fn dict_union<'a, 'ctx, 'env>(
|
||||
|
||||
let key_width = env
|
||||
.ptr_int()
|
||||
.const_int(key_layout.stack_size(env.ptr_bytes) as u64, false);
|
||||
.const_int(key_layout.stack_size(env.target_info) as u64, false);
|
||||
|
||||
let value_width = env
|
||||
.ptr_int()
|
||||
.const_int(value_layout.stack_size(env.ptr_bytes) as u64, false);
|
||||
.const_int(value_layout.stack_size(env.target_info) as u64, false);
|
||||
|
||||
let alignment = Alignment::from_key_value_layout(key_layout, value_layout, env.ptr_bytes);
|
||||
let alignment = Alignment::from_key_value_layout(key_layout, value_layout, env.target_info);
|
||||
let alignment_iv = alignment.as_int_value(env.context);
|
||||
|
||||
let hash_fn = build_hash_wrapper(env, layout_ids, key_layout);
|
||||
@ -576,13 +576,13 @@ fn dict_intersect_or_difference<'a, 'ctx, 'env>(
|
||||
|
||||
let key_width = env
|
||||
.ptr_int()
|
||||
.const_int(key_layout.stack_size(env.ptr_bytes) as u64, false);
|
||||
.const_int(key_layout.stack_size(env.target_info) as u64, false);
|
||||
|
||||
let value_width = env
|
||||
.ptr_int()
|
||||
.const_int(value_layout.stack_size(env.ptr_bytes) as u64, false);
|
||||
.const_int(value_layout.stack_size(env.target_info) as u64, false);
|
||||
|
||||
let alignment = Alignment::from_key_value_layout(key_layout, value_layout, env.ptr_bytes);
|
||||
let alignment = Alignment::from_key_value_layout(key_layout, value_layout, env.target_info);
|
||||
let alignment_iv = alignment.as_int_value(env.context);
|
||||
|
||||
let hash_fn = build_hash_wrapper(env, layout_ids, key_layout);
|
||||
@ -631,7 +631,7 @@ pub fn dict_walk<'a, 'ctx, 'env>(
|
||||
let accum_ptr = builder.build_alloca(accum_bt, "accum_ptr");
|
||||
env.builder.build_store(accum_ptr, accum);
|
||||
|
||||
let alignment = Alignment::from_key_value_layout(key_layout, value_layout, env.ptr_bytes);
|
||||
let alignment = Alignment::from_key_value_layout(key_layout, value_layout, env.target_info);
|
||||
let alignment_iv = alignment.as_int_value(env.context);
|
||||
|
||||
let output_ptr = builder.build_alloca(accum_bt, "output_ptr");
|
||||
@ -671,13 +671,13 @@ pub fn dict_values<'a, 'ctx, 'env>(
|
||||
|
||||
let key_width = env
|
||||
.ptr_int()
|
||||
.const_int(key_layout.stack_size(env.ptr_bytes) as u64, false);
|
||||
.const_int(key_layout.stack_size(env.target_info) as u64, false);
|
||||
|
||||
let value_width = env
|
||||
.ptr_int()
|
||||
.const_int(value_layout.stack_size(env.ptr_bytes) as u64, false);
|
||||
.const_int(value_layout.stack_size(env.target_info) as u64, false);
|
||||
|
||||
let alignment = Alignment::from_key_value_layout(key_layout, value_layout, env.ptr_bytes);
|
||||
let alignment = Alignment::from_key_value_layout(key_layout, value_layout, env.target_info);
|
||||
let alignment_iv = alignment.as_int_value(env.context);
|
||||
|
||||
let inc_value_fn = build_inc_wrapper(env, layout_ids, value_layout);
|
||||
@ -729,14 +729,14 @@ pub fn set_from_list<'a, 'ctx, 'env>(
|
||||
|
||||
let key_width = env
|
||||
.ptr_int()
|
||||
.const_int(key_layout.stack_size(env.ptr_bytes) as u64, false);
|
||||
.const_int(key_layout.stack_size(env.target_info) as u64, false);
|
||||
|
||||
let value_width = env.ptr_int().const_zero();
|
||||
|
||||
let result_alloca = builder.build_alloca(zig_dict_type(env), "result_alloca");
|
||||
|
||||
let alignment =
|
||||
Alignment::from_key_value_layout(key_layout, &Layout::Struct(&[]), env.ptr_bytes);
|
||||
Alignment::from_key_value_layout(key_layout, &Layout::Struct(&[]), env.target_info);
|
||||
let alignment_iv = alignment.as_int_value(env.context);
|
||||
|
||||
let hash_fn = build_hash_wrapper(env, layout_ids, key_layout);
|
||||
|
@ -120,7 +120,7 @@ fn hash_builtin<'a, 'ctx, 'env>(
|
||||
builtin: &Builtin<'a>,
|
||||
when_recursive: WhenRecursive<'a>,
|
||||
) -> IntValue<'ctx> {
|
||||
let ptr_bytes = env.ptr_bytes;
|
||||
let ptr_bytes = env.target_info;
|
||||
|
||||
match builtin {
|
||||
Builtin::Int(_) | Builtin::Float(_) | Builtin::Bool | Builtin::Decimal => {
|
||||
@ -246,7 +246,7 @@ fn hash_struct<'a, 'ctx, 'env>(
|
||||
when_recursive: WhenRecursive<'a>,
|
||||
field_layouts: &[Layout<'a>],
|
||||
) -> IntValue<'ctx> {
|
||||
let ptr_bytes = env.ptr_bytes;
|
||||
let ptr_bytes = env.target_info;
|
||||
|
||||
let layout = Layout::Struct(field_layouts);
|
||||
|
||||
@ -423,7 +423,7 @@ fn hash_tag<'a, 'ctx, 'env>(
|
||||
env,
|
||||
seed,
|
||||
hash_bytes,
|
||||
tag_id_layout.stack_size(env.ptr_bytes),
|
||||
tag_id_layout.stack_size(env.target_info),
|
||||
);
|
||||
|
||||
// hash the tag data
|
||||
@ -474,7 +474,7 @@ fn hash_tag<'a, 'ctx, 'env>(
|
||||
env,
|
||||
seed,
|
||||
hash_bytes,
|
||||
tag_id_layout.stack_size(env.ptr_bytes),
|
||||
tag_id_layout.stack_size(env.target_info),
|
||||
);
|
||||
|
||||
// hash the tag data
|
||||
@ -574,7 +574,7 @@ fn hash_tag<'a, 'ctx, 'env>(
|
||||
env,
|
||||
seed,
|
||||
hash_bytes,
|
||||
tag_id_layout.stack_size(env.ptr_bytes),
|
||||
tag_id_layout.stack_size(env.target_info),
|
||||
);
|
||||
|
||||
// hash tag data
|
||||
|
@ -87,7 +87,7 @@ pub fn layout_width<'a, 'ctx, 'env>(
|
||||
layout: &Layout<'a>,
|
||||
) -> BasicValueEnum<'ctx> {
|
||||
env.ptr_int()
|
||||
.const_int(layout.stack_size(env.ptr_bytes) as u64, false)
|
||||
.const_int(layout.stack_size(env.target_info) as u64, false)
|
||||
.into()
|
||||
}
|
||||
|
||||
@ -1254,17 +1254,17 @@ pub fn allocate_list<'a, 'ctx, 'env>(
|
||||
let ctx = env.context;
|
||||
|
||||
let len_type = env.ptr_int();
|
||||
let elem_bytes = elem_layout.stack_size(env.ptr_bytes) as u64;
|
||||
let elem_bytes = elem_layout.stack_size(env.target_info) as u64;
|
||||
let bytes_per_element = len_type.const_int(elem_bytes, false);
|
||||
let number_of_data_bytes =
|
||||
builder.build_int_mul(bytes_per_element, number_of_elements, "data_length");
|
||||
|
||||
// the refcount of a new list is initially 1
|
||||
// we assume that the list is indeed used (dead variables are eliminated)
|
||||
let rc1 = crate::llvm::refcounting::refcount_1(ctx, env.ptr_bytes);
|
||||
let rc1 = crate::llvm::refcounting::refcount_1(ctx, env.target_info);
|
||||
|
||||
let basic_type = basic_type_from_layout(env, elem_layout);
|
||||
let alignment_bytes = elem_layout.alignment_bytes(env.ptr_bytes);
|
||||
let alignment_bytes = elem_layout.alignment_bytes(env.target_info);
|
||||
allocate_with_refcount_help(env, basic_type, alignment_bytes, number_of_data_bytes, rc1)
|
||||
}
|
||||
|
||||
|
@ -10,6 +10,7 @@ use morphic_lib::UpdateMode;
|
||||
use roc_builtins::bitcode::{self, IntWidth};
|
||||
use roc_module::symbol::Symbol;
|
||||
use roc_mono::layout::{Builtin, Layout};
|
||||
use roc_target::PtrWidth;
|
||||
|
||||
use super::build::load_symbol;
|
||||
|
||||
@ -79,10 +80,9 @@ fn str_symbol_to_c_abi<'a, 'ctx, 'env>(
|
||||
) -> IntValue<'ctx> {
|
||||
let string = load_symbol(scope, &symbol);
|
||||
|
||||
let target_type = match env.ptr_bytes {
|
||||
8 => env.context.i128_type().into(),
|
||||
4 => env.context.i64_type().into(),
|
||||
_ => unreachable!(),
|
||||
let target_type = match env.target_info.ptr_width() {
|
||||
PtrWidth::Bytes8 => env.context.i128_type().into(),
|
||||
PtrWidth::Bytes4 => env.context.i64_type().into(),
|
||||
};
|
||||
|
||||
complex_bitcast(env.builder, string, target_type, "str_to_c_abi").into_int_value()
|
||||
@ -96,10 +96,9 @@ pub fn str_to_c_abi<'a, 'ctx, 'env>(
|
||||
|
||||
env.builder.build_store(cell, value);
|
||||
|
||||
let target_type = match env.ptr_bytes {
|
||||
8 => env.context.i128_type(),
|
||||
4 => env.context.i64_type(),
|
||||
_ => unreachable!(),
|
||||
let target_type = match env.target_info.ptr_width() {
|
||||
PtrWidth::Bytes8 => env.context.i128_type(),
|
||||
PtrWidth::Bytes4 => env.context.i64_type(),
|
||||
};
|
||||
|
||||
let target_type_ptr = env
|
||||
@ -310,20 +309,19 @@ fn decode_from_utf8_result<'a, 'ctx, 'env>(
|
||||
let builder = env.builder;
|
||||
let ctx = env.context;
|
||||
|
||||
let fields = match env.ptr_bytes {
|
||||
8 | 4 => [
|
||||
let fields = match env.target_info.ptr_width() {
|
||||
PtrWidth::Bytes4 | PtrWidth::Bytes8 => [
|
||||
env.ptr_int().into(),
|
||||
super::convert::zig_str_type(env).into(),
|
||||
env.context.bool_type().into(),
|
||||
ctx.i8_type().into(),
|
||||
],
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
let record_type = env.context.struct_type(&fields, false);
|
||||
|
||||
match env.ptr_bytes {
|
||||
8 | 4 => {
|
||||
match env.target_info.ptr_width() {
|
||||
PtrWidth::Bytes4 | PtrWidth::Bytes8 => {
|
||||
let result_ptr_cast = env
|
||||
.builder
|
||||
.build_bitcast(
|
||||
@ -337,7 +335,6 @@ fn decode_from_utf8_result<'a, 'ctx, 'env>(
|
||||
.build_load(result_ptr_cast, "load_utf8_validate_bytes_result")
|
||||
.into_struct_value()
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4,6 +4,7 @@ use inkwell::types::{BasicType, BasicTypeEnum, FloatType, IntType, StructType};
|
||||
use inkwell::AddressSpace;
|
||||
use roc_builtins::bitcode::{FloatWidth, IntWidth};
|
||||
use roc_mono::layout::{Builtin, Layout, UnionLayout};
|
||||
use roc_target::TargetInfo;
|
||||
|
||||
fn basic_type_from_record<'a, 'ctx, 'env>(
|
||||
env: &crate::llvm::build::Env<'a, 'ctx, 'env>,
|
||||
@ -36,7 +37,7 @@ pub fn basic_type_from_layout<'a, 'ctx, 'env>(
|
||||
|
||||
match union_layout {
|
||||
NonRecursive(tags) => {
|
||||
let data = block_of_memory_slices(env.context, tags, env.ptr_bytes);
|
||||
let data = block_of_memory_slices(env.context, tags, env.target_info);
|
||||
|
||||
env.context.struct_type(&[data, tag_id_type], false).into()
|
||||
}
|
||||
@ -44,9 +45,9 @@ pub fn basic_type_from_layout<'a, 'ctx, 'env>(
|
||||
| NullableWrapped {
|
||||
other_tags: tags, ..
|
||||
} => {
|
||||
let data = block_of_memory_slices(env.context, tags, env.ptr_bytes);
|
||||
let data = block_of_memory_slices(env.context, tags, env.target_info);
|
||||
|
||||
if union_layout.stores_tag_id_as_data(env.ptr_bytes) {
|
||||
if union_layout.stores_tag_id_as_data(env.target_info) {
|
||||
env.context
|
||||
.struct_type(&[data, tag_id_type], false)
|
||||
.ptr_type(AddressSpace::Generic)
|
||||
@ -56,11 +57,12 @@ pub fn basic_type_from_layout<'a, 'ctx, 'env>(
|
||||
}
|
||||
}
|
||||
NullableUnwrapped { other_fields, .. } => {
|
||||
let block = block_of_memory_slices(env.context, &[other_fields], env.ptr_bytes);
|
||||
let block =
|
||||
block_of_memory_slices(env.context, &[other_fields], env.target_info);
|
||||
block.ptr_type(AddressSpace::Generic).into()
|
||||
}
|
||||
NonNullableUnwrapped(fields) => {
|
||||
let block = block_of_memory_slices(env.context, &[fields], env.ptr_bytes);
|
||||
let block = block_of_memory_slices(env.context, &[fields], env.target_info);
|
||||
block.ptr_type(AddressSpace::Generic).into()
|
||||
}
|
||||
}
|
||||
@ -95,7 +97,7 @@ pub fn basic_type_from_layout_1<'a, 'ctx, 'env>(
|
||||
|
||||
match union_layout {
|
||||
NonRecursive(tags) => {
|
||||
let data = block_of_memory_slices(env.context, tags, env.ptr_bytes);
|
||||
let data = block_of_memory_slices(env.context, tags, env.target_info);
|
||||
let struct_type = env.context.struct_type(&[data, tag_id_type], false);
|
||||
|
||||
struct_type.ptr_type(AddressSpace::Generic).into()
|
||||
@ -104,9 +106,9 @@ pub fn basic_type_from_layout_1<'a, 'ctx, 'env>(
|
||||
| NullableWrapped {
|
||||
other_tags: tags, ..
|
||||
} => {
|
||||
let data = block_of_memory_slices(env.context, tags, env.ptr_bytes);
|
||||
let data = block_of_memory_slices(env.context, tags, env.target_info);
|
||||
|
||||
if union_layout.stores_tag_id_as_data(env.ptr_bytes) {
|
||||
if union_layout.stores_tag_id_as_data(env.target_info) {
|
||||
env.context
|
||||
.struct_type(&[data, tag_id_type], false)
|
||||
.ptr_type(AddressSpace::Generic)
|
||||
@ -116,11 +118,12 @@ pub fn basic_type_from_layout_1<'a, 'ctx, 'env>(
|
||||
}
|
||||
}
|
||||
NullableUnwrapped { other_fields, .. } => {
|
||||
let block = block_of_memory_slices(env.context, &[other_fields], env.ptr_bytes);
|
||||
let block =
|
||||
block_of_memory_slices(env.context, &[other_fields], env.target_info);
|
||||
block.ptr_type(AddressSpace::Generic).into()
|
||||
}
|
||||
NonNullableUnwrapped(fields) => {
|
||||
let block = block_of_memory_slices(env.context, &[fields], env.ptr_bytes);
|
||||
let block = block_of_memory_slices(env.context, &[fields], env.target_info);
|
||||
block.ptr_type(AddressSpace::Generic).into()
|
||||
}
|
||||
}
|
||||
@ -188,13 +191,13 @@ pub fn float_type_from_float_width<'a, 'ctx, 'env>(
|
||||
pub fn block_of_memory_slices<'ctx>(
|
||||
context: &'ctx Context,
|
||||
layouts: &[&[Layout<'_>]],
|
||||
ptr_bytes: u32,
|
||||
target_info: TargetInfo,
|
||||
) -> BasicTypeEnum<'ctx> {
|
||||
let mut union_size = 0;
|
||||
for tag in layouts {
|
||||
let mut total = 0;
|
||||
for layout in tag.iter() {
|
||||
total += layout.stack_size(ptr_bytes as u32);
|
||||
total += layout.stack_size(target_info);
|
||||
}
|
||||
|
||||
union_size = union_size.max(total);
|
||||
@ -206,13 +209,13 @@ pub fn block_of_memory_slices<'ctx>(
|
||||
pub fn block_of_memory<'ctx>(
|
||||
context: &'ctx Context,
|
||||
layout: &Layout<'_>,
|
||||
ptr_bytes: u32,
|
||||
target_info: TargetInfo,
|
||||
) -> BasicTypeEnum<'ctx> {
|
||||
// TODO make this dynamic
|
||||
let mut union_size = layout.stack_size(ptr_bytes as u32);
|
||||
let mut union_size = layout.stack_size(target_info);
|
||||
|
||||
if let Layout::Union(UnionLayout::NonRecursive { .. }) = layout {
|
||||
union_size -= ptr_bytes;
|
||||
union_size -= target_info.ptr_width() as u32;
|
||||
}
|
||||
|
||||
block_of_memory_help(context, union_size)
|
||||
@ -251,16 +254,10 @@ fn block_of_memory_help(context: &Context, union_size: u32) -> BasicTypeEnum<'_>
|
||||
}
|
||||
|
||||
/// The int type that the C ABI turns our RocList/RocStr into
|
||||
pub fn str_list_int(ctx: &Context, ptr_bytes: u32) -> IntType<'_> {
|
||||
match ptr_bytes {
|
||||
1 => ctx.i16_type(),
|
||||
2 => ctx.i32_type(),
|
||||
4 => ctx.i64_type(),
|
||||
8 => ctx.i128_type(),
|
||||
_ => panic!(
|
||||
"Invalid target: Roc does't support compiling to {}-bit systems.",
|
||||
ptr_bytes * 8
|
||||
),
|
||||
pub fn str_list_int(ctx: &Context, target_info: TargetInfo) -> IntType<'_> {
|
||||
match target_info.ptr_width() {
|
||||
roc_target::PtrWidth::Bytes4 => ctx.i64_type(),
|
||||
roc_target::PtrWidth::Bytes8 => ctx.i128_type(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -175,7 +175,9 @@ pub fn add_sjlj_roc_panic(env: &Env<'_, '_, '_>) {
|
||||
let buffer = crate::llvm::build::get_sjlj_buffer(env);
|
||||
|
||||
// write our error message pointer
|
||||
let index = env.ptr_int().const_int(3 * env.ptr_bytes as u64, false);
|
||||
let index = env
|
||||
.ptr_int()
|
||||
.const_int(3 * env.target_info.ptr_width() as u64, false);
|
||||
let message_buffer_raw =
|
||||
unsafe { builder.build_gep(buffer, &[index], "raw_msg_buffer_ptr") };
|
||||
let message_buffer = builder.build_bitcast(
|
||||
|
@ -18,21 +18,16 @@ use inkwell::{AddressSpace, IntPredicate};
|
||||
use roc_module::symbol::Interns;
|
||||
use roc_module::symbol::Symbol;
|
||||
use roc_mono::layout::{Builtin, Layout, LayoutIds, UnionLayout};
|
||||
use roc_target::TargetInfo;
|
||||
|
||||
/// "Infinite" reference count, for static values
|
||||
/// Ref counts are encoded as negative numbers where isize::MIN represents 1
|
||||
pub const REFCOUNT_MAX: usize = 0_usize;
|
||||
|
||||
pub fn refcount_1(ctx: &Context, ptr_bytes: u32) -> IntValue<'_> {
|
||||
match ptr_bytes {
|
||||
1 => ctx.i8_type().const_int(i8::MIN as u64, false),
|
||||
2 => ctx.i16_type().const_int(i16::MIN as u64, false),
|
||||
4 => ctx.i32_type().const_int(i32::MIN as u64, false),
|
||||
8 => ctx.i64_type().const_int(i64::MIN as u64, false),
|
||||
_ => panic!(
|
||||
"Invalid target: Roc does't support compiling to {}-bit systems.",
|
||||
ptr_bytes * 8
|
||||
),
|
||||
pub fn refcount_1(ctx: &Context, target_info: TargetInfo) -> IntValue<'_> {
|
||||
match target_info.ptr_width() {
|
||||
roc_target::PtrWidth::Bytes4 => ctx.i32_type().const_int(i32::MIN as u64, false),
|
||||
roc_target::PtrWidth::Bytes8 => ctx.i64_type().const_int(i64::MIN as u64, false),
|
||||
}
|
||||
}
|
||||
|
||||
@ -98,7 +93,7 @@ impl<'ctx> PointerToRefcount<'ctx> {
|
||||
|
||||
pub fn is_1<'a, 'env>(&self, env: &Env<'a, 'ctx, 'env>) -> IntValue<'ctx> {
|
||||
let current = self.get_refcount(env);
|
||||
let one = refcount_1(env.context, env.ptr_bytes);
|
||||
let one = refcount_1(env.context, env.target_info);
|
||||
|
||||
env.builder
|
||||
.build_int_compare(IntPredicate::EQ, current, one, "is_one")
|
||||
@ -163,8 +158,8 @@ impl<'ctx> PointerToRefcount<'ctx> {
|
||||
|
||||
pub fn decrement<'a, 'env>(&self, env: &Env<'a, 'ctx, 'env>, layout: &Layout<'a>) {
|
||||
let alignment = layout
|
||||
.allocation_alignment_bytes(env.ptr_bytes)
|
||||
.max(env.ptr_bytes);
|
||||
.allocation_alignment_bytes(env.target_info)
|
||||
.max(env.target_info.ptr_width() as u32);
|
||||
|
||||
let context = env.context;
|
||||
let block = env.builder.get_insert_block().expect("to be in a function");
|
||||
@ -1192,7 +1187,7 @@ fn build_rec_union_help<'a, 'ctx, 'env>(
|
||||
|
||||
debug_assert!(arg_val.is_pointer_value());
|
||||
let current_tag_id = get_tag_id(env, fn_val, &union_layout, arg_val);
|
||||
let value_ptr = if union_layout.stores_tag_id_in_pointer(env.ptr_bytes) {
|
||||
let value_ptr = if union_layout.stores_tag_id_in_pointer(env.target_info) {
|
||||
tag_pointer_clear_tag_id(env, arg_val.into_pointer_value())
|
||||
} else {
|
||||
arg_val.into_pointer_value()
|
||||
|
@ -11,5 +11,6 @@ roc_builtins = { path = "../builtins" }
|
||||
roc_collections = { path = "../collections" }
|
||||
roc_module = { path = "../module" }
|
||||
roc_mono = { path = "../mono" }
|
||||
roc_target = { path = "../roc_target" }
|
||||
roc_std = { path = "../../roc_std" }
|
||||
roc_error_macros = { path = "../../error_macros" }
|
||||
|
@ -26,7 +26,7 @@ use crate::wasm_module::{
|
||||
};
|
||||
use crate::{
|
||||
copy_memory, round_up_to_alignment, CopyMemoryConfig, Env, DEBUG_LOG_SETTINGS, MEMORY_NAME,
|
||||
PTR_SIZE, PTR_TYPE, STACK_POINTER_GLOBAL_ID, STACK_POINTER_NAME,
|
||||
PTR_SIZE, PTR_TYPE, STACK_POINTER_GLOBAL_ID, STACK_POINTER_NAME, TARGET_INFO,
|
||||
};
|
||||
|
||||
/// The memory address where the constants data will be loaded during module instantiation.
|
||||
@ -943,7 +943,7 @@ impl<'a> WasmBackend<'a> {
|
||||
}
|
||||
};
|
||||
for field in field_layouts.iter().take(index as usize) {
|
||||
offset += field.stack_size(PTR_SIZE);
|
||||
offset += field.stack_size(TARGET_INFO);
|
||||
}
|
||||
self.storage
|
||||
.copy_value_from_memory(&mut self.code_builder, sym, local_id, offset);
|
||||
@ -1010,11 +1010,11 @@ impl<'a> WasmBackend<'a> {
|
||||
elems: &'a [ListLiteralElement<'a>],
|
||||
) {
|
||||
if let StoredValue::StackMemory { location, .. } = storage {
|
||||
let size = elem_layout.stack_size(PTR_SIZE) * (elems.len() as u32);
|
||||
let size = elem_layout.stack_size(TARGET_INFO) * (elems.len() as u32);
|
||||
|
||||
// Allocate heap space and store its address in a local variable
|
||||
let heap_local_id = self.storage.create_anonymous_local(PTR_TYPE);
|
||||
let heap_alignment = elem_layout.alignment_bytes(PTR_SIZE);
|
||||
let heap_alignment = elem_layout.alignment_bytes(TARGET_INFO);
|
||||
self.allocate_with_refcount(Some(size), heap_alignment, 1);
|
||||
self.code_builder.set_local(heap_local_id);
|
||||
|
||||
@ -1099,9 +1099,9 @@ impl<'a> WasmBackend<'a> {
|
||||
return;
|
||||
}
|
||||
|
||||
let stores_tag_id_as_data = union_layout.stores_tag_id_as_data(PTR_SIZE);
|
||||
let stores_tag_id_in_pointer = union_layout.stores_tag_id_in_pointer(PTR_SIZE);
|
||||
let (data_size, data_alignment) = union_layout.data_size_and_alignment(PTR_SIZE);
|
||||
let stores_tag_id_as_data = union_layout.stores_tag_id_as_data(TARGET_INFO);
|
||||
let stores_tag_id_in_pointer = union_layout.stores_tag_id_in_pointer(TARGET_INFO);
|
||||
let (data_size, data_alignment) = union_layout.data_size_and_alignment(TARGET_INFO);
|
||||
|
||||
// We're going to use the pointer many times, so put it in a local variable
|
||||
let stored_with_local =
|
||||
@ -1138,7 +1138,7 @@ impl<'a> WasmBackend<'a> {
|
||||
if stores_tag_id_as_data {
|
||||
let id_offset = data_offset + data_size - data_alignment;
|
||||
|
||||
let id_align = union_layout.tag_id_builtin().alignment_bytes(PTR_SIZE);
|
||||
let id_align = union_layout.tag_id_builtin().alignment_bytes(TARGET_INFO);
|
||||
let id_align = Align::from(id_align);
|
||||
|
||||
self.code_builder.get_local(local_id);
|
||||
@ -1218,11 +1218,11 @@ impl<'a> WasmBackend<'a> {
|
||||
}
|
||||
};
|
||||
|
||||
if union_layout.stores_tag_id_as_data(PTR_SIZE) {
|
||||
let (data_size, data_alignment) = union_layout.data_size_and_alignment(PTR_SIZE);
|
||||
if union_layout.stores_tag_id_as_data(TARGET_INFO) {
|
||||
let (data_size, data_alignment) = union_layout.data_size_and_alignment(TARGET_INFO);
|
||||
let id_offset = data_size - data_alignment;
|
||||
|
||||
let id_align = union_layout.tag_id_builtin().alignment_bytes(PTR_SIZE);
|
||||
let id_align = union_layout.tag_id_builtin().alignment_bytes(TARGET_INFO);
|
||||
let id_align = Align::from(id_align);
|
||||
|
||||
self.storage
|
||||
@ -1237,7 +1237,7 @@ impl<'a> WasmBackend<'a> {
|
||||
Builtin::Int(IntWidth::U64) => self.code_builder.i64_load(id_align, id_offset),
|
||||
x => internal_error!("Unexpected layout for tag union id {:?}", x),
|
||||
}
|
||||
} else if union_layout.stores_tag_id_in_pointer(PTR_SIZE) {
|
||||
} else if union_layout.stores_tag_id_in_pointer(TARGET_INFO) {
|
||||
self.storage
|
||||
.load_symbols(&mut self.code_builder, &[structure]);
|
||||
self.code_builder.i32_const(3);
|
||||
@ -1284,7 +1284,7 @@ impl<'a> WasmBackend<'a> {
|
||||
let field_offset: u32 = field_layouts
|
||||
.iter()
|
||||
.take(index as usize)
|
||||
.map(|field_layout| field_layout.stack_size(PTR_SIZE))
|
||||
.map(|field_layout| field_layout.stack_size(TARGET_INFO))
|
||||
.sum();
|
||||
|
||||
// Get pointer and offset to the tag's data
|
||||
@ -1304,7 +1304,7 @@ impl<'a> WasmBackend<'a> {
|
||||
}
|
||||
};
|
||||
|
||||
let stores_tag_id_in_pointer = union_layout.stores_tag_id_in_pointer(PTR_SIZE);
|
||||
let stores_tag_id_in_pointer = union_layout.stores_tag_id_in_pointer(TARGET_INFO);
|
||||
|
||||
let from_ptr = if stores_tag_id_in_pointer {
|
||||
let ptr = self.storage.create_anonymous_local(ValueType::I32);
|
||||
|
@ -2,7 +2,7 @@ use roc_builtins::bitcode::{FloatWidth, IntWidth};
|
||||
use roc_mono::layout::{Layout, UnionLayout};
|
||||
|
||||
use crate::wasm_module::ValueType;
|
||||
use crate::{PTR_SIZE, PTR_TYPE};
|
||||
use crate::{PTR_SIZE, PTR_TYPE, TARGET_INFO};
|
||||
|
||||
/// Manually keep up to date with the Zig version we are using for builtins
|
||||
pub const BUILTINS_ZIG_VERSION: ZigVersion = ZigVersion::Zig8;
|
||||
@ -47,8 +47,8 @@ impl WasmLayout {
|
||||
use UnionLayout::*;
|
||||
use ValueType::*;
|
||||
|
||||
let size = layout.stack_size(PTR_SIZE);
|
||||
let alignment_bytes = layout.alignment_bytes(PTR_SIZE);
|
||||
let size = layout.stack_size(TARGET_INFO);
|
||||
let alignment_bytes = layout.alignment_bytes(TARGET_INFO);
|
||||
|
||||
match layout {
|
||||
Layout::Builtin(Int(int_width)) => {
|
||||
|
@ -6,20 +6,29 @@ pub mod wasm_module;
|
||||
|
||||
use bumpalo::{self, collections::Vec, Bump};
|
||||
|
||||
use roc_builtins::bitcode::IntWidth;
|
||||
use roc_collections::all::{MutMap, MutSet};
|
||||
use roc_module::low_level::LowLevelWrapperType;
|
||||
use roc_module::symbol::{Interns, ModuleId, Symbol};
|
||||
use roc_mono::code_gen_help::CodeGenHelp;
|
||||
use roc_mono::ir::{Proc, ProcLayout};
|
||||
use roc_mono::layout::LayoutIds;
|
||||
use roc_target::TargetInfo;
|
||||
|
||||
use crate::backend::WasmBackend;
|
||||
use crate::wasm_module::{
|
||||
Align, CodeBuilder, Export, ExportType, LocalId, SymInfo, ValueType, WasmModule,
|
||||
};
|
||||
|
||||
const PTR_SIZE: u32 = 4;
|
||||
const TARGET_INFO: TargetInfo = TargetInfo::default_wasm32();
|
||||
const PTR_SIZE: u32 = {
|
||||
let value = TARGET_INFO.ptr_width() as u32;
|
||||
|
||||
// const assert that our pointer width is actually 4
|
||||
// the code relies on the pointer width being exactly 4
|
||||
assert!(value == 4);
|
||||
|
||||
value
|
||||
};
|
||||
const PTR_TYPE: ValueType = ValueType::I32;
|
||||
|
||||
pub const STACK_POINTER_GLOBAL_ID: u32 = 0;
|
||||
@ -111,7 +120,7 @@ pub fn build_module_without_test_wrapper<'a>(
|
||||
proc_symbols,
|
||||
initial_module,
|
||||
fn_index_offset,
|
||||
CodeGenHelp::new(env.arena, IntWidth::I32, env.module_id),
|
||||
CodeGenHelp::new(env.arena, TargetInfo::default_wasm32(), env.module_id),
|
||||
);
|
||||
|
||||
if DEBUG_LOG_SETTINGS.user_procs_ir {
|
||||
|
@ -18,6 +18,7 @@ roc_unify = { path = "../unify" }
|
||||
roc_parse = { path = "../parse" }
|
||||
roc_solve = { path = "../solve" }
|
||||
roc_mono = { path = "../mono" }
|
||||
roc_target = { path = "../roc_target" }
|
||||
roc_reporting = { path = "../../reporting" }
|
||||
morphic_lib = { path = "../../vendor/morphic_lib" }
|
||||
ven_pretty = { path = "../../vendor/pretty" }
|
||||
|
@ -32,6 +32,7 @@ use roc_parse::parser::{FileError, Parser, SyntaxError};
|
||||
use roc_region::all::{LineInfo, Loc, Region};
|
||||
use roc_solve::module::SolvedModule;
|
||||
use roc_solve::solve;
|
||||
use roc_target::TargetInfo;
|
||||
use roc_types::solved_types::Solved;
|
||||
use roc_types::subs::{Subs, VarStore, Variable};
|
||||
use roc_types::types::{Alias, Type};
|
||||
@ -878,7 +879,7 @@ struct State<'a> {
|
||||
pub exposed_types: SubsByModule,
|
||||
pub output_path: Option<&'a str>,
|
||||
pub platform_path: PlatformPath<'a>,
|
||||
pub ptr_bytes: u32,
|
||||
pub target_info: TargetInfo,
|
||||
|
||||
pub module_cache: ModuleCache<'a>,
|
||||
pub dependencies: Dependencies<'a>,
|
||||
@ -1083,7 +1084,7 @@ pub fn load_and_typecheck<'a, F>(
|
||||
stdlib: &'a StdLib,
|
||||
src_dir: &Path,
|
||||
exposed_types: SubsByModule,
|
||||
ptr_bytes: u32,
|
||||
target_info: TargetInfo,
|
||||
look_up_builtin: F,
|
||||
) -> Result<LoadedModule, LoadingProblem<'a>>
|
||||
where
|
||||
@ -1100,7 +1101,7 @@ where
|
||||
src_dir,
|
||||
exposed_types,
|
||||
Phase::SolveTypes,
|
||||
ptr_bytes,
|
||||
target_info,
|
||||
look_up_builtin,
|
||||
)? {
|
||||
Monomorphized(_) => unreachable!(""),
|
||||
@ -1115,7 +1116,7 @@ pub fn load_and_monomorphize<'a, F>(
|
||||
stdlib: &'a StdLib,
|
||||
src_dir: &Path,
|
||||
exposed_types: SubsByModule,
|
||||
ptr_bytes: u32,
|
||||
target_info: TargetInfo,
|
||||
look_up_builtin: F,
|
||||
) -> Result<MonomorphizedModule<'a>, LoadingProblem<'a>>
|
||||
where
|
||||
@ -1132,7 +1133,7 @@ where
|
||||
src_dir,
|
||||
exposed_types,
|
||||
Phase::MakeSpecializations,
|
||||
ptr_bytes,
|
||||
target_info,
|
||||
look_up_builtin,
|
||||
)? {
|
||||
Monomorphized(module) => Ok(module),
|
||||
@ -1148,7 +1149,7 @@ pub fn load_and_monomorphize_from_str<'a, F>(
|
||||
stdlib: &'a StdLib,
|
||||
src_dir: &Path,
|
||||
exposed_types: SubsByModule,
|
||||
ptr_bytes: u32,
|
||||
target_info: TargetInfo,
|
||||
look_up_builtin: F,
|
||||
) -> Result<MonomorphizedModule<'a>, LoadingProblem<'a>>
|
||||
where
|
||||
@ -1165,7 +1166,7 @@ where
|
||||
src_dir,
|
||||
exposed_types,
|
||||
Phase::MakeSpecializations,
|
||||
ptr_bytes,
|
||||
target_info,
|
||||
look_up_builtin,
|
||||
)? {
|
||||
Monomorphized(module) => Ok(module),
|
||||
@ -1317,7 +1318,7 @@ fn load<'a, F>(
|
||||
src_dir: &Path,
|
||||
exposed_types: SubsByModule,
|
||||
goal_phase: Phase,
|
||||
ptr_bytes: u32,
|
||||
target_info: TargetInfo,
|
||||
look_up_builtins: F,
|
||||
) -> Result<LoadResult<'a>, LoadingProblem<'a>>
|
||||
where
|
||||
@ -1433,7 +1434,7 @@ where
|
||||
worker_arena,
|
||||
src_dir,
|
||||
msg_tx.clone(),
|
||||
ptr_bytes,
|
||||
target_info,
|
||||
look_up_builtins,
|
||||
);
|
||||
|
||||
@ -1474,7 +1475,7 @@ where
|
||||
|
||||
let mut state = State {
|
||||
root_id,
|
||||
ptr_bytes,
|
||||
target_info,
|
||||
platform_data: None,
|
||||
goal_phase,
|
||||
stdlib,
|
||||
@ -1999,7 +2000,7 @@ fn update<'a>(
|
||||
let layout_cache = state
|
||||
.layout_caches
|
||||
.pop()
|
||||
.unwrap_or_else(|| LayoutCache::new(state.ptr_bytes));
|
||||
.unwrap_or_else(|| LayoutCache::new(state.target_info));
|
||||
|
||||
let typechecked = TypeCheckedModule {
|
||||
module_id,
|
||||
@ -3812,7 +3813,7 @@ fn make_specializations<'a>(
|
||||
mut layout_cache: LayoutCache<'a>,
|
||||
specializations_we_must_make: Vec<ExternalSpecializations>,
|
||||
mut module_timing: ModuleTiming,
|
||||
ptr_bytes: u32,
|
||||
target_info: TargetInfo,
|
||||
) -> Msg<'a> {
|
||||
let make_specializations_start = SystemTime::now();
|
||||
let mut mono_problems = Vec::new();
|
||||
@ -3824,7 +3825,7 @@ fn make_specializations<'a>(
|
||||
subs: &mut subs,
|
||||
home,
|
||||
ident_ids: &mut ident_ids,
|
||||
ptr_bytes,
|
||||
target_info,
|
||||
update_mode_ids: &mut update_mode_ids,
|
||||
// call_specialization_counter=0 is reserved
|
||||
call_specialization_counter: 1,
|
||||
@ -3895,7 +3896,7 @@ fn build_pending_specializations<'a>(
|
||||
decls: Vec<Declaration>,
|
||||
mut module_timing: ModuleTiming,
|
||||
mut layout_cache: LayoutCache<'a>,
|
||||
ptr_bytes: u32,
|
||||
target_info: TargetInfo,
|
||||
// TODO remove
|
||||
exposed_to_host: ExposedToHost,
|
||||
) -> Msg<'a> {
|
||||
@ -3920,7 +3921,7 @@ fn build_pending_specializations<'a>(
|
||||
subs: &mut subs,
|
||||
home,
|
||||
ident_ids: &mut ident_ids,
|
||||
ptr_bytes,
|
||||
target_info,
|
||||
update_mode_ids: &mut update_mode_ids,
|
||||
// call_specialization_counter=0 is reserved
|
||||
call_specialization_counter: 1,
|
||||
@ -4128,7 +4129,7 @@ fn run_task<'a, F>(
|
||||
arena: &'a Bump,
|
||||
src_dir: &Path,
|
||||
msg_tx: MsgSender<'a>,
|
||||
ptr_bytes: u32,
|
||||
target_info: TargetInfo,
|
||||
look_up_builtins: F,
|
||||
) -> Result<(), LoadingProblem<'a>>
|
||||
where
|
||||
@ -4206,7 +4207,7 @@ where
|
||||
decls,
|
||||
module_timing,
|
||||
layout_cache,
|
||||
ptr_bytes,
|
||||
target_info,
|
||||
exposed_to_host,
|
||||
)),
|
||||
MakeSpecializations {
|
||||
@ -4226,7 +4227,7 @@ where
|
||||
layout_cache,
|
||||
specializations_we_must_make,
|
||||
module_timing,
|
||||
ptr_bytes,
|
||||
target_info,
|
||||
)),
|
||||
}?;
|
||||
|
||||
|
@ -28,6 +28,8 @@ mod test_load {
|
||||
use roc_types::subs::Subs;
|
||||
use std::collections::HashMap;
|
||||
|
||||
const TARGET_INFO: roc_target::TargetInfo = roc_target::TargetInfo::default_x86_64();
|
||||
|
||||
// HELPERS
|
||||
|
||||
fn multiple_modules(files: Vec<(&str, &str)>) -> Result<LoadedModule, String> {
|
||||
@ -110,7 +112,7 @@ mod test_load {
|
||||
arena.alloc(stdlib),
|
||||
dir.path(),
|
||||
exposed_types,
|
||||
8,
|
||||
TARGET_INFO,
|
||||
builtin_defs_map,
|
||||
)
|
||||
};
|
||||
@ -134,7 +136,7 @@ mod test_load {
|
||||
arena.alloc(roc_builtins::std::standard_stdlib()),
|
||||
src_dir.as_path(),
|
||||
subs_by_module,
|
||||
8,
|
||||
TARGET_INFO,
|
||||
builtin_defs_map,
|
||||
);
|
||||
let mut loaded_module = match loaded {
|
||||
@ -305,7 +307,7 @@ mod test_load {
|
||||
arena.alloc(roc_builtins::std::standard_stdlib()),
|
||||
src_dir.as_path(),
|
||||
subs_by_module,
|
||||
8,
|
||||
TARGET_INFO,
|
||||
builtin_defs_map,
|
||||
);
|
||||
|
||||
|
@ -16,6 +16,7 @@ roc_solve = { path = "../solve" }
|
||||
roc_std = { path = "../../roc_std" }
|
||||
roc_problem = { path = "../problem" }
|
||||
roc_builtins = { path = "../builtins" }
|
||||
roc_target = { path = "../roc_target" }
|
||||
ven_pretty = { path = "../../vendor/pretty" }
|
||||
morphic_lib = { path = "../../vendor/morphic_lib" }
|
||||
bumpalo = { version = "3.8.0", features = ["collections"] }
|
||||
|
@ -590,7 +590,9 @@ fn eq_list<'a>(
|
||||
|
||||
// let size = literal int
|
||||
let size = root.create_symbol(ident_ids, "size");
|
||||
let size_expr = Expr::Literal(Literal::Int(elem_layout.stack_size(root.ptr_size) as i128));
|
||||
let size_expr = Expr::Literal(Literal::Int(
|
||||
elem_layout.stack_size(root.target_info) as i128
|
||||
));
|
||||
let size_stmt = |next| Stmt::Let(size, size_expr, layout_isize, next);
|
||||
|
||||
// let list_size = len_1 * size
|
||||
|
@ -1,9 +1,9 @@
|
||||
use bumpalo::collections::vec::Vec;
|
||||
use bumpalo::Bump;
|
||||
use roc_builtins::bitcode::IntWidth;
|
||||
use roc_module::ident::Ident;
|
||||
use roc_module::low_level::LowLevel;
|
||||
use roc_module::symbol::{IdentIds, ModuleId, Symbol};
|
||||
use roc_target::TargetInfo;
|
||||
|
||||
use crate::ir::{
|
||||
Call, CallSpecId, CallType, Expr, HostExposedLayouts, JoinPointId, ModifyRc, Proc, ProcLayout,
|
||||
@ -74,19 +74,19 @@ pub struct Context<'a> {
|
||||
pub struct CodeGenHelp<'a> {
|
||||
arena: &'a Bump,
|
||||
home: ModuleId,
|
||||
ptr_size: u32,
|
||||
target_info: TargetInfo,
|
||||
layout_isize: Layout<'a>,
|
||||
specializations: Vec<'a, Specialization<'a>>,
|
||||
debug_recursion_depth: usize,
|
||||
}
|
||||
|
||||
impl<'a> CodeGenHelp<'a> {
|
||||
pub fn new(arena: &'a Bump, intwidth_isize: IntWidth, home: ModuleId) -> Self {
|
||||
pub fn new(arena: &'a Bump, target_info: TargetInfo, home: ModuleId) -> Self {
|
||||
CodeGenHelp {
|
||||
arena,
|
||||
home,
|
||||
ptr_size: intwidth_isize.stack_size(),
|
||||
layout_isize: Layout::Builtin(Builtin::Int(intwidth_isize)),
|
||||
target_info,
|
||||
layout_isize: Layout::usize(target_info),
|
||||
specializations: Vec::with_capacity_in(16, arena),
|
||||
debug_recursion_depth: 0,
|
||||
}
|
||||
|
@ -207,7 +207,7 @@ pub fn rc_ptr_from_data_ptr<'a>(
|
||||
|
||||
// Mask for lower bits (for tag union id)
|
||||
let mask_sym = root.create_symbol(ident_ids, "mask");
|
||||
let mask_expr = Expr::Literal(Literal::Int(-(root.ptr_size as i128)));
|
||||
let mask_expr = Expr::Literal(Literal::Int(-(root.target_info.ptr_width() as i128)));
|
||||
let mask_stmt = |next| Stmt::Let(mask_sym, mask_expr, root.layout_isize, next);
|
||||
|
||||
let masked_sym = root.create_symbol(ident_ids, "masked");
|
||||
@ -222,7 +222,7 @@ pub fn rc_ptr_from_data_ptr<'a>(
|
||||
|
||||
// Pointer size constant
|
||||
let ptr_size_sym = root.create_symbol(ident_ids, "ptr_size");
|
||||
let ptr_size_expr = Expr::Literal(Literal::Int(root.ptr_size as i128));
|
||||
let ptr_size_expr = Expr::Literal(Literal::Int(root.target_info.ptr_width() as i128));
|
||||
let ptr_size_stmt = |next| Stmt::Let(ptr_size_sym, ptr_size_expr, root.layout_isize, next);
|
||||
|
||||
// Refcount address
|
||||
@ -382,7 +382,7 @@ fn refcount_str<'a>(
|
||||
|
||||
// A pointer to the refcount value itself
|
||||
let rc_ptr = root.create_symbol(ident_ids, "rc_ptr");
|
||||
let alignment = root.ptr_size;
|
||||
let alignment = root.target_info.ptr_width() as u32;
|
||||
|
||||
let ret_unit_stmt = rc_return_stmt(root, ident_ids, ctx);
|
||||
let mod_rc_stmt = modify_refcount(
|
||||
@ -487,7 +487,7 @@ fn refcount_list<'a>(
|
||||
//
|
||||
|
||||
let rc_ptr = root.create_symbol(ident_ids, "rc_ptr");
|
||||
let alignment = layout.alignment_bytes(root.ptr_size);
|
||||
let alignment = layout.alignment_bytes(root.target_info);
|
||||
|
||||
let ret_stmt = rc_return_stmt(root, ident_ids, ctx);
|
||||
let modify_list = modify_refcount(
|
||||
@ -584,7 +584,9 @@ fn refcount_list_elems<'a>(
|
||||
|
||||
// let size = literal int
|
||||
let elem_size = root.create_symbol(ident_ids, "elem_size");
|
||||
let elem_size_expr = Expr::Literal(Literal::Int(elem_layout.stack_size(root.ptr_size) as i128));
|
||||
let elem_size_expr = Expr::Literal(Literal::Int(
|
||||
elem_layout.stack_size(root.target_info) as i128
|
||||
));
|
||||
let elem_size_stmt = |next| Stmt::Let(elem_size, elem_size_expr, layout_isize, next);
|
||||
|
||||
// let list_size = len * size
|
||||
@ -972,7 +974,7 @@ fn refcount_union_rec<'a>(
|
||||
let rc_structure_stmt = {
|
||||
let rc_ptr = root.create_symbol(ident_ids, "rc_ptr");
|
||||
|
||||
let alignment = Layout::Union(union_layout).alignment_bytes(root.ptr_size);
|
||||
let alignment = Layout::Union(union_layout).alignment_bytes(root.target_info);
|
||||
let ret_stmt = rc_return_stmt(root, ident_ids, ctx);
|
||||
let modify_structure_stmt = modify_refcount(
|
||||
root,
|
||||
@ -988,7 +990,7 @@ fn refcount_union_rec<'a>(
|
||||
ident_ids,
|
||||
structure,
|
||||
rc_ptr,
|
||||
union_layout.stores_tag_id_in_pointer(root.ptr_size),
|
||||
union_layout.stores_tag_id_in_pointer(root.target_info),
|
||||
root.arena.alloc(modify_structure_stmt),
|
||||
)
|
||||
};
|
||||
@ -1080,7 +1082,7 @@ fn refcount_union_tailrec<'a>(
|
||||
)
|
||||
};
|
||||
|
||||
let alignment = layout.alignment_bytes(root.ptr_size);
|
||||
let alignment = layout.alignment_bytes(root.target_info);
|
||||
let modify_structure_stmt = modify_refcount(
|
||||
root,
|
||||
ident_ids,
|
||||
@ -1095,7 +1097,7 @@ fn refcount_union_tailrec<'a>(
|
||||
ident_ids,
|
||||
current,
|
||||
rc_ptr,
|
||||
union_layout.stores_tag_id_in_pointer(root.ptr_size),
|
||||
union_layout.stores_tag_id_in_pointer(root.target_info),
|
||||
root.arena.alloc(modify_structure_stmt),
|
||||
)
|
||||
};
|
||||
|
@ -16,6 +16,7 @@ use roc_module::symbol::{IdentIds, ModuleId, Symbol};
|
||||
use roc_problem::can::RuntimeError;
|
||||
use roc_region::all::{Loc, Region};
|
||||
use roc_std::RocDec;
|
||||
use roc_target::TargetInfo;
|
||||
use roc_types::subs::{Content, FlatType, StorageSubs, Subs, Variable, VariableSubsSlice};
|
||||
use std::collections::HashMap;
|
||||
use ven_pretty::{BoxAllocator, DocAllocator, DocBuilder};
|
||||
@ -1071,7 +1072,7 @@ pub struct Env<'a, 'i> {
|
||||
pub problems: &'i mut std::vec::Vec<MonoProblem>,
|
||||
pub home: ModuleId,
|
||||
pub ident_ids: &'i mut IdentIds,
|
||||
pub ptr_bytes: u32,
|
||||
pub target_info: TargetInfo,
|
||||
pub update_mode_ids: &'i mut UpdateModeIds,
|
||||
pub call_specialization_counter: u32,
|
||||
}
|
||||
@ -2471,7 +2472,7 @@ fn specialize_external<'a>(
|
||||
env.arena,
|
||||
);
|
||||
|
||||
let ptr_bytes = env.ptr_bytes;
|
||||
let ptr_bytes = env.target_info;
|
||||
|
||||
combined.sort_by(|(_, layout1), (_, layout2)| {
|
||||
let size1 = layout1.alignment_bytes(ptr_bytes);
|
||||
@ -2504,7 +2505,7 @@ fn specialize_external<'a>(
|
||||
env.arena,
|
||||
);
|
||||
|
||||
let ptr_bytes = env.ptr_bytes;
|
||||
let ptr_bytes = env.target_info;
|
||||
|
||||
combined.sort_by(|(_, layout1), (_, layout2)| {
|
||||
let size1 = layout1.alignment_bytes(ptr_bytes);
|
||||
@ -3009,14 +3010,14 @@ fn try_make_literal<'a>(
|
||||
|
||||
match can_expr {
|
||||
Int(_, precision, _, int) => {
|
||||
match num_argument_to_int_or_float(env.subs, env.ptr_bytes, *precision, false) {
|
||||
match num_argument_to_int_or_float(env.subs, env.target_info, *precision, false) {
|
||||
IntOrFloat::Int(_) => Some(Literal::Int(*int)),
|
||||
_ => unreachable!("unexpected float precision for integer"),
|
||||
}
|
||||
}
|
||||
|
||||
Float(_, precision, float_str, float) => {
|
||||
match num_argument_to_int_or_float(env.subs, env.ptr_bytes, *precision, true) {
|
||||
match num_argument_to_int_or_float(env.subs, env.target_info, *precision, true) {
|
||||
IntOrFloat::Float(_) => Some(Literal::Float(*float)),
|
||||
IntOrFloat::DecimalFloatType => {
|
||||
let dec = match RocDec::from_str(float_str) {
|
||||
@ -3037,7 +3038,7 @@ fn try_make_literal<'a>(
|
||||
// Str(string) => Some(Literal::Str(env.arena.alloc(string))),
|
||||
Num(var, num_str, num) => {
|
||||
// first figure out what kind of number this is
|
||||
match num_argument_to_int_or_float(env.subs, env.ptr_bytes, *var, false) {
|
||||
match num_argument_to_int_or_float(env.subs, env.target_info, *var, false) {
|
||||
IntOrFloat::Int(_) => Some(Literal::Int((*num).into())),
|
||||
IntOrFloat::Float(_) => Some(Literal::Float(*num as f64)),
|
||||
IntOrFloat::DecimalFloatType => {
|
||||
@ -3072,7 +3073,7 @@ pub fn with_hole<'a>(
|
||||
|
||||
match can_expr {
|
||||
Int(_, precision, _, int) => {
|
||||
match num_argument_to_int_or_float(env.subs, env.ptr_bytes, precision, false) {
|
||||
match num_argument_to_int_or_float(env.subs, env.target_info, precision, false) {
|
||||
IntOrFloat::Int(precision) => Stmt::Let(
|
||||
assigned,
|
||||
Expr::Literal(Literal::Int(int)),
|
||||
@ -3084,7 +3085,7 @@ pub fn with_hole<'a>(
|
||||
}
|
||||
|
||||
Float(_, precision, float_str, float) => {
|
||||
match num_argument_to_int_or_float(env.subs, env.ptr_bytes, precision, true) {
|
||||
match num_argument_to_int_or_float(env.subs, env.target_info, precision, true) {
|
||||
IntOrFloat::Float(precision) => Stmt::Let(
|
||||
assigned,
|
||||
Expr::Literal(Literal::Float(float)),
|
||||
@ -3116,7 +3117,7 @@ pub fn with_hole<'a>(
|
||||
|
||||
Num(var, num_str, num) => {
|
||||
// first figure out what kind of number this is
|
||||
match num_argument_to_int_or_float(env.subs, env.ptr_bytes, var, false) {
|
||||
match num_argument_to_int_or_float(env.subs, env.target_info, var, false) {
|
||||
IntOrFloat::Int(precision) => Stmt::Let(
|
||||
assigned,
|
||||
Expr::Literal(Literal::Int(num.into())),
|
||||
@ -3393,7 +3394,7 @@ pub fn with_hole<'a>(
|
||||
env.arena,
|
||||
record_var,
|
||||
env.subs,
|
||||
env.ptr_bytes,
|
||||
env.target_info,
|
||||
) {
|
||||
Ok(fields) => fields,
|
||||
Err(_) => return Stmt::RuntimeError("Can't create record with improper layout"),
|
||||
@ -3754,7 +3755,7 @@ pub fn with_hole<'a>(
|
||||
env.arena,
|
||||
record_var,
|
||||
env.subs,
|
||||
env.ptr_bytes,
|
||||
env.target_info,
|
||||
) {
|
||||
Ok(fields) => fields,
|
||||
Err(_) => return Stmt::RuntimeError("Can't access record with improper layout"),
|
||||
@ -3911,7 +3912,7 @@ pub fn with_hole<'a>(
|
||||
env.arena,
|
||||
record_var,
|
||||
env.subs,
|
||||
env.ptr_bytes,
|
||||
env.target_info,
|
||||
) {
|
||||
Ok(fields) => fields,
|
||||
Err(_) => return Stmt::RuntimeError("Can't update record with improper layout"),
|
||||
@ -4586,7 +4587,7 @@ fn construct_closure_data<'a>(
|
||||
env.arena,
|
||||
);
|
||||
|
||||
let ptr_bytes = env.ptr_bytes;
|
||||
let ptr_bytes = env.target_info;
|
||||
|
||||
combined.sort_by(|(_, layout1), (_, layout2)| {
|
||||
let size1 = layout1.alignment_bytes(ptr_bytes);
|
||||
@ -4617,7 +4618,7 @@ fn construct_closure_data<'a>(
|
||||
env.arena,
|
||||
);
|
||||
|
||||
let ptr_bytes = env.ptr_bytes;
|
||||
let ptr_bytes = env.target_info;
|
||||
|
||||
combined.sort_by(|(_, layout1), (_, layout2)| {
|
||||
let size1 = layout1.alignment_bytes(ptr_bytes);
|
||||
@ -4692,7 +4693,7 @@ fn convert_tag_union<'a>(
|
||||
) -> Stmt<'a> {
|
||||
use crate::layout::UnionVariant::*;
|
||||
let res_variant =
|
||||
crate::layout::union_sorted_tags(env.arena, variant_var, env.subs, env.ptr_bytes);
|
||||
crate::layout::union_sorted_tags(env.arena, variant_var, env.subs, env.target_info);
|
||||
let variant = match res_variant {
|
||||
Ok(cached) => cached,
|
||||
Err(LayoutProblem::UnresolvedTypeVar(_)) => {
|
||||
@ -5035,7 +5036,7 @@ fn sorted_field_symbols<'a>(
|
||||
}
|
||||
};
|
||||
|
||||
let alignment = layout.alignment_bytes(env.ptr_bytes);
|
||||
let alignment = layout.alignment_bytes(env.target_info);
|
||||
|
||||
let symbol = possible_reuse_symbol(env, procs, &arg.value);
|
||||
field_symbols_temp.push((alignment, symbol, ((var, arg), &*env.arena.alloc(symbol))));
|
||||
@ -5120,7 +5121,7 @@ fn register_capturing_closure<'a>(
|
||||
|
||||
let captured_symbols = match *env.subs.get_content_without_compacting(function_type) {
|
||||
Content::Structure(FlatType::Func(_, closure_var, _)) => {
|
||||
match LambdaSet::from_var(env.arena, env.subs, closure_var, env.ptr_bytes) {
|
||||
match LambdaSet::from_var(env.arena, env.subs, closure_var, env.target_info) {
|
||||
Ok(lambda_set) => {
|
||||
if let Layout::Struct(&[]) = lambda_set.runtime_representation() {
|
||||
CapturedSymbols::None
|
||||
@ -7621,7 +7622,7 @@ fn from_can_pattern_help<'a>(
|
||||
Underscore => Ok(Pattern::Underscore),
|
||||
Identifier(symbol) => Ok(Pattern::Identifier(*symbol)),
|
||||
IntLiteral(var, _, int) => {
|
||||
match num_argument_to_int_or_float(env.subs, env.ptr_bytes, *var, false) {
|
||||
match num_argument_to_int_or_float(env.subs, env.target_info, *var, false) {
|
||||
IntOrFloat::Int(precision) => Ok(Pattern::IntLiteral(*int as i128, precision)),
|
||||
other => {
|
||||
panic!(
|
||||
@ -7633,7 +7634,7 @@ fn from_can_pattern_help<'a>(
|
||||
}
|
||||
FloatLiteral(var, float_str, float) => {
|
||||
// TODO: Can I reuse num_argument_to_int_or_float here if I pass in true?
|
||||
match num_argument_to_int_or_float(env.subs, env.ptr_bytes, *var, true) {
|
||||
match num_argument_to_int_or_float(env.subs, env.target_info, *var, true) {
|
||||
IntOrFloat::Int(_) => {
|
||||
panic!("Invalid precision for float pattern {:?}", var)
|
||||
}
|
||||
@ -7663,7 +7664,7 @@ fn from_can_pattern_help<'a>(
|
||||
Err(RuntimeError::UnsupportedPattern(*region))
|
||||
}
|
||||
NumLiteral(var, num_str, num) => {
|
||||
match num_argument_to_int_or_float(env.subs, env.ptr_bytes, *var, false) {
|
||||
match num_argument_to_int_or_float(env.subs, env.target_info, *var, false) {
|
||||
IntOrFloat::Int(precision) => Ok(Pattern::IntLiteral(*num as i128, precision)),
|
||||
IntOrFloat::Float(precision) => Ok(Pattern::FloatLiteral(*num as u64, precision)),
|
||||
IntOrFloat::DecimalFloatType => {
|
||||
@ -7686,7 +7687,7 @@ fn from_can_pattern_help<'a>(
|
||||
use crate::layout::UnionVariant::*;
|
||||
|
||||
let res_variant =
|
||||
crate::layout::union_sorted_tags(env.arena, *whole_var, env.subs, env.ptr_bytes)
|
||||
crate::layout::union_sorted_tags(env.arena, *whole_var, env.subs, env.target_info)
|
||||
.map_err(Into::into);
|
||||
|
||||
let variant = match res_variant {
|
||||
@ -7768,12 +7769,12 @@ fn from_can_pattern_help<'a>(
|
||||
arguments.sort_by(|arg1, arg2| {
|
||||
let size1 = layout_cache
|
||||
.from_var(env.arena, arg1.0, env.subs)
|
||||
.map(|x| x.alignment_bytes(env.ptr_bytes))
|
||||
.map(|x| x.alignment_bytes(env.target_info))
|
||||
.unwrap_or(0);
|
||||
|
||||
let size2 = layout_cache
|
||||
.from_var(env.arena, arg2.0, env.subs)
|
||||
.map(|x| x.alignment_bytes(env.ptr_bytes))
|
||||
.map(|x| x.alignment_bytes(env.target_info))
|
||||
.unwrap_or(0);
|
||||
|
||||
size2.cmp(&size1)
|
||||
@ -7806,8 +7807,8 @@ fn from_can_pattern_help<'a>(
|
||||
let layout2 =
|
||||
layout_cache.from_var(env.arena, arg2.0, env.subs).unwrap();
|
||||
|
||||
let size1 = layout1.alignment_bytes(env.ptr_bytes);
|
||||
let size2 = layout2.alignment_bytes(env.ptr_bytes);
|
||||
let size1 = layout1.alignment_bytes(env.target_info);
|
||||
let size2 = layout2.alignment_bytes(env.target_info);
|
||||
|
||||
size2.cmp(&size1)
|
||||
});
|
||||
@ -8107,7 +8108,7 @@ fn from_can_pattern_help<'a>(
|
||||
} => {
|
||||
// sorted fields based on the type
|
||||
let sorted_fields =
|
||||
crate::layout::sort_record_fields(env.arena, *whole_var, env.subs, env.ptr_bytes)
|
||||
crate::layout::sort_record_fields(env.arena, *whole_var, env.subs, env.target_info)
|
||||
.map_err(RuntimeError::from)?;
|
||||
|
||||
// sorted fields based on the destruct
|
||||
@ -8259,7 +8260,7 @@ pub enum IntOrFloat {
|
||||
/// Given the `a` in `Num a`, determines whether it's an int or a float
|
||||
pub fn num_argument_to_int_or_float(
|
||||
subs: &Subs,
|
||||
ptr_bytes: u32,
|
||||
target_info: TargetInfo,
|
||||
var: Variable,
|
||||
known_to_be_float: bool,
|
||||
) -> IntOrFloat {
|
||||
@ -8274,7 +8275,7 @@ pub fn num_argument_to_int_or_float(
|
||||
|
||||
// Recurse on the second argument
|
||||
let var = subs[args.variables().into_iter().next().unwrap()];
|
||||
num_argument_to_int_or_float(subs, ptr_bytes, var, false)
|
||||
num_argument_to_int_or_float(subs, target_info, var, false)
|
||||
}
|
||||
|
||||
other @ Content::Alias(symbol, args, _) => {
|
||||
@ -8292,16 +8293,15 @@ pub fn num_argument_to_int_or_float(
|
||||
|
||||
// Recurse on the second argument
|
||||
let var = subs[args.variables().into_iter().next().unwrap()];
|
||||
num_argument_to_int_or_float(subs, ptr_bytes, var, true)
|
||||
num_argument_to_int_or_float(subs, target_info, var, true)
|
||||
}
|
||||
|
||||
Symbol::NUM_DECIMAL | Symbol::NUM_AT_DECIMAL => IntOrFloat::DecimalFloatType,
|
||||
|
||||
Symbol::NUM_NAT | Symbol::NUM_NATURAL | Symbol::NUM_AT_NATURAL => {
|
||||
let int_width = match ptr_bytes {
|
||||
4 => IntWidth::U32,
|
||||
8 => IntWidth::U64,
|
||||
_ => panic!("unsupported word size"),
|
||||
let int_width = match target_info.ptr_width() {
|
||||
roc_target::PtrWidth::Bytes4 => IntWidth::U32,
|
||||
roc_target::PtrWidth::Bytes8 => IntWidth::U64,
|
||||
};
|
||||
|
||||
IntOrFloat::Int(int_width)
|
||||
|
@ -6,6 +6,7 @@ use roc_collections::all::{default_hasher, MutMap};
|
||||
use roc_module::ident::{Lowercase, TagName};
|
||||
use roc_module::symbol::{Interns, Symbol};
|
||||
use roc_problem::can::RuntimeError;
|
||||
use roc_target::TargetInfo;
|
||||
use roc_types::subs::{
|
||||
Content, FlatType, RecordFields, Subs, UnionTags, UnsortedUnionTags, Variable,
|
||||
};
|
||||
@ -123,7 +124,7 @@ impl<'a> RawFunctionLayout<'a> {
|
||||
// Nat
|
||||
Alias(Symbol::NUM_NAT, args, _) => {
|
||||
debug_assert!(args.is_empty());
|
||||
Ok(Self::ZeroArgumentThunk(Layout::usize(env.ptr_bytes)))
|
||||
Ok(Self::ZeroArgumentThunk(Layout::usize(env.target_info)))
|
||||
}
|
||||
|
||||
Alias(symbol, _, _) if symbol.is_builtin() => Ok(Self::ZeroArgumentThunk(
|
||||
@ -158,7 +159,7 @@ impl<'a> RawFunctionLayout<'a> {
|
||||
let ret = arena.alloc(ret);
|
||||
|
||||
let lambda_set =
|
||||
LambdaSet::from_var(env.arena, env.subs, closure_var, env.ptr_bytes)?;
|
||||
LambdaSet::from_var(env.arena, env.subs, closure_var, env.target_info)?;
|
||||
|
||||
Ok(Self::Function(fn_args, lambda_set, ret))
|
||||
}
|
||||
@ -360,29 +361,29 @@ impl<'a> UnionLayout<'a> {
|
||||
Layout::Builtin(self.tag_id_builtin())
|
||||
}
|
||||
|
||||
fn stores_tag_id_in_pointer_bits(tags: &[&[Layout<'a>]], ptr_bytes: u32) -> bool {
|
||||
tags.len() < ptr_bytes as usize
|
||||
fn stores_tag_id_in_pointer_bits(tags: &[&[Layout<'a>]], target_info: TargetInfo) -> bool {
|
||||
tags.len() < target_info.ptr_width() as usize
|
||||
}
|
||||
|
||||
// i.e. it is not implicit and not stored in the pointer bits
|
||||
pub fn stores_tag_id_as_data(&self, ptr_bytes: u32) -> bool {
|
||||
pub fn stores_tag_id_as_data(&self, target_info: TargetInfo) -> bool {
|
||||
match self {
|
||||
UnionLayout::NonRecursive(_) => true,
|
||||
UnionLayout::Recursive(tags)
|
||||
| UnionLayout::NullableWrapped {
|
||||
other_tags: tags, ..
|
||||
} => !Self::stores_tag_id_in_pointer_bits(tags, ptr_bytes),
|
||||
} => !Self::stores_tag_id_in_pointer_bits(tags, target_info),
|
||||
UnionLayout::NonNullableUnwrapped(_) | UnionLayout::NullableUnwrapped { .. } => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn stores_tag_id_in_pointer(&self, ptr_bytes: u32) -> bool {
|
||||
pub fn stores_tag_id_in_pointer(&self, target_info: TargetInfo) -> bool {
|
||||
match self {
|
||||
UnionLayout::NonRecursive(_) => false,
|
||||
UnionLayout::Recursive(tags)
|
||||
| UnionLayout::NullableWrapped {
|
||||
other_tags: tags, ..
|
||||
} => Self::stores_tag_id_in_pointer_bits(tags, ptr_bytes),
|
||||
} => Self::stores_tag_id_in_pointer_bits(tags, target_info),
|
||||
UnionLayout::NonNullableUnwrapped(_) | UnionLayout::NullableUnwrapped { .. } => false,
|
||||
}
|
||||
}
|
||||
@ -406,76 +407,73 @@ impl<'a> UnionLayout<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
fn tags_alignment_bytes(tags: &[&[Layout]], pointer_size: u32) -> u32 {
|
||||
fn tags_alignment_bytes(tags: &[&[Layout]], target_info: TargetInfo) -> u32 {
|
||||
tags.iter()
|
||||
.map(|fields| Layout::Struct(fields).alignment_bytes(pointer_size))
|
||||
.map(|fields| Layout::Struct(fields).alignment_bytes(target_info))
|
||||
.max()
|
||||
.unwrap_or(0)
|
||||
}
|
||||
|
||||
pub fn allocation_alignment_bytes(&self, pointer_size: u32) -> u32 {
|
||||
pub fn allocation_alignment_bytes(&self, target_info: TargetInfo) -> u32 {
|
||||
let allocation = match self {
|
||||
UnionLayout::NonRecursive(_) => unreachable!("not heap-allocated"),
|
||||
UnionLayout::Recursive(tags) => Self::tags_alignment_bytes(tags, pointer_size),
|
||||
UnionLayout::Recursive(tags) => Self::tags_alignment_bytes(tags, target_info),
|
||||
UnionLayout::NonNullableUnwrapped(fields) => {
|
||||
Layout::Struct(fields).alignment_bytes(pointer_size)
|
||||
Layout::Struct(fields).alignment_bytes(target_info)
|
||||
}
|
||||
UnionLayout::NullableWrapped { other_tags, .. } => {
|
||||
Self::tags_alignment_bytes(other_tags, pointer_size)
|
||||
Self::tags_alignment_bytes(other_tags, target_info)
|
||||
}
|
||||
UnionLayout::NullableUnwrapped { other_fields, .. } => {
|
||||
Layout::Struct(other_fields).alignment_bytes(pointer_size)
|
||||
Layout::Struct(other_fields).alignment_bytes(target_info)
|
||||
}
|
||||
};
|
||||
|
||||
// because we store a refcount, the alignment must be at least the size of a pointer
|
||||
allocation.max(pointer_size)
|
||||
allocation.max(target_info.ptr_width() as u32)
|
||||
}
|
||||
|
||||
/// Size of the data in memory, whether it's stack or heap (for non-null tag ids)
|
||||
pub fn data_size_and_alignment(&self, pointer_size: u32) -> (u32, u32) {
|
||||
let id_data_layout = if self.stores_tag_id_as_data(pointer_size) {
|
||||
pub fn data_size_and_alignment(&self, target_info: TargetInfo) -> (u32, u32) {
|
||||
let id_data_layout = if self.stores_tag_id_as_data(target_info) {
|
||||
Some(self.tag_id_layout())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
self.data_size_and_alignment_help_match(id_data_layout, pointer_size)
|
||||
self.data_size_and_alignment_help_match(id_data_layout, target_info)
|
||||
}
|
||||
|
||||
/// Size of the data before the tag_id, if it exists.
|
||||
/// Returns None if the tag_id is not stored as data in the layout.
|
||||
pub fn data_size_without_tag_id(&self, pointer_size: u32) -> Option<u32> {
|
||||
if !self.stores_tag_id_as_data(pointer_size) {
|
||||
pub fn data_size_without_tag_id(&self, target_info: TargetInfo) -> Option<u32> {
|
||||
if !self.stores_tag_id_as_data(target_info) {
|
||||
return None;
|
||||
};
|
||||
|
||||
Some(
|
||||
self.data_size_and_alignment_help_match(None, pointer_size)
|
||||
.0,
|
||||
)
|
||||
Some(self.data_size_and_alignment_help_match(None, target_info).0)
|
||||
}
|
||||
|
||||
fn data_size_and_alignment_help_match(
|
||||
&self,
|
||||
id_data_layout: Option<Layout>,
|
||||
pointer_size: u32,
|
||||
target_info: TargetInfo,
|
||||
) -> (u32, u32) {
|
||||
match self {
|
||||
Self::NonRecursive(tags) => {
|
||||
Self::data_size_and_alignment_help(tags, id_data_layout, pointer_size)
|
||||
Self::data_size_and_alignment_help(tags, id_data_layout, target_info)
|
||||
}
|
||||
Self::Recursive(tags) => {
|
||||
Self::data_size_and_alignment_help(tags, id_data_layout, pointer_size)
|
||||
Self::data_size_and_alignment_help(tags, id_data_layout, target_info)
|
||||
}
|
||||
Self::NonNullableUnwrapped(fields) => {
|
||||
Self::data_size_and_alignment_help(&[fields], id_data_layout, pointer_size)
|
||||
Self::data_size_and_alignment_help(&[fields], id_data_layout, target_info)
|
||||
}
|
||||
Self::NullableWrapped { other_tags, .. } => {
|
||||
Self::data_size_and_alignment_help(other_tags, id_data_layout, pointer_size)
|
||||
Self::data_size_and_alignment_help(other_tags, id_data_layout, target_info)
|
||||
}
|
||||
Self::NullableUnwrapped { other_fields, .. } => {
|
||||
Self::data_size_and_alignment_help(&[other_fields], id_data_layout, pointer_size)
|
||||
Self::data_size_and_alignment_help(&[other_fields], id_data_layout, target_info)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -483,7 +481,7 @@ impl<'a> UnionLayout<'a> {
|
||||
fn data_size_and_alignment_help(
|
||||
variant_field_layouts: &[&[Layout]],
|
||||
id_data_layout: Option<Layout>,
|
||||
pointer_size: u32,
|
||||
target_info: TargetInfo,
|
||||
) -> (u32, u32) {
|
||||
let mut size = 0;
|
||||
let mut alignment_bytes = 0;
|
||||
@ -497,7 +495,7 @@ impl<'a> UnionLayout<'a> {
|
||||
data = Layout::Struct(&fields_and_id);
|
||||
}
|
||||
|
||||
let (variant_size, variant_alignment) = data.stack_size_and_alignment(pointer_size);
|
||||
let (variant_size, variant_alignment) = data.stack_size_and_alignment(target_info);
|
||||
alignment_bytes = alignment_bytes.max(variant_alignment);
|
||||
size = size.max(variant_size);
|
||||
}
|
||||
@ -692,7 +690,7 @@ impl<'a> LambdaSet<'a> {
|
||||
arena: &'a Bump,
|
||||
subs: &Subs,
|
||||
closure_var: Variable,
|
||||
ptr_bytes: u32,
|
||||
target_info: TargetInfo,
|
||||
) -> Result<Self, LayoutProblem> {
|
||||
let mut tags = std::vec::Vec::new();
|
||||
match roc_types::pretty_print::chase_ext_tag_union(subs, closure_var, &mut tags) {
|
||||
@ -706,7 +704,7 @@ impl<'a> LambdaSet<'a> {
|
||||
arena,
|
||||
subs,
|
||||
seen: Vec::new_in(arena),
|
||||
ptr_bytes,
|
||||
target_info,
|
||||
};
|
||||
|
||||
for (tag_name, variables) in tags.iter() {
|
||||
@ -724,7 +722,7 @@ impl<'a> LambdaSet<'a> {
|
||||
}
|
||||
|
||||
let representation =
|
||||
arena.alloc(Self::make_representation(arena, subs, tags, ptr_bytes));
|
||||
arena.alloc(Self::make_representation(arena, subs, tags, target_info));
|
||||
|
||||
Ok(LambdaSet {
|
||||
set: set.into_bump_slice(),
|
||||
@ -747,10 +745,10 @@ impl<'a> LambdaSet<'a> {
|
||||
arena: &'a Bump,
|
||||
subs: &Subs,
|
||||
tags: std::vec::Vec<(TagName, std::vec::Vec<Variable>)>,
|
||||
ptr_bytes: u32,
|
||||
target_info: TargetInfo,
|
||||
) -> Layout<'a> {
|
||||
// otherwise, this is a closure with a payload
|
||||
let variant = union_sorted_tags_help(arena, tags, None, subs, ptr_bytes);
|
||||
let variant = union_sorted_tags_help(arena, tags, None, subs, target_info);
|
||||
|
||||
use UnionVariant::*;
|
||||
match variant {
|
||||
@ -790,8 +788,8 @@ impl<'a> LambdaSet<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn stack_size(&self, pointer_size: u32) -> u32 {
|
||||
self.representation.stack_size(pointer_size)
|
||||
pub fn stack_size(&self, target_info: TargetInfo) -> u32 {
|
||||
self.representation.stack_size(target_info)
|
||||
}
|
||||
pub fn contains_refcounted(&self) -> bool {
|
||||
self.representation.contains_refcounted()
|
||||
@ -800,8 +798,8 @@ impl<'a> LambdaSet<'a> {
|
||||
self.representation.safe_to_memcpy()
|
||||
}
|
||||
|
||||
pub fn alignment_bytes(&self, pointer_size: u32) -> u32 {
|
||||
self.representation.alignment_bytes(pointer_size)
|
||||
pub fn alignment_bytes(&self, target_info: TargetInfo) -> u32 {
|
||||
self.representation.alignment_bytes(target_info)
|
||||
}
|
||||
}
|
||||
|
||||
@ -818,7 +816,7 @@ pub enum Builtin<'a> {
|
||||
}
|
||||
|
||||
pub struct Env<'a, 'b> {
|
||||
ptr_bytes: u32,
|
||||
target_info: TargetInfo,
|
||||
arena: &'a Bump,
|
||||
seen: Vec<'a, Variable>,
|
||||
subs: &'b Subs,
|
||||
@ -890,7 +888,7 @@ impl<'a> Layout<'a> {
|
||||
}
|
||||
|
||||
Symbol::NUM_NAT | Symbol::NUM_NATURAL | Symbol::NUM_AT_NATURAL => {
|
||||
return Ok(Layout::usize(env.ptr_bytes))
|
||||
return Ok(Layout::usize(env.target_info))
|
||||
}
|
||||
|
||||
_ => Self::from_var(env, actual_var),
|
||||
@ -962,31 +960,31 @@ impl<'a> Layout<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn stack_size(&self, pointer_size: u32) -> u32 {
|
||||
let width = self.stack_size_without_alignment(pointer_size);
|
||||
let alignment = self.alignment_bytes(pointer_size);
|
||||
pub fn stack_size(&self, target_info: TargetInfo) -> u32 {
|
||||
let width = self.stack_size_without_alignment(target_info);
|
||||
let alignment = self.alignment_bytes(target_info);
|
||||
|
||||
round_up_to_alignment(width, alignment)
|
||||
}
|
||||
|
||||
pub fn stack_size_and_alignment(&self, pointer_size: u32) -> (u32, u32) {
|
||||
let width = self.stack_size_without_alignment(pointer_size);
|
||||
let alignment = self.alignment_bytes(pointer_size);
|
||||
pub fn stack_size_and_alignment(&self, target_info: TargetInfo) -> (u32, u32) {
|
||||
let width = self.stack_size_without_alignment(target_info);
|
||||
let alignment = self.alignment_bytes(target_info);
|
||||
|
||||
let size = round_up_to_alignment(width, alignment);
|
||||
(size, alignment)
|
||||
}
|
||||
|
||||
fn stack_size_without_alignment(&self, pointer_size: u32) -> u32 {
|
||||
fn stack_size_without_alignment(&self, target_info: TargetInfo) -> u32 {
|
||||
use Layout::*;
|
||||
|
||||
match self {
|
||||
Builtin(builtin) => builtin.stack_size(pointer_size),
|
||||
Builtin(builtin) => builtin.stack_size(target_info),
|
||||
Struct(fields) => {
|
||||
let mut sum = 0;
|
||||
|
||||
for field_layout in *fields {
|
||||
sum += field_layout.stack_size(pointer_size);
|
||||
sum += field_layout.stack_size(target_info);
|
||||
}
|
||||
|
||||
sum
|
||||
@ -995,26 +993,26 @@ impl<'a> Layout<'a> {
|
||||
use UnionLayout::*;
|
||||
|
||||
match variant {
|
||||
NonRecursive(_) => variant.data_size_and_alignment(pointer_size).0,
|
||||
NonRecursive(_) => variant.data_size_and_alignment(target_info).0,
|
||||
|
||||
Recursive(_)
|
||||
| NullableWrapped { .. }
|
||||
| NullableUnwrapped { .. }
|
||||
| NonNullableUnwrapped(_) => pointer_size,
|
||||
| NonNullableUnwrapped(_) => target_info.ptr_width() as u32,
|
||||
}
|
||||
}
|
||||
LambdaSet(lambda_set) => lambda_set
|
||||
.runtime_representation()
|
||||
.stack_size_without_alignment(pointer_size),
|
||||
RecursivePointer => pointer_size,
|
||||
.stack_size_without_alignment(target_info),
|
||||
RecursivePointer => target_info.ptr_width() as u32,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn alignment_bytes(&self, pointer_size: u32) -> u32 {
|
||||
pub fn alignment_bytes(&self, target_info: TargetInfo) -> u32 {
|
||||
match self {
|
||||
Layout::Struct(fields) => fields
|
||||
.iter()
|
||||
.map(|x| x.alignment_bytes(pointer_size))
|
||||
.map(|x| x.alignment_bytes(target_info))
|
||||
.max()
|
||||
.unwrap_or(0),
|
||||
|
||||
@ -1028,44 +1026,44 @@ impl<'a> Layout<'a> {
|
||||
.flat_map(|layouts| {
|
||||
layouts
|
||||
.iter()
|
||||
.map(|layout| layout.alignment_bytes(pointer_size))
|
||||
.map(|layout| layout.alignment_bytes(target_info))
|
||||
})
|
||||
.max();
|
||||
|
||||
let tag_id_builtin = variant.tag_id_builtin();
|
||||
match max_alignment {
|
||||
Some(align) => round_up_to_alignment(
|
||||
align.max(tag_id_builtin.alignment_bytes(pointer_size)),
|
||||
tag_id_builtin.alignment_bytes(pointer_size),
|
||||
align.max(tag_id_builtin.alignment_bytes(target_info)),
|
||||
tag_id_builtin.alignment_bytes(target_info),
|
||||
),
|
||||
None => {
|
||||
// none of the tags had any payload, but the tag id still contains information
|
||||
tag_id_builtin.alignment_bytes(pointer_size)
|
||||
tag_id_builtin.alignment_bytes(target_info)
|
||||
}
|
||||
}
|
||||
}
|
||||
Recursive(_)
|
||||
| NullableWrapped { .. }
|
||||
| NullableUnwrapped { .. }
|
||||
| NonNullableUnwrapped(_) => pointer_size,
|
||||
| NonNullableUnwrapped(_) => target_info.ptr_width() as u32,
|
||||
}
|
||||
}
|
||||
Layout::LambdaSet(lambda_set) => lambda_set
|
||||
.runtime_representation()
|
||||
.alignment_bytes(pointer_size),
|
||||
Layout::Builtin(builtin) => builtin.alignment_bytes(pointer_size),
|
||||
Layout::RecursivePointer => pointer_size,
|
||||
.alignment_bytes(target_info),
|
||||
Layout::Builtin(builtin) => builtin.alignment_bytes(target_info),
|
||||
Layout::RecursivePointer => target_info.ptr_width() as u32,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn allocation_alignment_bytes(&self, pointer_size: u32) -> u32 {
|
||||
pub fn allocation_alignment_bytes(&self, target_info: TargetInfo) -> u32 {
|
||||
match self {
|
||||
Layout::Builtin(builtin) => builtin.allocation_alignment_bytes(pointer_size),
|
||||
Layout::Builtin(builtin) => builtin.allocation_alignment_bytes(target_info),
|
||||
Layout::Struct(_) => unreachable!("not heap-allocated"),
|
||||
Layout::Union(union_layout) => union_layout.allocation_alignment_bytes(pointer_size),
|
||||
Layout::Union(union_layout) => union_layout.allocation_alignment_bytes(target_info),
|
||||
Layout::LambdaSet(lambda_set) => lambda_set
|
||||
.runtime_representation()
|
||||
.allocation_alignment_bytes(pointer_size),
|
||||
.allocation_alignment_bytes(target_info),
|
||||
Layout::RecursivePointer => unreachable!("should be looked up to get an actual layout"),
|
||||
}
|
||||
}
|
||||
@ -1149,7 +1147,7 @@ impl<'a> Layout<'a> {
|
||||
/// But if we're careful when to invalidate certain keys, we still get some benefit
|
||||
#[derive(Debug)]
|
||||
pub struct LayoutCache<'a> {
|
||||
ptr_bytes: u32,
|
||||
target_info: TargetInfo,
|
||||
_marker: std::marker::PhantomData<&'a u8>,
|
||||
}
|
||||
|
||||
@ -1161,9 +1159,9 @@ pub enum CachedLayout<'a> {
|
||||
}
|
||||
|
||||
impl<'a> LayoutCache<'a> {
|
||||
pub fn new(ptr_bytes: u32) -> Self {
|
||||
pub fn new(target_info: TargetInfo) -> Self {
|
||||
Self {
|
||||
ptr_bytes,
|
||||
target_info,
|
||||
_marker: Default::default(),
|
||||
}
|
||||
}
|
||||
@ -1181,7 +1179,7 @@ impl<'a> LayoutCache<'a> {
|
||||
arena,
|
||||
subs,
|
||||
seen: Vec::new_in(arena),
|
||||
ptr_bytes: self.ptr_bytes,
|
||||
target_info: self.target_info,
|
||||
};
|
||||
|
||||
Layout::from_var(&mut env, var)
|
||||
@ -1200,7 +1198,7 @@ impl<'a> LayoutCache<'a> {
|
||||
arena,
|
||||
subs,
|
||||
seen: Vec::new_in(arena),
|
||||
ptr_bytes: self.ptr_bytes,
|
||||
target_info: self.target_info,
|
||||
};
|
||||
RawFunctionLayout::from_var(&mut env, var)
|
||||
}
|
||||
@ -1232,11 +1230,17 @@ impl<'a> Layout<'a> {
|
||||
Layout::Builtin(Builtin::Float(FloatWidth::F32))
|
||||
}
|
||||
|
||||
pub fn usize(ptr_bytes: u32) -> Layout<'a> {
|
||||
match ptr_bytes {
|
||||
4 => Self::u32(),
|
||||
8 => Self::u64(),
|
||||
_ => panic!("width of usize {} not supported", ptr_bytes),
|
||||
pub fn usize(target_info: TargetInfo) -> Layout<'a> {
|
||||
match target_info.ptr_width() {
|
||||
roc_target::PtrWidth::Bytes4 => Self::u32(),
|
||||
roc_target::PtrWidth::Bytes8 => Self::u64(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn isize(target_info: TargetInfo) -> Layout<'a> {
|
||||
match target_info.ptr_width() {
|
||||
roc_target::PtrWidth::Bytes4 => Self::i32(),
|
||||
roc_target::PtrWidth::Bytes8 => Self::i64(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -1310,42 +1314,46 @@ impl<'a> Builtin<'a> {
|
||||
pub const WRAPPER_PTR: u32 = 0;
|
||||
pub const WRAPPER_LEN: u32 = 1;
|
||||
|
||||
pub fn stack_size(&self, pointer_size: u32) -> u32 {
|
||||
pub fn stack_size(&self, target_info: TargetInfo) -> u32 {
|
||||
use Builtin::*;
|
||||
|
||||
let ptr_width = target_info.ptr_width() as u32;
|
||||
|
||||
match self {
|
||||
Int(int) => int.stack_size(),
|
||||
Float(float) => float.stack_size(),
|
||||
Bool => Builtin::I1_SIZE,
|
||||
Decimal => Builtin::DECIMAL_SIZE,
|
||||
Str => Builtin::STR_WORDS * pointer_size,
|
||||
Dict(_, _) => Builtin::DICT_WORDS * pointer_size,
|
||||
Set(_) => Builtin::SET_WORDS * pointer_size,
|
||||
List(_) => Builtin::LIST_WORDS * pointer_size,
|
||||
Str => Builtin::STR_WORDS * ptr_width,
|
||||
Dict(_, _) => Builtin::DICT_WORDS * ptr_width,
|
||||
Set(_) => Builtin::SET_WORDS * ptr_width,
|
||||
List(_) => Builtin::LIST_WORDS * ptr_width,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn alignment_bytes(&self, pointer_size: u32) -> u32 {
|
||||
pub fn alignment_bytes(&self, target_info: TargetInfo) -> u32 {
|
||||
use std::mem::align_of;
|
||||
use Builtin::*;
|
||||
|
||||
let ptr_width = target_info.ptr_width() as u32;
|
||||
|
||||
// for our data structures, what counts is the alignment of the `( ptr, len )` tuple, and
|
||||
// since both of those are one pointer size, the alignment of that structure is a pointer
|
||||
// size
|
||||
match self {
|
||||
Int(int_width) => int_width.alignment_bytes(),
|
||||
Float(float_width) => float_width.alignment_bytes(),
|
||||
Int(int_width) => int_width.alignment_bytes(target_info),
|
||||
Float(float_width) => float_width.alignment_bytes(target_info),
|
||||
Bool => align_of::<bool>() as u32,
|
||||
Decimal => align_of::<i128>() as u32,
|
||||
Dict(_, _) => pointer_size,
|
||||
Set(_) => pointer_size,
|
||||
Decimal => IntWidth::I128.alignment_bytes(target_info),
|
||||
Dict(_, _) => ptr_width,
|
||||
Set(_) => ptr_width,
|
||||
// we often treat these as i128 (64-bit systems)
|
||||
// or i64 (32-bit systems).
|
||||
//
|
||||
// In webassembly, For that to be safe
|
||||
// they must be aligned to allow such access
|
||||
List(_) => pointer_size,
|
||||
Str => pointer_size,
|
||||
List(_) => ptr_width,
|
||||
Str => ptr_width,
|
||||
}
|
||||
}
|
||||
|
||||
@ -1425,21 +1433,23 @@ impl<'a> Builtin<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn allocation_alignment_bytes(&self, pointer_size: u32) -> u32 {
|
||||
pub fn allocation_alignment_bytes(&self, target_info: TargetInfo) -> u32 {
|
||||
let ptr_width = target_info.ptr_width() as u32;
|
||||
|
||||
let allocation = match self {
|
||||
Builtin::Int(_) | Builtin::Float(_) | Builtin::Bool | Builtin::Decimal => {
|
||||
unreachable!("not heap-allocated")
|
||||
}
|
||||
Builtin::Str => pointer_size,
|
||||
Builtin::Str => ptr_width,
|
||||
Builtin::Dict(k, v) => k
|
||||
.alignment_bytes(pointer_size)
|
||||
.max(v.alignment_bytes(pointer_size))
|
||||
.max(pointer_size),
|
||||
Builtin::Set(k) => k.alignment_bytes(pointer_size).max(pointer_size),
|
||||
Builtin::List(e) => e.alignment_bytes(pointer_size).max(pointer_size),
|
||||
.alignment_bytes(target_info)
|
||||
.max(v.alignment_bytes(target_info))
|
||||
.max(ptr_width),
|
||||
Builtin::Set(k) => k.alignment_bytes(target_info).max(ptr_width),
|
||||
Builtin::List(e) => e.alignment_bytes(target_info).max(ptr_width),
|
||||
};
|
||||
|
||||
allocation.max(pointer_size)
|
||||
allocation.max(ptr_width)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1451,7 +1461,7 @@ fn layout_from_flat_type<'a>(
|
||||
|
||||
let arena = env.arena;
|
||||
let subs = env.subs;
|
||||
let ptr_bytes = env.ptr_bytes;
|
||||
let target_info = env.target_info;
|
||||
|
||||
match flat_type {
|
||||
Apply(symbol, args) => {
|
||||
@ -1461,7 +1471,7 @@ fn layout_from_flat_type<'a>(
|
||||
// Ints
|
||||
Symbol::NUM_NAT => {
|
||||
debug_assert_eq!(args.len(), 0);
|
||||
Ok(Layout::usize(env.ptr_bytes))
|
||||
Ok(Layout::usize(env.target_info))
|
||||
}
|
||||
|
||||
Symbol::NUM_I128 => {
|
||||
@ -1527,7 +1537,7 @@ fn layout_from_flat_type<'a>(
|
||||
let var = args[0];
|
||||
let content = subs.get_content_without_compacting(var);
|
||||
|
||||
layout_from_num_content(content)
|
||||
layout_from_num_content(content, target_info)
|
||||
}
|
||||
|
||||
Symbol::STR_STR => Ok(Layout::Builtin(Builtin::Str)),
|
||||
@ -1543,7 +1553,8 @@ fn layout_from_flat_type<'a>(
|
||||
}
|
||||
}
|
||||
Func(_, closure_var, _) => {
|
||||
let lambda_set = LambdaSet::from_var(env.arena, env.subs, closure_var, env.ptr_bytes)?;
|
||||
let lambda_set =
|
||||
LambdaSet::from_var(env.arena, env.subs, closure_var, env.target_info)?;
|
||||
|
||||
Ok(Layout::LambdaSet(lambda_set))
|
||||
}
|
||||
@ -1563,8 +1574,8 @@ fn layout_from_flat_type<'a>(
|
||||
}
|
||||
|
||||
pairs.sort_by(|(label1, layout1), (label2, layout2)| {
|
||||
let size1 = layout1.alignment_bytes(ptr_bytes);
|
||||
let size2 = layout2.alignment_bytes(ptr_bytes);
|
||||
let size1 = layout1.alignment_bytes(target_info);
|
||||
let size2 = layout2.alignment_bytes(target_info);
|
||||
|
||||
size2.cmp(&size1).then(label1.cmp(label2))
|
||||
});
|
||||
@ -1584,7 +1595,7 @@ fn layout_from_flat_type<'a>(
|
||||
|
||||
debug_assert!(ext_var_is_empty_tag_union(subs, ext_var));
|
||||
|
||||
Ok(layout_from_tag_union(arena, &tags, subs, env.ptr_bytes))
|
||||
Ok(layout_from_tag_union(arena, &tags, subs, env.target_info))
|
||||
}
|
||||
FunctionOrTagUnion(tag_name, _, ext_var) => {
|
||||
debug_assert!(
|
||||
@ -1595,7 +1606,7 @@ fn layout_from_flat_type<'a>(
|
||||
let union_tags = UnionTags::from_tag_name_index(tag_name);
|
||||
let (tags, _) = union_tags.unsorted_tags_and_ext(subs, ext_var);
|
||||
|
||||
Ok(layout_from_tag_union(arena, &tags, subs, env.ptr_bytes))
|
||||
Ok(layout_from_tag_union(arena, &tags, subs, env.target_info))
|
||||
}
|
||||
RecursiveTagUnion(rec_var, tags, ext_var) => {
|
||||
let (tags, ext_var) = tags.unsorted_tags_and_ext(subs, ext_var);
|
||||
@ -1645,8 +1656,8 @@ fn layout_from_flat_type<'a>(
|
||||
}
|
||||
|
||||
tag_layout.sort_by(|layout1, layout2| {
|
||||
let size1 = layout1.alignment_bytes(ptr_bytes);
|
||||
let size2 = layout2.alignment_bytes(ptr_bytes);
|
||||
let size1 = layout1.alignment_bytes(target_info);
|
||||
let size2 = layout2.alignment_bytes(target_info);
|
||||
|
||||
size2.cmp(&size1)
|
||||
});
|
||||
@ -1691,13 +1702,13 @@ pub fn sort_record_fields<'a>(
|
||||
arena: &'a Bump,
|
||||
var: Variable,
|
||||
subs: &Subs,
|
||||
ptr_bytes: u32,
|
||||
target_info: TargetInfo,
|
||||
) -> Result<Vec<'a, SortedField<'a>>, LayoutProblem> {
|
||||
let mut env = Env {
|
||||
arena,
|
||||
subs,
|
||||
seen: Vec::new_in(arena),
|
||||
ptr_bytes,
|
||||
target_info,
|
||||
};
|
||||
|
||||
let (it, _) = match gather_fields_unsorted_iter(subs, RecordFields::empty(), var) {
|
||||
@ -1716,7 +1727,7 @@ fn sort_record_fields_help<'a>(
|
||||
env: &mut Env<'a, '_>,
|
||||
fields_map: impl Iterator<Item = (Lowercase, RecordField<Variable>)>,
|
||||
) -> Result<Vec<'a, SortedField<'a>>, LayoutProblem> {
|
||||
let ptr_bytes = env.ptr_bytes;
|
||||
let target_info = env.target_info;
|
||||
|
||||
// Sort the fields by label
|
||||
let mut sorted_fields = Vec::with_capacity_in(fields_map.size_hint().0, env.arena);
|
||||
@ -1738,8 +1749,8 @@ fn sort_record_fields_help<'a>(
|
||||
|(label1, _, res_layout1), (label2, _, res_layout2)| match res_layout1 {
|
||||
Ok(layout1) | Err(layout1) => match res_layout2 {
|
||||
Ok(layout2) | Err(layout2) => {
|
||||
let size1 = layout1.alignment_bytes(ptr_bytes);
|
||||
let size2 = layout2.alignment_bytes(ptr_bytes);
|
||||
let size1 = layout1.alignment_bytes(target_info);
|
||||
let size2 = layout2.alignment_bytes(target_info);
|
||||
|
||||
size2.cmp(&size1).then(label1.cmp(label2))
|
||||
}
|
||||
@ -1873,7 +1884,7 @@ pub fn union_sorted_tags<'a>(
|
||||
arena: &'a Bump,
|
||||
var: Variable,
|
||||
subs: &Subs,
|
||||
ptr_bytes: u32,
|
||||
target_info: TargetInfo,
|
||||
) -> Result<UnionVariant<'a>, LayoutProblem> {
|
||||
let var =
|
||||
if let Content::RecursionVar { structure, .. } = subs.get_content_without_compacting(var) {
|
||||
@ -1886,7 +1897,7 @@ pub fn union_sorted_tags<'a>(
|
||||
let result = match roc_types::pretty_print::chase_ext_tag_union(subs, var, &mut tags_vec) {
|
||||
Ok(()) | Err((_, Content::FlexVar(_))) | Err((_, Content::RecursionVar { .. })) => {
|
||||
let opt_rec_var = get_recursion_var(subs, var);
|
||||
union_sorted_tags_help(arena, tags_vec, opt_rec_var, subs, ptr_bytes)
|
||||
union_sorted_tags_help(arena, tags_vec, opt_rec_var, subs, target_info)
|
||||
}
|
||||
Err((_, Content::Error)) => return Err(LayoutProblem::Erroneous),
|
||||
Err(other) => panic!("invalid content in tag union variable: {:?}", other),
|
||||
@ -1920,7 +1931,7 @@ fn union_sorted_tags_help_new<'a>(
|
||||
tags_list: &[(&'_ TagName, &[Variable])],
|
||||
opt_rec_var: Option<Variable>,
|
||||
subs: &Subs,
|
||||
ptr_bytes: u32,
|
||||
target_info: TargetInfo,
|
||||
) -> UnionVariant<'a> {
|
||||
// sort up front; make sure the ordering stays intact!
|
||||
let mut tags_list = Vec::from_iter_in(tags_list.iter(), arena);
|
||||
@ -1930,7 +1941,7 @@ fn union_sorted_tags_help_new<'a>(
|
||||
arena,
|
||||
subs,
|
||||
seen: Vec::new_in(arena),
|
||||
ptr_bytes,
|
||||
target_info,
|
||||
};
|
||||
|
||||
match tags_list.len() {
|
||||
@ -1949,7 +1960,8 @@ fn union_sorted_tags_help_new<'a>(
|
||||
match tag_name {
|
||||
TagName::Private(Symbol::NUM_AT_NUM) => {
|
||||
let var = arguments[0];
|
||||
layouts.push(unwrap_num_tag(subs, var, ptr_bytes).expect("invalid num layout"));
|
||||
layouts
|
||||
.push(unwrap_num_tag(subs, var, target_info).expect("invalid num layout"));
|
||||
}
|
||||
_ => {
|
||||
for &var in arguments {
|
||||
@ -1973,8 +1985,8 @@ fn union_sorted_tags_help_new<'a>(
|
||||
}
|
||||
|
||||
layouts.sort_by(|layout1, layout2| {
|
||||
let size1 = layout1.alignment_bytes(ptr_bytes);
|
||||
let size2 = layout2.alignment_bytes(ptr_bytes);
|
||||
let size1 = layout1.alignment_bytes(target_info);
|
||||
let size2 = layout2.alignment_bytes(target_info);
|
||||
|
||||
size2.cmp(&size1)
|
||||
});
|
||||
@ -2051,8 +2063,8 @@ fn union_sorted_tags_help_new<'a>(
|
||||
}
|
||||
|
||||
arg_layouts.sort_by(|layout1, layout2| {
|
||||
let size1 = layout1.alignment_bytes(ptr_bytes);
|
||||
let size2 = layout2.alignment_bytes(ptr_bytes);
|
||||
let size1 = layout1.alignment_bytes(target_info);
|
||||
let size2 = layout2.alignment_bytes(target_info);
|
||||
|
||||
size2.cmp(&size1)
|
||||
});
|
||||
@ -2123,7 +2135,7 @@ pub fn union_sorted_tags_help<'a>(
|
||||
mut tags_vec: std::vec::Vec<(TagName, std::vec::Vec<Variable>)>,
|
||||
opt_rec_var: Option<Variable>,
|
||||
subs: &Subs,
|
||||
ptr_bytes: u32,
|
||||
target_info: TargetInfo,
|
||||
) -> UnionVariant<'a> {
|
||||
// sort up front; make sure the ordering stays intact!
|
||||
tags_vec.sort_unstable_by(|(a, _), (b, _)| a.cmp(b));
|
||||
@ -2132,7 +2144,7 @@ pub fn union_sorted_tags_help<'a>(
|
||||
arena,
|
||||
subs,
|
||||
seen: Vec::new_in(arena),
|
||||
ptr_bytes,
|
||||
target_info,
|
||||
};
|
||||
|
||||
match tags_vec.len() {
|
||||
@ -2151,7 +2163,8 @@ pub fn union_sorted_tags_help<'a>(
|
||||
match tag_name {
|
||||
TagName::Private(Symbol::NUM_AT_NUM) => {
|
||||
layouts.push(
|
||||
unwrap_num_tag(subs, arguments[0], ptr_bytes).expect("invalid num layout"),
|
||||
unwrap_num_tag(subs, arguments[0], target_info)
|
||||
.expect("invalid num layout"),
|
||||
);
|
||||
}
|
||||
_ => {
|
||||
@ -2181,8 +2194,8 @@ pub fn union_sorted_tags_help<'a>(
|
||||
}
|
||||
|
||||
layouts.sort_by(|layout1, layout2| {
|
||||
let size1 = layout1.alignment_bytes(ptr_bytes);
|
||||
let size2 = layout2.alignment_bytes(ptr_bytes);
|
||||
let size1 = layout1.alignment_bytes(target_info);
|
||||
let size2 = layout2.alignment_bytes(target_info);
|
||||
|
||||
size2.cmp(&size1)
|
||||
});
|
||||
@ -2264,8 +2277,8 @@ pub fn union_sorted_tags_help<'a>(
|
||||
}
|
||||
|
||||
arg_layouts.sort_by(|layout1, layout2| {
|
||||
let size1 = layout1.alignment_bytes(ptr_bytes);
|
||||
let size2 = layout2.alignment_bytes(ptr_bytes);
|
||||
let size1 = layout1.alignment_bytes(target_info);
|
||||
let size2 = layout2.alignment_bytes(target_info);
|
||||
|
||||
size2.cmp(&size1)
|
||||
});
|
||||
@ -2335,20 +2348,20 @@ fn layout_from_newtype<'a>(
|
||||
arena: &'a Bump,
|
||||
tags: &UnsortedUnionTags,
|
||||
subs: &Subs,
|
||||
ptr_bytes: u32,
|
||||
target_info: TargetInfo,
|
||||
) -> Layout<'a> {
|
||||
debug_assert!(tags.is_newtype_wrapper(subs));
|
||||
|
||||
let (tag_name, var) = tags.get_newtype(subs);
|
||||
|
||||
if tag_name == &TagName::Private(Symbol::NUM_AT_NUM) {
|
||||
unwrap_num_tag(subs, var, ptr_bytes).expect("invalid Num argument")
|
||||
unwrap_num_tag(subs, var, target_info).expect("invalid Num argument")
|
||||
} else {
|
||||
let mut env = Env {
|
||||
arena,
|
||||
subs,
|
||||
seen: Vec::new_in(arena),
|
||||
ptr_bytes,
|
||||
target_info,
|
||||
};
|
||||
|
||||
match Layout::from_var(&mut env, var) {
|
||||
@ -2372,12 +2385,12 @@ fn layout_from_tag_union<'a>(
|
||||
arena: &'a Bump,
|
||||
tags: &UnsortedUnionTags,
|
||||
subs: &Subs,
|
||||
ptr_bytes: u32,
|
||||
target_info: TargetInfo,
|
||||
) -> Layout<'a> {
|
||||
use UnionVariant::*;
|
||||
|
||||
if tags.is_newtype_wrapper(subs) {
|
||||
return layout_from_newtype(arena, tags, subs, ptr_bytes);
|
||||
return layout_from_newtype(arena, tags, subs, target_info);
|
||||
}
|
||||
|
||||
let tags_vec = &tags.tags;
|
||||
@ -2388,11 +2401,12 @@ fn layout_from_tag_union<'a>(
|
||||
|
||||
let &var = arguments.iter().next().unwrap();
|
||||
|
||||
unwrap_num_tag(subs, var, ptr_bytes).expect("invalid Num argument")
|
||||
unwrap_num_tag(subs, var, target_info).expect("invalid Num argument")
|
||||
}
|
||||
_ => {
|
||||
let opt_rec_var = None;
|
||||
let variant = union_sorted_tags_help_new(arena, tags_vec, opt_rec_var, subs, ptr_bytes);
|
||||
let variant =
|
||||
union_sorted_tags_help_new(arena, tags_vec, opt_rec_var, subs, target_info);
|
||||
|
||||
match variant {
|
||||
Never => Layout::VOID,
|
||||
@ -2490,12 +2504,13 @@ pub fn ext_var_is_empty_tag_union(_: &Subs, _: Variable) -> bool {
|
||||
unreachable!();
|
||||
}
|
||||
|
||||
fn layout_from_num_content<'a>(content: &Content) -> Result<Layout<'a>, LayoutProblem> {
|
||||
fn layout_from_num_content<'a>(
|
||||
content: &Content,
|
||||
target_info: TargetInfo,
|
||||
) -> Result<Layout<'a>, LayoutProblem> {
|
||||
use roc_types::subs::Content::*;
|
||||
use roc_types::subs::FlatType::*;
|
||||
|
||||
let ptr_bytes = 8;
|
||||
|
||||
match content {
|
||||
RecursionVar { .. } => panic!("recursion var in num"),
|
||||
FlexVar(_) | RigidVar(_) => {
|
||||
@ -2507,7 +2522,7 @@ fn layout_from_num_content<'a>(content: &Content) -> Result<Layout<'a>, LayoutPr
|
||||
}
|
||||
Structure(Apply(symbol, args)) => match *symbol {
|
||||
// Ints
|
||||
Symbol::NUM_NAT => Ok(Layout::usize(ptr_bytes)),
|
||||
Symbol::NUM_NAT => Ok(Layout::usize(target_info)),
|
||||
|
||||
Symbol::NUM_INTEGER => Ok(Layout::i64()),
|
||||
Symbol::NUM_I128 => Ok(Layout::i128()),
|
||||
@ -2550,7 +2565,7 @@ fn layout_from_num_content<'a>(content: &Content) -> Result<Layout<'a>, LayoutPr
|
||||
fn unwrap_num_tag<'a>(
|
||||
subs: &Subs,
|
||||
var: Variable,
|
||||
ptr_bytes: u32,
|
||||
target_info: TargetInfo,
|
||||
) -> Result<Layout<'a>, LayoutProblem> {
|
||||
match subs.get_content_without_compacting(var) {
|
||||
Content::Alias(Symbol::NUM_INTEGER, args, _) => {
|
||||
@ -2575,7 +2590,7 @@ fn unwrap_num_tag<'a>(
|
||||
Symbol::NUM_UNSIGNED32 => Layout::u32(),
|
||||
Symbol::NUM_UNSIGNED16 => Layout::u16(),
|
||||
Symbol::NUM_UNSIGNED8 => Layout::u8(),
|
||||
Symbol::NUM_NATURAL => Layout::usize(ptr_bytes),
|
||||
Symbol::NUM_NATURAL => Layout::usize(target_info),
|
||||
|
||||
_ => unreachable!("not a valid int variant: {:?} {:?}", symbol, args),
|
||||
};
|
||||
@ -2821,8 +2836,8 @@ mod test {
|
||||
|
||||
let layout = Layout::Union(UnionLayout::NonRecursive(&tt));
|
||||
|
||||
let ptr_width = 8;
|
||||
assert_eq!(layout.stack_size(ptr_width), 1);
|
||||
assert_eq!(layout.alignment_bytes(ptr_width), 1);
|
||||
let target_info = TargetInfo::default_x86_64();
|
||||
assert_eq!(layout.stack_size(target_info), 1);
|
||||
assert_eq!(layout.alignment_bytes(target_info), 1);
|
||||
}
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ use roc_builtins::bitcode::{FloatWidth, IntWidth};
|
||||
use roc_collections::all::MutMap;
|
||||
use roc_module::ident::TagName;
|
||||
use roc_module::symbol::Symbol;
|
||||
use roc_target::TargetInfo;
|
||||
use roc_types::subs::{Content, FlatType, Subs, Variable};
|
||||
use roc_types::types::RecordField;
|
||||
use std::collections::hash_map::Entry;
|
||||
@ -99,7 +100,7 @@ pub struct Layouts {
|
||||
lambda_sets: Vec<LambdaSet>,
|
||||
symbols: Vec<Symbol>,
|
||||
recursion_variable_to_structure_variable_map: MutMap<Variable, Index<Layout>>,
|
||||
usize_int_width: IntWidth,
|
||||
target_info: TargetInfo,
|
||||
}
|
||||
|
||||
pub struct FunctionLayout {
|
||||
@ -402,7 +403,7 @@ impl Layouts {
|
||||
const VOID_TUPLE: Index<(Layout, Layout)> = Index::new(0);
|
||||
const UNIT_INDEX: Index<Layout> = Index::new(2);
|
||||
|
||||
pub fn new(usize_int_width: IntWidth) -> Self {
|
||||
pub fn new(target_info: TargetInfo) -> Self {
|
||||
let mut layouts = Vec::with_capacity(64);
|
||||
|
||||
layouts.push(Layout::VOID);
|
||||
@ -420,7 +421,7 @@ impl Layouts {
|
||||
lambda_sets: Vec::default(),
|
||||
symbols: Vec::default(),
|
||||
recursion_variable_to_structure_variable_map: MutMap::default(),
|
||||
usize_int_width,
|
||||
target_info,
|
||||
}
|
||||
}
|
||||
|
||||
@ -443,7 +444,12 @@ impl Layouts {
|
||||
}
|
||||
|
||||
fn usize(&self) -> Layout {
|
||||
Layout::Int(self.usize_int_width)
|
||||
let usize_int_width = match self.target_info.ptr_width() {
|
||||
roc_target::PtrWidth::Bytes4 => IntWidth::U32,
|
||||
roc_target::PtrWidth::Bytes8 => IntWidth::U64,
|
||||
};
|
||||
|
||||
Layout::Int(usize_int_width)
|
||||
}
|
||||
|
||||
fn align_of_layout_index(&self, index: Index<Layout>) -> u16 {
|
||||
@ -453,18 +459,23 @@ impl Layouts {
|
||||
}
|
||||
|
||||
fn align_of_layout(&self, layout: Layout) -> u16 {
|
||||
let ptr_alignment = self.usize_int_width.alignment_bytes() as u16;
|
||||
let usize_int_width = match self.target_info.ptr_width() {
|
||||
roc_target::PtrWidth::Bytes4 => IntWidth::U32,
|
||||
roc_target::PtrWidth::Bytes8 => IntWidth::U64,
|
||||
};
|
||||
|
||||
let ptr_alignment = usize_int_width.alignment_bytes(self.target_info) as u16;
|
||||
|
||||
match layout {
|
||||
Layout::Reserved => unreachable!(),
|
||||
Layout::Int(int_width) => int_width.alignment_bytes() as u16,
|
||||
Layout::Float(float_width) => float_width.alignment_bytes() as u16,
|
||||
Layout::Decimal => IntWidth::U128.alignment_bytes() as u16,
|
||||
Layout::Int(int_width) => int_width.alignment_bytes(self.target_info) as u16,
|
||||
Layout::Float(float_width) => float_width.alignment_bytes(self.target_info) as u16,
|
||||
Layout::Decimal => IntWidth::U128.alignment_bytes(self.target_info) as u16,
|
||||
Layout::Str | Layout::Dict(_) | Layout::Set(_) | Layout::List(_) => ptr_alignment,
|
||||
Layout::Struct(slice) => self.align_of_layout_slice(slice),
|
||||
Layout::Boxed(_) | Layout::UnionRecursive(_) => ptr_alignment,
|
||||
Layout::UnionNonRecursive(slices) => {
|
||||
let tag_id_align = IntWidth::I64.alignment_bytes() as u16;
|
||||
let tag_id_align = IntWidth::I64.alignment_bytes(self.target_info) as u16;
|
||||
|
||||
self.align_of_layout_slices(slices).max(tag_id_align)
|
||||
}
|
||||
@ -518,7 +529,12 @@ impl Layouts {
|
||||
}
|
||||
|
||||
pub fn size_of_layout(&self, layout: Layout) -> u16 {
|
||||
let ptr_width = self.usize_int_width.stack_size() as u16;
|
||||
let usize_int_width = match self.target_info.ptr_width() {
|
||||
roc_target::PtrWidth::Bytes4 => IntWidth::U32,
|
||||
roc_target::PtrWidth::Bytes8 => IntWidth::U64,
|
||||
};
|
||||
|
||||
let ptr_width = usize_int_width.stack_size() as u16;
|
||||
|
||||
match layout {
|
||||
Layout::Reserved => unreachable!(),
|
||||
|
9
compiler/roc_target/Cargo.toml
Normal file
9
compiler/roc_target/Cargo.toml
Normal file
@ -0,0 +1,9 @@
|
||||
[package]
|
||||
name = "roc_target"
|
||||
version = "0.1.0"
|
||||
authors = ["The Roc Contributors"]
|
||||
license = "UPL-1.0"
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
target-lexicon = "0.12.2"
|
74
compiler/roc_target/src/lib.rs
Normal file
74
compiler/roc_target/src/lib.rs
Normal file
@ -0,0 +1,74 @@
|
||||
#![warn(clippy::dbg_macro)]
|
||||
// See github.com/rtfeldman/roc/issues/800 for discussion of the large_enum_variant check.
|
||||
#![allow(clippy::large_enum_variant)]
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct TargetInfo {
|
||||
pub architecture: Architecture,
|
||||
}
|
||||
|
||||
impl TargetInfo {
|
||||
pub const fn ptr_width(&self) -> PtrWidth {
|
||||
self.architecture.ptr_width()
|
||||
}
|
||||
|
||||
pub const fn default_x86_64() -> Self {
|
||||
TargetInfo {
|
||||
architecture: Architecture::X86_64,
|
||||
}
|
||||
}
|
||||
|
||||
pub const fn default_wasm32() -> Self {
|
||||
TargetInfo {
|
||||
architecture: Architecture::Wasm32,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&target_lexicon::Triple> for TargetInfo {
|
||||
fn from(triple: &target_lexicon::Triple) -> Self {
|
||||
let architecture = Architecture::from(triple.architecture);
|
||||
|
||||
Self { architecture }
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(u8)]
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum PtrWidth {
|
||||
Bytes4 = 4,
|
||||
Bytes8 = 8,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum Architecture {
|
||||
X86_64,
|
||||
X86_32,
|
||||
Aarch64,
|
||||
Arm,
|
||||
Wasm32,
|
||||
}
|
||||
|
||||
impl Architecture {
|
||||
pub const fn ptr_width(&self) -> PtrWidth {
|
||||
use Architecture::*;
|
||||
|
||||
match self {
|
||||
X86_64 | Aarch64 | Arm => PtrWidth::Bytes8,
|
||||
X86_32 | Wasm32 => PtrWidth::Bytes4,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<target_lexicon::Architecture> for Architecture {
|
||||
fn from(target: target_lexicon::Architecture) -> Self {
|
||||
match target {
|
||||
target_lexicon::Architecture::X86_64 => Architecture::X86_64,
|
||||
target_lexicon::Architecture::X86_32(_) => Architecture::X86_32,
|
||||
target_lexicon::Architecture::Aarch64(_) => Architecture::Aarch64,
|
||||
target_lexicon::Architecture::Arm(_) => Architecture::Arm,
|
||||
target_lexicon::Architecture::Wasm32 => Architecture::Wasm32,
|
||||
_ => unreachable!("unsupported architecture"),
|
||||
}
|
||||
}
|
||||
}
|
@ -21,6 +21,7 @@ roc_builtins = { path = "../builtins" }
|
||||
roc_problem = { path = "../problem" }
|
||||
roc_parse = { path = "../parse" }
|
||||
roc_solve = { path = "../solve" }
|
||||
roc_target = { path = "../roc_target" }
|
||||
pretty_assertions = "1.0.0"
|
||||
indoc = "1.0.3"
|
||||
tempfile = "3.2.0"
|
||||
|
@ -63,7 +63,7 @@ mod solve_expr {
|
||||
&stdlib,
|
||||
dir.path(),
|
||||
exposed_types,
|
||||
8,
|
||||
roc_target::TargetInfo::default_x86_64(),
|
||||
builtin_defs_map,
|
||||
);
|
||||
|
||||
|
@ -31,6 +31,7 @@ roc_load = { path = "../load" }
|
||||
roc_can = { path = "../can" }
|
||||
roc_parse = { path = "../parse" }
|
||||
roc_build = { path = "../build" }
|
||||
roc_target = { path = "../roc_target" }
|
||||
roc_std = { path = "../../roc_std" }
|
||||
bumpalo = { version = "3.8.0", features = ["collections"] }
|
||||
either = "1.6.1"
|
||||
|
@ -23,9 +23,9 @@ fn width_and_alignment_u8_u8() {
|
||||
|
||||
let layout = Layout::Union(UnionLayout::NonRecursive(&tt));
|
||||
|
||||
let ptr_width = 8;
|
||||
assert_eq!(layout.alignment_bytes(ptr_width), 1);
|
||||
assert_eq!(layout.stack_size(ptr_width), 2);
|
||||
let target_info = roc_target::TargetInfo::default_x86_64();
|
||||
assert_eq!(layout.alignment_bytes(target_info), 1);
|
||||
assert_eq!(layout.stack_size(target_info), 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -57,7 +57,7 @@ pub fn helper(
|
||||
&stdlib,
|
||||
src_dir,
|
||||
exposed_types,
|
||||
8,
|
||||
roc_target::TargetInfo::default_x86_64(),
|
||||
builtin_defs_map,
|
||||
);
|
||||
|
||||
|
@ -42,6 +42,8 @@ fn create_llvm_module<'a>(
|
||||
) -> (&'static str, String, &'a Module<'a>) {
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
let target_info = roc_target::TargetInfo::from(target);
|
||||
|
||||
let filename = PathBuf::from("Test.roc");
|
||||
let src_dir = Path::new("fake/test/path");
|
||||
|
||||
@ -56,8 +58,6 @@ fn create_llvm_module<'a>(
|
||||
module_src = &temp;
|
||||
}
|
||||
|
||||
let ptr_bytes = target.pointer_width().unwrap().bytes() as u32;
|
||||
|
||||
let exposed_types = MutMap::default();
|
||||
let loaded = roc_load::file::load_and_monomorphize_from_str(
|
||||
arena,
|
||||
@ -66,7 +66,7 @@ fn create_llvm_module<'a>(
|
||||
stdlib,
|
||||
src_dir,
|
||||
exposed_types,
|
||||
ptr_bytes,
|
||||
target_info,
|
||||
test_builtin_defs,
|
||||
);
|
||||
|
||||
@ -213,7 +213,7 @@ fn create_llvm_module<'a>(
|
||||
context,
|
||||
interns,
|
||||
module,
|
||||
ptr_bytes,
|
||||
target_info,
|
||||
is_gen_test,
|
||||
// important! we don't want any procedures to get the C calling convention
|
||||
exposed_to_host: MutSet::default(),
|
||||
|
@ -94,7 +94,6 @@ fn compile_roc_to_wasm_bytes<'a, T: Wasm32TestResult>(
|
||||
}
|
||||
|
||||
let exposed_types = MutMap::default();
|
||||
let ptr_bytes = 4;
|
||||
let loaded = roc_load::file::load_and_monomorphize_from_str(
|
||||
arena,
|
||||
filename,
|
||||
@ -102,7 +101,7 @@ fn compile_roc_to_wasm_bytes<'a, T: Wasm32TestResult>(
|
||||
stdlib,
|
||||
src_dir,
|
||||
exposed_types,
|
||||
ptr_bytes,
|
||||
roc_target::TargetInfo::default_wasm32(),
|
||||
builtin_defs_map,
|
||||
);
|
||||
|
||||
|
@ -16,6 +16,7 @@ roc_builtins = { path = "../builtins" }
|
||||
roc_load = { path = "../load" }
|
||||
roc_can = { path = "../can" }
|
||||
roc_mono = { path = "../mono" }
|
||||
roc_target = { path = "../roc_target" }
|
||||
test_mono_macros = { path = "../test_mono_macros" }
|
||||
pretty_assertions = "1.0.0"
|
||||
bumpalo = { version = "3.8.0", features = ["collections"] }
|
||||
|
@ -25,6 +25,8 @@ use roc_mono::ir::Proc;
|
||||
|
||||
use roc_mono::ir::ProcLayout;
|
||||
|
||||
const TARGET_INFO: roc_target::TargetInfo = roc_target::TargetInfo::default_x86_64();
|
||||
|
||||
/// Without this, some tests pass in `cargo test --release` but fail without
|
||||
/// the --release flag because they run out of stack space. This increases
|
||||
/// stack size for debug builds only, while leaving the stack space at the default
|
||||
@ -104,7 +106,7 @@ fn compiles_to_ir(test_name: &str, src: &str) {
|
||||
&stdlib,
|
||||
src_dir,
|
||||
exposed_types,
|
||||
8,
|
||||
TARGET_INFO,
|
||||
builtin_defs_map,
|
||||
);
|
||||
|
||||
|
@ -18,6 +18,7 @@ roc_module = { path = "../compiler/module" }
|
||||
roc_region = { path = "../compiler/region" }
|
||||
roc_types = { path = "../compiler/types" }
|
||||
roc_parse = { path = "../compiler/parse" }
|
||||
roc_target = { path = "../compiler/roc_target" }
|
||||
roc_collections = { path = "../compiler/collections" }
|
||||
bumpalo = { version = "3.8.0", features = ["collections"] }
|
||||
snafu = { version = "0.6.10", features = ["backtraces"] }
|
||||
|
@ -428,7 +428,7 @@ pub fn load_modules_for_files(filenames: Vec<PathBuf>, std_lib: StdLib) -> Vec<L
|
||||
&std_lib,
|
||||
src_dir.as_path(),
|
||||
MutMap::default(),
|
||||
std::mem::size_of::<usize>() as u32, // This is just type-checking for docs, so "target" doesn't matter
|
||||
roc_target::TargetInfo::default_x86_64(), // This is just type-checking for docs, so "target" doesn't matter
|
||||
builtin_defs_map,
|
||||
) {
|
||||
Ok(loaded) => modules.push(loaded),
|
||||
|
@ -21,6 +21,22 @@ main =
|
||||
|
||||
|> Task.map (\_ -> {})
|
||||
|
||||
nest : (I64, Expr -> IO Expr), I64, Expr -> IO Expr
|
||||
nest = \f, n, e -> Task.loop { s: n, f, m: n, x: e } nestHelp
|
||||
|
||||
State : { s : I64, f : I64, Expr -> IO Expr, m : I64, x : Expr }
|
||||
|
||||
nestHelp : State -> IO [ Step State, Done Expr ]
|
||||
nestHelp = \{ s, f, m, x } ->
|
||||
when m is
|
||||
0 ->
|
||||
Task.succeed (Done x)
|
||||
|
||||
_ ->
|
||||
w <- Task.after (f (s - m) x)
|
||||
|
||||
Task.succeed (Step { s, f, m: (m - 1), x: w })
|
||||
|
||||
Expr : [ Val I64, Var Str, Add Expr Expr, Mul Expr Expr, Pow Expr Expr, Ln Expr ]
|
||||
|
||||
divmod : I64, I64 -> Result { div : I64, mod : I64 } [ DivByZero ]*
|
||||
@ -180,18 +196,6 @@ count = \expr ->
|
||||
Ln f ->
|
||||
count f
|
||||
|
||||
nest : (I64, Expr -> IO Expr), I64, Expr -> IO Expr
|
||||
nest = \f, n, e -> nestHelp n f n e
|
||||
|
||||
nestHelp : I64, (I64, Expr -> IO Expr), I64, Expr -> IO Expr
|
||||
nestHelp = \s, f, m, x ->
|
||||
when m is
|
||||
0 ->
|
||||
Task.succeed x
|
||||
|
||||
_ ->
|
||||
f (s - m) x |> Task.after \w -> nestHelp s f (m - 1) w
|
||||
|
||||
deriv : I64, Expr -> IO Expr
|
||||
deriv = \i, f ->
|
||||
fprime = d "x" f
|
||||
|
@ -1,5 +1,5 @@
|
||||
platform "folkertdev/foo"
|
||||
requires { Model, Msg } { main : Effect {} }
|
||||
requires {} { main : Effect {} }
|
||||
exposes []
|
||||
packages {}
|
||||
imports [ Task.{ Task } ]
|
||||
|
@ -89,6 +89,10 @@ isWhitespace = \char ->
|
||||
== 0x9# tab
|
||||
interpretCtx : Context -> Task Context InterpreterErrors
|
||||
interpretCtx = \ctx ->
|
||||
Task.loop ctx interpretCtxLoop
|
||||
|
||||
interpretCtxLoop : Context -> Task [ Step Context, Done Context ] InterpreterErrors
|
||||
interpretCtxLoop = \ctx ->
|
||||
when ctx.state is
|
||||
Executing if Context.inWhileScope ctx ->
|
||||
# Deal with the current while loop potentially looping.
|
||||
@ -104,11 +108,11 @@ interpretCtx = \ctx ->
|
||||
if n == 0 then
|
||||
newScope = { scope & whileInfo: None }
|
||||
|
||||
interpretCtx { popCtx & scopes: List.set ctx.scopes last newScope }
|
||||
Task.succeed (Step { popCtx & scopes: List.set ctx.scopes last newScope })
|
||||
else
|
||||
newScope = { scope & whileInfo: Some { state: InBody, body, cond } }
|
||||
|
||||
interpretCtx { popCtx & scopes: List.append (List.set ctx.scopes last newScope) { data: None, buf: body, index: 0, whileInfo: None } }
|
||||
Task.succeed (Step { popCtx & scopes: List.append (List.set ctx.scopes last newScope) { data: None, buf: body, index: 0, whileInfo: None } })
|
||||
|
||||
Err e ->
|
||||
Task.fail e
|
||||
@ -117,7 +121,7 @@ interpretCtx = \ctx ->
|
||||
# Just rand the body. Run the condition again.
|
||||
newScope = { scope & whileInfo: Some { state: InCond, body, cond } }
|
||||
|
||||
interpretCtx { ctx & scopes: List.append (List.set ctx.scopes last newScope) { data: None, buf: cond, index: 0, whileInfo: None } }
|
||||
Task.succeed (Step { ctx & scopes: List.append (List.set ctx.scopes last newScope) { data: None, buf: cond, index: 0, whileInfo: None } })
|
||||
|
||||
None ->
|
||||
Task.fail NoScope
|
||||
@ -131,7 +135,7 @@ interpretCtx = \ctx ->
|
||||
when result is
|
||||
Ok (T val newCtx) ->
|
||||
execCtx <- Task.await (stepExecCtx newCtx val)
|
||||
interpretCtx execCtx
|
||||
Task.succeed (Step execCtx)
|
||||
|
||||
Err NoScope ->
|
||||
Task.fail NoScope
|
||||
@ -143,9 +147,9 @@ interpretCtx = \ctx ->
|
||||
|
||||
# If no scopes left, all execution complete.
|
||||
if List.isEmpty dropCtx.scopes then
|
||||
Task.succeed dropCtx
|
||||
Task.succeed (Done dropCtx)
|
||||
else
|
||||
interpretCtx dropCtx
|
||||
Task.succeed (Step dropCtx)
|
||||
|
||||
InComment ->
|
||||
result <- Task.attempt (Context.getChar ctx)
|
||||
@ -153,9 +157,9 @@ interpretCtx = \ctx ->
|
||||
Ok (T val newCtx) ->
|
||||
if val == 0x7D then
|
||||
# `}` end of comment
|
||||
interpretCtx { newCtx & state: Executing }
|
||||
Task.succeed (Step { newCtx & state: Executing })
|
||||
else
|
||||
interpretCtx { newCtx & state: InComment }
|
||||
Task.succeed (Step { newCtx & state: InComment })
|
||||
|
||||
Err NoScope ->
|
||||
Task.fail NoScope
|
||||
@ -174,13 +178,13 @@ interpretCtx = \ctx ->
|
||||
# so this is make i64 mul by 10 then convert back to i32.
|
||||
nextAccum = (10 * Num.intCast accum) + Num.intCast (val - 0x30)
|
||||
|
||||
interpretCtx { newCtx & state: InNumber (Num.intCast nextAccum) }
|
||||
Task.succeed (Step { newCtx & state: InNumber (Num.intCast nextAccum) })
|
||||
else
|
||||
# outside of number now, this needs to be executed.
|
||||
pushCtx = Context.pushStack newCtx (Number accum)
|
||||
|
||||
execCtx <- Task.await (stepExecCtx { pushCtx & state: Executing } val)
|
||||
interpretCtx execCtx
|
||||
Task.succeed (Step execCtx)
|
||||
|
||||
Err NoScope ->
|
||||
Task.fail NoScope
|
||||
@ -197,12 +201,12 @@ interpretCtx = \ctx ->
|
||||
when Str.fromUtf8 bytes is
|
||||
Ok str ->
|
||||
{ } <- Task.await (Stdout.raw str)
|
||||
interpretCtx { newCtx & state: Executing }
|
||||
Task.succeed (Step { newCtx & state: Executing })
|
||||
|
||||
Err _ ->
|
||||
Task.fail BadUtf8
|
||||
else
|
||||
interpretCtx { newCtx & state: InString (List.append bytes val) }
|
||||
Task.succeed (Step { newCtx & state: InString (List.append bytes val) })
|
||||
|
||||
Err NoScope ->
|
||||
Task.fail NoScope
|
||||
@ -216,17 +220,17 @@ interpretCtx = \ctx ->
|
||||
Ok (T val newCtx) ->
|
||||
if val == 0x5B then
|
||||
# start of a nested lambda `[`
|
||||
interpretCtx { newCtx & state: InLambda (depth + 1) (List.append bytes val) }
|
||||
Task.succeed (Step { newCtx & state: InLambda (depth + 1) (List.append bytes val) })
|
||||
else if val == 0x5D then
|
||||
# `]` end of current lambda
|
||||
if depth == 0 then
|
||||
# end of all lambdas
|
||||
interpretCtx (Context.pushStack { newCtx & state: Executing } (Lambda bytes))
|
||||
Task.succeed (Step (Context.pushStack { newCtx & state: Executing } (Lambda bytes)))
|
||||
else
|
||||
# end of nested lambda
|
||||
interpretCtx { newCtx & state: InLambda (depth - 1) (List.append bytes val) }
|
||||
Task.succeed (Step { newCtx & state: InLambda (depth - 1) (List.append bytes val) })
|
||||
else
|
||||
interpretCtx { newCtx & state: InLambda depth (List.append bytes val) }
|
||||
Task.succeed (Step { newCtx & state: InLambda depth (List.append bytes val) })
|
||||
|
||||
Err NoScope ->
|
||||
Task.fail NoScope
|
||||
@ -252,14 +256,14 @@ interpretCtx = \ctx ->
|
||||
|
||||
when result2 is
|
||||
Ok a ->
|
||||
interpretCtx a
|
||||
Task.succeed (Step a)
|
||||
|
||||
Err e ->
|
||||
Task.fail e
|
||||
|
||||
Ok (T 0x9F newCtx) ->
|
||||
# This is supposed to flush io buffers. We don't buffer, so it does nothing
|
||||
interpretCtx newCtx
|
||||
Task.succeed (Step newCtx)
|
||||
|
||||
Ok (T x _) ->
|
||||
data = Num.toStr (Num.intCast x)
|
||||
@ -276,7 +280,7 @@ interpretCtx = \ctx ->
|
||||
result <- Task.attempt (Context.getChar { ctx & state: Executing })
|
||||
when result is
|
||||
Ok (T x newCtx) ->
|
||||
interpretCtx (Context.pushStack newCtx (Number (Num.intCast x)))
|
||||
Task.succeed (Step (Context.pushStack newCtx (Number (Num.intCast x))))
|
||||
|
||||
Err NoScope ->
|
||||
Task.fail NoScope
|
||||
|
@ -1,9 +1,27 @@
|
||||
interface Task
|
||||
exposes [ Task, succeed, fail, await, map, onFail, attempt, fromResult ]
|
||||
exposes [ Task, succeed, fail, await, map, onFail, attempt, fromResult, loop ]
|
||||
imports [ fx.Effect ]
|
||||
|
||||
Task ok err : Effect.Effect (Result ok err)
|
||||
|
||||
loop : state, (state -> Task [ Step state, Done done ] err) -> Task done err
|
||||
loop = \state, step ->
|
||||
looper = \current ->
|
||||
step current
|
||||
|> Effect.map
|
||||
\res ->
|
||||
when res is
|
||||
Ok (Step newState) ->
|
||||
Step newState
|
||||
|
||||
Ok (Done result) ->
|
||||
Done (Ok result)
|
||||
|
||||
Err e ->
|
||||
Done (Err e)
|
||||
|
||||
Effect.loop state looper
|
||||
|
||||
succeed : val -> Task val *
|
||||
succeed = \val ->
|
||||
Effect.always (Ok val)
|
||||
|
@ -24,6 +24,7 @@ roc_constrain = { path = "../compiler/constrain" }
|
||||
roc_builtins = { path = "../compiler/builtins" }
|
||||
roc_problem = { path = "../compiler/problem" }
|
||||
roc_parse = { path = "../compiler/parse" }
|
||||
roc_target = { path = "../compiler/roc_target" }
|
||||
roc_test_utils = { path = "../test_utils" }
|
||||
pretty_assertions = "1.0.0"
|
||||
indoc = "1.0.3"
|
||||
|
@ -96,8 +96,8 @@ mod test_reporting {
|
||||
let mut update_mode_ids = UpdateModeIds::new();
|
||||
|
||||
// Populate Procs and Subs, and get the low-level Expr from the canonical Expr
|
||||
let ptr_bytes = 8;
|
||||
let mut layout_cache = LayoutCache::new(ptr_bytes);
|
||||
let target_info = roc_target::TargetInfo::default_x86_64();
|
||||
let mut layout_cache = LayoutCache::new(target_info);
|
||||
let mut mono_env = roc_mono::ir::Env {
|
||||
arena: &arena,
|
||||
subs: &mut subs,
|
||||
@ -105,7 +105,7 @@ mod test_reporting {
|
||||
home,
|
||||
ident_ids: &mut ident_ids,
|
||||
update_mode_ids: &mut update_mode_ids,
|
||||
ptr_bytes,
|
||||
target_info,
|
||||
// call_specialization_counter=0 is reserved
|
||||
call_specialization_counter: 1,
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user